opynsim
Unofficial C++ Documentation
Loading...
Searching...
No Matches
scaling_state.h
Go to the documentation of this file.
1#pragma once
2
8
9#include <filesystem>
10#include <memory>
11#include <sstream>
12#include <utility>
13#include <vector>
14
15namespace opyn
16{
17 // Top-level input state that's required to actually perform model scaling.
18 class ScalingState final { // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
19 public:
20 explicit ScalingState()
21 {
22 scalingDocument->finalizeConnections(*scalingDocument);
23 scalingDocument->finalizeFromProperties();
24 }
25
26 ScalingState(const ScalingState& other) :
27 sourceModel{std::make_shared<BasicModelStatePair>(*other.sourceModel)},
28 scalingDocument{std::make_shared<ModelWarperV3Document>(*other.scalingDocument)}
29 {
30 // care: separate `ScalingState`s should act like separate instances with no
31 // reference sharing between them, but the shared pointers in the "main"
32 // `ScalingState` might already be divvied out to UI components, so we
33 // can't just switch the pointers around.
34 scalingDocument->clearConnections();
35 scalingDocument->finalizeConnections(*scalingDocument);
36 scalingDocument->finalizeFromProperties();
37 }
38
39 ScalingState(ScalingState&& tmp) noexcept :
40 ScalingState{static_cast<const ScalingState&>(tmp)}
41 {}
42
43 ~ScalingState() noexcept = default;
44
45 ScalingState& operator=(const ScalingState& other)
46 {
47 // care: separate `ScalingState`s should act like separate instances with no
48 // reference sharing between them, but the shared pointers in the "main"
49 // `ScalingState` might already be divvied out to UI components, so we
50 // can't just switch the pointers around.
51 if (&other == this) {
52 return *this;
53 }
54 *sourceModel = *other.sourceModel;
55 *scalingDocument = *other.scalingDocument;
56 scalingDocument->clearConnections();
57 scalingDocument->finalizeConnections(*scalingDocument);
58 scalingDocument->finalizeFromProperties();
59 return *this;
60 }
61
62 ScalingState& operator=(ScalingState&& tmp) noexcept { return *this = static_cast<const ScalingState&>(tmp); }
63
64 // Source Model Methods
65
66 const ModelStatePair& getSourceModel() const { return *sourceModel; }
67 std::shared_ptr<ModelStatePair> getSourceModelPtr() { return sourceModel; }
68 void loadSourceModelFromOsim(const std::filesystem::path& path)
69 {
70 sourceModel = std::make_shared<BasicModelStatePair>(path);
71 }
73 {
74 sourceModel = std::make_shared<BasicModelStatePair>();
75 }
76
77 // Scaling Document Methods
78
79 std::shared_ptr<const ModelWarperV3Document> getScalingDocumentPtr() const { return scalingDocument; }
80 bool hasScalingSteps() const { return scalingDocument->hasScalingSteps(); }
81 auto iterateScalingSteps() const { return scalingDocument->iterateScalingSteps(); }
82 void addScalingStep(std::unique_ptr<ScalingStep> step)
83 {
84 scalingDocument->addScalingStep(std::move(step));
85 }
87 {
88 return scalingDocument->removeScalingStep(step);
89 }
90 bool eraseScalingStep(const OpenSim::ComponentPath& path)
91 {
92 if (auto* scalingStep = findScalingComponentMut<ScalingStep>(path)) {
93 return eraseScalingStep(*scalingStep);
94 }
95 else {
96 return false;
97 }
98 }
100 {
101 OpenSim::Component* component = findScalingComponentMut(edit.getComponentAbsPath());
102 if (not component) {
103 return;
104 }
105 OpenSim::AbstractProperty* property = FindPropertyMut(*component, edit.getPropertyName());
106 if (not property) {
107 return;
108 }
109 edit.apply(*property);
110 scalingDocument->clearConnections();
111 scalingDocument->finalizeConnections(*scalingDocument);
112 scalingDocument->finalizeFromProperties();
113 }
114 bool disableScalingStep(const OpenSim::ComponentPath& path)
115 {
116 if (auto* scalingStep = findScalingComponentMut<ScalingStep>(path)) {
117 scalingStep->set_enabled(false);
118 scalingDocument->clearConnections();
119 scalingDocument->finalizeConnections(*scalingDocument);
120 scalingDocument->finalizeFromProperties();
121 return true;
122 }
123 else {
124 return false;
125 }
126 }
127 std::vector<ScalingDocumentValidationMessage> getEnabledScalingStepValidationMessages(ScalingCache& scalingCache) const
128 {
129 std::vector<ScalingDocumentValidationMessage> rv;
130
131 if (not hasScalingSteps()) {
132 return rv;
133 }
134
135 const ScalingParameters scalingParameters = getEffectiveScalingParameters();
136
137 for (const auto& scalingStep : scalingDocument->getComponentList<ScalingStep>()) {
138 if (not scalingStep.get_enabled()) {
139 // Only aggregate validation errors from enabled `ScalingStep`s at the document-level.
140 continue;
141 }
142 auto stepMessages = scalingStep.validate(scalingCache, scalingParameters, *sourceModel);
143 rv.reserve(rv.size() + stepMessages.size());
144 for (auto& stepMessage : stepMessages) {
146 .sourceScalingStepAbsPath = scalingStep.getAbsolutePath(),
147 .payload = std::move(stepMessage),
148 });
149 }
150 }
151 return rv;
152 }
154 {
155 return not getEnabledScalingStepValidationMessages(scalingCache).empty();
156 }
158 {
159 scalingDocument = std::make_shared<ModelWarperV3Document>();
160 scalingDocument->finalizeConnections(*scalingDocument);
161 scalingDocument->finalizeFromProperties();
162 }
163 void loadScalingDocument(const std::filesystem::path& path)
164 {
165 const auto ptr = std::shared_ptr<OpenSim::Object>{OpenSim::Object::makeObjectFromFile(path.string())};
166 if (auto downcasted = std::dynamic_pointer_cast<ModelWarperV3Document>(ptr)) {
167 scalingDocument = std::move(downcasted);
168 scalingDocument->finalizeConnections(*scalingDocument);
169 scalingDocument->finalizeFromProperties();
170 }
171 else {
172 std::stringstream ss;
173 ss << path.string() << ": is a valid object file, but doesn't contain a ModelWarperV3Document";
174 throw std::runtime_error{std::move(ss).str()};
175 }
176 }
177 std::optional<std::filesystem::path> scalingDocumentFilesystemLocation() const
178 {
179 if (const auto filename = scalingDocument->getDocumentFileName(); not filename.empty()) {
180 return std::filesystem::path{filename};
181 }
182 else {
183 return std::nullopt;
184 }
185 }
186
187 bool hasScalingParameterDeclarations() const { return scalingDocument->hasScalingParameters(); }
188 ScalingParameters getEffectiveScalingParameters() const { return scalingDocument->getEffectiveScalingParameters(); }
189 bool setScalingParameterOverride(const std::string& scalingParamName, ScalingParameterValue newValue)
190 {
191 return scalingDocument->setScalingParameterOverride(scalingParamName, newValue);
192 }
193
194 // Model Scaling
195
196 // Tries to generate a scaled version of the source model using the current
197 // scaling steps and scaling parameters.
198 std::unique_ptr<BasicModelStatePair> tryGenerateScaledModel(ScalingCache& scalingCache) const
199 {
200 if (hasScalingStepValidationIssues(scalingCache)) {
201 return nullptr; // there are validation errors, so scaling isn't possible
202 }
203
204 // Create an independent copy of the source model, which will be scaled in-place.
205 OpenSim::Model resultModel = sourceModel->getModel();
206 resultModel.clearConnections();
207 InitializeModel(resultModel);
208 InitializeState(resultModel);
209
210 if (not hasScalingSteps()) {
211 // There are no scaling steps, so a copy of the source model is a scaled model (trivially).
212 return std::make_unique<BasicModelStatePair>(std::move(resultModel));
213 }
214
215 // Calculate the effective scaling parameters (defaults + user-enacted overrides)
216 const ScalingParameters scalingParams = getEffectiveScalingParameters();
217
218 // Apply each scaling step to the scaled model
219 for (auto& step : scalingDocument->updComponentList<ScalingStep>()) {
220 step.applyScalingStep(scalingCache, scalingParams, *sourceModel, resultModel);
221 }
222
223 // Return the warped model
224 return std::make_unique<BasicModelStatePair>(std::move(resultModel));
225 }
226
227 private:
228 template<typename T = OpenSim::Component>
229 T* findScalingComponentMut(const OpenSim::ComponentPath& p) { return FindComponentMut<T>(*scalingDocument, p); }
230
231 std::shared_ptr<BasicModelStatePair> sourceModel = std::make_shared<BasicModelStatePair>();
232 std::shared_ptr<ModelWarperV3Document> scalingDocument = std::make_shared<ModelWarperV3Document>();
233 };
234}
Definition basic_model_state_pair.h:22
Definition model_state_pair.h:19
Definition model_warper_v3_document.h:25
Definition scaling_cache.h:30
Definition scaling_parameters.h:14
Definition scaling_state.h:18
void applyScalingObjectPropertyEdit(osc::ObjectPropertyEdit edit)
Definition scaling_state.h:99
std::unique_ptr< BasicModelStatePair > tryGenerateScaledModel(ScalingCache &scalingCache) const
Definition scaling_state.h:198
void resetScalingDocument()
Definition scaling_state.h:157
bool eraseScalingStep(const OpenSim::ComponentPath &path)
Definition scaling_state.h:90
void addScalingStep(std::unique_ptr< ScalingStep > step)
Definition scaling_state.h:82
const ModelStatePair & getSourceModel() const
Definition scaling_state.h:66
void loadSourceModelFromOsim(const std::filesystem::path &path)
Definition scaling_state.h:68
std::shared_ptr< const ModelWarperV3Document > getScalingDocumentPtr() const
Definition scaling_state.h:79
auto iterateScalingSteps() const
Definition scaling_state.h:81
bool hasScalingParameterDeclarations() const
Definition scaling_state.h:187
std::shared_ptr< ModelStatePair > getSourceModelPtr()
Definition scaling_state.h:67
std::vector< ScalingDocumentValidationMessage > getEnabledScalingStepValidationMessages(ScalingCache &scalingCache) const
Definition scaling_state.h:127
ScalingState()
Definition scaling_state.h:20
bool hasScalingStepValidationIssues(ScalingCache &scalingCache) const
Definition scaling_state.h:153
ScalingState(const ScalingState &other)
Definition scaling_state.h:26
void loadScalingDocument(const std::filesystem::path &path)
Definition scaling_state.h:163
bool hasScalingSteps() const
Definition scaling_state.h:80
~ScalingState() noexcept=default
ScalingState & operator=(ScalingState &&tmp) noexcept
Definition scaling_state.h:62
bool eraseScalingStep(ScalingStep &step)
Definition scaling_state.h:86
std::optional< std::filesystem::path > scalingDocumentFilesystemLocation() const
Definition scaling_state.h:177
ScalingState(ScalingState &&tmp) noexcept
Definition scaling_state.h:39
ScalingParameters getEffectiveScalingParameters() const
Definition scaling_state.h:188
bool setScalingParameterOverride(const std::string &scalingParamName, ScalingParameterValue newValue)
Definition scaling_state.h:189
void resetSourceModel()
Definition scaling_state.h:72
bool disableScalingStep(const OpenSim::ComponentPath &path)
Definition scaling_state.h:114
Definition scaling_step.h:25
Definition object_property_edit.h:15
void apply(OpenSim::AbstractProperty &)
const std::string & getPropertyName() const
const std::string & getComponentAbsPath() const
Definition component_registry.h:14
void InitializeModel(OpenSim::Model &)
double ScalingParameterValue
Definition scaling_parameter_value.h:9
OpenSim::AbstractProperty * FindPropertyMut(OpenSim::Component &, const std::string &)
SimTK::State & InitializeState(OpenSim::Model &)
Definition scaling_document_validation_message.h:12
OpenSim::ComponentPath sourceScalingStepAbsPath
Definition scaling_document_validation_message.h:13