1 #ifndef OPENSIM_OPENSIM_CONTEXT_H_
2 #define OPENSIM_OPENSIM_CONTEXT_H_
3 /* -------------------------------------------------------------------------- *
4  *                         OpenSim:  OpenSimContext.h                         *
5  * -------------------------------------------------------------------------- *
6  * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
7  * See http://opensim.stanford.edu and the NOTICE file for more information.  *
8  * OpenSim is developed at Stanford University and supported by the US        *
9  * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
10  * through the Warrior Web program.                                           *
11  *                                                                            *
12  * Copyright (c) 2005-2017 Stanford University and the Authors                *
13  * Author(s): Jack Middleton, Ayman Habib                                     *
14  *                                                                            *
15  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
16  * not use this file except in compliance with the License. You may obtain a  *
17  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
18  *                                                                            *
19  * Unless required by applicable law or agreed to in writing, software        *
20  * distributed under the License is distributed on an "AS IS" BASIS,          *
21  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
22  * See the License for the specific language governing permissions and        *
23  * limitations under the License.                                             *
24  * -------------------------------------------------------------------------- */
25 
26 #include <OpenSim/Common/Object.h>
27 #include <OpenSim/Common/PropertyTransform.h>
28 #include <OpenSim/Simulation/osimSimulationDLL.h>
29 #include <OpenSim/Simulation/Model/Model.h>
30 #include <OpenSim/Simulation/Model/Force.h>
31 #include <OpenSim/Common/Array.h>
32 #include <OpenSim/Tools/InverseKinematicsTool.h>
33 
34 #include "Simbody.h"
35 
36 namespace OpenSim {
37 
38 class Body;
39 class Coordinate;
40 class TransformAxis;
41 class Function;
42 class Marker;
43 class MarkerSet;
44 class Model;
45 class MovingPathPoint;
46 class Muscle;
47 class GeometryPath;
48 class AbstractPathPoint;
49 class PathWrap;
50 class ConditionalPathPoint;
51 class WrapObject;
52 class Analysis;
53 class AnalyzeTool;
54 class ModelScaler;
55 class MarkerPlacer;
56 class MarkerData;
57 class Measurement;
58 
59 // Flag to indicate whether calls to the API are made from within try/catch block
60 // so that exceptions due to misuse, typos etc. are handled gracefully in scripts
61 // Set to true by default.
62 static bool mapCxxExceptionsToJava = true;
63 
64 //==============================================================================
65 //                                 OpenSimContext
66 //==============================================================================
67 /** Class intended to keep the SimTK::State under an OpenSim model to make it possible
68 to get/set values in the SimTK::State without exposing the SimTK::State class itself.
69 
70 The class provides convenient methods to get/set various state entries and query the
71 state for cache values. The main function this class provides is an adaptor of various
72 data types from Java and scripting supported primitive, wrapped and array types to the
73 corresponding possibly templatized or SimTK native data types.
74 
75 Most methods of this class are implementated by delegating the call to the SimTK::State
76 under the object, for example:
77 Context::isDisabled(const Force& force) -> force.isDisabled(state)
78 
79 The class also provides convenient services to recreateSystem and realize to various stages.
80 
81 @author Ayman Habib & Jack Middleton
82 **/
83 
84 class OpenSimContext : public Object {
85 OpenSim_DECLARE_CONCRETE_OBJECT(OpenSimContext, Object);
86 
87 
88 public:
89     OpenSimContext(SimTK::State* s, Model* model);
90 
setState(SimTK::State * s)91     void setState( SimTK::State* s) { _configState.reset(s); }
setModel(Model * m)92     void setModel( Model* m) { _model.reset(m); }
93 
94     /** Get reference to the single instance of SimTK::State maintained by the Context object **/
getCurrentStateRef()95     const SimTK::State& getCurrentStateRef() const { return (*_configState); };
96     /** Return a "clone" of  the single instance of SimTK::State maintained by the Context object **/
getCurrentStateCopy()97     SimTK::State getCurrentStateCopy() const { return SimTK::State(*_configState); };
98         void recreateSystemAfterSystemExistsKeepStage();
99         void recreateSystemAfterSystemExists();
resetStateToDefault()100         void resetStateToDefault() {
101              SimTK::Stage stageBeforeRecreatingSystem = _configState->getSystemStage();
102              SimTK::State* newState = &_model->initSystem();
103              setState( newState );
104             _model->getMultibodySystem().realize( *_configState, stageBeforeRecreatingSystem );
105         }
106     // Transforms
107     void transformPosition(const PhysicalFrame& body, double offset[], double gOffset[]);
108     SimTK::Transform getTransform(const PhysicalFrame& body);
109     void transform(const PhysicalFrame& ground, double d[], PhysicalFrame& body, double dragVectorBody[]);
110     // Coordinates
111     double getValue(const Coordinate& coord);
112     bool getLocked(const Coordinate& coord);
113     void setValue(const Coordinate& coord, double d, bool enforceConstraints=true);
114     void setClamped(Coordinate& coord, bool newValue);
115     bool getClamped(const Coordinate& coord);
116     void setLocked(Coordinate& coord, bool newValue);
117     bool isPrescribed(const Coordinate& coord) const;
118     bool isConstrained(const Coordinate& coord) const;
119     // Constraints
isEnforced(const Constraint & constraint)120     bool isEnforced(const Constraint& constraint) const {
121         return constraint.isEnforced(*_configState);
122     }
setIsEnforced(Constraint & constraint,bool isEnforced)123     void setIsEnforced(Constraint& constraint, bool isEnforced) {
124         constraint.setIsEnforced(*_configState, isEnforced);
125         _model->assemble(*_configState);
126     }
127     // Forces
appliesForce(const Force & force)128     bool appliesForce(const Force& force) const {
129         return  force.appliesForce(*_configState);
130     }
setAppliesForce(Force & force,bool applyForce)131     void setAppliesForce(Force& force, bool applyForce) const {
132         force.setAppliesForce(*_configState, applyForce);
133         _model->getMultibodySystem().realize(*_configState,
134                                              SimTK::Stage::Position);
135     }
136     // Muscles
137     double getActivation(Muscle& act);
138     double getMuscleLength(Muscle& act);
139     const Array<AbstractPathPoint*>& getCurrentPath(Muscle& act);
140     void copyMuscle(Muscle& from, Muscle& to);
141     void replacePropertyFunction(OpenSim::Object& obj, OpenSim::Function* aOldFunction, OpenSim::Function* aNewFunction);
142 
143     // Muscle Points
144     void setXFunction(MovingPathPoint& mmp, Function& newFunction);
145     void setYFunction(MovingPathPoint& mmp, Function& newFunction);
146     void setZFunction(MovingPathPoint& mmp, Function& newFunction);
147     void setXCoordinate(MovingPathPoint& mmp, Coordinate& newCoord);
148     void setYCoordinate(MovingPathPoint& mmp, Coordinate& newCoord);
149     void setZCoordinate(MovingPathPoint& mmp, Coordinate& newCoord);
150     void setBody(AbstractPathPoint& pathPoint, PhysicalFrame& newBody);
151     void setCoordinate(ConditionalPathPoint& via, Coordinate& newCoord);
152     void setRangeMin(ConditionalPathPoint& via, double d);
153     void setRangeMax(ConditionalPathPoint& via, double d);
154     bool replacePathPoint(GeometryPath& p, AbstractPathPoint& mp, AbstractPathPoint& newPoint);
155     void setLocation(PathPoint& mp, int i, double d);
156 
157     void setLocation(PathPoint& mp, const SimTK::Vec3& newLocation);
158     void setEndPoint(PathWrap& mw, int newEndPt);
159     void addPathPoint(GeometryPath& p, int menuChoice, PhysicalFrame& body);
160     bool deletePathPoint(GeometryPath& p, int menuChoice);
161     bool isActivePathPoint(AbstractPathPoint& mp) ;
162     // Muscle Wrapping
163     void setStartPoint(PathWrap& mw, int newStartPt);
164     void addPathWrap(GeometryPath& p, WrapObject& awo);
165     void moveUpPathWrap(GeometryPath& p, int num);
166     void moveDownPathWrap(GeometryPath& p, int num);
167     void deletePathWrap(GeometryPath& p, int num);
168     // Markers
169     void setBody(Marker& currentMarker, PhysicalFrame& newBody, bool  b);
170     void updateMarkerSet(Model& model, MarkerSet& aMarkerSet);
171 
getCenterOfMassInGround(double com[3])172     void getCenterOfMassInGround(double com[3]) const {
173         SimTK::Vec3 comV = _model->getMatterSubsystem().calcSystemMassCenterLocationInGround(*_configState);
174         for(int i=0; i<3; i++) com[i] = comV[i];
175     }
176     // Analyses
177     int step(Analysis& analysis);
178     // Tools
179     bool solveInverseKinematics( InverseKinematicsTool& ikTool);
180     void setStatesFromMotion(AnalyzeTool& analyzeTool, const Storage &aMotion, bool aInDegrees);
181     void loadStatesFromFile(AnalyzeTool& analyzeTool);
182     bool processModelScale(ModelScaler& modelScaler,
183         Model* aModel, const std::string& aPathToSubject="", double aFinalMass = -1.0);
184     bool processModelMarkerPlacer( MarkerPlacer& markerPlacer,
185         Model* aModel, const std::string& aPathToSubject="");
186     double computeMeasurementScaleFactor(ModelScaler& modelScaler,
187         const Model& aModel, const MarkerData& aMarkerData, const Measurement& aMeasurement) const;
188    void replaceTransformAxisFunction(TransformAxis& aDof, OpenSim::Function& aFunction);
189 
190     // Utilities
isNaN(double v)191     static bool isNaN( double v ) { return (SimTK::isNaN(v)); }
192 
getTime()193     double getTime() {
194         assert(_configState);
195         return (_configState->getTime());
196     }
197     // Convert SimTK::Transform into a double[] array of 16 doubles
getTransformAsDouble16(const SimTK::Transform & aTransform,double flattened[])198     static void getTransformAsDouble16(const SimTK::Transform& aTransform, double flattened[]){
199          double* matStart = &aTransform.toMat44()[0][0];
200          for (int i=0; i<16; i++) flattened[i]=matStart[i];
201     }
202     // Sets the property values in the model from the current state if there
203     // are state variables that correspond to properties.
setPropertiesFromState()204     void setPropertiesFromState() {
205         _model->setPropertiesFromState(*_configState);
206     }
207     /**
208      * Create a new System under the model then realize it to the same stage it had
209      */
recreateSystemKeepStage()210     void recreateSystemKeepStage() {
211         SimTK::Stage stageBeforeRecreatingSystem = _configState->getSystemStage();
212         SimTK::Vector y1 = _configState->getY();
213         SimTK::State* newState = &_model->initSystem();
214         newState->updY() = y1;
215         setState( newState );
216         _model->getMultibodySystem().realize( *_configState, stageBeforeRecreatingSystem );
217     }
218     // Force re-realization
219     void realizePosition();
220     void realizeVelocity();
221 
222     void cacheModelAndState();
223     void restoreStateFromCachedModel()  SWIG_DECLARE_EXCEPTION;
224     void setSocketConnecteePath(AbstractSocket& socket,
225             const std::string& newValue)   SWIG_DECLARE_EXCEPTION;
226 //=============================================================================
227 // DATA
228 //=============================================================================
229 
230 private:
231     // SimTK::State supporting the OpenSim::Model
232     SimTK::ReferencePtr<SimTK::State> _configState;
233     // The OpenSim::model
234     SimTK::ReferencePtr<Model> _model;
235 
236     SimTK::ResetOnCopy<std::unique_ptr<Model> > clonedModel;
237     SimTK::State clonedState;
238 }; // class OpenSimContext
239 
240 //==============================================================================
241 //                                 OpenSimJavaObject
242 //==============================================================================
243 /**
244 In some cases, the GUI ad/or scripting language needs to create objects that derive from OpenSim::Object
245 The class OpenSim::Object however is not a concrete class, so we introduce OpenSimJavaObject
246 for this purpose
247 **/
248 class OpenSimJavaObject : public Object {
249 OpenSim_DECLARE_CONCRETE_OBJECT(OpenSimJavaObject, Object);
250 };
251 
252 class AdhocModelComponent : public ModelComponent {
253     OpenSim_DECLARE_CONCRETE_OBJECT(AdhocModelComponent, ModelComponent);
254 };
255 //==============================================================================
256 //                                 AnalysisWrapper
257 //==============================================================================
258 /**
259 Class used as base class for Java classes deriving from Analysis (used to be callback)
260 It lives on the C++ side so that it gets access to SimTK::State, but it returns quantities
261 in Java data types
262 **/
263 
264 class AnalysisWrapper : public Analysis {
265 OpenSim_DECLARE_CONCRETE_OBJECT(AnalysisWrapper, Analysis);
266 public:
267     AnalysisWrapper(Model *aModel=0):
Analysis(aModel)268       Analysis(aModel){
269     }
~AnalysisWrapper()270     virtual ~AnalysisWrapper() {}
271 }; // Class AnalysisWrapper
272 
273 
274 //==============================================================================
275 //                                 InterruptCallback
276 //==============================================================================
277 /**
278 Class used to handle interrupts (synchronously). Works by adding it as an analysis
279 And when the client (GUI in most cases) decides to interrupt the simulation/analysis,
280 it calls the interrupt() method. When the step method is invoked later, an exception
281 is thrown.
282 **/
283 // Class to handle interrupts
284 class InterruptCallback : public AnalysisWrapper {
285     bool _throwException;
286 public:
287     InterruptCallback(Model *aModel=0):
AnalysisWrapper(aModel)288       AnalysisWrapper(aModel),
289       _throwException(false){};
290 
interrupt()291     void interrupt() {
292         _throwException=true;
293     }
step(const SimTK::State & s,int stepNumber)294     virtual int step( const SimTK::State& s, int stepNumber) {
295         if (_throwException)
296             throw Exception("Operation Aborted");
297         return 0;
298     }
299 
300 };
301 
302 //==============================================================================
303 //                                 PropertyHelper
304 //==============================================================================
305 /**
306 This class allows access to property values using template-free
307  methods. Note that this will work regardless of whether the given
308  AbstractProperty is the deprecated kind or the new one.
309 
310  An AbstractProperty represents a (name, list-of-values) pair, possibly
311  with restrictions on the minimum and maximum list length. Basic container
312  methods size(), resize(), clear(), and empty() are available; use resize()
313  before assigning a value to an indexed element.
314 
315  For properties that contain objects, you can obtain the values directly
316  from the base class via non-templatized methods.
317  **/
318 class PropertyHelper {
319 public:
320     //=================Boolean Properties==================
321     // Recover boolean value from an AbstractProperty that was assumed to contain a boolean
322     // Will throw exception if the assumption was wrong/invalid. Use index only if the
323     // property contains an array of booleans.
324     static bool getValueBool(const AbstractProperty& p, int index=-1)
325     {   return p.getValue<bool>(index); }
326     // Set boolean value in an AbstractProperty that was assumed to hold a boolean
327     // Will throw exception if the assumption was wrong/invalid. Use index only if the
328     // property contains an array of booleans.
329     static void setValueBool(bool v, AbstractProperty& p, int index=-1)
330     {   p.updValue<bool>(index) = v; }
331     // Append a new boolean value to an AbstractProperty that was assumed to hold a variable size
332     // array of booleans. Will throw exception if the assumption was wrong/invalid.
appendValueBool(bool v,AbstractProperty & p)333     static void appendValueBool(bool v, AbstractProperty& p)
334     {   p.appendValue<bool>(v); }
335     //=================Int Properties, see Boolean Properties for details ==================
336     static int getValueInt(const AbstractProperty& p, int index=-1)
337     {   return p.getValue<int>(index); }
338     static void setValueInt(int v, AbstractProperty& p, int index=-1)
339     {   p.updValue<int>(index) = v; }
appendValueInt(int v,AbstractProperty & p)340     static void appendValueInt(int v, AbstractProperty& p)
341     {   p.appendValue<int>(v); }
342     //=================Double Properties, see Boolean Properties for details ==================
343     static double getValueDouble(const AbstractProperty& p, int index=-1)
344     {   return p.getValue<double>(index); }
345     static void setValueDouble(double v, AbstractProperty& p, int index=-1)
346     {   p.updValue<double>(index) = v; }
appendValueDouble(double v,AbstractProperty & p)347     static void appendValueDouble(double v, AbstractProperty& p)
348     {   p.appendValue<double>(v); }
349     //=================String Properties, see Boolean Properties for details ==================
350     static std::string getValueString(const AbstractProperty& p, int index=-1)
351     {   return p.getValue<std::string>(index); }
352     static void setValueString(const std::string& v,
353                                AbstractProperty& p, int index=-1)
354     {   p.updValue<std::string>(index) = v; }
appendValueString(const std::string & v,AbstractProperty & p)355     static void appendValueString(const std::string& v, AbstractProperty& p)
356     {   p.appendValue<std::string>(v); }
357     //=================Transform Properties, treated as six Doubles ==================
getValueTransform(const AbstractProperty & p,int index)358     static double getValueTransform(const AbstractProperty& p, int index)
359     {
360         const PropertyTransform& pd = dynamic_cast<const PropertyTransform&>(p);
361         double array6[] = {0., 0., 0., 0., 0., 0.};
362         pd.getRotationsAndTranslationsAsArray6(array6);
363         return array6[index];
364     }
setValueTransform(double v,AbstractProperty & p,int index)365     static void setValueTransform(double v, AbstractProperty& p, int index)
366     {
367         PropertyTransform& pd = dynamic_cast<PropertyTransform&>(p);
368         double array6[] = {0., 0., 0., 0., 0., 0.};
369         pd.getRotationsAndTranslationsAsArray6(array6);
370         array6[index] = v;
371         pd.setValue(6, array6);
372     }
373     //=================Vec3 Properties, treated as three Doubles ==================
getValueVec3(const AbstractProperty & p,int index)374     static double getValueVec3(const AbstractProperty& p, int index)
375     {
376         const Property<SimTK::Vec3>& pd = dynamic_cast<const Property<SimTK::Vec3>&>(p);
377         const SimTK::Vec3& vec3 = pd.getValue();
378         return vec3[index];
379     }
setValueVec3(double v,AbstractProperty & p,int index)380     static void setValueVec3(double v, AbstractProperty& p, int index)
381     {
382         Property<SimTK::Vec3>& pd = dynamic_cast<Property<SimTK::Vec3>&>(p);
383         pd.updValue()[index] = v;
384     }
getValueVec6(const AbstractProperty & p,int index)385     static double getValueVec6(const AbstractProperty& p, int index)
386     {
387         const Property<SimTK::Vec6>& pd = dynamic_cast<const Property<SimTK::Vec6>&>(p);
388         const SimTK::Vec6& vec6 = pd.getValue();
389         return vec6[index];
390     }
setValueVec6(double v,AbstractProperty & p,int index)391     static void setValueVec6(double v, AbstractProperty& p, int index)
392     {
393         Property<SimTK::Vec6>& pd = dynamic_cast<Property<SimTK::Vec6>&>(p);
394         pd.updValue()[index] = v;
395     }
396     // ================ String arrays ===================================================
getValueStringArray(const AbstractProperty & p)397     static OpenSim::Array<std::string> getValueStringArray(const AbstractProperty& p)
398     {
399         OpenSim::Array<std::string> val = OpenSim::Array<std::string>();
400         for (int i=0; i< p.size(); i++)
401             val.append(p.getValue<std::string>(i));
402         return val;
403     }
setValueStringArray(AbstractProperty & p,OpenSim::Array<std::string> & aStringArray)404     static void setValueStringArray(AbstractProperty& p,  OpenSim::Array<std::string>& aStringArray)
405     {
406         p.clear();
407         for (int i=0; i< aStringArray.getSize(); i++)
408             try {
409                 p.appendValue<std::string>(aStringArray.get(i));
410             } catch (OpenSim::Exception e) {
411                 OpenSim::Exception ex("ERROR- Invalid input (invalid character/spaces in input string)");
412                 throw ex;
413             }
414     }
415 
removeItem(AbstractProperty & p,int index)416     static void removeItem(AbstractProperty& p, int index)
417     {
418         if (p.size()>index){
419             AbstractProperty* cloneP = p.clone();
420             p.clear();
421             for(int i=0; i<cloneP->size();i++){
422                 if (i!= index){
423                 if (p.getTypeName()=="string")
424                     p.appendValue(cloneP->getValue<std::string>(i));
425                 else if (p.getTypeName()=="int")
426                     p.appendValue(cloneP->getValue<int>(i));
427                 else if (p.getTypeName()=="double")
428                     p.appendValue(cloneP->getValue<double>(i));
429                 else if (p.getTypeName()=="bool")
430                     p.appendValue(cloneP->getValue<bool>(i));
431                 }
432             }
433         }
434     }
435 
436 };
437 
438 } // namespace OpenSim
439 
440 #endif // OPENSIM_OPENSIM_CONTEXT_H_
441 
442