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(), ¶ms[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(), ¶ms[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