1 /* -------------------------------------------------------------------------- *
2  *                     OpenSim:  ConditionalPathPoint.cpp                     *
3  * -------------------------------------------------------------------------- *
4  * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
5  * See http://opensim.stanford.edu and the NOTICE file for more information.  *
6  * OpenSim is developed at Stanford University and supported by the US        *
7  * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
8  * through the Warrior Web program.                                           *
9  *                                                                            *
10  * Copyright (c) 2005-2017 Stanford University and the Authors                *
11  * Author(s): Peter Loan                                                      *
12  *                                                                            *
13  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
14  * not use this file except in compliance with the License. You may obtain a  *
15  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
16  *                                                                            *
17  * Unless required by applicable law or agreed to in writing, software        *
18  * distributed under the License is distributed on an "AS IS" BASIS,          *
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
20  * See the License for the specific language governing permissions and        *
21  * limitations under the License.                                             *
22  * -------------------------------------------------------------------------- */
23 
24 //=============================================================================
25 // INCLUDES
26 //=============================================================================
27 #include "ConditionalPathPoint.h"
28 #include <OpenSim/Simulation/SimbodyEngine/Coordinate.h>
29 
30 //=============================================================================
31 // STATICS
32 //=============================================================================
33 using namespace std;
34 using namespace OpenSim;
35 
36 //=============================================================================
37 // CONSTRUCTOR(S) AND DESTRUCTOR
38 //=============================================================================
39 //_____________________________________________________________________________
40 /**
41  * Default constructor.
42  */
ConditionalPathPoint()43 ConditionalPathPoint::ConditionalPathPoint() : PathPoint()
44 {
45     constructProperties();
46 }
47 
48 //_____________________________________________________________________________
49 /**
50  * Destructor.
51  */
~ConditionalPathPoint()52 ConditionalPathPoint::~ConditionalPathPoint()
53 {}
54 
55 //_____________________________________________________________________________
56 /*
57  * Override default implementation by object to intercept and fix the XML node
58  * underneath the model to match current version
59  */
updateFromXMLNode(SimTK::Xml::Element & node,int versionNumber)60 void ConditionalPathPoint::updateFromXMLNode(SimTK::Xml::Element& node,
61                                              int versionNumber)
62 {
63     if (versionNumber <= 20001) {
64         // Version has to be 1.6 or later, otherwise assert
65         XMLDocument::renameChildNode(node, "coordinates", "coordinate");
66     }
67     if (versionNumber < 30505) {
68         // replace old properties with latest use of Sockets
69         SimTK::Xml::element_iterator coord = node.element_begin("coordinate");
70         std::string coordName("");
71         if (coord != node.element_end())
72             coord->getValueAs<std::string>(coordName);
73 
74         // As a backup, we will specify just the coordinate name as the
75         // connectee name...
76         std::string connectee_name = coordName;
77 
78         // ...but if possible, we try to create a relative path from this
79         // PathPoint to the coordinate.
80         SimTK::Xml::Element coordElem =
81             XMLDocument::findElementWithName(node, coordName);
82         if (coordElem.isValid() && coordElem.hasParentElement()) {
83             // We found an Xml Element with the coordinate's name.
84             std::string jointName =
85                 coordElem.getParentElement().getOptionalAttributeValue("name");
86             // PathPoints in pre-4.0 models are necessarily
87             // 3 levels deep (model, muscle, geometry path), and Coordinates
88             // are necessarily 2 levels deep.
89             // Here we create the correct relative path (accounting for sets
90             // being components).
91             if (jointName.empty())
92                 jointName = IO::Lowercase(
93                         coordElem.getParentElement().getElementTag());
94             connectee_name = XMLDocument::updateConnecteePath30517(
95                     "jointset", jointName + "/" + coordName);
96         }
97 
98         XMLDocument::addConnector(node, "Connector_Coordinate_", "coordinate",
99                 connectee_name);
100     }
101 
102     // Call base class now assuming _node has been corrected for current version
103     Super::updateFromXMLNode(node, versionNumber);
104 }
105 
106 //_____________________________________________________________________________
107 /*
108  * Connect properties to local pointers.
109  */
constructProperties()110 void ConditionalPathPoint::constructProperties()
111 {
112     Array<double> defaultRange(0.0, 2); //two values of the range
113     constructProperty_range(defaultRange);
114 }
115 
116 
117 //_____________________________________________________________________________
118 /*
119  * Set the coordinate that this point is linked to.
120  */
setCoordinate(const Coordinate & coordinate)121 void ConditionalPathPoint::setCoordinate(const Coordinate& coordinate)
122 {
123     connectSocket_coordinate(coordinate);
124 }
125 
hasCoordinate() const126 bool ConditionalPathPoint::hasCoordinate() const
127 {
128     return getSocket<Coordinate>("coordinate").isConnected();
129 }
130 
getCoordinate() const131 const Coordinate& ConditionalPathPoint::getCoordinate() const
132 {
133     return getConnectee<Coordinate>("coordinate");
134 }
135 
136 
137 //_____________________________________________________________________________
138 /*
139  * Set the range min.
140  */
setRangeMin(double minVal)141 void ConditionalPathPoint::setRangeMin(double minVal)
142 {
143     set_range(0, minVal);
144 }
145 
146 //_____________________________________________________________________________
147 /*
148  * Set the range max.
149  */
setRangeMax(double maxVal)150 void ConditionalPathPoint::setRangeMax(double maxVal)
151 {
152     set_range(1, maxVal);
153 }
154 
155 //_____________________________________________________________________________
156 /*
157  * Determine if this point is active by checking the value of the
158  * coordinate that it is linked to.
159  */
isActive(const SimTK::State & s) const160 bool ConditionalPathPoint::isActive(const SimTK::State& s) const
161 {
162     if (getSocket<Coordinate>("coordinate").isConnected()) {
163         double value = getConnectee<Coordinate>("coordinate").getValue(s);
164         if (value >= get_range(0) - 1e-5 &&
165              value <= get_range(1) + 1e-5)
166             return true;
167     }
168     return false;
169 }
170