1 /* -------------------------------------------------------------------------- *
2  *                               Simbody(tm)                                  *
3  * -------------------------------------------------------------------------- *
4  * This is part of the SimTK biosimulation toolkit originating from           *
5  * Simbios, the NIH National Center for Physics-Based Simulation of           *
6  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
7  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
8  *                                                                            *
9  * Portions copyright (c) 2007-13 Stanford University and the Authors.        *
10  * Authors: Michael Sherman                                                   *
11  * Contributors: Peter Eastman                                                *
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 /**@file
25  *
26  * Private implementation of MobilizedBody, and its included subclasses which
27  * represent the built-in mobilizer types.
28  */
29 
30 #include "SimTKcommon.h"
31 #include "simbody/internal/common.h"
32 #include "simbody/internal/MobilizedBody.h"
33 #include "simbody/internal/MobilizedBody_BuiltIns.h"
34 
35 #include "MobilizedBodyImpl.h"
36 #include "SimbodyMatterSubsystemRep.h"
37 
38 namespace SimTK {
39 
40     ////////////////////
41     // MOBILIZED BODY //
42     ////////////////////
43 
MobilizedBody(MobilizedBodyImpl * r)44 MobilizedBody::MobilizedBody(MobilizedBodyImpl* r) : HandleBase(r) {
45 }
46 
47 int MobilizedBody::
addOutboardDecoration(const Transform & X_MD,const DecorativeGeometry & g)48 addOutboardDecoration(const Transform& X_MD,  const DecorativeGeometry& g)
49 {   return updImpl().addOutboardDecoration(X_MD,g); }
getNumOutboardDecorations() const50 int MobilizedBody::getNumOutboardDecorations() const
51 {   return (int)getImpl().outboardGeometry.size(); }
getOutboardDecoration(int i) const52 const DecorativeGeometry& MobilizedBody::getOutboardDecoration(int i) const
53 {   return getImpl().outboardGeometry[i]; }
updOutboardDecoration(int i)54 DecorativeGeometry& MobilizedBody::updOutboardDecoration(int i)
55 {   return updImpl().outboardGeometry[i]; }
56 
57 int MobilizedBody::
addInboardDecoration(const Transform & X_FD,const DecorativeGeometry & g)58 addInboardDecoration(const Transform& X_FD, const DecorativeGeometry& g)
59 {   return updImpl().addInboardDecoration(X_FD,g); }
getNumInboardDecorations() const60 int MobilizedBody::getNumInboardDecorations() const
61 {   return (int)getImpl().inboardGeometry.size(); }
getInboardDecoration(int i) const62 const DecorativeGeometry& MobilizedBody::getInboardDecoration(int i) const
63 {   return getImpl().inboardGeometry[i]; }
updInboardDecoration(int i)64 DecorativeGeometry& MobilizedBody::updInboardDecoration(int i)
65 {   return updImpl().inboardGeometry[i]; }
66 
67 
68 void MobilizedBody::
lock(State & s,Motion::Level level) const69 lock(State& s, Motion::Level level) const
70 {   getImpl().lock(s,level); }
71 
72 void MobilizedBody::
lockAt(State & s,Real value,Motion::Level level) const73 lockAt(State& s, Real value, Motion::Level level) const
74 {   getImpl().lockAt(s,1,&value,level); }
75 
76 void MobilizedBody::
lockAt(State & s,const Vector & value,Motion::Level level) const77 lockAt(State& s, const Vector& value, Motion::Level level) const
78 {
79     const MobilizedBodyImpl& impl = getImpl();
80     if (value.hasContiguousData()) {
81         getImpl().lockAt(s,value.size(),&value[0],level);
82         return;
83     }
84 
85     Vector contig(value.size()); // contiguous
86     contig.viewAssign(value); // don't reallocate
87     // This will produce an error if value.size()>7.
88     getImpl().lockAt(s,value.size(),&contig[0],level);
89 }
90 
91 template <> SimTK_SIMBODY_EXPORT void MobilizedBody::
lockAt(State & s,const Vec<1> & value,Motion::Level level) const92 lockAt(State& s, const Vec<1>& value, Motion::Level level) const
93 {   getImpl().lockAt(s,1,&value[0],level); }
94 template <> SimTK_SIMBODY_EXPORT void MobilizedBody::
lockAt(State & s,const Vec<2> & value,Motion::Level level) const95 lockAt(State& s, const Vec<2>& value, Motion::Level level) const
96 {   getImpl().lockAt(s,2,&value[0],level); }
97 template <> SimTK_SIMBODY_EXPORT void MobilizedBody::
lockAt(State & s,const Vec<3> & value,Motion::Level level) const98 lockAt(State& s, const Vec<3>& value, Motion::Level level) const
99 {   getImpl().lockAt(s,3,&value[0],level); }
100 template <> SimTK_SIMBODY_EXPORT void MobilizedBody::
lockAt(State & s,const Vec<4> & value,Motion::Level level) const101 lockAt(State& s, const Vec<4>& value, Motion::Level level) const
102 {   getImpl().lockAt(s,4,&value[0],level); }
103 template <> SimTK_SIMBODY_EXPORT void MobilizedBody::
lockAt(State & s,const Vec<5> & value,Motion::Level level) const104 lockAt(State& s, const Vec<5>& value, Motion::Level level) const
105 {   getImpl().lockAt(s,5,&value[0],level); }
106 template <> SimTK_SIMBODY_EXPORT void MobilizedBody::
lockAt(State & s,const Vec<6> & value,Motion::Level level) const107 lockAt(State& s, const Vec<6>& value, Motion::Level level) const
108 {   getImpl().lockAt(s,6,&value[0],level); }
109 template <> SimTK_SIMBODY_EXPORT void MobilizedBody::
lockAt(State & s,const Vec<7> & value,Motion::Level level) const110 lockAt(State& s, const Vec<7>& value, Motion::Level level) const
111 {   getImpl().lockAt(s,7,&value[0],level); }
112 
unlock(State & s) const113 void MobilizedBody::unlock(State& s) const
114 {   getImpl().unlock(s); }
115 
getLockLevel(const State & s) const116 Motion::Level MobilizedBody::getLockLevel(const State& s) const
117 {   return getImpl().getLockLevel(s); }
118 
getLockValueAsVector(const State & s) const119 Vector MobilizedBody::getLockValueAsVector(const State& s) const
120 {   return getImpl().getLockValueAsVector(s); }
121 
lockByDefault(Motion::Level level)122 MobilizedBody& MobilizedBody::lockByDefault(Motion::Level level)
123 {   updImpl().lockByDefault(level); return *this; }
124 
getLockByDefaultLevel() const125 Motion::Level MobilizedBody::getLockByDefaultLevel() const
126 {   return getImpl().getLockByDefaultLevel(); }
127 
128 
getMatterSubsystem() const129 const SimbodyMatterSubsystem& MobilizedBody::getMatterSubsystem() const {
130     SimTK_ASSERT_ALWAYS(isInSubsystem(),
131         "getMatterSubsystem() called on a MobilizedBody that is not part of a subsystem.");
132     return getImpl().getMyMatterSubsystemRep().getMySimbodyMatterSubsystemHandle();
133 }
134 
135 
getMobilizedBodyIndex() const136 MobilizedBodyIndex MobilizedBody::getMobilizedBodyIndex() const {
137     SimTK_ASSERT_ALWAYS(isInSubsystem(),
138         "getMobilizedBodyIndex() called on a MobilizedBody that is not part of a subsystem.");
139     return getImpl().getMyMobilizedBodyIndex();
140 }
141 
getParentMobilizedBody() const142 const MobilizedBody& MobilizedBody::getParentMobilizedBody() const {
143     SimTK_ASSERT_ALWAYS(isInSubsystem(),
144         "getParentMobilizedBody() called on a MobilizedBody that is not part of a subsystem.");
145     return getImpl().getMyMatterSubsystemRep()
146            .getMobilizedBody(getImpl().getMyParentMobilizedBodyIndex());
147 }
148 
getBaseMobilizedBody() const149 const MobilizedBody& MobilizedBody::getBaseMobilizedBody() const {
150     SimTK_ASSERT_ALWAYS(isInSubsystem(),
151         "getBaseMobilizedBody() called on a MobilizedBody that is not part of a subsystem.");
152     return getImpl().getMyMatterSubsystemRep()
153            .getMobilizedBody(getImpl().getMyBaseBodyMobilizedBodyIndex());
154 }
155 
isInSubsystem() const156 bool MobilizedBody::isInSubsystem() const {
157     return !isEmptyHandle() && getImpl().isInSubsystem();
158 }
159 
isInSameSubsystem(const MobilizedBody & otherBody) const160 bool MobilizedBody::isInSameSubsystem(const MobilizedBody& otherBody) const {
161     return isInSubsystem() && otherBody.isInSubsystem()
162         && getMatterSubsystem().isSameSubsystem(otherBody.getMatterSubsystem());
163 }
164 
isSameMobilizedBody(const MobilizedBody & otherBody) const165 bool MobilizedBody::isSameMobilizedBody(const MobilizedBody& otherBody) const {
166     return hasSameImplementation(otherBody);
167 }
168 
isGround() const169 bool MobilizedBody::isGround() const {
170     return isInSubsystem()
171         && isSameMobilizedBody(getMatterSubsystem().getGround());
172 }
173 
getLevelInMultibodyTree() const174 int MobilizedBody::getLevelInMultibodyTree() const {
175     return getImpl().getMyLevel();
176 }
177 
updMatterSubsystem()178 SimbodyMatterSubsystem& MobilizedBody::updMatterSubsystem() {
179     SimTK_ASSERT_ALWAYS(isInSubsystem(),
180         "updMatterSubsystem() called on a MobilizedBody that is not part of a subsystem.");
181     return updImpl().updMyMatterSubsystemRep()
182             .updMySimbodyMatterSubsystemHandle();
183 }
184 
getBody() const185 const Body& MobilizedBody::getBody() const {
186     return getImpl().theBody;
187 }
updBody()188 Body& MobilizedBody::updBody() {
189     getImpl().invalidateTopologyCache();
190     return updImpl().theBody;
191 }
setBody(const Body & b)192 MobilizedBody& MobilizedBody::setBody(const Body& b) {
193     updBody() = b;
194     return *this;
195 }
setDefaultInboardFrame(const Transform & X_PMb)196 MobilizedBody& MobilizedBody::setDefaultInboardFrame (const Transform& X_PMb) {
197     getImpl().invalidateTopologyCache();
198     updImpl().defaultInboardFrame = X_PMb;
199     return *this;
200 }
setDefaultOutboardFrame(const Transform & X_BM)201 MobilizedBody& MobilizedBody::setDefaultOutboardFrame(const Transform& X_BM) {
202     getImpl().invalidateTopologyCache();
203     updImpl().defaultOutboardFrame = X_BM;
204     return *this;
205 }
206 
getDefaultInboardFrame() const207 const Transform& MobilizedBody::getDefaultInboardFrame() const {
208     return getImpl().defaultInboardFrame;
209 }
getDefaultOutboardFrame() const210 const Transform& MobilizedBody::getDefaultOutboardFrame() const {
211     return getImpl().defaultOutboardFrame;
212 }
213 
214 // Access to State
215 
getBodyMassProperties(const State & s) const216 const MassProperties& MobilizedBody::getBodyMassProperties(const State& s) const
217 {   return getImpl().getBodyMassProperties(s); }
218 
219 const SpatialInertia& MobilizedBody::
getBodySpatialInertiaInGround(const State & s) const220 getBodySpatialInertiaInGround(const State& s) const {
221     return getImpl().getBodySpatialInertiaInGround(s);
222 }
223 
getInboardFrame(const State & s) const224 const Transform& MobilizedBody::getInboardFrame (const State& s) const {
225     return getImpl().getInboardFrame(s);
226 }
getOutboardFrame(const State & s) const227 const Transform& MobilizedBody::getOutboardFrame(const State& s) const {
228     return getImpl().getOutboardFrame(s);
229 }
230 
setInboardFrame(State & s,const Transform & X_PMb) const231 void MobilizedBody::setInboardFrame (State& s, const Transform& X_PMb) const {
232     getImpl().setInboardFrame(s, X_PMb);
233 }
setOutboardFrame(State & s,const Transform & X_BM) const234 void MobilizedBody::setOutboardFrame(State& s, const Transform& X_BM) const {
235     getImpl().setOutboardFrame(s, X_BM);
236 }
237 
getBodyTransform(const State & s) const238 const Transform& MobilizedBody::getBodyTransform(const State& s) const {
239     return getImpl().getBodyTransform(s);
240 }
getBodyVelocity(const State & s) const241 const SpatialVec& MobilizedBody::getBodyVelocity(const State& s) const {
242     return getImpl().getBodyVelocity(s);
243 }
getBodyAcceleration(const State & s) const244 const SpatialVec& MobilizedBody::getBodyAcceleration(const State& s) const {
245     return getImpl().getBodyAcceleration(s);
246 }
247 
getMobilizerTransform(const State & s) const248 const Transform& MobilizedBody::getMobilizerTransform(const State& s) const {
249     return getImpl().getMobilizerTransform(s);
250 }
getMobilizerVelocity(const State & s) const251 const SpatialVec& MobilizedBody::getMobilizerVelocity(const State& s) const {
252     return getImpl().getMobilizerVelocity(s);
253 }
254 
setQToFitTransform(State & s,const Transform & X_MbM) const255 void MobilizedBody::setQToFitTransform(State& s, const Transform& X_MbM) const {
256     getImpl().setQToFitTransform(s,X_MbM);
257 }
setQToFitRotation(State & s,const Rotation & R_MbM) const258 void MobilizedBody::setQToFitRotation(State& s, const Rotation& R_MbM) const {
259     getImpl().setQToFitRotation(s,R_MbM);
260 }
setQToFitTranslation(State & s,const Vec3 & p_MbM) const261 void MobilizedBody::setQToFitTranslation(State& s, const Vec3& p_MbM) const {
262     getImpl().setQToFitTranslation(s,p_MbM);
263 }
setUToFitVelocity(State & s,const SpatialVec & V_MbM) const264 void MobilizedBody::setUToFitVelocity(State& s, const SpatialVec& V_MbM) const {
265     getImpl().setUToFitVelocity(s,V_MbM);
266 }
setUToFitAngularVelocity(State & s,const Vec3 & w_MbM) const267 void MobilizedBody::setUToFitAngularVelocity(State& s, const Vec3& w_MbM) const {
268     getImpl().setUToFitAngularVelocity(s,w_MbM);
269 }
setUToFitLinearVelocity(State & s,const Vec3 & v_MbM) const270 void MobilizedBody::setUToFitLinearVelocity(State& s, const Vec3& v_MbM) const {
271     getImpl().setUToFitLinearVelocity(s,v_MbM);
272 }
273 
getHCol(const State & s,MobilizerUIndex ux) const274 SpatialVec MobilizedBody::getHCol(const State& s, MobilizerUIndex ux) const {
275     SimTK_INDEXCHECK(ux, getNumU(s), "MobilizedBody::getHCol()");
276     return getImpl().getHCol(s,ux);
277 }
278 
getH_FMCol(const State & s,MobilizerUIndex ux) const279 SpatialVec MobilizedBody::getH_FMCol(const State& s, MobilizerUIndex ux) const {
280     SimTK_INDEXCHECK(ux, getNumU(s), "MobilizedBody::getH_FMCol()");
281     return getImpl().getH_FMCol(s,ux);
282 }
283 
getNumQ(const State & s) const284 int MobilizedBody::getNumQ(const State& s) const {
285     QIndex qStart; int nq; getImpl().findMobilizerQs(s, qStart, nq);
286     return nq;
287 }
288 
getFirstQIndex(const State & s) const289 QIndex MobilizedBody::getFirstQIndex(const State& s) const {
290     QIndex qStart; int nq; getImpl().findMobilizerQs(s, qStart, nq);
291     return qStart;
292 }
293 
getNumU(const State & s) const294 int MobilizedBody::getNumU(const State& s) const {
295     UIndex uStart; int nu; getImpl().findMobilizerUs(s, uStart, nu);
296     return nu;
297 }
298 
getFirstUIndex(const State & s) const299 UIndex MobilizedBody::getFirstUIndex(const State& s) const {
300     UIndex uStart; int nu; getImpl().findMobilizerUs(s, uStart, nu);
301     return uStart;
302 }
303 
getQMotionMethod(const State & s) const304 Motion::Method MobilizedBody::getQMotionMethod(const State& s) const
305 {   return getImpl().getQMotionMethod(s); }
getUMotionMethod(const State & s) const306 Motion::Method MobilizedBody::getUMotionMethod(const State& s) const
307 {   return getImpl().getUMotionMethod(s); }
getUDotMotionMethod(const State & s) const308 Motion::Method MobilizedBody::getUDotMotionMethod(const State& s) const
309 {   return getImpl().getUDotMotionMethod(s); }
310 
getOneFromQPartition(const State & s,int which,const Vector & qlike) const311 Real MobilizedBody::getOneFromQPartition
312    (const State& s, int which, const Vector& qlike) const {
313     QIndex qStart; int nq; getImpl().findMobilizerQs(s, qStart, nq);
314     assert(0 <= which && which < nq);
315     return qlike[qStart+which];
316 }
updOneFromQPartition(const State & s,int which,Vector & qlike) const317 Real& MobilizedBody::updOneFromQPartition
318    (const State& s, int which, Vector& qlike) const {
319     QIndex qStart; int nq; getImpl().findMobilizerQs(s, qStart, nq);
320     assert(0 <= which && which < nq);
321     return qlike[qStart+which];
322 }
323 
getOneFromUPartition(const State & s,int which,const Vector & ulike) const324 Real MobilizedBody::getOneFromUPartition
325    (const State& s, int which, const Vector& ulike) const {
326     UIndex uStart; int nu; getImpl().findMobilizerUs(s, uStart, nu);
327     assert(0 <= which && which < nu);
328     return ulike[uStart+which];
329 }
updOneFromUPartition(const State & s,int which,Vector & ulike) const330 Real& MobilizedBody::updOneFromUPartition
331    (const State& s, int which, Vector& ulike) const {
332     UIndex uStart; int nu; getImpl().findMobilizerUs(s, uStart, nu);
333     assert(0 <= which && which < nu);
334     return ulike[uStart+which];
335 }
336 
337 void MobilizedBody::
convertQForceToUForce(const State & state,const Array_<Real,MobilizerQIndex> & fq,Array_<Real,MobilizerUIndex> & fu) const338 convertQForceToUForce(  const State&                        state,
339                         const Array_<Real,MobilizerQIndex>& fq,
340                         Array_<Real,MobilizerUIndex>&       fu) const
341 {
342     const MobilizedBodyImpl& impl = getImpl();
343     const SimbodyMatterSubsystemRep& matter = impl.getMyMatterSubsystemRep();
344 
345     UIndex uStart; int nu;
346     QIndex qStart; int nq;
347     matter.findMobilizerUs(state, impl.getMyMobilizedBodyIndex(), uStart, nu);
348     matter.findMobilizerQs(state, impl.getMyMobilizedBodyIndex(), qStart, nq);
349     assert(fq.size() == nq);
350 
351     fu.resize(nu);
352     const RigidBodyNode& node = impl.getMyRigidBodyNode();
353     const SBStateDigest digest(state, matter, Stage::Velocity);
354     node.multiplyByN(digest, true, fq.cbegin(), fu.begin());
355 }
356 
357 SpatialVec MobilizedBody::
findMobilizerReactionOnBodyAtMInGround(const State & s) const358 findMobilizerReactionOnBodyAtMInGround(const State& s) const {
359     const SpatialVec FB_G = findMobilizerReactionOnBodyAtOriginInGround(s);
360     // Shift to M
361     const Rotation&  R_GB   = getBodyRotation(s);
362     const Vec3&      p_BM   = getOutboardFrame(s).p();
363     const Vec3       p_BM_G = R_GB*p_BM; // p_BM in G, 15 flops
364     const SpatialVec FM_G = shiftForceBy(FB_G, p_BM_G);  // 12 flop
365     return FM_G;
366 }
367 
368 
369 SpatialVec MobilizedBody::
findMobilizerReactionOnBodyAtOriginInGround(const State & s) const370 findMobilizerReactionOnBodyAtOriginInGround(const State& s) const {
371     const MobilizedBodyImpl& impl = getImpl();
372     const SimbodyMatterSubsystemRep& matter = impl.getMyMatterSubsystemRep();
373 
374     // This will initiate computation if necessary.
375     const Array_<ArticulatedInertia,MobilizedBodyIndex>& PPlus =
376                                         matter.getArticulatedBodyInertiasPlus(s);
377     const Array_<SpatialVec,MobilizedBodyIndex>& zPlus =
378                                         matter.getArticulatedBodyForcesPlus(s);
379 
380     const Transform& X_GB = impl.getBodyTransform(s);
381     const MobilizedBodyIndex mbx = impl.getMyMobilizedBodyIndex();
382 
383     SpatialVec FB_G = zPlus[mbx];
384     if (mbx != GroundIndex) {
385         const MobilizedBody& parent = getParentMobilizedBody();
386         const Transform&  X_GP = parent.getBodyTransform(s);
387         const SpatialVec& A_GP = parent.getBodyAcceleration(s);
388         const Vec3& p_PB_G = X_GB.p() - X_GP.p(); // 3 flops
389         SpatialVec APlus( A_GP[0],
390                           A_GP[1] + A_GP[0] % p_PB_G ); // 12 flops
391         FB_G += PPlus[mbx]*APlus; // 72 flops
392     }
393     return FB_G;
394 }
395 
396 
397 SpatialVec MobilizedBody::
findMobilizerReactionOnParentAtFInGround(const State & s) const398 findMobilizerReactionOnParentAtFInGround(const State& s) const {
399     const SpatialVec FP_G = findMobilizerReactionOnParentAtOriginInGround(s);
400     // Shift from P to F
401     const Vec3&      p_PF   = getInboardFrame(s).p();
402     if (isGround())
403         return shiftForceBy(FP_G, p_PF); // P==G (12 flops)
404     const Rotation&  R_GP   = getParentMobilizedBody().getBodyRotation(s);
405     const Vec3       p_PF_G = R_GP*p_PF; // p_PF in G, 15 flops
406     return shiftForceBy(FP_G, p_PF_G);  // 12 flops
407 }
408 
409 SpatialVec MobilizedBody::
findMobilizerReactionOnParentAtOriginInGround(const State & s) const410 findMobilizerReactionOnParentAtOriginInGround(const State& s) const {
411     const SpatialVec FB_G = // negate this
412         -findMobilizerReactionOnBodyAtOriginInGround(s); // 6 flops
413     if (isGround())
414         return FB_G; // Ground is welded to the universe at its origin
415 
416     const MobilizedBody& parent = getParentMobilizedBody();
417     const Vec3& p_GB = getBodyTransform(s).p();
418     const Vec3& p_GP = parent.getBodyTransform(s).p();
419     const Vec3 p_BP_G = p_GP - p_GB; // 3 flops
420     const SpatialVec FP_G = shiftForceBy(FB_G, p_BP_G); // 12 flops
421 
422     return FP_G;
423 }
424 
425 
applyBodyForce(const State & s,const SpatialVec & spatialForceInG,Vector_<SpatialVec> & bodyForces) const426 void MobilizedBody::applyBodyForce
427    (const State& s, const SpatialVec& spatialForceInG,
428     Vector_<SpatialVec>& bodyForces) const
429 {
430     assert(bodyForces.size() == getMatterSubsystem().getNumBodies());
431     bodyForces[getMobilizedBodyIndex()] += spatialForceInG;
432 }
433 
applyBodyTorque(const State & s,const Vec3 & torqueInG,Vector_<SpatialVec> & bodyForces) const434 void MobilizedBody::applyBodyTorque(const State& s, const Vec3& torqueInG,
435                      Vector_<SpatialVec>& bodyForces) const
436 {
437     assert(bodyForces.size() == getMatterSubsystem().getNumBodies());
438     bodyForces[getMobilizedBodyIndex()][0] += torqueInG; // don't change force
439 }
440 
applyForceToBodyPoint(const State & s,const Vec3 & pointInB,const Vec3 & forceInG,Vector_<SpatialVec> & bodyForces) const441 void MobilizedBody::applyForceToBodyPoint
442    (const State& s, const Vec3& pointInB, const Vec3& forceInG,
443     Vector_<SpatialVec>& bodyForces) const
444 {
445     assert(bodyForces.size() == getMatterSubsystem().getNumBodies());
446     const Rotation& R_GB = getBodyTransform(s).R();
447     bodyForces[getMobilizedBodyIndex()] +=
448         SpatialVec((R_GB*pointInB) % forceInG, forceInG);
449 }
450 
getOneQ(const State & s,int which) const451 Real MobilizedBody::getOneQ(const State& s, int which) const {
452     return getOneFromQPartition
453        (s,which,getImpl().getMyMatterSubsystemRep().getQ(s));
454 }
455 
setOneQ(State & s,int which,Real value) const456 void MobilizedBody::setOneQ(State& s, int which, Real value) const {
457     updOneFromQPartition
458        (s,which,getImpl().getMyMatterSubsystemRep().updQ(s)) = value;
459 }
460 
getOneU(const State & s,int which) const461 Real MobilizedBody::getOneU(const State& s, int which) const {
462     return getOneFromUPartition
463        (s,which,getImpl().getMyMatterSubsystemRep().getU(s));
464 }
setOneU(State & s,int which,Real value) const465 void MobilizedBody::setOneU(State& s, int which, Real value) const {
466     updOneFromUPartition
467        (s,which,getImpl().getMyMatterSubsystemRep().updU(s)) = value;
468 }
469 
getOneQDot(const State & s,int which) const470 Real MobilizedBody::getOneQDot(const State& s, int which) const {
471     return getOneFromQPartition
472        (s,which,getImpl().getMyMatterSubsystemRep().getQDot(s));
473 }
getOneUDot(const State & s,int which) const474 Real MobilizedBody::getOneUDot(const State& s, int which) const {
475     return getOneFromUPartition
476        (s,which,getImpl().getMyMatterSubsystemRep().getUDot(s));
477 }
getOneQDotDot(const State & s,int which) const478 Real MobilizedBody::getOneQDotDot(const State& s, int which) const {
479     return getOneFromQPartition
480        (s,which,getImpl().getMyMatterSubsystemRep().getQDotDot(s));
481 }
getOneTau(const State & s,MobilizerUIndex which) const482 Real MobilizedBody::getOneTau(const State& s, MobilizerUIndex which) const {
483     const MobilizedBodyImpl&         mbimpl = MobilizedBody::getImpl();
484     const MobilizedBodyIndex         mbx    = mbimpl.getMyMobilizedBodyIndex();
485     const SimbodyMatterSubsystemRep& matter = mbimpl.getMyMatterSubsystemRep();
486     const SBModelCache&              mc     = matter.getModelCache(s);
487     const SBModelPerMobodInfo&
488         mobodModelInfo = mc.getMobodModelInfo(mbx);
489     const int nu = mobodModelInfo.nUInUse;
490 
491     SimTK_INDEXCHECK(which, nu, "MobilizedBody::getOneTau()");
492 
493     const SBInstanceCache& ic = matter.getInstanceCache(s);
494     const SBInstancePerMobodInfo&
495         mobodInstanceInfo = ic.getMobodInstanceInfo(mbx);
496     if (mobodInstanceInfo.udotMethod == Motion::Free)
497         return 0; // not prescribed
498 
499     const SBTreeAccelerationCache& tac = matter.getTreeAccelerationCache(s);
500     return tac.presMotionForces[mobodInstanceInfo.firstPresForce + which];
501 }
502 
getTauAsVector(const State & s) const503 Vector MobilizedBody::getTauAsVector(const State& s) const {
504     const MobilizedBodyImpl&         mbimpl = MobilizedBody::getImpl();
505     const MobilizedBodyIndex         mbx    = mbimpl.getMyMobilizedBodyIndex();
506     const SimbodyMatterSubsystemRep& matter = mbimpl.getMyMatterSubsystemRep();
507     const SBModelCache&              mc     = matter.getModelCache(s);
508     const SBModelPerMobodInfo&
509         mobodModelInfo = mc.getMobodModelInfo(mbx);
510     const int nu = mobodModelInfo.nUInUse;
511 
512     const SBInstanceCache& ic = matter.getInstanceCache(s);
513     const SBInstancePerMobodInfo&
514         mobodInstanceInfo = ic.getMobodInstanceInfo(mbx);
515     if (mobodInstanceInfo.udotMethod == Motion::Free)
516         return Vector(nu, Real(0)); // not prescribed
517 
518     const SBTreeAccelerationCache& tac = matter.getTreeAccelerationCache(s);
519     return tac.presMotionForces(mobodInstanceInfo.firstPresForce, nu);
520 }
521 
getQAsVector(const State & s) const522 Vector MobilizedBody::getQAsVector(const State& s) const {
523     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
524     QIndex qStart; int nq; mbr.findMobilizerQs(s, qStart, nq);
525     return mbr.getMyMatterSubsystemRep().getQ(s)(qStart,nq);
526 }
527 
setQFromVector(State & s,const Vector & q) const528 void MobilizedBody::setQFromVector(State& s, const Vector& q) const {
529     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
530     QIndex qStart; int nq; mbr.findMobilizerQs(s, qStart, nq);
531     assert(q.size() == nq);
532     mbr.getMyMatterSubsystemRep().updQ(s)(qStart,nq) = q;
533 }
534 
getUAsVector(const State & s) const535 Vector MobilizedBody::getUAsVector(const State& s) const {
536     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
537     UIndex uStart; int nu; mbr.findMobilizerUs(s, uStart, nu);
538     return mbr.getMyMatterSubsystemRep().getU(s)(uStart,nu);
539 }
540 
setUFromVector(State & s,const Vector & u) const541 void MobilizedBody::setUFromVector(State& s, const Vector& u) const {
542     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
543     UIndex uStart; int nu; mbr.findMobilizerUs(s, uStart, nu);
544     assert(u.size() == nu);
545     mbr.getMyMatterSubsystemRep().updU(s)(uStart,nu) = u;
546 }
547 
getQDotAsVector(const State & s) const548 Vector MobilizedBody::getQDotAsVector(const State& s) const {
549     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
550     QIndex qStart; int nq; mbr.findMobilizerQs(s, qStart, nq);
551     return mbr.getMyMatterSubsystemRep().getQDot(s)(qStart,nq);
552 }
553 
getUDotAsVector(const State & s) const554 Vector MobilizedBody::getUDotAsVector(const State& s) const {
555     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
556     UIndex uStart; int nu; mbr.findMobilizerUs(s, uStart, nu);
557     return mbr.getMyMatterSubsystemRep().getUDot(s)(uStart,nu);
558 }
559 
getQDotDotAsVector(const State & s) const560 Vector MobilizedBody::getQDotDotAsVector(const State& s) const {
561     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
562     QIndex qStart; int nq; mbr.findMobilizerQs(s, qStart, nq);
563     return mbr.getMyMatterSubsystemRep().getQDotDot(s)(qStart,nq);
564 }
565 
cloneForNewParent(MobilizedBody & parent) const566 MobilizedBody& MobilizedBody::cloneForNewParent(MobilizedBody& parent) const {
567     MobilizedBody copyBody;
568     copyBody.copyAssign(*this);
569     copyBody.updImpl().myMatterSubsystemRep = 0;
570     copyBody.updImpl().myRBnode = 0;
571     parent.updMatterSubsystem()
572         .adoptMobilizedBody(parent.getMobilizedBodyIndex(), copyBody);
573     return parent.updMatterSubsystem()
574         .updMobilizedBody(copyBody.getMobilizedBodyIndex());
575 }
576 
adoptMotion(Motion & ownerHandle)577 void MobilizedBody::adoptMotion(Motion& ownerHandle) {
578    updImpl().adoptMotion(ownerHandle);
579 }
580 
clearMotion()581 void MobilizedBody::clearMotion() {
582    updImpl().clearMotion();
583 }
584 
hasMotion() const585 bool MobilizedBody::hasMotion() const {
586     return getImpl().hasMotion();
587 }
588 
getMotion() const589 const Motion& MobilizedBody::getMotion() const {
590     return getImpl().getMotion();
591 }
592 
593 
594 
595 //==============================================================================
596 //                          MOBILIZED BODY IMPL
597 //==============================================================================
598 
findMobilizerQs(const State & s,QIndex & qStart,int & nq) const599 void MobilizedBodyImpl::findMobilizerQs
600    (const State& s, QIndex& qStart, int& nq) const {
601     getMyMatterSubsystemRep()
602         .findMobilizerQs(s, myMobilizedBodyIndex, qStart, nq);
603 }
findMobilizerUs(const State & s,UIndex & uStart,int & nu) const604 void MobilizedBodyImpl::findMobilizerUs
605    (const State& s, UIndex& uStart, int& nu) const {
606     getMyMatterSubsystemRep()
607         .findMobilizerUs(s, myMobilizedBodyIndex, uStart, nu);
608 }
609 
610 // Set the lock level and record the current q or u if needed so we can
611 // ensure that the state is prescribed to the recorded value. When locking
612 // q, set u to zero now.
613 // Can't do this until *after* realize(Model) because that's when the q's and
614 // u's are sized and the lock-by-default coordinates are recorded, and this
615 // should override those.
616 void MobilizedBodyImpl::
lock(State & state,Motion::Level level) const617 lock(State& state, Motion::Level level) const {
618     SimTK_STAGECHECK_GE_ALWAYS(getMyMatterSubsystemRep().getStage(state),
619         Stage::Model, "MobilizedBody::lock()");
620 
621     SBInstanceVars& iv = getMyMatterSubsystemRep().updInstanceVars(state);
622     iv.mobilizerLockLevel[getMyMobilizedBodyIndex()] = level;
623     UIndex uStart; int nu; findMobilizerUs(state, uStart, nu);
624     const UIndex uEnd(uStart+nu);
625 
626     if (level == Motion::Position) {
627         Vector& u = state.updU(); // set generalized speeds to zero
628         for (UIndex ux=uStart; ux != uEnd; ++ux)
629             u[ux] = 0;
630         const Vector& q = state.getQ();
631         assert(iv.lockedQs.size() == q.size());
632         QIndex qStart; int nq; findMobilizerQs(state, qStart, nq);
633         const QIndex qEnd(qStart+nq);
634         for (QIndex qx=qStart; qx != qEnd; ++qx)
635             iv.lockedQs[qx] = q[qx];
636     }
637     else if (level == Motion::Velocity) {
638         const Vector& u = state.getU();
639         assert(iv.lockedUs.size() == u.size());
640         for (UIndex ux=uStart; ux != uEnd; ++ux)
641             iv.lockedUs[ux] = u[ux];
642     }
643     else if (level == Motion::Acceleration) {
644         for (UIndex ux=uStart; ux != uEnd; ++ux)
645             iv.lockedUs[ux] = 0;
646     }
647 }
648 
649 void MobilizedBodyImpl::
lockAt(State & state,int n,const Real * value,Motion::Level level) const650 lockAt(State& state, int n, const Real* value, Motion::Level level) const {
651     SimTK_STAGECHECK_GE_ALWAYS(getMyMatterSubsystemRep().getStage(state),
652         Stage::Model, "MobilizedBody::lockAt()");
653 
654     SBInstanceVars& iv = getMyMatterSubsystemRep().updInstanceVars(state);
655     iv.mobilizerLockLevel[getMyMobilizedBodyIndex()] = level;
656     UIndex uStart; int nu; findMobilizerUs(state, uStart, nu);
657     const UIndex uEnd(uStart+nu);
658 
659     if (level == Motion::Position) {
660         Vector& u = state.updU(); // set generalized speeds to zero
661         for (UIndex ux=uStart; ux != uEnd; ++ux)
662             u[ux] = 0;
663         Vector& q = state.updQ();
664         QIndex qStart; int nq; findMobilizerQs(state, qStart, nq);
665         const QIndex qEnd(qStart+nq);
666         SimTK_ERRCHK3_ALWAYS(n==nq, "MobilizedBody::lockAt()",
667             "Supplied value had wrong length %d for locking at "
668             "%s level; should have been nq=%d.",
669             n, Motion::nameOfLevel(level), nq);
670         for (QIndex qx=qStart; qx != qEnd; ++qx)
671             q[qx] = iv.lockedQs[qx] = *value++; // set qs now & remember
672     }
673     else if (level == Motion::Velocity || level == Motion::Acceleration) {
674         SimTK_ERRCHK3_ALWAYS(n==nu, "MobilizedBody::lockAt()",
675             "Supplied value had wrong length %d for locking at "
676             "%s level; should have been nu=%d.",
677             n, Motion::nameOfLevel(level), nu);
678         for (UIndex ux=uStart; ux != uEnd; ++ux)
679             iv.lockedUs[ux] = *value++;
680     }
681 }
682 
683 Vector MobilizedBodyImpl::
getLockValueAsVector(const State & state) const684 getLockValueAsVector(const State& state) const {
685     const SBInstanceVars& iv = getMyMatterSubsystemRep().getInstanceVars(state);
686     const Motion::Level level =
687         iv.mobilizerLockLevel[getMyMobilizedBodyIndex()];
688     Vector value;
689     if (level == Motion::Position) {
690         QIndex qStart; int nq; findMobilizerQs(state, qStart, nq);
691         value.resize(nq);
692         for (int i=0; i < nq; ++i)
693             value[i] = iv.lockedQs[QIndex(qStart+i)];
694     } else if (level == Motion::Velocity || level == Motion::Acceleration) {
695         UIndex uStart; int nu; findMobilizerUs(state, uStart, nu);
696         value.resize(nu);
697         for (int i=0; i < nu; ++i)
698              value[i] = iv.lockedUs[UIndex(uStart+i)];
699     }
700     return value;
701 }
702 
703 
704 // OK to do this after realize(Topology) since we're not looking at q or u.
705 // If this was a lock-by-default mobilizer, this will unlock it since the
706 // lock-by-default flag is transferred to InstanceVars during realize(Topology).
unlock(State & state) const707 void MobilizedBodyImpl::unlock(State& state) const {
708     SimTK_STAGECHECK_GE_ALWAYS(getMyMatterSubsystemRep().getStage(state),
709         Stage::Topology, "MobilizedBody::unlock()");
710 
711     SBInstanceVars& iv = getMyMatterSubsystemRep().updInstanceVars(state);
712     iv.mobilizerLockLevel[getMyMobilizedBodyIndex()] = Motion::NoLevel;
713 }
getLockLevel(const State & state) const714 Motion::Level MobilizedBodyImpl::getLockLevel(const State& state) const {
715     const SBInstanceVars& iv = getMyMatterSubsystemRep().getInstanceVars(state);
716     return iv.mobilizerLockLevel[getMyMobilizedBodyIndex()];
717 }
718 
getQMotionMethod(const State & s) const719 Motion::Method MobilizedBodyImpl::getQMotionMethod(const State& s) const
720 {   return getMyInstanceInfo(s).qMethod; }
getUMotionMethod(const State & s) const721 Motion::Method MobilizedBodyImpl::getUMotionMethod(const State& s) const
722 {   return getMyInstanceInfo(s).uMethod; }
getUDotMotionMethod(const State & s) const723 Motion::Method MobilizedBodyImpl::getUDotMotionMethod(const State& s) const
724 {   return getMyInstanceInfo(s).udotMethod; }
725 
726 void MobilizedBodyImpl::
copyOutDefaultQ(const State & s,Vector & qDefault) const727 copyOutDefaultQ(const State& s, Vector& qDefault) const {
728     SimTK_STAGECHECK_GE_ALWAYS(getMyMatterSubsystemRep().getStage(s),
729         Stage::Topology, "MobilizedBody::copyOutDefaultQ()");
730     QIndex qStart; int nq;
731     findMobilizerQs(s, qStart, nq);
732     if (nq) // nq may vary due to modeling options, e.g. 3 or 4 for Ball
733         copyOutDefaultQImpl(nq, &qDefault[qStart]);
734 }
735 
736     // TODO: currently we delegate these requests to the RigidBodyNodes.
737     // Probably most of this functionality should be handled directly
738     // by the MobilizedBody objects.
739 
setQToFitTransform(State & s,const Transform & X_MbM) const740 void MobilizedBodyImpl::setQToFitTransform(State& s, const Transform& X_MbM) const {
741     const SimbodyMatterSubsystemRep& matterRep = getMyMatterSubsystemRep();
742     const SBStateDigest digest(s, matterRep, Stage::Instance);
743     Vector& q = matterRep.updQ(s);
744     return getMyRigidBodyNode().setQToFitTransform(digest, X_MbM, q);
745 }
setQToFitRotation(State & s,const Rotation & R_MbM) const746 void MobilizedBodyImpl::setQToFitRotation(State& s, const Rotation& R_MbM) const {
747     const SimbodyMatterSubsystemRep& matterRep = getMyMatterSubsystemRep();
748     const SBStateDigest digest(s, matterRep, Stage::Instance);
749     Vector& q = matterRep.updQ(s);
750     return getMyRigidBodyNode().setQToFitRotation(digest, R_MbM, q);
751 }
setQToFitTranslation(State & s,const Vec3 & p_MbM) const752 void MobilizedBodyImpl::setQToFitTranslation(State& s, const Vec3& p_MbM) const
753 {
754     const SimbodyMatterSubsystemRep& matterRep = getMyMatterSubsystemRep();
755     const SBStateDigest digest(s, matterRep, Stage::Instance);
756     Vector& q = matterRep.updQ(s);
757     return getMyRigidBodyNode().setQToFitTranslation(digest, p_MbM, q);
758 }
759 
setUToFitVelocity(State & s,const SpatialVec & V_MbM) const760 void MobilizedBodyImpl::setUToFitVelocity(State& s, const SpatialVec& V_MbM) const {
761     const SimbodyMatterSubsystemRep& matterRep = getMyMatterSubsystemRep();
762     const SBStateDigest digest(s, matterRep, Stage::Instance);
763     const Vector& q = matterRep.updQ(s);
764     Vector&       u = matterRep.updU(s);
765     return getMyRigidBodyNode().setUToFitVelocity(digest, q, V_MbM, u);
766 }
setUToFitAngularVelocity(State & s,const Vec3 & w_MbM) const767 void MobilizedBodyImpl::setUToFitAngularVelocity(State& s, const Vec3& w_MbM) const {
768     const SimbodyMatterSubsystemRep& matterRep = getMyMatterSubsystemRep();
769     const SBStateDigest digest(s, matterRep, Stage::Instance);
770     const Vector& q = matterRep.updQ(s);
771     Vector&       u = matterRep.updU(s);
772     return getMyRigidBodyNode().setUToFitAngularVelocity(digest, q, w_MbM, u);
773 }
setUToFitLinearVelocity(State & s,const Vec3 & v_MbM) const774 void MobilizedBodyImpl::setUToFitLinearVelocity(State& s, const Vec3& v_MbM)  const
775 {
776     const SimbodyMatterSubsystemRep& matterRep = getMyMatterSubsystemRep();
777     const SBStateDigest digest(s, matterRep, Stage::Instance);
778     const Vector& q = matterRep.updQ(s);
779     Vector&       u = matterRep.updU(s);
780     return getMyRigidBodyNode().setUToFitLinearVelocity(digest, q, v_MbM, u);
781 }
782 
783     // REALIZE TOPOLOGY
realizeTopology(State & s,UIndex & nxtU,USquaredIndex & nxtUSq,QIndex & nxtQ) const784 const RigidBodyNode& MobilizedBodyImpl::realizeTopology
785    (State& s, UIndex& nxtU, USquaredIndex& nxtUSq, QIndex& nxtQ) const
786 {
787     delete myRBnode;
788     myRBnode = createRigidBodyNode(nxtU,nxtUSq,nxtQ);
789 
790     assert(myMobilizedBodyIndex.isValid());
791     assert(myParentIndex.isValid() || myMobilizedBodyIndex == GroundIndex);
792 
793     if (myParentIndex.isValid()) {
794         // not ground
795         const MobilizedBodyImpl& parent =
796             myMatterSubsystemRep->getMobilizedBody(myParentIndex).getImpl();
797         assert(myLevel == parent.myRBnode->getLevel() + 1);
798         parent.myRBnode->addChild(myRBnode);
799         myRBnode->setParent(parent.myRBnode);
800     }
801 
802     myRBnode->setLevel(myLevel);
803     myRBnode->setNodeNum(myMobilizedBodyIndex);
804 
805     // Realize Motion topology.
806     if (hasMotion())
807         getMotion().getImpl().realizeTopology(s);
808 
809     // Realize MobilizedBody-specific topology.
810     realizeTopologyVirtual(s);
811     return *myRBnode;
812 }
813 
814 //------------------------------------------------------------------------------
815 //                              REALIZE MODEL
816 //------------------------------------------------------------------------------
realizeModel(State & s) const817 void MobilizedBodyImpl::realizeModel(State& s) const {
818     if (hasMotion())
819         getMotion().getImpl().realizeModel(s);
820     realizeModelVirtual(s);
821 }
822 
823 //------------------------------------------------------------------------------
824 //                             REALIZE INSTANCE
825 //------------------------------------------------------------------------------
realizeInstance(const SBStateDigest & sbs) const826 void MobilizedBodyImpl::realizeInstance(const SBStateDigest& sbs) const {
827     if (hasMotion())
828         getMotion().getImpl().realizeInstance(sbs.getState());
829     realizeInstanceVirtual(sbs.getState());
830 }
831 
832 //------------------------------------------------------------------------------
833 //                               REALIZE TIME
834 //------------------------------------------------------------------------------
realizeTime(const SBStateDigest & sbs) const835 void MobilizedBodyImpl::realizeTime(const SBStateDigest& sbs) const {
836     const MobilizedBodyIndex      mbx       = getMyMobilizedBodyIndex();
837     const SBInstanceVars&         iv        = sbs.getInstanceVars();
838     const SBInstanceCache&        ic        = sbs.getInstanceCache();
839     const SBInstancePerMobodInfo& instInfo  = ic.getMobodInstanceInfo(mbx);
840 
841     // Note that we only need to deal with explicitly prescribed motion;
842     // if the mobilizer is prescribed to zero it will be dealt with elsewhere.
843     // A mobilizer can be prescribed either due to a locked position or to
844     // an explicit Motion.
845     if (instInfo.qMethod==Motion::Prescribed) {
846         const SBModelCache&         mc        = sbs.getModelCache();
847         const SBModelPerMobodInfo&  modelInfo = mc.getMobodModelInfo(mbx);
848         const int                   nq        = modelInfo.nQInUse;
849         const QIndex                qStart    = modelInfo.firstQIndex;
850         const PresQPoolIndex        pqx       = instInfo.firstPresQ;
851         SBTimeCache&                tc        = sbs.updTimeCache();
852 
853         if (iv.mobilizerLockLevel[mbx] != Motion::NoLevel) {
854             // Positions are prescribed because of a lock.
855             assert(iv.mobilizerLockLevel[mbx] == Motion::Position);
856             for (int i=0; i < nq; ++i)
857                 tc.presQPool[pqx+i] = iv.lockedQs[QIndex(qStart+i)];
858         } else {
859             // Positions are prescribed because of a Motion.
860             assert(hasMotion() && !iv.prescribedMotionIsDisabled[mbx]);
861             const MotionImpl& motion = getMotion().getImpl();
862             motion.calcPrescribedPosition(sbs.getState(), nq,
863                                           &tc.presQPool[pqx]);
864         }
865     }
866 
867     realizeTimeVirtual(sbs.getState());
868 }
869 
870 //------------------------------------------------------------------------------
871 //                             REALIZE POSITION
872 //------------------------------------------------------------------------------
realizePosition(const SBStateDigest & sbs) const873 void MobilizedBodyImpl::realizePosition(const SBStateDigest& sbs) const {
874     const MobilizedBodyIndex      mbx = getMyMobilizedBodyIndex();
875     const SBInstanceVars&         iv  = sbs.getInstanceVars();
876     const SBInstanceCache&        ic  = sbs.getInstanceCache();
877     const SBInstancePerMobodInfo& instInfo = ic.getMobodInstanceInfo(mbx);
878 
879     // Note that we only need to deal with explicitly prescribed motion;
880     // if the u is prescribed to zero it will be dealt with elsewhere.
881     // Prescribed u may be due to nonholonomic prescribed u, or to derivative
882     // of holonomic prescribed q, or to a lock(Velocity).
883     if (instInfo.uMethod==Motion::Prescribed) {
884         const SBModelCache&         mc        = sbs.getModelCache();
885         const SBModelPerMobodInfo&  modelInfo = mc.getMobodModelInfo(mbx);
886         const int                   nu        = modelInfo.nUInUse;
887         const UIndex                uStart    = modelInfo.firstUIndex;
888         const PresUPoolIndex        pux       = instInfo.firstPresU;
889         SBConstrainedPositionCache& cpc       = sbs.updConstrainedPositionCache();
890 
891         if (iv.mobilizerLockLevel[mbx] != Motion::NoLevel) {
892             // Velocities are prescribed because of a lock.
893             assert(iv.mobilizerLockLevel[mbx] == Motion::Velocity);
894             for (int i=0; i < nu; ++i)
895                 cpc.presUPool[pux+i] = iv.lockedUs[UIndex(uStart+i)];
896         } else {
897             // Velocities are prescribed because of a Motion.
898             assert(hasMotion() && !iv.prescribedMotionIsDisabled[mbx]);
899             const MotionImpl& motion = getMotion().getImpl();
900 
901             if (instInfo.qMethod==Motion::Prescribed) {
902                 // Holonomic
903                 const int nq = modelInfo.nQInUse;
904                 const RigidBodyNode& rbn = getMyRigidBodyNode();
905 
906                 if (rbn.isQDotAlwaysTheSameAsU()) {
907                     assert(nq==nu);
908                     motion.calcPrescribedPositionDot(sbs.getState(), nu,
909                                                      &cpc.presUPool[pux]);
910                 } else {
911                     Real qdot[8]; // we won't use all of these -- max is 7
912                     motion.calcPrescribedPositionDot(sbs.getState(), nq, qdot);
913                     // u = N^-1 qdot
914                     rbn.multiplyByNInv(sbs, false, qdot, &cpc.presUPool[pux]);
915                 }
916             } else { // Non-holonomic
917                 motion.calcPrescribedVelocity(sbs.getState(), nu,
918                                               &cpc.presUPool[pux]);
919             }
920         }
921     }
922 
923     realizePositionVirtual(sbs.getState());
924 }
925 
926 //------------------------------------------------------------------------------
927 //                             REALIZE VELOCITY
928 //------------------------------------------------------------------------------
realizeVelocity(const SBStateDigest & sbs) const929 void MobilizedBodyImpl::realizeVelocity(const SBStateDigest& sbs) const {
930     // We don't deal with prescribed accelerations until Dynamics stage.
931     realizeVelocityVirtual(sbs.getState());
932 }
933 
934 //------------------------------------------------------------------------------
935 //                             REALIZE DYNAMICS
936 //------------------------------------------------------------------------------
realizeDynamics(const SBStateDigest & sbs) const937 void MobilizedBodyImpl::realizeDynamics(const SBStateDigest& sbs) const {
938     const MobilizedBodyIndex      mbx      = getMyMobilizedBodyIndex();
939     const SBInstanceVars&         iv       = sbs.getInstanceVars();
940     const SBInstanceCache&        ic       = sbs.getInstanceCache();
941     const SBInstancePerMobodInfo& instInfo = ic.getMobodInstanceInfo(mbx);
942 
943     // Note that we only need to deal with explicitly prescribed motion;
944     // if the udot is prescribed to zero it will be dealt with elsewhere.
945     // Prescribed udot may be due to acceleration-only prescribed udot,
946     // derivative of nonholonomic prescribed u, or to 2nd derivative
947     // of holonomic prescribed q, or to a lock(Acceleration).
948     if (instInfo.udotMethod==Motion::Prescribed) {
949 
950         const SBModelCache&         mc        = sbs.getModelCache();
951         const SBModelPerMobodInfo&  modelInfo = mc.getMobodModelInfo(mbx);
952         const int                   nu        = modelInfo.nUInUse;
953         const UIndex                uStart    = modelInfo.firstUIndex;
954         const PresUDotPoolIndex     pudx      = instInfo.firstPresUDot;
955         SBDynamicsCache&            dc        = sbs.updDynamicsCache();
956         Real*                       presUDotp = &dc.presUDotPool[pudx];
957 
958         if (iv.mobilizerLockLevel[mbx] != Motion::NoLevel) {
959             // Accelerations are prescribed because of a lock.
960             assert(iv.mobilizerLockLevel[mbx] == Motion::Acceleration);
961             for (int i=0; i < nu; ++i)
962                 presUDotp[i] = iv.lockedUs[UIndex(uStart+i)];
963         } else {
964             // Accelerations are prescribed because of a Motion.
965             assert(hasMotion() && !iv.prescribedMotionIsDisabled[mbx]);
966             const MotionImpl& motion = getMotion().getImpl();
967 
968             if (instInfo.qMethod==Motion::Prescribed) {
969                 // Holonomic
970                 const int nq = modelInfo.nQInUse;
971                 const RigidBodyNode& rbn = getMyRigidBodyNode();
972 
973                 if (rbn.isQDotAlwaysTheSameAsU()) {
974                     assert(nq==nu);
975                     motion.calcPrescribedPositionDotDot(sbs.getState(), nu,
976                                                         presUDotp);
977                 } else {
978                     Real ndotU[8]; // remainder term NDot*u (nq; max is 7)
979                     const Vector& u = sbs.getU();
980                     rbn.multiplyByNDot(sbs, false, &u[uStart], ndotU);
981 
982                     Real qdotdot[8]; // nq of these -- max is 7
983                     motion.calcPrescribedPositionDotDot(sbs.getState(), nq,
984                                                         qdotdot);
985 
986                     for (int i=0; i < nq; ++i)
987                         qdotdot[i] -= ndotU[i]; // velocity correction
988 
989                     // udot = N^-1 (qdotdot - NDot*u)
990                     rbn.multiplyByNInv(sbs, false, qdotdot, presUDotp);
991                 }
992             } else if (instInfo.uMethod==Motion::Prescribed) {
993                 // Non-holonomic
994                 motion.calcPrescribedVelocityDot(sbs.getState(), nu, presUDotp);
995             } else {
996                 // Acceleration-only
997                 motion.calcPrescribedAcceleration(sbs.getState(), nu, presUDotp);
998             }
999         }
1000     }
1001 
1002     realizeDynamicsVirtual(sbs.getState());
1003 }
1004 
1005 //------------------------------------------------------------------------------
1006 //                           REALIZE ACCELERATION
1007 //------------------------------------------------------------------------------
realizeAcceleration(const SBStateDigest & sbs) const1008 void MobilizedBodyImpl::realizeAcceleration(const SBStateDigest& sbs) const {
1009     realizeAccelerationVirtual(sbs.getState());
1010 }
1011 
1012 //------------------------------------------------------------------------------
1013 //                             REALIZE REPORT
1014 //------------------------------------------------------------------------------
realizeReport(const SBStateDigest & sbs) const1015 void MobilizedBodyImpl::realizeReport(const SBStateDigest& sbs) const {
1016     realizeReportVirtual(sbs.getState());
1017 }
1018 
1019     /////////////////////////
1020     // MOBILIZED BODY::PIN //
1021     /////////////////////////
1022 
Pin(MobilizedBody & parent,const Body & body,Direction d)1023 MobilizedBody::Pin::Pin(MobilizedBody& parent, const Body& body, Direction d)
1024 :   MobilizedBody(new PinImpl(d)) {
1025     // inb & outb frames are just the parent body's frame and new body's frame
1026     setBody(body);
1027 
1028     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1029                                                    *this);
1030 }
1031 
Pin(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)1032 MobilizedBody::Pin::Pin(MobilizedBody& parent, const Transform& inbFrame,
1033                         const Body& body, const Transform& outbFrame, Direction d)
1034 :   MobilizedBody(new PinImpl(d)) {
1035     setDefaultInboardFrame(inbFrame);
1036     setDefaultOutboardFrame(outbFrame);
1037     setBody(body);
1038 
1039     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1040                                                    *this);
1041 }
1042 
1043 
getDefaultQ() const1044 Real MobilizedBody::Pin::getDefaultQ() const {
1045     return getImpl().defaultQ;
1046 }
1047 
setDefaultQ(Real q)1048 MobilizedBody::Pin& MobilizedBody::Pin::setDefaultQ(Real q) {
1049     getImpl().invalidateTopologyCache();
1050     updImpl().defaultQ = q;
1051     return *this;
1052 }
1053 
getQ(const State & s) const1054 Real MobilizedBody::Pin::getQ(const State& s) const {
1055     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1056     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 1);
1057     return mbr.getMyMatterSubsystemRep().getQ(s)[qStart];
1058 }
setQ(State & s,Real q) const1059 void MobilizedBody::Pin::setQ(State& s, Real q) const {
1060     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1061     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 1);
1062     mbr.getMyMatterSubsystemRep().updQ(s)[qStart] = q;
1063 }
getQDot(const State & s) const1064 Real MobilizedBody::Pin::getQDot(const State& s) const {
1065     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1066     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 1);
1067     return mbr.getMyMatterSubsystemRep().getQDot(s)[qStart];
1068 }
getQDotDot(const State & s) const1069 Real MobilizedBody::Pin::getQDotDot(const State& s) const {
1070     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1071     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 1);
1072     return mbr.getMyMatterSubsystemRep().getQDotDot(s)[qStart];
1073 }
1074 
1075 
getU(const State & s) const1076 Real MobilizedBody::Pin::getU(const State& s) const {
1077     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1078     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 1);
1079     return mbr.getMyMatterSubsystemRep().getU(s)[uStart];
1080 }
setU(State & s,Real u) const1081 void MobilizedBody::Pin::setU(State& s, Real u) const {
1082     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1083     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 1);
1084     mbr.getMyMatterSubsystemRep().updU(s)[uStart] = u;
1085 }
getUDot(const State & s) const1086 Real MobilizedBody::Pin::getUDot(const State& s) const {
1087     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1088     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 1);
1089     return mbr.getMyMatterSubsystemRep().getUDot(s)[uStart];
1090 }
1091 
getMyPartQ(const State & s,const Vector & qlike) const1092 Real MobilizedBody::Pin::getMyPartQ(const State& s, const Vector& qlike) const {
1093     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 1);
1094     return qlike[qStart];
1095 }
1096 
getMyPartU(const State & s,const Vector & ulike) const1097 Real MobilizedBody::Pin::getMyPartU(const State& s, const Vector& ulike) const {
1098     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 1);
1099     return ulike[uStart];
1100 }
1101 
updMyPartQ(const State & s,Vector & qlike) const1102 Real& MobilizedBody::Pin::updMyPartQ(const State& s, Vector& qlike) const {
1103     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 1);
1104     return qlike[qStart];
1105 }
1106 
updMyPartU(const State & s,Vector & ulike) const1107 Real& MobilizedBody::Pin::updMyPartU(const State& s, Vector& ulike) const {
1108     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 1);
1109     return ulike[uStart];
1110 }
1111 
1112 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Pin,
1113                                         MobilizedBody::PinImpl, MobilizedBody);
1114 
1115     ////////////////////////////
1116     // MOBILIZED BODY::SLIDER //
1117     ////////////////////////////
1118 
Slider(MobilizedBody & parent,const Body & body,Direction d)1119 MobilizedBody::Slider::Slider(MobilizedBody& parent, const Body& body, Direction d)
1120 :   MobilizedBody(new SliderImpl(d)) {
1121     // inb & outb frames are just the parent body's frame and new body's frame
1122     setBody(body);
1123 
1124     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1125                                                    *this);
1126 }
1127 
Slider(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)1128 MobilizedBody::Slider::Slider(MobilizedBody& parent, const Transform& inbFrame,
1129                               const Body& body, const Transform& outbFrame, Direction d)
1130 :   MobilizedBody(new SliderImpl(d)) {
1131     setDefaultInboardFrame(inbFrame);
1132     setDefaultOutboardFrame(outbFrame);
1133     setBody(body);
1134 
1135     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1136                                                    *this);
1137 }
1138 
getDefaultQ() const1139 Real MobilizedBody::Slider::getDefaultQ() const {
1140     return getImpl().defaultQ;
1141 }
1142 
setDefaultQ(Real q)1143 MobilizedBody::Slider& MobilizedBody::Slider::setDefaultQ(Real q) {
1144     getImpl().invalidateTopologyCache();
1145     updImpl().defaultQ = q;
1146     return *this;
1147 }
1148 
getQ(const State & s) const1149 Real MobilizedBody::Slider::getQ(const State& s) const {
1150     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1151     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 1);
1152     return mbr.getMyMatterSubsystemRep().getQ(s)[qStart];
1153 }
setQ(State & s,Real q) const1154 void MobilizedBody::Slider::setQ(State& s, Real q) const {
1155     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1156     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 1);
1157     mbr.getMyMatterSubsystemRep().updQ(s)[qStart] = q;
1158 }
getQDot(const State & s) const1159 Real MobilizedBody::Slider::getQDot(const State& s) const {
1160     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1161     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 1);
1162     return mbr.getMyMatterSubsystemRep().getQDot(s)[qStart];
1163 }
getQDotDot(const State & s) const1164 Real MobilizedBody::Slider::getQDotDot(const State& s) const {
1165     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1166     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 1);
1167     return mbr.getMyMatterSubsystemRep().getQDotDot(s)[qStart];
1168 }
1169 
1170 
getU(const State & s) const1171 Real MobilizedBody::Slider::getU(const State& s) const {
1172     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1173     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 1);
1174     return mbr.getMyMatterSubsystemRep().getU(s)[uStart];
1175 }
setU(State & s,Real u) const1176 void MobilizedBody::Slider::setU(State& s, Real u) const {
1177     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1178     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 1);
1179     mbr.getMyMatterSubsystemRep().updU(s)[uStart] = u;
1180 }
getUDot(const State & s) const1181 Real MobilizedBody::Slider::getUDot(const State& s) const {
1182     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1183     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 1);
1184     return mbr.getMyMatterSubsystemRep().getUDot(s)[uStart];
1185 }
1186 
getMyPartQ(const State & s,const Vector & qlike) const1187 Real MobilizedBody::Slider::getMyPartQ(const State& s, const Vector& qlike) const {
1188     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 1);
1189     return qlike[qStart];
1190 }
1191 
getMyPartU(const State & s,const Vector & ulike) const1192 Real MobilizedBody::Slider::getMyPartU(const State& s, const Vector& ulike) const {
1193     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 1);
1194     return ulike[uStart];
1195 }
1196 
updMyPartQ(const State & s,Vector & qlike) const1197 Real& MobilizedBody::Slider::updMyPartQ(const State& s, Vector& qlike) const {
1198     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 1);
1199     return qlike[qStart];
1200 }
1201 
updMyPartU(const State & s,Vector & ulike) const1202 Real& MobilizedBody::Slider::updMyPartU(const State& s, Vector& ulike) const {
1203     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 1);
1204     return ulike[uStart];
1205 }
1206 
1207 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Slider,
1208                                         MobilizedBody::SliderImpl, MobilizedBody);
1209 
1210     ///////////////////////////////
1211     // MOBILIZED BODY::UNIVERSAL //
1212     ///////////////////////////////
1213 
Universal(MobilizedBody & parent,const Body & body,Direction d)1214 MobilizedBody::Universal::Universal
1215    (MobilizedBody& parent, const Body& body, Direction d)
1216 :   MobilizedBody(new UniversalImpl(d)) {
1217     // inb & outb frames are just the parent body's frame and new body's frame
1218     setBody(body);
1219 
1220     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1221                                                    *this);
1222 }
1223 
Universal(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)1224 MobilizedBody::Universal::Universal
1225    (MobilizedBody& parent, const Transform& inbFrame,
1226     const Body& body, const Transform& outbFrame, Direction d)
1227 :   MobilizedBody(new UniversalImpl(d)) {
1228     setDefaultInboardFrame(inbFrame);
1229     setDefaultOutboardFrame(outbFrame);
1230     setBody(body);
1231 
1232     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1233                                                    *this);
1234 }
1235 
1236 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Universal,
1237     MobilizedBody::UniversalImpl, MobilizedBody);
1238 
1239     //////////////////////////////
1240     // MOBILIZED BODY::CYLINDER //
1241     //////////////////////////////
1242 
Cylinder(MobilizedBody & parent,const Body & body,Direction d)1243 MobilizedBody::Cylinder::Cylinder
1244    (MobilizedBody& parent, const Body& body, Direction d)
1245 :   MobilizedBody(new CylinderImpl(d)) {
1246     // inb & outb frames are just the parent body's frame and new body's frame
1247     setBody(body);
1248 
1249     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1250                                                    *this);
1251 }
1252 
Cylinder(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)1253 MobilizedBody::Cylinder::Cylinder
1254    (MobilizedBody& parent, const Transform& inbFrame,
1255     const Body& body, const Transform& outbFrame, Direction d)
1256 :   MobilizedBody(new CylinderImpl(d)) {
1257     setDefaultInboardFrame(inbFrame);
1258     setDefaultOutboardFrame(outbFrame);
1259     setBody(body);
1260 
1261     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1262                                                    *this);
1263 }
1264 
1265 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Cylinder,
1266     MobilizedBody::CylinderImpl, MobilizedBody);
1267 
1268     //////////////////////////////////
1269     // MOBILIZED BODY::BEND STRETCH //
1270     //////////////////////////////////
1271 
BendStretch(MobilizedBody & parent,const Body & body,Direction d)1272 MobilizedBody::BendStretch::BendStretch
1273    (MobilizedBody& parent, const Body& body, Direction d)
1274 :   MobilizedBody(new BendStretchImpl(d)) {
1275     // inb & outb frames are just the parent body's frame and new body's frame
1276     setBody(body);
1277 
1278     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1279                                                    *this);
1280 }
1281 
BendStretch(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)1282 MobilizedBody::BendStretch::BendStretch
1283    (MobilizedBody& parent, const Transform& inbFrame,
1284     const Body& body, const Transform& outbFrame, Direction d)
1285 :   MobilizedBody(new BendStretchImpl(d)) {
1286     setDefaultInboardFrame(inbFrame);
1287     setDefaultOutboardFrame(outbFrame);
1288     setBody(body);
1289 
1290     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1291                                                    *this);
1292 }
1293 
1294 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::BendStretch,
1295     MobilizedBody::BendStretchImpl, MobilizedBody);
1296 
1297     ////////////////////////////
1298     // MOBILIZED BODY::PLANAR //
1299     ////////////////////////////
1300 
Planar(MobilizedBody & parent,const Body & body,Direction d)1301 MobilizedBody::Planar::Planar
1302    (MobilizedBody& parent, const Body& body, Direction d)
1303 :   MobilizedBody(new PlanarImpl(d)) {
1304     // inb & outb frames are just the parent body's frame and new body's frame
1305     setBody(body);
1306 
1307     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1308                                                    *this);
1309 }
1310 
Planar(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)1311 MobilizedBody::Planar::Planar(MobilizedBody& parent, const Transform& inbFrame,
1312                               const Body& body, const Transform& outbFrame,
1313                               Direction d)
1314 :   MobilizedBody(new PlanarImpl(d)) {
1315     setDefaultInboardFrame(inbFrame);
1316     setDefaultOutboardFrame(outbFrame);
1317     setBody(body);
1318 
1319     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1320                                                    *this);
1321 }
1322 
getDefaultQ() const1323 const Vec3& MobilizedBody::Planar::getDefaultQ() const {
1324     return getImpl().defaultQ;
1325 }
setDefaultQ(const Vec3 & q)1326 MobilizedBody::Planar& MobilizedBody::Planar::setDefaultQ(const Vec3& q) {
1327     getImpl().invalidateTopologyCache();
1328     updImpl().defaultQ = q;
1329     return *this;
1330 }
1331 
getQ(const State & s) const1332 const Vec3& MobilizedBody::Planar::getQ(const State& s) const {
1333     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1334     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
1335     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getQ(s)[qStart]);
1336 }
setQ(State & s,const Vec3 & q) const1337 void MobilizedBody::Planar::setQ(State& s, const Vec3& q) const {
1338     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1339     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
1340     Vec3::updAs(&mbr.getMyMatterSubsystemRep().updQ(s)[qStart]) = q;
1341 }
getQDot(const State & s) const1342 const Vec3& MobilizedBody::Planar::getQDot(const State& s) const {
1343     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1344     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
1345     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getQDot(s)[qStart]);
1346 }
getQDotDot(const State & s) const1347 const Vec3& MobilizedBody::Planar::getQDotDot(const State& s) const {
1348     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1349     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
1350     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getQDotDot(s)[qStart]);
1351 }
1352 
1353 
getU(const State & s) const1354 const Vec3& MobilizedBody::Planar::getU(const State& s) const {
1355     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1356     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
1357     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getU(s)[uStart]);
1358 }
setU(State & s,const Vec3 & u) const1359 void MobilizedBody::Planar::setU(State& s, const Vec3& u) const {
1360     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1361     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
1362     Vec3::updAs(&mbr.getMyMatterSubsystemRep().updU(s)[uStart]) = u;
1363 }
getUDot(const State & s) const1364 const Vec3& MobilizedBody::Planar::getUDot(const State& s) const {
1365     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1366     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
1367     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getUDot(s)[uStart]);
1368 }
1369 
getMyPartQ(const State & s,const Vector & qlike) const1370 const Vec3& MobilizedBody::Planar::getMyPartQ(const State& s, const Vector& qlike) const {
1371     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 3);
1372     return Vec3::getAs(&qlike[qStart]);
1373 }
1374 
getMyPartU(const State & s,const Vector & ulike) const1375 const Vec3& MobilizedBody::Planar::getMyPartU(const State& s, const Vector& ulike) const {
1376     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 3);
1377     return Vec3::getAs(&ulike[uStart]);
1378 }
1379 
updMyPartQ(const State & s,Vector & qlike) const1380 Vec3& MobilizedBody::Planar::updMyPartQ(const State& s, Vector& qlike) const {
1381     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 3);
1382     return Vec3::updAs(&qlike[qStart]);
1383 }
1384 
updMyPartU(const State & s,Vector & ulike) const1385 Vec3& MobilizedBody::Planar::updMyPartU(const State& s, Vector& ulike) const {
1386     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 3);
1387     return Vec3::updAs(&ulike[uStart]);
1388 }
1389 
1390 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Planar,
1391     MobilizedBody::PlanarImpl, MobilizedBody);
1392 
1393 
1394     //////////////////////////////////////
1395     // MOBILIZED BODY::SPHERICAL COORDS //
1396     //////////////////////////////////////
1397 
SphericalCoords(MobilizedBody & parent,const Body & body,Direction d)1398 MobilizedBody::SphericalCoords::SphericalCoords
1399    (MobilizedBody& parent, const Body& body, Direction d)
1400 :   MobilizedBody(new SphericalCoordsImpl(d)) {
1401     // inb & outb frames are just the parent body's frame and new body's frame
1402     setBody(body);
1403 
1404     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1405                                                    *this);
1406 }
1407 
SphericalCoords(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)1408 MobilizedBody::SphericalCoords::SphericalCoords
1409    (MobilizedBody&  parent, const Transform& inbFrame,
1410     const Body&     body,   const Transform& outbFrame,
1411     Direction       d)
1412 :   MobilizedBody(new SphericalCoordsImpl(d)) {
1413     setDefaultInboardFrame(inbFrame);
1414     setDefaultOutboardFrame(outbFrame);
1415     setBody(body);
1416 
1417     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1418                                                    *this);
1419 }
1420 
SphericalCoords(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Real azimuthOffset,bool azimuthNegated,Real zenithOffset,bool zenithNegated,CoordinateAxis radialAxis,bool radialNegated,Direction d)1421 MobilizedBody::SphericalCoords::SphericalCoords
1422    (MobilizedBody&  parent,         const Transform&    inbFrame,
1423     const Body&     body,           const Transform&    outbFrame,
1424     Real            azimuthOffset,  bool                azimuthNegated,
1425     Real            zenithOffset,   bool                zenithNegated,
1426     CoordinateAxis  radialAxis,     bool                radialNegated,
1427     Direction       d)
1428 :   MobilizedBody(new SphericalCoordsImpl(azimuthOffset, azimuthNegated,
1429                                           zenithOffset,  zenithNegated,
1430                                           radialAxis,    radialNegated,
1431                                           d))
1432 {
1433     SimTK_APIARGCHECK_ALWAYS(radialAxis != YAxis, "MobilizedBody::SphericalCoords", "ctor",
1434         "SphericalCoords translation (radial) axis must be X or Z; Y is not allowed.");
1435 
1436     setDefaultInboardFrame(inbFrame);
1437     setDefaultOutboardFrame(outbFrame);
1438     setBody(body);
1439 
1440     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1441                                                    *this);
1442 }
1443 
1444 MobilizedBody::SphericalCoords&
setRadialAxis(CoordinateAxis axis)1445 MobilizedBody::SphericalCoords::setRadialAxis(CoordinateAxis axis) {
1446     SimTK_APIARGCHECK_ALWAYS(axis != YAxis,
1447         "MobilizedBody::SphericalCoords", "setRadialAxis",
1448         "SphericalCoords translation (radial) axis must be X or Z; Y is not allowed.");
1449     getImpl().invalidateTopologyCache();
1450     updImpl().axisT = axis;
1451     return *this;
1452 }
1453 
1454 MobilizedBody::SphericalCoords&
setNegateAzimuth(bool shouldNegate)1455 MobilizedBody::SphericalCoords::setNegateAzimuth(bool shouldNegate) {
1456     getImpl().invalidateTopologyCache();
1457     updImpl().negAz = shouldNegate;
1458     return *this;
1459 }
1460 MobilizedBody::SphericalCoords&
setNegateZenith(bool shouldNegate)1461 MobilizedBody::SphericalCoords::setNegateZenith(bool shouldNegate) {
1462     getImpl().invalidateTopologyCache();
1463     updImpl().negZe = shouldNegate;
1464     return *this;
1465 }
1466 MobilizedBody::SphericalCoords&
setNegateRadial(bool shouldNegate)1467 MobilizedBody::SphericalCoords::setNegateRadial(bool shouldNegate) {
1468     getImpl().invalidateTopologyCache();
1469     updImpl().negT = shouldNegate;
1470     return *this;
1471 }
1472 
getRadialAxis() const1473 CoordinateAxis MobilizedBody::SphericalCoords::getRadialAxis()    const
1474 {   return getImpl().axisT; }
isAzimuthNegated() const1475 bool MobilizedBody::SphericalCoords::isAzimuthNegated() const
1476 {   return getImpl().negAz; }
isZenithNegated() const1477 bool MobilizedBody::SphericalCoords::isZenithNegated()  const
1478 {   return getImpl().negZe; }
isRadialNegated() const1479 bool MobilizedBody::SphericalCoords::isRadialNegated()  const
1480 {   return getImpl().negT; }
1481 
getDefaultQ() const1482 const Vec3& MobilizedBody::SphericalCoords::getDefaultQ() const {
1483     return getImpl().defaultQ;
1484 }
1485 MobilizedBody::SphericalCoords& MobilizedBody::SphericalCoords::
setDefaultQ(const Vec3 & q)1486 setDefaultQ(const Vec3& q) {
1487     getImpl().invalidateTopologyCache();
1488     updImpl().defaultQ = q;
1489     return *this;
1490 }
1491 
getQ(const State & s) const1492 const Vec3& MobilizedBody::SphericalCoords::getQ(const State& s) const {
1493     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1494     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
1495     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getQ(s)[qStart]);
1496 }
setQ(State & s,const Vec3 & q) const1497 void MobilizedBody::SphericalCoords::setQ(State& s, const Vec3& q) const {
1498     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1499     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
1500     Vec3::updAs(&mbr.getMyMatterSubsystemRep().updQ(s)[qStart]) = q;
1501 }
getQDot(const State & s) const1502 const Vec3& MobilizedBody::SphericalCoords::getQDot(const State& s) const {
1503     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1504     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
1505     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getQDot(s)[qStart]);
1506 }
getQDotDot(const State & s) const1507 const Vec3& MobilizedBody::SphericalCoords::getQDotDot(const State& s) const {
1508     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1509     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
1510     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getQDotDot(s)[qStart]);
1511 }
1512 
1513 
getU(const State & s) const1514 const Vec3& MobilizedBody::SphericalCoords::getU(const State& s) const {
1515     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1516     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
1517     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getU(s)[uStart]);
1518 }
setU(State & s,const Vec3 & u) const1519 void MobilizedBody::SphericalCoords::setU(State& s, const Vec3& u) const {
1520     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1521     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
1522     Vec3::updAs(&mbr.getMyMatterSubsystemRep().updU(s)[uStart]) = u;
1523 }
getUDot(const State & s) const1524 const Vec3& MobilizedBody::SphericalCoords::getUDot(const State& s) const {
1525     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1526     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
1527     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getUDot(s)[uStart]);
1528 }
1529 
1530 const Vec3& MobilizedBody::SphericalCoords::
getMyPartQ(const State & s,const Vector & qlike) const1531 getMyPartQ(const State& s, const Vector& qlike) const {
1532     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq==3);
1533     return Vec3::getAs(&qlike[qStart]);
1534 }
1535 
1536 const Vec3& MobilizedBody::SphericalCoords::
getMyPartU(const State & s,const Vector & ulike) const1537 getMyPartU(const State& s, const Vector& ulike) const {
1538     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu==3);
1539     return Vec3::getAs(&ulike[uStart]);
1540 }
1541 
1542 Vec3& MobilizedBody::SphericalCoords::
updMyPartQ(const State & s,Vector & qlike) const1543 updMyPartQ(const State& s, Vector& qlike) const {
1544     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq==3);
1545     return Vec3::updAs(&qlike[qStart]);
1546 }
1547 
1548 Vec3& MobilizedBody::SphericalCoords::
updMyPartU(const State & s,Vector & ulike) const1549 updMyPartU(const State& s, Vector& ulike) const {
1550     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu==3);
1551     return Vec3::updAs(&ulike[uStart]);
1552 }
1553 
1554 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::SphericalCoords,
1555     MobilizedBody::SphericalCoordsImpl, MobilizedBody);
1556 
1557     ////////////////////////////
1558     // MOBILIZED BODY::GIMBAL //
1559     ////////////////////////////
1560 
Gimbal(MobilizedBody & parent,const Body & body,Direction d)1561 MobilizedBody::Gimbal::Gimbal
1562    (MobilizedBody& parent, const Body& body, Direction d)
1563 :   MobilizedBody(new GimbalImpl(d)) {
1564     // inb & outb frames are just the parent body's frame and new body's frame
1565     setBody(body);
1566 
1567     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1568                                                    *this);
1569 }
1570 
Gimbal(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)1571 MobilizedBody::Gimbal::Gimbal
1572    (MobilizedBody& parent, const Transform& inbFrame,
1573     const Body& body, const Transform& outbFrame, Direction d)
1574 :   MobilizedBody(new GimbalImpl(d)) {
1575     setDefaultInboardFrame(inbFrame);
1576     setDefaultOutboardFrame(outbFrame);
1577     setBody(body);
1578 
1579     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1580                                                    *this);
1581 }
1582 
setDefaultRadius(Real r)1583 MobilizedBody::Gimbal& MobilizedBody::Gimbal::setDefaultRadius(Real r) {
1584     getImpl().invalidateTopologyCache();
1585     updImpl().setDefaultRadius(r);
1586     return *this;
1587 }
1588 
getDefaultRadius() const1589 Real MobilizedBody::Gimbal::getDefaultRadius() const {
1590     return getImpl().getDefaultRadius();
1591 }
1592 
getDefaultQ() const1593 const Vec3& MobilizedBody::Gimbal::getDefaultQ() const {
1594     return getImpl().defaultQ;
1595 }
setDefaultQ(const Vec3 & q)1596 MobilizedBody::Gimbal& MobilizedBody::Gimbal::setDefaultQ(const Vec3& q) {
1597     getImpl().invalidateTopologyCache();
1598     updImpl().defaultQ = q;
1599     return *this;
1600 }
1601 
getQ(const State & s) const1602 const Vec3& MobilizedBody::Gimbal::getQ(const State& s) const {
1603     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1604     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
1605     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getQ(s)[qStart]);
1606 }
setQ(State & s,const Vec3 & q) const1607 void MobilizedBody::Gimbal::setQ(State& s, const Vec3& q) const {
1608     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1609     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
1610     Vec3::updAs(&mbr.getMyMatterSubsystemRep().updQ(s)[qStart]) = q;
1611 }
getQDot(const State & s) const1612 const Vec3& MobilizedBody::Gimbal::getQDot(const State& s) const {
1613     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1614     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
1615     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getQDot(s)[qStart]);
1616 }
getQDotDot(const State & s) const1617 const Vec3& MobilizedBody::Gimbal::getQDotDot(const State& s) const {
1618     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1619     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
1620     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getQDotDot(s)[qStart]);
1621 }
1622 
1623 
getU(const State & s) const1624 const Vec3& MobilizedBody::Gimbal::getU(const State& s) const {
1625     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1626     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
1627     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getU(s)[uStart]);
1628 }
setU(State & s,const Vec3 & u) const1629 void MobilizedBody::Gimbal::setU(State& s, const Vec3& u) const {
1630     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1631     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
1632     Vec3::updAs(&mbr.getMyMatterSubsystemRep().updU(s)[uStart]) = u;
1633 }
getUDot(const State & s) const1634 const Vec3& MobilizedBody::Gimbal::getUDot(const State& s) const {
1635     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1636     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
1637     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getUDot(s)[uStart]);
1638 }
1639 
1640 const Vec3& MobilizedBody::Gimbal::
getMyPartQ(const State & s,const Vector & qlike) const1641 getMyPartQ(const State& s, const Vector& qlike) const {
1642     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq==3);
1643     return Vec3::getAs(&qlike[qStart]);
1644 }
1645 
1646 const Vec3& MobilizedBody::Gimbal::
getMyPartU(const State & s,const Vector & ulike) const1647 getMyPartU(const State& s, const Vector& ulike) const {
1648     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu==3);
1649     return Vec3::getAs(&ulike[uStart]);
1650 }
1651 
1652 Vec3& MobilizedBody::Gimbal::
updMyPartQ(const State & s,Vector & qlike) const1653 updMyPartQ(const State& s, Vector& qlike) const {
1654     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq==3);
1655     return Vec3::updAs(&qlike[qStart]);
1656 }
1657 
1658 Vec3& MobilizedBody::Gimbal::
updMyPartU(const State & s,Vector & ulike) const1659 updMyPartU(const State& s, Vector& ulike) const {
1660     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu==3);
1661     return Vec3::updAs(&ulike[uStart]);
1662 }
1663 
1664 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Gimbal,
1665     MobilizedBody::GimbalImpl, MobilizedBody);
1666 
1667     // GimbalImpl
1668 
calcDecorativeGeometryAndAppendImpl(const State & s,Stage stage,Array_<DecorativeGeometry> & geom) const1669 void MobilizedBody::GimbalImpl::calcDecorativeGeometryAndAppendImpl
1670    (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const
1671 {
1672     // Call the superclass implementation to get standard default geometry.
1673 
1674     MobilizedBodyImpl::calcDecorativeGeometryAndAppendImpl(s, stage, geom);
1675 
1676     // We can't generate the ball until we know the radius, and we can't place
1677     // the geometry on the body until we know the parent and child mobilizer frame
1678     // placement on the body, which might not be until Instance stage.
1679     if (stage == Stage::Instance && getMyMatterSubsystemRep().getShowDefaultGeometry())
1680     {
1681         const SimbodyMatterSubsystemRep& matterRep = getMyMatterSubsystemRep();
1682         const Transform& X_PMb = getInboardFrame(s);
1683         const Transform& X_BM  = getOutboardFrame(s);
1684 
1685         // On the inboard body, draw a solid sphere and a wireframe one attached to it for
1686         // easier visualization of its rotation. These are at about 90% of the radius.
1687         geom.push_back(DecorativeSphere(Real(0.92)*getDefaultRadius())
1688                                             .setColor(Gray)
1689                                             .setRepresentation(DecorativeGeometry::DrawSurface)
1690                                             .setOpacity(Real(0.5))
1691                                             .setResolution(Real(0.75))
1692                                             .setBodyId(getMyParentMobilizedBodyIndex())
1693                                             .setTransform(X_PMb));
1694         geom.push_back(DecorativeSphere(Real(0.90)*getDefaultRadius())
1695             .setColor(White)
1696             .setRepresentation(DecorativeGeometry::DrawWireframe)
1697             .setResolution(Real(0.75))
1698             .setLineThickness(3)
1699             .setOpacity(Real(0.1))
1700             .setBodyId(getMyParentMobilizedBodyIndex())
1701             .setTransform(X_PMb));
1702 
1703         // On the outboard body draw an orange mesh sphere at the ball radius.
1704         geom.push_back(DecorativeSphere(getDefaultRadius())
1705                                             .setColor(Orange)
1706                                             .setRepresentation(DecorativeGeometry::DrawWireframe)
1707                                             .setOpacity(0.5)
1708                                             .setResolution(0.5)
1709                                             .setBodyId(getMyMobilizedBodyIndex())
1710                                             .setTransform(X_BM));
1711     }
1712 }
1713 
1714     /////////////////////////////
1715     // MOBILIZED BODY::BUSHING //
1716     /////////////////////////////
1717 
Bushing(MobilizedBody & parent,const Body & body,Direction d)1718 MobilizedBody::Bushing::Bushing(MobilizedBody& parent, const Body& body,
1719                                 Direction d)
1720 :   MobilizedBody(new BushingImpl(d)) {
1721     // inb & outb frames are just the parent body's frame and new body's frame
1722     setBody(body);
1723 
1724     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1725                                                    *this);
1726 }
1727 
Bushing(MobilizedBody & parent,const Transform & inbFrame,const Body & bodyInfo,const Transform & outbFrame,Direction d)1728 MobilizedBody::Bushing::Bushing(MobilizedBody& parent, const Transform& inbFrame,
1729                                 const Body& bodyInfo, const Transform& outbFrame,
1730                                 Direction d)
1731 :   MobilizedBody(new BushingImpl(d)) {
1732     setDefaultInboardFrame(inbFrame);
1733     setDefaultOutboardFrame(outbFrame);
1734     setBody(bodyInfo);
1735 
1736     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1737                                                    *this);
1738 }
1739 
getDefaultQ() const1740 const Vec6& MobilizedBody::Bushing::getDefaultQ() const
1741 {   return getImpl().defaultQ; }
1742 
setDefaultQ(const Vec6 & q)1743 MobilizedBody::Bushing& MobilizedBody::Bushing::setDefaultQ(const Vec6& q) {
1744     getImpl().invalidateTopologyCache();
1745     updImpl().defaultQ = q;
1746     return *this;
1747 }
1748 
getQ(const State & s) const1749 const Vec6& MobilizedBody::Bushing::getQ(const State& s) const {
1750     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1751     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 6);
1752     return Vec6::getAs(&mbr.getMyMatterSubsystemRep().getQ(s)[qStart]);
1753 }
setQ(State & s,const Vec6 & q) const1754 void MobilizedBody::Bushing::setQ(State& s, const Vec6& q) const {
1755     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1756     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 6);
1757     Vec6::updAs(&mbr.getMyMatterSubsystemRep().updQ(s)[qStart]) = q;
1758 }
getQDot(const State & s) const1759 const Vec6& MobilizedBody::Bushing::getQDot(const State& s) const {
1760     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1761     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 6);
1762     return Vec6::getAs(&mbr.getMyMatterSubsystemRep().getQDot(s)[qStart]);
1763 }
getQDotDot(const State & s) const1764 const Vec6& MobilizedBody::Bushing::getQDotDot(const State& s) const {
1765     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1766     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 6);
1767     return Vec6::getAs(&mbr.getMyMatterSubsystemRep().getQDotDot(s)[qStart]);
1768 }
1769 
1770 
getU(const State & s) const1771 const Vec6& MobilizedBody::Bushing::getU(const State& s) const {
1772     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1773     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 6);
1774     return Vec6::getAs(&mbr.getMyMatterSubsystemRep().getU(s)[uStart]);
1775 }
setU(State & s,const Vec6 & u) const1776 void MobilizedBody::Bushing::setU(State& s, const Vec6& u) const {
1777     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1778     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 6);
1779     Vec6::updAs(&mbr.getMyMatterSubsystemRep().updU(s)[uStart]) = u;
1780 }
getUDot(const State & s) const1781 const Vec6& MobilizedBody::Bushing::getUDot(const State& s) const {
1782     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1783     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 6);
1784     return Vec6::getAs(&mbr.getMyMatterSubsystemRep().getUDot(s)[uStart]);
1785 }
1786 
1787 const Vec6& MobilizedBody::Bushing::
getMyPartQ(const State & s,const Vector & qlike) const1788 getMyPartQ(const State& s, const Vector& qlike) const {
1789     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq==6);
1790     return Vec6::getAs(&qlike[qStart]);
1791 }
1792 
1793 const Vec6& MobilizedBody::Bushing::
getMyPartU(const State & s,const Vector & ulike) const1794 getMyPartU(const State& s, const Vector& ulike) const {
1795     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu==6);
1796     return Vec6::getAs(&ulike[uStart]);
1797 }
1798 
1799 Vec6& MobilizedBody::Bushing::
updMyPartQ(const State & s,Vector & qlike) const1800 updMyPartQ(const State& s, Vector& qlike) const {
1801     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq==6);
1802     return Vec6::updAs(&qlike[qStart]);
1803 }
1804 
1805 Vec6& MobilizedBody::Bushing::
updMyPartU(const State & s,Vector & ulike) const1806 updMyPartU(const State& s, Vector& ulike) const {
1807     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu==6);
1808     return Vec6::updAs(&ulike[uStart]);
1809 }
1810 
1811 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Bushing,
1812     MobilizedBody::BushingImpl, MobilizedBody);
1813 
1814 
1815     ///////////////////////////////////////////////////
1816     // MOBILIZED BODY::BALL (ORIENTATION, SPHERICAL) //
1817     ///////////////////////////////////////////////////
1818 
Ball(MobilizedBody & parent,const Body & body,Direction d)1819 MobilizedBody::Ball::Ball
1820    (MobilizedBody& parent, const Body& body, Direction d)
1821 :   MobilizedBody(new BallImpl(d)) {
1822     // inb & outb frames are just the parent body's frame and new body's frame
1823     setBody(body);
1824 
1825     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1826                                                    *this);
1827 }
1828 
Ball(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)1829 MobilizedBody::Ball::Ball
1830    (MobilizedBody& parent, const Transform& inbFrame,
1831     const Body& body, const Transform& outbFrame, Direction d)
1832 :   MobilizedBody(new BallImpl(d)) {
1833     setDefaultInboardFrame(inbFrame);
1834     setDefaultOutboardFrame(outbFrame);
1835     setBody(body);
1836 
1837     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1838                                                    *this);
1839 }
1840 
setDefaultRadius(Real r)1841 MobilizedBody::Ball& MobilizedBody::Ball::setDefaultRadius(Real r) {
1842     getImpl().invalidateTopologyCache();
1843     updImpl().setDefaultRadius(r);
1844     return *this;
1845 }
1846 
getDefaultRadius() const1847 Real MobilizedBody::Ball::getDefaultRadius() const {
1848     return getImpl().getDefaultRadius();
1849 }
1850 
getDefaultQ() const1851 const Quaternion& MobilizedBody::Ball::getDefaultQ() const {
1852     return getImpl().defaultQ;
1853 }
setDefaultQ(const Quaternion & quat)1854 MobilizedBody::Ball& MobilizedBody::Ball::setDefaultQ(const Quaternion& quat) {
1855     getImpl().invalidateTopologyCache();
1856     updImpl().defaultQ = quat;
1857     return *this;
1858 }
1859 
getQ(const State & s) const1860 const Vec4& MobilizedBody::Ball::getQ(const State& s) const {
1861     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1862     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 4);
1863     return Vec4::getAs(&mbr.getMyMatterSubsystemRep().getQ(s)[qStart]);
1864 }
setQ(State & s,const Vec4 & q) const1865 void MobilizedBody::Ball::setQ(State& s, const Vec4& q) const {
1866     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1867     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 4);
1868     Vec4::updAs(&mbr.getMyMatterSubsystemRep().updQ(s)[qStart]) = q;
1869 }
getQDot(const State & s) const1870 const Vec4& MobilizedBody::Ball::getQDot(const State& s) const {
1871     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1872     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 4);
1873     return Vec4::getAs(&mbr.getMyMatterSubsystemRep().getQDot(s)[qStart]);
1874 }
getQDotDot(const State & s) const1875 const Vec4& MobilizedBody::Ball::getQDotDot(const State& s) const {
1876     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1877     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 4);
1878     return Vec4::getAs(&mbr.getMyMatterSubsystemRep().getQDotDot(s)[qStart]);
1879 }
1880 
getU(const State & s) const1881 const Vec3& MobilizedBody::Ball::getU(const State& s) const {
1882     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1883     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
1884     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getU(s)[uStart]);
1885 }
setU(State & s,const Vec3 & u) const1886 void MobilizedBody::Ball::setU(State& s, const Vec3& u) const {
1887     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1888     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
1889     Vec3::updAs(&mbr.getMyMatterSubsystemRep().updU(s)[uStart]) = u;
1890 }
getUDot(const State & s) const1891 const Vec3& MobilizedBody::Ball::getUDot(const State& s) const {
1892     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
1893     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
1894     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getUDot(s)[uStart]);
1895 }
1896 
1897 const Vec4& MobilizedBody::Ball::
getMyPartQ(const State & s,const Vector & qlike) const1898 getMyPartQ(const State& s, const Vector& qlike) const {
1899     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 4);
1900     return Vec4::getAs(&qlike[qStart]);
1901 }
1902 
1903 const Vec3& MobilizedBody::Ball::
getMyPartU(const State & s,const Vector & ulike) const1904 getMyPartU(const State& s, const Vector& ulike) const {
1905     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 3);
1906     return Vec3::getAs(&ulike[uStart]);
1907 }
1908 
1909 Vec4& MobilizedBody::Ball::
updMyPartQ(const State & s,Vector & qlike) const1910 updMyPartQ(const State& s, Vector& qlike) const {
1911     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 4);
1912     return Vec4::updAs(&qlike[qStart]);
1913 }
1914 
1915 Vec3& MobilizedBody::Ball::
updMyPartU(const State & s,Vector & ulike) const1916 updMyPartU(const State& s, Vector& ulike) const {
1917     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 3);
1918     return Vec3::updAs(&ulike[uStart]);
1919 }
1920 
1921 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Ball,
1922     MobilizedBody::BallImpl, MobilizedBody);
1923 
1924     // BallImpl
1925 
calcDecorativeGeometryAndAppendImpl(const State & s,Stage stage,Array_<DecorativeGeometry> & geom) const1926 void MobilizedBody::BallImpl::calcDecorativeGeometryAndAppendImpl
1927    (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const
1928 {
1929     // Call the superclass implementation to get standard default geometry.
1930 
1931     MobilizedBodyImpl::calcDecorativeGeometryAndAppendImpl(s, stage, geom);
1932 
1933     // We can't generate the ball until we know the radius, and we can't place
1934     // the geometry on the body until we know the parent and child mobilizer frame
1935     // placement on the body, which might not be until Instance stage.
1936     if (stage == Stage::Instance && getMyMatterSubsystemRep().getShowDefaultGeometry()) {
1937         const SimbodyMatterSubsystemRep& matterRep = getMyMatterSubsystemRep();
1938         const Transform& X_PMb = getInboardFrame(s);
1939         const Transform& X_BM  = getOutboardFrame(s);
1940 
1941         // On the inboard body, draw a solid sphere and a wireframe one attached to it for
1942         // easier visualization of its rotation. These are at about 90% of the radius.
1943         geom.push_back(DecorativeSphere(Real(0.92)*getDefaultRadius())
1944                         .setColor(Gray)
1945                         .setRepresentation(DecorativeGeometry::DrawSurface)
1946                         .setOpacity(Real(0.5))
1947                         .setResolution(Real(0.75))
1948                         .setBodyId(getMyParentMobilizedBodyIndex())
1949                         .setTransform(X_PMb));
1950         geom.push_back(DecorativeSphere(Real(0.90)*getDefaultRadius())
1951                         .setColor(White)
1952                         .setRepresentation(DecorativeGeometry::DrawWireframe)
1953                         .setResolution(Real(0.75))
1954                         .setLineThickness(3)
1955                         .setOpacity(Real(0.1))
1956                         .setBodyId(getMyParentMobilizedBodyIndex())
1957                         .setTransform(X_PMb));
1958 
1959         // On the outboard body draw an orange mesh sphere at the ball radius.
1960         geom.push_back(DecorativeSphere(getDefaultRadius())
1961                         .setColor(Orange)
1962                         .setRepresentation(DecorativeGeometry::DrawWireframe)
1963                         .setOpacity(Real(0.5))
1964                         .setResolution(Real(0.5))
1965                         .setBodyId(getMyMobilizedBodyIndex())
1966                         .setTransform(X_BM));
1967     }
1968 }
1969 
1970     ///////////////////////////////
1971     // MOBILIZED BODY::ELLIPSOID //
1972     ///////////////////////////////
1973 
Ellipsoid(MobilizedBody & parent,const Body & body,Direction d)1974 MobilizedBody::Ellipsoid::Ellipsoid
1975    (MobilizedBody& parent, const Body& body, Direction d)
1976 :   MobilizedBody(new EllipsoidImpl(d)) {
1977     // inb & outb frames are just the parent body's frame and new body's frame
1978     setBody(body);
1979 
1980     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1981                                                    *this);
1982 }
1983 
Ellipsoid(MobilizedBody & parent,const Body & body,const Vec3 & radii,Direction d)1984 MobilizedBody::Ellipsoid::Ellipsoid
1985    (MobilizedBody& parent, const Body& body, const Vec3& radii, Direction d)
1986 :   MobilizedBody(new EllipsoidImpl(d)) {
1987     // inb & outb frames are just the parent body's frame and new body's frame
1988     setBody(body);
1989     setDefaultRadii(radii);
1990 
1991     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
1992                                                    *this);
1993 }
1994 
Ellipsoid(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)1995 MobilizedBody::Ellipsoid::Ellipsoid
1996    (MobilizedBody& parent, const Transform& inbFrame,
1997     const Body& body,      const Transform& outbFrame, Direction d)
1998 :   MobilizedBody(new EllipsoidImpl(d)) {
1999     setDefaultInboardFrame(inbFrame);
2000     setDefaultOutboardFrame(outbFrame);
2001     setBody(body);
2002 
2003     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2004                                                    *this);
2005 }
2006 
Ellipsoid(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,const Vec3 & radii,Direction d)2007 MobilizedBody::Ellipsoid::Ellipsoid
2008    (MobilizedBody& parent, const Transform& inbFrame,
2009     const Body& body,      const Transform& outbFrame,
2010     const Vec3& radii, Direction d)
2011 :   MobilizedBody(new EllipsoidImpl(d)) {
2012     setDefaultInboardFrame(inbFrame);
2013     setDefaultOutboardFrame(outbFrame);
2014     setBody(body);
2015     setDefaultRadii(radii);
2016 
2017     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2018                                                    *this);
2019 }
2020 
2021 MobilizedBody::Ellipsoid& MobilizedBody::Ellipsoid::
setDefaultRadii(const Vec3 & r)2022 setDefaultRadii(const Vec3& r) {
2023     updImpl().setDefaultRadii(r);
2024     return *this;
2025 }
2026 
getDefaultRadii() const2027 const Vec3& MobilizedBody::Ellipsoid::getDefaultRadii() const {
2028     return getImpl().getDefaultRadii();
2029 }
2030 
getDefaultQ() const2031 const Quaternion& MobilizedBody::Ellipsoid::getDefaultQ() const {
2032     return getImpl().defaultQ;
2033 }
updDefaultQ()2034 Quaternion& MobilizedBody::Ellipsoid::updDefaultQ() {
2035     return updImpl().defaultQ;
2036 }
2037 
getQ(const State & s) const2038 const Vec4& MobilizedBody::Ellipsoid::getQ(const State& s) const {
2039     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2040     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 4);
2041     return Vec4::getAs(&mbr.getMyMatterSubsystemRep().getQ(s)[qStart]);
2042 }
setQ(State & s,const Vec4 & q) const2043 void MobilizedBody::Ellipsoid::setQ(State& s, const Vec4& q) const {
2044     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2045     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 4);
2046     Vec4::updAs(&mbr.getMyMatterSubsystemRep().updQ(s)[qStart]) = q;
2047 }
getQDot(const State & s) const2048 const Vec4& MobilizedBody::Ellipsoid::getQDot(const State& s) const {
2049     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2050     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 4);
2051     return Vec4::getAs(&mbr.getMyMatterSubsystemRep().getQDot(s)[qStart]);
2052 }
getQDotDot(const State & s) const2053 const Vec4& MobilizedBody::Ellipsoid::getQDotDot(const State& s) const {
2054     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2055     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 4);
2056     return Vec4::getAs(&mbr.getMyMatterSubsystemRep().getQDotDot(s)[qStart]);
2057 }
2058 
getU(const State & s) const2059 const Vec3& MobilizedBody::Ellipsoid::getU(const State& s) const {
2060     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2061     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
2062     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getU(s)[uStart]);
2063 }
setU(State & s,const Vec3 & u) const2064 void MobilizedBody::Ellipsoid::setU(State& s, const Vec3& u) const {
2065     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2066     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
2067     Vec3::updAs(&mbr.getMyMatterSubsystemRep().updU(s)[uStart]) = u;
2068 }
getUDot(const State & s) const2069 const Vec3& MobilizedBody::Ellipsoid::getUDot(const State& s) const {
2070     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2071     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
2072     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getUDot(s)[uStart]);
2073 }
2074 
2075 const Vec4& MobilizedBody::Ellipsoid::
getMyPartQ(const State & s,const Vector & qlike) const2076 getMyPartQ(const State& s, const Vector& qlike) const {
2077     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq==4);
2078     return Vec4::getAs(&qlike[qStart]);
2079 }
2080 
2081 const Vec3& MobilizedBody::Ellipsoid::
getMyPartU(const State & s,const Vector & ulike) const2082 getMyPartU(const State& s, const Vector& ulike) const {
2083     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu==3);
2084     return Vec3::getAs(&ulike[uStart]);
2085 }
2086 
2087 Vec4& MobilizedBody::Ellipsoid::
updMyPartQ(const State & s,Vector & qlike) const2088 updMyPartQ(const State& s, Vector& qlike) const {
2089     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq==4);
2090     return Vec4::updAs(&qlike[qStart]);
2091 }
2092 
2093 Vec3& MobilizedBody::Ellipsoid::
updMyPartU(const State & s,Vector & ulike) const2094 updMyPartU(const State& s, Vector& ulike) const {
2095     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu==3);
2096     return Vec3::updAs(&ulike[uStart]);
2097 }
2098 
calcDecorativeGeometryAndAppendImpl(const State & s,Stage stage,Array_<DecorativeGeometry> & geom) const2099 void MobilizedBody::EllipsoidImpl::calcDecorativeGeometryAndAppendImpl
2100    (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const
2101 {
2102     // Call the superclass implementation to get standard default geometry.
2103 
2104     MobilizedBodyImpl::calcDecorativeGeometryAndAppendImpl(s, stage, geom);
2105 
2106     // We can't generate the ellipsoid until we know the radius, and we can't
2107     // place either piece of geometry on the bodies until we know the parent
2108     // and child mobilizer frame placements, which might not be until Instance
2109     // stage.
2110     if (stage == Stage::Instance && getMyMatterSubsystemRep().getShowDefaultGeometry())
2111     {
2112         const SimbodyMatterSubsystemRep& matterRep = getMyMatterSubsystemRep();
2113         const Transform& X_PMb = getInboardFrame(s);
2114         const Transform& X_BM  = getOutboardFrame(s);
2115 
2116         //TODO: this should come from the State.
2117         const Vec3 radii = getDefaultRadii();
2118 
2119         // Put an ellipsoid on the parent, and some wires to make it easier to track.
2120         geom.push_back(DecorativeEllipsoid(radii)
2121             .setColor(Gray)
2122             .setRepresentation(DecorativeGeometry::DrawSurface)
2123             .setOpacity(Real(0.5))
2124             .setResolution(Real(1.25))
2125             .setBodyId(getMyParentMobilizedBodyIndex())
2126             .setTransform(X_PMb));
2127         geom.push_back(DecorativeEllipsoid(radii*Real(.99))
2128             .setColor(White)
2129             .setRepresentation(DecorativeGeometry::DrawWireframe)
2130             .setResolution(Real(0.75))
2131             .setLineThickness(3)
2132             .setOpacity(Real(0.1))
2133             .setBodyId(getMyParentMobilizedBodyIndex())
2134             .setTransform(X_PMb));
2135 
2136         // Calculate the follower plate dimensions from the ellipsoid dimensions.
2137         const Real minr = std::min(radii[0],std::min(radii[1],radii[2]));
2138         const Real hw = minr/3;  // half width of follower plate in x
2139         const Real hh = minr/30; // half height of follower plate
2140 
2141         // raise up so bottom is on xy plane
2142         const Transform X_BFollower(X_BM.R(), X_BM.p() + Vec3(0,0,hh));
2143         geom.push_back(DecorativeBrick(Vec3(hw,Real(2*hw/3.),hh))
2144             .setColor(Orange)
2145             .setBodyId(getMyMobilizedBodyIndex())
2146             .setTransform(X_BFollower));
2147     }
2148 }
2149 
2150 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Ellipsoid,
2151     MobilizedBody::EllipsoidImpl, MobilizedBody);
2152 
2153     /////////////////////////////////
2154     // MOBILIZED BODY::TRANSLATION //
2155     /////////////////////////////////
2156 
Translation(MobilizedBody & parent,const Body & body,Direction d)2157 MobilizedBody::Translation::Translation
2158    (MobilizedBody& parent, const Body& body, Direction d)
2159 :   MobilizedBody(new TranslationImpl(d)) {
2160     // inb & outb frames are just the parent body's frame and new body's frame
2161     setBody(body);
2162 
2163     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2164                                                    *this);
2165 }
2166 
Translation(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)2167 MobilizedBody::Translation::Translation
2168    (MobilizedBody& parent, const Transform& inbFrame,
2169     const Body& body, const Transform& outbFrame, Direction d)
2170 :   MobilizedBody(new TranslationImpl(d)) {
2171     setDefaultInboardFrame(inbFrame);
2172     setDefaultOutboardFrame(outbFrame);
2173     setBody(body);
2174 
2175     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2176                                                    *this);
2177 }
2178 
getDefaultQ() const2179 const Vec3& MobilizedBody::Translation::getDefaultQ() const {
2180     return getImpl().defaultQ;
2181 }
2182 MobilizedBody::Translation& MobilizedBody::Translation::
setDefaultQ(const Vec3 & q)2183 setDefaultQ(const Vec3& q) {
2184     getImpl().invalidateTopologyCache();
2185     updImpl().defaultQ = q;
2186     return *this;
2187 }
2188 
getQ(const State & s) const2189 const Vec3& MobilizedBody::Translation::getQ(const State& s) const {
2190     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2191     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
2192     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getQ(s)[qStart]);
2193 }
setQ(State & s,const Vec3 & q) const2194 void MobilizedBody::Translation::setQ(State& s, const Vec3& q) const {
2195     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2196     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
2197     Vec3::updAs(&mbr.getMyMatterSubsystemRep().updQ(s)[qStart]) = q;
2198 }
getQDot(const State & s) const2199 const Vec3& MobilizedBody::Translation::getQDot(const State& s) const {
2200     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2201     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
2202     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getQDot(s)[qStart]);
2203 }
getQDotDot(const State & s) const2204 const Vec3& MobilizedBody::Translation::getQDotDot(const State& s) const {
2205     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2206     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 3);
2207     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getQDotDot(s)[qStart]);
2208 }
2209 
2210 
getU(const State & s) const2211 const Vec3& MobilizedBody::Translation::getU(const State& s) const {
2212     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2213     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
2214     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getU(s)[uStart]);
2215 }
setU(State & s,const Vec3 & u) const2216 void MobilizedBody::Translation::setU(State& s, const Vec3& u) const {
2217     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2218     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
2219     Vec3::updAs(&mbr.getMyMatterSubsystemRep().updU(s)[uStart]) = u;
2220 }
getUDot(const State & s) const2221 const Vec3& MobilizedBody::Translation::getUDot(const State& s) const {
2222     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2223     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
2224     return Vec3::getAs(&mbr.getMyMatterSubsystemRep().getUDot(s)[uStart]);
2225 }
2226 
2227 const Vec3& MobilizedBody::Translation::
getMyPartQ(const State & s,const Vector & qlike) const2228 getMyPartQ(const State& s, const Vector& qlike) const {
2229     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 3);
2230     return Vec3::getAs(&qlike[qStart]);
2231 }
2232 
2233 const Vec3& MobilizedBody::Translation::
getMyPartU(const State & s,const Vector & ulike) const2234 getMyPartU(const State& s, const Vector& ulike) const {
2235     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 3);
2236     return Vec3::getAs(&ulike[uStart]);
2237 }
2238 
2239 Vec3& MobilizedBody::Translation::
updMyPartQ(const State & s,Vector & qlike) const2240 updMyPartQ(const State& s, Vector& qlike) const {
2241     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 3);
2242     return Vec3::updAs(&qlike[qStart]);
2243 }
2244 
2245 Vec3& MobilizedBody::Translation::
updMyPartU(const State & s,Vector & ulike) const2246 updMyPartU(const State& s, Vector& ulike) const {
2247     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 3);
2248     return Vec3::updAs(&ulike[uStart]);
2249 }
2250 
2251 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Translation,
2252     MobilizedBody::TranslationImpl, MobilizedBody);
2253 
2254     //////////////////////////
2255     // MOBILIZED BODY::FREE //
2256     //////////////////////////
2257 
Free(MobilizedBody & parent,const Body & body,Direction d)2258 MobilizedBody::Free::Free(MobilizedBody& parent, const Body& body, Direction d)
2259 :   MobilizedBody(new FreeImpl(d)) {
2260     // inb & outb frames are just the parent body's frame and new body's frame
2261     setBody(body);
2262 
2263     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2264                                                    *this);
2265 }
2266 
Free(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)2267 MobilizedBody::Free::Free(MobilizedBody& parent, const Transform& inbFrame,
2268                           const Body& body, const Transform& outbFrame, Direction d)
2269 :   MobilizedBody(new FreeImpl(d)) {
2270     setDefaultInboardFrame(inbFrame);
2271     setDefaultOutboardFrame(outbFrame);
2272     setBody(body);
2273 
2274     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2275                                                    *this);
2276 }
2277 
2278 MobilizedBody::Free& MobilizedBody::Free::
setDefaultTranslation(const Vec3 & p_FM)2279 setDefaultTranslation(const Vec3& p_FM) {
2280     getImpl().invalidateTopologyCache();
2281     updImpl().defaultQTranslation = p_FM;
2282     return *this;
2283 }
2284 
2285 
2286 MobilizedBody::Free& MobilizedBody::Free::
setDefaultQuaternion(const Quaternion & R_FM)2287 setDefaultQuaternion(const Quaternion& R_FM) {
2288     getImpl().invalidateTopologyCache();
2289     updImpl().defaultQOrientation = R_FM;
2290     return *this;
2291 }
2292 
2293 MobilizedBody::Free& MobilizedBody::Free::
setDefaultRotation(const Rotation & R_FM)2294 setDefaultRotation(const Rotation& R_FM) {
2295     setDefaultQuaternion(R_FM.convertRotationToQuaternion());
2296     return *this;
2297 }
2298 
2299 MobilizedBody::Free& MobilizedBody::Free::
setDefaultTransform(const Transform & X_FM)2300 setDefaultTransform(const Transform& X_FM) {
2301     setDefaultTranslation(X_FM.p());
2302     setDefaultQuaternion(X_FM.R().convertRotationToQuaternion());
2303     return *this;
2304 }
2305 
getDefaultTranslation() const2306 const Vec3& MobilizedBody::Free::getDefaultTranslation() const {
2307     return getImpl().defaultQTranslation;
2308 }
2309 
getDefaultQuaternion() const2310 const Quaternion& MobilizedBody::Free::getDefaultQuaternion() const {
2311     return getImpl().defaultQOrientation;
2312 }
2313 
getDefaultQ() const2314 const Vec7& MobilizedBody::Free::getDefaultQ() const {
2315     // assuming struct is packed so (Orientation,Translation) are contiguous
2316     return Vec7::getAs((const Real*)&getImpl().defaultQOrientation);
2317 }
setDefaultQ(const Vec7 & q)2318 MobilizedBody::Free& MobilizedBody::Free::setDefaultQ(const Vec7& q) {
2319     getImpl().invalidateTopologyCache();
2320     updImpl().defaultQOrientation = Quaternion(q.getSubVec<4>(0));
2321     updImpl().defaultQTranslation = q.getSubVec<3>(4);
2322     return *this;
2323 }
2324 
getQ(const State & s) const2325 const Vec7& MobilizedBody::Free::getQ(const State& s) const {
2326     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2327     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq==7);
2328     return Vec7::getAs(&mbr.getMyMatterSubsystemRep().getQ(s)[qStart]);
2329 }
setQ(State & s,const Vec7 & q) const2330 void MobilizedBody::Free::setQ(State& s, const Vec7& q) const {
2331     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2332     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq==7);
2333     Vec7::updAs(&mbr.getMyMatterSubsystemRep().updQ(s)[qStart]) = q;
2334 }
getQDot(const State & s) const2335 const Vec7& MobilizedBody::Free::getQDot(const State& s) const {
2336     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2337     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq==7);
2338     return Vec7::getAs(&mbr.getMyMatterSubsystemRep().getQDot(s)[qStart]);
2339 }
getQDotDot(const State & s) const2340 const Vec7& MobilizedBody::Free::getQDotDot(const State& s) const {
2341     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2342     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq==7);
2343     return Vec7::getAs(&mbr.getMyMatterSubsystemRep().getQDotDot(s)[qStart]);
2344 }
2345 
2346 
getU(const State & s) const2347 const Vec6& MobilizedBody::Free::getU(const State& s) const {
2348     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2349     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 6);
2350     return Vec6::getAs(&mbr.getMyMatterSubsystemRep().getU(s)[uStart]);
2351 }
setU(State & s,const Vec6 & u) const2352 void MobilizedBody::Free::setU(State& s, const Vec6& u) const {
2353     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2354     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 6);
2355     Vec6::updAs(&mbr.getMyMatterSubsystemRep().updU(s)[uStart]) = u;
2356 }
getUDot(const State & s) const2357 const Vec6& MobilizedBody::Free::getUDot(const State& s) const {
2358     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2359     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 6);
2360     return Vec6::getAs(&mbr.getMyMatterSubsystemRep().getUDot(s)[uStart]);
2361 }
2362 
2363 const Vec7& MobilizedBody::Free::
getMyPartQ(const State & s,const Vector & qlike) const2364 getMyPartQ(const State& s, const Vector& qlike) const {
2365     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 7);
2366     return Vec7::getAs(&qlike[qStart]);
2367 }
2368 
2369 const Vec6& MobilizedBody::Free::
getMyPartU(const State & s,const Vector & ulike) const2370 getMyPartU(const State& s, const Vector& ulike) const {
2371     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 6);
2372     return Vec6::getAs(&ulike[uStart]);
2373 }
2374 
2375 Vec7& MobilizedBody::Free::
updMyPartQ(const State & s,Vector & qlike) const2376 updMyPartQ(const State& s, Vector& qlike) const {
2377     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 7);
2378     return Vec7::updAs(&qlike[qStart]);
2379 }
2380 
2381 Vec6& MobilizedBody::Free::
updMyPartU(const State & s,Vector & ulike) const2382 updMyPartU(const State& s, Vector& ulike) const {
2383     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 6);
2384     return Vec6::updAs(&ulike[uStart]);
2385 }
2386 
2387 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Free,
2388     MobilizedBody::FreeImpl, MobilizedBody);
2389 
2390     //////////////////////////////////////
2391     // MOBILIZED BODY::LINE ORIENTATION //
2392     //////////////////////////////////////
2393 
LineOrientation(MobilizedBody & parent,const Body & body,Direction d)2394 MobilizedBody::LineOrientation::LineOrientation
2395    (MobilizedBody& parent, const Body& body, Direction d)
2396 :   MobilizedBody(new LineOrientationImpl(d)) {
2397     // inb & outb frames are just the parent body's frame and new body's frame
2398     setBody(body);
2399 
2400     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2401                                                    *this);
2402 }
2403 
LineOrientation(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)2404 MobilizedBody::LineOrientation::LineOrientation
2405    (MobilizedBody& parent, const Transform& inbFrame,
2406     const Body& body, const Transform& outbFrame, Direction d)
2407 :   MobilizedBody(new LineOrientationImpl(d)) {
2408     setDefaultInboardFrame(inbFrame);
2409     setDefaultOutboardFrame(outbFrame);
2410     setBody(body);
2411 
2412     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2413                                                    *this);
2414 }
2415 
getDefaultQ() const2416 const Quaternion& MobilizedBody::LineOrientation::getDefaultQ() const {
2417     return getImpl().defaultQ;
2418 }
2419 MobilizedBody::LineOrientation& MobilizedBody::LineOrientation::
setDefaultQ(const Quaternion & quat)2420 setDefaultQ(const Quaternion& quat) {
2421     getImpl().invalidateTopologyCache();
2422     updImpl().defaultQ = quat;
2423     return *this;
2424 }
2425 
getQ(const State & s) const2426 const Vec4& MobilizedBody::LineOrientation::getQ(const State& s) const {
2427     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2428     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 4);
2429     return Vec4::getAs(&mbr.getMyMatterSubsystemRep().getQ(s)[qStart]);
2430 }
setQ(State & s,const Vec4 & q) const2431 void MobilizedBody::LineOrientation::setQ(State& s, const Vec4& q) const {
2432     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2433     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 4);
2434     Vec4::updAs(&mbr.getMyMatterSubsystemRep().updQ(s)[qStart]) = q;
2435 }
getQDot(const State & s) const2436 const Vec4& MobilizedBody::LineOrientation::getQDot(const State& s) const {
2437     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2438     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 4);
2439     return Vec4::getAs(&mbr.getMyMatterSubsystemRep().getQDot(s)[qStart]);
2440 }
getQDotDot(const State & s) const2441 const Vec4& MobilizedBody::LineOrientation::getQDotDot(const State& s) const {
2442     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2443     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 4);
2444     return Vec4::getAs(&mbr.getMyMatterSubsystemRep().getQDotDot(s)[qStart]);
2445 }
2446 
getU(const State & s) const2447 const Vec2& MobilizedBody::LineOrientation::getU(const State& s) const {
2448     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2449     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
2450     return Vec2::getAs(&mbr.getMyMatterSubsystemRep().getU(s)[uStart]);
2451 }
setU(State & s,const Vec2 & u) const2452 void MobilizedBody::LineOrientation::setU(State& s, const Vec2& u) const {
2453     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2454     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
2455     Vec2::updAs(&mbr.getMyMatterSubsystemRep().updU(s)[uStart]) = u;
2456 }
getUDot(const State & s) const2457 const Vec2& MobilizedBody::LineOrientation::getUDot(const State& s) const {
2458     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2459     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 3);
2460     return Vec2::getAs(&mbr.getMyMatterSubsystemRep().getUDot(s)[uStart]);
2461 }
2462 
2463 const Vec4& MobilizedBody::LineOrientation::
getMyPartQ(const State & s,const Vector & qlike) const2464 getMyPartQ(const State& s, const Vector& qlike) const {
2465     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 4);
2466     return Vec4::getAs(&qlike[qStart]);
2467 }
2468 
2469 const Vec2& MobilizedBody::LineOrientation::
getMyPartU(const State & s,const Vector & ulike) const2470 getMyPartU(const State& s, const Vector& ulike) const {
2471     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 3);
2472     return Vec2::getAs(&ulike[uStart]);
2473 }
2474 
2475 Vec4& MobilizedBody::LineOrientation::
updMyPartQ(const State & s,Vector & qlike) const2476 updMyPartQ(const State& s, Vector& qlike) const {
2477     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq == 4);
2478     return Vec4::updAs(&qlike[qStart]);
2479 }
2480 
2481 Vec2& MobilizedBody::LineOrientation::
updMyPartU(const State & s,Vector & ulike) const2482 updMyPartU(const State& s, Vector& ulike) const {
2483     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu == 3);
2484     return Vec2::updAs(&ulike[uStart]);
2485 }
2486 
2487 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::LineOrientation,
2488     MobilizedBody::LineOrientationImpl, MobilizedBody);
2489 
2490     ///////////////////////////////
2491     // MOBILIZED BODY::FREE LINE //
2492     ///////////////////////////////
2493 
FreeLine(MobilizedBody & parent,const Body & body,Direction d)2494 MobilizedBody::FreeLine::FreeLine
2495    (MobilizedBody& parent, const Body& body, Direction d)
2496 :   MobilizedBody(new FreeLineImpl(d)) {
2497     // inb & outb frames are just the parent body's frame and new body's frame
2498     setBody(body);
2499 
2500     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2501                                                    *this);
2502 }
2503 
FreeLine(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)2504 MobilizedBody::FreeLine::FreeLine
2505    (MobilizedBody& parent, const Transform& inbFrame,
2506     const Body& body, const Transform& outbFrame, Direction d)
2507 :   MobilizedBody(new FreeLineImpl(d)) {
2508     setDefaultInboardFrame(inbFrame);
2509     setDefaultOutboardFrame(outbFrame);
2510     setBody(body);
2511 
2512     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2513                                                    *this);
2514 }
2515 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::FreeLine,
2516     MobilizedBody::FreeLineImpl, MobilizedBody);
2517 
2518     //////////////////////////
2519     // MOBILIZED BODY::WELD //
2520     //////////////////////////
2521 
Weld(MobilizedBody & parent,const Body & body)2522 MobilizedBody::Weld::Weld(MobilizedBody& parent, const Body& body)
2523 :   MobilizedBody(new WeldImpl(MobilizedBody::Forward)) {
2524     // inb & outb frames are just the parent body's frame and new body's frame
2525     setBody(body);
2526 
2527     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2528                                                    *this);
2529 }
2530 
Weld(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame)2531 MobilizedBody::Weld::Weld(MobilizedBody& parent, const Transform& inbFrame,
2532                           const Body& body, const Transform& outbFrame)
2533 :   MobilizedBody(new WeldImpl(MobilizedBody::Forward)) {
2534     setDefaultInboardFrame(inbFrame);
2535     setDefaultOutboardFrame(outbFrame);
2536     setBody(body);
2537 
2538     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2539                                                    *this);
2540 }
2541 
2542 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Weld,
2543     MobilizedBody::WeldImpl, MobilizedBody);
2544 
2545     ////////////////////////////////
2546     // (IM)MOBILIZED BODY::GROUND //
2547     ////////////////////////////////
2548 
Ground()2549 MobilizedBody::Ground::Ground() : MobilizedBody(new GroundImpl()) {
2550     setBody(Body::Ground());
2551 }
2552 
2553 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Ground,
2554     MobilizedBody::GroundImpl, MobilizedBody);
2555 
2556     ///////////////////////////
2557     // MOBILIZED BODY::SCREW //
2558     ///////////////////////////
2559 
Screw(MobilizedBody & parent,const Body & body,Real pitch,Direction d)2560 MobilizedBody::Screw::Screw
2561    (MobilizedBody& parent, const Body& body, Real pitch, Direction d)
2562 :   MobilizedBody(new ScrewImpl(pitch,d)) {
2563     // inb & outb frames are just the parent body's frame and new body's frame
2564     setBody(body);
2565 
2566     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2567                                                    *this);
2568 }
2569 
Screw(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Real pitch,Direction d)2570 MobilizedBody::Screw::Screw(MobilizedBody& parent, const Transform& inbFrame,
2571                             const Body& body, const Transform& outbFrame,
2572                             Real pitch, Direction d)
2573 :   MobilizedBody(new ScrewImpl(pitch,d)) {
2574     setDefaultInboardFrame(inbFrame);
2575     setDefaultOutboardFrame(outbFrame);
2576     setBody(body);
2577 
2578     parent.updMatterSubsystem().adoptMobilizedBody(parent.getMobilizedBodyIndex(),
2579                                                    *this);
2580 }
2581 
setDefaultPitch(Real pitch)2582 MobilizedBody::Screw& MobilizedBody::Screw::setDefaultPitch(Real pitch) {
2583     updImpl().setDefaultPitch(pitch);
2584     return *this;
2585 }
2586 
getDefaultPitch() const2587 Real MobilizedBody::Screw::getDefaultPitch() const {
2588     return getImpl().getDefaultPitch();
2589 }
2590 
getDefaultQ() const2591 Real MobilizedBody::Screw::getDefaultQ() const {
2592     return getImpl().defaultQ;
2593 }
2594 
setDefaultQ(Real q)2595 MobilizedBody::Screw& MobilizedBody::Screw::setDefaultQ(Real q) {
2596     getImpl().invalidateTopologyCache();
2597     updImpl().defaultQ = q;
2598     return *this;
2599 }
2600 
getQ(const State & s) const2601 Real MobilizedBody::Screw::getQ(const State& s) const {
2602     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2603     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 1);
2604     return mbr.getMyMatterSubsystemRep().getQ(s)[qStart];
2605 }
setQ(State & s,Real q) const2606 void MobilizedBody::Screw::setQ(State& s, Real q) const {
2607     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2608     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 1);
2609     mbr.getMyMatterSubsystemRep().updQ(s)[qStart] = q;
2610 }
getQDot(const State & s) const2611 Real MobilizedBody::Screw::getQDot(const State& s) const {
2612     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2613     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 1);
2614     return mbr.getMyMatterSubsystemRep().getQDot(s)[qStart];
2615 }
getQDotDot(const State & s) const2616 Real MobilizedBody::Screw::getQDotDot(const State& s) const {
2617     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2618     QIndex qStart; int nq; mbr.findMobilizerQs(s,qStart,nq); assert(nq == 1);
2619     return mbr.getMyMatterSubsystemRep().getQDotDot(s)[qStart];
2620 }
2621 
2622 
getU(const State & s) const2623 Real MobilizedBody::Screw::getU(const State& s) const {
2624     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2625     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 1);
2626     return mbr.getMyMatterSubsystemRep().getU(s)[uStart];
2627 }
setU(State & s,Real u) const2628 void MobilizedBody::Screw::setU(State& s, Real u) const {
2629     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2630     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 1);
2631     mbr.getMyMatterSubsystemRep().updU(s)[uStart] = u;
2632 }
getUDot(const State & s) const2633 Real MobilizedBody::Screw::getUDot(const State& s) const {
2634     const MobilizedBodyImpl& mbr = MobilizedBody::getImpl();
2635     UIndex uStart; int nu; mbr.findMobilizerUs(s,uStart,nu); assert(nu == 1);
2636     return mbr.getMyMatterSubsystemRep().getUDot(s)[uStart];
2637 }
2638 
getMyPartQ(const State & s,const Vector & qlike) const2639 Real MobilizedBody::Screw::getMyPartQ(const State& s, const Vector& qlike) const {
2640     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq==1);
2641     return qlike[qStart];
2642 }
2643 
getMyPartU(const State & s,const Vector & ulike) const2644 Real MobilizedBody::Screw::getMyPartU(const State& s, const Vector& ulike) const {
2645     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu==1);
2646     return ulike[uStart];
2647 }
2648 
updMyPartQ(const State & s,Vector & qlike) const2649 Real& MobilizedBody::Screw::updMyPartQ(const State& s, Vector& qlike) const {
2650     QIndex qStart; int nq; getImpl().findMobilizerQs(s,qStart,nq); assert(nq==1);
2651     return qlike[qStart];
2652 }
2653 
updMyPartU(const State & s,Vector & ulike) const2654 Real& MobilizedBody::Screw::updMyPartU(const State& s, Vector& ulike) const {
2655     UIndex uStart; int nu; getImpl().findMobilizerUs(s,uStart,nu); assert(nu==1);
2656     return ulike[uStart];
2657 }
2658 
2659 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Screw,
2660     MobilizedBody::ScrewImpl, MobilizedBody);
2661 
2662     ////////////////////////////
2663     // MOBILIZED BODY::CUSTOM //
2664     ////////////////////////////
2665 
2666 // We are given an Implementation object which is already holding a CustomImpl
2667 // object for us. We'll first take away ownership of the CustomImpl, then
2668 // make the CustomImpl take over ownership of the Implementation object.
Custom(MobilizedBody & parent,MobilizedBody::Custom::Implementation * implementation,const Body & body,Direction d)2669 MobilizedBody::Custom::Custom
2670    (MobilizedBody& parent, MobilizedBody::Custom::Implementation* implementation,
2671     const Body& body, Direction d)
2672 :   MobilizedBody(implementation
2673         ? implementation->updImpl().removeOwnershipOfCustomImpl()
2674         : 0)
2675 {
2676     SimTK_ASSERT_ALWAYS(implementation,
2677         "MobilizedBody::Custom::Custom(): Implementation pointer was NULL.");
2678     setBody(body);
2679 
2680     updImpl().setDirection(d);
2681 
2682     // Now store the Implementation pointer in our CustomImpl. The Implementation
2683     // object retains its original pointer to the CustomImpl object so it can
2684     // operate as a proxy for the CustomImpl. However the Custom handle now owns
2685     // the CustomImpl and the CustomImpl owns the Implementation.
2686     updImpl().takeOwnershipOfImplementation(implementation);
2687 
2688     updImpl().updMyMatterSubsystemRep()
2689         .adoptMobilizedBody(parent.getMobilizedBodyIndex(), *this);
2690 }
2691 
Custom(MobilizedBody & parent,MobilizedBody::Custom::Implementation * implementation,const Transform & inbFrame,const Body & body,const Transform & outbFrame,Direction d)2692 MobilizedBody::Custom::Custom
2693    (MobilizedBody& parent, MobilizedBody::Custom::Implementation* implementation,
2694     const Transform& inbFrame, const Body& body, const Transform& outbFrame,
2695     Direction d)
2696 :   MobilizedBody(implementation
2697         ? implementation->updImpl().removeOwnershipOfCustomImpl()
2698         : 0)
2699 {
2700     SimTK_ASSERT_ALWAYS(implementation,
2701         "MobilizedBody::Custom::Custom(): Implementation pointer was NULL.");
2702     setBody(body);
2703     setDefaultInboardFrame(inbFrame);
2704     setDefaultOutboardFrame(outbFrame);
2705 
2706     updImpl().setDirection(d);
2707 
2708     // Now store the Implementation pointer in our CustomImpl. The Implementation
2709     // object retains its original pointer to the CustomImpl object so it can
2710     // operate as a proxy for the CustomImpl. However the Custom handle now owns
2711     // the CustomImpl and the CustomImpl owns the Implementation.
2712     updImpl().takeOwnershipOfImplementation(implementation);
2713 
2714     updImpl().updMyMatterSubsystemRep()
2715         .adoptMobilizedBody(parent.getMobilizedBodyIndex(), *this);
2716 }
2717 
2718 const MobilizedBody::Custom::Implementation& MobilizedBody::Custom::
getImplementation() const2719 getImplementation() const {
2720     return getImpl().getImplementation();
2721 }
2722 
2723 MobilizedBody::Custom::Implementation& MobilizedBody::Custom::
updImplementation()2724 updImplementation() {
2725     return updImpl().updImplementation();
2726 }
2727 
2728 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(MobilizedBody::Custom,
2729     MobilizedBody::CustomImpl, MobilizedBody);
2730 
2731 // MobilizedBody::CustomImpl
2732 
2733 // The Implementation object should already contain a pointer to this CustomImpl object.
2734 void MobilizedBody::CustomImpl::
takeOwnershipOfImplementation(Custom::Implementation * userImpl)2735 takeOwnershipOfImplementation(Custom::Implementation* userImpl) {
2736     assert(!implementation); // you can only do this once!
2737     assert(userImpl);
2738     const Custom::ImplementationImpl& impImpl = userImpl->getImpl();
2739     assert(&impImpl.getCustomImpl() == this && !impImpl.isOwnerOfCustomImpl());
2740     implementation = userImpl;
2741 }
2742 
2743 ////////////////////////////////////////////
2744 // MOBILIZED BODY::CUSTOM::IMPLEMENTATION //
2745 ////////////////////////////////////////////
2746 
2747 // We create the initial CustomImpl as though it the mobilizer will be in the
2748 // forward direction. However, that may be changed later when this
2749 // implementation is put to use.
Implementation(SimbodyMatterSubsystem & matter,int nu,int nq,int nAngles)2750 MobilizedBody::Custom::Implementation::Implementation
2751    (SimbodyMatterSubsystem& matter, int nu, int nq, int nAngles)
2752 :   PIMPLHandle<Implementation,ImplementationImpl>
2753        (new ImplementationImpl(new CustomImpl(MobilizedBody::Forward),
2754                                nu, nq, nAngles))
2755 {
2756     assert(nu > 0);
2757     assert(nq > 0);
2758     assert(nAngles >= 0);
2759     assert(nu <= 6);
2760     assert(nq <= 7);
2761     assert(nAngles <= 4);
2762     assert(nu <= nq);
2763     assert(nAngles <= nq);
2764     // We don't know the MobilizedBodyIndex yet since this hasn't been adopted
2765     // by the MatterSubsystem.
2766     updImpl().updCustomImpl().setMyMatterSubsystem
2767        (matter, MobilizedBodyIndex(0), MobilizedBodyIndex(0));
2768 }
2769 
~Implementation()2770 MobilizedBody::Custom::Implementation::~Implementation() {
2771 }
2772 
invalidateTopologyCache() const2773 void MobilizedBody::Custom::Implementation::invalidateTopologyCache() const {
2774     getImpl().getCustomImpl().invalidateTopologyCache();
2775 }
2776 
2777 bool MobilizedBody::Custom::Implementation::
getUseEulerAngles(const State & state) const2778 getUseEulerAngles(const State& state) const {
2779     return getImpl().getCustomImpl().getMyMatterSubsystemRep().getUseEulerAngles(state);
2780 }
2781 
getQ(const State & state) const2782 Vector MobilizedBody::Custom::Implementation::getQ(const State& state) const {
2783     const SBModelVars& mv = getImpl().getCustomImpl().getMyMatterSubsystemRep()
2784                                                         .getModelVars(state);
2785     const RigidBodyNode& body = getImpl().getCustomImpl().getMyRigidBodyNode();
2786     const int indexBase = body.getQIndex();
2787     Vector q(body.getNQInUse(mv));
2788     for (int i = 0; i < q.size(); ++i) {
2789         int index = indexBase+i;
2790         q[i] = state.getQ()[index];
2791     }
2792     return q;
2793 }
2794 
getU(const State & state) const2795 Vector MobilizedBody::Custom::Implementation::getU(const State& state) const {
2796     const SBModelVars& mv = getImpl().getCustomImpl().getMyMatterSubsystemRep()
2797                                                         .getModelVars(state);
2798     const RigidBodyNode& body = getImpl().getCustomImpl().getMyRigidBodyNode();
2799     const int indexBase = body.getUIndex();
2800     Vector u(body.getNUInUse(mv));
2801     for (int i = 0; i < u.size(); ++i) {
2802         int index = indexBase+i;
2803         u[i] = state.getU()[index];
2804     }
2805     return u;
2806 }
2807 
getQDot(const State & state) const2808 Vector MobilizedBody::Custom::Implementation::getQDot(const State& state) const {
2809     const SBModelVars& mv = getImpl().getCustomImpl().getMyMatterSubsystemRep()
2810                                                         .getModelVars(state);
2811     const RigidBodyNode& body = getImpl().getCustomImpl().getMyRigidBodyNode();
2812     const int indexBase = body.getQIndex();
2813     Vector qdot(body.getNQInUse(mv));
2814     for (int i = 0; i < qdot.size(); ++i) {
2815         int index = indexBase+i;
2816         qdot[i] = state.getQDot()[index];
2817     }
2818     return qdot;
2819 }
2820 
getUDot(const State & state) const2821 Vector MobilizedBody::Custom::Implementation::getUDot(const State& state) const {
2822     const SBModelVars& mv = getImpl().getCustomImpl().getMyMatterSubsystemRep()
2823                                                         .getModelVars(state);
2824     const RigidBodyNode& body = getImpl().getCustomImpl().getMyRigidBodyNode();
2825     const int indexBase = body.getUIndex();
2826     Vector udot(body.getNUInUse(mv));
2827     for (int i = 0; i < udot.size(); ++i) {
2828         int index = indexBase+i;
2829         udot[i] = state.getUDot()[index];
2830     }
2831     return udot;
2832 }
2833 
getQDotDot(const State & state) const2834 Vector MobilizedBody::Custom::Implementation::getQDotDot(const State& state) const {
2835     const SBModelVars& mv = getImpl().getCustomImpl().getMyMatterSubsystemRep()
2836                                                         .getModelVars(state);
2837     const RigidBodyNode& body = getImpl().getCustomImpl().getMyRigidBodyNode();
2838     const int indexBase = body.getQIndex();
2839     Vector qdotdot(body.getNQInUse(mv));
2840     for (int i = 0; i < qdotdot.size(); ++i) {
2841         int index = indexBase+i;
2842         qdotdot[i] = state.getQDotDot()[index];
2843     }
2844     return qdotdot;
2845 }
2846 
2847 // Careful: must return the transform X_F0M0 using the "as defined" frames,
2848 // rather than X_FM which might be reversed due to mobilizer reversal.
2849 Transform MobilizedBody::Custom::Implementation::
getMobilizerTransform(const State & s) const2850 getMobilizerTransform(const State& s) const {
2851     // Use "upd" instead of "get" here because the custom mobilizer definition
2852     // needs access to this local information during realizePosition() so get
2853     // would throw a stage violation.
2854     const SBTreePositionCache& pc = getImpl().getCustomImpl()
2855                             .getMyMatterSubsystemRep().updTreePositionCache(s);
2856     const RigidBodyNode& node = getImpl().getCustomImpl().getMyRigidBodyNode();
2857     return node.findX_F0M0(pc);
2858 }
2859 
2860 // Careful: must return the velocity V_F0M0 using the "as defined" frames,
2861 // rather than V_FM which might be reversed due to mobilizer reversal.
2862 SpatialVec MobilizedBody::Custom::Implementation::
getMobilizerVelocity(const State & s) const2863 getMobilizerVelocity(const State& s) const {
2864     const SBTreePositionCache& pc = getImpl().getCustomImpl()
2865                             .getMyMatterSubsystemRep().getTreePositionCache(s);
2866     // Use "upd" instead of "get" here because the custom mobilizer definition
2867     // needs access to this local information during realizeVelocity() so get
2868     // would throw a stage violation.
2869     const SBTreeVelocityCache& vc = getImpl().getCustomImpl()
2870                             .getMyMatterSubsystemRep().updTreeVelocityCache(s);
2871     const RigidBodyNode& node = getImpl().getCustomImpl().getMyRigidBodyNode();
2872     return node.findV_F0M0(pc,vc);
2873 }
2874 
2875 void MobilizedBody::Custom::Implementation::
multiplyByN(const State & s,bool transposeMatrix,int nIn,const Real * in,int nOut,Real * out) const2876 multiplyByN(const State& s, bool transposeMatrix,
2877             int nIn, const Real* in, int nOut, Real* out) const {
2878     // Default implementation
2879     assert((nIn==0 || in) && (nOut==0 || out));
2880     int nu = getImpl().getNU(), nq = getImpl().getNQ(),
2881         nAngles = getImpl().getNumAngles();
2882     assert(nq==nu && nIn==nu && nOut==nu && nAngles < 4);
2883     for (int i=0; i<nu; ++i) out[i] = in[i];
2884 }
2885 
2886 void MobilizedBody::Custom::Implementation::
multiplyByNInv(const State & s,bool transposeMatrix,int nIn,const Real * in,int nOut,Real * out) const2887 multiplyByNInv(const State& s, bool transposeMatrix,
2888                int nIn, const Real* in, int nOut, Real* out) const {
2889     // Default implementation
2890     assert((nIn==0 || in) && (nOut==0 || out));
2891     int nu = getImpl().getNU(), nq = getImpl().getNQ(),
2892         nAngles = getImpl().getNumAngles();
2893     assert(nq==nu && nIn==nu && nOut==nu && nAngles < 4);
2894     for (int i=0; i<nu; ++i) out[i] = in[i];
2895 }
2896 
2897 void MobilizedBody::Custom::Implementation::
multiplyByNDot(const State & s,bool transposeMatrix,int nIn,const Real * in,int nOut,Real * out) const2898 multiplyByNDot(const State& s, bool transposeMatrix,
2899                int nIn, const Real* in, int nOut, Real* out) const {
2900     // Default implementation
2901     assert((nIn==0 || in) && (nOut==0 || out));
2902     int nu = getImpl().getNU(), nq = getImpl().getNQ(),
2903         nAngles = getImpl().getNumAngles();
2904     assert(nq==nu && nIn==nu && nOut==nu && nAngles < 4);
2905     for (int i=0; i<nu; ++i) out[i] = 0;
2906 }
2907 
2908 void MobilizedBody::Custom::Implementation::
setQToFitTransform(const State & state,const Transform & X_FM,int nq,Real * q) const2909 setQToFitTransform(const State& state, const Transform& X_FM,
2910                    int nq, Real* q) const
2911 {
2912     class OptimizerFunction : public OptimizerSystem {
2913     public:
2914         OptimizerFunction(const MobilizedBody::Custom::Implementation& impl,
2915                           const State& state, int nq, const Transform& X_FM)
2916         :   OptimizerSystem(nq), impl(impl), state(state), X_FM(X_FM) {}
2917 
2918         int objectiveFunc(const Vector& params, bool new_params, Real& f) const override {
2919             Transform transform = impl.calcMobilizerTransformFromQ
2920                                             (state, params.size(), &params[0]);
2921             f = (transform.p()-X_FM.p()).norm();
2922             f += std::abs((~transform.R()*X_FM.R()).convertRotationToAngleAxis()[0]);
2923             return 0;
2924         }
2925     private:
2926         const MobilizedBody::Custom::Implementation& impl;
2927         const State& state;
2928         const Transform& X_FM;
2929     };
2930     OptimizerFunction function(*this, state, nq, X_FM);
2931     Optimizer opt(function);
2932     opt.useNumericalJacobian(true);
2933     opt.useNumericalGradient(true);
2934     opt.setLimitedMemoryHistory(100);
2935     Vector qvec(nq);
2936 
2937     // Pick initial values which are 1) deterministic and 2) unlikely to
2938     // correspond to a local maximum or inflection point, which could cause the
2939     // optimizer to fail.
2940 
2941     for (int i = 0; i < nq; i++)
2942         qvec[i] = i+Real(0.12354);
2943     opt.optimize(qvec);
2944     for (int i = 0; i < nq; i++)
2945         q[i] = qvec[i];
2946 }
2947 
2948 void MobilizedBody::Custom::Implementation::
setUToFitVelocity(const State & state,const SpatialVec & V_FM,int nu,Real * u) const2949 setUToFitVelocity(const State& state, const SpatialVec& V_FM,
2950                   int nu, Real* u) const
2951 {
2952     class OptimizerFunction : public OptimizerSystem {
2953     public:
2954         OptimizerFunction(const MobilizedBody::Custom::Implementation& impl,
2955                           const State& state, int nu, const SpatialVec& V_FM)
2956         :   OptimizerSystem(nu), impl(impl), state(state), V_FM(V_FM) {}
2957 
2958         int objectiveFunc(const Vector& params, bool new_params, Real& f) const override {
2959             SpatialVec v = impl.multiplyByHMatrix
2960                                             (state, params.size(), &params[0]);
2961             f = (v[0]-V_FM[0]).norm();
2962             f += (v[1]-V_FM[1]).norm();
2963             return 0;
2964         }
2965     private:
2966         const MobilizedBody::Custom::Implementation& impl;
2967         const State& state;
2968         const SpatialVec& V_FM;
2969     };
2970     OptimizerFunction function(*this, state, nu, V_FM);
2971     Optimizer opt(function);
2972     opt.useNumericalJacobian(true);
2973     opt.useNumericalGradient(true);
2974     opt.setLimitedMemoryHistory(100);
2975     Vector uvec(nu);
2976 
2977     // Pick initiial values which are 1) deterministic and 2) unlikely to
2978     // correspond to a local maximum or inflection point, which could cause the
2979     // optimizer to fail.
2980 
2981     for (int i = 0; i < nu; i++)
2982         uvec[i] = i+Real(0.12354);
2983     opt.optimize(uvec);
2984     for (int i = 0; i < nu; i++)
2985         u[i] = uvec[i];
2986 }
2987 
2988 // Constructors without user-specified axes for function-based mobilized body
FunctionBased(MobilizedBody & parent,const Body & body,int nmobilities,const Array_<const Function * > & functions,const Array_<Array_<int>> & coordIndices,Direction direction)2989 MobilizedBody::FunctionBased::FunctionBased
2990    (MobilizedBody& parent, const Body& body,
2991     int nmobilities, const Array_<const Function*>& functions,
2992     const Array_<Array_<int> >& coordIndices,
2993     Direction direction)
2994 :   Custom(parent, new FunctionBasedImpl(parent.updMatterSubsystem(),
2995                                          nmobilities, functions, coordIndices),
2996            body, direction)
2997 {
2998 }
2999 
FunctionBased(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,int nmobilities,const Array_<const Function * > & functions,const Array_<Array_<int>> & coordIndices,Direction direction)3000 MobilizedBody::FunctionBased::FunctionBased
3001    (MobilizedBody& parent, const Transform& inbFrame,
3002     const Body& body, const Transform& outbFrame,
3003     int nmobilities, const Array_<const Function*>& functions,
3004     const Array_<Array_<int> >& coordIndices,
3005     Direction direction)
3006 :   Custom(parent, new FunctionBasedImpl(parent.updMatterSubsystem(),
3007                                          nmobilities, functions, coordIndices),
3008            body, direction)
3009 {
3010     setDefaultInboardFrame(inbFrame);
3011     setDefaultOutboardFrame(outbFrame);
3012 }
3013 
3014 // Constructors that allow user-specified axes for function-based mobilized body
FunctionBased(MobilizedBody & parent,const Body & body,int nmobilities,const Array_<const Function * > & functions,const Array_<Array_<int>> & coordIndices,const Array_<Vec3> & axes,Direction direction)3015 MobilizedBody::FunctionBased::FunctionBased
3016    (MobilizedBody& parent, const Body& body,
3017     int nmobilities, const Array_<const Function*>& functions,
3018     const Array_<Array_<int> >& coordIndices, const Array_<Vec3>& axes,
3019     Direction direction)
3020 :   Custom(parent, new FunctionBasedImpl(parent.updMatterSubsystem(),
3021                                          nmobilities, functions,
3022                                          coordIndices, axes),
3023            body, direction)
3024 {
3025 }
3026 
FunctionBased(MobilizedBody & parent,const Transform & inbFrame,const Body & body,const Transform & outbFrame,int nmobilities,const Array_<const Function * > & functions,const Array_<Array_<int>> & coordIndices,const Array_<Vec3> & axes,Direction direction)3027 MobilizedBody::FunctionBased::FunctionBased
3028    (MobilizedBody& parent, const Transform& inbFrame,
3029     const Body& body, const Transform& outbFrame,
3030     int nmobilities, const Array_<const Function*>& functions,
3031     const Array_<Array_<int> >& coordIndices, const Array_<Vec3>& axes,
3032     Direction direction)
3033 :   Custom(parent, new FunctionBasedImpl(parent.updMatterSubsystem(),
3034                                          nmobilities, functions,
3035                                          coordIndices, axes),
3036            body, direction)
3037 {
3038     setDefaultInboardFrame(inbFrame);
3039     setDefaultOutboardFrame(outbFrame);
3040 }
3041 
3042 } // namespace SimTK
3043 
3044