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