1 /* -------------------------------------------------------------------------- *
2 * OpenSim: Frame.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): Matt DeMers & Ayman Habib *
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 "Frame.h"
28 #include <OpenSim/Common/ScaleSet.h>
29
30 //=============================================================================
31 // STATICS
32 //=============================================================================
33 using namespace std;
34 using namespace OpenSim;
35 using SimTK::Mat33;
36 using SimTK::Vec3;
37 using SimTK::State;
38 using SimTK::SpatialVec;
39
40 //=============================================================================
41 // CONSTRUCTOR(S)
42 //=============================================================================
Frame()43 Frame::Frame() : ModelComponent()
44 {
45 setAuthors("Matt DeMers, Ajay Seth");
46
47 FrameGeometry default_frame_geometry;
48 default_frame_geometry.setName("frame_geometry");
49 constructProperty_frame_geometry(default_frame_geometry);
50
51 constructProperty_attached_geometry();
52 }
53
extendConnectToModel(Model & model)54 void Frame::extendConnectToModel(Model& model)
55 {
56 Super::extendConnectToModel(model);
57 // All the Geometry attached to this Frame should have
58 // their frame connections automatically set to this Frame.
59 upd_frame_geometry().setFrame(*this);
60 int nag = getProperty_attached_geometry().size();
61 for (int i = 0; i < nag; ++i) {
62 upd_attached_geometry(i).setFrame(*this);
63 }
64 }
65
extendAddToSystem(SimTK::MultibodySystem & system) const66 void Frame::extendAddToSystem(SimTK::MultibodySystem& system) const
67 {
68 Super::extendAddToSystem(system);
69 SimTK::Transform x;
70 SpatialVec v;
71 // If the properties, topology or coordinate values change,
72 // Stage::Position and above will be invalid.
73 addCacheVariable("transform_in_g", x, SimTK::Stage::Position);
74 // if a speed (u) changes then Stage::Velocity will also be invalid
75 addCacheVariable("velocity_in_g", v, SimTK::Stage::Velocity);
76 // if a force changes then Stage::Acceleration will also be invalid
77 addCacheVariable("acceleration_in_g", v, SimTK::Stage::Acceleration);
78 }
79
getTransformInGround(const State & s) const80 const SimTK::Transform& Frame::getTransformInGround(const State& s) const
81 {
82 if (!getSystem().getDefaultSubsystem().
83 isCacheValueRealized(s, _transformIndex)){
84 //cache is not valid so calculate the transform
85 SimTK::Value<SimTK::Transform>::downcast(
86 getSystem().getDefaultSubsystem().updCacheEntry(s, _transformIndex))
87 .upd() = calcTransformInGround(s);
88 // mark cache as up-to-date
89 getSystem().getDefaultSubsystem().
90 markCacheValueRealized(s, _transformIndex);
91 }
92 return SimTK::Value<SimTK::Transform>::downcast(
93 getSystem().getDefaultSubsystem().
94 getCacheEntry(s, _transformIndex)).get();
95 }
96
getVelocityInGround(const State & s) const97 const SimTK::SpatialVec& Frame::getVelocityInGround(const State& s) const
98 {
99 if (!getSystem().getDefaultSubsystem().
100 isCacheValueRealized(s, _velocityIndex)) {
101 //cache is not valid so calculate the transform
102 SimTK::Value<SpatialVec>::downcast(
103 getSystem().getDefaultSubsystem().
104 updCacheEntry(s, _velocityIndex)).upd()
105 = calcVelocityInGround(s);
106 // mark cache as up-to-date
107 getSystem().getDefaultSubsystem().
108 markCacheValueRealized(s, _velocityIndex);
109 }
110 return SimTK::Value<SpatialVec>::downcast(
111 getSystem().getDefaultSubsystem().
112 getCacheEntry(s, _velocityIndex)).get();
113 }
114
getAngularVelocityInGround(const State & s) const115 const SimTK::Vec3& Frame::getAngularVelocityInGround(const State& s) const
116 {
117 return getVelocityInGround(s)[0];
118 }
119
getLinearVelocityInGround(const State & s) const120 const SimTK::Vec3& Frame::getLinearVelocityInGround(const State& s) const
121 {
122 return getVelocityInGround(s)[1];
123 }
124
getAccelerationInGround(const State & s) const125 const SimTK::SpatialVec& Frame::getAccelerationInGround(const State& s) const
126 {
127 if (!getSystem().getDefaultSubsystem().
128 isCacheValueRealized(s, _accelerationIndex)) {
129 //cache is not valid so calculate the transform
130 SimTK::Value<SpatialVec>::downcast(
131 getSystem().getDefaultSubsystem().
132 updCacheEntry(s, _accelerationIndex)).upd()
133 = calcAccelerationInGround(s);
134 // mark cache as up-to-date
135 getSystem().getDefaultSubsystem().
136 markCacheValueRealized(s, _accelerationIndex);
137 }
138 return SimTK::Value<SpatialVec>::downcast(
139 getSystem().getDefaultSubsystem().
140 getCacheEntry(s, _accelerationIndex)).get();
141 }
142
getAngularAccelerationInGround(const State & s) const143 const SimTK::Vec3& Frame::getAngularAccelerationInGround(const State& s) const
144 {
145 return getAccelerationInGround(s)[0];
146 }
147
getLinearAccelerationInGround(const State & s) const148 const SimTK::Vec3& Frame::getLinearAccelerationInGround(const State& s) const
149 {
150 return getAccelerationInGround(s)[1];
151 }
152
attachGeometry(OpenSim::Geometry * geom)153 void Frame::attachGeometry(OpenSim::Geometry* geom)
154 {
155 // Check that name exists and is unique as it's used to form PathName
156 if (geom->getName().empty()) {
157 bool nameFound = false;
158 int index = 1;
159 while (!nameFound) {
160 std::stringstream ss;
161 // generate candidate name
162 ss << getName() << "_geom_" << index;
163 std::string candidate = ss.str();
164 bool exists = false;
165 for (int idx = 0;
166 idx < getProperty_attached_geometry().size() && !exists; idx++) {
167 if (get_attached_geometry(idx).getName() == candidate) {
168 exists = true;
169 break;
170 }
171 }
172 if (!exists) {
173 nameFound = true;
174 geom->setName(candidate);
175 }
176 else
177 index++;
178 }
179 }
180
181 geom->setFrame(*this);
182 updProperty_attached_geometry().adoptAndAppendValue(geom);
183 finalizeFromProperties();
184 prependComponentPathToConnecteePath(*geom);
185 }
186
scaleAttachedGeometry(const SimTK::Vec3 & scaleFactors)187 void Frame::scaleAttachedGeometry(const SimTK::Vec3& scaleFactors)
188 {
189 for (int i = 0; i < getProperty_attached_geometry().size(); ++i) {
190 Geometry& geo = upd_attached_geometry(i);
191 geo.upd_scale_factors() = geo.get_scale_factors()
192 .elementwiseMultiply(scaleFactors);
193 }
194 }
195
extendScale(const SimTK::State & s,const ScaleSet & scaleSet)196 void Frame::extendScale(const SimTK::State& s, const ScaleSet& scaleSet)
197 {
198 Super::extendScale(s, scaleSet);
199
200 if (getProperty_attached_geometry().size() == 0)
201 return;
202
203 // Get scale factors (if an entry for the base Body exists).
204 const Vec3& scaleFactors = getScaleFactors(scaleSet, *this);
205 if (scaleFactors == ModelComponent::InvalidScaleFactors)
206 return;
207
208 scaleAttachedGeometry(scaleFactors);
209 }
210
211 //=============================================================================
212 // FRAME COMPUTATIONS
213 //=============================================================================
214 //_____________________________________________________________________________
findTransformBetween(const SimTK::State & state,const Frame & otherFrame) const215 SimTK::Transform Frame::findTransformBetween(const SimTK::State& state,
216 const Frame& otherFrame) const
217 {
218 const SimTK::Transform& X_GF = getTransformInGround(state);
219 const SimTK::Transform& X_GA = otherFrame.getTransformInGround(state);
220 // return the transform, X_AF that expresses quantities in F into A
221 return ~X_GA*X_GF;
222 }
223
expressVectorInAnotherFrame(const SimTK::State & state,const SimTK::Vec3 & vec,const Frame & frame) const224 SimTK::Vec3 Frame::expressVectorInAnotherFrame(const SimTK::State& state,
225 const SimTK::Vec3& vec, const Frame& frame) const
226 {
227 return findTransformBetween(state, frame).R()*vec;
228 }
229
expressVectorInGround(const SimTK::State & state,const SimTK::Vec3 & vec_F) const230 SimTK::Vec3 Frame::expressVectorInGround(const SimTK::State& state,
231 const SimTK::Vec3& vec_F) const
232 {
233 return getTransformInGround(state).R()*vec_F;
234 }
235
findStationLocationInAnotherFrame(const SimTK::State & state,const SimTK::Vec3 & station_F,const Frame & otherFrame) const236 SimTK::Vec3 Frame::findStationLocationInAnotherFrame(const SimTK::State& state,
237 const SimTK::Vec3& station_F, const Frame& otherFrame) const
238 {
239 return findTransformBetween(state, otherFrame)*station_F;
240 }
241
findStationLocationInGround(const SimTK::State & state,const SimTK::Vec3 & station_F) const242 SimTK::Vec3 Frame::findStationLocationInGround(const SimTK::State& state,
243 const SimTK::Vec3& station_F) const
244 {
245 return getTransformInGround(state)*station_F;
246 }
247
findStationVelocityInGround(const SimTK::State & state,const SimTK::Vec3 & station_F) const248 SimTK::Vec3 Frame::findStationVelocityInGround(const SimTK::State& state,
249 const SimTK::Vec3& station_F) const
250 {
251 const SimTK::SpatialVec& V_GF = getVelocityInGround(state);
252 SimTK::Vec3 r_G = expressVectorInGround(state, station_F);
253 return V_GF[1] + SimTK::cross(V_GF[0], r_G);
254 }
255
findStationAccelerationInGround(const SimTK::State & state,const SimTK::Vec3 & station_F) const256 SimTK::Vec3 Frame::findStationAccelerationInGround(const SimTK::State& state,
257 const SimTK::Vec3& station_F) const
258 {
259 const SimTK::SpatialVec& V_GF = getVelocityInGround(state);
260 const SimTK::SpatialVec& A_GF = getAccelerationInGround(state);
261 SimTK::Vec3 r_G = expressVectorInGround(state, station_F);
262 return A_GF[1] + SimTK::cross(A_GF[0], r_G) +
263 SimTK::cross(V_GF[0], SimTK::cross(V_GF[0], r_G));
264 }
265
findBaseFrame() const266 const Frame& Frame::findBaseFrame() const
267 {
268 return extendFindBaseFrame();
269 }
270
findTransformInBaseFrame() const271 SimTK::Transform Frame::findTransformInBaseFrame() const
272 {
273 return extendFindTransformInBaseFrame();
274 }
275
extendRealizeTopology(SimTK::State & s) const276 void Frame::extendRealizeTopology(SimTK::State& s) const
277 {
278 Super::extendRealizeTopology(s);
279
280 const_cast<Self*>(this)->_transformIndex =
281 getCacheVariableIndex("transform_in_g");
282
283 const_cast<Self*>(this)->_velocityIndex =
284 getCacheVariableIndex("velocity_in_g");
285
286 const_cast<Self*>(this)->_accelerationIndex =
287 getCacheVariableIndex("acceleration_in_g");
288 }
289