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