diff --git a/Source/Filtering/imstkCleanMesh.cpp b/Source/Filtering/imstkCleanMesh.cpp index 3c3c752a08a1d3de682177b626bc1e6898f64ddf..55a40d8955c99361617b02807d6404d807f36ead 100644 --- a/Source/Filtering/imstkCleanMesh.cpp +++ b/Source/Filtering/imstkCleanMesh.cpp @@ -31,9 +31,9 @@ namespace imstk { CleanMesh::CleanMesh() { - setInputPortReq<SurfaceMesh>(0); - setNumberOfInputPorts(1); + setRequiredInputType<SurfaceMesh>(0); + setNumberOfOutputPorts(1); setOutput(std::make_shared<SurfaceMesh>()); } diff --git a/Source/Filtering/imstkExtractEdges.cpp b/Source/Filtering/imstkExtractEdges.cpp index 12e94a658f1f00783b13d2ed16f4afa0582bfdee..01d76e5f6b0d60c72ea28974092ec075f88eb271 100644 --- a/Source/Filtering/imstkExtractEdges.cpp +++ b/Source/Filtering/imstkExtractEdges.cpp @@ -32,9 +32,9 @@ namespace imstk { ExtractEdges::ExtractEdges() { - setInputPortReq<SurfaceMesh>(0); - setNumberOfInputPorts(1); + setRequiredInputType<SurfaceMesh>(0); + setNumberOfOutputPorts(1); setOutput(std::make_shared<LineMesh>()); } diff --git a/Source/Filtering/imstkImageDistanceTransform.cpp b/Source/Filtering/imstkImageDistanceTransform.cpp index 660e8cce3aed38b826e1c6aee7f1a84bdc7290ca..cae9e0fba0646f1eaf77d139741438cb88fb688b 100644 --- a/Source/Filtering/imstkImageDistanceTransform.cpp +++ b/Source/Filtering/imstkImageDistanceTransform.cpp @@ -34,9 +34,9 @@ namespace imstk { ImageDistanceTransform::ImageDistanceTransform() { - setInputPortReq<ImageData>(0); - setNumberOfInputPorts(1); + setRequiredInputType<ImageData>(0); + setNumberOfOutputPorts(1); setOutput(std::make_shared<ImageData>(), 0); } diff --git a/Source/Filtering/imstkImageGradient.cpp b/Source/Filtering/imstkImageGradient.cpp index e1719dc0adfc1a6c983a2f2fc41ff72cd29678d1..4095e2d1e749f30a0716b623d71dde61b4068aa6 100644 --- a/Source/Filtering/imstkImageGradient.cpp +++ b/Source/Filtering/imstkImageGradient.cpp @@ -32,9 +32,9 @@ namespace imstk { ImageGradient::ImageGradient() { - setInputPortReq<ImageData>(0); - setNumberOfInputPorts(1); + setRequiredInputType<ImageData>(0); + setNumberOfOutputPorts(1); setOutput(std::make_shared<PointSet>()); } diff --git a/Source/Filtering/imstkImageResample.cpp b/Source/Filtering/imstkImageResample.cpp index 153655af959ad438c14f552436f6bd89fe17a6a1..ab647500127c83e490e7887d97661d260b169a87 100644 --- a/Source/Filtering/imstkImageResample.cpp +++ b/Source/Filtering/imstkImageResample.cpp @@ -33,9 +33,9 @@ namespace imstk { ImageResample::ImageResample() { - setInputPortReq<ImageData>(0); - setNumberOfInputPorts(1); + setRequiredInputType<ImageData>(0); + setNumberOfOutputPorts(1); setOutput(std::make_shared<ImageData>()); } diff --git a/Source/Filtering/imstkImageReslice.cpp b/Source/Filtering/imstkImageReslice.cpp index ab24e5d4e45628e8a2a179f4cf745e8dad423849..97d5a5cdd7a3b31df9aa46918abf362144d6f770 100644 --- a/Source/Filtering/imstkImageReslice.cpp +++ b/Source/Filtering/imstkImageReslice.cpp @@ -32,9 +32,9 @@ namespace imstk { ImageReslice::ImageReslice() { - setInputPortReq<ImageData>(0); - setNumberOfInputPorts(1); + setRequiredInputType<ImageData>(0); + setNumberOfOutputPorts(1); setOutput(std::make_shared<ImageData>()); } diff --git a/Source/Filtering/imstkImplicitGeometryToImageData.cpp b/Source/Filtering/imstkImplicitGeometryToImageData.cpp index 0cc636b4c6345548d5463b132c76d3325747a64e..1f8aa74697226e021bfef7cad612dcb9631544d5 100644 --- a/Source/Filtering/imstkImplicitGeometryToImageData.cpp +++ b/Source/Filtering/imstkImplicitGeometryToImageData.cpp @@ -30,9 +30,9 @@ namespace imstk { ImplicitGeometryToImageData::ImplicitGeometryToImageData() { - setInputPortReq<ImplicitGeometry>(0); - setNumberOfInputPorts(1); + setRequiredInputType<ImplicitGeometry>(0); + setNumberOfOutputPorts(1); setOutput(std::make_shared<ImageData>()); } diff --git a/Source/Filtering/imstkLocalMarchingCubes.cpp b/Source/Filtering/imstkLocalMarchingCubes.cpp index 331dc08084ff5abcffb468c999c4f222a645546f..97bed7704edab9f12b10f0337018427fc64570b6 100644 --- a/Source/Filtering/imstkLocalMarchingCubes.cpp +++ b/Source/Filtering/imstkLocalMarchingCubes.cpp @@ -360,9 +360,9 @@ lerp(double val1, double val2, double isovalue, double spacing) LocalMarchingCubes::LocalMarchingCubes() { - setInputPortReq<ImageData>(0); - setNumberOfInputPorts(1); + setRequiredInputType<ImageData>(0); + setNumberOfOutputPorts(0); } diff --git a/Source/Filtering/imstkQuadricDecimate.cpp b/Source/Filtering/imstkQuadricDecimate.cpp index 230ab092ae24b8b67c254f25ec2741e31118f00c..bf09650906bd939411624cdcf48d7953b7c10a85 100644 --- a/Source/Filtering/imstkQuadricDecimate.cpp +++ b/Source/Filtering/imstkQuadricDecimate.cpp @@ -31,7 +31,7 @@ namespace imstk QuadricDecimate::QuadricDecimate() : m_VolumePreserving(true), m_TargetReduction(0.6) { - setInputPortReq<SurfaceMesh>(0); + setRequiredInputType<SurfaceMesh>(0); setNumberOfInputPorts(1); setNumberOfOutputPorts(1); diff --git a/Source/Filtering/imstkSelectEnclosedPoints.cpp b/Source/Filtering/imstkSelectEnclosedPoints.cpp index 9ca99062980b2fb19a51a2cbf5124f3260f40f62..4d708db960939c50c189f2084e7d043c01fda130 100644 --- a/Source/Filtering/imstkSelectEnclosedPoints.cpp +++ b/Source/Filtering/imstkSelectEnclosedPoints.cpp @@ -32,10 +32,10 @@ namespace imstk { SelectEnclosedPoints::SelectEnclosedPoints() { - setInputPortReq<SurfaceMesh>(0); - setInputPortReq<PointSet>(1); - setNumberOfInputPorts(2); + setRequiredInputType<SurfaceMesh>(0); + setRequiredInputType<PointSet>(1); + setNumberOfOutputPorts(1); setOutput(std::make_shared<PointSet>()); } diff --git a/Source/Filtering/imstkSurfaceMeshCut.cpp b/Source/Filtering/imstkSurfaceMeshCut.cpp index 583bc1f39a9777189b40911273aa13e70801ad31..03c0b96899756dc2627ac12b74db16192b117fc9 100644 --- a/Source/Filtering/imstkSurfaceMeshCut.cpp +++ b/Source/Filtering/imstkSurfaceMeshCut.cpp @@ -32,9 +32,9 @@ namespace imstk { SurfaceMeshCut::SurfaceMeshCut() { - setInputPortReq<SurfaceMesh>(0); - setNumberOfInputPorts(1); + setRequiredInputType<SurfaceMesh>(0); + setNumberOfOutputPorts(1); setOutput(std::make_shared<SurfaceMesh>()); diff --git a/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp b/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp index 204651aaa18e5f592fb99a0096e841f097c235b9..a209904b149bec00f19a2819de792f23452c1a75 100644 --- a/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp +++ b/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp @@ -202,9 +202,9 @@ computeFullDT(std::shared_ptr<ImageData> imageData, std::shared_ptr<SurfaceMesh> SurfaceMeshDistanceTransform::SurfaceMeshDistanceTransform() { - setInputPortReq<SurfaceMesh>(0); - setNumberOfInputPorts(1); + setRequiredInputType<SurfaceMesh>(0); + setNumberOfOutputPorts(1); setOutput(std::make_shared<ImageData>(), 0); } diff --git a/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp b/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp index b3127d94f7022215a37a1d44f99fc5bde031d3de..0151b05c6434b086afc1172c9233ce78cc384b47 100644 --- a/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp +++ b/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp @@ -32,9 +32,9 @@ namespace imstk { SurfaceMeshFlyingEdges::SurfaceMeshFlyingEdges() { - setInputPortReq<ImageData>(0); - setNumberOfInputPorts(1); + setRequiredInputType<ImageData>(0); + setNumberOfOutputPorts(1); setOutput(std::make_shared<SurfaceMesh>()); } diff --git a/Source/Filtering/imstkSurfaceMeshImageMask.cpp b/Source/Filtering/imstkSurfaceMeshImageMask.cpp index d40be31dec8afb8f7dcef4cd3ea916c92e576438..251cc4e353f77ac9b78168e6aae0fca2c86eb709 100644 --- a/Source/Filtering/imstkSurfaceMeshImageMask.cpp +++ b/Source/Filtering/imstkSurfaceMeshImageMask.cpp @@ -35,10 +35,10 @@ namespace imstk { SurfaceMeshImageMask::SurfaceMeshImageMask() { - setInputPortReq<SurfaceMesh>(0); - setInputPortReq<ImageData>(1); - setNumberOfInputPorts(2); + setRequiredInputType<SurfaceMesh>(0); + setOptionalInputType<ImageData>(1); + setNumberOfOutputPorts(1); setOutput(std::make_shared<ImageData>(), 0); } diff --git a/Source/Filtering/imstkSurfaceMeshSmoothen.cpp b/Source/Filtering/imstkSurfaceMeshSmoothen.cpp index 35432eb3b724a06274913fcc855e7ce89c72eece..48d9cafc8261581e388e1d0c368125983897b404 100644 --- a/Source/Filtering/imstkSurfaceMeshSmoothen.cpp +++ b/Source/Filtering/imstkSurfaceMeshSmoothen.cpp @@ -30,9 +30,9 @@ namespace imstk { SurfaceMeshSmoothen::SurfaceMeshSmoothen() { - setInputPortReq<SurfaceMesh>(0); - setNumberOfInputPorts(1); + setRequiredInputType<SurfaceMesh>(0); + setNumberOfOutputPorts(1); setOutput(std::make_shared<SurfaceMesh>()); } diff --git a/Source/Filtering/imstkSurfaceMeshSubdivide.cpp b/Source/Filtering/imstkSurfaceMeshSubdivide.cpp index 6e15d9e3efdbf143a8c980d7814f0e104d2cb5ce..393540127bbfcea085de8007ae76602f7f5cb1a6 100644 --- a/Source/Filtering/imstkSurfaceMeshSubdivide.cpp +++ b/Source/Filtering/imstkSurfaceMeshSubdivide.cpp @@ -32,9 +32,9 @@ namespace imstk { SurfaceMeshSubdivide::SurfaceMeshSubdivide() { - setInputPortReq<SurfaceMesh>(0); - setNumberOfInputPorts(1); + setRequiredInputType<SurfaceMesh>(0); + setNumberOfOutputPorts(1); setOutput(std::make_shared<SurfaceMesh>()); } diff --git a/Source/Filtering/imstkSurfaceMeshTextureProject.cpp b/Source/Filtering/imstkSurfaceMeshTextureProject.cpp index e728a21130a49dca496114d12ad1fa2ecd874488..720f2fdc12b2e70746d1b061e9e87ff4ba6ae464 100644 --- a/Source/Filtering/imstkSurfaceMeshTextureProject.cpp +++ b/Source/Filtering/imstkSurfaceMeshTextureProject.cpp @@ -105,10 +105,10 @@ baryInterpolate(T v1, T v2, T v3, Vec3d uvw) SurfaceMeshTextureProject::SurfaceMeshTextureProject() { - setInputPortReq<SurfaceMesh>(0); - setInputPortReq<SurfaceMesh>(1); - setNumberOfInputPorts(2); + setRequiredInputType<SurfaceMesh>(0); + setRequiredInputType<SurfaceMesh>(1); + setNumberOfOutputPorts(1); setOutput(std::make_shared<SurfaceMesh>(), 0); } diff --git a/Source/FilteringCore/CMakeLists.txt b/Source/FilteringCore/CMakeLists.txt index 8b9c7d72792dc9745ea2d76392f1e7bc04ee084c..3ca75375a0a2136bed648cbf16ba75641bcffd4c 100644 --- a/Source/FilteringCore/CMakeLists.txt +++ b/Source/FilteringCore/CMakeLists.txt @@ -14,3 +14,10 @@ imstk_add_library( FilteringCore Geometry DataStructures ${VTK_LIBRARIES}) + +#----------------------------------------------------------------------------- +# Testing +#----------------------------------------------------------------------------- +if( ${PROJECT_NAME}_BUILD_TESTING ) + add_subdirectory(Testing) +endif() \ No newline at end of file diff --git a/Source/FilteringCore/Testing/CMakeLists.txt b/Source/FilteringCore/Testing/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6e2536781a7fba5c9e009fef7f9775965dbc8a74 --- /dev/null +++ b/Source/FilteringCore/Testing/CMakeLists.txt @@ -0,0 +1,2 @@ +include(imstkAddTest) +imstk_add_test( FilteringCore ) \ No newline at end of file diff --git a/Source/FilteringCore/Testing/GeometryAlgorithmTest.cpp b/Source/FilteringCore/Testing/GeometryAlgorithmTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d365a5dfee3229a1a1a03fe1a3963c212a41b5fe --- /dev/null +++ b/Source/FilteringCore/Testing/GeometryAlgorithmTest.cpp @@ -0,0 +1,154 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include <gtest/gtest.h> + +#include <imstkGeometryAlgorithm.h> +#include <imstkSurfaceMesh.h> +#include <imstkSphere.h> + +using namespace imstk; +namespace +{ +class MockAlgorithm : public GeometryAlgorithm +{ +public: + + bool areInputsValid() const override + { + return GeometryAlgorithm::areInputsValid(); + } + + void requestUpdate() override + { + } +}; + +class EmptyAlgorithm : public MockAlgorithm +{ +public: + EmptyAlgorithm() + { + setNumberOfInputPorts(4); + } +}; + +class ExpectingAlgorithm : public MockAlgorithm +{ +public: + ExpectingAlgorithm() + { + setNumberOfInputPorts(4); + setRequiredInputType<SurfaceMesh>(1); + } +}; + +class ExpectingOptional : public MockAlgorithm +{ +public: + ExpectingOptional() + { + setNumberOfInputPorts(4); + setOptionalInputType<SurfaceMesh>(1); + } +}; + +class ExpectingAllKinds : public MockAlgorithm +{ +public: + ExpectingAllKinds() + { + setNumberOfInputPorts(5); + setRequiredInputType<SurfaceMesh>(1); + setRequiredInputType<Sphere>(2); + setOptionalInputType<SurfaceMesh>(3); + setOptionalInputType<Sphere>(4); + } +}; +} + +TEST(imstkGeometryAlgorithmTest, no_expectations) +{ + EmptyAlgorithm a; + + EXPECT_TRUE(a.areInputsValid()); + + auto mesh = std::make_shared<SurfaceMesh>(); + a.setInput(mesh, 0); + EXPECT_TRUE(a.areInputsValid()); +} + +TEST(imstkGeometryAlgorithmTest, required_only) +{ + ExpectingAlgorithm a; + + EXPECT_FALSE(a.areInputsValid()); + + auto mesh = std::make_shared<SurfaceMesh>(); + a.setInput(mesh, 1); + EXPECT_TRUE(a.areInputsValid()); + + auto sphere = std::make_shared<Sphere>(); + a.setInput(sphere, 1); + EXPECT_FALSE(a.areInputsValid()); +} + +TEST(imstkGeometryAlgorithmTest, optional_only) +{ + ExpectingOptional a; + + // optional is true when there isn't a value + EXPECT_TRUE(a.areInputsValid()); + + // should be true, expected is mesh + auto mesh = std::make_shared<SurfaceMesh>(); + a.setInput(mesh, 1); + EXPECT_TRUE(a.areInputsValid()); + + // should be false ... mesh is expected + auto sphere = std::make_shared<Sphere>(); + a.setInput(sphere, 1); + EXPECT_FALSE(a.areInputsValid()); +} + +TEST(imstkGeometryAlgorithmTest, all_kinds) +{ + ExpectingAllKinds a; + + EXPECT_FALSE(a.areInputsValid()); + + auto mesh = std::make_shared<SurfaceMesh>(); + auto sphere = std::make_shared<Sphere>(); + a.setInput(mesh, 1); + EXPECT_FALSE(a.areInputsValid()); + a.setInput(sphere, 2); + EXPECT_TRUE(a.areInputsValid()); + + a.setInput(mesh, 3); + EXPECT_TRUE(a.areInputsValid()); + a.setInput(sphere, 4); + EXPECT_TRUE(a.areInputsValid()); + + a.setInput(sphere, 3); + EXPECT_FALSE(a.areInputsValid()); + a.setInput(mesh, 4); + EXPECT_FALSE(a.areInputsValid()); +} \ No newline at end of file diff --git a/Source/FilteringCore/imstkGeometryAlgorithm.cpp b/Source/FilteringCore/imstkGeometryAlgorithm.cpp index 8f11baac28f1a9dec888555bbd84d8047851928a..2f6392b11ef2987d1f89caee5b6b242204c73cd3 100644 --- a/Source/FilteringCore/imstkGeometryAlgorithm.cpp +++ b/Source/FilteringCore/imstkGeometryAlgorithm.cpp @@ -17,7 +17,7 @@ See the License for the specific language governing permissions and limitations under the License. -=========================================================================*/ + =========================================================================*/ #include "imstkGeometryAlgorithm.h" #include "imstkGeometry.h" @@ -32,7 +32,9 @@ GeometryAlgorithm::setInput(std::shared_ptr<Geometry> inputGeometry, size_t port { LOG(WARNING) << "Tried to set input " << port << " on filter with " << m_NumberOfInputPorts << " ports"; } + m_inputs[port] = inputGeometry; + areInputsValid(); } void @@ -74,30 +76,39 @@ GeometryAlgorithm::setNumberOfOutputPorts(size_t numPorts) } bool -GeometryAlgorithm::checkInputRequirements( - const std::unordered_map<size_t, std::shared_ptr<Geometry>>& inputs, - const std::unordered_map<size_t, PortReq>& inputPortReqs) +GeometryAlgorithm::areInputsValid() const { // Check input types - for (auto i : inputs) + for (const auto& port : m_inputs) { - const size_t portId = i.first; - if (i.second == nullptr) + const size_t portId = port.first; + Geometry* input = port.second.get(); + auto found = m_requiredTypeChecks.find(portId); + if (found != m_requiredTypeChecks.cend()) { - LOG(WARNING) << "GeometryAlgorithm input " << portId << " missing!"; - return false; + // Require Input: can't be null has to succeed type check + if (port.second == nullptr) + { + LOG(WARNING) << "GeometryAlgorithm input " << portId << " missing!"; + return false; + } + else if (!found->second(input)) + { + LOG(WARNING) << "GeometryAlgorithm received invalid geometry type \"" << + m_inputs.at(portId)->getTypeName() << "\" in port " << portId; + return false; + } + continue; } - // If the user added a requirement for this port - if (inputPortReqs.count(portId) != 0) + found = m_optionalTypeChecks.find(portId); + if (found != m_optionalTypeChecks.cend()) { - // Check if it's valid - if (!inputPortReqs.at(portId).isValid(i.second)) + // Require Input: may be null, if not has succeed type check + if (input != nullptr && !found->second(input)) { - LOG(WARNING) << "GeometryAlgorithm recieved invalid geometry type \"" << - inputs.at(portId)->getTypeName() << "\" in port " << portId; - /*LOG(WARNING) << "GeometryAlgorithm required port " << portId; << - " to be of type " << inputPortReqs.at(portId).validGeomName();*/ + LOG(WARNING) << "GeometryAlgorithm received invalid geometry type \"" << + m_inputs.at(portId)->getTypeName() << "\" in port " << portId; return false; } } diff --git a/Source/FilteringCore/imstkGeometryAlgorithm.h b/Source/FilteringCore/imstkGeometryAlgorithm.h index a2bc40ca71e9420420ccc20650265d09a2e1d635..e3ebb04bbed48f6dca84c95f7614113eba4b65d2 100644 --- a/Source/FilteringCore/imstkGeometryAlgorithm.h +++ b/Source/FilteringCore/imstkGeometryAlgorithm.h @@ -30,81 +30,71 @@ namespace imstk { class Geometry; +/// Returns a function that for instances with common Base classes determines +/// whether it is of the Target type +template<class Base, class Target> +std::function<bool(Base*)> +makeTypeCheck() +{ + return [](Base* p) { + return (dynamic_cast<Target*>(p) != nullptr); + }; +} + /// /// \class GeometryAlgorithm /// -/// \brief Base abstract class for geometry algorithms. GeometryAlgorithms take N input -/// geometries and produce N output geometries. Sublcasses should implement requestUpdate +/// \brief Abstract base class for geometry algorithms. GeometryAlgorithms take N input +/// geometries and produce N output geometries. Subclasses should implement requestUpdate /// to do algorithm logic. Subclasses may also setInputPortReq to require an input to be /// a certain type. /// class GeometryAlgorithm { -public: - /// - /// \brief Used for type erasure of the port requirements - /// \todo: Type names can't be deduced for abstract classes. - /// Would be nice to have static type name as well - /// - class PortReq - { - public: - struct BaseReq - { - virtual ~BaseReq() = default; - virtual bool isValid(std::shared_ptr<Geometry> geom) const = 0; - //virtual std::string name() const = 0; - }; - - template<typename T> - struct Requirement : public BaseReq - { - virtual ~Requirement() override = default; - bool isValid(std::shared_ptr<Geometry> geom) const override - { - return std::dynamic_pointer_cast<T>(geom) != nullptr; - } - - //std::string name() const override - //{ - // T t; // Can't use - // return t.getTypeName(); - //} - }; - - std::shared_ptr<BaseReq> req = nullptr; - - public: - PortReq() = default; - - template<typename T> - PortReq(T*) : req(std::make_shared<Requirement<T>>()) { } - - bool isValid(std::shared_ptr<Geometry> geom) const { return req->isValid(geom); } - //std::string validGeomName() const { return req->name(); } - }; - protected: GeometryAlgorithm() = default; public: virtual ~GeometryAlgorithm() = default; -public: /// /// \brief Returns input geometry given port, returns nullptr if doesn't exist /// - std::shared_ptr<Geometry> getInput(size_t port = 0) const { return (m_inputs.count(port) == 0) ? nullptr : m_inputs.at(port); } + std::shared_ptr<Geometry> getInput(size_t port = 0) const + { + return (m_inputs.count(port) == 0) ? nullptr : m_inputs.at(port); + } + /// /// \brief Returns output geometry given port, returns nullptr if doesn't exist /// - std::shared_ptr<Geometry> getOutput(size_t port = 0) const { return m_outputs.count(port) == 0 ? nullptr : m_outputs.at(port); } + std::shared_ptr<Geometry> getOutput(size_t port = 0) const + { + return m_outputs.count(port) == 0 ? nullptr : m_outputs.at(port); + } /// /// \brief Set the input at the port /// void setInput(std::shared_ptr<Geometry> inputGeometry, size_t port = 0); + /// + /// \brief Do the actual algorithm + /// + void update() + { + if (!areInputsValid()) + { + LOG(WARNING) << "GeometryAlgorithm failed to run, inputs not satisfied"; + return; + } + //if (m_modified) + //{ + requestUpdate(); + //} + //m_modified = false; + } + protected: /// /// \brief Set the output at the port @@ -125,54 +115,50 @@ protected: void setNumberOfOutputPorts(size_t numPorts); /// - /// \brief Set a type requirement on the inputs, it will check when running - /// the algorithm and warn at runtime + /// \brief Declares the type for the port with the given number, also defines that + /// the give port is required for the filter to run correctly /// template<typename T> - void setInputPortReq(size_t port) + void setRequiredInputType(size_t port) { - T* ptr = nullptr; - m_inputPortTypeReqs[port] = PortReq(ptr); + CHECK(m_optionalTypeChecks.find(port) == m_optionalTypeChecks.end()) + << "There is already an optional type for this port " << port << ", can't assign another one."; + m_requiredTypeChecks[port] = makeTypeCheck<Geometry, T>(); } -public: - //void modified() { this->m_modified = true; } - /// - /// \brief Do the actual algorithm + /// \brief Declares the type for the port with the given number, the data + /// for this port is optional and may be omitted /// - void update() + template<typename T> + void setOptionalInputType(size_t port) { - if (!checkInputRequirements(m_inputs, m_inputPortTypeReqs)) - { - LOG(WARNING) << "GeometryAlgorithm failed to run, inputs not satisfied"; - return; - } - //if (m_modified) - //{ - requestUpdate(); - //} - //m_modified = false; + CHECK(m_requiredTypeChecks.find(port) == m_requiredTypeChecks.end()) + << "There is already a required type for port " << port << " , can't assign another one."; + m_optionalTypeChecks[port] = makeTypeCheck<Geometry, T>(); } -protected: /// - /// \brief Check inputs are correct - /// \return true if all inputs match the requirements, false if not + /// \brief Users can implement this for the logic to be run /// - virtual bool checkInputRequirements( - const std::unordered_map<size_t, std::shared_ptr<Geometry>>& inputs, - const std::unordered_map<size_t, PortReq>& inputPortReqs); + virtual void requestUpdate() = 0; /// - /// \brief Users can implement this for the logic to be run + /// \brief Check inputs are correct + /// \return true if all inputs match the requirements, false if not /// - virtual void requestUpdate() = 0; + virtual bool areInputsValid() const; private: - std::unordered_map<size_t, PortReq> m_inputPortTypeReqs; // The desired types of the input + using GeometryCheck = std::function<bool (Geometry*)>; + using TypeCheckContainer = std::unordered_map<size_t, GeometryCheck>; + + std::unordered_map<size_t, GeometryCheck> m_requiredTypeChecks; + std::unordered_map<size_t, GeometryCheck> m_optionalTypeChecks; + std::unordered_map<size_t, std::shared_ptr<Geometry>> m_inputs; std::unordered_map<size_t, std::shared_ptr<Geometry>> m_outputs; + //bool m_modified = true; size_t m_NumberOfInputPorts = 1; size_t m_NumberOfOutputPorts = 1;