Skip to content

Commit 60dd70d

Browse files
Merge pull request #2685 from opensim-org/unify_iktools
Upgrade InverseKinematicsTool to new Property system
2 parents 65d46f1 + c722623 commit 60dd70d

File tree

5 files changed

+132
-368
lines changed

5 files changed

+132
-368
lines changed

Applications/IK/ik.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,6 @@ int main(int argc,char **argv)
6868
)";
6969
std::cout << deprecationNotice << std::endl;
7070

71-
// REGISTER TYPES
72-
InverseKinematicsTool::registerTypes();
73-
7471
// PARSE COMMAND LINE
7572
string option = "";
7673
string setupFileName;

OpenSim/Tools/InverseDynamicsTool.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,6 @@ bool InverseDynamicsTool::run()
274274
<< _lowpassCutoffFrequency << "..." << endl << endl;
275275
_coordinateValues->pad(_coordinateValues->getSize()/2);
276276
_coordinateValues->lowpassIIR(_lowpassCutoffFrequency);
277-
if (getVerboseLevel()==Debug) _coordinateValues->print("coordinateDataFiltered.sto");
278277
}
279278
// Convert degrees to radian if indicated
280279
if(_coordinateValues->isInDegrees()){

OpenSim/Tools/InverseKinematicsTool.cpp

Lines changed: 48 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,9 @@ InverseKinematicsTool::~InverseKinematicsTool()
5858
/**
5959
* Default constructor.
6060
*/
61-
InverseKinematicsTool::InverseKinematicsTool() : Tool(),
62-
_modelFileName(_modelFileNameProp.getValueStr()),
63-
_constraintWeight(_constraintWeightProp.getValueDbl()),
64-
_accuracy(_accuracyProp.getValueDbl()),
65-
_ikTaskSetProp(PropertyObj("", IKTaskSet())),
66-
_ikTaskSet((IKTaskSet&)_ikTaskSetProp.getValueObj()),
67-
_markerFileName(_markerFileNameProp.getValueStr()),
68-
_coordinateFileName(_coordinateFileNameProp.getValueStr()),
69-
_timeRange(_timeRangeProp.getValueDblArray()),
70-
_reportErrors(_reportErrorsProp.getValueBool()),
71-
_outputMotionFileName(_outputMotionFileNameProp.getValueStr()),
72-
_reportMarkerLocations(_reportMarkerLocationsProp.getValueBool())
61+
InverseKinematicsTool::InverseKinematicsTool() : Tool()
7362
{
74-
setNull();
63+
constructProperties();
7564
}
7665
//_____________________________________________________________________________
7766
/**
@@ -83,176 +72,32 @@ InverseKinematicsTool::InverseKinematicsTool() : Tool(),
8372
* @param aFileName File name of the document.
8473
*/
8574
InverseKinematicsTool::InverseKinematicsTool(const string &aFileName, bool aLoadModel) :
86-
Tool(aFileName, true),
87-
_modelFileName(_modelFileNameProp.getValueStr()),
88-
_constraintWeight(_constraintWeightProp.getValueDbl()),
89-
_accuracy(_accuracyProp.getValueDbl()),
90-
_ikTaskSetProp(PropertyObj("", IKTaskSet())),
91-
_ikTaskSet((IKTaskSet&)_ikTaskSetProp.getValueObj()),
92-
_markerFileName(_markerFileNameProp.getValueStr()),
93-
_coordinateFileName(_coordinateFileNameProp.getValueStr()),
94-
_timeRange(_timeRangeProp.getValueDblArray()),
95-
_reportErrors(_reportErrorsProp.getValueBool()),
96-
_outputMotionFileName(_outputMotionFileNameProp.getValueStr()),
97-
_reportMarkerLocations(_reportMarkerLocationsProp.getValueBool())
75+
Tool(aFileName, true)
9876
{
99-
setNull();
77+
constructProperties();
10078
updateFromXMLDocument();
101-
102-
if(aLoadModel) {
103-
//loadModel(aFileName);
104-
}
105-
}
106-
//_____________________________________________________________________________
107-
/**
108-
* Copy constructor.
109-
*
110-
* @param aTool Object to be copied.
111-
112-
*/
113-
InverseKinematicsTool::InverseKinematicsTool(const InverseKinematicsTool &aTool) :
114-
Tool(aTool),
115-
_modelFileName(_modelFileNameProp.getValueStr()),
116-
_constraintWeight(_constraintWeightProp.getValueDbl()),
117-
_accuracy(_accuracyProp.getValueDbl()),
118-
_ikTaskSetProp(PropertyObj("", IKTaskSet())),
119-
_ikTaskSet((IKTaskSet&)_ikTaskSetProp.getValueObj()),
120-
_markerFileName(_markerFileNameProp.getValueStr()),
121-
_coordinateFileName(_coordinateFileNameProp.getValueStr()),
122-
_timeRange(_timeRangeProp.getValueDblArray()),
123-
_reportErrors(_reportErrorsProp.getValueBool()),
124-
_outputMotionFileName(_outputMotionFileNameProp.getValueStr()),
125-
_reportMarkerLocations(_reportMarkerLocationsProp.getValueBool())
126-
{
127-
setNull();
128-
*this = aTool;
129-
}
130-
131-
//_____________________________________________________________________________
132-
/**
133-
* Set all member variables to their null or default values.
134-
*/
135-
void InverseKinematicsTool::setNull()
136-
{
137-
setupProperties();
138-
_model = NULL;
139-
}
140-
//_____________________________________________________________________________
141-
/**
142-
* Connect properties to local pointers.
143-
*/
144-
void InverseKinematicsTool::setupProperties()
145-
{
146-
_modelFileNameProp.setComment(
147-
"Name of the model file (.osim) to use for inverse kinematics.");
148-
_modelFileNameProp.setName("model_file");
149-
_propertySet.append( &_modelFileNameProp );
150-
151-
_constraintWeightProp.setComment(
152-
"A positive scalar that weights the relative importance of satisfying "
153-
"constraints. A weighting of 'Infinity' (the default) results in the "
154-
"constraints being strictly enforced. Otherwise, the weighted-squared "
155-
"constraint errors are appended to the cost function.");
156-
_constraintWeightProp.setName("constraint_weight");
157-
_constraintWeightProp.setValue(std::numeric_limits<SimTK::Real>::infinity());
158-
_propertySet.append( &_constraintWeightProp );
159-
160-
_accuracyProp.setComment(
161-
"The accuracy of the solution in absolute terms. Default is 1e-5. "
162-
"It determines the number of significant digits to which the solution "
163-
"can be trusted.");
164-
_accuracyProp.setName("accuracy");
165-
_accuracyProp.setValue(1e-5);
166-
_propertySet.append( &_accuracyProp );
167-
168-
_ikTaskSetProp.setComment(
169-
"Markers and coordinates to be considered (tasks) and their weightings. "
170-
"The sum of weighted-squared task errors composes the cost function.");
171-
_ikTaskSetProp.setName("IKTaskSet");
172-
_propertySet.append(&_ikTaskSetProp);
173-
174-
_markerFileNameProp.setComment(
175-
"TRC file (.trc) containing the time history of observations of marker "
176-
"positions obtained during a motion capture experiment. Markers in this "
177-
"file that have a corresponding task and model marker are included.");
178-
_markerFileNameProp.setName("marker_file");
179-
_propertySet.append(&_markerFileNameProp);
180-
181-
_coordinateFileNameProp.setComment(
182-
"The name of the storage (.sto or .mot) file containing the time history"
183-
" of coordinate observations. Coordinate values from this file are "
184-
"included if there is a corresponding model coordinate and task. ");
185-
_coordinateFileNameProp.setName("coordinate_file");
186-
_propertySet.append(&_coordinateFileNameProp);
187-
188-
const double defaultTimeRange[] =
189-
{-std::numeric_limits<SimTK::Real>::infinity(),
190-
std::numeric_limits<SimTK::Real>::infinity()};
191-
_timeRangeProp.setComment(
192-
"The desired time range over which inverse kinematics is solved. "
193-
"The closest start and final times from the provided observations "
194-
"are used to specify the actual time range to be processed.");
195-
_timeRangeProp.setName("time_range");
196-
_timeRangeProp.setValue(2, defaultTimeRange);
197-
_timeRangeProp.setAllowableListSize(2);
198-
_propertySet.append(&_timeRangeProp);
199-
200-
_reportErrorsProp.setComment(
201-
"Flag (true or false) indicating whether or not to report marker "
202-
"errors from the inverse kinematics solution.");
203-
_reportErrorsProp.setName("report_errors");
204-
_reportErrorsProp.setValue(true);
205-
_propertySet.append(&_reportErrorsProp);
206-
207-
_outputMotionFileNameProp.setComment(
208-
"Name of the resulting inverse kinematics motion (.mot) file.");
209-
_outputMotionFileNameProp.setName("output_motion_file");
210-
_propertySet.append(&_outputMotionFileNameProp);
211-
212-
_reportMarkerLocationsProp.setComment(
213-
"Flag indicating whether or not to report model marker locations. "
214-
"Note, model marker locations are expressed in Ground.");
215-
_reportMarkerLocationsProp.setName("report_marker_locations");
216-
_reportMarkerLocationsProp.setValue(false);
217-
_propertySet.append(&_reportMarkerLocationsProp);
21879
}
21980

22081
//_____________________________________________________________________________
22182
/**
222-
* Register InverseKinematicsTool and any Object types it may employ internally.
223-
*/
224-
void InverseKinematicsTool::registerTypes()
225-
{
226-
Object::registerType(InverseKinematicsTool());
227-
}
228-
//=============================================================================
229-
// OPERATORS
230-
//=============================================================================
231-
//_____________________________________________________________________________
232-
/**
233-
* Assignment operator.
234-
*
235-
* @return Reference to this object.
83+
* Construct properties
23684
*/
237-
InverseKinematicsTool& InverseKinematicsTool::
238-
operator=(const InverseKinematicsTool &aTool)
85+
void InverseKinematicsTool::constructProperties()
23986
{
240-
// BASE CLASS
241-
Tool::operator=(aTool);
242-
243-
// MEMBER VARIABLES
244-
_modelFileName = aTool._modelFileName;
245-
_constraintWeight = aTool._constraintWeight;
246-
_accuracy = aTool._accuracy;
247-
_ikTaskSet = aTool._ikTaskSet;
248-
_markerFileName = aTool._markerFileName;
249-
_timeRange = aTool._timeRange;
250-
_coordinateFileName = aTool._coordinateFileName;
251-
_reportErrors = aTool._reportErrors;
252-
_outputMotionFileName = aTool._outputMotionFileName;
253-
_reportMarkerLocations = aTool._reportMarkerLocations;
254-
255-
return(*this);
87+
constructProperty_model_file("");
88+
constructProperty_constraint_weight(Infinity);
89+
constructProperty_accuracy(1e-5);
90+
constructProperty_IKTaskSet(IKTaskSet());
91+
constructProperty_marker_file("");
92+
constructProperty_coordinate_file("");
93+
Array<double> range{Infinity, 2};
94+
range[0] = -Infinity; // Make range -Infinity to Infinity unless limited by
95+
// data
96+
constructProperty_time_range(range);
97+
98+
constructProperty_report_errors(true);
99+
constructProperty_output_motion_file("");
100+
constructProperty_report_marker_locations(false);
256101
}
257102

258103
//=============================================================================
@@ -274,10 +119,10 @@ bool InverseKinematicsTool::run()
274119
Kinematics* kinematicsReporter = nullptr;
275120
try{
276121
//Load and create the indicated model
277-
if (!_model) {
278-
OPENSIM_THROW_IF_FRMOBJ(_modelFileName.empty(), Exception,
279-
"No model filename was provided.");
280-
_model = new Model(_modelFileName);
122+
if (_model.empty()) {
123+
OPENSIM_THROW_IF_FRMOBJ(get_model_file().empty(), Exception,
124+
"No model filename was provided.");
125+
_model.reset(new Model(get_model_file()));
281126
}
282127
else
283128
modelFromFile = false;
@@ -317,11 +162,11 @@ bool InverseKinematicsTool::run()
317162
// specified then use time from marker reference.
318163
// Adjust the time range for the tool if the provided range exceeds
319164
// that of the marker data.
320-
SimTK::Vec2 markersValidTimRange = markersReference.getValidTimeRange();
321-
double start_time = (markersValidTimRange[0] > _timeRange[0]) ?
322-
markersValidTimRange[0] : _timeRange[0];
323-
double final_time = (markersValidTimRange[1] < _timeRange[1]) ?
324-
markersValidTimRange[1] : _timeRange[1];
165+
SimTK::Vec2 markersValidTimeRange = markersReference.getValidTimeRange();
166+
double start_time = (markersValidTimeRange[0] > get_time_range(0)) ?
167+
markersValidTimeRange[0] : get_time_range(0);
168+
double final_time = (markersValidTimeRange[1] < get_time_range(1)) ?
169+
markersValidTimeRange[1] : get_time_range(1);
325170

326171
SimTK_ASSERT2_ALWAYS(final_time >= start_time,
327172
"InverseKinematicsTool final time (%f) is before start time (%f).",
@@ -337,8 +182,8 @@ bool InverseKinematicsTool::run()
337182

338183
// create the solver given the input data
339184
InverseKinematicsSolver ikSolver(*_model, markersReference,
340-
coordinateReferences, _constraintWeight);
341-
ikSolver.setAccuracy(_accuracy);
185+
coordinateReferences, get_constraint_weight());
186+
ikSolver.setAccuracy(get_accuracy());
342187
s.updTime() = times[start_ix];
343188
ikSolver.assemble(s);
344189
kinematicsReporter->begin(s);
@@ -352,9 +197,9 @@ bool InverseKinematicsTool::run()
352197
SimTK::Array_<double> squaredMarkerErrors(nm, 0.0);
353198
SimTK::Array_<Vec3> markerLocations(nm, Vec3(0));
354199

355-
Storage *modelMarkerLocations = _reportMarkerLocations ?
200+
Storage *modelMarkerLocations = get_report_marker_locations() ?
356201
new Storage(Nframes, "ModelMarkerLocations") : nullptr;
357-
Storage *modelMarkerErrors = _reportErrors ?
202+
Storage *modelMarkerErrors = get_report_errors() ?
358203
new Storage(Nframes, "ModelMarkerErrors") : nullptr;
359204

360205
Stopwatch watch;
@@ -365,7 +210,7 @@ bool InverseKinematicsTool::run()
365210
// show progress line every 1000 frames so users see progress
366211
if (std::remainder(i - start_ix, 1000) == 0 && i != start_ix)
367212
cout << "Solved " << i - start_ix << " frames..." << std::endl;
368-
if(_reportErrors){
213+
if(get_report_errors()){
369214
Array<double> markerErrors(0.0, 3);
370215
double totalSquaredMarkerError = 0.0;
371216
double maxSquaredMarkerError = 0.0;
@@ -393,7 +238,7 @@ bool InverseKinematicsTool::run()
393238
<< ikSolver.getMarkerNameForIndex(worst) << ")" << endl;
394239
}
395240

396-
if(_reportMarkerLocations){
241+
if(get_report_marker_locations()){
397242
ikSolver.computeCurrentMarkerLocations(markerLocations);
398243
Array<double> locations(0.0, 3*nm);
399244
for(int j=0; j<nm; ++j){
@@ -411,8 +256,10 @@ bool InverseKinematicsTool::run()
411256

412257
// Do the maneuver to change then restore working directory
413258
// so that output files are saved to same folder as setup file.
414-
if (_outputMotionFileName!= "" && _outputMotionFileName!="Unassigned"){
415-
kinematicsReporter->getPositionStorage()->print(_outputMotionFileName);
259+
if (get_output_motion_file() != "" &&
260+
get_output_motion_file() != "Unassigned") {
261+
kinematicsReporter->getPositionStorage()->print(
262+
get_output_motion_file());
416263
}
417264
// Remove the analysis we added to the model, this also deletes it
418265
_model->removeAnalysis(kinematicsReporter);
@@ -472,7 +319,8 @@ bool InverseKinematicsTool::run()
472319
"please see messages window for details..."));
473320
}
474321

475-
if (modelFromFile) delete _model;
322+
if (modelFromFile)
323+
_model.reset();
476324

477325
return success;
478326
}
@@ -511,9 +359,7 @@ void InverseKinematicsTool::updateFromXMLNode(SimTK::Xml::Element& aNode, int ve
511359
for (; p!= trialIter->node_end(); ++p) {
512360
iter->insertNodeAfter( iter->node_end(), p->clone());
513361
}
514-
iter->insertNodeAfter( iter->node_end(), Xml::Comment(_constraintWeightProp.getComment()));
515362
iter->insertNodeAfter( iter->node_end(), Xml::Element("constraint_weight", "20.0"));
516-
iter->insertNodeAfter( iter->node_end(), Xml::Comment(_accuracyProp.getComment()));
517363
iter->insertNodeAfter( iter->node_end(), Xml::Element("accuracy", "1e-4"));
518364
// erase node for IKTrialSet
519365
iter->eraseNode(toolIter);
@@ -545,9 +391,7 @@ void InverseKinematicsTool::updateFromXMLNode(SimTK::Xml::Element& aNode, int ve
545391
for (; p!= trialIter->node_end(); ++p) {
546392
root.insertNodeAfter( root.node_end(), p->clone());
547393
}
548-
root.insertNodeAfter( root.node_end(), Xml::Comment(_constraintWeightProp.getComment()));
549394
root.insertNodeAfter( root.node_end(), Xml::Element("constraint_weight", "20.0"));
550-
root.insertNodeAfter( root.node_end(), Xml::Comment(_accuracyProp.getComment()));
551395
root.insertNodeAfter( root.node_end(), Xml::Element("accuracy", "1e-5"));
552396
// erase node for IKTrialSet
553397
root.eraseNode(toolIter);
@@ -577,8 +421,8 @@ void InverseKinematicsTool::populateReferences(MarkersReference& markersReferenc
577421
FunctionSet *coordFunctions = NULL;
578422
// Load the coordinate data
579423
// bool haveCoordinateFile = false;
580-
if (_coordinateFileName != "" && _coordinateFileName != "Unassigned") {
581-
Storage coordinateValues(_coordinateFileName);
424+
if (get_coordinate_file() != "" && get_coordinate_file() != "Unassigned") {
425+
Storage coordinateValues(get_coordinate_file());
582426
// Convert degrees to radian (TODO: this needs to have a check that the storage is, in fact, in degrees!)
583427
_model->getSimbodyEngine().convertDegreesToRadians(coordinateValues);
584428
// haveCoordinateFile = true;
@@ -589,9 +433,9 @@ void InverseKinematicsTool::populateReferences(MarkersReference& markersReferenc
589433
// Loop through old "IKTaskSet" and assign weights to the coordinate and marker references
590434
// For coordinates, create the functions for coordinate reference values
591435
int index = 0;
592-
for (int i = 0; i < _ikTaskSet.getSize(); i++) {
593-
if (!_ikTaskSet[i].getApply()) continue;
594-
if (IKCoordinateTask *coordTask = dynamic_cast<IKCoordinateTask *>(&_ikTaskSet[i])) {
436+
for (int i = 0; i < get_IKTaskSet().getSize(); i++) {
437+
if (!get_IKTaskSet()[i].getApply()) continue;
438+
if (IKCoordinateTask *coordTask = dynamic_cast<IKCoordinateTask *>(&get_IKTaskSet()[i])) {
595439
CoordinateReference *coordRef = NULL;
596440
if (coordTask->getValueType() == IKCoordinateTask::FromFile) {
597441
if (!coordFunctions)
@@ -619,7 +463,7 @@ void InverseKinematicsTool::populateReferences(MarkersReference& markersReferenc
619463

620464
coordinateReferences.push_back(*coordRef);
621465
}
622-
else if (IKMarkerTask *markerTask = dynamic_cast<IKMarkerTask *>(&_ikTaskSet[i])) {
466+
else if (IKMarkerTask *markerTask = dynamic_cast<IKMarkerTask *>(&get_IKTaskSet()[i])) {
623467
if (markerTask->getApply()) {
624468
// Only track markers that have a task and it is "applied"
625469
markerWeights.adoptAndAppend(
@@ -631,7 +475,7 @@ void InverseKinematicsTool::populateReferences(MarkersReference& markersReferenc
631475
//Read in the marker data file and set the weights for associated markers.
632476
//Markers in the model and the marker file but not in the markerWeights are
633477
//ignored
634-
markersReference.initializeFromMarkersFile(_markerFileName, markerWeights);
478+
markersReference.initializeFromMarkersFile(get_marker_file(), markerWeights);
635479
}
636480

637481

0 commit comments

Comments
 (0)