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) 2011-15 Stanford University and the Authors. *
10 * Authors: Peter Eastman *
11 * Contributors: Michael Sherman *
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 #include "SimbodyMatterSubsystemRep.h"
25 #include "RigidBodyNode.h"
26 #include "MobilizedBodyImpl.h"
27 #include "RigidBodyNodeSpec_Translation.h"
28
29 /* This is a specialized class used for MobilizedBody::Translation objects that
30 satisfy all of the following requirements:
31 - The body has no children.
32 - The body's parent is ground.
33 - The inboard and outboard transforms are both identities.
34 - The body is not reversed.
35
36 These assumptions allow lots of routines to be implemented simpler and faster.
37 */
38 class RBNodeLoneParticle : public RigidBodyNode {
39 public:
RBNodeLoneParticle(const MassProperties & mProps_B,UIndex & nextUSlot,USquaredIndex & nextUSqSlot,QIndex & nextQSlot)40 RBNodeLoneParticle(const MassProperties& mProps_B,
41 UIndex& nextUSlot,
42 USquaredIndex& nextUSqSlot,
43 QIndex& nextQSlot)
44 : RigidBodyNode(mProps_B, Vec3(0), Vec3(0),
45 QDotIsAlwaysTheSameAsU, QuaternionIsNeverUsed, false) {
46 uIndex = nextUSlot;
47 uSqIndex = nextUSqSlot;
48 qIndex = nextQSlot;
49 nextUSlot += 3;
50 nextUSqSlot += 9;
51 nextQSlot += 3;
52 }
53
type() const54 const char* type() const override {return "loneparticle";}
getDOF() const55 int getDOF() const override {return 3;}
getMaxNQ() const56 int getMaxNQ() const override {return 3;}
57
getNQInUse(const SBModelVars &) const58 int getNQInUse(const SBModelVars&) const override {return 3;}
getNUInUse(const SBModelVars &) const59 int getNUInUse(const SBModelVars&) const override {return 3;}
60
isUsingQuaternion(const SBStateDigest &,MobilizerQIndex & startOfQuaternion) const61 bool isUsingQuaternion(const SBStateDigest&,
62 MobilizerQIndex& startOfQuaternion) const override {
63 return false;
64 }
65
calcQPoolSize(const SBModelVars &) const66 int calcQPoolSize(const SBModelVars&) const override {
67 return 0;
68 }
69
performQPrecalculations(const SBStateDigest & sbs,const Real * q,int nq,Real * qCache,int nQCache,Real * qErr,int nQErr) const70 void performQPrecalculations(const SBStateDigest& sbs,
71 const Real* q, int nq,
72 Real* qCache, int nQCache,
73 Real* qErr, int nQErr) const override {
74 assert(q && nq==3 && nQCache==0 && nQErr==0);
75 }
76
calcX_FM(const SBStateDigest & sbs,const Real * q,int nq,const Real * qCache,int nQCache,Transform & X_FM) const77 void calcX_FM(const SBStateDigest& sbs,
78 const Real* q, int nq,
79 const Real* qCache, int nQCache,
80 Transform& X_FM) const override {
81 assert(q && nq==3 && nQCache==0);
82 X_FM = Transform(Rotation(), Vec3::getAs(&q[0]));
83 }
84
calcQDot(const SBStateDigest &,const Real * u,Real * qdot) const85 void calcQDot(const SBStateDigest&, const Real* u, Real* qdot) const override {
86 Vec3::updAs(qdot) = Vec3::getAs(u);
87 }
calcQDotDot(const SBStateDigest &,const Real * udot,Real * qdotdot) const88 void calcQDotDot(const SBStateDigest&, const Real* udot,
89 Real* qdotdot) const override {
90 Vec3::updAs(qdotdot) = Vec3::getAs(udot);
91 }
92
multiplyByN(const SBStateDigest &,bool matrixOnRight,const Real * in,Real * out) const93 void multiplyByN(const SBStateDigest&, bool matrixOnRight, const Real* in,
94 Real* out) const override {
95 Vec3::updAs(out) = Vec3::getAs(in);
96 }
multiplyByNInv(const SBStateDigest &,bool matrixOnRight,const Real * in,Real * out) const97 void multiplyByNInv(const SBStateDigest&, bool matrixOnRight, const Real* in,
98 Real* out) const override {
99 Vec3::updAs(out) = Vec3::getAs(in);
100 }
multiplyByNDot(const SBStateDigest &,bool matrixOnRight,const Real * in,Real * out) const101 void multiplyByNDot(const SBStateDigest&, bool matrixOnRight, const Real* in,
102 Real* out) const override {
103 Vec3::updAs(out) = 0;
104 }
105
enforceQuaternionConstraints(const SBStateDigest & sbs,Vector & q,Vector & qErrest) const106 bool enforceQuaternionConstraints(
107 const SBStateDigest& sbs,
108 Vector& q,
109 Vector& qErrest) const override {
110 return false;
111 }
112
convertToEulerAngles(const Vector & inputQ,Vector & outputQ) const113 void convertToEulerAngles(const Vector& inputQ,
114 Vector& outputQ) const override {
115 Vec3::updAs(&outputQ[qIndex]) = Vec3::getAs(&inputQ[qIndex]);
116 }
117
convertToQuaternions(const Vector & inputQ,Vector & outputQ) const118 void convertToQuaternions(const Vector& inputQ,
119 Vector& outputQ) const override {
120 Vec3::updAs(&outputQ[qIndex]) = Vec3::getAs(&inputQ[qIndex]);
121 }
122
setMobilizerDefaultModelValues(const SBTopologyCache &,SBModelVars &) const123 void setMobilizerDefaultModelValues
124 (const SBTopologyCache&, SBModelVars&) const override {}
125
setMobilizerDefaultInstanceValues(const SBModelVars &,SBInstanceVars &) const126 void setMobilizerDefaultInstanceValues
127 (const SBModelVars&, SBInstanceVars&) const override {}
setMobilizerDefaultTimeValues(const SBModelVars &,SBTimeVars &) const128 void setMobilizerDefaultTimeValues
129 (const SBModelVars&, SBTimeVars&) const override {}
setMobilizerDefaultPositionValues(const SBModelVars &,Vector & q) const130 void setMobilizerDefaultPositionValues
131 (const SBModelVars&, Vector& q) const override {q = 0;}
setMobilizerDefaultVelocityValues(const SBModelVars &,Vector & u) const132 void setMobilizerDefaultVelocityValues
133 (const SBModelVars&, Vector& u) const override {u = 0;}
setMobilizerDefaultDynamicsValues(const SBModelVars &,SBDynamicsVars &) const134 void setMobilizerDefaultDynamicsValues
135 (const SBModelVars&, SBDynamicsVars&) const override {}
setMobilizerDefaultAccelerationValues(const SBModelVars &,SBAccelerationVars &) const136 void setMobilizerDefaultAccelerationValues
137 (const SBModelVars&, SBAccelerationVars&) const override {}
138
realizeModel(SBStateDigest & sbs) const139 void realizeModel(SBStateDigest& sbs) const override {
140 }
141
realizeInstance(const SBStateDigest & sbs) const142 void realizeInstance(const SBStateDigest& sbs) const override {
143 // Initialize cache entries that will never be changed at later stages.
144
145 SBTreePositionCache& pc = sbs.updTreePositionCache();
146 SBTreeVelocityCache& vc = sbs.updTreeVelocityCache();
147 SBDynamicsCache& dc = sbs.updDynamicsCache();
148 SBTreeAccelerationCache& ac = sbs.updTreeAccelerationCache();
149 Transform& X_FM = toB(pc.bodyJointInParentJointFrame);
150 X_FM.updR().setRotationToIdentityMatrix();
151 updV_FM(vc)[0] = Vec3(0);
152 updV_PB_G(vc)[0] = Vec3(0);
153 updVD_PB_G(vc)[0] = Vec3(0);
154 updV_GB(vc)[0] = Vec3(0);
155 updGyroscopicForce(vc) = SpatialVec(Vec3(0), Vec3(0));
156 updMobilizerCoriolisAcceleration(vc) = SpatialVec(Vec3(0), Vec3(0));
157 updTotalCoriolisAcceleration(vc) = SpatialVec(Vec3(0), Vec3(0));
158 updTotalCentrifugalForces(vc) = SpatialVec(Vec3(0), Vec3(0));
159 updY(dc) = SpatialMat(Mat33(0), Mat33(0), Mat33(0), Mat33(1/getMass()));
160 updA_GB(ac)[0] = Vec3(0);
161 }
162
realizePosition(const SBStateDigest & sbs) const163 void realizePosition(const SBStateDigest& sbs) const override {
164 SBTreePositionCache& pc = sbs.updTreePositionCache();
165 Transform& X_FM = toB(pc.bodyJointInParentJointFrame);
166 const Vec3& q = Vec3::getAs(&sbs.getQ()[qIndex]);
167 X_FM.updP() = q;
168 updX_PB(pc) = X_FM;
169 updX_GB(pc) = X_FM;
170 updPhi(pc) = PhiMatrix(q);
171 updCOM_G(pc) = q + getCOM_B(); // 3 flops
172 updMk_G(pc) = SpatialInertia(getMass(), getCOM_B(), getUnitInertia_OB_B());
173 }
174
realizeVelocity(const SBStateDigest & sbs) const175 void realizeVelocity(const SBStateDigest& sbs) const override {
176 SBTreeVelocityCache& vc = sbs.updTreeVelocityCache();
177 const Vector& allU = sbs.getU();
178 const Vec3& u = Vec3::getAs(&allU[uIndex]);
179
180 Vec3::updAs(&sbs.updQDot()[qIndex]) = Vec3::getAs(&allU[uIndex]);
181 updV_FM(vc)[1] = u;
182 updV_PB_G(vc)[1] = u;
183 updV_GB(vc)[1] = u;
184 }
185
realizeDynamics(const SBStateDigest &) const186 void realizeDynamics(const SBStateDigest&) const override {
187 }
188
189 // There is no realizeAcceleration().
190
realizeReport(const SBStateDigest &) const191 void realizeReport(const SBStateDigest&) const override {
192 }
193
realizeArticulatedBodyInertiasInward(const SBInstanceCache & ic,const SBTreePositionCache & pc,SBArticulatedBodyInertiaCache & abc) const194 void realizeArticulatedBodyInertiasInward(
195 const SBInstanceCache& ic,
196 const SBTreePositionCache& pc,
197 SBArticulatedBodyInertiaCache& abc) const override {
198 ArticulatedInertia& P = updP(abc);
199 ArticulatedInertia& PPlus = updPPlus(abc);
200
201 PPlus = P = ArticulatedInertia(getMk_G(pc));
202 }
203
realizeYOutward(const SBInstanceCache & ic,const SBTreePositionCache & pc,const SBArticulatedBodyInertiaCache & abc,SBDynamicsCache & dc) const204 void realizeYOutward(
205 const SBInstanceCache& ic,
206 const SBTreePositionCache& pc,
207 const SBArticulatedBodyInertiaCache& abc,
208 SBDynamicsCache& dc) const override {
209 }
210
calcCompositeBodyInertiasInward(const SBTreePositionCache & pc,Array_<SpatialInertia,MobilizedBodyIndex> & R) const211 void calcCompositeBodyInertiasInward
212 (const SBTreePositionCache& pc,
213 Array_<SpatialInertia,MobilizedBodyIndex>& R) const override {
214 toB(R) = getMk_G(pc);
215 }
216
multiplyBySystemJacobian(const SBTreePositionCache & pc,const Real * v,SpatialVec * Jv) const217 void multiplyBySystemJacobian(
218 const SBTreePositionCache& pc,
219 const Real* v,
220 SpatialVec* Jv) const override {
221 const Vec3& in = Vec3::getAs(&v[uIndex]);
222 SpatialVec& out = Jv[nodeNum];
223 out = ~getPhi(pc) * Jv[parent->getNodeNum()];
224 out[1] += in;
225 }
226
multiplyBySystemJacobianTranspose(const SBTreePositionCache & pc,SpatialVec * zTmp,const SpatialVec * X,Real * JtX) const227 void multiplyBySystemJacobianTranspose(
228 const SBTreePositionCache& pc,
229 SpatialVec* zTmp,
230 const SpatialVec* X,
231 Real* JtX) const override {
232 const SpatialVec& in = X[getNodeNum()];
233 Vec3& out = Vec3::updAs(&JtX[getUIndex()]);
234 SpatialVec& z = zTmp[getNodeNum()];
235 z = in;
236 out = z[1];
237 }
238
calcEquivalentJointForces(const SBTreePositionCache & pc,const SBTreeVelocityCache & vc,const SpatialVec * bodyForces,SpatialVec * allZ,Real * jointForces) const239 void calcEquivalentJointForces(
240 const SBTreePositionCache& pc,
241 const SBTreeVelocityCache& vc,
242 const SpatialVec* bodyForces,
243 SpatialVec* allZ,
244 Real* jointForces) const override {
245 const SpatialVec& myBodyForce = bodyForces[nodeNum];
246 SpatialVec& z = allZ[nodeNum];
247 Vec3& eps = Vec3::updAs(&jointForces[uIndex]);
248 z = myBodyForce;
249 eps = z[1];
250 }
251
calcUDotPass1Inward(const SBInstanceCache & ic,const SBTreePositionCache &,const SBArticulatedBodyInertiaCache &,const SBArticulatedBodyVelocityCache &,const Real * jointForces,const SpatialVec * bodyForces,const Real * allUDot,SpatialVec * allZ,SpatialVec * allZPlus,Real * allEpsilon) const252 void calcUDotPass1Inward(
253 const SBInstanceCache& ic,
254 const SBTreePositionCache&,
255 const SBArticulatedBodyInertiaCache&,
256 const SBArticulatedBodyVelocityCache&,
257 const Real* jointForces,
258 const SpatialVec* bodyForces,
259 const Real* allUDot,
260 SpatialVec* allZ,
261 SpatialVec* allZPlus,
262 Real* allEpsilon) const override
263 {
264 const Vec3& f = Vec3::getAs(&jointForces[uIndex]);
265 const SpatialVec& F = bodyForces[nodeNum];
266 SpatialVec& z = allZ[nodeNum];
267 SpatialVec& zPlus = allZPlus[nodeNum];
268 Vec3& eps = Vec3::updAs(&allEpsilon[uIndex]);
269
270 const bool isPrescribed = isUDotKnown(ic);
271
272 z = -F;
273
274 if (isPrescribed && !isUDotKnownToBeZero(ic)) {
275 const Vec3& udot = Vec3::getAs(&allUDot[uIndex]);
276 z[1] += getMass()*udot; // == P*H*udot
277 }
278
279 // Lone particle has no children.
280
281 eps = f - z[1];
282
283 zPlus = z;
284 if (!isPrescribed)
285 zPlus[1] += eps;
286 }
287
calcUDotPass2Outward(const SBInstanceCache & ic,const SBTreePositionCache & pc,const SBArticulatedBodyInertiaCache & abc,const SBTreeVelocityCache & vc,const SBDynamicsCache & dc,const Real * allEpsilon,SpatialVec * allA_GB,Real * allUDot,Real * allTau) const288 void calcUDotPass2Outward(
289 const SBInstanceCache& ic,
290 const SBTreePositionCache& pc,
291 const SBArticulatedBodyInertiaCache& abc,
292 const SBTreeVelocityCache& vc,
293 const SBDynamicsCache& dc,
294 const Real* allEpsilon,
295 SpatialVec* allA_GB,
296 Real* allUDot,
297 Real* allTau) const override {
298 const Vec3& eps = Vec3::getAs(&allEpsilon[uIndex]);
299 SpatialVec& A_GB = allA_GB[nodeNum];
300 Vec3& udot = Vec3::updAs(&allUDot[uIndex]);
301
302 const bool isPrescribed = isUDotKnown(ic);
303
304 if (isPrescribed) {
305 const PresForcePoolIndex tauIx =
306 ic.getMobodInstanceInfo(nodeNum).firstPresForce;
307 assert(tauIx.isValid());
308 Vec3& tau = Vec3::updAs(&allTau[tauIx]);
309 tau = eps; // our sign convention
310 } else
311 udot = eps/getMass();
312
313 A_GB = SpatialVec(Vec3(0), udot);
314 }
315
316 // Note that we're not setting z temporaries here; you can't count on that as
317 // a side effect the M^-1*f kernel.
multiplyByMInvPass1Inward(const SBInstanceCache & ic,const SBTreePositionCache & pc,const SBArticulatedBodyInertiaCache & abc,const Real * jointForces,SpatialVec * allZ,SpatialVec * allZPlus,Real * allEpsilon) const318 void multiplyByMInvPass1Inward(
319 const SBInstanceCache& ic,
320 const SBTreePositionCache& pc,
321 const SBArticulatedBodyInertiaCache& abc,
322 const Real* jointForces,
323 SpatialVec* allZ,
324 SpatialVec* allZPlus,
325 Real* allEpsilon) const override
326 {
327 if (isUDotKnown(ic)) // prescribed
328 return;
329
330 // We promised not to look at f if it is part of f_p (prescribed).
331 const Vec3& f = Vec3::getAs(&jointForces[uIndex]);
332 Vec3& eps = Vec3::updAs(&allEpsilon[uIndex]);
333
334 eps = f;
335 }
336
337 // Outward pass must set A_GB properly so it can be propagated
338 // to children.
multiplyByMInvPass2Outward(const SBInstanceCache & ic,const SBTreePositionCache & pc,const SBArticulatedBodyInertiaCache & abc,const Real * allEpsilon,SpatialVec * allA_GB,Real * allUDot) const339 void multiplyByMInvPass2Outward(
340 const SBInstanceCache& ic,
341 const SBTreePositionCache& pc,
342 const SBArticulatedBodyInertiaCache& abc,
343 const Real* allEpsilon,
344 SpatialVec* allA_GB,
345 Real* allUDot) const override
346 {
347 const bool isPrescribed = isUDotKnown(ic);
348 const Vec3& eps = Vec3::getAs(&allEpsilon[uIndex]);
349 SpatialVec& A_GB = allA_GB[nodeNum];
350 Vec3& udot = Vec3::updAs(&allUDot[uIndex]);
351
352 if (isPrescribed) {
353 udot = 0;
354 A_GB = SpatialVec(Vec3(0), Vec3(0));
355 } else {
356 udot = eps/getMass();
357 A_GB = SpatialVec(Vec3(0), udot);
358 }
359 }
360
361 // Also serves as pass 1 for inverse dynamics.
calcBodyAccelerationsFromUdotOutward(const SBTreePositionCache & pc,const SBTreeVelocityCache & vc,const Real * allUDot,SpatialVec * allA_GB) const362 void calcBodyAccelerationsFromUdotOutward(
363 const SBTreePositionCache& pc,
364 const SBTreeVelocityCache& vc,
365 const Real* allUDot,
366 SpatialVec* allA_GB) const override {
367 const Vec3& udot = Vec3::getAs(&allUDot[uIndex]);
368 SpatialVec& A_GB = allA_GB[nodeNum];
369 A_GB = SpatialVec(Vec3(0), udot);
370 }
calcInverseDynamicsPass2Inward(const SBTreePositionCache & pc,const SBTreeVelocityCache & vc,const SpatialVec * allA_GB,const Real * jointForces,const SpatialVec * bodyForces,SpatialVec * allF,Real * allTau) const371 void calcInverseDynamicsPass2Inward(
372 const SBTreePositionCache& pc,
373 const SBTreeVelocityCache& vc,
374 const SpatialVec* allA_GB,
375 const Real* jointForces,
376 const SpatialVec* bodyForces,
377 SpatialVec* allF,
378 Real* allTau) const override {
379 const Vec3& myJointForce = Vec3::getAs(&jointForces[uIndex]);
380 const SpatialVec& myBodyForce = bodyForces[nodeNum];
381 const SpatialVec& A_GB = allA_GB[nodeNum];
382 SpatialVec& F = allF[nodeNum];
383 Vec3& tau = Vec3::updAs(&allTau[uIndex]);
384 F = getMk_G(pc)*A_GB - myBodyForce;
385 tau = F[1] - myJointForce;
386 }
387
multiplyByMPass1Outward(const SBTreePositionCache & pc,const Real * allUDot,SpatialVec * allA_GB) const388 void multiplyByMPass1Outward(
389 const SBTreePositionCache& pc,
390 const Real* allUDot,
391 SpatialVec* allA_GB) const override {
392 const Vec3& udot = Vec3::getAs(&allUDot[uIndex]);
393 SpatialVec& A_GB = allA_GB[nodeNum];
394 A_GB = SpatialVec(Vec3(0), udot);
395 }
multiplyByMPass2Inward(const SBTreePositionCache & pc,const SpatialVec * allA_GB,SpatialVec * allF,Real * allTau) const396 void multiplyByMPass2Inward(
397 const SBTreePositionCache& pc,
398 const SpatialVec* allA_GB,
399 SpatialVec* allF,
400 Real* allTau) const override {
401 const SpatialVec& A_GB = allA_GB[nodeNum];
402 SpatialVec& F = allF[nodeNum];
403 Vec3& tau = Vec3::updAs(&allTau[uIndex]);
404 F = getMk_G(pc)*A_GB;
405 tau = F[1];
406 }
407
getHCol(const SBTreePositionCache & pc,int j) const408 const SpatialVec& getHCol(const SBTreePositionCache& pc,
409 int j) const override {
410 Mat<2,3,Vec3> H = Mat<2,3,Vec3>::getAs(&pc.storageForH[2*uIndex]);
411 SpatialVec& col = H(j);
412 col = SpatialVec(Vec3(0), Vec3(0));
413 col[1][j] = 1;
414 return col;
415 }
416
getH_FMCol(const SBTreePositionCache & pc,int j) const417 const SpatialVec& getH_FMCol(const SBTreePositionCache& pc,
418 int j) const override {
419 Mat<2,3,Vec3> H = Mat<2,3,Vec3>::getAs(&pc.storageForH_FM[2*uIndex]);
420 SpatialVec& col = H(j);
421 col = SpatialVec(Vec3(0), Vec3(0));
422 col[1][j] = 1;
423 return col;
424 }
425
setQToFitTransformImpl(const SBStateDigest &,const Transform & X_F0M0,Vector & q) const426 void setQToFitTransformImpl(const SBStateDigest&, const Transform& X_F0M0,
427 Vector& q) const override {
428 Vec3::updAs(&q[qIndex]) = X_F0M0.p();
429 }
setQToFitRotationImpl(const SBStateDigest &,const Rotation & R_F0M0,Vector & q) const430 void setQToFitRotationImpl(const SBStateDigest&, const Rotation& R_F0M0,
431 Vector& q) const override {
432 }
setQToFitTranslationImpl(const SBStateDigest &,const Vec3 & p_F0M0,Vector & q) const433 void setQToFitTranslationImpl(const SBStateDigest&, const Vec3& p_F0M0,
434 Vector& q) const override {
435 Vec3::updAs(&q[qIndex]) = p_F0M0;
436 }
437
setUToFitVelocityImpl(const SBStateDigest &,const Vector & q,const SpatialVec & V_F0M0,Vector & u) const438 void setUToFitVelocityImpl(const SBStateDigest&, const Vector& q,
439 const SpatialVec& V_F0M0, Vector& u) const override {
440 Vec3::updAs(&u[uIndex]) = V_F0M0[1];
441 }
setUToFitAngularVelocityImpl(const SBStateDigest &,const Vector & q,const Vec3 & w_F0M0,Vector & u) const442 void setUToFitAngularVelocityImpl(const SBStateDigest&, const Vector& q,
443 const Vec3& w_F0M0, Vector& u) const override {
444 }
setUToFitLinearVelocityImpl(const SBStateDigest &,const Vector & q,const Vec3 & v_F0M0,Vector & u) const445 void setUToFitLinearVelocityImpl(const SBStateDigest&, const Vector& q,
446 const Vec3& v_F0M0, Vector& u) const override {
447 Vec3::updAs(&u[uIndex]) = v_F0M0;
448 }
449
450 };
451
createRigidBodyNode(UIndex & nextUSlot,USquaredIndex & nextUSqSlot,QIndex & nextQSlot) const452 RigidBodyNode* MobilizedBody::TranslationImpl::createRigidBodyNode(
453 UIndex& nextUSlot,
454 USquaredIndex& nextUSqSlot,
455 QIndex& nextQSlot) const {
456 if (!hasChildren && getMyParentMobilizedBodyIndex() == 0 && !isReversed() &&
457 getDefaultInboardFrame().p() == 0 && getDefaultInboardFrame().R() == Mat33(1) &&
458 getDefaultOutboardFrame().p() == 0 && getDefaultOutboardFrame().R() == Mat33(1)) {
459 // This satisfies all the requirements to use RBNodeLoneParticle.
460
461 return new RBNodeLoneParticle(getDefaultRigidBodyMassProperties(), nextUSlot,nextUSqSlot,nextQSlot);
462 }
463
464 // Use RBNodeTranslate for the general case.
465
466 bool noX_MB = (getDefaultOutboardFrame().p() == 0 && getDefaultOutboardFrame().R() == Mat33(1));
467 bool noR_PF = (getDefaultInboardFrame().R() == Mat33(1));
468 if (noX_MB) {
469 if (noR_PF)
470 return new RBNodeTranslate<true, true> (
471 getDefaultRigidBodyMassProperties(),
472 getDefaultInboardFrame(),getDefaultOutboardFrame(),
473 isReversed(),
474 nextUSlot,nextUSqSlot,nextQSlot);
475 else
476 return new RBNodeTranslate<true, false> (
477 getDefaultRigidBodyMassProperties(),
478 getDefaultInboardFrame(),getDefaultOutboardFrame(),
479 isReversed(),
480 nextUSlot,nextUSqSlot,nextQSlot);
481 }
482 else {
483 if (noR_PF)
484 return new RBNodeTranslate<false, true> (
485 getDefaultRigidBodyMassProperties(),
486 getDefaultInboardFrame(),getDefaultOutboardFrame(),
487 isReversed(),
488 nextUSlot,nextUSqSlot,nextQSlot);
489 else
490 return new RBNodeTranslate<false, false> (
491 getDefaultRigidBodyMassProperties(),
492 getDefaultInboardFrame(),getDefaultOutboardFrame(),
493 isReversed(),
494 nextUSlot,nextUSqSlot,nextQSlot);
495 }
496 }
497