diff --git a/src/OpenSimCreator/CMakeLists.txt b/src/OpenSimCreator/CMakeLists.txt index cb06e47868..17600743a4 100644 --- a/src/OpenSimCreator/CMakeLists.txt +++ b/src/OpenSimCreator/CMakeLists.txt @@ -411,7 +411,7 @@ add_library(OpenSimCreator STATIC Utils/SimTKHelpers.h Utils/TPS3D.cpp Utils/TPS3D.h - ) + ) # OpenSimCreatorConfig.h # diff --git a/src/OpenSimCreator/Documents/ModelWarper/IValidateable.cpp b/src/OpenSimCreator/Documents/ModelWarper/IValidateable.cpp index 6345fc0eca..5d5a745626 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/IValidateable.cpp +++ b/src/OpenSimCreator/Documents/ModelWarper/IValidateable.cpp @@ -6,10 +6,10 @@ using namespace osc::mow; -ValidationCheckState osc::mow::IValidateable::implState() const +ValidationCheckState osc::mow::IValidateable::implState(const WarpableModel& root) const { ValidationCheckState worst = ValidationCheckState::Ok; - for (const auto& c : validate()) { + for (const auto& c : validate(root)) { worst = max(worst, c.state()); if (worst == ValidationCheckState::Error) { break; diff --git a/src/OpenSimCreator/Documents/ModelWarper/IValidateable.h b/src/OpenSimCreator/Documents/ModelWarper/IValidateable.h index a4f2258d6b..1bc3902dcc 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/IValidateable.h +++ b/src/OpenSimCreator/Documents/ModelWarper/IValidateable.h @@ -5,9 +5,12 @@ #include +namespace osc::mow { class WarpableModel; } + namespace osc::mow { - // an interface to an object that can be runtime-validated + // an interface to an object that can be runtime-validated against the + // root document class IValidateable { protected: IValidateable() = default; @@ -19,10 +22,12 @@ namespace osc::mow friend bool operator==(const IValidateable&, const IValidateable&) = default; public: virtual ~IValidateable() noexcept = default; - std::vector validate() const { return implValidate(); } - ValidationCheckState state() const { return implState(); } + std::vector validate(const WarpableModel& root) const { return implValidate(root); } + ValidationCheckState state(const WarpableModel& root) const { return implState(root); } + private: - virtual std::vector implValidate() const { return {}; } - virtual ValidationCheckState implState() const; // by default, gets the least-valid entry returned by `validate()` + virtual std::vector implValidate(const WarpableModel&) const { return {}; } + // by default, gets the least-valid entry returned by `validate()` + virtual ValidationCheckState implState(const WarpableModel&) const; }; } diff --git a/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.cpp b/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.cpp index 8da8eace3d..a6ed129353 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.cpp +++ b/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.cpp @@ -23,7 +23,7 @@ std::vector osc::mow::IdentityFrameWarperFactory::implWarpDetails() return {}; } -std::vector osc::mow::IdentityFrameWarperFactory::implValidate() const +std::vector osc::mow::IdentityFrameWarperFactory::implValidate(const WarpableModel&) const { return { ValidationCheckResult{"this is an identity warp (i.e. it ignores warping this frame altogether)", ValidationCheckState::Warning}, diff --git a/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.h b/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.h index e9d02e6768..15286ff558 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.h +++ b/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.h @@ -20,7 +20,7 @@ namespace osc::mow private: std::unique_ptr implClone() const override; std::vector implWarpDetails() const override; - std::vector implValidate() const override; + std::vector implValidate(const WarpableModel&) const override; std::unique_ptr implTryCreateFrameWarper(const WarpableModel&) const override; }; } diff --git a/src/OpenSimCreator/Documents/ModelWarper/ModelWarperConfiguration.h b/src/OpenSimCreator/Documents/ModelWarper/ModelWarperConfiguration.h index 87576fedbc..01487ccc73 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/ModelWarperConfiguration.h +++ b/src/OpenSimCreator/Documents/ModelWarper/ModelWarperConfiguration.h @@ -1,5 +1,9 @@ #pragma once +#include +#include +#include + #include #include #include @@ -43,9 +47,46 @@ namespace osc::mow State _state = State::None; }; + // an abstract interface to something that is capable of warping one specific component in + // the model + // + // a `ComponentWarpingStrategy` produces this after matching the component, validating it against, + // the rest of the model, etc. + class IComponentWarper { + protected: + IComponentWarper() = default; + IComponentWarper(const IComponentWarper&) = default; + IComponentWarper(IComponentWarper&&) noexcept = default; + IComponentWarper& operator=(const IComponentWarper&) = default; + IComponentWarper& operator=(IComponentWarper&&) noexcept = default; + public: + virtual ~IComponentWarper() noexcept = default; + + void warpInPlace(const WarpableModel& model, const OpenSim::Component& source, OpenSim::Component& targetCopy) + { + implWarpInPlace(model, source, targetCopy); + } + private: + virtual void implWarpInPlace(const WarpableModel&, const OpenSim::Component& source, OpenSim::Component& targetCopy) = 0; + }; + + // concrete implementation of an `IComponentWarper` that does nothing + // + // (handy as a stand-in during development) + class IdentityComponentWarper : public IComponentWarper { + private: + void implWarpInPlace(const WarpableModel&, const OpenSim::Component&, OpenSim::Component&) override + {} + }; + // abstract interface to a component that is capable of warping `n` other // components (`StrategyTargets`) during a model warp - class ComponentWarpingStrategy : public OpenSim::Component { + class ComponentWarpingStrategy : + public OpenSim::Component, + public ICloneable, + public IWarpDetailProvider, + public IValidateable { + OpenSim_DECLARE_ABSTRACT_OBJECT(ComponentWarpingStrategy, OpenSim::Component); public: OpenSim_DECLARE_LIST_PROPERTY(StrategyTargets, std::string, "a sequence of strategy target strings that this strategy applies to"); @@ -91,9 +132,15 @@ namespace osc::mow } return best; } + + std::unique_ptr createWarper(const WarpableModel& model, const OpenSim::Component& component) + { + return implCreateWarper(model, component); + } private: virtual const std::type_info& implGetTargetComponentTypeInfo() const = 0; virtual bool implIsMatchForComponentType(const OpenSim::Component&) const = 0; + virtual std::unique_ptr implCreateWarper(const WarpableModel&, const OpenSim::Component&) = 0; void extendFinalizeFromProperties() override { @@ -101,14 +148,14 @@ namespace osc::mow assertStrategyTargetsAreUnique(); } - void assertStrategyTargetsNotEmpty() + void assertStrategyTargetsNotEmpty() const { if (getProperty_StrategyTargets().empty()) { OPENSIM_THROW_FRMOBJ(OpenSim::Exception, "The property of this component must be populated with at least one entry"); } } - void assertStrategyTargetsAreUnique() + void assertStrategyTargetsAreUnique() const { const int numStrategyTargets = getProperty_StrategyTargets().size(); std::unordered_set uniqueStrategyTargets; @@ -158,6 +205,20 @@ namespace osc::mow public: // PointSources private: + std::unique_ptr implClone() const override + { + return std::make_unique(*this); + } + + std::vector implWarpDetails() const override + { + return {}; + } + + std::unique_ptr implCreateWarper(const WarpableModel&, const OpenSim::Component&) override + { + return std::make_unique(); + } }; // concrete implementation of an `OffsetFrameWarpingStrategy` in which the @@ -165,6 +226,21 @@ namespace osc::mow // the model warp class ProduceErrorOffsetFrameWarpingStrategy final : public OffsetFrameWarpingStrategy { OpenSim_DECLARE_CONCRETE_OBJECT(ProduceErrorOffsetFrameWarpingStrategy, OffsetFrameWarpingStrategy); + private: + std::unique_ptr implClone() const override + { + return std::make_unique(*this); + } + + std::vector implWarpDetails() const override + { + return {}; + } + + std::unique_ptr implCreateWarper(const WarpableModel&, const OpenSim::Component&) override + { + return std::make_unique(); + } }; // concrete implementation of an `OffsetFrameWarpingStrategy` in which the implementation @@ -172,6 +248,21 @@ namespace osc::mow // the destination model with no modifications class IdentityOffsetFrameWarpingStrategy final : public OffsetFrameWarpingStrategy { OpenSim_DECLARE_CONCRETE_OBJECT(IdentityOffsetFrameWarpingStrategy, OffsetFrameWarpingStrategy); + private: + std::unique_ptr implClone() const override + { + return std::make_unique(*this); + } + + std::vector implWarpDetails() const override + { + return {}; + } + + std::unique_ptr implCreateWarper(const WarpableModel&, const OpenSim::Component&) override + { + return std::make_unique(); + } }; // abstract interface to a component that is capable of warping `n` @@ -185,18 +276,63 @@ namespace osc::mow class ThinPlateSplineStationWarpingStrategy final : public StationWarpingStrategy { OpenSim_DECLARE_CONCRETE_OBJECT(ThinPlateSplineStationWarpingStrategy, StationWarpingStrategy); // MeshSources + private: + std::unique_ptr implClone() const override + { + return std::make_unique(*this); + } + + std::vector implWarpDetails() const override + { + return {}; + } + + std::unique_ptr implCreateWarper(const WarpableModel&, const OpenSim::Component&) override + { + return std::make_unique(); + } }; // concrete implementation of a `StationWarpingStrategy` in which the implementation should // produce a halting error rather than continuing with the model warp class ProduceErrorStationWarpingStrategy final : public StationWarpingStrategy { OpenSim_DECLARE_CONCRETE_OBJECT(ProduceErrorStationWarpingStrategy, StationWarpingStrategy); + private: + std::unique_ptr implClone() const override + { + return std::make_unique(*this); + } + + std::vector implWarpDetails() const override + { + return {}; + } + + std::unique_ptr implCreateWarper(const WarpableModel&, const OpenSim::Component&) override + { + return std::make_unique(); + } }; // concrete implementation of a `StationWarpingStrategy` in which the implementation should // just copy the station's postion (+parent) without any modification class IdentityStationWarpingStrategy final : public StationWarpingStrategy { OpenSim_DECLARE_CONCRETE_OBJECT(IdentityStationWarpingStrategy, StationWarpingStrategy); + private: + std::unique_ptr implClone() const override + { + return std::make_unique(*this); + } + + std::vector implWarpDetails() const override + { + return {}; + } + + std::unique_ptr implCreateWarper(const WarpableModel&, const OpenSim::Component&) override + { + return std::make_unique(); + } }; // top-level model warping configuration file diff --git a/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.cpp b/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.cpp index ddbea6a4a5..79c3ec1be8 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.cpp +++ b/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.cpp @@ -23,7 +23,7 @@ std::vector osc::mow::StationDefinedFrameWarperFactory::implWarpDeta return {}; } -std::vector osc::mow::StationDefinedFrameWarperFactory::implValidate() const +std::vector osc::mow::StationDefinedFrameWarperFactory::implValidate(const WarpableModel&) const { return { ValidationCheckResult{"this frame is automatically warped when the model warper warps all stations in the model", ValidationCheckState::Ok}, diff --git a/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.h b/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.h index 964f3febee..cd12b70f01 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.h +++ b/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.h @@ -24,7 +24,7 @@ namespace osc::mow private: std::unique_ptr implClone() const override; std::vector implWarpDetails() const override; - std::vector implValidate() const override; + std::vector implValidate(const WarpableModel&) const override; std::unique_ptr implTryCreateFrameWarper(const WarpableModel&) const override; }; } diff --git a/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.cpp b/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.cpp index c8031d6883..7f99aa8752 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.cpp +++ b/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.cpp @@ -279,7 +279,7 @@ std::vector osc::mow::TPSLandmarkPairWarperFactory::implWarpDetails( return rv; } -std::vector osc::mow::TPSLandmarkPairWarperFactory::implValidate() const +std::vector osc::mow::TPSLandmarkPairWarperFactory::implValidate(const WarpableModel&) const { std::vector rv; diff --git a/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.h b/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.h index ca0e243591..1d420376d4 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.h +++ b/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.h @@ -65,7 +65,7 @@ namespace osc::mow private: std::unique_ptr implClone() const override; std::vector implWarpDetails() const override; - std::vector implValidate() const override; + std::vector implValidate(const WarpableModel&) const override; std::unique_ptr implTryCreatePointWarper(const WarpableModel&) const override; std::filesystem::path m_SourceMeshAbsoluteFilepath; diff --git a/src/OpenSimCreator/Documents/ModelWarper/WarpableModel.cpp b/src/OpenSimCreator/Documents/ModelWarper/WarpableModel.cpp index 630fb0127f..ba07e6223d 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/WarpableModel.cpp +++ b/src/OpenSimCreator/Documents/ModelWarper/WarpableModel.cpp @@ -62,7 +62,7 @@ std::vector osc::mow::WarpableModel::details(const OpenSim::Mesh& me std::vector osc::mow::WarpableModel::validate(const OpenSim::Mesh& mesh) const { if (const IPointWarperFactory* p = m_MeshWarpLookup->find(GetAbsolutePathString(mesh))) { - return p->validate(); + return p->validate(*this); } else { return {ValidationCheckResult{"no mesh warp pairing found: this is probably an implementation error (try reloading?)", ValidationCheckState::Error}}; @@ -72,7 +72,7 @@ std::vector osc::mow::WarpableModel::validate(const OpenS ValidationCheckState osc::mow::WarpableModel::state(const OpenSim::Mesh& mesh) const { const IPointWarperFactory* p = m_MeshWarpLookup->find(GetAbsolutePathString(mesh)); - return p ? p->state() : ValidationCheckState::Error; + return p ? p->state(*this) : ValidationCheckState::Error; } const IPointWarperFactory* osc::mow::WarpableModel::findMeshWarp(const OpenSim::Mesh& mesh) const @@ -91,7 +91,7 @@ std::vector osc::mow::WarpableModel::details(const OpenSim::Physical std::vector osc::mow::WarpableModel::validate(const OpenSim::PhysicalOffsetFrame& pof) const { if (const IFrameWarperFactory* p = m_FrameWarpLookup->find(GetAbsolutePathString(pof))) { - return p->validate(); + return p->validate(*this); } else { return {ValidationCheckResult{"no frame warp method found: this is probably an implementation error (try reloading?)", ValidationCheckState::Error}}; @@ -102,7 +102,7 @@ ValidationCheckState osc::mow::WarpableModel::state( const OpenSim::PhysicalOffsetFrame& pof) const { const IFrameWarperFactory* p = m_FrameWarpLookup->find(GetAbsolutePathString(pof)); - return p ? p->state() : ValidationCheckState::Error; + return p ? p->state(*this) : ValidationCheckState::Error; } ValidationCheckState osc::mow::WarpableModel::state() const