From 59bf26af553b8b4768560975e3cfb8120441ffd2 Mon Sep 17 00:00:00 2001 From: Adam Kewley Date: Wed, 26 Jun 2024 12:51:25 +0200 Subject: [PATCH] Rename ModelWarpDocument --> WarpableModel --- src/OpenSimCreator/CMakeLists.txt | 4 +- .../ModelWarper/CachedModelWarper.cpp | 15 +-- .../Documents/ModelWarper/CachedModelWarper.h | 4 +- .../ModelWarper/IFrameWarperFactory.h | 6 +- .../ModelWarper/IPointWarperFactory.h | 6 +- .../IdentityFrameWarperFactory.cpp | 2 +- .../ModelWarper/IdentityFrameWarperFactory.h | 4 +- .../ModelWarper/OffsetFrameFallbackStrategy.h | 12 +++ .../StationDefinedFrameWarperFactory.cpp | 2 +- .../StationDefinedFrameWarperFactory.h | 4 +- .../TPSLandmarkPairWarperFactory.cpp | 4 +- .../TPSLandmarkPairWarperFactory.h | 2 +- ...odelWarpDocument.cpp => WarpableModel.cpp} | 50 +++++----- .../{ModelWarpDocument.h => WarpableModel.h} | 33 ++++--- .../ModelWarper/WarpableOpenSimComponent.h | 6 +- src/OpenSimCreator/UI/ModelWarper/UIState.cpp | 4 +- src/OpenSimCreator/UI/ModelWarper/UIState.h | 4 +- tests/TestOpenSimCreator/CMakeLists.txt | 2 +- .../ModelWarper/TestCachedModelWarper.cpp | 4 +- ...WarpDocument.cpp => TestWarpableModel.cpp} | 96 +++++++++---------- 20 files changed, 143 insertions(+), 121 deletions(-) create mode 100644 src/OpenSimCreator/Documents/ModelWarper/OffsetFrameFallbackStrategy.h rename src/OpenSimCreator/Documents/ModelWarper/{ModelWarpDocument.cpp => WarpableModel.cpp} (65%) rename src/OpenSimCreator/Documents/ModelWarper/{ModelWarpDocument.h => WarpableModel.h} (68%) rename tests/TestOpenSimCreator/Documents/ModelWarper/{TestModelWarpDocument.cpp => TestWarpableModel.cpp} (54%) diff --git a/src/OpenSimCreator/CMakeLists.txt b/src/OpenSimCreator/CMakeLists.txt index baf97a90e..a0b04e722 100644 --- a/src/OpenSimCreator/CMakeLists.txt +++ b/src/OpenSimCreator/CMakeLists.txt @@ -121,8 +121,6 @@ add_library(OpenSimCreator STATIC Documents/ModelWarper/MaybePairedLandmark.h Documents/ModelWarper/ModelWarpConfiguration.cpp Documents/ModelWarper/ModelWarpConfiguration.h - Documents/ModelWarper/ModelWarpDocument.cpp - Documents/ModelWarper/ModelWarpDocument.h Documents/ModelWarper/PointWarperFactories.cpp Documents/ModelWarper/PointWarperFactories.h Documents/ModelWarper/StationDefinedFrameWarperFactory.cpp @@ -131,6 +129,8 @@ add_library(OpenSimCreator STATIC Documents/ModelWarper/TPSLandmarkPairWarperFactory.h Documents/ModelWarper/ValidationCheckResult.h Documents/ModelWarper/ValidationCheckState.h + Documents/ModelWarper/WarpableModel.cpp + Documents/ModelWarper/WarpableModel.h Documents/ModelWarper/WarpableOpenSimComponent.h Documents/ModelWarper/WarpDetail.h diff --git a/src/OpenSimCreator/Documents/ModelWarper/CachedModelWarper.cpp b/src/OpenSimCreator/Documents/ModelWarper/CachedModelWarper.cpp index 7ddd7f85f..05813f0bc 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/CachedModelWarper.cpp +++ b/src/OpenSimCreator/Documents/ModelWarper/CachedModelWarper.cpp @@ -7,7 +7,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -25,7 +26,7 @@ using namespace osc::mow; namespace { std::unique_ptr WarpMesh( - const ModelWarpDocument& document, + const WarpableModel& document, const OpenSim::Model& model, const SimTK::State& state, const OpenSim::Mesh& inputMesh, @@ -88,7 +89,7 @@ namespace class osc::mow::CachedModelWarper::Impl final { public: - std::shared_ptr warp(const ModelWarpDocument& document) + std::shared_ptr warp(const WarpableModel& document) { if (document != m_PreviousDocument) { m_PreviousResult = createWarpedModel(document); @@ -97,7 +98,7 @@ class osc::mow::CachedModelWarper::Impl final { return m_PreviousResult; } - std::shared_ptr createWarpedModel(const ModelWarpDocument& document) + std::shared_ptr createWarpedModel(const WarpableModel& document) { // copy the model into an editable "warped" version OpenSim::Model warpedModel{document.model()}; @@ -130,7 +131,7 @@ class osc::mow::CachedModelWarper::Impl final { // iterate over each `PathPoint` in the model (incl. muscle points) and warp them by // figuring out how each relates to a mesh in the model // - // TODO: the `osc::mow::ModelWarpDocument` should handle figuring out each point's warper, because + // TODO: the `osc::mow::WarpableModel` should handle figuring out each point's warper, because // there are situations where there isn't a 1:1 relationship between meshes and bodies for (auto& pp : warpedModel.updComponentList()) { auto baseFramePath = pp.getParentFrame().findBaseFrame().getAbsolutePath(); @@ -199,7 +200,7 @@ class osc::mow::CachedModelWarper::Impl final { ); } private: - std::optional m_PreviousDocument; + std::optional m_PreviousDocument; std::shared_ptr m_PreviousResult; }; @@ -210,7 +211,7 @@ osc::mow::CachedModelWarper::CachedModelWarper(CachedModelWarper&&) noexcept = d CachedModelWarper& osc::mow::CachedModelWarper::operator=(CachedModelWarper&&) noexcept = default; osc::mow::CachedModelWarper::~CachedModelWarper() noexcept = default; -std::shared_ptr osc::mow::CachedModelWarper::warp(const ModelWarpDocument& document) +std::shared_ptr osc::mow::CachedModelWarper::warp(const WarpableModel& document) { return m_Impl->warp(document); } diff --git a/src/OpenSimCreator/Documents/ModelWarper/CachedModelWarper.h b/src/OpenSimCreator/Documents/ModelWarper/CachedModelWarper.h index 724a8f3d4..4bdc31bc5 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/CachedModelWarper.h +++ b/src/OpenSimCreator/Documents/ModelWarper/CachedModelWarper.h @@ -5,7 +5,7 @@ #include namespace OpenSim { class Model; } -namespace osc::mow { class ModelWarpDocument; } +namespace osc::mow { class WarpableModel; } namespace osc::mow { @@ -21,7 +21,7 @@ namespace osc::mow CachedModelWarper& operator=(CachedModelWarper&&) noexcept; ~CachedModelWarper() noexcept; - std::shared_ptr warp(const ModelWarpDocument&); + std::shared_ptr warp(const WarpableModel&); private: class Impl; std::unique_ptr m_Impl; diff --git a/src/OpenSimCreator/Documents/ModelWarper/IFrameWarperFactory.h b/src/OpenSimCreator/Documents/ModelWarper/IFrameWarperFactory.h index 1695e3f04..5fd66213c 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/IFrameWarperFactory.h +++ b/src/OpenSimCreator/Documents/ModelWarper/IFrameWarperFactory.h @@ -5,7 +5,7 @@ #include #include -namespace osc::mow { class ModelWarpDocument; } +namespace osc::mow { class WarpableModel; } namespace osc::mow { @@ -22,11 +22,11 @@ namespace osc::mow public: virtual ~IFrameWarperFactory() noexcept = default; - std::unique_ptr tryCreateFrameWarper(const ModelWarpDocument& document) const + std::unique_ptr tryCreateFrameWarper(const WarpableModel& document) const { return implTryCreateFrameWarper(document); } private: - virtual std::unique_ptr implTryCreateFrameWarper(const ModelWarpDocument& document) const = 0; + virtual std::unique_ptr implTryCreateFrameWarper(const WarpableModel& document) const = 0; }; } diff --git a/src/OpenSimCreator/Documents/ModelWarper/IPointWarperFactory.h b/src/OpenSimCreator/Documents/ModelWarper/IPointWarperFactory.h index 47932a649..afbd57055 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/IPointWarperFactory.h +++ b/src/OpenSimCreator/Documents/ModelWarper/IPointWarperFactory.h @@ -10,7 +10,7 @@ #include #include -namespace osc::mow { class ModelWarpDocument; } +namespace osc::mow { class WarpableModel; } namespace osc::mow { @@ -28,8 +28,8 @@ namespace osc::mow public: virtual ~IPointWarperFactory() = default; - std::unique_ptr tryCreatePointWarper(const ModelWarpDocument& document) const { return implTryCreatePointWarper(document); } + std::unique_ptr tryCreatePointWarper(const WarpableModel& document) const { return implTryCreatePointWarper(document); } private: - virtual std::unique_ptr implTryCreatePointWarper(const ModelWarpDocument&) const = 0; + virtual std::unique_ptr implTryCreatePointWarper(const WarpableModel&) const = 0; }; } diff --git a/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.cpp b/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.cpp index 2edfb962e..8da8eace3 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.cpp +++ b/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.cpp @@ -30,7 +30,7 @@ std::vector osc::mow::IdentityFrameWarperFactory::implVal }; } -std::unique_ptr osc::mow::IdentityFrameWarperFactory::implTryCreateFrameWarper(const ModelWarpDocument&) const +std::unique_ptr osc::mow::IdentityFrameWarperFactory::implTryCreateFrameWarper(const WarpableModel&) const { class IdentityFrameWarper final : public IFrameWarper { private: diff --git a/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.h b/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.h index cd670327e..e9d02e676 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.h +++ b/src/OpenSimCreator/Documents/ModelWarper/IdentityFrameWarperFactory.h @@ -9,7 +9,7 @@ #include #include -namespace osc::mow { class ModelWarpDocument; } +namespace osc::mow { class WarpableModel; } namespace osc::mow { @@ -21,6 +21,6 @@ namespace osc::mow std::unique_ptr implClone() const override; std::vector implWarpDetails() const override; std::vector implValidate() const override; - std::unique_ptr implTryCreateFrameWarper(const ModelWarpDocument&) const override; + std::unique_ptr implTryCreateFrameWarper(const WarpableModel&) const override; }; } diff --git a/src/OpenSimCreator/Documents/ModelWarper/OffsetFrameFallbackStrategy.h b/src/OpenSimCreator/Documents/ModelWarper/OffsetFrameFallbackStrategy.h new file mode 100644 index 000000000..85c15db7b --- /dev/null +++ b/src/OpenSimCreator/Documents/ModelWarper/OffsetFrameFallbackStrategy.h @@ -0,0 +1,12 @@ +#pragma once + +namespace osc +{ + enum class OffsetFrameFallbackStrategy { + Error, + Ignore, + WarpPosition, + NUM_OPTIONS, + Default = Error, + }; +} diff --git a/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.cpp b/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.cpp index 939d29624..ddbea6a4a 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.cpp +++ b/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.cpp @@ -30,7 +30,7 @@ std::vector osc::mow::StationDefinedFrameWarperFactory::i }; } -std::unique_ptr osc::mow::StationDefinedFrameWarperFactory::implTryCreateFrameWarper(const ModelWarpDocument&) const +std::unique_ptr osc::mow::StationDefinedFrameWarperFactory::implTryCreateFrameWarper(const WarpableModel&) const { class IdentityFrameWarper final : public IFrameWarper { private: diff --git a/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.h b/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.h index 8f0de4746..964f3febe 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.h +++ b/src/OpenSimCreator/Documents/ModelWarper/StationDefinedFrameWarperFactory.h @@ -9,7 +9,7 @@ #include #include -namespace osc::mow { class ModelWarpDocument; } +namespace osc::mow { class WarpableModel; } namespace osc::mow { @@ -25,6 +25,6 @@ namespace osc::mow std::unique_ptr implClone() const override; std::vector implWarpDetails() const override; std::vector implValidate() const override; - std::unique_ptr implTryCreateFrameWarper(const ModelWarpDocument&) 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 f829ecb6e..c8031d688 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.cpp +++ b/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.cpp @@ -1,8 +1,8 @@ #include "TPSLandmarkPairWarperFactory.h" #include -#include #include +#include #include #include @@ -319,7 +319,7 @@ std::vector osc::mow::TPSLandmarkPairWarperFactory::implV return rv; } -std::unique_ptr osc::mow::TPSLandmarkPairWarperFactory::implTryCreatePointWarper(const ModelWarpDocument& document) const +std::unique_ptr osc::mow::TPSLandmarkPairWarperFactory::implTryCreatePointWarper(const WarpableModel& document) const { class TPSWarper : public IPointWarper { public: diff --git a/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.h b/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.h index bd61fb482..ca0e24359 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.h +++ b/src/OpenSimCreator/Documents/ModelWarper/TPSLandmarkPairWarperFactory.h @@ -66,7 +66,7 @@ namespace osc::mow std::unique_ptr implClone() const override; std::vector implWarpDetails() const override; std::vector implValidate() const override; - std::unique_ptr implTryCreatePointWarper(const ModelWarpDocument&) const override; + std::unique_ptr implTryCreatePointWarper(const WarpableModel&) const override; std::filesystem::path m_SourceMeshAbsoluteFilepath; diff --git a/src/OpenSimCreator/Documents/ModelWarper/ModelWarpDocument.cpp b/src/OpenSimCreator/Documents/ModelWarper/WarpableModel.cpp similarity index 65% rename from src/OpenSimCreator/Documents/ModelWarper/ModelWarpDocument.cpp rename to src/OpenSimCreator/Documents/ModelWarper/WarpableModel.cpp index 79e87ff01..630fb0127 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/ModelWarpDocument.cpp +++ b/src/OpenSimCreator/Documents/ModelWarper/WarpableModel.cpp @@ -1,4 +1,4 @@ -#include "ModelWarpDocument.h" +#include "WarpableModel.h" #include #include @@ -16,37 +16,37 @@ using namespace osc; using namespace osc::mow; -osc::mow::ModelWarpDocument::ModelWarpDocument() : +osc::mow::WarpableModel::WarpableModel() : m_ModelState{make_cow()}, m_ModelWarpConfig{make_cow()}, m_MeshWarpLookup{make_cow()}, m_FrameWarpLookup{make_cow()} {} -osc::mow::ModelWarpDocument::ModelWarpDocument(const std::filesystem::path& osimFileLocation) : +osc::mow::WarpableModel::WarpableModel(const std::filesystem::path& osimFileLocation) : m_ModelState{make_cow(osimFileLocation)}, m_ModelWarpConfig{make_cow(osimFileLocation, m_ModelState->getModel())}, m_MeshWarpLookup{make_cow(osimFileLocation, m_ModelState->getModel(), *m_ModelWarpConfig)}, m_FrameWarpLookup{make_cow(osimFileLocation, m_ModelState->getModel(), *m_ModelWarpConfig)} {} -osc::mow::ModelWarpDocument::ModelWarpDocument(const ModelWarpDocument&) = default; -osc::mow::ModelWarpDocument::ModelWarpDocument(ModelWarpDocument&&) noexcept = default; -osc::mow::ModelWarpDocument& osc::mow::ModelWarpDocument::operator=(const ModelWarpDocument&) = default; -osc::mow::ModelWarpDocument& osc::mow::ModelWarpDocument::operator=(ModelWarpDocument&&) noexcept = default; -osc::mow::ModelWarpDocument::~ModelWarpDocument() noexcept = default; +osc::mow::WarpableModel::WarpableModel(const WarpableModel&) = default; +osc::mow::WarpableModel::WarpableModel(WarpableModel&&) noexcept = default; +osc::mow::WarpableModel& osc::mow::WarpableModel::operator=(const WarpableModel&) = default; +osc::mow::WarpableModel& osc::mow::WarpableModel::operator=(WarpableModel&&) noexcept = default; +osc::mow::WarpableModel::~WarpableModel() noexcept = default; -const OpenSim::Model& osc::mow::ModelWarpDocument::model() const +const OpenSim::Model& osc::mow::WarpableModel::model() const { return m_ModelState->getModel(); } -const IConstModelStatePair& osc::mow::ModelWarpDocument::modelstate() const +const IConstModelStatePair& osc::mow::WarpableModel::modelstate() const { return *m_ModelState; } -std::vector osc::mow::ModelWarpDocument::details(const OpenSim::Mesh& mesh) const +std::vector osc::mow::WarpableModel::details(const OpenSim::Mesh& mesh) const { std::vector rv; rv.emplace_back("OpenSim::Mesh path in the OpenSim::Model", GetAbsolutePathString(mesh)); @@ -59,7 +59,7 @@ std::vector osc::mow::ModelWarpDocument::details(const OpenSim::Mesh return rv; } -std::vector osc::mow::ModelWarpDocument::validate(const OpenSim::Mesh& mesh) const +std::vector osc::mow::WarpableModel::validate(const OpenSim::Mesh& mesh) const { if (const IPointWarperFactory* p = m_MeshWarpLookup->find(GetAbsolutePathString(mesh))) { return p->validate(); @@ -69,18 +69,18 @@ std::vector osc::mow::ModelWarpDocument::validate(const O } } -ValidationCheckState osc::mow::ModelWarpDocument::state(const OpenSim::Mesh& mesh) const +ValidationCheckState osc::mow::WarpableModel::state(const OpenSim::Mesh& mesh) const { const IPointWarperFactory* p = m_MeshWarpLookup->find(GetAbsolutePathString(mesh)); return p ? p->state() : ValidationCheckState::Error; } -const IPointWarperFactory* osc::mow::ModelWarpDocument::findMeshWarp(const OpenSim::Mesh& mesh) const +const IPointWarperFactory* osc::mow::WarpableModel::findMeshWarp(const OpenSim::Mesh& mesh) const { return m_MeshWarpLookup->find(GetAbsolutePathString(mesh)); } -std::vector osc::mow::ModelWarpDocument::details(const OpenSim::PhysicalOffsetFrame& pof) const +std::vector osc::mow::WarpableModel::details(const OpenSim::PhysicalOffsetFrame& pof) const { if (const IFrameWarperFactory* p = m_FrameWarpLookup->find(GetAbsolutePathString(pof))) { return p->details(); @@ -88,7 +88,7 @@ std::vector osc::mow::ModelWarpDocument::details(const OpenSim::Phys return {}; } -std::vector osc::mow::ModelWarpDocument::validate(const OpenSim::PhysicalOffsetFrame& pof) const +std::vector osc::mow::WarpableModel::validate(const OpenSim::PhysicalOffsetFrame& pof) const { if (const IFrameWarperFactory* p = m_FrameWarpLookup->find(GetAbsolutePathString(pof))) { return p->validate(); @@ -98,14 +98,14 @@ std::vector osc::mow::ModelWarpDocument::validate(const O } } -ValidationCheckState osc::mow::ModelWarpDocument::state( +ValidationCheckState osc::mow::WarpableModel::state( const OpenSim::PhysicalOffsetFrame& pof) const { const IFrameWarperFactory* p = m_FrameWarpLookup->find(GetAbsolutePathString(pof)); return p ? p->state() : ValidationCheckState::Error; } -ValidationCheckState osc::mow::ModelWarpDocument::state() const +ValidationCheckState osc::mow::WarpableModel::state() const { ValidationCheckState rv = ValidationCheckState::Ok; for (const auto& mesh : model().getComponentList()) { @@ -117,27 +117,27 @@ ValidationCheckState osc::mow::ModelWarpDocument::state() const return rv; } -float osc::mow::ModelWarpDocument::getWarpBlendingFactor() const +float osc::mow::WarpableModel::getWarpBlendingFactor() const { return m_ModelWarpConfig->getWarpBlendingFactor(); } -void osc::mow::ModelWarpDocument::setWarpBlendingFactor(float v) +void osc::mow::WarpableModel::setWarpBlendingFactor(float v) { m_ModelWarpConfig.upd()->setWarpBlendingFactor(v); } -bool osc::mow::ModelWarpDocument::getShouldWriteWarpedMeshesToDisk() const +bool osc::mow::WarpableModel::getShouldWriteWarpedMeshesToDisk() const { return m_ModelWarpConfig->getShouldWriteWarpedMeshesToDisk(); } -void osc::mow::ModelWarpDocument::setShouldWriteWarpedMeshesToDisk(bool v) +void osc::mow::WarpableModel::setShouldWriteWarpedMeshesToDisk(bool v) { m_ModelWarpConfig.upd()->setShouldWriteWarpedMeshesToDisk(v); } -std::optional osc::mow::ModelWarpDocument::getWarpedMeshesOutputDirectory() const +std::optional osc::mow::WarpableModel::getWarpedMeshesOutputDirectory() const { const auto osimFileLocation = getOsimFileLocation(); if (not osimFileLocation) { @@ -146,12 +146,12 @@ std::optional osc::mow::ModelWarpDocument::getWarpedMeshe return std::filesystem::weakly_canonical(osimFileLocation->parent_path() / m_ModelWarpConfig->getWarpedMeshesOutputDirectory()); } -std::optional osc::mow::ModelWarpDocument::getOsimFileLocation() const +std::optional osc::mow::WarpableModel::getOsimFileLocation() const { return TryFindInputFile(m_ModelState->getModel()); } -std::vector osc::mow::ModelWarpDocument::implValidate() const +std::vector osc::mow::WarpableModel::implValidate() const { std::vector rv; for (const auto& mesh : model().getComponentList()) { diff --git a/src/OpenSimCreator/Documents/ModelWarper/ModelWarpDocument.h b/src/OpenSimCreator/Documents/ModelWarper/WarpableModel.h similarity index 68% rename from src/OpenSimCreator/Documents/ModelWarper/ModelWarpDocument.h rename to src/OpenSimCreator/Documents/ModelWarper/WarpableModel.h index d63e3a8cb..c1da13e2a 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/ModelWarpDocument.h +++ b/src/OpenSimCreator/Documents/ModelWarper/WarpableModel.h @@ -22,18 +22,25 @@ namespace OpenSim { class PhysicalOffsetFrame; } namespace osc::mow { - // top-level model warping document that contains all the necessary state to render - // the model warping UI and can, if valid, contain all the necessary state to warp - // an OpenSim model - class ModelWarpDocument final : public IValidateable { + // a top-level datastructure that can produce a warped `OpenSim::Model` from + // appropriate inputs + // + // i.e. this ties together: + // + // - an input `OpenSim::Model` + // - (optional) a warp configuration, which tells the engine how to warp the model + // + // because this may be polled or used by the UI, it may (hopefully, temporarily) be + // in an error/warning state that the user is expected to resolve at runtime + class WarpableModel final : public IValidateable { public: - ModelWarpDocument(); - explicit ModelWarpDocument(const std::filesystem::path& osimFileLocation); - ModelWarpDocument(const ModelWarpDocument&); - ModelWarpDocument(ModelWarpDocument&&) noexcept; - ModelWarpDocument& operator=(const ModelWarpDocument&); - ModelWarpDocument& operator=(ModelWarpDocument&&) noexcept; - ~ModelWarpDocument() noexcept; + WarpableModel(); + explicit WarpableModel(const std::filesystem::path& osimFileLocation); + WarpableModel(const WarpableModel&); + WarpableModel(WarpableModel&&) noexcept; + WarpableModel& operator=(const WarpableModel&); + WarpableModel& operator=(WarpableModel&&) noexcept; + ~WarpableModel() noexcept; const OpenSim::Model& model() const; const IConstModelStatePair& modelstate() const; @@ -59,8 +66,8 @@ namespace osc::mow ValidationCheckState state() const; - // only checks reference equality by leaning on the copy-on-write behavior - friend bool operator==(const ModelWarpDocument&, const ModelWarpDocument&) = default; + // returns `true` if both the left- and right-hand side _point_ to the same information + friend bool operator==(const WarpableModel&, const WarpableModel&) = default; private: std::vector implValidate() const; diff --git a/src/OpenSimCreator/Documents/ModelWarper/WarpableOpenSimComponent.h b/src/OpenSimCreator/Documents/ModelWarper/WarpableOpenSimComponent.h index 8bfb7463b..cfe1133c6 100644 --- a/src/OpenSimCreator/Documents/ModelWarper/WarpableOpenSimComponent.h +++ b/src/OpenSimCreator/Documents/ModelWarper/WarpableOpenSimComponent.h @@ -2,14 +2,16 @@ #include #include +#include #include namespace osc::mow { - // a compile-time list of OpenSim types that are specifically handled by the model warper + // satisfied by OpenSim types that can be warped by the model warper template concept WarpableOpenSimComponent = IsAnyOf; } diff --git a/src/OpenSimCreator/UI/ModelWarper/UIState.cpp b/src/OpenSimCreator/UI/ModelWarper/UIState.cpp index 96e9f741d..df2e63dbd 100644 --- a/src/OpenSimCreator/UI/ModelWarper/UIState.cpp +++ b/src/OpenSimCreator/UI/ModelWarper/UIState.cpp @@ -23,7 +23,7 @@ void osc::mow::UIState::actionOpenOsimOrPromptUser(std::optional()->push_back(*path); - m_Document = std::make_shared(std::move(path).value()); + m_Document = std::make_shared(std::move(path).value()); } } @@ -42,7 +42,7 @@ void osc::mow::UIState::actionWarpModelAndOpenInModelEditor() // create a copy of the document so that we can apply export-specific // configuration changes to it - ModelWarpDocument copy{*m_Document}; + WarpableModel copy{*m_Document}; copy.setShouldWriteWarpedMeshesToDisk(true); // required for OpenSim to be able to load the warped model correctly auto warpedModelStatePair = m_ModelWarper.warp(copy); m_TabHost->add_and_select_tab(*api, std::make_unique(warpedModelStatePair->getModel())); diff --git a/src/OpenSimCreator/UI/ModelWarper/UIState.h b/src/OpenSimCreator/UI/ModelWarper/UIState.h index f98c1ef13..43f1e6d9b 100644 --- a/src/OpenSimCreator/UI/ModelWarper/UIState.h +++ b/src/OpenSimCreator/UI/ModelWarper/UIState.h @@ -2,9 +2,9 @@ #include #include -#include #include #include +#include #include #include @@ -70,7 +70,7 @@ namespace osc::mow void actionWarpModelAndOpenInModelEditor(); private: ParentPtr m_TabHost; - std::shared_ptr m_Document = std::make_shared(); + std::shared_ptr m_Document = std::make_shared(); CachedModelWarper m_ModelWarper; bool m_LinkCameras = true; diff --git a/tests/TestOpenSimCreator/CMakeLists.txt b/tests/TestOpenSimCreator/CMakeLists.txt index 5a56af83c..7c27fb411 100644 --- a/tests/TestOpenSimCreator/CMakeLists.txt +++ b/tests/TestOpenSimCreator/CMakeLists.txt @@ -11,8 +11,8 @@ add_executable(TestOpenSimCreator Documents/Model/TestUndoableModelStatePair.cpp Documents/ModelWarper/TestCachedModelWarper.cpp Documents/ModelWarper/TestFrameWarperFactories.cpp - Documents/ModelWarper/TestModelWarpDocument.cpp Documents/ModelWarper/TestPointWarperFactories.cpp + Documents/ModelWarper/TestWarpableModel.cpp Documents/OutputExtractors/TestConstantOutputExtractor.cpp Documents/Simulation/TestForwardDynamicSimulation.cpp Documents/Simulation/TestSimulationHelpers.cpp diff --git a/tests/TestOpenSimCreator/Documents/ModelWarper/TestCachedModelWarper.cpp b/tests/TestOpenSimCreator/Documents/ModelWarper/TestCachedModelWarper.cpp index 7b60345a0..7ca5e6db4 100644 --- a/tests/TestOpenSimCreator/Documents/ModelWarper/TestCachedModelWarper.cpp +++ b/tests/TestOpenSimCreator/Documents/ModelWarper/TestCachedModelWarper.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include using namespace osc; @@ -15,7 +15,7 @@ TEST(CachedModelWarper, CanBeDefaultConstructed) TEST(CachedModelWarper, CanWarpDefaultConstructedModelWarpingDocument) { - ModelWarpDocument document; + WarpableModel document; CachedModelWarper warper; const auto rv = warper.warp(document); diff --git a/tests/TestOpenSimCreator/Documents/ModelWarper/TestModelWarpDocument.cpp b/tests/TestOpenSimCreator/Documents/ModelWarper/TestWarpableModel.cpp similarity index 54% rename from tests/TestOpenSimCreator/Documents/ModelWarper/TestModelWarpDocument.cpp rename to tests/TestOpenSimCreator/Documents/ModelWarper/TestWarpableModel.cpp index 586a52e13..8bceb67bb 100644 --- a/tests/TestOpenSimCreator/Documents/ModelWarper/TestModelWarpDocument.cpp +++ b/tests/TestOpenSimCreator/Documents/ModelWarper/TestWarpableModel.cpp @@ -1,4 +1,4 @@ -#include +#include #include @@ -23,115 +23,115 @@ namespace } } -TEST(ModelWarpDocument, CanDefaultConstruct) +TEST(WarpableModel, CanDefaultConstruct) { - ASSERT_NO_THROW({ ModelWarpDocument{}; }); + ASSERT_NO_THROW({ WarpableModel{}; }); } -TEST(ModelWarpDocument, CanConstructFromPathToOsim) +TEST(WarpableModel, CanConstructFromPathToOsim) { - ASSERT_NO_THROW({ ModelWarpDocument{GetFixturesDir() / "blank.osim"}; }); + ASSERT_NO_THROW({ WarpableModel{GetFixturesDir() / "blank.osim"}; }); } -TEST(ModelWarpDocument, ConstructorThrowsIfGivenInvalidOsimPath) +TEST(WarpableModel, ConstructorThrowsIfGivenInvalidOsimPath) { - ASSERT_THROW({ ModelWarpDocument{std::filesystem::path{"bs.osim"}}; }, std::exception); + ASSERT_THROW({ WarpableModel{std::filesystem::path{"bs.osim"}}; }, std::exception); } -TEST(ModelWarpDocument, AfterConstructingFromBasicOsimFileTheReturnedModelContainsExpectedComponents) +TEST(WarpableModel, AfterConstructingFromBasicOsimFileTheReturnedModelContainsExpectedComponents) { - const ModelWarpDocument doc{GetFixturesDir() / "onebody.osim"}; + const WarpableModel doc{GetFixturesDir() / "onebody.osim"}; doc.model().getComponent("bodyset/some_body"); } -TEST(ModelWarpDocument, DefaultConstructedIsInAnOKState) +TEST(WarpableModel, DefaultConstructedIsInAnOKState) { // i.e. it is possible to warp a blank model - const ModelWarpDocument doc; + const WarpableModel doc; ASSERT_EQ(doc.state(), ValidationCheckState::Ok); } -TEST(ModelWarpDocument, BlankOsimFileIsInAnOKState) +TEST(WarpableModel, BlankOsimFileIsInAnOKState) { // a blank document is also warpable (albeit, trivially) - const ModelWarpDocument doc{GetFixturesDir() / "blank.osim"}; + const WarpableModel doc{GetFixturesDir() / "blank.osim"}; ASSERT_EQ(doc.state(), ValidationCheckState::Ok); } -TEST(ModelWarpDocument, OneBodyIsInAnOKState) +TEST(WarpableModel, OneBodyIsInAnOKState) { // the onebody example isn't warpable, because it can't figure out how to warp // the offset frame in it (the user _must_ specify that they want to ignore it, or // use StationDefinedFrame, etc.) - const ModelWarpDocument doc{GetFixturesDir() / "onebody.osim"}; + const WarpableModel doc{GetFixturesDir() / "onebody.osim"}; ASSERT_EQ(doc.state(), ValidationCheckState::Error); } -TEST(ModelWarpDocument, SparselyNamedPairedIsInAnOKState) +TEST(WarpableModel, SparselyNamedPairedIsInAnOKState) { // the landmarks in this example are sparesely named, but fully paired, and the // model contains no PhysicalOffsetFrames to worry about, so it's fine - const ModelWarpDocument doc{GetFixturesDir() / "SparselyNamedPaired" / "model.osim"}; + const WarpableModel doc{GetFixturesDir() / "SparselyNamedPaired" / "model.osim"}; ASSERT_EQ(doc.state(), ValidationCheckState::Ok); } -TEST(ModelWarpDocument, SimpleUnnamedIsInAnErrorState) +TEST(WarpableModel, SimpleUnnamedIsInAnErrorState) { // the model is simple, and has landmarks on the source mesh, but there is no // destination mesh/landmarks, and the user hasn't specified any overrides // etc., so it's un-warpable - const ModelWarpDocument doc{GetFixturesDir() / "SimpleUnnamed" / "model.osim"}; + const WarpableModel doc{GetFixturesDir() / "SimpleUnnamed" / "model.osim"}; ASSERT_EQ(doc.state(), ValidationCheckState::Error); } -TEST(ModelWarpDocument, SimpleIsInAnErrorState) +TEST(WarpableModel, SimpleIsInAnErrorState) { // the model is simple, and has named landmarks on the source mesh, but there // is no destination mesh/landmarks, and the user hasn't specified any overrides // etc., so it's un-warpable - const ModelWarpDocument doc{GetFixturesDir() / "Simple" / "model.osim"}; + const WarpableModel doc{GetFixturesDir() / "Simple" / "model.osim"}; ASSERT_EQ(doc.state(), ValidationCheckState::Error); } -TEST(ModelWarpDocument, PairedIsInAnOKState) +TEST(WarpableModel, PairedIsInAnOKState) { // the model is simple and has fully paired meshes+landmarks: it can be warped - const ModelWarpDocument doc{GetFixturesDir() / "Paired" / "model.osim"}; + const WarpableModel doc{GetFixturesDir() / "Paired" / "model.osim"}; ASSERT_EQ(doc.state(), ValidationCheckState::Ok); } -TEST(ModelWarpDocument, MissingSourceLMsIsInAnErrorState) +TEST(WarpableModel, MissingSourceLMsIsInAnErrorState) { // the model is simple, has source+destination meshes, but is missing landmark // data for a source mesh: unwarpable - const ModelWarpDocument doc{GetFixturesDir() / "MissingSourceLMs" / "model.osim"}; + const WarpableModel doc{GetFixturesDir() / "MissingSourceLMs" / "model.osim"}; ASSERT_EQ(doc.state(), ValidationCheckState::Error); } -TEST(ModelWarpDocument, MissingDestinationLMsIsInAnErrorState) +TEST(WarpableModel, MissingDestinationLMsIsInAnErrorState) { // the model is simple, has source+destination meshes, but is missing landmark // data for a destination mesh: unwarpable - const ModelWarpDocument doc{GetFixturesDir() / "MissingDestinationLMs" / "model.osim"}; + const WarpableModel doc{GetFixturesDir() / "MissingDestinationLMs" / "model.osim"}; ASSERT_EQ(doc.state(), ValidationCheckState::Error); } -TEST(ModelWarpDocument, PofPairedIsInAnErrorState) +TEST(WarpableModel, PofPairedIsInAnErrorState) { // the model has fully-paired meshes (good), but contains `PhysicalOffsetFrame`s // that haven't been explicitly handled by the user (ignored, least-squares fit, etc.) - const ModelWarpDocument doc{GetFixturesDir() / "PofPaired" / "model.osim"}; + const WarpableModel doc{GetFixturesDir() / "PofPaired" / "model.osim"}; ASSERT_EQ(doc.state(), ValidationCheckState::Error); } -TEST(ModelWarpDocument, WarpBlendingFactorInitiallyOne) +TEST(WarpableModel, WarpBlendingFactorInitiallyOne) { - ASSERT_EQ(ModelWarpDocument{}.getWarpBlendingFactor(), 1.0f); + ASSERT_EQ(WarpableModel{}.getWarpBlendingFactor(), 1.0f); } -TEST(ModelWarpDocument, WarpBlendingFactorClampedBetweenZeroAndOne) +TEST(WarpableModel, WarpBlendingFactorClampedBetweenZeroAndOne) { - ModelWarpDocument doc; + WarpableModel doc; ASSERT_EQ(doc.getWarpBlendingFactor(), 1.0f); doc.setWarpBlendingFactor(5.0f); ASSERT_EQ(doc.getWarpBlendingFactor(), 1.0f); @@ -141,53 +141,53 @@ TEST(ModelWarpDocument, WarpBlendingFactorClampedBetweenZeroAndOne) ASSERT_EQ(doc.getWarpBlendingFactor(), 1.0f); } -TEST(ModelWarpDocument, getShouldWriteWarpedMeshesToDisk_InitiallyFalse) +TEST(WarpableModel, getShouldWriteWarpedMeshesToDisk_InitiallyFalse) { // this might be important, because the UI performs _much_ better if it doesn't // have to write the warped meshes to disk. So it should be an explicit operation // when the caller (e.g. the export process) actually needs this behavior (e.g. // because OpenSim is going to expect on-disk mesh data) - ASSERT_FALSE(ModelWarpDocument{}.getShouldWriteWarpedMeshesToDisk()); + ASSERT_FALSE(WarpableModel{}.getShouldWriteWarpedMeshesToDisk()); } -TEST(ModelWarpDocument, setShouldWriteWarpedMeshesToDisk_CanBeUsedToSetBehaviorToTrue) +TEST(WarpableModel, setShouldWriteWarpedMeshesToDisk_CanBeUsedToSetBehaviorToTrue) { - ModelWarpDocument doc; + WarpableModel doc; ASSERT_FALSE(doc.getShouldWriteWarpedMeshesToDisk()); doc.setShouldWriteWarpedMeshesToDisk(true); ASSERT_TRUE(doc.getShouldWriteWarpedMeshesToDisk()); } -TEST(ModelWarpDocument, setShouldWriteWarpedMeshesToDisk_ChangesEquality) +TEST(WarpableModel, setShouldWriteWarpedMeshesToDisk_ChangesEquality) { - ModelWarpDocument a; - ModelWarpDocument b = a; + WarpableModel a; + WarpableModel b = a; ASSERT_EQ(a, b); b.setShouldWriteWarpedMeshesToDisk(true); ASSERT_NE(a, b); } -TEST(ModelWarpDocument, getWarpedMeshesOutputDirectory_ReturnsNulloptWhenNoOsimProvided) +TEST(WarpableModel, getWarpedMeshesOutputDirectory_ReturnsNulloptWhenNoOsimProvided) { - ASSERT_EQ(ModelWarpDocument{}.getWarpedMeshesOutputDirectory(), std::nullopt); + ASSERT_EQ(WarpableModel{}.getWarpedMeshesOutputDirectory(), std::nullopt); } -TEST(ModelWarpDocument, getWarpedMeshesOutputDirectory_ReturnsNonNulloptWhenOsimProvied) +TEST(WarpableModel, getWarpedMeshesOutputDirectory_ReturnsNonNulloptWhenOsimProvied) { const std::filesystem::path fileLocation = GetFixturesDir() / "blank.osim"; - const ModelWarpDocument doc{fileLocation}; + const WarpableModel doc{fileLocation}; ASSERT_NE(doc.getWarpedMeshesOutputDirectory(), std::nullopt); } -TEST(ModelWarpDocument, getOsimFileLocation_ReturnsNulloptOnDefaultConstruction) +TEST(WarpableModel, getOsimFileLocation_ReturnsNulloptOnDefaultConstruction) { - ASSERT_EQ(ModelWarpDocument{}.getOsimFileLocation(), std::nullopt); + ASSERT_EQ(WarpableModel{}.getOsimFileLocation(), std::nullopt); } -TEST(ModelWarpDocument, getOsimFileLocation_ReturnsProvidedOsimFileLocationWHenConstructedFromPath) +TEST(WarpableModel, getOsimFileLocation_ReturnsProvidedOsimFileLocationWHenConstructedFromPath) { const std::filesystem::path fileLocation = GetFixturesDir() / "blank.osim"; - const ModelWarpDocument doc{fileLocation}; + const WarpableModel doc{fileLocation}; ASSERT_EQ(doc.getOsimFileLocation(), fileLocation); }