1 #ifndef SimTK_SIMBODY_CONSTRAINT_IMPL_H_
2 #define SimTK_SIMBODY_CONSTRAINT_IMPL_H_
3 
4 /* -------------------------------------------------------------------------- *
5  *                               Simbody(tm)                                  *
6  * -------------------------------------------------------------------------- *
7  * This is part of the SimTK biosimulation toolkit originating from           *
8  * Simbios, the NIH National Center for Physics-Based Simulation of           *
9  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
10  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
11  *                                                                            *
12  * Portions copyright (c) 2007-14 Stanford University and the Authors.        *
13  * Authors: Michael Sherman                                                   *
14  * Contributors:                                                              *
15  *                                                                            *
16  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
17  * not use this file except in compliance with the License. You may obtain a  *
18  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
19  *                                                                            *
20  * Unless required by applicable law or agreed to in writing, software        *
21  * distributed under the License is distributed on an "AS IS" BASIS,          *
22  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
23  * See the License for the specific language governing permissions and        *
24  * limitations under the License.                                             *
25  * -------------------------------------------------------------------------- */
26 
27 /**@file
28 Private implementation of Constraint and its included subclasses which
29 represent the built-in constraint types. **/
30 
31 #include "SimTKmath.h"
32 #include "simbody/internal/common.h"
33 #include "simbody/internal/Constraint.h"
34 #include "simbody/internal/SimbodyMatterSubsystem.h"
35 #include "simbody/internal/SimbodyMatterSubtree.h"
36 
37 #include "SimbodyTreeState.h"
38 
39 #include <map>
40 #include <utility>  // std::pair
41 #include <iostream>
42 using std::cout; using std::endl;
43 
44 class SimbodyMatterSubsystemRep;
45 
46 namespace SimTK {
47 
48 class SimbodyMatterSubsystem;
49 class SimbodyMatterSubtree;
50 class MobilizedBody;
51 
52 //==============================================================================
53 //                           CONSTRAINT IMPL
54 //==============================================================================
55 // This is what a Constraint handle points to.
56 class ConstraintImpl : public PIMPLImplementation<Constraint, ConstraintImpl> {
57 public:
58 
ConstraintImpl()59 ConstraintImpl()
60     : myMatterSubsystemRep(0),
61     defaultMp(0), defaultMv(0), defaultMa(0), defaultDisabled(false),
62     constraintIsConditional(false), myAncestorBodyIsNotGround(false)
63 {
64 }
~ConstraintImpl()65 virtual ~ConstraintImpl() { }
66 virtual ConstraintImpl* clone() const = 0;
67 
ConstraintImpl(int mp,int mv,int ma)68 ConstraintImpl(int mp, int mv, int ma)
69     : myMatterSubsystemRep(0),
70     defaultMp(mp), defaultMv(mv), defaultMa(ma), defaultDisabled(false),
71     constraintIsConditional(false), myAncestorBodyIsNotGround(false)
72 {
73 }
74 
setDefaultNumConstraintEquations(int mp,int mv,int ma)75 void setDefaultNumConstraintEquations(int mp, int mv, int ma) {
76     assert(mp >= 0 && mv >= 0 && ma >= 0);
77     invalidateTopologyCache();
78     defaultMp = mp;
79     defaultMv = mv;
80     defaultMa = ma;
81 }
82 
getDefaultNumConstraintEquations(int & mp,int & mv,int & ma)83 void getDefaultNumConstraintEquations(int& mp, int& mv, int& ma) const {
84     mp = defaultMp;
85     mv = defaultMv;
86     ma = defaultMa;
87 }
88 
setDisabledByDefault(bool shouldBeDisabled)89 void setDisabledByDefault(bool shouldBeDisabled) {
90     invalidateTopologyCache();
91     defaultDisabled = shouldBeDisabled;
92 }
93 
isDisabledByDefault()94 bool isDisabledByDefault() const {
95     return defaultDisabled;
96 }
97 
98 void setDisabled(State& s, bool shouldBeDisabled) const ;
99 bool isDisabled(const State& s) const;
100 
setIsConditional(bool isConditional)101 void setIsConditional(bool isConditional) {
102     invalidateTopologyCache();
103     constraintIsConditional = isConditional;
104 }
105 
isConditional()106 bool isConditional() const {return constraintIsConditional;}
107 
108 typedef std::map<MobilizedBodyIndex,ConstrainedBodyIndex>
109     MobilizedBody2ConstrainedBodyMap;
110 typedef std::map<MobilizedBodyIndex,ConstrainedMobilizerIndex>
111     MobilizedBody2ConstrainedMobilizerMap;
112 
113 // Call this during construction phase to add a body to the topological
114 // structure of this Constraint. This body's mobilizer's mobilities are *not*
115 // part of the constraint; mobilizers must be added separately. If this
116 // mobilized body has been seen as a constrained body before we'll return the
117 // same index as first assigned to it.
118 ConstrainedBodyIndex addConstrainedBody(const MobilizedBody&);
119 
120 // Call this during construction phase to add a mobilizer to the topological
121 // structure of this Constraint. All the coordinates q and mobilities u for
122 // this mobilizer are added as "constrainable". We don't know how many
123 // coordinates and speeds there are until Stage::Model. If this
124 // mobilized body has been seen as a constrained mobilizer before we'll return
125 // the same index as first assigned to it.
126 ConstrainedMobilizerIndex addConstrainedMobilizer(const MobilizedBody&);
127 
getMobilizedBodyIndexOfConstrainedBody(ConstrainedBodyIndex c)128 MobilizedBodyIndex getMobilizedBodyIndexOfConstrainedBody
129    (ConstrainedBodyIndex c) const {
130     assert(0 <= c && c < (int)myConstrainedBodies.size());
131     return myConstrainedBodies[c];
132 }
getMobilizedBodyIndexOfConstrainedMobilizer(ConstrainedMobilizerIndex c)133 MobilizedBodyIndex getMobilizedBodyIndexOfConstrainedMobilizer
134    (ConstrainedMobilizerIndex c) const {
135     assert(0 <= c && c < (int)myConstrainedMobilizers.size());
136     return myConstrainedMobilizers[c];
137 }
138 
139 //TODO: Constraint-local State allocation
140 //int allocateDiscreteVariable(State& s, Stage g, AbstractValue* v) const;
141 //int allocateCacheEntry(State& s, Stage g, AbstractValue* v) const;
142 
143 QIndex getQIndexOfConstrainedQ(const State& s, ConstrainedQIndex cqx) const;
144 UIndex getUIndexOfConstrainedU(const State& s, ConstrainedUIndex cqx) const;
145 
146 void convertQForcesToUForces(const State&                          s,
147                              const Array_<Real,ConstrainedQIndex>& qForces,
148                              Array_<Real,ConstrainedUIndex>&       uForces) const;
149 
150 // Given a position-stage state and an array of body velocities for all
151 // bodies (relative to Ground), select the short list of constrained bodies
152 // for this Constraint and ensure that their velocities are relative to
153 // the Ancestor body.
154 void convertBodyVelocityToConstrainedBodyVelocity
155    (const State&                                    state,
156     const Array_<SpatialVec, MobilizedBodyIndex>&   V_GB,
157     Array_<SpatialVec, ConstrainedBodyIndex>&       V_AB) const;
158 
159 // Given a velocity-stage state and an array of body accelerations for all
160 // bodies (relative to Ground), select the short list of constrained bodies
161 // for this Constraint and ensure that their accelerations are relative to
162 // the Ancestor body.
163 void convertBodyAccelToConstrainedBodyAccel
164    (const State&                                    state,
165     const Array_<SpatialVec, MobilizedBodyIndex>&   A_GB,
166     Array_<SpatialVec, ConstrainedBodyIndex>&       A_AB) const;
167 
168 void realizeTopology(State&)       const; // eventually calls realizeTopologyVirtual()
169 void realizeModel   (State&)       const; // eventually calls realizeModelVirtual()
170 void realizeInstance(const State&) const; // eventually calls realizeInstanceVirtual()
171 
172 // These are called in loops over all the Constraints from the
173 // SimbodyMatterSubsystem realize() methods, which will have already
174 // deconstructed the State into an SBStateDigest object.
175 void realizeTime    (const SBStateDigest&) const; // eventually calls realizeTimeVirtual()
176 void realizePosition(const SBStateDigest&) const; // eventually calls realizePositionVirtual()
177 void realizeVelocity(const SBStateDigest&) const; // eventually calls realizeVelocityVirtual()
178 void realizeDynamics(const SBStateDigest&) const; // eventually calls realizeDynamicsVirtual()
179 void realizeAcceleration
180                     (const SBStateDigest&) const; // eventually calls realizeAccelerationVirtual()
181 void realizeReport  (const State&) const; // eventually calls realizeReportVirtual()
182 
183 // Given a state realized to Position stage, extract the position constraint
184 // errors corresponding to this Constraint. The 'mp' argument is for sanity
185 // checking -- it is an error if that isn't an exact match for the current
186 // number of holonomic constraint equations generated by this Constraint. We
187 // expect that perr points to an array of at least mp elements that we can
188 // write on.
189 void getPositionErrors(const State& s, int mp, Real* perr) const;
190 
191 // Given a State realized to Velocity stage, extract the velocity constraint
192 // errors corresponding to this Constraint. This includes velocity constraints
193 // which were produced by differentiation of holonomic (position) constraints,
194 // and nonholonomic constraints which are introduced at the velocity level. The
195 // 'mpv' argument is for sanity checking -- it is an error if that isn't an
196 // exact match for the current number of holonomic+nonholonomic (mp+mv)
197 // constraint equations generated by this Constraint. We expect that pverr
198 // points to an array of at least mp+mv elements that we can write on.
199 void getVelocityErrors(const State& s, int mpv, Real* pverr) const;
200 
201 // Given a State realized to Acceleration stage, extract the accleration
202 // constraint errors corresponding to this Constraint. This includes
203 // acceleration constraints which were produced by twice differentiation of
204 // holonomic (position) constraints, and differentiation of nonholonomic
205 // (velocity) constraints, and acceleration-only constraints which are first
206 // introduced at the acceleration level. The 'mpva' argument is for sanity
207 // checking -- it is an error if that isn't an exact match for the current
208 // number of holonomic+nonholonomic+accelerationOnly (mp+mv+ma) constraint
209 // equations generated by this Constraint. We expect that pvaerr points to an
210 // array of at least mp+mv+ma elements that we can write on.
211 void getAccelerationErrors(const State& s, int mpva, Real* pvaerr) const;
212 
213 // Given a State realized to Acceleration stage, extract the constraint
214 // multipliers lambda corresponding to this constraint. This includes
215 // multipliers for all the holonomic, nonholonomic, and acceleration-only
216 // constraints (but not quaternion constraints which do not use multipliers).
217 // The 'mpva' argument is for sanity checking -- it is an error if that isn't
218 // an exact match for the current number (mp+mv+ma) of constraint equations
219 // generated by this Constraint. We expect that lambda points to an array of at
220 // least mp+mv+ma elements that we can write on.
221 void getMultipliers(const State& s, int mpva, Real* lambda) const;
222 
223 // Return a small, writable array directly referencing the segment of the longer
224 // passed-in array that belongs to this constraint. State must be realized
225 // through Instance stage.
226 ArrayView_<SpatialVec,ConstrainedBodyIndex>
227 updConstrainedBodyForces(const State&        state,
228                          Array_<SpatialVec>& allConsBodyForces) const;
229 // Same, but for mobility forces.
230 ArrayView_<Real,ConstrainedUIndex>
231 updConstrainedMobilityForces(const State&  state,
232                              Array_<Real>& allConsMobForces) const;
233 
234 // Return a const reference to our segment. Can use above methods efficiently
235 // since ArrayView is derived from ArrayViewConst; this just does a
236 // shallow copy to fill in the ArrayViewConst handle; no heap is involved.
237 ArrayViewConst_<SpatialVec,ConstrainedBodyIndex>
getConstrainedBodyForces(const State & state,const Array_<SpatialVec> & allConsBodyForces)238 getConstrainedBodyForces(const State&              state,
239                          const Array_<SpatialVec>& allConsBodyForces) const
240 {
241     return updConstrainedBodyForces
242        (state, const_cast<Array_<SpatialVec>&>(allConsBodyForces));
243 }
244 ArrayViewConst_<Real,ConstrainedUIndex>
getConstrainedMobilityForces(const State & state,const Array_<Real> & allConsMobForces)245 getConstrainedMobilityForces(const State&        state,
246                              const Array_<Real>& allConsMobForces) const
247 {
248     return updConstrainedMobilityForces
249        (state, const_cast<Array_<Real>&>(allConsMobForces));
250 }
251 
252 // Same as above but we use the matter subsystem's constrained acceleration
253 // cache as the source of the full-sized constrained body forces array,
254 // where the forces are expressed in Ground. That cache entry must have been
255 // realized which occurs during Acceleration stage computations.
256 ArrayViewConst_<SpatialVec,ConstrainedBodyIndex>
getConstrainedBodyForcesInGFromState(const State & state)257 getConstrainedBodyForcesInGFromState(const State& state) const
258 {
259     const SBConstrainedAccelerationCache& cac =
260         getConstrainedAccelerationCache(state);
261     return getConstrainedBodyForces(state, cac.constrainedBodyForcesInG);
262 }
263 
264 ArrayView_<SpatialVec,ConstrainedBodyIndex>
updConstrainedBodyForcesInGFromState(const State & state)265 updConstrainedBodyForcesInGFromState(const State& state) const
266 {
267     SBConstrainedAccelerationCache& cac =
268         updConstrainedAccelerationCache(state);
269     return updConstrainedBodyForces(state, cac.constrainedBodyForcesInG);
270 }
271 
272 ArrayViewConst_<Real,ConstrainedUIndex>
getConstrainedMobilityForcesFromState(const State & state)273 getConstrainedMobilityForcesFromState(const State& state) const
274 {
275     const SBConstrainedAccelerationCache& cac =
276         getConstrainedAccelerationCache(state);
277     return getConstrainedMobilityForces(state, cac.constraintMobilityForces);
278 }
279 
280 ArrayView_<Real,ConstrainedUIndex>
updConstrainedMobilityForcesFromState(const State & state)281 updConstrainedMobilityForcesFromState(const State& state) const
282 {
283     SBConstrainedAccelerationCache& cac =
284         updConstrainedAccelerationCache(state);
285     return getConstrainedMobilityForces(state, cac.constraintMobilityForces);
286 }
287 
288 // Given a State and a set of m multipliers lambda,
289 // calculate in O(m) time the constraint forces (body forces and torques and
290 // u-space mobility forces) which would be generated by those multipliers. You can
291 // restrict this to P,V,A subsets setting mp, mv, or ma to zero; in any case
292 // m = mp+mv+ma and any non-zero segments must match the corresponding number
293 // of constraint equations of that type.
294 //
295 // The State must be realized to at least Position stage, and if you ask for
296 // forces from holonomic (mv>0) or acceleration-only (ma>0) constraints then
297 // the State will have to be realized to Velocity stage if the corresponding
298 // constraint equations are velocity dependent.
calcConstraintForcesFromMultipliers(const State & s,const Array_<Real> & lambdap,const Array_<Real> & lambdav,const Array_<Real> & lambdaa,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedUIndex> & mobilityForces)299 void calcConstraintForcesFromMultipliers
300    (const State& s,
301     const Array_<Real>&                      lambdap, // 0 or mp of these
302     const Array_<Real>&                      lambdav, // 0 or mv of these
303     const Array_<Real>&                      lambdaa, // 0 or ma of these
304     Array_<SpatialVec,ConstrainedBodyIndex>& bodyForcesInA,
305     Array_<Real,      ConstrainedUIndex>&    mobilityForces) const
306 {
307     int actual_mp,actual_mv,actual_ma;
308     getNumConstraintEquationsInUse(s, actual_mp, actual_mv, actual_ma);
309 
310     bodyForcesInA.resize(getNumConstrainedBodies());
311     bodyForcesInA.fill(SpatialVec(Vec3(0), Vec3(0)));
312     mobilityForces.resize(getNumConstrainedU(s));
313     mobilityForces.fill(Real(0));
314 
315     if (lambdap.size()) {
316         assert(lambdap.size() == actual_mp);
317         const int ncq = getNumConstrainedQ(s);
318         const int ncu = getNumConstrainedU(s);
319         // State need only be realized to Position stage
320         Array_<Real, ConstrainedQIndex> qForces(ncq, Real(0));
321         Array_<Real, ConstrainedUIndex> uForces(ncu);
322         addInPositionConstraintForces(s, lambdap,
323                                       bodyForcesInA, qForces);
324         convertQForcesToUForces(s, qForces, uForces);
325         for (ConstrainedUIndex cux(0); cux < ncu; ++cux)
326             mobilityForces[cux] += uForces[cux];
327     }
328     if (lambdav.size()) {
329         assert(lambdav.size() == actual_mv);
330         // State may need to be realized to Velocity stage
331         addInVelocityConstraintForces(s, lambdav,
332                                       bodyForcesInA, mobilityForces);
333     }
334     if (lambdaa.size()) {
335         assert(lambdaa.size() == actual_ma);
336         // State may need to be realized to Velocity stage
337         addInAccelerationConstraintForces(s, lambdaa,
338                                           bodyForcesInA, mobilityForces);
339     }
340 }
341 
342 // Given a State realized to Position stage, and a set of spatial forces applied
343 // to the constrained bodies and u-space generalized forces applied to the
344 // constrained mobilities, convert these to an equivalent set
345 // of n generalized forces applied at each of the participating mobilities, in
346 // O(n) time.
347 // TODO
convertConstraintForcesToGeneralizedForces(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,const Array_<Real,ConstrainedUIndex> & mobilityForces,Vector & generalizedForces)348 void convertConstraintForcesToGeneralizedForces(const State& s,
349     const Array_<SpatialVec,ConstrainedBodyIndex>& bodyForcesInA,
350     const Array_<Real,      ConstrainedUIndex>&    mobilityForces,
351     Vector& generalizedForces) const
352 {
353     // TODO
354     assert(!"convertConstraintForcesToGeneralizedForces: not implemented yet");
355 }
356 
357 // Calculate f = ~G*lambda in O(n+m) time. ~G=[~P ~V ~A] and you can work with
358 // any subblock or combination by setting some of mp,mv,ma to zero. If nonzero
359 // they have to match the actual number of holonomic, nonholonomic, and
360 // acceleration-only constraints. Vector lambda (typically Lagrange multipliers
361 // but not necessarily) is segmented lambda=[mp|mv|ma] where some of the
362 // segments can be empty.
calcGTransposeLambda(const State & s,const Array_<Real> & lambdap,const Array_<Real> & lambdav,const Array_<Real> & lambdaa,Vector & f)363 void calcGTransposeLambda
364    (const State& s,
365     const Array_<Real>&                      lambdap, // 0 or mp of these
366     const Array_<Real>&                      lambdav, // 0 or mv of these
367     const Array_<Real>&                      lambdaa, // 0 or ma of these
368     Vector&                                  f) const
369 {
370     Array_<SpatialVec,ConstrainedBodyIndex> bodyForcesInA;
371     Array_<Real,      ConstrainedUIndex>    mobilityForces;
372 
373     calcConstraintForcesFromMultipliers
374        (s, lambdap, lambdav, lambdaa, bodyForcesInA, mobilityForces);
375     convertConstraintForcesToGeneralizedForces
376        (s, bodyForcesInA, mobilityForces, f);
377 }
378 
379 // Find the indicated cache in the passed-in State. The "get" methods require
380 // that the cache entry has already been marked valid.
381 
382 const SBModelCache&             getModelCache(const State&) const;
383 const SBInstanceCache&          getInstanceCache(const State&) const;
384 const SBTreePositionCache&      getTreePositionCache(const State&) const;
385 const SBTreeVelocityCache&      getTreeVelocityCache(const State&) const;
386 const SBTreeAccelerationCache&  getTreeAccelerationCache(const State&) const;
387 const SBConstrainedAccelerationCache&
388     getConstrainedAccelerationCache(const State& s) const;
389 SBConstrainedAccelerationCache&
390     updConstrainedAccelerationCache(const State& s) const;
391 
392     // Methods for use with ConstrainedMobilizers.
393 
394 Real getOneQFromState
395    (const State&, ConstrainedMobilizerIndex, MobilizerQIndex) const;
396 Real getOneQDotFromState
397    (const State&, ConstrainedMobilizerIndex, MobilizerQIndex) const;
398 Real getOneQDotDotFromState
399    (const State&, ConstrainedMobilizerIndex, MobilizerQIndex) const;
400 
401 Real getOneUFromState
402    (const State&, ConstrainedMobilizerIndex, MobilizerUIndex) const;
403 Real getOneUDotFromState
404    (const State&, ConstrainedMobilizerIndex, MobilizerUIndex) const;
405 
406 // Analogous methods for use when the generalized coordinate has been provided
407 // as an operand. The state is still necessary for modeling information.
getOneQ(const State & s,const Array_<Real,ConstrainedQIndex> & cq,ConstrainedMobilizerIndex M,MobilizerQIndex whichQ)408 Real getOneQ(const State& s,
409              const Array_<Real,ConstrainedQIndex>&  cq,
410              ConstrainedMobilizerIndex              M,
411              MobilizerQIndex                        whichQ) const
412 {
413     assert(cq.size() == getNumConstrainedQ(s));
414     assert(0 <= whichQ && whichQ < getNumConstrainedQ(s, M));
415     return cq[getConstrainedQIndex(s,M,whichQ)];
416 }
getOneQDot(const State & s,const Array_<Real,ConstrainedQIndex> & cqdot,ConstrainedMobilizerIndex M,MobilizerQIndex whichQ)417 Real getOneQDot(const State& s,
418                 const Array_<Real,ConstrainedQIndex>&  cqdot,
419                 ConstrainedMobilizerIndex              M,
420                 MobilizerQIndex                        whichQ) const
421 {
422     assert(cqdot.size() == getNumConstrainedQ(s));
423     assert(0 <= whichQ && whichQ < getNumConstrainedQ(s, M));
424     return cqdot[getConstrainedQIndex(s,M,whichQ)];
425 }
getOneQDotDot(const State & s,const Array_<Real,ConstrainedQIndex> & cqdotdot,ConstrainedMobilizerIndex M,MobilizerQIndex whichQ)426 Real getOneQDotDot(const State& s,
427                    const Array_<Real,ConstrainedQIndex>&  cqdotdot,
428                    ConstrainedMobilizerIndex              M,
429                    MobilizerQIndex                        whichQ) const
430 {
431     assert(cqdotdot.size() == getNumConstrainedQ(s));
432     assert(0 <= whichQ && whichQ < getNumConstrainedQ(s, M));
433     return cqdotdot[getConstrainedQIndex(s,M,whichQ)];
434 }
435 
getOneU(const State & s,const Array_<Real,ConstrainedUIndex> & cu,ConstrainedMobilizerIndex M,MobilizerUIndex whichU)436 Real getOneU(const State& s,
437              const Array_<Real,ConstrainedUIndex>&  cu,
438              ConstrainedMobilizerIndex              M,
439              MobilizerUIndex                        whichU) const
440 {
441     assert(cu.size() == getNumConstrainedU(s));
442     assert(0 <= whichU && whichU < getNumConstrainedU(s, M));
443     return cu[getConstrainedUIndex(s,M,whichU)];
444 }
445 
getOneUDot(const State & s,const Array_<Real,ConstrainedUIndex> & cudot,ConstrainedMobilizerIndex M,MobilizerUIndex whichU)446 Real getOneUDot(const State& s,
447                 const Array_<Real,ConstrainedUIndex>&  cudot,
448                 ConstrainedMobilizerIndex              M,
449                 MobilizerUIndex                        whichU) const
450 {
451     assert(cudot.size() == getNumConstrainedU(s));
452     assert(0 <= whichU && whichU < getNumConstrainedU(s, M));
453     return cudot[getConstrainedUIndex(s,M,whichU)];
454 }
455 
456 // Apply a u-space (mobility) generalized force fu to a particular mobility of
457 // the given constrained mobilizer, adding it in to the appropriate slot of the
458 // mobilityForces vector which is of length numConstrainedU for this Constraint.
addInOneMobilityForce(const State & s,ConstrainedMobilizerIndex cmx,MobilizerUIndex whichU,Real fu,Array_<Real,ConstrainedUIndex> & mobilityForces)459 void addInOneMobilityForce
460    (const State&                        s,
461     ConstrainedMobilizerIndex           cmx,
462     MobilizerUIndex                     whichU,
463     Real                                fu,
464     Array_<Real,ConstrainedUIndex>&     mobilityForces) const
465 {
466     assert(mobilityForces.size() == getNumConstrainedU(s));
467     assert(0 <= whichU && whichU < getNumConstrainedU(s, cmx));
468     mobilityForces[getConstrainedUIndex(s,cmx,whichU)] += fu;
469 }
470 
471 // Apply a q-space generalized force fq to a particular generalized coordinate q
472 // of the given constrained mobilizer, adding it in to the appropriate slot of
473 // the qForces vector which is of length numConstrainedQ for this Constraint.
addInOneQForce(const State & s,ConstrainedMobilizerIndex cmx,MobilizerQIndex whichQ,Real fq,Array_<Real,ConstrainedQIndex> & qForces)474 void addInOneQForce
475    (const State&                        s,
476     ConstrainedMobilizerIndex           cmx,
477     MobilizerQIndex                     whichQ,
478     Real                                fq,
479     Array_<Real,ConstrainedQIndex>&     qForces) const
480 {
481     assert(qForces.size() == getNumConstrainedQ(s));
482     assert(0 <= whichQ && whichQ < getNumConstrainedQ(s, cmx));
483     qForces[getConstrainedQIndex(s,cmx,whichQ)] += fq;
484 }
485 
486     // Methods for use with ConstrainedBodies.
487 
488 // These are used to retrieve the indicated values from the State cache, with all values
489 // measured and expressed in the Ancestor (A) frame.
490 const Transform&  getBodyTransformFromState
491    (const State& s, ConstrainedBodyIndex B) const;      // X_AB
492 const SpatialVec& getBodyVelocityFromState
493    (const State& s, ConstrainedBodyIndex B) const;      // V_AB
494 
495 // Extract just the rotational quantities from the spatial quantities above.
getBodyRotationFromState(const State & s,ConstrainedBodyIndex B)496 const Rotation& getBodyRotationFromState
497    (const State& s, ConstrainedBodyIndex B)     const   // R_AB
498     {return getBodyTransformFromState(s,B).R();}
getBodyAngularVelocityFromState(const State & s,ConstrainedBodyIndex B)499 const Vec3& getBodyAngularVelocityFromState
500    (const State& s, ConstrainedBodyIndex B)     const   // w_AB
501     {return getBodyVelocityFromState(s,B)[0];}
502 
503 // Extract just the translational (linear) quantities from the spatial quantities above.
getBodyOriginLocationFromState(const State & s,ConstrainedBodyIndex B)504 const Vec3& getBodyOriginLocationFromState
505    (const State& s, ConstrainedBodyIndex B)     const   // p_AB
506     {return getBodyTransformFromState(s,B).p();}
getBodyOriginVelocityFromState(const State & s,ConstrainedBodyIndex B)507 const Vec3& getBodyOriginVelocityFromState
508    (const State& s, ConstrainedBodyIndex B)     const   // v_AB
509     {return getBodyVelocityFromState(s,B)[1];}
510 
511 // These are analogous methods for when you've been given X_AB, V_AB, or A_AB
512 // explicitly as an operand. These are all inline and trivial.
getBodyTransform(const Array_<Transform,ConstrainedBodyIndex> & allX_AB,ConstrainedBodyIndex B)513 const Transform& getBodyTransform
514    (const Array_<Transform,ConstrainedBodyIndex>&   allX_AB,
515     ConstrainedBodyIndex                            B) const
516 {   return allX_AB[B]; }
517 
getBodyVelocity(const Array_<SpatialVec,ConstrainedBodyIndex> & allV_AB,ConstrainedBodyIndex B)518 const SpatialVec& getBodyVelocity
519    (const Array_<SpatialVec,ConstrainedBodyIndex>&  allV_AB,
520     ConstrainedBodyIndex                            B) const
521 {   return allV_AB[B]; }
522 
getBodyAcceleration(const Array_<SpatialVec,ConstrainedBodyIndex> & allA_AB,ConstrainedBodyIndex B)523 const SpatialVec& getBodyAcceleration
524    (const Array_<SpatialVec,ConstrainedBodyIndex>&  allA_AB,
525     ConstrainedBodyIndex                            B) const
526 {   return allA_AB[B]; }
527 
getBodyRotation(const Array_<Transform,ConstrainedBodyIndex> & allX_AB,ConstrainedBodyIndex B)528 const Rotation& getBodyRotation
529    (const Array_<Transform,ConstrainedBodyIndex>&   allX_AB,
530     ConstrainedBodyIndex                            B) const
531 {   return allX_AB[B].R(); }
532 
getBodyAngularVelocity(const Array_<SpatialVec,ConstrainedBodyIndex> & allV_AB,ConstrainedBodyIndex B)533 const Vec3& getBodyAngularVelocity
534    (const Array_<SpatialVec,ConstrainedBodyIndex>&  allV_AB,
535     ConstrainedBodyIndex                            B) const
536 {   return allV_AB[B][0]; }
537 
getBodyAngularAcceleration(const Array_<SpatialVec,ConstrainedBodyIndex> & allA_AB,ConstrainedBodyIndex B)538 const Vec3& getBodyAngularAcceleration
539    (const Array_<SpatialVec,ConstrainedBodyIndex>&  allA_AB,
540     ConstrainedBodyIndex                            B) const
541 {   return allA_AB[B][0]; }
542 
getBodyOriginLocation(const Array_<Transform,ConstrainedBodyIndex> & allX_AB,ConstrainedBodyIndex B)543 const Vec3& getBodyOriginLocation
544    (const Array_<Transform,ConstrainedBodyIndex>&   allX_AB,
545     ConstrainedBodyIndex                            B) const
546 {   return allX_AB[B].p(); }
547 
getBodyOriginVelocity(const Array_<SpatialVec,ConstrainedBodyIndex> & allV_AB,ConstrainedBodyIndex B)548 const Vec3& getBodyOriginVelocity
549    (const Array_<SpatialVec,ConstrainedBodyIndex>&  allV_AB,
550     ConstrainedBodyIndex                            B) const
551 {   return allV_AB[B][1]; }
552 
getBodyOriginAcceleration(const Array_<SpatialVec,ConstrainedBodyIndex> & allA_AB,ConstrainedBodyIndex B)553 const Vec3& getBodyOriginAcceleration
554    (const Array_<SpatialVec,ConstrainedBodyIndex>&  allA_AB,
555     ConstrainedBodyIndex                            B) const
556 {   return allA_AB[B][1]; }
557 
558 
559 // Given a station S on body B, specified by the vector p_BS from Bo to S
560 // expressed in B, find its location p_AS measured from Ao and expressed in the
561 // Ancestor's frame A. 18 flops.
findStationLocationFromState(const State & s,ConstrainedBodyIndex B,const Vec3 & p_BS)562 Vec3 findStationLocationFromState
563    (const State& s, ConstrainedBodyIndex B, const Vec3& p_BS) const {
564     return getBodyTransformFromState(s,B) * p_BS; // re-measure and re-express
565 }
566 
567 // Same, but we're given the constrained body poses as an operand (18 flops).
findStationLocation(const Array_<Transform,ConstrainedBodyIndex> & allX_AB,ConstrainedBodyIndex B,const Vec3 & p_BS)568 Vec3 findStationLocation
569    (const Array_<Transform, ConstrainedBodyIndex>& allX_AB,
570     ConstrainedBodyIndex B, const Vec3& p_BS) const {
571     const Transform& X_AB = allX_AB[B];
572     return X_AB * p_BS; // re-measure and re-express (18 flops)
573 }
574 
575 // Given a station S on body B, find its velocity measured and expressed in the
576 // Ancestor's frame A. 27 flops.
findStationVelocityFromState(const State & s,ConstrainedBodyIndex B,const Vec3 & p_BS)577 Vec3 findStationVelocityFromState
578    (const State& s, ConstrainedBodyIndex B, const Vec3& p_BS) const {
579     // p_BS rexpressed in A but not shifted to Ao
580     const Vec3        p_BS_A = getBodyRotationFromState(s,B) * p_BS; // 15 flops
581     const SpatialVec& V_AB   = getBodyVelocityFromState(s,B);
582     return V_AB[1] + (V_AB[0] % p_BS_A);                             // 12 flops
583 }
584 
585 // Same, but only configuration comes from state; velocities are an operand.
findStationVelocity(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allV_AB,ConstrainedBodyIndex B,const Vec3 & p_BS)586 Vec3 findStationVelocity
587    (const State& s,
588     const Array_<SpatialVec, ConstrainedBodyIndex>& allV_AB,
589     ConstrainedBodyIndex B, const Vec3& p_BS) const
590 {
591     // p_BS rexpressed in A but not shifted to Ao
592     const Vec3        p_BS_A  = getBodyRotationFromState(s,B) * p_BS;
593     const SpatialVec& V_AB = allV_AB[B];
594     return V_AB[1] + (V_AB[0] % p_BS_A);
595 }
596 
597 // Combo method is cheaper. Location comes from state, velocities from operand.
598 // NOTE: you must provide the p_BS vector expressed (but not measured) in A.
599 // 15 flops.
findStationInALocationVelocity(const Transform & X_AB,const SpatialVec & V_AB,const Vec3 & p_BS_A,Vec3 & p_AS,Vec3 & v_AS)600 void findStationInALocationVelocity
601    (const Transform&    X_AB,
602     const SpatialVec&   V_AB,
603     const Vec3&         p_BS_A,
604     Vec3& p_AS, Vec3& v_AS) const
605 {
606     const Vec3& w_AB = V_AB[0]; const Vec3& v_AB = V_AB[1];
607     const Vec3 pdot_BS_A = w_AB % p_BS_A;   //  9 flops
608 
609     p_AS = X_AB.p() + p_BS_A;               //  3 flops
610     v_AS = v_AB + pdot_BS_A;                //  3 flops
611 }
612 
613 // Given a station P on body F, and a station Q on body B, report the
614 // relative position p_PQ_A and relative velocity v_PQ_A=v_FQ_A. Note that
615 // the velocity is measured in the F frame, but expressed in the common A
616 // frame. 78 flops
findRelativePositionVelocity(const Transform & X_AF,const SpatialVec & V_AF,const Vec3 & p_FP,const Transform & X_AB,const SpatialVec & V_AB,const Vec3 & p_BQ,Vec3 & p_PQ_A,Vec3 & v_FQ_A)617 void findRelativePositionVelocity
618    (const Transform&    X_AF,
619     const SpatialVec&   V_AF,
620     const Vec3&         p_FP,
621     const Transform&    X_AB,
622     const SpatialVec&   V_AB,
623     const Vec3&         p_BQ,
624     Vec3& p_PQ_A, Vec3& v_FQ_A) const
625 {
626     const Vec3& w_AF = V_AF[0];
627 
628     // Express the point vectors in the A frame, but still measuring from the
629     // body origins.
630     const Vec3 p_FP_A = X_AF.R() * p_FP; // 15 flops
631     const Vec3 p_BQ_A = X_AB.R() * p_BQ; // 15 flops
632 
633     Vec3 p_AP, v_AP;
634     findStationInALocationVelocity(X_AF, V_AF, p_FP_A, p_AP, v_AP);//15 flops
635 
636     Vec3 p_AQ, v_AQ;
637     findStationInALocationVelocity(X_AB, V_AB, p_BQ_A, p_AQ, v_AQ);//15 flops
638 
639     p_PQ_A = p_AQ - p_AP;                // 3 flops
640     const Vec3 p_PQ_A_dot = v_AQ - v_AP; // derivative in A (3 flops)
641     v_FQ_A = p_PQ_A_dot - w_AF % p_PQ_A; // derivative in F (12 flops)
642 }
643 
644 // There is no findStationAccelerationFromState().
645 
646 // Only configuration and velocity come from state; accelerations are an
647 // operand (15 flops).
648 // p_BS_A      is p_BS rexpressed in A but not shifted to Ao.
649 // wXwX_p_BS_A is w_AB x (w_AB x p_BS_A)  (Coriolis acceleration)
findStationInAAcceleration(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allA_AB,ConstrainedBodyIndex B,const Vec3 & p_BS_A,const Vec3 & wXwX_p_BS_A)650 Vec3 findStationInAAcceleration
651    (const State&                                    s,
652     const Array_<SpatialVec,ConstrainedBodyIndex>&  allA_AB,
653     ConstrainedBodyIndex                            B,
654     const Vec3&                                     p_BS_A,
655     const Vec3&                                     wXwX_p_BS_A) const
656 {
657     const SpatialVec& A_AB   = allA_AB[B];
658     const Vec3& b_AB = A_AB[0]; const Vec3& a_AB = A_AB[1];
659 
660     // Result is a + b X r + w X (w X r).
661     // ("b" is angular acceleration; w is angular velocity) 15 flops.
662     const Vec3 a_AS = a_AB + (b_AB % p_BS_A) + wXwX_p_BS_A;
663     return a_AS;
664 }
665 
666 // Same as above but we only know the station in B. (48 flops)
findStationAcceleration(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allA_AB,ConstrainedBodyIndex B,const Vec3 & p_BS)667 Vec3 findStationAcceleration
668    (const State&                                    s,
669     const Array_<SpatialVec,ConstrainedBodyIndex>&  allA_AB,
670     ConstrainedBodyIndex                            B,
671     const Vec3&                                     p_BS) const
672 {   // p_BS_A is p_BS rexpressed in A but not shifted to Ao
673     const Rotation& R_AB   = getBodyRotationFromState(s,B);
674     const Vec3&     w_AB   = getBodyAngularVelocityFromState(s,B);
675     const Vec3 p_BS_A = R_AB * p_BS;                 // 15 flops
676     const Vec3 wXwX_p_BS_A = w_AB % (w_AB % p_BS_A); // 18 flops
677     return findStationInAAcceleration(s,allA_AB,B,p_BS_A,wXwX_p_BS_A);
678 }
679 
680 
681 // Combo method is cheaper. Location and velocity come from state, accelerations
682 // from operand. NOTE: you must provide the p_BS vector expressed (but not
683 // measured) in A. 39 flops.
findStationInALocationVelocityAcceleration(const Transform & X_AB,const SpatialVec & V_AB,const SpatialVec & A_AB,const Vec3 & p_BS_A,Vec3 & p_AS,Vec3 & v_AS,Vec3 & a_AS)684 void findStationInALocationVelocityAcceleration
685    (const Transform&                                X_AB,
686     const SpatialVec&                               V_AB,
687     const SpatialVec&                               A_AB,
688     const Vec3&                                     p_BS_A,
689     Vec3& p_AS, Vec3& v_AS, Vec3& a_AS) const
690 {
691     const Vec3& w_AB = V_AB[0]; const Vec3& v_AB = V_AB[1];
692     const Vec3& b_AB = A_AB[0]; const Vec3& a_AB = A_AB[1];
693 
694     const Vec3 pdot_BS_A = w_AB % p_BS_A;   //  9 flops
695 
696     p_AS = X_AB.p() + p_BS_A;               //  3 flops
697     v_AS = v_AB + pdot_BS_A;                //  3 flops
698 
699     // Result is a + b X r + w X (w X r).
700     // ("b" is angular acceleration; w is angular velocity) 24 flops.
701     a_AS = a_AB + (b_AB % p_BS_A) + (w_AB % pdot_BS_A);
702 }
703 
704 // Apply an Ancestor-frame force to a B-frame station S, adding it to the
705 // appropriate bodyForcesInA entry, where bodyForcesInA is *already* size
706 // numConstrainedBodies for this Constraint. 30 flops.
addInStationForce(const State & s,ConstrainedBodyIndex B,const Vec3 & p_BS,const Vec3 & forceInA,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA)707 void addInStationForce(const State& s,
708                        ConstrainedBodyIndex B, const Vec3& p_BS,
709                        const Vec3& forceInA,
710                        Array_<SpatialVec, ConstrainedBodyIndex>& bodyForcesInA)
711                        const
712 {
713     assert(bodyForcesInA.size() == getNumConstrainedBodies());
714     const Rotation& R_AB = getBodyRotationFromState(s,B);
715     const Vec3      p_BS_A = R_AB * p_BS;         // 15 flops
716     bodyForcesInA[B] += SpatialVec(p_BS_A % forceInA, forceInA); // rXf, f
717 }
718 
719 // If you already have the p_BS station vector re-expressed in A, use this
720 // faster method (15 flops).
addInStationInAForce(const Vec3 & p_BS_A,const Vec3 & forceInA,SpatialVec & bodyForceOnBInA)721 void addInStationInAForce(const Vec3& p_BS_A, const Vec3& forceInA,
722                           SpatialVec& bodyForceOnBInA)
723                           const
724 {
725     bodyForceOnBInA += SpatialVec(p_BS_A % forceInA, forceInA); // rXf, f
726 }
727 
728 // Same thing but subtract the force; this is just to save having to negate it.
subInStationInAForce(const Vec3 & p_BS_A,const Vec3 & negForceInA,SpatialVec & bodyForceOnBInA)729 void subInStationInAForce(const Vec3& p_BS_A, const Vec3& negForceInA,
730                           SpatialVec& bodyForceOnBInA)
731                           const
732 {
733     bodyForceOnBInA -= SpatialVec(p_BS_A % negForceInA, negForceInA); //-rXf,-f
734 }
735 
736 // Apply an Ancestor-frame torque to body B, updating the appropriate
737 // bodyForcesInA entry, where bodyForcesInA is *already* size
738 // numConstrainedBodies for this Constraint. 3 flops.
addInBodyTorque(const State & s,ConstrainedBodyIndex B,const Vec3 & torqueInA,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA)739 void addInBodyTorque(const State& s, ConstrainedBodyIndex B,
740                      const Vec3& torqueInA,
741                      Array_<SpatialVec, ConstrainedBodyIndex>& bodyForcesInA)
742                      const
743 {
744     assert(bodyForcesInA.size() == getNumConstrainedBodies());
745     bodyForcesInA[B][0] += torqueInA; // no force
746 }
747 
748 // After realizeTopology() we can look at the values of modeling variables in
749 // the State. A Constraint is free to use those in determining how many
750 // constraint equations of each type to generate. The default implementation
751 // doesn't look at the state but instead returns the default numbers of
752 // equations supplied when the Constraint was constructed.
calcNumConstraintEquationsInUse(const State & s,int & mp,int & mv,int & ma)753 void calcNumConstraintEquationsInUse(const State& s, int& mp, int& mv, int& ma) const {
754     calcNumConstraintEquationsInUseVirtual(s,mp,mv,ma);
755 }
756 
757 // Abbreviated version of the above; returns number of holonomic constraint
758 // equations in use.
calcNumPositionEquationsInUse(const State & s)759 int calcNumPositionEquationsInUse(const State& s) const {
760     int mp, mv, ma; calcNumConstraintEquationsInUse(s, mp, mv, ma);
761     return mp;
762 }
763 // Abbreviated version of the above; returns number of nonholonomic constraint
764 // equations in use.
calcNumVelocityEquationsInUse(const State & s)765 int calcNumVelocityEquationsInUse(const State& s) const {
766     int mp, mv, ma; calcNumConstraintEquationsInUse(s, mp, mv, ma);
767     return mv;
768 }
769 // Abbreviated version of the above; returns number of acceleration-only
770 // constraint equations in use.
calcNumAccelerationEquationsInUse(const State & s)771 int calcNumAccelerationEquationsInUse(const State& s) const {
772     int mp, mv, ma; calcNumConstraintEquationsInUse(s, mp, mv, ma);
773     return ma;
774 }
775 
776     // The next three methods are just interfaces to the constraint
777     // operators like calcPositionErrors(); they extract needed operands
778     // from the supplied state and then call the operator.
779 
780 // Calculate the mp position errors that would result from the configuration
781 // present in the supplied state (that is, q's and body transforms). The state
782 // must be realized through Time stage and part way through realization of
783 // Position stage.
784 void calcPositionErrorsFromState(const State& s, Array_<Real>& perr) const;
785 
786 // Calculate the mp velocity errors resulting from pdot equations, given a
787 // configuration and velocities in the supplied state which must be realized
788 // through Position stage and part way through realization of Velocity stage.
789 void calcPositionDotErrorsFromState(const State& s, Array_<Real>& pverr) const;
790 
791 // Calculate the mv velocity errors resulting from the nonholonomic constraint
792 // equations here, taking the configuration and velocities (u, qdot, body
793 // spatial velocities) from the supplied state, which must be realized through
794 // Position stage and part way through realization of Velocity stage.
795 void calcVelocityErrorsFromState(const State& s, Array_<Real>& verr) const;
796 
797 // Calculate position errors given pose of the constrained bodies and the
798 // values of the constrained q's. Pull t from state.
calcPositionErrors(const State & s,const Array_<Transform,ConstrainedBodyIndex> & X_AB,const Array_<Real,ConstrainedQIndex> & constrainedQ,Array_<Real> & perr)799 void calcPositionErrors
800    (const State&                                    s,     // Stage::Time
801     const Array_<Transform,ConstrainedBodyIndex>&   X_AB,
802     const Array_<Real,     ConstrainedQIndex>&      constrainedQ,
803     Array_<Real>&                                   perr)  // mp of these
804     const
805 {
806     assert(X_AB.size()         == getNumConstrainedBodies());
807     assert(constrainedQ.size() == getNumConstrainedQ(s));
808     assert(perr.size()         == calcNumPositionEquationsInUse(s));
809 
810     calcPositionErrorsVirtual(s,X_AB,constrainedQ,perr);
811 }
812 
813 // Calculate pdot errors given spatial velocity of the constrained bodies and
814 // the values of the constrained qdot's. Pull t, X_AB and q from state.
calcPositionDotErrors(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & V_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDot,Array_<Real> & pverr)815 void calcPositionDotErrors
816    (const State&                                    s, // Stage::Position
817     const Array_<SpatialVec,ConstrainedBodyIndex>&  V_AB,
818     const Array_<Real,      ConstrainedQIndex>&     constrainedQDot,
819     Array_<Real>&                                   pverr) // mp of these
820     const
821 {
822     assert(V_AB.size()            == getNumConstrainedBodies());
823     assert(constrainedQDot.size() == getNumConstrainedQ(s));
824     assert(pverr.size()           == calcNumPositionEquationsInUse(s));
825 
826     calcPositionDotErrorsVirtual(s,V_AB,constrainedQDot,pverr);
827 }
828 
829 // Calculate pdotdot errors given spatial acceleration of the constrained
830 // bodies and the values of the constrained qdotdot's. Pull t, X_AB, q, V_AB,
831 // qdot from state.
calcPositionDotDotErrors(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & A_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDotDot,Array_<Real> & paerr)832 void calcPositionDotDotErrors
833    (const State&                                    s, // Stage::Velocity
834     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
835     const Array_<Real,      ConstrainedQIndex>&     constrainedQDotDot,
836     Array_<Real>&                                   paerr) // mp of these
837     const
838 {
839     assert(A_AB.size()               == getNumConstrainedBodies());
840     assert(constrainedQDotDot.size() == getNumConstrainedQ(s));
841     assert(paerr.size()              == calcNumPositionEquationsInUse(s));
842 
843     calcPositionDotDotErrorsVirtual(s,A_AB,constrainedQDotDot,paerr);
844 }
845 
846 // Given mp position constraint multipliers, generate the corresponding
847 // constraint forces acting on the constrained bodies and the generalized
848 // coordinates q of the constrained mobilizers and add them in to the given
849 // arrays. The state must be realized through Position stage.
addInPositionConstraintForces(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedQIndex> & qForces)850 void addInPositionConstraintForces
851     (const State& s,
852      const Array_<Real>&                       multipliers, // mp of these
853      Array_<SpatialVec, ConstrainedBodyIndex>& bodyForcesInA,
854      Array_<Real,       ConstrainedQIndex>&    qForces) const
855 {
856     assert(multipliers.size()   == calcNumPositionEquationsInUse(s));
857     assert(bodyForcesInA.size() == getNumConstrainedBodies());
858     assert(qForces.size()       == getNumConstrainedQ(s));
859 
860     // Note that position constraints act on q (qdot,qdotdot) and for
861     // convenience we allow them to generate generalized forces in qdot-space
862     // rather than u-space. These will have to be mapped into u-space when
863     // they are used, since Simbody only deals in u-space forces normally.
864     // Since qdot=N*u, and we must have power ~f_qdot*qdot==~f_u*u, we have
865     // f_u=~N * f_qdot.
866     addInPositionConstraintForcesVirtual
867        (s,multipliers,bodyForcesInA,qForces);
868 }
869 
870 // Calculate velocity errors (errors produced by nonholonomic constraint
871 // equations) given spatial velocity of the constrained bodies and the
872 // values of the constrained u's. Pull t, X_AB, q from state.
calcVelocityErrors(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & V_AB,const Array_<Real,ConstrainedUIndex> & constrainedU,Array_<Real> & verr)873 void calcVelocityErrors
874    (const State&                                    s,    // Stage::Position
875     const Array_<SpatialVec,ConstrainedBodyIndex>&  V_AB,
876     const Array_<Real,      ConstrainedUIndex>&     constrainedU,
877     Array_<Real>&                                   verr) // mv of these
878     const
879 {
880     assert(V_AB.size()         == getNumConstrainedBodies());
881     assert(constrainedU.size() == getNumConstrainedU(s));
882     assert(verr.size()         == calcNumVelocityEquationsInUse(s));
883 
884     calcVelocityErrorsVirtual(s,V_AB,constrainedU,verr);
885 }
886 
887 // Calculate vdot errors (errors produced by nonholonomic constraint
888 // derivatives) given spatial acceleration of the constrained bodies and the
889 // values of the constrained udot's. Pull t, X_AB, q, V_AB, u from state.
calcVelocityDotErrors(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & A_AB,const Array_<Real,ConstrainedUIndex> & constrainedUDot,Array_<Real> & vaerr)890 void calcVelocityDotErrors
891    (const State&                                    s,     // Stage::Velocity
892     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
893     const Array_<Real,      ConstrainedUIndex>&     constrainedUDot,
894     Array_<Real>&                                   vaerr) // mv of these
895     const
896 {
897     assert(A_AB.size()            == getNumConstrainedBodies());
898     assert(constrainedUDot.size() == getNumConstrainedU(s));
899     assert(vaerr.size()           == calcNumVelocityEquationsInUse(s));
900 
901     calcVelocityDotErrorsVirtual(s,A_AB,constrainedUDot,vaerr);
902 }
903 
904 
905 // Given mv velocity constraint multipliers, generate the corresponding
906 // constraint forces acting on the constrained bodies and the mobilities of the
907 // constrained mobilizers, and add them in to the given arrays. The state must
908 // be realized through Velocity stage unless the V matrix is
909 // velocity-independent in which case Position stage is enough.
addInVelocityConstraintForces(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedUIndex> & mobilityForces)910 void addInVelocityConstraintForces
911     (const State& s,
912      const Array_<Real>&                       multipliers, // mv of these
913      Array_<SpatialVec, ConstrainedBodyIndex>& bodyForcesInA,
914      Array_<Real,       ConstrainedUIndex>&    mobilityForces) const
915 {
916     assert(multipliers.size()    == calcNumVelocityEquationsInUse(s));
917     assert(bodyForcesInA.size()  == getNumConstrainedBodies());
918     assert(mobilityForces.size() == getNumConstrainedU(s));
919 
920     addInVelocityConstraintForcesVirtual
921        (s,multipliers,bodyForcesInA,mobilityForces);
922 }
923 
924 // Calculate acceleration errors (errors produced by acceleration-only
925 // constraint equations) given spatial acceleration of the constrained bodies
926 // and the values of the constrained udot's. Pull t, X_AB, q, V_AB, u from state.
calcAccelerationErrors(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & A_AB,const Array_<Real,ConstrainedUIndex> & constrainedUDot,Array_<Real> & aerr)927 void calcAccelerationErrors
928    (const State&                                    s,    // Stage::Velocity
929     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
930     const Array_<Real,      ConstrainedUIndex>&     constrainedUDot,
931     Array_<Real>&                                   aerr) // ma of these
932     const
933 {
934     assert(A_AB.size()            == getNumConstrainedBodies());
935     assert(constrainedUDot.size() == getNumConstrainedU(s));
936     assert(aerr.size()            == calcNumAccelerationEquationsInUse(s));
937 
938     calcAccelerationErrorsVirtual(s,A_AB,constrainedUDot,aerr);
939 }
940 
941 
942 // Given ma acceleration constraint multipliers, generate the corresponding
943 // constraint forces acting on the constrained bodies and the mobilities of the
944 // constrained mobilizers, and add them in to the given arrays. The state must
945 // be realized through Velocity stage unless the A matrix is
946 // velocity-independent in which case Position stage is enough.
addInAccelerationConstraintForces(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedUIndex> & mobilityForces)947 void addInAccelerationConstraintForces
948     (const State& s,
949      const Array_<Real>&                       multipliers, // ma of these
950      Array_<SpatialVec, ConstrainedBodyIndex>& bodyForcesInA,
951      Array_<Real,       ConstrainedUIndex>&    mobilityForces) const
952 {
953     assert(multipliers.size()    == calcNumAccelerationEquationsInUse(s));
954     assert(bodyForcesInA.size()  == getNumConstrainedBodies());
955     assert(mobilityForces.size() == getNumConstrainedU(s));
956 
957     addInAccelerationConstraintForcesVirtual
958        (s,multipliers,bodyForcesInA,mobilityForces);
959 }
960 
calcDecorativeGeometryAndAppend(const State & s,Stage stage,Array_<DecorativeGeometry> & geom)961 void calcDecorativeGeometryAndAppend
962     (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const
963 {
964     // Let the individual constraint deal with any complicated stuff.
965     calcDecorativeGeometryAndAppendVirtual(s,stage,geom);
966 }
967 
968     // Don't call these virtuals directly; use the provided interface
969     // methods for safety (they evaporate in Release builds anyway).
970 
calcNumConstraintEquationsInUseVirtual(const State &,int & mp,int & mv,int & ma)971 virtual void calcNumConstraintEquationsInUseVirtual
972    (const State&, int& mp, int& mv, int& ma) const
973 {   mp = defaultMp; mv = defaultMv; ma = defaultMa; }
974 
realizeTopologyVirtual(State &)975 virtual void realizeTopologyVirtual     (State&)        const {}
realizeModelVirtual(State &)976 virtual void realizeModelVirtual        (State&)        const {}
realizeInstanceVirtual(const State &)977 virtual void realizeInstanceVirtual     (const State&)  const {}
realizeTimeVirtual(const State &)978 virtual void realizeTimeVirtual         (const State&)  const {}
realizePositionVirtual(const State &)979 virtual void realizePositionVirtual     (const State&)  const {}
realizeVelocityVirtual(const State &)980 virtual void realizeVelocityVirtual     (const State&)  const {}
realizeDynamicsVirtual(const State &)981 virtual void realizeDynamicsVirtual     (const State&)  const {}
realizeAccelerationVirtual(const State &)982 virtual void realizeAccelerationVirtual (const State&)  const {}
realizeReportVirtual(const State &)983 virtual void realizeReportVirtual       (const State&)  const {}
984 
985     // These must be defined if there are any position (holonomic) constraints.
986 
987 // Pull t from state.
988 virtual void calcPositionErrorsVirtual
989    (const State&                                    state, // Stage::Time
990     const Array_<Transform,ConstrainedBodyIndex>&   X_AB,
991     const Array_<Real,     ConstrainedQIndex>&      constrainedQ,
992     Array_<Real>&                                   perr)  // mp of these
993     const;
994 
995 // Pull t, X_AB and q from state.
996 virtual void calcPositionDotErrorsVirtual
997    (const State&                                    state, // Stage::Position
998     const Array_<SpatialVec,ConstrainedBodyIndex>&  V_AB,
999     const Array_<Real,      ConstrainedQIndex>&     constrainedQDot,
1000     Array_<Real>&                                   pverr) // mp of these
1001     const;
1002 
1003 // Pull t, X_AB, q, V_AB, qdot from state.
1004 virtual void calcPositionDotDotErrorsVirtual
1005    (const State&                                    state, // Stage::Velocity
1006     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
1007     const Array_<Real,      ConstrainedQIndex>&     constrainedQDotDot,
1008     Array_<Real>&                                   paerr) // mp of these
1009     const;
1010 
1011 // Pull t, X_AB and q from state.
1012 virtual void addInPositionConstraintForcesVirtual
1013    (const State&                                    state, // Stage::Position
1014     const Array_<Real>&                             multipliers, // mp of these
1015     Array_<SpatialVec,ConstrainedBodyIndex>&        bodyForcesInA,
1016     Array_<Real,      ConstrainedQIndex>&           qForces)
1017     const;
1018 
1019     // These must be defined if there are velocity (nonholonomic) constraints.
1020 
1021 // Pull t, X_AB, q from state.
1022 virtual void calcVelocityErrorsVirtual
1023    (const State&                                    state, // Stage::Position
1024     const Array_<SpatialVec,ConstrainedBodyIndex>&  V_AB,
1025     const Array_<Real,      ConstrainedUIndex>&     constrainedU,
1026     Array_<Real>&                                   verr) // mv of these
1027     const;
1028 
1029 // Pull t, X_AB, q, V_AB, u from state.
1030 virtual void calcVelocityDotErrorsVirtual
1031    (const State&                                    state, // Stage::Velocity
1032     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
1033     const Array_<Real,      ConstrainedUIndex>&     constrainedUDot,
1034     Array_<Real>&                                   vaerr) // mv of these
1035     const;
1036 
1037 // Pull t, X_AB, q, V_AB, u from state.
1038 virtual void addInVelocityConstraintForcesVirtual
1039    (const State&                                    state, // Stage::Velocity
1040     const Array_<Real>&                             multipliers, // mv of these
1041     Array_<SpatialVec,ConstrainedBodyIndex>&        bodyForcesInA,
1042     Array_<Real,      ConstrainedUIndex>&           mobilityForces)
1043     const;
1044 
1045     // These must be defined if there are any acceleration-only constraints.
1046 
1047 // Pull t, X_AB, q, V_AB, u from state.
1048 virtual void calcAccelerationErrorsVirtual
1049    (const State&                                    state, // Stage::Velocity
1050     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
1051     const Array_<Real,      ConstrainedUIndex>&     constrainedUDot,
1052     Array_<Real>&                                   aerr) // ma of these
1053     const;
1054 
1055 // Pull t, X_AB, q, V_AB, u from state.
1056 virtual void addInAccelerationConstraintForcesVirtual
1057    (const State&                                    state, // Stage::Velocity
1058     const Array_<Real>&                             multipliers, // ma of these
1059     Array_<SpatialVec,ConstrainedBodyIndex>&        bodyForcesInA,
1060     Array_<Real,      ConstrainedUIndex>&           mobilityForces)
1061     const;
1062 
1063 
calcDecorativeGeometryAndAppendVirtual(const State & s,Stage stage,Array_<DecorativeGeometry> & geom)1064 virtual void calcDecorativeGeometryAndAppendVirtual
1065    (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const {}
1066 
1067 
1068 void invalidateTopologyCache() const;
1069 bool subsystemTopologyHasBeenRealized() const;
1070 
1071 void setMyMatterSubsystem(SimbodyMatterSubsystem& matter,
1072                           ConstraintIndex id);
1073 
1074 const SimbodyMatterSubsystem& getMyMatterSubsystem() const;
1075 
isInSubsystem()1076 bool isInSubsystem() const {
1077     return myMatterSubsystemRep != 0;
1078 }
1079 
1080 // Is the supplied body in the same subsystem as this Constraint? (Returns
1081 // false also if either the Constraint or the MobilizedBody is not in a
1082 // subsystem.)
1083 bool isInSameSubsystem(const MobilizedBody& body) const;
1084 
getNumConstrainedBodies()1085 int getNumConstrainedBodies() const {
1086     SimTK_ASSERT(subsystemTopologyHasBeenRealized(),
1087         "Number of constrained bodies is not available until Topology stage has been realized.");
1088     return (int)myConstrainedBodies.size();
1089 }
getNumConstrainedMobilizers()1090 int getNumConstrainedMobilizers() const {
1091     SimTK_ASSERT(subsystemTopologyHasBeenRealized(),
1092         "Number of constrained mobilizers is not available until Topology stage has been realized.");
1093     return (int)myConstrainedMobilizers.size();
1094 }
1095 
1096 const MobilizedBody&
1097     getMobilizedBodyFromConstrainedMobilizer(ConstrainedMobilizerIndex) const;
1098 const MobilizedBody&
1099     getMobilizedBodyFromConstrainedBody(ConstrainedBodyIndex) const;
1100 
1101 // Don't call this unless there is at least one Constrained Body.
1102 const MobilizedBody& getAncestorMobilizedBody() const;
1103 
1104 // After realizeTopology() we remember whether this constraint's Ancestor
1105 // body is different from Ground.
isAncestorDifferentFromGround()1106 bool isAncestorDifferentFromGround() const {
1107     SimTK_ASSERT(subsystemTopologyHasBeenRealized(),
1108         "isAncestorDifferentFromGround(): must call realizeTopology() first.");
1109     return myAncestorBodyIsNotGround;
1110 }
1111 
1112 // Find out how many holonomic (position), nonholonomic (velocity),
1113 // and acceleration-only constraint equations are generated by this Constraint
1114 // as currently modeled. State must be realized to Stage::Model.
1115 void getNumConstraintEquationsInUse
1116    (const State&, int& mHolo, int& mNonholo, int& mAccOnly) const;
1117 
1118 // Return the starting index within the multiplier or udot error arrays
1119 // for each of the acceleration-level constraints produced by this Constraint.
1120 // Let holo0, nonholo0, accOnly0 be the first index of the slots assigned to
1121 // this Constraint's holonomic, nonholonomic, and acceleration-only constraints
1122 // within each block for that category. Then the returns here are:
1123 //     px = holo0
1124 //     vx = totalNumHolo + nonholo0
1125 //     ax = totalNumHolo+totalNumNonholo + accOnly0
1126 // These are returned invalid if there are no constraint equations in that
1127 // category.
1128 void getIndexOfMultipliersInUse(const State& state,
1129                                 MultiplierIndex& px0,
1130                                 MultiplierIndex& vx0,
1131                                 MultiplierIndex& ax0) const;
1132 
1133 void setMyPartInConstraintSpaceVector(const State& state,
1134                                  const Vector& myPart,
1135                                  Vector& constraintSpace) const;
1136 
1137 void getMyPartFromConstraintSpaceVector(const State& state,
1138                                    const Vector& constraintSpace,
1139                                    Vector& myPart) const;
1140 
1141 int getNumConstrainedQ(const State&) const;
1142 int getNumConstrainedU(const State&) const;
1143 int getNumConstrainedQ(const State&, ConstrainedMobilizerIndex) const;
1144 int getNumConstrainedU(const State&, ConstrainedMobilizerIndex) const;
1145 ConstrainedQIndex getConstrainedQIndex
1146     (const State&, ConstrainedMobilizerIndex, MobilizerQIndex which) const;
1147 ConstrainedUIndex getConstrainedUIndex
1148     (const State&, ConstrainedMobilizerIndex, MobilizerUIndex which) const;
1149 
getMyMatterSubsystemRep()1150 const SimbodyMatterSubsystemRep& getMyMatterSubsystemRep() const {
1151     SimTK_ASSERT(myMatterSubsystemRep,
1152         "Operation illegal on a Constraint that is not in a Subsystem.");
1153     return *myMatterSubsystemRep;
1154 }
updMyMatterSubsystemRep()1155 SimbodyMatterSubsystemRep& updMyMatterSubsystemRep() {
1156     SimTK_ASSERT(myMatterSubsystemRep,
1157         "Operation illegal on a Constraint that is not in a Subsystem.");
1158     return *myMatterSubsystemRep;
1159 }
1160 
getMyConstraintIndex()1161 ConstraintIndex getMyConstraintIndex() const {
1162     SimTK_ASSERT(myMatterSubsystemRep,
1163         "Operation illegal on a Constraint that is not in a Subsystem.");
1164     return myConstraintIndex;
1165 }
1166 
1167 
1168 // Calculate the transform X_AB of each ConstrainedBody in its Ancestor frame,
1169 // provided Ancestor!=Ground and A!=B. We expect a TreePositionCache in
1170 // which the mobilizer- and ground-frame position kinematics results have
1171 // already been calculated. We then fill in the missing ancestor-frame
1172 // results back into that same TreePositionCache.
1173 void calcConstrainedBodyTransformInAncestor(const SBInstanceVars&,  // in only
1174                                             SBTreePositionCache&    // in/out
1175                                             ) const;
1176 
1177 // Similarly we calculate V_AB during realizeVelocity().
1178 // Here we expect a StateDigest realized through Position stage, and a
1179 // partly-filled-in VelocityCache where we'll put V_AB for the
1180 // ConstrainedBodies.
1181 void calcConstrainedBodyVelocityInAncestor(const SBInstanceVars&,   // in only
1182                                            const SBTreePositionCache&, // "
1183                                            SBTreeVelocityCache&     // in/out
1184                                            ) const;
1185 
1186 // A_AB is not cached.
1187 
1188 private:
1189 friend class Constraint;
1190 
1191     // TOPOLOGY "STATE"
1192 
1193 // These data members are filled in once the Constraint is added to
1194 // a MatterSubsystem.
1195 SimbodyMatterSubsystemRep* myMatterSubsystemRep;
1196 ConstraintIndex            myConstraintIndex; // id within the matter subsystem
1197 
1198 // We'll keep the constrained bodies and constrained mobilizers each in two
1199 // maps: one maps MobilizedBodyIndex->ConstrainedBody[Mobilizer]Index (O(log n)
1200 // to look up), and the other maps ConstrainedBody[Mobilizer]Index->
1201 // MobilizedBodyIndex (randomly addressable in constant time).
1202 MobilizedBody2ConstrainedBodyMap        myMobilizedBody2ConstrainedBodyMap;
1203 MobilizedBody2ConstrainedMobilizerMap   myMobilizedBody2ConstrainedMobilizerMap;
1204 
1205 Array_<MobilizedBodyIndex> myConstrainedBodies;     // [ConstrainedBodyIndex]
1206 Array_<MobilizedBodyIndex> myConstrainedMobilizers; // [ConstrainedMobilizerIndex]
1207 
1208 
1209 // These are the defaults for the number of position (holonomic) constraint
1210 // equations, the number of velocity (nonholonomic) constraint equations, and
1211 // the number of acceleration-only constraint equations.
1212 int defaultMp, defaultMv, defaultMa;
1213 
1214 // This says whether the Model-stage "disabled" flag for this Constraint should
1215 // be initially on or off. Most constraints are enabled by default.
1216 bool defaultDisabled;
1217 
1218 // ConditionalConstraints set this flag when they add a constraint to the
1219 // system. It can be referenced by a time stepper to determine whether to
1220 // treat a constraint as unconditional (in which case someone else has to
1221 // figure out whether it is active). This flag doesn't affect the operation of
1222 // the Constraint object itself; it is just stored and reported.
1223 bool constraintIsConditional;
1224 
1225     // TOPOLOGY "CACHE"
1226 
1227 // When topology is realized we study the constrained bodies to identify the
1228 // subtree of mobilized bodies which may be kinematically involved in
1229 // satisfaction of this Constraint. This requires finding the outmost common
1230 // ancestor of the constrained bodies. All mobilized bodies on the paths inward
1231 // from the constrained bodies to the ancestor are included; nothing outboard
1232 // of the constrained bodies is included; and the ancestor is treated as ground
1233 // so that its mobilities are *not* included. The Ancestor may be one of the
1234 // Constrained Bodies or may be distinct.
1235 mutable SimbodyMatterSubtree mySubtree;
1236 
1237 // This is true only when (1) there are Constrained Bodies and (2) their
1238 // Ancestor is some MobilizedBody other than Ground.
1239 mutable bool myAncestorBodyIsNotGround;
1240 
1241 // When the Ancestor is not Ground, each of the Constrained Bodies (except
1242 // the Ancestor) needs some additional precalculated data in the State cache
1243 // so is assigned a MatterSubsystem-global AncestorConstrainedBodyPool slot.
1244 // If Ancestor isn't Ground there is an entry here for each ConstrainedBody
1245 // (including Ancestor if it is one), but the index is invalid for Ancestor's
1246 // entry. When Ancestor is Ground we don't allocate this array.
1247 mutable Array_<AncestorConstrainedBodyPoolIndex> myPoolIndex;
1248                                             // index with ConstrainedBodyIndex
1249 };
1250 
1251 
1252 
1253 //==============================================================================
1254 //                           POINT IN PLANE IMPL
1255 //==============================================================================
1256 class Constraint::PointInPlaneImpl : public ConstraintImpl {
1257 public:
PointInPlaneImpl()1258 PointInPlaneImpl()
1259     : ConstraintImpl(1,0,0), defaultPlaneNormal(), defaultPlaneHeight(0), defaultFollowerPoint(0),
1260     planeHalfWidth(1), pointRadius(Real(0.05))
1261 { }
clone()1262 PointInPlaneImpl* clone() const override { return new PointInPlaneImpl(*this); }
1263 
1264 void calcDecorativeGeometryAndAppendVirtual
1265     (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const override;
1266 
setPlaneDisplayHalfWidth(Real h)1267 void setPlaneDisplayHalfWidth(Real h) {
1268     // h <= 0 means don't display plane
1269     invalidateTopologyCache();
1270     planeHalfWidth = h > 0 ? h : 0;
1271 }
getPlaneDisplayHalfWidth()1272 Real getPlaneDisplayHalfWidth() const {return planeHalfWidth;}
1273 
setPointDisplayRadius(Real r)1274 void setPointDisplayRadius(Real r) {
1275     // r <= 0 means don't display point
1276     invalidateTopologyCache();
1277     pointRadius= r > 0 ? r : 0;
1278 }
getPointDisplayRadius()1279 Real getPointDisplayRadius() const {return pointRadius;}
1280 
1281 // Implementation of virtuals required for holonomic constraints.
1282 
1283 // We have a point-in-plane connection between base body B, on which the plane
1284 // is fixed, and follower body F, on which the follower point S is fixed. All
1285 // forces will be applied at point S and the coincident material point C on B
1286 // which is instantaneously at the same spatial location as S. Then n is the
1287 // plane normal (a constant unit vector in B), h is the plane height measured
1288 // from the B origin along n (a scalar constant).Point C's location in B is
1289 // given by the vector p_BC from B's origin to the current location of S, and
1290 // expressed in B. That vector expressed in A is p_BC_A (= p_AS-p_AB). We will
1291 // express in the A frame but differentiate in the B frame.
1292 //
1293 // Derivation:
1294 //   (1) Note that to take a derivative d/dt_B in a moving frame B, we can take
1295 //       the derivative d/dt_A and then add in the contribution d_A/dt_B from
1296 //       A's rotation in B (which is the angular velocity of A in B,
1297 //       w_BA=-w_AB).
1298 //   (2) p_CS = p_AS-p_AC = 0 by construction of C, but its derivative in A,
1299 //       v_CS_A = d/dt_A p_CS != 0.
1300 //
1301 //    perr = p_CS * n + constant
1302 //         = constant  (because p_CS==0 by construction)
1303 //
1304 //    verr = d/dt_B perr = d/dt_A perr + d_A/dt_B perr
1305 //         = [v_CS_A*n + p_CS * (w_AB X n)] + [(w_BA X p_CS) * n + p_CS * (w_BA X n)]
1306 //         = v_CS_A*n + p_CS * (w_AB X n) (because terms in 2nd [] cancel)
1307 //         = v_CS_A * n  (because p_CS==0 by construction)
1308 //
1309 //    aerr = d/dt_B verr = d/dt_A verr + d_A/dt_B verr
1310 //         = [a_CS_A*n + v_CS_A*(w_AB X n) + v_CS_A*(w_AB X n) + p_CS*(2 w_AB X(w_AB X n))]
1311 //           + [w_BAXv_CS_A*n + v_CS_A*w_BAXn]
1312 //         = (a_CS_A - 2 w_AB X v_CS_A) * n   (2nd bracket cancels, and p_CS==0)
1313 //
1314 // (The constant in perr is set so that S starts at the same height h as the
1315 // plane.)
1316 //
1317 // Then, from examination of verr noting that v_CS_A=v_AS-v_AC:
1318 //       ~v_AS*n                  (body F at point S)
1319 //     - ~v_AC*n                  (body B at point C)
1320 // so we apply a forces lambda*n to F at S, -lambda*n to B at C.
1321 //
1322 //    --------------------------------
1323 //    perr = ~p_BS*n - h
1324 //    --------------------------------
calcPositionErrorsVirtual(const State & s,const Array_<Transform,ConstrainedBodyIndex> & allX_AB,const Array_<Real,ConstrainedQIndex> & constrainedQ,Array_<Real> & perr)1325 void calcPositionErrorsVirtual
1326    (const State&                                    s,      // Stage::Time
1327     const Array_<Transform,ConstrainedBodyIndex>&   allX_AB,
1328     const Array_<Real,     ConstrainedQIndex>&      constrainedQ,
1329     Array_<Real>&                                   perr)   // mp of these
1330     const override
1331 {
1332     assert(allX_AB.size()==2 && constrainedQ.size()==0 && perr.size() == 1);
1333 
1334     const Vec3       p_AS = findStationLocation(allX_AB, followerBody,
1335                                                 defaultFollowerPoint);
1336     const Transform& X_AB = getBodyTransform(allX_AB, planeBody);
1337     const Vec3       p_BC = ~X_AB * p_AS; // shift to B origin, reexpress in B;
1338                                      // C is material pt of B coincident with S
1339 
1340     // We'll calculate this scalar using B-frame vectors, but any frame would
1341     // have done.
1342     perr[0] = dot(p_BC, defaultPlaneNormal) - defaultPlaneHeight;
1343 }
1344 
1345 //    --------------------------------
1346 //    verr = ~v_CS_A*n
1347 //    --------------------------------
calcPositionDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & V_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDot,Array_<Real> & pverr)1348 void calcPositionDotErrorsVirtual
1349    (const State&                                    s,      // Stage::Position
1350     const Array_<SpatialVec,ConstrainedBodyIndex>&  V_AB,
1351     const Array_<Real,      ConstrainedQIndex>&     constrainedQDot,
1352     Array_<Real>&                                   pverr)  // mp of these
1353     const override
1354 {
1355     assert(V_AB.size()==2 && constrainedQDot.size()==0 && pverr.size() == 1);
1356     //TODO: should be able to get p info from State
1357 
1358     const Vec3       p_AS = findStationLocationFromState(s, followerBody,
1359                                                          defaultFollowerPoint);
1360     const Transform& X_AB = getBodyTransformFromState(s, planeBody);
1361     const Vec3       p_BC = ~X_AB * p_AS; // shift to B origin, reexpress in B;
1362                                    // C is material point of B coincident with S
1363     const UnitVec3   n_A  = X_AB.R() * defaultPlaneNormal;
1364 
1365     const Vec3       v_AS = findStationVelocity(s, V_AB, followerBody,
1366                                                 defaultFollowerPoint);
1367     const Vec3       v_AC = findStationVelocity(s, V_AB, planeBody, p_BC);
1368 
1369     // Calculate this scalar using A-frame vectors.
1370     pverr[0] = dot( v_AS-v_AC, n_A );
1371 }
1372 
1373 //    -------------------------------------
1374 //    aerr = ~(a_CS_A - 2 w_AB X v_CS_A) * n
1375 //    -------------------------------------
calcPositionDotDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & A_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDotDot,Array_<Real> & paerr)1376 void calcPositionDotDotErrorsVirtual
1377    (const State&                                    s,      // Stage::Velocity
1378     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
1379     const Array_<Real,      ConstrainedQIndex>&     constrainedQDotDot,
1380     Array_<Real>&                                   paerr)  // mp of these
1381     const override
1382 {
1383     assert(A_AB.size()==2 && constrainedQDotDot.size()==0 && paerr.size() == 1);
1384     //TODO: should be able to get p and v info from State
1385     const Vec3       p_AS = findStationLocationFromState(s, followerBody,
1386                                                          defaultFollowerPoint);
1387     const Transform& X_AB = getBodyTransformFromState(s, planeBody);
1388     const Vec3       p_BC = ~X_AB * p_AS; // shift to B origin, reexpress in B;
1389                                    // C is material point of B coincident with S
1390     const UnitVec3   n_A  = X_AB.R() * defaultPlaneNormal;
1391 
1392     const Vec3&      w_AB = getBodyAngularVelocityFromState(s, planeBody);
1393     const Vec3       v_AS = findStationVelocityFromState(s, followerBody,
1394                                                          defaultFollowerPoint);
1395     const Vec3       v_AC = findStationVelocityFromState(s, planeBody, p_BC);
1396 
1397     const Vec3       a_AS = findStationAcceleration(s, A_AB, followerBody,
1398                                                     defaultFollowerPoint);;
1399     const Vec3       a_AC = findStationAcceleration(s, A_AB, planeBody, p_BC);
1400 
1401     paerr[0] = dot( (a_AS-a_AC) - 2.*w_AB % (v_AS-v_AC), n_A );
1402 }
1403 
1404 // apply f=lambda*n to the follower point S of body F,
1405 //       -f         to point C (coincident point) of body B
addInPositionConstraintForcesVirtual(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedQIndex> & qForces)1406 void addInPositionConstraintForcesVirtual
1407    (const State&                                    s,      // Stage::Position
1408     const Array_<Real>&                             multipliers, // mp of these
1409     Array_<SpatialVec,ConstrainedBodyIndex>&        bodyForcesInA,
1410     Array_<Real,      ConstrainedQIndex>&           qForces)
1411     const override
1412 {
1413     assert(multipliers.size()==1 && bodyForcesInA.size()==2
1414            && qForces.size()==0);
1415     const Real lambda = multipliers[0];
1416 
1417     //TODO: should be able to get p info from State
1418     const Vec3&      p_FS    = defaultFollowerPoint; // measured & expressed in F
1419     const Vec3       p_AS    = findStationLocationFromState(s, followerBody,
1420                                                             defaultFollowerPoint);
1421     const Transform& X_AB    = getBodyTransformFromState(s, planeBody);
1422     const Vec3       p_BC    = ~X_AB * p_AS;         // measured & expressed in B
1423     const Vec3       force_A = X_AB.R()*(lambda*defaultPlaneNormal);
1424 
1425     addInStationForce(s, followerBody, p_FS,  force_A, bodyForcesInA);
1426     addInStationForce(s, planeBody,    p_BC, -force_A, bodyForcesInA);
1427 }
1428 
1429 SimTK_DOWNCAST(PointInPlaneImpl, ConstraintImpl);
1430 //------------------------------------------------------------------------------
1431                                     private:
1432 friend class Constraint::PointInPlane;
1433 
1434 ConstrainedBodyIndex    planeBody;    // B1
1435 ConstrainedBodyIndex    followerBody; // B2
1436 
1437 UnitVec3                defaultPlaneNormal;   // on body 1, exp. in B1 frame
1438 Real                    defaultPlaneHeight;
1439 Vec3                    defaultFollowerPoint; // on body 2, exp. in B2 frame
1440 
1441 // These are just for visualization
1442 Real                    planeHalfWidth;
1443 Real                    pointRadius;
1444 };
1445 
1446 
1447 
1448 //==============================================================================
1449 //                           POINT ON LINE IMPL
1450 //==============================================================================
1451 class Constraint::PointOnLineImpl : public ConstraintImpl {
1452 public:
PointOnLineImpl()1453 PointOnLineImpl()
1454 :   ConstraintImpl(2,0,0),
1455     defaultLineDirection(), defaultPointOnLine(), defaultFollowerPoint(0),
1456     lineHalfLength(1), pointRadius(Real(0.05))
1457 { }
clone()1458 PointOnLineImpl* clone() const override { return new PointOnLineImpl(*this); }
1459 
1460 void calcDecorativeGeometryAndAppendVirtual
1461     (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const override;
1462 
setLineDisplayHalfLength(Real h)1463 void setLineDisplayHalfLength(Real h) {
1464     // h <= 0 means don't display line
1465     invalidateTopologyCache();
1466     lineHalfLength = h > 0 ? h : 0;
1467 }
getLineDisplayHalfLength()1468 Real getLineDisplayHalfLength() const {return lineHalfLength;}
1469 
setPointDisplayRadius(Real r)1470 void setPointDisplayRadius(Real r) {
1471     // r <= 0 means don't display point
1472     invalidateTopologyCache();
1473     pointRadius= r > 0 ? r : 0;
1474 }
getPointDisplayRadius()1475 Real getPointDisplayRadius() const {return pointRadius;}
1476 
1477 // Implementation of ContraintRep virtuals
realizeTopologyVirtual(State & s)1478 void realizeTopologyVirtual(State& s) const override {
1479     x = defaultLineDirection.perp(); // x and y are mutable
1480     y = UnitVec3(defaultLineDirection % x);
1481 }
1482 
1483 // Implementation of virtuals required for holonomic constraints.
1484 
1485 // We have a point-on-line connection between base body B, on which the line is
1486 // fixed, and follower body F, on which the follower point S is fixed. All
1487 // forces will be applied at point S and the coincident material point C on B
1488 // which is instantaneously at the same spatial location as S. Then z is a unit
1489 // vector in the direction of the line, and P is a point fixed to B that the
1490 // line passes through. We will enforce this using two point-on-plane
1491 // constraints, where the intersection of the two planes is the line. For that
1492 // we need two plane normals perpendicular to z. We'll use an arbitrary
1493 // perpendicular x, then use y=z X x as the other perpendicular. This
1494 // establishes a right handed coordinate system where the line is along the z
1495 // axis, and we'll apply constraint forces in the x-y plane.
1496 //
1497 // See the point-in-plane constraint for details; here we're just picking x and
1498 // y as plane normals.
1499 
1500 //    --------------------------------
1501 //    perr = ~(p_BS-p_BP) * x
1502 //           ~(p_BS-p_BP) * y
1503 //    --------------------------------
calcPositionErrorsVirtual(const State & s,const Array_<Transform,ConstrainedBodyIndex> & allX_AB,const Array_<Real,ConstrainedQIndex> & constrainedQ,Array_<Real> & perr)1504 void calcPositionErrorsVirtual
1505    (const State&                                    s,      // Stage::Time
1506     const Array_<Transform,ConstrainedBodyIndex>&   allX_AB,
1507     const Array_<Real,     ConstrainedQIndex>&      constrainedQ,
1508     Array_<Real>&                                   perr)   // mp of these
1509     const override
1510 {
1511     assert(allX_AB.size()==2 && constrainedQ.size()==0 && perr.size() == 2);
1512 
1513     const Transform& X_AB = getBodyTransform(allX_AB, lineBody);
1514     const Vec3       p_AS = findStationLocation(allX_AB, followerBody,
1515                                                 defaultFollowerPoint);
1516     const Vec3       p_BC = ~X_AB * p_AS; // shift to B origin, reexpress in B;
1517                                    // C is material point of B coincident with S
1518     const Vec3       p_PC = p_BC - defaultPointOnLine;
1519 
1520     // We'll calculate these two scalars using B-frame vectors, but any frame
1521     // would have done.
1522     perr[0] = ~p_PC * x;
1523     perr[1] = ~p_PC * y;
1524 }
1525 
1526 //    --------------------------------
1527 //    verr = ~v_CS_A*n
1528 //    --------------------------------
calcPositionDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allV_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDot,Array_<Real> & pverr)1529 void calcPositionDotErrorsVirtual
1530    (const State&                                    s,      // Stage::Position
1531     const Array_<SpatialVec,ConstrainedBodyIndex>&  allV_AB,
1532     const Array_<Real,      ConstrainedQIndex>&     constrainedQDot,
1533     Array_<Real>&                                   pverr)  // mp of these
1534     const override
1535 {
1536     assert(allV_AB.size()==2 && constrainedQDot.size()==0 && pverr.size() == 2);
1537     //TODO: should be able to get p info from State
1538     const Transform& X_AB = getBodyTransformFromState(s, lineBody);
1539     const Vec3       p_AS = findStationLocationFromState(s, followerBody,
1540                                                          defaultFollowerPoint);
1541     const Vec3       p_BC = ~X_AB * p_AS;
1542     const Vec3       p_PC = p_BC - defaultPointOnLine;
1543 
1544     const Vec3       v_AS = findStationVelocity(s, allV_AB, followerBody,
1545                                                 defaultFollowerPoint);
1546     const Vec3       v_AC = findStationVelocity(s, allV_AB, lineBody, p_BC);
1547 
1548     const Vec3       v_CS_B = ~X_AB.R()*(v_AS-v_AC); // reexpress in B
1549 
1550     // Calculate these scalar using B-frame vectors, but any frame would
1551     // have done.
1552     pverr[0] = ~v_CS_B * x;
1553     pverr[1] = ~v_CS_B * y;
1554 }
1555 
1556 //    -------------------------------------
1557 //    aerr = ~(a_CS_A - 2 w_AB X v_CS_A) * n
1558 //    -------------------------------------
calcPositionDotDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allA_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDotDot,Array_<Real> & paerr)1559 void calcPositionDotDotErrorsVirtual
1560    (const State&                                    s,      // Stage::Velocity
1561     const Array_<SpatialVec,ConstrainedBodyIndex>&  allA_AB,
1562     const Array_<Real,      ConstrainedQIndex>&     constrainedQDotDot,
1563     Array_<Real>&                                   paerr)  // mp of these
1564     const override
1565 {
1566     assert(allA_AB.size()==2 && constrainedQDotDot.size()==0 && paerr.size()==2);
1567     //TODO: should be able to get p and v info from State
1568     const Transform& X_AB = getBodyTransformFromState(s, lineBody);
1569     const Vec3       p_AS = findStationLocationFromState(s, followerBody,
1570                                                          defaultFollowerPoint);
1571     const Vec3       p_BC = ~X_AB * p_AS; // shift to B origin, reexpress in B;
1572                                  // C is material point of B coincident with S
1573     const Vec3       p_PC = p_BC - defaultPointOnLine;
1574 
1575     const Vec3&      w_AB = getBodyAngularVelocityFromState(s, lineBody);
1576     const Vec3       v_AS = findStationVelocityFromState(s, followerBody, defaultFollowerPoint);
1577     const Vec3       v_AC = findStationVelocityFromState(s, lineBody, p_BC);
1578 
1579     const Vec3       a_AS = findStationAcceleration(s, allA_AB, followerBody,
1580                                                     defaultFollowerPoint);
1581     const Vec3       a_AC = findStationAcceleration(s, allA_AB, lineBody, p_BC);
1582     const Vec3       a_CS_B = ~X_AB.R()*(a_AS-a_AC - 2 * w_AB % (v_AS-v_AC));
1583 
1584     // Calculate these scalar using B-frame vectors, but any frame would
1585     // have done.
1586     paerr[0] = ~a_CS_B * x;
1587     paerr[1] = ~a_CS_B * y;
1588 }
1589 
1590 // apply f=lambda0*x + lambda1*y to the follower point S of body F,
1591 //      -f                       to point C (coincident point) of body B
addInPositionConstraintForcesVirtual(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedQIndex> & qForces)1592 void addInPositionConstraintForcesVirtual
1593    (const State&                                    s,      // Stage::Position
1594     const Array_<Real>&                             multipliers, // mp of these
1595     Array_<SpatialVec,ConstrainedBodyIndex>&        bodyForcesInA,
1596     Array_<Real,      ConstrainedQIndex>&           qForces)
1597     const override
1598 {
1599     assert(multipliers.size()==2 && bodyForcesInA.size()==2
1600            && qForces.size()==0);
1601     const Vec2 lambda = Vec2::getAs(&multipliers[0]);
1602 
1603     //TODO: should be able to get p info from State
1604     const Transform& X_AB    = getBodyTransformFromState(s, lineBody);
1605     const Vec3&      p_FS    = defaultFollowerPoint; // measured & expressed in F
1606     const Vec3       p_AS    = findStationLocationFromState(s, followerBody,
1607                                                             defaultFollowerPoint);
1608     const Vec3       p_BC    = ~X_AB * p_AS;         // measured & expressed in B
1609 
1610     const Vec3       force_B = lambda[0] * x + lambda[1] * y;
1611     const Vec3       force_A = X_AB.R() * force_B;
1612 
1613     addInStationForce(s, followerBody, p_FS,  force_A, bodyForcesInA);
1614     addInStationForce(s, lineBody,     p_BC, -force_A, bodyForcesInA);
1615 }
1616 
1617 SimTK_DOWNCAST(PointOnLineImpl, ConstraintImpl);
1618 //------------------------------------------------------------------------------
1619                                     private:
1620 friend class Constraint::PointOnLine;
1621 
1622 ConstrainedBodyIndex    lineBody;     // B
1623 ConstrainedBodyIndex    followerBody; // F
1624 
1625 UnitVec3                defaultLineDirection;   // z on B, exp. in B frame
1626 Vec3                    defaultPointOnLine;     // P on B, meas&exp in B frame
1627 Vec3                    defaultFollowerPoint;   // S on F, meas&exp in F frame
1628 
1629 // These are just for visualization
1630 Real                    lineHalfLength;
1631 Real                    pointRadius;
1632 
1633 // TOPOLOGY CACHE (that is, calculated from construction data)
1634 mutable UnitVec3        x, y;
1635 };
1636 
1637 
1638 
1639 //==============================================================================
1640 //                           CONSTANT ANGLE IMPL
1641 //==============================================================================
1642 class Constraint::ConstantAngleImpl : public ConstraintImpl {
1643 public:
ConstantAngleImpl()1644 ConstantAngleImpl()
1645     : ConstraintImpl(1,0,0), defaultAxisB(), defaultAxisF(), defaultAngle(Pi/2),
1646     axisLength(1), axisThickness(1), cosineOfDefaultAngle(NaN)
1647 { }
clone()1648 ConstantAngleImpl* clone() const override { return new ConstantAngleImpl(*this); }
1649 
1650 void calcDecorativeGeometryAndAppendVirtual
1651     (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const override;
1652 
setAxisLength(Real length)1653 void setAxisLength(Real length) {
1654     // length <= 0 means don't display axis
1655     invalidateTopologyCache();
1656     axisLength = length > 0 ? length : 0;
1657 }
getAxisLength()1658 Real getAxisLength() const {return axisLength;}
1659 
setAxisThickness(Real t)1660 void setAxisThickness(Real t) {
1661     // t <= 0 means don't display axis
1662     invalidateTopologyCache();
1663     axisThickness = t > 0 ? t : 0;
1664 }
getAxisThickness()1665 Real getAxisThickness() const {return axisThickness;}
1666 
1667 // Implementation of ContraintRep virtuals
realizeTopologyVirtual(State & s)1668 void realizeTopologyVirtual(State& s) const override {
1669     cosineOfDefaultAngle = std::cos(defaultAngle);
1670 }
1671 
1672 
1673 // Implementation of virtuals required for holonomic constraints.
1674 
1675 // Let B=B1 be the "base" body onto which unit vector b is fixed, and F=B2 the
1676 // "follower" body onto which unit vector f is fixed. The angle theta between
1677 // these vectors is given by cos(theta) = dot(b, f) with the axes expressed in
1678 // a common basis. This can range from 1 to -1, corresponding to angles 0 to
1679 // 180 respectively. We would like to enforce the constraint that cos(theta) is
1680 // a constant. This can be done with a single constraint equation as long as
1681 // theta is sufficiently far away from 0 and 180, with the numerically best
1682 // performance at theta=90 degrees where cos(theta)==0.
1683 //
1684 // If you want to enforce that two axes are aligned with one another (that is,
1685 // the angle between them is 0 or 180), that takes *two* constraint equations
1686 // since the only remaining rotation is about the common axis.
1687 //
1688 // We will work in the A frame.
1689 //
1690 // ------------------------------
1691 // perr = ~b_A * f_A - cos(theta)
1692 // ------------------------------
1693 //
1694 // verr = d/dt perr (derivative taken in A)
1695 //      = ~b_A * (w_AF % f_A) + ~f_A * (w_AB % b_A)
1696 //      = ~w_AF * (f_A % b_A) - ~w_AB * (f_A % b_A)  (scalar triple product identity)
1697 // => ------------------------------
1698 // verr = ~(w_AF-w_AB) * (f_A % b_A)
1699 // ---------------------------------
1700 //
1701 // aerr = d/dt verr (derivative taken in A)
1702 //      = ~(b_AF-b_AB) * (f_A % b_A)
1703 //        + (w_AF-w_AB) * ((w_AF%f_A) % b_A)
1704 //        + (w_AF-w_AB) * (f_A % (w_AB%b_A))
1705 //      =   ~(b_AF-b_AB) * (f_A % b_A)
1706 //        + ~(w_AF-w_AB) * ((w_AF%f_A) % b_A) - (w_AB%b_A) % f_A)
1707 // => -----------------------------------------------------------
1708 // aerr =   ~(b_AF-b_AB) * (f_A % b_A)
1709 //        + ~(w_AF-w_AB) * ((w_AF%f_A) % b_A) - (w_AB%b_A) % f_A)
1710 // --------------------------------------------------------------
1711 //
1712 // Constraint torque can be determined by inspection of verr:
1713 //    lambda * (f_A % b_A) applied to body F
1714 //   -lambda * (f_A % b_A) applied to body B
1715 //
1716 
1717 // ------------------------------
1718 // perr = ~b_A * f_A - cos(theta)
1719 // ------------------------------
calcPositionErrorsVirtual(const State & s,const Array_<Transform,ConstrainedBodyIndex> & allX_AB,const Array_<Real,ConstrainedQIndex> & constrainedQ,Array_<Real> & perr)1720 void calcPositionErrorsVirtual
1721    (const State&                                    s,      // Stage::Time
1722     const Array_<Transform,ConstrainedBodyIndex>&   allX_AB,
1723     const Array_<Real,     ConstrainedQIndex>&      constrainedQ,
1724     Array_<Real>&                                   perr)   // mp of these
1725     const override
1726 {
1727     assert(allX_AB.size()==2 && constrainedQ.size()==0 && perr.size() == 1);
1728 
1729     const Rotation& R_AB = getBodyRotation(allX_AB, B);
1730     const Rotation& R_AF = getBodyRotation(allX_AB, F);
1731     const UnitVec3  b_A  = R_AB * defaultAxisB;
1732     const UnitVec3  f_A  = R_AF * defaultAxisF;
1733 
1734     perr[0] = dot(b_A, f_A) - cosineOfDefaultAngle;
1735 }
1736 
1737 // ----------------------------------
1738 // pverr = ~(w_AF-w_AB) * (f_A % b_A)
1739 // ----------------------------------
calcPositionDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allV_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDot,Array_<Real> & pverr)1740 void calcPositionDotErrorsVirtual
1741    (const State&                                    s,      // Stage::Position
1742     const Array_<SpatialVec,ConstrainedBodyIndex>&  allV_AB,
1743     const Array_<Real,      ConstrainedQIndex>&     constrainedQDot,
1744     Array_<Real>&                                   pverr)  // mp of these
1745     const override
1746 {
1747     assert(allV_AB.size()==2 && constrainedQDot.size()==0 && pverr.size()==1);
1748     //TODO: should be able to get p info from State
1749     const Rotation& R_AB = getBodyRotationFromState(s, B);
1750     const Rotation& R_AF = getBodyRotationFromState(s, F);
1751     const UnitVec3  b_A  = R_AB * defaultAxisB;
1752     const UnitVec3  f_A  = R_AF * defaultAxisF;
1753 
1754     const Vec3&     w_AB = getBodyAngularVelocity(allV_AB, B);
1755     const Vec3&     w_AF = getBodyAngularVelocity(allV_AB, F);
1756 
1757     pverr[0] = dot( w_AF-w_AB,  f_A % b_A );
1758 }
1759 
1760 // --------------------------------------------------------------
1761 // paerr =  ~(b_AF-b_AB) * (f_A % b_A)
1762 //        + ~(w_AF-w_AB) * ((w_AF%f_A) % b_A) - (w_AB%b_A) % f_A)
1763 // --------------------------------------------------------------
calcPositionDotDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allA_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDotDot,Array_<Real> & paerr)1764 void calcPositionDotDotErrorsVirtual
1765    (const State&                                    s,      // Stage::Velocity
1766     const Array_<SpatialVec,ConstrainedBodyIndex>&  allA_AB,
1767     const Array_<Real,      ConstrainedQIndex>&     constrainedQDotDot,
1768     Array_<Real>&                                   paerr)  // mp of these
1769     const override
1770 {
1771     assert(allA_AB.size()==2 && constrainedQDotDot.size()==0 && paerr.size()==1);
1772     //TODO: should be able to get p and v info from State
1773     const Rotation& R_AB = getBodyRotationFromState(s, B);
1774     const Rotation& R_AF = getBodyRotationFromState(s, F);
1775     const UnitVec3  b_A  = R_AB * defaultAxisB;
1776     const UnitVec3  f_A  = R_AF * defaultAxisF;
1777     const Vec3&     w_AB = getBodyAngularVelocityFromState(s, B);
1778     const Vec3&     w_AF = getBodyAngularVelocityFromState(s, F);
1779 
1780     const Vec3&     b_AB = getBodyAngularAcceleration(allA_AB, B);
1781     const Vec3&     b_AF = getBodyAngularAcceleration(allA_AB, F);
1782 
1783     paerr[0] =    dot( b_AF-b_AB, f_A % b_A )
1784                 + dot( w_AF-w_AB, (w_AF%f_A) % b_A - (w_AB%b_A) % f_A);
1785 }
1786 
1787 //    lambda * (f_A % b_A) applied to body F
1788 //   -lambda * (f_A % b_A) applied to body B
addInPositionConstraintForcesVirtual(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedQIndex> & qForces)1789 void addInPositionConstraintForcesVirtual
1790    (const State&                                    s,      // Stage::Position
1791     const Array_<Real>&                             multipliers, // mp of these
1792     Array_<SpatialVec,ConstrainedBodyIndex>&        bodyForcesInA,
1793     Array_<Real,      ConstrainedQIndex>&           qForces)
1794     const override
1795 {
1796     assert(multipliers.size()==1 && bodyForcesInA.size()==2
1797            && qForces.size()==0);
1798     const Real lambda = multipliers[0];
1799     //TODO: should be able to get p info from State
1800     const Rotation&  R_AB = getBodyRotationFromState(s, B);
1801     const Rotation&  R_AF = getBodyRotationFromState(s, F);
1802     const UnitVec3   b_A = R_AB*defaultAxisB;
1803     const UnitVec3   f_A = R_AF*defaultAxisF;
1804     const Vec3       torque_F_A = lambda * (f_A % b_A); // on F, in A frame
1805 
1806     addInBodyTorque(s, F,  torque_F_A, bodyForcesInA);
1807     addInBodyTorque(s, B, -torque_F_A, bodyForcesInA);
1808 }
1809 
1810 SimTK_DOWNCAST(ConstantAngleImpl, ConstraintImpl);
1811 //------------------------------------------------------------------------------
1812                                     private:
1813 friend class Constraint::ConstantAngle;
1814 
1815 ConstrainedBodyIndex    B; // B1 is "base" body
1816 ConstrainedBodyIndex    F; // B2 is "follower" body
1817 
1818 UnitVec3                defaultAxisB; // fixed to B, expressed in B frame
1819 UnitVec3                defaultAxisF; // fixed to F, expressed in F frame
1820 Real                    defaultAngle; // required angle between axisB and axisF
1821 
1822 // These are just for visualization
1823 Real                    axisLength;
1824 Real                    axisThickness;
1825 
1826 // TOPOLOGY CACHE (that is, calculated from construction data)
1827 mutable Real            cosineOfDefaultAngle;
1828 };
1829 
1830 
1831 
1832 //==============================================================================
1833 //                                 BALL IMPL
1834 //==============================================================================
1835 class Constraint::BallImpl : public ConstraintImpl {
1836 public:
BallImpl()1837 BallImpl() : ConstraintImpl(3,0,0), defaultPoint1(0), defaultPoint2(0),
1838              defaultRadius(Real(0.1)) { }
clone()1839 BallImpl* clone() const override { return new BallImpl(*this); }
1840 
1841 void calcDecorativeGeometryAndAppendVirtual
1842     (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const override;
1843 
setDefaultRadius(Real r)1844 void setDefaultRadius(Real r) {
1845     // r <= 0 means don't display
1846     invalidateTopologyCache();
1847     defaultRadius = r > 0 ? r : 0;
1848 }
getDefaultRadius()1849 Real getDefaultRadius() const {return defaultRadius;}
1850 
1851 // The default body stations may be overridden by setting instance variables
1852 // in the state. We allocate the state resources here.
1853 void realizeTopologyVirtual(State& state) const override;
1854 
1855 // Return the pair of constrained station points, with the first expressed
1856 // in the body 1 frame and the second in the body 2 frame. Note that although
1857 // these are used to define the position error, only the station on body 2
1858 // is used to generate constraint forces; the point of body 1 that is
1859 // coincident with the body 2 point receives the equal and opposite force.
1860 const std::pair<Vec3,Vec3>& getBodyStations(const State& state) const;
1861 
1862 // Return a writable reference into the Instance-stage state variable
1863 // containing the pair of constrained station points, with the first expressed
1864 // in the body 1 frame and the second in the body 2 frame. Calling this
1865 // method invalidates the Instance stage and above in the given state.
1866 std::pair<Vec3,Vec3>& updBodyStations(State& state) const;
1867 
1868 // Implementation of virtuals required for holonomic constraints.
1869 
1870 // We have a ball joint between base body B and follower body F, located at a
1871 // point P fixed to B and point S fixed on F. All forces will be applied at
1872 // point S and the coincident material point C on B which is instantaneously at
1873 // the same spatial location as S. We will work in the A frame.
1874 //
1875 //  First, find the material point C of B that is coincident
1876 //  in space with point S of F: p_BC = p_AS-p_AB. This vector
1877 //  is *constant* in the B frame because it is a material point,
1878 //  despite the fact that its definition involves a point which
1879 //  moves with respect to B. The velocity constraint is then
1880 //  very simple: the spatial velocity of point C of B should be
1881 //  the same as the spatial velocity of point S of F:
1882 //      verr = v_AS - v_AC = v_AS - (v_AB + w_AB X p_BC) = 0
1883 //  Integrating to get perr, we get
1884 //      perr = p_AS - p_AC + constant = 0
1885 //  But p_AC=p_AS by construction, so perr=constant=0.
1886 //  The constant is defined by the fact that we want material point
1887 //  C of B to be in the same spatial location as point P of B,
1888 //  so constant=p_BC-p_BP=0. Writing in the A frame we have:
1889 //      perr = p_AS-(p_AB+R_AB*p_BP) = 0 (a constant)
1890 //      verr = v_AS - (v_AB + w_AB X R_AB*p_BC)
1891 //      aerr = a_AS - (a_AB + b_AB X R_AB*p_BC + w_AB X (w_AB X R_AB*p_BC))
1892 //  apply +lambda to S of F, -lambda to C of B.
1893 //
1894 //
1895 
calcPositionErrorsVirtual(const State & s,const Array_<Transform,ConstrainedBodyIndex> & allX_AB,const Array_<Real,ConstrainedQIndex> & constrainedQ,Array_<Real> & perr)1896 void calcPositionErrorsVirtual
1897    (const State&                                    s,      // Stage::Time
1898     const Array_<Transform,ConstrainedBodyIndex>&   allX_AB,
1899     const Array_<Real,     ConstrainedQIndex>&      constrainedQ,
1900     Array_<Real>&                                   perr)   // mp of these
1901     const override
1902 {
1903     assert(allX_AB.size()==2 && constrainedQ.size()==0 && perr.size() == 3);
1904 
1905     const std::pair<Vec3,Vec3>& pts = getBodyStations(s);
1906 
1907     const Vec3 p_AP = findStationLocation(allX_AB, B1, pts.first);
1908     const Vec3 p_AS = findStationLocation(allX_AB, B2, pts.second);
1909 
1910     // See above comments -- this is just the constant of integration; there is a missing (p_AS-p_AC)
1911     // term (always 0) here which is what we differentiate to get the verr equation.
1912     Vec3::updAs(&perr[0]) = p_AS - p_AP;
1913 }
1914 
calcPositionDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allV_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDot,Array_<Real> & pverr)1915 void calcPositionDotErrorsVirtual
1916    (const State&                                    s,      // Stage::Position
1917     const Array_<SpatialVec,ConstrainedBodyIndex>&  allV_AB,
1918     const Array_<Real,      ConstrainedQIndex>&     constrainedQDot,
1919     Array_<Real>&                                   pverr)  // mp of these
1920     const override
1921 {
1922     assert(allV_AB.size()==2 && constrainedQDot.size()==0 && pverr.size()==3);
1923 
1924     // Note that we're not using point1.
1925     const Vec3& point2 = getBodyStations(s).second;
1926 
1927     //TODO: should be able to get p info from State
1928     const Transform&  X_AB   = getBodyTransformFromState(s, B1);
1929     const Vec3        p_AS   = findStationLocationFromState(s, B2, point2);
1930     const Vec3        p_BC   = ~X_AB*p_AS; // C is a material point of body B
1931 
1932     const Vec3        v_AS    = findStationVelocity(s, allV_AB, B2,
1933                                                     point2);
1934     const Vec3        v_AC    = findStationVelocity(s, allV_AB, B1, p_BC);
1935     Vec3::updAs(&pverr[0]) = v_AS - v_AC;
1936 }
1937 
calcPositionDotDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allA_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDotDot,Array_<Real> & paerr)1938 void calcPositionDotDotErrorsVirtual
1939    (const State&                                    s,      // Stage::Velocity
1940     const Array_<SpatialVec,ConstrainedBodyIndex>&  allA_AB,
1941     const Array_<Real,      ConstrainedQIndex>&     constrainedQDotDot,
1942     Array_<Real>&                                   paerr)  // mp of these
1943     const override
1944 {
1945     assert(allA_AB.size()==2 && constrainedQDotDot.size()==0 && paerr.size()==3);
1946 
1947     // Note that we're not using point1.
1948     const Vec3& point2 = getBodyStations(s).second;
1949 
1950     //TODO: should be able to get p and v info from State
1951 
1952     const Transform&  X_AB   = getBodyTransformFromState(s, B1);
1953     const Vec3        p_AS   = findStationLocationFromState(s, B2, point2);
1954     const Vec3        p_BC   = ~X_AB*p_AS; // C is a material point of body B
1955 
1956     const Vec3        a_AS    = findStationAcceleration(s, allA_AB, B2,
1957                                                         point2);
1958     const Vec3        a_AC    = findStationAcceleration(s, allA_AB, B1, p_BC);
1959     Vec3::updAs(&paerr[0]) = a_AS - a_AC;
1960 }
1961 
addInPositionConstraintForcesVirtual(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedQIndex> & qForces)1962 void addInPositionConstraintForcesVirtual
1963    (const State&                                    s,      // Stage::Position
1964     const Array_<Real>&                             multipliers, // mp of these
1965     Array_<SpatialVec,ConstrainedBodyIndex>&        bodyForcesInA,
1966     Array_<Real,      ConstrainedQIndex>&           qForces)
1967     const override
1968 {
1969     assert(multipliers.size()==3 && bodyForcesInA.size()==2
1970            && qForces.size()==0);
1971 
1972     // Note that we're not using point1.
1973     const Vec3& point2 = getBodyStations(s).second;
1974 
1975     //TODO: should be able to get p info from State
1976     const Transform& X_AB  = getBodyTransformFromState(s,B1);
1977     const Vec3&      p_FS  = point2;
1978     const Vec3       p_AS  = findStationLocationFromState(s, B2, p_FS);
1979     const Vec3       p_BC = ~X_AB * p_AS; // shift to B origin, reexpress in B;
1980                                   // C is material point of B coincident with S
1981 
1982     const Vec3 force_A = Vec3::getAs(&multipliers[0]);
1983 
1984     // Multipliers are force to be applied to S on F, but
1985     // apply the -force not to point P of B, but to the point "C" of B
1986     // coincident with S, which won't be exactly the same place
1987     // as P if the position-level constraint isn't met exactly.
1988 
1989     addInStationForce(s, B2, p_FS,  force_A, bodyForcesInA);
1990     addInStationForce(s, B1, p_BC, -force_A, bodyForcesInA);
1991 }
1992 
1993 SimTK_DOWNCAST(BallImpl, ConstraintImpl);
1994 //------------------------------------------------------------------------------
1995                                     private:
1996 friend class Constraint::Ball;
1997 
1998 ConstrainedBodyIndex    B1;
1999 ConstrainedBodyIndex    B2;
2000 
2001 Vec3                    defaultPoint1; // on body 1, exp. in B1 frame
2002 Vec3                    defaultPoint2; // on body 2, exp. in B2 frame
2003 Real                    defaultRadius; // used for visualization only
2004 
2005 // This Instance-stage variable holds the actual stations on B1 & B2.
2006 mutable DiscreteVariableIndex   stationsIx;
2007 };
2008 
2009 
2010 
2011 //==============================================================================
2012 //                          CONSTANT ORIENTATION IMPL
2013 //==============================================================================
2014 class Constraint::ConstantOrientationImpl : public ConstraintImpl {
2015 public:
ConstantOrientationImpl()2016 ConstantOrientationImpl()
2017     : ConstraintImpl(3,0,0), defaultRB(), defaultRF()
2018 { }
clone()2019 ConstantOrientationImpl* clone() const override { return new ConstantOrientationImpl(*this); }
2020 
2021 //TODO: visualization?
2022 
2023 
2024 // Implementation of virtuals required for holonomic constraints.
2025 
2026 // Let B=B1 be the "base" body onto which rotation matrix RB is fixed, and F=B2
2027 // the "follower" body onto which rotation matrix RF is fixed. We would like to
2028 // enforce the constraint that RB==RF when both are expressed in a common basis.
2029 // (Remember that a rotation matrix is just three axis vectors.)
2030 //
2031 // Here the (redundant) assembly constraint is that all the axes are parallel,
2032 // that is RBx==RFx, RBy==RFy, and RBz==RFz. However, aligning two vectors
2033 // takes *two* constraints so that would be a total of 6 constraints, with only
2034 // 3 independent. The independent runtime constraints just enforce
2035 // perpendicularity, but can be satisfied in cases where some of the axes are
2036 // antiparallel so are not suited for the initial assembly. The runtime
2037 // constraints are thus three "constant angle" constraints, where the angle
2038 // is always 90 degrees:
2039 //
2040 //    ~RFx * RBy = 0
2041 //    ~RFy * RBz = 0
2042 //    ~RFz * RBx = 0
2043 //
2044 // We'll work in A. See the "constant angle" constraint for details.
2045 //
2046 // -----------------
2047 // perr = ~RFx * RBy  (with all axes expressed in A)
2048 //        ~RFy * RBz
2049 //        ~RFz * RBx
2050 // -----------------
2051 //
2052 // ---------------------------------
2053 // verr = ~(w_AF-w_AB) * (RFx % RBy)
2054 //      = ~(w_AF-w_AB) * (RFy % RBz)
2055 //      = ~(w_AF-w_AB) * (RFz % RBx)
2056 // ---------------------------------
2057 //
2058 // -----------------------------------------------------------------------
2059 // aerr = ~(b_AF-b_AB) * (RFx % RBy)
2060 //                 + ~(w_AF-w_AB) * ((w_AF%RFx) % RBy) - (w_AB%RBy) % RFx)
2061 //        ~(b_AF-b_AB) * (RFy % RBz)
2062 //                 + ~(w_AF-w_AB) * ((w_AF%RFy) % RBz) - (w_AB%RBz) % RFy)
2063 //        ~(b_AF-b_AB) * (RFz % RBx)
2064 //                 + ~(w_AF-w_AB) * ((w_AF%RFz) % RBx) - (w_AB%RBx) % RFz)
2065 // -----------------------------------------------------------------------
2066 //
2067 // Constraint torque can be determined by inspection of verr:
2068 //    t_F =   lambda_x * (RFx % RBy)   (applied to body F)
2069 //          + lambda_y * (RFy % RBz)
2070 //          + lambda_z * (RFz % RBx)
2071 //    t_B = -t_F                       (applied to body B)
2072 //
2073 
2074 // -----------------
2075 // perr = ~RFx * RBy  (with all axes expressed in A)
2076 //        ~RFy * RBz
2077 //        ~RFz * RBx
2078 // -----------------
calcPositionErrorsVirtual(const State & s,const Array_<Transform,ConstrainedBodyIndex> & allX_AB,const Array_<Real,ConstrainedQIndex> & constrainedQ,Array_<Real> & perr)2079 void calcPositionErrorsVirtual
2080    (const State&                                    s,      // Stage::Time
2081     const Array_<Transform,ConstrainedBodyIndex>&   allX_AB,
2082     const Array_<Real,     ConstrainedQIndex>&      constrainedQ,
2083     Array_<Real>&                                   perr)   // mp of these
2084     const override
2085 {
2086     assert(allX_AB.size()==2 && constrainedQ.size()==0 && perr.size()==3);
2087 
2088     const Rotation& R_AB = getBodyRotation(allX_AB, B);
2089     const Rotation& R_AF = getBodyRotation(allX_AB, F);
2090     const Rotation  RB = R_AB * defaultRB; // now expressed in A
2091     const Rotation  RF = R_AF * defaultRF;
2092 
2093     Vec3::updAs(&perr[0]) = Vec3(~RF.x()*RB.y(),
2094                                  ~RF.y()*RB.z(),
2095                                  ~RF.z()*RB.x());
2096 }
2097 
2098 // ----------------------------------
2099 // verr = ~(w_AF-w_AB) * (RFx % RBy)
2100 //      = ~(w_AF-w_AB) * (RFy % RBz)
2101 //      = ~(w_AF-w_AB) * (RFz % RBx)
2102 // ----------------------------------
calcPositionDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allV_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDot,Array_<Real> & pverr)2103 void calcPositionDotErrorsVirtual
2104    (const State&                                    s,      // Stage::Position
2105     const Array_<SpatialVec,ConstrainedBodyIndex>&  allV_AB,
2106     const Array_<Real,      ConstrainedQIndex>&     constrainedQDot,
2107     Array_<Real>&                                   pverr)  // mp of these
2108     const override
2109 {
2110     assert(allV_AB.size()==2 && constrainedQDot.size()==0 && pverr.size()==3);
2111     //TODO: should be able to get p info from State
2112     const Rotation& R_AB = getBodyRotationFromState(s, B);
2113     const Rotation& R_AF = getBodyRotationFromState(s, F);
2114     const Rotation  RB = R_AB * defaultRB; // now expressed in A
2115     const Rotation  RF = R_AF * defaultRF;
2116 
2117     const Vec3&     w_AB = getBodyAngularVelocity(allV_AB, B);
2118     const Vec3&     w_AF = getBodyAngularVelocity(allV_AB, F);
2119     const Vec3      w_BF = w_AF-w_AB; // in A
2120 
2121     Vec3::updAs(&pverr[0]) = Vec3( ~w_BF * (RF.x() % RB.y()),
2122                                    ~w_BF * (RF.y() % RB.z()),
2123                                    ~w_BF * (RF.z() % RB.x()) );
2124 }
2125 
2126 //------------------------------------------------------------------------
2127 // aerr = ~(b_AF-b_AB) * (RFx % RBy)
2128 //                 + ~(w_AF-w_AB) * ((w_AF%RFx) % RBy) - (w_AB%RBy) % RFx)
2129 //        ~(b_AF-b_AB) * (RFy % RBz)
2130 //                 + ~(w_AF-w_AB) * ((w_AF%RFy) % RBz) - (w_AB%RBz) % RFy)
2131 //        ~(b_AF-b_AB) * (RFz % RBx)
2132 //                 + ~(w_AF-w_AB) * ((w_AF%RFz) % RBx) - (w_AB%RBx) % RFz)
2133 //------------------------------------------------------------------------
calcPositionDotDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allA_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDotDot,Array_<Real> & paerr)2134 void calcPositionDotDotErrorsVirtual
2135    (const State&                                    s,      // Stage::Velocity
2136     const Array_<SpatialVec,ConstrainedBodyIndex>&  allA_AB,
2137     const Array_<Real,      ConstrainedQIndex>&     constrainedQDotDot,
2138     Array_<Real>&                                   paerr)  // mp of these
2139     const override
2140 {
2141     assert(allA_AB.size()==2 && constrainedQDotDot.size()==0 && paerr.size()==3);
2142     //TODO: should be able to get p and v info from State
2143     const Rotation& R_AB = getBodyRotationFromState(s, B);
2144     const Rotation& R_AF = getBodyRotationFromState(s, F);
2145     const Rotation  RB = R_AB * defaultRB; // now expressed in A
2146     const Rotation  RF = R_AF * defaultRF;
2147 
2148     const Vec3&     w_AB = getBodyAngularVelocityFromState(s, B);
2149     const Vec3&     w_AF = getBodyAngularVelocityFromState(s, F);
2150     const Vec3      w_BF = w_AF-w_AB; // in A
2151 
2152     const Vec3&     b_AB = getBodyAngularAcceleration(allA_AB, B);
2153     const Vec3&     b_AF = getBodyAngularAcceleration(allA_AB, F);
2154     const Vec3      b_BF = b_AF-b_AB; // in A
2155 
2156     Vec3::updAs(&paerr[0]) =
2157         Vec3( dot( b_BF, RF.x() % RB.y() )
2158                   + dot( w_BF, (w_AF%RF.x()) % RB.y() - (w_AB%RB.y()) % RF.x()),
2159               dot( b_BF, RF.y() % RB.z() )
2160                   + dot( w_BF, (w_AF%RF.y()) % RB.z() - (w_AB%RB.z()) % RF.y()),
2161               dot( b_BF, RF.z() % RB.x() )
2162                   + dot( w_BF, (w_AF%RF.z()) % RB.x() - (w_AB%RB.x()) % RF.z()));
2163 }
2164 
2165 //    t_F =   lambda_x * (RFx % RBy)   (applied to body F)
2166 //          + lambda_y * (RFy % RBz)
2167 //          + lambda_z * (RFz % RBx)
2168 //    t_B = -t_F                       (applied to body B)
addInPositionConstraintForcesVirtual(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedQIndex> & qForces)2169 void addInPositionConstraintForcesVirtual
2170    (const State&                                    s,      // Stage::Position
2171     const Array_<Real>&                             multipliers, // mp of these
2172     Array_<SpatialVec,ConstrainedBodyIndex>&        bodyForcesInA,
2173     Array_<Real,      ConstrainedQIndex>&           qForces)
2174     const override
2175 {
2176     assert(multipliers.size()==3 && bodyForcesInA.size()==2
2177            && qForces.size()==0);
2178     const Vec3& lambda = Vec3::getAs(&multipliers[0]);
2179 
2180     //TODO: should be able to get p info from State
2181     const Rotation& R_AB = getBodyRotationFromState(s, B);
2182     const Rotation& R_AF = getBodyRotationFromState(s, F);
2183     const Rotation  RB = R_AB * defaultRB; // now expressed in A
2184     const Rotation  RF = R_AF * defaultRF;
2185 
2186     const Vec3 torque_F_A =   lambda[0] * (RF.x() % RB.y())
2187                             + lambda[1] * (RF.y() % RB.z())
2188                             + lambda[2] * (RF.z() % RB.x());
2189 
2190     addInBodyTorque(s, F,  torque_F_A, bodyForcesInA);
2191     addInBodyTorque(s, B, -torque_F_A, bodyForcesInA);
2192 }
2193 
2194 SimTK_DOWNCAST(ConstantOrientationImpl, ConstraintImpl);
2195 //------------------------------------------------------------------------------
2196                                     private:
2197 friend class Constraint::ConstantOrientation;
2198 
2199 ConstrainedBodyIndex    B; // B1 is "base" body
2200 ConstrainedBodyIndex    F; // B2 is "follower" body
2201 
2202 Rotation    defaultRB; // fixed to B, expressed in B frame; RB = R_B_RB
2203 Rotation    defaultRF; // fixed to F, expressed in F frame; RF = R_F_RF
2204 };
2205 
2206 
2207 
2208 //==============================================================================
2209 //                               WELD IMPL
2210 //==============================================================================
2211 class Constraint::WeldImpl : public ConstraintImpl {
getDefaultAxisDisplayLength()2212 static Real getDefaultAxisDisplayLength() {return 1;}
getDefaultFrameColor(int which)2213 static Vec3 getDefaultFrameColor(int which) {
2214     return which==0 ? Blue : Purple;
2215 }
2216 public:
WeldImpl()2217 WeldImpl()
2218     : ConstraintImpl(6,0,0), axisDisplayLength(-1), // means "use default axis length"
2219     frameBColor(-1), frameFColor(-1) // means "use default colors"
2220 {   // default Transforms are identity, i.e. body frames
2221 }
clone()2222 WeldImpl* clone() const override { return new WeldImpl(*this); }
2223 
2224 // Draw the two frames.
2225 void calcDecorativeGeometryAndAppendVirtual
2226     (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const override;
2227 
setAxisDisplayLength(Real len)2228 void setAxisDisplayLength(Real len) {
2229     // len == 0 means "don't display"
2230     // len < 0 means "use default"
2231     invalidateTopologyCache();
2232     axisDisplayLength = len >= 0 ? len : -1;
2233 }
getAxisDisplayLength()2234 Real getAxisDisplayLength() const {
2235     return axisDisplayLength < 0 ? getDefaultAxisDisplayLength() : axisDisplayLength;
2236 }
2237 
setFrameColor(int which,const Vec3 & color)2238 void setFrameColor(int which, const Vec3& color) {
2239     assert(which==0 || which==1);
2240     // color[0] < 0 means "use default color for this frame"
2241     invalidateTopologyCache();
2242     if (which==0) frameBColor = color[0] < 0 ? Vec3(-1) : color;
2243     else          frameFColor = color[0] < 0 ? Vec3(-1) : color;
2244 }
getFrameColor(int which)2245 Vec3 getFrameColor(int which) const {
2246     assert(which==0 || which==1);
2247     if (which==0) return frameBColor[0] < 0 ? getDefaultFrameColor(0) : frameBColor;
2248     else          return frameFColor[0] < 0 ? getDefaultFrameColor(1) : frameFColor;
2249 }
2250 
2251 // Implementation of virtuals required for holonomic constraints.
2252 
2253 // For theory, look at the ConstantOrientation (1st 3 equations) and
2254 // Ball (last 3 equations) theory above. Otherwise just lay back and
2255 // enjoy the ride.
2256 
calcPositionErrorsVirtual(const State & s,const Array_<Transform,ConstrainedBodyIndex> & allX_AB,const Array_<Real,ConstrainedQIndex> & constrainedQ,Array_<Real> & perr)2257 void calcPositionErrorsVirtual
2258    (const State&                                    s,      // Stage::Time
2259     const Array_<Transform,ConstrainedBodyIndex>&   allX_AB,
2260     const Array_<Real,     ConstrainedQIndex>&      constrainedQ,
2261     Array_<Real>&                                   perr)   // mp of these
2262     const override
2263 {
2264     assert(allX_AB.size()==2 && constrainedQ.size()==0 && perr.size()==6);
2265 
2266     const Rotation& R_AB = getBodyRotation(allX_AB, B);
2267     const Rotation& R_AF = getBodyRotation(allX_AB, F);
2268     const Rotation  RB = R_AB * defaultFrameB.R(); // now expressed in A
2269     const Rotation  RF = R_AF * defaultFrameF.R();
2270 
2271     // Orientation error
2272     Vec3::updAs(&perr[0]) = Vec3(~RF.x()*RB.y(),
2273                                  ~RF.y()*RB.z(),
2274                                  ~RF.z()*RB.x());
2275 
2276     const Vec3 p_AF1 = findStationLocation(allX_AB, B, defaultFrameB.p());
2277     const Vec3 p_AF2 = findStationLocation(allX_AB, F, defaultFrameF.p());
2278 
2279     // position error
2280     Vec3::updAs(&perr[3]) = p_AF2 - p_AF1;
2281 }
2282 
calcPositionDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allV_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDot,Array_<Real> & pverr)2283 void calcPositionDotErrorsVirtual
2284    (const State&                                    s,      // Stage::Position
2285     const Array_<SpatialVec,ConstrainedBodyIndex>&  allV_AB,
2286     const Array_<Real,      ConstrainedQIndex>&     constrainedQDot,
2287     Array_<Real>&                                   pverr)  // mp of these
2288     const override
2289 {
2290     assert(allV_AB.size()==2 && constrainedQDot.size()==0 && pverr.size()==6);
2291     //TODO: should be able to get p info from State
2292     const Rotation& R_AB = getBodyRotationFromState(s, B);
2293     const Rotation& R_AF = getBodyRotationFromState(s, F);
2294     const Rotation  RB = R_AB * defaultFrameB.R(); // now expressed in A
2295     const Rotation  RF = R_AF * defaultFrameF.R();
2296 
2297     const Vec3&     w_AB = getBodyAngularVelocity(allV_AB, B);
2298     const Vec3&     w_AF = getBodyAngularVelocity(allV_AB, F);
2299     const Vec3      w_BF = w_AF-w_AB; // in A
2300 
2301     // orientation error
2302     Vec3::updAs(&pverr[0]) = Vec3( ~w_BF * (RF.x() % RB.y()),
2303                                    ~w_BF * (RF.y() % RB.z()),
2304                                    ~w_BF * (RF.z() % RB.x()) );
2305 
2306     //TODO: should be able to get p info from State
2307     const Transform&  X_AB   = getBodyTransformFromState(s, B);
2308     const Vec3        p_AF2  = findStationLocationFromState(s, F,
2309                                                             defaultFrameF.p());
2310     const Vec3        p_BC   = ~X_AB*p_AF2; // C is a material point of body B
2311 
2312     const Vec3        v_AF2  = findStationVelocity(s, allV_AB, F,
2313                                                    defaultFrameF.p());
2314     const Vec3        v_AC   = findStationVelocity(s, allV_AB, B, p_BC);
2315 
2316     // position error
2317     Vec3::updAs(&pverr[3]) = v_AF2 - v_AC;
2318 }
2319 
calcPositionDotDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allA_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDotDot,Array_<Real> & paerr)2320 void calcPositionDotDotErrorsVirtual
2321    (const State&                                    s,      // Stage::Velocity
2322     const Array_<SpatialVec,ConstrainedBodyIndex>&  allA_AB,
2323     const Array_<Real,      ConstrainedQIndex>&     constrainedQDotDot,
2324     Array_<Real>&                                   paerr)  // mp of these
2325     const override
2326 {
2327     assert(allA_AB.size()==2 && constrainedQDotDot.size()==0 && paerr.size()==6);
2328     //TODO: should be able to get p and v info from State
2329     const Rotation& R_AB = getBodyRotationFromState(s, B);
2330     const Rotation& R_AF = getBodyRotationFromState(s, F);
2331     const Rotation  RB = R_AB * defaultFrameB.R(); // now expressed in A
2332     const Rotation  RF = R_AF * defaultFrameF.R();
2333 
2334     const Vec3&     w_AB = getBodyAngularVelocityFromState(s, B);
2335     const Vec3&     w_AF = getBodyAngularVelocityFromState(s, F);
2336     const Vec3      w_BF = w_AF-w_AB; // in A
2337 
2338     const Vec3&     b_AB = getBodyAngularAcceleration(allA_AB, B);
2339     const Vec3&     b_AF = getBodyAngularAcceleration(allA_AB, F);
2340     const Vec3      b_BF = b_AF-b_AB; // in A
2341 
2342     // orientation error
2343     Vec3::updAs(&paerr[0]) =
2344         Vec3( dot( b_BF, RF.x() % RB.y() )
2345                   + dot( w_BF, (w_AF%RF.x()) % RB.y() - (w_AB%RB.y()) % RF.x()),
2346               dot( b_BF, RF.y() % RB.z() )
2347                   + dot( w_BF, (w_AF%RF.y()) % RB.z() - (w_AB%RB.z()) % RF.y()),
2348               dot( b_BF, RF.z() % RB.x() )
2349                   + dot( w_BF, (w_AF%RF.z()) % RB.x() - (w_AB%RB.x()) % RF.z()));
2350 
2351     const Transform&  X_AB   = getBodyTransformFromState(s, B);
2352     const Vec3        p_AF2  = findStationLocationFromState(s, F,
2353                                                             defaultFrameF.p());
2354     const Vec3        p_BC   = ~X_AB*p_AF2; // C is a material point of body B
2355 
2356     const Vec3        a_AF2  = findStationAcceleration(s, allA_AB, F,
2357                                                        defaultFrameF.p());
2358     const Vec3        a_AC   = findStationAcceleration(s, allA_AB, B, p_BC);
2359 
2360     // position error
2361     Vec3::updAs(&paerr[3]) = a_AF2 - a_AC;
2362 }
2363 
addInPositionConstraintForcesVirtual(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedQIndex> & qForces)2364 void addInPositionConstraintForcesVirtual
2365    (const State&                                    s,      // Stage::Position
2366     const Array_<Real>&                             multipliers, // mp of these
2367     Array_<SpatialVec,ConstrainedBodyIndex>&        bodyForcesInA,
2368     Array_<Real,      ConstrainedQIndex>&           qForces)
2369     const override
2370 {
2371     assert(multipliers.size()==6 && bodyForcesInA.size()==2
2372            && qForces.size()==0);
2373 
2374     const Vec3& torques = Vec3::getAs(&multipliers[0]);
2375     const Vec3& force_A = Vec3::getAs(&multipliers[3]);
2376 
2377     //TODO: should be able to get p info from State
2378     const Rotation& R_AB = getBodyRotationFromState(s, B);
2379     const Rotation& R_AF = getBodyRotationFromState(s, F);
2380     const Rotation  RB = R_AB * defaultFrameB.R(); // now expressed in A
2381     const Rotation  RF = R_AF * defaultFrameF.R();
2382 
2383     const Vec3 torque_F_A =   torques[0] * (RF.x() % RB.y())
2384                             + torques[1] * (RF.y() % RB.z())
2385                             + torques[2] * (RF.z() % RB.x());
2386 
2387     addInBodyTorque(s, F,  torque_F_A, bodyForcesInA);
2388     addInBodyTorque(s, B, -torque_F_A, bodyForcesInA);
2389 
2390     const Transform& X_AB  = getBodyTransformFromState(s,B);
2391     const Vec3&      p_FF2 = defaultFrameF.p();
2392     const Vec3       p_AF2 = findStationLocationFromState(s, F, p_FF2);
2393     const Vec3       p_BC = ~X_AB * p_AF2;
2394 
2395     addInStationForce(s, F, p_FF2, force_A, bodyForcesInA);
2396     addInStationForce(s, B, p_BC, -force_A, bodyForcesInA);
2397 }
2398 
2399 SimTK_DOWNCAST(WeldImpl, ConstraintImpl);
2400 //------------------------------------------------------------------------------
2401                                     private:
2402 friend class Constraint::Weld;
2403 
2404 ConstrainedBodyIndex    B; // aka "body 1"
2405 ConstrainedBodyIndex    F; // aka "body 2"
2406 
2407 Transform               defaultFrameB; // on body 1, relative to B frame
2408 Transform               defaultFrameF; // on body 2, relative to F frame};
2409 
2410 // These are for visualization control only.
2411 Real                    axisDisplayLength; // for all 6 axes; <= 0 means "don't
2412 Vec3                    frameBColor;       //       display"
2413 Vec3                    frameFColor;
2414 };
2415 
2416 
2417 
2418 //==============================================================================
2419 //                             NO SLIP 1D IMPL
2420 //==============================================================================
2421 class Constraint::NoSlip1DImpl : public ConstraintImpl {
2422 public:
NoSlip1DImpl()2423 NoSlip1DImpl()
2424 :   ConstraintImpl(0,1,0), defaultContactPoint(0), defaultNoSlipDirection(),
2425     directionLength(1), pointRadius(Real(0.05))
2426 { }
clone()2427 NoSlip1DImpl* clone() const override { return new NoSlip1DImpl(*this); }
2428 
2429 // The default contact point and no-slip direction may be overridden by
2430 // setting an instance variable in the state. We allocate the state
2431 // resources here.
2432 void realizeTopologyVirtual(State& state) const override;
2433 
2434 // Return the contact point and no-slip direction, both expressed
2435 // in the Case body frame C.
2436 const std::pair<Vec3,UnitVec3>& getContactInfo(const State& state) const;
2437 
2438 // Return a writable reference into the Instance-stage state variable
2439 // containing the contact point and no-slip direction, both expressed
2440 // in the Case body frame C. Calling this
2441 // method invalidates the Instance stage and above in the given state.
2442 std::pair<Vec3,UnitVec3>& updContactInfo(State& state) const;
2443 
2444 void calcDecorativeGeometryAndAppendVirtual
2445     (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const override;
2446 
setDirectionDisplayLength(Real l)2447 void setDirectionDisplayLength(Real l) {
2448     // l <= 0 means don't display direction line
2449     invalidateTopologyCache();
2450     directionLength = l > 0 ? l : 0;
2451 }
getDirectionDisplayLength()2452 Real getDirectionDisplayLength() const {return directionLength;}
2453 
setPointDisplayRadius(Real r)2454 void setPointDisplayRadius(Real r) {
2455     // r <= 0 means don't display point
2456     invalidateTopologyCache();
2457     pointRadius= r > 0 ? r : 0;
2458 }
getPointDisplayRadius()2459 Real getPointDisplayRadius() const {return pointRadius;}
2460 
2461 // Implementation of virtuals required for nonholonomic constraints.
2462 
2463 // One non-holonomic constraint equation. There is a contact point P and a
2464 // no-slip direction n fixed in a case body C. There are two moving bodies B0
2465 // and B1. The material point P0 of B0 and the material point P1 of B1 which
2466 // are each coincident with the contact point P must have identical velocities
2467 // in C, along the direction n. This can be used to implement simple rolling
2468 // contact between disks, such as occurs in gear trains.
2469 //
2470 // There is no perr equation here since this is a non-holonomic (velocity)
2471 // constraint. In the C frame, the constraint we want is
2472 //    verr = ~(v_CP1 - v_CP0) * n_C
2473 // that is, the two contact points have no relative velocity in C along the
2474 // normal. We can calculate this in A instead since the velocities in C of each
2475 // point will differ from their velocities in A by a constant (because they are
2476 // both in the same place in space). So:
2477 //    verr = ~(v_AP1 - v_AP0) * n_A
2478 // Differentiating material point velocities in A, we get the acceleration
2479 // error
2480 //    aerr = ~(a_AP1 - a_AP0) * n_A + ~(v_AP1 - v_AP0) * (w_AC X n_A)
2481 //         = ~(a_AP1 - a_AP0 - w_AC X (v_AP1 - v_AP0)) * n_A
2482 //
calcVelocityErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allV_AB,const Array_<Real,ConstrainedUIndex> & constrainedU,Array_<Real> & verr)2483 void calcVelocityErrorsVirtual
2484    (const State&                                    s,      // Stage::Position
2485     const Array_<SpatialVec,ConstrainedBodyIndex>&  allV_AB,
2486     const Array_<Real,      ConstrainedUIndex>&     constrainedU,
2487     Array_<Real>&                                   verr)   // mv of these
2488     const override
2489 {
2490     // There ought to be at least 2 distinct bodies, up to 3.
2491     assert((allV_AB.size()==2 || allV_AB.size() == 3)
2492            && constrainedU.size()==0 && verr.size()==1);
2493 
2494     const std::pair<Vec3,UnitVec3>& info = getContactInfo(s);
2495     const Vec3&     P_C = info.first;
2496     const UnitVec3& n_C = info.second;
2497 
2498     //TODO: should be able to get p info from State
2499     const Transform& X_AC  = getBodyTransformFromState(s, caseBody);
2500     const Transform& X_AB0 = getBodyTransformFromState(s, movingBody0);
2501     const Transform& X_AB1 = getBodyTransformFromState(s, movingBody1);
2502     const Vec3       p_AP  =  X_AC * P_C;       // P's location in A
2503     const Vec3       p_P0  = ~X_AB0 * p_AP;     // P0's station in B0
2504     const Vec3       p_P1  = ~X_AB1 * p_AP;     // P1's station in B1
2505     const UnitVec3   n_A   = X_AC.R() * n_C;
2506 
2507     const Vec3       v_AP0 = findStationVelocity(s, allV_AB, movingBody0, p_P0);
2508     const Vec3       v_AP1 = findStationVelocity(s, allV_AB, movingBody1, p_P1);
2509 
2510     // Calculate this scalar using A-frame vectors.
2511     verr[0] = ~(v_AP1-v_AP0) * n_A;
2512 }
2513 
calcVelocityDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allA_AB,const Array_<Real,ConstrainedUIndex> & constrainedUDot,Array_<Real> & vaerr)2514 void calcVelocityDotErrorsVirtual
2515    (const State&                                    s,      // Stage::Velocity
2516     const Array_<SpatialVec,ConstrainedBodyIndex>&  allA_AB,
2517     const Array_<Real,      ConstrainedUIndex>&     constrainedUDot,
2518     Array_<Real>&                                   vaerr)  // mv of these
2519     const override
2520 {
2521     assert((allA_AB.size()==2 || allA_AB.size() == 3)
2522            && constrainedUDot.size()==0 && vaerr.size()==1);
2523 
2524     const std::pair<Vec3,UnitVec3>& info = getContactInfo(s);
2525     const Vec3&     P_C = info.first;
2526     const UnitVec3& n_C = info.second;
2527 
2528     //TODO: should be able to get p and v info from State
2529     const Transform& X_AC  = getBodyTransformFromState(s, caseBody);
2530     const Transform& X_AB0 = getBodyTransformFromState(s, movingBody0);
2531     const Transform& X_AB1 = getBodyTransformFromState(s, movingBody1);
2532     const Vec3       p_AP  =  X_AC * P_C;       // P's location in A
2533     const Vec3       p_P0  = ~X_AB0 * p_AP;     // P0's station in B0
2534     const Vec3       p_P1  = ~X_AB1 * p_AP;     // P1's station in B1
2535     const UnitVec3   n_A   = X_AC.R() * n_C;
2536 
2537     const Vec3  v_AP0 = findStationVelocityFromState(s, movingBody0, p_P0);
2538     const Vec3  v_AP1 = findStationVelocityFromState(s, movingBody1, p_P1);
2539     const Vec3& w_AC  = getBodyAngularVelocityFromState(s, caseBody);
2540 
2541     const Vec3  a_AP0 = findStationAcceleration(s, allA_AB, movingBody0, p_P0);
2542     const Vec3  a_AP1 = findStationAcceleration(s, allA_AB, movingBody1, p_P1);
2543 
2544     // Calculate this scalar using A-frame vectors.
2545     vaerr[0] = ~(a_AP1-a_AP0 - w_AC % (v_AP1-v_AP0)) * n_A;
2546 }
2547 
2548 // apply f=lambda*n to contact point P1 of B1,
2549 //      -f          to contact point P2 of B2
addInVelocityConstraintForcesVirtual(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedUIndex> & mobilityForces)2550 void addInVelocityConstraintForcesVirtual
2551    (const State&                                    s,      // Stage::Velocity
2552     const Array_<Real>&                             multipliers, // mv of these
2553     Array_<SpatialVec,ConstrainedBodyIndex>&        bodyForcesInA,
2554     Array_<Real,      ConstrainedUIndex>&           mobilityForces) const override
2555 {
2556     assert(multipliers.size()==1 && mobilityForces.size()==0
2557            && (bodyForcesInA.size()==2 || bodyForcesInA.size()==3));
2558 
2559     const std::pair<Vec3,UnitVec3>& info = getContactInfo(s);
2560     const Vec3&     P_C = info.first;
2561     const UnitVec3& n_C = info.second;
2562 
2563     const Real lambda = multipliers[0];
2564 
2565     //TODO: should be able to get p info from State
2566     const Transform& X_AC  = getBodyTransformFromState(s, caseBody);
2567     const Transform& X_AB0 = getBodyTransformFromState(s, movingBody0);
2568     const Transform& X_AB1 = getBodyTransformFromState(s, movingBody1);
2569     const Vec3       p_AP  = X_AC * P_C; // P's location in A
2570     const Vec3       p_P0  = ~X_AB0 * p_AP;              // P0's station in B0
2571     const Vec3       p_P1  = ~X_AB1 * p_AP;              // P1's station in B1
2572 
2573     const Vec3       force_A = X_AC.R()*(lambda*n_C);
2574 
2575     addInStationForce(s, movingBody1, p_P1,  force_A, bodyForcesInA);
2576     addInStationForce(s, movingBody0, p_P0, -force_A, bodyForcesInA);
2577 }
2578 
2579 SimTK_DOWNCAST(NoSlip1DImpl, ConstraintImpl);
2580 //------------------------------------------------------------------------------
2581                                     private:
2582 friend class Constraint::NoSlip1D;
2583 
2584 ConstrainedBodyIndex    caseBody;     // C
2585 ConstrainedBodyIndex    movingBody0;  // B0
2586 ConstrainedBodyIndex    movingBody1;  // B1
2587 
2588 Vec3                    defaultContactPoint;      // on body C, exp. in C frame
2589 UnitVec3                defaultNoSlipDirection;   // on body C, exp. in C frame
2590 
2591 // These are just for visualization
2592 Real                    directionLength;
2593 Real                    pointRadius;
2594 
2595 // This Instance-stage variable holds the actual contact point and no-slip
2596 // direction on the Case body.
2597 mutable DiscreteVariableIndex   contactInfoIx;
2598 };
2599 
2600 
2601 //==============================================================================
2602 //                        CONSTANT COORDINATE IMPL
2603 //==============================================================================
2604 class Constraint::ConstantCoordinateImpl : public ConstraintImpl {
2605 public:
ConstantCoordinateImpl()2606 ConstantCoordinateImpl()
2607 :   ConstraintImpl(1,0,0), theMobilizer(), whichCoordinate(),
2608     defaultPosition(NaN){}
2609 
clone()2610 ConstantCoordinateImpl* clone() const override
2611 {   return new ConstantCoordinateImpl(*this); }
2612 
2613 // Allocate a state variable to hold the desired position.
2614 void realizeTopologyVirtual(State& state) const override;
2615 // Obtain the currently-set desired position from the state.
2616 Real getPosition(const State& state) const;
2617 // Get a reference to the desired position in the state; this
2618 // invalidates Position stage in the supplied state.
2619 Real& updPosition(State& state) const;
2620 
2621 // Implementation of virtuals required for holonomic constraints.
2622 
2623 // One holonomic constraint equation.
2624 //    perr = q - p
2625 //    verr = qdot
2626 //    aerr = qdotdot
2627 //
calcPositionErrorsVirtual(const State & s,const Array_<Transform,ConstrainedBodyIndex> & X_AB,const Array_<Real,ConstrainedQIndex> & constrainedQ,Array_<Real> & perr)2628 void calcPositionErrorsVirtual
2629    (const State&                                    s, // Stage::Time
2630     const Array_<Transform,ConstrainedBodyIndex>&   X_AB,
2631     const Array_<Real,     ConstrainedQIndex>&      constrainedQ,
2632     Array_<Real>&                                   perr)  // mp of these
2633     const override
2634 {
2635     // All the q's for a given constrained mobilizer are considered
2636     // constrainedQ's, but we're just going to grab one of them.
2637     assert(X_AB.size()==0 && constrainedQ.size()>=1 && perr.size()==1);
2638     const Real q = getOneQ(s, constrainedQ, theMobilizer, whichCoordinate);
2639     perr[0] = q - getPosition(s);
2640 }
2641 
calcPositionDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & V_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDot,Array_<Real> & pverr)2642 void calcPositionDotErrorsVirtual
2643    (const State&                                    s, // Stage::Position
2644     const Array_<SpatialVec,ConstrainedBodyIndex>&  V_AB,
2645     const Array_<Real,      ConstrainedQIndex>&     constrainedQDot,
2646     Array_<Real>&                                   pverr) // mp of these
2647     const override
2648 {
2649     // All the q's for a given constrained mobilizer are considered
2650     // constrainedQDots's, but we're just going to grab one of them.
2651     assert(V_AB.size()==0 && constrainedQDot.size()>=1 && pverr.size()==1);
2652     const Real qdot = getOneQDot(s, constrainedQDot,
2653                                  theMobilizer, whichCoordinate);
2654     pverr[0] = qdot;
2655 }
2656 
2657 // Pull t, X_AB, q, V_AB, qdot from state.
calcPositionDotDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & A_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDotDot,Array_<Real> & paerr)2658 void calcPositionDotDotErrorsVirtual
2659    (const State&                                    s, // Stage::Velocity
2660     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
2661     const Array_<Real,      ConstrainedQIndex>&     constrainedQDotDot,
2662     Array_<Real>&                                   paerr) // mp of these
2663     const override
2664 {
2665     // All the q's for a given constrained mobilizer are considered
2666     // constrainedQDotDots's, but we're just going to grab one of them.
2667     assert(A_AB.size()==0 && constrainedQDotDot.size()>=1 && paerr.size()==1);
2668     const Real qdotdot = getOneQDotDot(s, constrainedQDotDot,
2669                                        theMobilizer, whichCoordinate);
2670     paerr[0] = qdotdot;
2671 }
2672 
2673 // apply generalized force lambda to the mobility
addInPositionConstraintForcesVirtual(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedQIndex> & qForces)2674 void addInPositionConstraintForcesVirtual
2675    (const State&                                    s, // Stage::Position
2676     const Array_<Real>&                             multipliers, // mp of these
2677     Array_<SpatialVec,ConstrainedBodyIndex>&        bodyForcesInA,
2678     Array_<Real,      ConstrainedQIndex>&           qForces)
2679     const override
2680 {
2681    // All the coordinates for a given constrained mobilizer have slots in
2682    // qForces, but we're just going to update one of them.
2683    assert(multipliers.size()==1 && bodyForcesInA.size()==0
2684           && qForces.size()>=1);
2685 
2686     const Real lambda = multipliers[0];
2687     addInOneQForce(s, theMobilizer, whichCoordinate, lambda, qForces);
2688 }
2689 
2690 SimTK_DOWNCAST(ConstantCoordinateImpl, ConstraintImpl);
2691 //------------------------------------------------------------------------------
2692                                     private:
2693 friend class Constraint::ConstantCoordinate;
2694 
2695 // TOPOLOGY STATE
2696 ConstrainedMobilizerIndex   theMobilizer;
2697 MobilizerQIndex             whichCoordinate;
2698 Real                        defaultPosition;
2699 
2700 // TOPOLOGY CACHE
2701 DiscreteVariableIndex       positionIx;
2702 };
2703 
2704 
2705 
2706 
2707 //==============================================================================
2708 //                          CONSTANT SPEED IMPL
2709 //==============================================================================
2710 class Constraint::ConstantSpeedImpl : public ConstraintImpl {
2711 public:
ConstantSpeedImpl()2712 ConstantSpeedImpl()
2713 :   ConstraintImpl(0,1,0), theMobilizer(), whichMobility(),
2714     defaultSpeed(NaN){}
2715 
clone()2716 ConstantSpeedImpl* clone() const override
2717 {   return new ConstantSpeedImpl(*this); }
2718 
2719 // Allocate a state variable to hold the desired speed.
2720 void realizeTopologyVirtual(State& state) const override;
2721 // Obtain the currently-set desired speed from the state.
2722 Real getSpeed(const State& state) const;
2723 // Get a reference to the desired speed in the state; this
2724 // invalidates Velocity stage in the supplied state.
2725 Real& updSpeed(State& state) const;
2726 
2727 // Implementation of virtuals required for nonholonomic constraints.
2728 
2729 // One non-holonomic (well, velocity-level) constraint equation.
2730 //    verr = u - s
2731 //    aerr = udot
2732 //
calcVelocityErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allV_AB,const Array_<Real,ConstrainedUIndex> & constrainedU,Array_<Real> & verr)2733 void calcVelocityErrorsVirtual
2734    (const State&                                    s,      // Stage::Position
2735     const Array_<SpatialVec,ConstrainedBodyIndex>&  allV_AB,
2736     const Array_<Real,      ConstrainedUIndex>&     constrainedU,
2737     Array_<Real>&                                   verr)   // mv of these
2738     const override
2739 {
2740     // All the u's for a given constrained mobilizer are considered
2741     // constrainedU's, but we're just going to grab one of them.
2742     assert(allV_AB.size()==0 && constrainedU.size()>=1 && verr.size()==1);
2743     const Real u = getOneU(s, constrainedU, theMobilizer, whichMobility);
2744     verr[0] = u - getSpeed(s);
2745 }
2746 
calcVelocityDotErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allA_AB,const Array_<Real,ConstrainedUIndex> & constrainedUDot,Array_<Real> & vaerr)2747 void calcVelocityDotErrorsVirtual
2748    (const State&                                    s,      // Stage::Velocity
2749     const Array_<SpatialVec,ConstrainedBodyIndex>&  allA_AB,
2750     const Array_<Real,      ConstrainedUIndex>&     constrainedUDot,
2751     Array_<Real>&                                   vaerr)  // mv of these
2752     const override
2753 {
2754     // All the u's for a given constrained mobilizer are considered
2755     // constrainedUDots's, but we're just going to grab one of them.
2756     assert(allA_AB.size()==0 && constrainedUDot.size()>=1 && vaerr.size()==1);
2757     const Real udot = getOneUDot(s, constrainedUDot,
2758                                  theMobilizer, whichMobility);
2759     vaerr[0] = udot;
2760 }
2761 
2762 // apply generalized force lambda to the mobility
addInVelocityConstraintForcesVirtual(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedUIndex> & mobilityForces)2763 void addInVelocityConstraintForcesVirtual
2764    (const State&                              s,      // Stage::Velocity
2765     const Array_<Real>&                       multipliers, // mv of these
2766     Array_<SpatialVec,ConstrainedBodyIndex>&  bodyForcesInA,
2767     Array_<Real,      ConstrainedUIndex>&     mobilityForces) const override
2768 {
2769    // All the mobilities for a given constrained mobilizer have slots in
2770    // mobilizedForces, but we're just going to update one of them.
2771    assert(multipliers.size()==1 && bodyForcesInA.size()==0
2772            && mobilityForces.size()>=1);
2773 
2774     const Real lambda = multipliers[0];
2775     addInOneMobilityForce(s, theMobilizer, whichMobility, lambda,
2776                           mobilityForces);
2777 }
2778 
2779 SimTK_DOWNCAST(ConstantSpeedImpl, ConstraintImpl);
2780 //------------------------------------------------------------------------------
2781                                     private:
2782 friend class Constraint::ConstantSpeed;
2783 
2784 // TOPOLOGY STATE
2785 ConstrainedMobilizerIndex   theMobilizer;
2786 MobilizerUIndex             whichMobility;
2787 Real                        defaultSpeed;
2788 
2789 // TOPOLOGY CACHE
2790 DiscreteVariableIndex       speedIx;
2791 };
2792 
2793 
2794 
2795 //==============================================================================
2796 //                        CONSTANT ACCELERATION IMPL
2797 //==============================================================================
2798 class Constraint::ConstantAccelerationImpl : public ConstraintImpl {
2799 public:
ConstantAccelerationImpl()2800 ConstantAccelerationImpl()
2801 :   ConstraintImpl(0,0,1), theMobilizer(), whichMobility(),
2802     defaultAcceleration(NaN) {}
2803 
clone()2804 ConstantAccelerationImpl* clone() const override
2805 {   return new ConstantAccelerationImpl(*this); }
2806 
2807 // Allocate a state variable to hold the desired acceleration.
2808 void realizeTopologyVirtual(State& state) const override;
2809 // Obtain the currently-set desired acceleration from the state.
2810 Real getAcceleration(const State& state) const;
2811 // Get a reference to the desired acceleration in the state; this
2812 // invalidates Acceleration stage in the supplied state.
2813 Real& updAcceleration(State& state) const;
2814 
2815 // Implementation of virtuals required for acceleration-only constraints.
2816 
2817 // One acceleration-only constraint equation.
2818 //    aerr = udot - a
2819 //
calcAccelerationErrorsVirtual(const State & s,const Array_<SpatialVec,ConstrainedBodyIndex> & allA_AB,const Array_<Real,ConstrainedUIndex> & constrainedUDot,Array_<Real> & aerr)2820 void calcAccelerationErrorsVirtual
2821    (const State&                                    s,      // Stage::Velocity
2822     const Array_<SpatialVec,ConstrainedBodyIndex>&  allA_AB,
2823     const Array_<Real,      ConstrainedUIndex>&     constrainedUDot,
2824     Array_<Real>&                                   aerr) const override // ma of these
2825 {
2826     // All the u's for a given constrained mobilizer are considered
2827     // constrainedUDots's, but we're just going to grab one of them.
2828     assert(allA_AB.size()==0 && constrainedUDot.size()>=1 && aerr.size()==1);
2829 
2830     const Real udot = getOneUDot(s, constrainedUDot,
2831                                  theMobilizer, whichMobility);
2832     aerr[0] = udot - getAcceleration(s);
2833 }
2834 
2835 // apply generalized force lambda to the mobility
addInAccelerationConstraintForcesVirtual(const State & state,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedUIndex> & mobilityForces)2836 void addInAccelerationConstraintForcesVirtual
2837    (const State&                                    state, // Stage::Velocity
2838     const Array_<Real>&                             multipliers, // ma of these
2839     Array_<SpatialVec,ConstrainedBodyIndex>&        bodyForcesInA,
2840     Array_<Real,      ConstrainedUIndex>&           mobilityForces) const override
2841 {
2842    // All the mobilities for a given constrained mobilizer have slots in
2843    // mobilizedForces, but we're just going to update one of them.
2844     assert(multipliers.size()==1 && bodyForcesInA.size()==0
2845            && mobilityForces.size()>=1);
2846 
2847     const Real lambda = multipliers[0];
2848     addInOneMobilityForce(state, theMobilizer, whichMobility, lambda,
2849                           mobilityForces);
2850 }
2851 
2852 SimTK_DOWNCAST(ConstantAccelerationImpl, ConstraintImpl);
2853 //------------------------------------------------------------------------------
2854                                     private:
2855 friend class Constraint::ConstantAcceleration;
2856 
2857 // TOPOLOGY STATE
2858 ConstrainedMobilizerIndex   theMobilizer;
2859 MobilizerUIndex             whichMobility;
2860 Real                        defaultAcceleration;
2861 
2862 // TOPOLOGY CACHE
2863 DiscreteVariableIndex       accelIx;
2864 };
2865 
2866 
2867 
2868 //==============================================================================
2869 //                         CUSTOM IMPLEMENTATION IMPL
2870 //==============================================================================
2871 // This class exists primarily to allow the Custom::Implementation class to keep
2872 // a pointer to its handle class's CustomImpl class which is derived from
2873 // ConstraintImpl which has all the goodies that are needed for defining a
2874 // Constraint.
2875 //
2876 // At first this class is the owner of the CustomImpl. Then when this is put in
2877 // a Custom handle, that handle takes over ownership of the CustomImpl and the
2878 // CustomImpl takes over ownership of this ImplementationImpl object.
2879 class Constraint::Custom::ImplementationImpl
2880 :   public PIMPLImplementation<Implementation, ImplementationImpl>
2881 {
2882 public:
2883 // no default constructor
ImplementationImpl(CustomImpl * customImpl)2884 explicit ImplementationImpl(CustomImpl* customImpl) : isOwner(true), builtInImpl(customImpl) { }
2885 inline ~ImplementationImpl(); // see below -- have to wait for CustomImpl's definition
2886 
2887 // Copying one of these just gives us a new one with a NULL CustomImpl pointer.
ImplementationImpl(const ImplementationImpl & src)2888 ImplementationImpl(const ImplementationImpl& src) : isOwner(false), builtInImpl(0) { }
2889 
clone()2890 ImplementationImpl* clone() const {return new ImplementationImpl(*this);}
2891 
isOwnerOfCustomImpl()2892 bool isOwnerOfCustomImpl() const {return builtInImpl && isOwner;}
removeOwnershipOfCustomImpl()2893 CustomImpl* removeOwnershipOfCustomImpl() {
2894     assert(isOwnerOfCustomImpl());
2895     isOwner=false;
2896     return builtInImpl;
2897 }
2898 
setReferenceToCustomImpl(CustomImpl * cimpl)2899 void setReferenceToCustomImpl(CustomImpl* cimpl) {
2900     assert(!builtInImpl); // you can only do this once
2901     isOwner=false;
2902     builtInImpl = cimpl;
2903 }
2904 
hasCustomImpl()2905 bool hasCustomImpl() const {return builtInImpl != 0;}
2906 
getCustomImpl()2907 const CustomImpl& getCustomImpl() const {
2908     assert(builtInImpl);
2909     return *builtInImpl;
2910 }
updCustomImpl()2911 CustomImpl& updCustomImpl() {
2912     assert(builtInImpl);
2913     return *builtInImpl;
2914 }
2915 
2916 //------------------------------------------------------------------------------
2917                                     private:
2918 bool            isOwner;
2919 CustomImpl*     builtInImpl; // just a reference; not owned
2920 
2921 // suppress assignment
2922 ImplementationImpl& operator=(const ImplementationImpl&);
2923 };
2924 
2925 
2926 
2927 //==============================================================================
2928 //                                 CUSTOM IMPL
2929 //==============================================================================
2930 class Constraint::CustomImpl : public ConstraintImpl {
2931 public:
CustomImpl()2932 CustomImpl() : implementation(0) { }
CustomImpl(int mp,int mv,int ma)2933 CustomImpl(int mp, int mv, int ma) : ConstraintImpl(mp,mv,ma), implementation(0) { }
2934 
2935 void takeOwnershipOfImplementation(Custom::Implementation* userImpl);
2936 
CustomImpl(Custom::Implementation * userImpl)2937 explicit CustomImpl(Custom::Implementation* userImpl) : implementation(0) {
2938     assert(userImpl);
2939     implementation = userImpl;
2940     implementation->updImpl().setReferenceToCustomImpl(this);
2941 }
2942 
2943 // Copy constructor
CustomImpl(const CustomImpl & src)2944 CustomImpl(const CustomImpl& src) : implementation(0) {
2945     if (src.implementation) {
2946         implementation = src.implementation->clone();
2947         implementation->updImpl().setReferenceToCustomImpl(this);
2948     }
2949 }
2950 
~CustomImpl()2951 ~CustomImpl() {
2952     delete implementation;
2953 }
2954 
clone()2955 CustomImpl* clone() const override { return new CustomImpl(*this); }
2956 
getImplementation()2957 const Custom::Implementation& getImplementation() const {
2958     assert(implementation);
2959     return *implementation;
2960 }
2961 
updImplementation()2962 Custom::Implementation& updImplementation() {
2963     assert(implementation);
2964     return *implementation;
2965 }
2966 
2967 // Forward all the virtuals to the Custom::Implementation virtuals.
realizeTopologyVirtual(State & s)2968 void realizeTopologyVirtual(State& s) const override {getImplementation().realizeTopology(s);}
realizeModelVirtual(State & s)2969 void realizeModelVirtual   (State& s) const override {getImplementation().realizeModel(s);}
realizeInstanceVirtual(const State & s)2970 void realizeInstanceVirtual(const State& s) const override {getImplementation().realizeInstance(s);}
realizeTimeVirtual(const State & s)2971 void realizeTimeVirtual    (const State& s) const override {getImplementation().realizeTime(s);}
realizePositionVirtual(const State & s)2972 void realizePositionVirtual(const State& s) const override {getImplementation().realizePosition(s);}
realizeVelocityVirtual(const State & s)2973 void realizeVelocityVirtual(const State& s) const override {getImplementation().realizeVelocity(s);}
realizeDynamicsVirtual(const State & s)2974 void realizeDynamicsVirtual(const State& s) const override {getImplementation().realizeDynamics(s);}
realizeAccelerationVirtual(const State & s)2975 void realizeAccelerationVirtual(const State& s) const override {getImplementation().realizeAcceleration(s);}
realizeReportVirtual(const State & s)2976 void realizeReportVirtual  (const State& s) const override {getImplementation().realizeReport(s);}
2977 
calcPositionErrorsVirtual(const State & state,const Array_<Transform,ConstrainedBodyIndex> & X_AB,const Array_<Real,ConstrainedQIndex> & constrainedQ,Array_<Real> & perr)2978 void calcPositionErrorsVirtual
2979    (const State&                                    state,
2980     const Array_<Transform,ConstrainedBodyIndex>&   X_AB,
2981     const Array_<Real,     ConstrainedQIndex>&      constrainedQ,
2982     Array_<Real>&                                   perr) const override
2983 {   getImplementation().calcPositionErrors(state,X_AB,constrainedQ,perr); }
2984 
calcPositionDotErrorsVirtual(const State & state,const Array_<SpatialVec,ConstrainedBodyIndex> & V_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDot,Array_<Real> & pverr)2985 void calcPositionDotErrorsVirtual
2986    (const State&                                    state,
2987     const Array_<SpatialVec,ConstrainedBodyIndex>&  V_AB,
2988     const Array_<Real,      ConstrainedQIndex>&     constrainedQDot,
2989     Array_<Real>&                                   pverr) const override
2990 {   getImplementation().calcPositionDotErrors
2991                                         (state,V_AB,constrainedQDot,pverr); }
2992 
calcPositionDotDotErrorsVirtual(const State & state,const Array_<SpatialVec,ConstrainedBodyIndex> & A_AB,const Array_<Real,ConstrainedQIndex> & constrainedQDotDot,Array_<Real> & paerr)2993 void calcPositionDotDotErrorsVirtual
2994    (const State&                                    state,
2995     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
2996     const Array_<Real,      ConstrainedQIndex>&     constrainedQDotDot,
2997     Array_<Real>&                                   paerr) const override
2998 {   getImplementation().calcPositionDotDotErrors
2999                                     (state,A_AB,constrainedQDotDot,paerr); }
3000 
addInPositionConstraintForcesVirtual(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedQIndex> & qForces)3001 void addInPositionConstraintForcesVirtual
3002    (const State&                                s,
3003     const Array_<Real>&                         multipliers,
3004     Array_<SpatialVec,ConstrainedBodyIndex>&    bodyForcesInA,
3005     Array_<Real,ConstrainedQIndex>&             qForces) const override
3006 {   getImplementation().addInPositionConstraintForces
3007         (s,multipliers,bodyForcesInA,qForces); }
3008 
calcVelocityErrorsVirtual(const State & state,const Array_<SpatialVec,ConstrainedBodyIndex> & V_AB,const Array_<Real,ConstrainedUIndex> & constrainedU,Array_<Real> & verr)3009 void calcVelocityErrorsVirtual
3010    (const State&                                    state,
3011     const Array_<SpatialVec,ConstrainedBodyIndex>&  V_AB,
3012     const Array_<Real,      ConstrainedUIndex>&     constrainedU,
3013     Array_<Real>&                                   verr) const override
3014 {   getImplementation().calcVelocityErrors(state,V_AB,constrainedU,verr); }
3015 
calcVelocityDotErrorsVirtual(const State & state,const Array_<SpatialVec,ConstrainedBodyIndex> & A_AB,const Array_<Real,ConstrainedUIndex> & constrainedUDot,Array_<Real> & vaerr)3016 void calcVelocityDotErrorsVirtual
3017    (const State&                                    state,
3018     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
3019     const Array_<Real,      ConstrainedUIndex>&     constrainedUDot,
3020     Array_<Real>&                                   vaerr) const override
3021 {   getImplementation().calcVelocityDotErrors
3022                                         (state,A_AB,constrainedUDot,vaerr); }
3023 
addInVelocityConstraintForcesVirtual(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedUIndex> & mobilityForces)3024 void addInVelocityConstraintForcesVirtual
3025    (const State&                                s,
3026     const Array_<Real>&                         multipliers,
3027     Array_<SpatialVec,ConstrainedBodyIndex>&    bodyForcesInA,
3028     Array_<Real,ConstrainedUIndex>&             mobilityForces) const override
3029 {   getImplementation().addInVelocityConstraintForces
3030         (s,multipliers,bodyForcesInA,mobilityForces); }
3031 
calcAccelerationErrorsVirtual(const State & state,const Array_<SpatialVec,ConstrainedBodyIndex> & A_AB,const Array_<Real,ConstrainedUIndex> & constrainedUDot,Array_<Real> & aerr)3032 void calcAccelerationErrorsVirtual
3033    (const State&                                    state,
3034     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
3035     const Array_<Real,      ConstrainedUIndex>&     constrainedUDot,
3036     Array_<Real>&                                   aerr) const override
3037 {   getImplementation().calcAccelerationErrors
3038                                         (state,A_AB,constrainedUDot,aerr); }
3039 
addInAccelerationConstraintForcesVirtual(const State & s,const Array_<Real> & multipliers,Array_<SpatialVec,ConstrainedBodyIndex> & bodyForcesInA,Array_<Real,ConstrainedUIndex> & mobilityForces)3040 void addInAccelerationConstraintForcesVirtual
3041    (const State&                                s,
3042     const Array_<Real>&                         multipliers,
3043     Array_<SpatialVec,ConstrainedBodyIndex>&    bodyForcesInA,
3044     Array_<Real,ConstrainedUIndex>&             mobilityForces) const override
3045 {   getImplementation().addInAccelerationConstraintForces
3046         (s,multipliers,bodyForcesInA,mobilityForces); }
3047 
calcDecorativeGeometryAndAppendVirtual(const State & s,Stage stage,Array_<DecorativeGeometry> & geom)3048 void calcDecorativeGeometryAndAppendVirtual
3049         (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const override
3050     {getImplementation().calcDecorativeGeometryAndAppend(s,stage,geom);}
3051 
3052 SimTK_DOWNCAST(CustomImpl, ConstraintImpl);
3053 //------------------------------------------------------------------------------
3054                                     private:
3055 friend class Constraint::Custom;
3056 
3057 Custom::Implementation*     implementation;
3058 
3059 CustomImpl& operator=(const CustomImpl&); // suppress assignment
3060 };
3061 
3062 // Need definition for CustomImpl here in case we have to delete it.
~ImplementationImpl()3063 inline Constraint::Custom::ImplementationImpl::~ImplementationImpl() {
3064     if (isOwner)
3065         delete builtInImpl;
3066     builtInImpl=0;
3067 }
3068 
3069 
3070 
3071 //==============================================================================
3072 //                          COORDINATE COUPLER IMPL
3073 //==============================================================================
3074 class Constraint::CoordinateCouplerImpl
3075 :   public Constraint::Custom::Implementation {
3076 public:
3077 CoordinateCouplerImpl(SimbodyMatterSubsystem&           matter,
3078                       const Function*                   function,
3079                       const Array_<MobilizedBodyIndex>& coordBody,
3080                       const Array_<MobilizerQIndex>&    coordIndex);
3081 
~CoordinateCouplerImpl()3082 ~CoordinateCouplerImpl() {
3083     if (--referenceCount[0] == 0) {
3084         delete function;
3085         delete[] referenceCount;
3086     }
3087 }
3088 
clone()3089 Implementation* clone() const override {
3090     referenceCount[0]++;
3091     CoordinateCouplerImpl* newCoupler = new CoordinateCouplerImpl(*this);
3092     return newCoupler;
3093 }
3094 
3095 void calcPositionErrors
3096    (const State&                                    state,
3097     const Array_<Transform,ConstrainedBodyIndex>&   X_AB,
3098     const Array_<Real,     ConstrainedQIndex>&      constrainedQ,
3099     Array_<Real>&                                   perr) const override;
3100 
3101 void calcPositionDotErrors
3102    (const State&                                    state,
3103     const Array_<SpatialVec,ConstrainedBodyIndex>&  V_AB,
3104     const Array_<Real,      ConstrainedQIndex>&     constrainedQDot,
3105     Array_<Real>&                                   pverr) const override;
3106 
3107 void calcPositionDotDotErrors
3108    (const State&                                    state,
3109     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
3110     const Array_<Real,      ConstrainedQIndex>&     constrainedQDotDot,
3111     Array_<Real>&                                   paerr) const override;
3112 
3113 void addInPositionConstraintForces
3114    (const State&                                state,
3115     const Array_<Real>&                         multipliers,
3116     Array_<SpatialVec,ConstrainedBodyIndex>&    bodyForces,
3117     Array_<Real,ConstrainedQIndex>&             qForces) const override;
3118 
3119 //------------------------------------------------------------------------------
3120                                     private:
3121 friend class Constraint::CoordinateCoupler;
3122 
3123 //  TOPOLOGY STATE
3124 const Function*                     function;
3125 Array_<ConstrainedMobilizerIndex>   coordBodies;
3126 Array_<MobilizerQIndex>             coordIndices;
3127 
3128 //  TOPOLOGY CACHE
3129 //  None.
3130 
3131 //  A reusable temporary variable allocated to the correct size
3132 //  to hold all the Function arguments.
3133 mutable Vector                      temp;
3134 
3135 // This allows copies to be made of this constraint which share
3136 // the function object.
3137 int*                                referenceCount;
3138 
3139 };
3140 
3141 
3142 
3143 //==============================================================================
3144 //                           SPEED COUPLER IMPL
3145 //==============================================================================
3146 class Constraint::SpeedCouplerImpl
3147 :   public Constraint::Custom::Implementation {
3148 public:
3149 SpeedCouplerImpl(SimbodyMatterSubsystem& matter,
3150                  const Function*                    function,
3151                  const Array_<MobilizedBodyIndex>&  speedBody,
3152                  const Array_<MobilizerUIndex>&     speedIndex,
3153                  const Array_<MobilizedBodyIndex>&  coordBody,
3154                  const Array_<MobilizerQIndex>&     coordIndex);
3155 
~SpeedCouplerImpl()3156 ~SpeedCouplerImpl() {
3157     if (--referenceCount[0] == 0) {
3158         delete function;
3159         delete[] referenceCount;
3160     }
3161 }
3162 
clone()3163 Implementation* clone() const override {
3164     referenceCount[0]++;
3165     return new SpeedCouplerImpl(*this);
3166 }
3167 
3168 void calcVelocityErrors
3169    (const State&                                    state,
3170     const Array_<SpatialVec,ConstrainedBodyIndex>&  V_AB,
3171     const Array_<Real,      ConstrainedUIndex>&     constrainedU,
3172     Array_<Real>&                                   verr) const override;
3173 
3174 void calcVelocityDotErrors
3175    (const State&                                    state,
3176     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
3177     const Array_<Real,      ConstrainedUIndex>&     constrainedUDot,
3178     Array_<Real>&                                   vaerr) const override;
3179 
3180 void addInVelocityConstraintForces
3181    (const State&                                state,
3182     const Array_<Real>&                         multipliers,
3183     Array_<SpatialVec,ConstrainedBodyIndex>&    bodyForces,
3184     Array_<Real,ConstrainedUIndex>&             mobilityForces) const override;
3185 
3186 //------------------------------------------------------------------------------
3187                                     private:
3188 
3189 const Function*                     function;
3190 int*                                referenceCount;
3191 Array_<ConstrainedMobilizerIndex>   speedBodies;
3192 Array_<MobilizedBodyIndex>          coordBodies;
3193 Array_<MobilizerUIndex>             speedIndices;
3194 Array_<MobilizerQIndex>             coordIndices;
3195 mutable Vector                      temp;
3196 };
3197 
3198 
3199 
3200 //==============================================================================
3201 //                          PRESCRIBED MOTION IMPL
3202 //==============================================================================
3203 class Constraint::PrescribedMotionImpl
3204 :   public Constraint::Custom::Implementation {
3205 public:
3206 PrescribedMotionImpl(SimbodyMatterSubsystem&    matter,
3207                      const Function*            function,
3208                      MobilizedBodyIndex         coordBody,
3209                      MobilizerQIndex            coordIndex);
3210 
~PrescribedMotionImpl()3211 ~PrescribedMotionImpl() {
3212     if (--referenceCount[0] == 0) {
3213         delete function;
3214         delete[] referenceCount;
3215     }
3216 }
3217 
clone()3218 Implementation* clone() const override {
3219     referenceCount[0]++;
3220     return new PrescribedMotionImpl(*this);
3221 }
3222 
3223 void calcPositionErrors
3224    (const State&                                    state,
3225     const Array_<Transform,ConstrainedBodyIndex>&   X_AB,
3226     const Array_<Real,     ConstrainedQIndex>&      constrainedQ,
3227     Array_<Real>&                                   perr) const override;
3228 
3229 void calcPositionDotErrors
3230    (const State&                                    state,
3231     const Array_<SpatialVec,ConstrainedBodyIndex>&  V_AB,
3232     const Array_<Real,      ConstrainedQIndex>&     constrainedQDot,
3233     Array_<Real>&                                   pverr) const override;
3234 
3235 void calcPositionDotDotErrors
3236    (const State&                                    state,
3237     const Array_<SpatialVec,ConstrainedBodyIndex>&  A_AB,
3238     const Array_<Real,      ConstrainedQIndex>&     constrainedQDotDot,
3239     Array_<Real>&                                   paerr) const override;
3240 
3241 void addInPositionConstraintForces
3242    (const State&                                state,
3243     const Array_<Real>&                         multipliers,
3244     Array_<SpatialVec,ConstrainedBodyIndex>&    bodyForces,
3245     Array_<Real,ConstrainedQIndex>&             qForces) const override;
3246 
3247 //------------------------------------------------------------------------------
3248                                     private:
3249 const Function*             function;
3250 int*                        referenceCount;
3251 ConstrainedMobilizerIndex   coordBody;
3252 MobilizerQIndex             coordIndex;
3253 mutable Vector              temp;
3254 };
3255 
3256 
3257 } // namespace SimTK
3258 
3259 #endif // SimTK_SIMBODY_CONSTRAINT_IMPL_H_
3260 
3261 
3262 
3263