1 /* -------------------------------------------------------------------------- *
2 * Simbody(tm) *
3 * -------------------------------------------------------------------------- *
4 * This is part of the SimTK biosimulation toolkit originating from *
5 * Simbios, the NIH National Center for Physics-Based Simulation of *
6 * Biological Structures at Stanford, funded under the NIH Roadmap for *
7 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. *
8 * *
9 * Portions copyright (c) 2014 Stanford University and the Authors. *
10 * Authors: Michael Sherman *
11 * Contributors: *
12 * *
13 * Licensed under the Apache License, Version 2.0 (the "License"); you may *
14 * not use this file except in compliance with the License. You may obtain a *
15 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. *
16 * *
17 * Unless required by applicable law or agreed to in writing, software *
18 * distributed under the License is distributed on an "AS IS" BASIS, *
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
20 * See the License for the specific language governing permissions and *
21 * limitations under the License. *
22 * -------------------------------------------------------------------------- */
23
24 /* Implementation of non-inline methods of the handle class
25 Constraint::LineOnLineContact, and its implementation class
26 Constraint::LineOnLineContactImpl. */
27
28 #include "SimTKcommon.h"
29 #include "simbody/internal/common.h"
30 #include "simbody/internal/Constraint.h"
31 #include "simbody/internal/Constraint_LineOnLineContact.h"
32
33 #include "Constraint_LineOnLineContactImpl.h"
34 #include "SimbodyMatterSubsystemRep.h"
35
36 namespace SimTK {
37
38
39 //==============================================================================
40 // LINE ON LINE CONTACT
41 //==============================================================================
42 SimTK_INSERT_DERIVED_HANDLE_DEFINITIONS(Constraint::LineOnLineContact,
43 Constraint::LineOnLineContactImpl,
44 Constraint);
45
LineOnLineContact(MobilizedBody & mobod_F,const Transform & defaultEdgeFrameF,Real defaultHalfLengthF,MobilizedBody & mobod_B,const Transform & defaultEdgeFrameB,Real defaultHalfLengthB,bool enforceRolling)46 Constraint::LineOnLineContact::LineOnLineContact
47 (MobilizedBody& mobod_F,
48 const Transform& defaultEdgeFrameF,
49 Real defaultHalfLengthF,
50 MobilizedBody& mobod_B,
51 const Transform& defaultEdgeFrameB,
52 Real defaultHalfLengthB,
53 bool enforceRolling)
54 : Constraint(new LineOnLineContactImpl(enforceRolling))
55 {
56 SimTK_APIARGCHECK_ALWAYS(mobod_F.isInSubsystem() && mobod_B.isInSubsystem(),
57 "Constraint::LineOnLineContact","LineOnLineContact",
58 "Both mobilized bodies must already be in a SimbodyMatterSubsystem.");
59 SimTK_APIARGCHECK_ALWAYS(mobod_F.isInSameSubsystem(mobod_B),
60 "Constraint::LineOnLineContact","LineOnLineContact",
61 "The two mobilized bodies to be connected must be in the same "
62 "SimbodyMatterSubsystem.");
63
64 mobod_F.updMatterSubsystem().adoptConstraint(*this);
65
66 updImpl().m_mobod_F = updImpl().addConstrainedBody(mobod_F);
67 updImpl().m_mobod_B = updImpl().addConstrainedBody(mobod_B);
68 updImpl().m_def_X_FEf = defaultEdgeFrameF;
69 updImpl().m_def_hf = defaultHalfLengthF;
70 updImpl().m_def_X_BEb = defaultEdgeFrameB;
71 updImpl().m_def_hb = defaultHalfLengthB;
72 }
73
74 Constraint::LineOnLineContact& Constraint::LineOnLineContact::
setDefaultEdgeFrameF(const Transform & defaultEdgeFrameF)75 setDefaultEdgeFrameF(const Transform& defaultEdgeFrameF) {
76 getImpl().invalidateTopologyCache();
77 updImpl().m_def_X_FEf = defaultEdgeFrameF;
78 return *this;
79 }
80
81 Constraint::LineOnLineContact& Constraint::LineOnLineContact::
setDefaultHalfLengthF(Real defaultHalfLengthF)82 setDefaultHalfLengthF(Real defaultHalfLengthF) {
83 getImpl().invalidateTopologyCache();
84 updImpl().m_def_hf = defaultHalfLengthF;
85 return *this;
86 }
87
88 Constraint::LineOnLineContact& Constraint::LineOnLineContact::
setDefaultEdgeFrameB(const Transform & defaultEdgeFrameB)89 setDefaultEdgeFrameB(const Transform& defaultEdgeFrameB) {
90 getImpl().invalidateTopologyCache();
91 updImpl().m_def_X_BEb = defaultEdgeFrameB;
92 return *this;
93 }
94
95 Constraint::LineOnLineContact& Constraint::LineOnLineContact::
setDefaultHalfLengthB(Real defaultHalfLengthB)96 setDefaultHalfLengthB(Real defaultHalfLengthB) {
97 getImpl().invalidateTopologyCache();
98 updImpl().m_def_hb = defaultHalfLengthB;
99 return *this;
100 }
101
102 const MobilizedBody& Constraint::LineOnLineContact::
getMobilizedBodyF() const103 getMobilizedBodyF() const {
104 const LineOnLineContactImpl& impl = getImpl();
105 return impl.getMobilizedBodyFromConstrainedBody(impl.m_mobod_F);
106 }
107 const MobilizedBody& Constraint::LineOnLineContact::
getMobilizedBodyB() const108 getMobilizedBodyB() const {
109 const LineOnLineContactImpl& impl = getImpl();
110 return impl.getMobilizedBodyFromConstrainedBody(impl.m_mobod_B);
111 }
112
isEnforcingRolling() const113 bool Constraint::LineOnLineContact::isEnforcingRolling() const
114 { return getImpl().m_enforceRolling; }
115
116 const Transform& Constraint::LineOnLineContact::
getDefaultEdgeFrameF() const117 getDefaultEdgeFrameF() const {return getImpl().m_def_X_FEf;}
118
119 Real Constraint::LineOnLineContact::
getDefaultHalfLengthF() const120 getDefaultHalfLengthF() const {return getImpl().m_def_hf;}
121
122 const Transform& Constraint::LineOnLineContact::
getDefaultEdgeFrameB() const123 getDefaultEdgeFrameB() const {return getImpl().m_def_X_BEb;}
124
125 Real Constraint::LineOnLineContact::
getDefaultHalfLengthB() const126 getDefaultHalfLengthB() const {return getImpl().m_def_hb;}
127
128 const Constraint::LineOnLineContact& Constraint::LineOnLineContact::
setEdgeFrameF(State & state,const Transform & edgeFrameF) const129 setEdgeFrameF(State& state, const Transform& edgeFrameF) const {
130 getImpl().updParameters(state).X_FEf = edgeFrameF;
131 return *this;
132 }
133
134 const Constraint::LineOnLineContact& Constraint::LineOnLineContact::
setHalfLengthF(State & state,Real halfLengthF) const135 setHalfLengthF(State& state, Real halfLengthF) const {
136 getImpl().updParameters(state).hf = halfLengthF;
137 return *this;
138 }
139
140 const Constraint::LineOnLineContact& Constraint::LineOnLineContact::
setEdgeFrameB(State & state,const Transform & edgeFrameB) const141 setEdgeFrameB(State& state, const Transform& edgeFrameB) const {
142 getImpl().updParameters(state).X_BEb = edgeFrameB;
143 return *this;
144 }
145
146 const Constraint::LineOnLineContact& Constraint::LineOnLineContact::
setHalfLengthB(State & state,Real halfLengthB) const147 setHalfLengthB(State& state, Real halfLengthB) const {
148 getImpl().updParameters(state).hb = halfLengthB;
149 return *this;
150 }
151 const Transform& Constraint::LineOnLineContact::
getEdgeFrameF(const State & state) const152 getEdgeFrameF(const State& state) const
153 { return getImpl().getParameters(state).X_FEf; }
154 Real Constraint::LineOnLineContact::
getHalfLengthF(const State & state) const155 getHalfLengthF(const State& state) const
156 { return getImpl().getParameters(state).hf; }
157 const Transform& Constraint::LineOnLineContact::
getEdgeFrameB(const State & state) const158 getEdgeFrameB(const State& state) const
159 { return getImpl().getParameters(state).X_BEb; }
160 Real Constraint::LineOnLineContact::
getHalfLengthB(const State & state) const161 getHalfLengthB(const State& state) const
162 { return getImpl().getParameters(state).hb; }
163
getPositionError(const State & s) const164 Real Constraint::LineOnLineContact::getPositionError(const State& s) const {
165 Real perr;
166 getImpl().getPositionErrors(s, 1, &perr);
167 return perr;
168 }
169
getVelocityErrors(const State & s) const170 Vec3 Constraint::LineOnLineContact::getVelocityErrors(const State& s) const {
171 const LineOnLineContactImpl& impl = getImpl();
172 Vec3 verr_PC; // result is velocity error in P frame
173 if (impl.m_enforceRolling) {
174 Real verr[3];
175 impl.getVelocityErrors(s, 3, verr);
176 verr_PC = Vec3(verr[1],verr[2],verr[0]); // switch to x,y,z order
177 } else {
178 Real pverr;
179 getImpl().getVelocityErrors(s, 1, &pverr);
180 verr_PC = Vec3(0,0,pverr); // lone error is in z direction
181 }
182 return verr_PC;
183 }
184
getAccelerationErrors(const State & s) const185 Vec3 Constraint::LineOnLineContact::getAccelerationErrors(const State& s) const {
186 const LineOnLineContactImpl& impl = getImpl();
187 Vec3 aerr_PC; // result is acceleration error in P frame
188 if (impl.m_enforceRolling) {
189 Real aerr[3];
190 impl.getAccelerationErrors(s, 3, aerr);
191 aerr_PC = Vec3(aerr[1],aerr[2],aerr[0]); // switch to x,y,z order
192 } else {
193 Real paerr;
194 getImpl().getAccelerationErrors(s, 1, &paerr);
195 aerr_PC = Vec3(0,0,paerr); // lone error is in z direction
196 }
197 return aerr_PC;
198 }
199
getMultipliers(const State & s) const200 Vec3 Constraint::LineOnLineContact::getMultipliers(const State& s) const {
201 const LineOnLineContactImpl& impl = getImpl();
202 Vec3 lambda_PC; // result is -force on point F in P frame
203 if (impl.m_enforceRolling) {
204 Real lambda[3];
205 impl.getMultipliers(s, 3, lambda);
206 lambda_PC = Vec3(lambda[1],lambda[2],lambda[0]); //switch to x,y,z order
207 } else {
208 Real lambda;
209 getImpl().getMultipliers(s, 1, &lambda);
210 lambda_PC = Vec3(0,0,lambda); // lone force is in z direction
211 }
212 return lambda_PC;
213 }
214
215 Vec3 Constraint::LineOnLineContact::
findForceOnBodyBInG(const State & s) const216 findForceOnBodyBInG(const State& s) const {
217 const LineOnLineContactImpl& impl = getImpl();
218 if (impl.isDisabled(s))
219 return Vec3(0);
220
221 const Transform X_GC = findContactFrameInG(s);
222
223 const Vec3 f_C = -getMultipliers(s); // watch sign convention
224 return X_GC.R()*f_C;
225 }
226
227 Transform Constraint::LineOnLineContact::
findContactFrameInG(const State & s) const228 findContactFrameInG(const State& s) const {
229 const LineOnLineContactImpl& impl = getImpl();
230 const LineOnLineContactImpl::PositionCache& pc =
231 impl.ensurePositionCacheRealized(s);
232
233 const MobilizedBody& mobod_A = impl.getAncestorMobilizedBody();
234 if (mobod_A.isGround())
235 return pc.X_AC; // == X_GC
236
237 const Transform& X_GA = mobod_A.getBodyTransform(s);
238 return X_GA * pc.X_AC; // 63 flops
239 }
240
241 void Constraint::LineOnLineContact::
findClosestPointsInG(const State & s,Vec3 & Qf_G,Vec3 & Qb_G,bool & linesAreParallel) const242 findClosestPointsInG(const State& s, Vec3& Qf_G, Vec3& Qb_G,
243 bool& linesAreParallel) const {
244 const LineOnLineContactImpl& impl = getImpl();
245 const LineOnLineContactImpl::PositionCache& pc =
246 impl.ensurePositionCacheRealized(s);
247
248 const MobilizedBody& mobod_A = impl.getAncestorMobilizedBody();
249 if (mobod_A.isGround()) {
250 Qf_G = pc.p_AQf;
251 Qb_G = pc.p_AQb;
252 } else {
253 const Transform& X_GA = mobod_A.getBodyTransform(s);
254 Qf_G = X_GA * pc.p_AQf; // 18 flops
255 Qb_G = X_GA * pc.p_AQb; // 18 flops
256 }
257 }
258
259 // The separation is the signed distance between the lines' closest points.
260 // Same as perr routine, but works when constraint is disabled.
261 Real Constraint::LineOnLineContact::
findSeparation(const State & s) const262 findSeparation(const State& s) const {
263 const LineOnLineContactImpl::PositionCache& pc =
264 getImpl().ensurePositionCacheRealized(s);
265
266 const Real r = ~pc.p_PfPb_A * pc.n_A; // 5 flops
267 return r;
268 }
269
270
271 //==============================================================================
272 // LINE ON LINE CONTACT IMPL
273 //==============================================================================
274
275 // The default parameters may be overridden by setting a discrete variable in
276 // the state, and we need a couple of cache entries to hold expensive
277 // computations. We allocate the state resources here.
278 void Constraint::LineOnLineContactImpl::
realizeTopologyVirtual(State & state) const279 realizeTopologyVirtual(State& state) const {
280 m_parametersIx = getMyMatterSubsystemRep().
281 allocateDiscreteVariable(state, Stage::Position,
282 new Value<Parameters>(Parameters(m_def_X_FEf, m_def_hf,
283 m_def_X_BEb, m_def_hb)));
284
285 m_posCacheIx = getMyMatterSubsystemRep().
286 allocateLazyCacheEntry(state, Stage::Position,
287 new Value<PositionCache>());
288
289 m_velCacheIx = getMyMatterSubsystemRep().
290 allocateLazyCacheEntry(state, Stage::Velocity,
291 new Value<VelocityCache>());
292 }
293
294 const Constraint::LineOnLineContactImpl::Parameters&
295 Constraint::LineOnLineContactImpl::
getParameters(const State & state) const296 getParameters(const State& state) const {
297 return Value<Parameters>::downcast
298 (getMyMatterSubsystemRep().getDiscreteVariable(state,m_parametersIx));
299 }
300
301 Constraint::LineOnLineContactImpl::Parameters&
302 Constraint::LineOnLineContactImpl::
updParameters(State & state) const303 updParameters(State& state) const {
304 return Value<Parameters>::updDowncast
305 (getMyMatterSubsystemRep().updDiscreteVariable(state,m_parametersIx));
306 }
307
308 const Constraint::LineOnLineContactImpl::PositionCache&
309 Constraint::LineOnLineContactImpl::
getPositionCache(const State & state) const310 getPositionCache(const State& state) const {
311 return Value<PositionCache>::downcast
312 (getMyMatterSubsystemRep().getCacheEntry(state,m_posCacheIx));
313 }
314
315 Constraint::LineOnLineContactImpl::PositionCache&
316 Constraint::LineOnLineContactImpl::
updPositionCache(const State & state) const317 updPositionCache(const State& state) const {
318 return Value<PositionCache>::updDowncast
319 (getMyMatterSubsystemRep().updCacheEntry(state,m_posCacheIx));
320 }
321
322 const Constraint::LineOnLineContactImpl::VelocityCache&
323 Constraint::LineOnLineContactImpl::
getVelocityCache(const State & state) const324 getVelocityCache(const State& state) const {
325 return Value<VelocityCache>::downcast
326 (getMyMatterSubsystemRep().getCacheEntry(state,m_velCacheIx));
327 }
328
329 Constraint::LineOnLineContactImpl::VelocityCache&
330 Constraint::LineOnLineContactImpl::
updVelocityCache(const State & state) const331 updVelocityCache(const State& state) const {
332 return Value<VelocityCache>::updDowncast
333 (getMyMatterSubsystemRep().updCacheEntry(state,m_velCacheIx));
334 }
335
336 // This costs about 213 flops.
337 void Constraint::LineOnLineContactImpl::
calcPositionInfo(const State & state,const Transform & X_AF,const Transform & X_AB,PositionCache & pc) const338 calcPositionInfo(const State& state,
339 const Transform& X_AF, const Transform& X_AB,
340 PositionCache& pc) const
341 {
342 const Parameters& params = getParameters(state);
343 const UnitVec3& df_F = params.X_FEf.x();
344 const UnitVec3& db_B = params.X_BEb.x();
345 const UnitVec3& sf_F = params.X_FEf.z(); // outward normal
346 const UnitVec3& sb_B = params.X_BEb.z();
347 const Vec3& p_FPf = params.X_FEf.p();
348 const Vec3& p_BPb = params.X_BEb.p();
349
350 pc.df_A = X_AF.R() * df_F; // 15 flops
351 pc.db_A = X_AB.R() * db_B; // 15
352 pc.p_FPf_A = X_AF.R() * p_FPf; // 15
353 pc.p_BPb_A = X_AB.R() * p_BPb; // 15
354 const Vec3 p_APf = X_AF.p() + pc.p_FPf_A; // 3
355 const Vec3 p_APb = X_AB.p() + pc.p_BPb_A; // 3
356 pc.p_PfPb_A = p_APb - p_APf; // 3
357
358 const UnitVec3 sf_A = X_AF.R() * sf_F; // 15 flops
359 const UnitVec3 sb_A = X_AB.R() * sb_B; // 15
360 const Vec3 wraw_A = pc.df_A % pc.db_A; // 9
361
362 // Use whichever of the outward normal directions gives a clearer signal.
363 // We want w point out from F or into B. ~12 flops
364 const Real wsf = ~wraw_A*sf_A, wsb = ~wraw_A*sb_A;
365 if (std::abs(wsf) > std::abs(wsb)) pc.sense = (wsf >= 0 ? 1 : -1);
366 else pc.sense = (wsb >= 0 ? -1 : 1);
367
368 pc.w_A = pc.sense * wraw_A; // 3 flops
369 const Real sinTheta = pc.w_A.norm(); //~20
370
371 //TODO: should do something better than this for parallel edges. Not clear
372 // that an exception is best though since this might occur prior to an
373 // assembly analysis that would fix the problem. Also consider if we're
374 // doing event-driven contact we may need to catch the event of edges
375 // going from crossed to parallel to turn off the edge/edge contact.
376
377 if (sinTheta < SignificantReal) { // 1 flop
378 pc.edgesAreParallel = true;
379 pc.oos = 1/SignificantReal; // just to avoid NaN-ing if sinTheta==0
380 } else {
381 pc.edgesAreParallel = false;
382 pc.oos = 1/sinTheta; //~10
383 }
384
385 pc.n_A = UnitVec3(pc.w_A * pc.oos, true); // 3
386
387 pc.pXn = pc.p_PfPb_A % pc.n_A; // 9 flops
388
389 const Real f = -pc.sense*pc.oos; // 2 flops
390 pc.tf = f*dot(pc.db_A, pc.pXn); // 6
391 pc.tb = f*dot(pc.df_A, pc.pXn); // 6
392
393 // Create the contact frame C. The origin should be half way between
394 // Qf and Qb. The z axis is the contact normal n. x is along edge Ef, in
395 // direction df. y = z X x = n X df.
396 pc.p_AQf = p_APf + pc.tf * pc.df_A; // 6 flops
397 pc.p_AQb = p_APb + pc.tb * pc.db_A; // 6
398 const Vec3 p_ACo = 0.5*(pc.p_AQf + pc.p_AQb); // 6
399 pc.X_AC.updP() = p_ACo;
400
401 // Since unit vector n is perpendicular to df (and db), n X df
402 // is already a unit vector without normalizing.
403 const UnitVec3 nXdf(pc.n_A % pc.df_A, true); // 9 flops
404 pc.X_AC.updR().setRotationFromUnitVecsTrustMe(pc.df_A, nXdf, pc.n_A);
405
406 // Vectors from F and B body origins to contact point, expressed in A.
407 // These are the station locations at which forces are applied.
408 pc.p_FCo_A = p_ACo - X_AF.p(); // 3 flops
409 pc.p_BCo_A = p_ACo - X_AB.p(); // 3
410 }
411
412
413 const Constraint::LineOnLineContactImpl::PositionCache&
414 Constraint::LineOnLineContactImpl::
ensurePositionCacheRealized(const State & s) const415 ensurePositionCacheRealized(const State& s) const {
416 if (getMyMatterSubsystemRep().isCacheValueRealized(s, m_posCacheIx))
417 return getPositionCache(s);
418 PositionCache& pc = updPositionCache(s);
419
420 const Transform& X_AF = getBodyTransformFromState(s, m_mobod_F);
421 const Transform& X_AB = getBodyTransformFromState(s, m_mobod_B);
422
423 calcPositionInfo(s, X_AF, X_AB, pc);
424
425 getMyMatterSubsystemRep().markCacheValueRealized(s, m_posCacheIx);
426 return pc;
427 }
428
429
430 // This costs about 340 flops if position info has already been calculated,
431 // otherwise we also pay for ensurePositionCacheRealized().
432 void Constraint::LineOnLineContactImpl::
calcVelocityInfo(const State & state,const SpatialVec & V_AF,const SpatialVec & V_AB,VelocityCache & vc) const433 calcVelocityInfo(const State& state,
434 const SpatialVec& V_AF, const SpatialVec& V_AB,
435 VelocityCache& vc) const
436 {
437 const PositionCache& pc = ensurePositionCacheRealized(state);
438 if (pc.edgesAreParallel)
439 return;
440
441 const Vec3& w_AF = V_AF[0]; // handy abbreviations
442 const Vec3& v_AF = V_AF[1];
443 const Vec3& w_AB = V_AB[0];
444 const Vec3& v_AB = V_AB[1];
445
446 // These are d/dt_A p_FPf and d/dt_A p_BPb
447 const Vec3 wX_p_FPf_A = w_AF % pc.p_FPf_A; // 9 flops
448 const Vec3 wX_p_BPb_A = w_AB % pc.p_BPb_A; // 9
449 const Vec3 v_APf = v_AF + wX_p_FPf_A; // 3
450 const Vec3 v_APb = v_AB + wX_p_BPb_A; // 3
451 vc.dp_PfPb_A = v_APb - v_APf; // 3
452
453 vc.ddf_A = w_AF % pc.df_A; // 9 flops
454 vc.ddb_A = w_AB % pc.db_A; // 9
455 vc.dw_A = pc.sense*(vc.ddf_A % pc.db_A + pc.df_A % vc.ddb_A);//24
456 vc.dn_A = pc.oos * (vc.dw_A - (~pc.n_A*vc.dw_A)*pc.n_A); // 14
457
458 // Calculate the velocity of B's material point (station) at Co,
459 // measured in the F frame and expressed in A.
460 const Vec3 vA_BCo_A = v_AB + w_AB % pc.p_BCo_A; // 12 flops
461 const Vec3 vA_FCo_A = v_AF + w_AF % pc.p_FCo_A; // 12
462 vc.vF_BCo_A = vA_BCo_A - vA_FCo_A; // 3
463
464 // We have s=||w||, oos=1/s. We want doos = d/dt oos.
465 vc.doos = -square(pc.oos) * dot(pc.n_A, vc.dw_A); // 8 flops
466
467 const Vec3 nXdb = pc.n_A % pc.db_A; // 9 flops
468 const Vec3 nXdf = pc.n_A % pc.df_A; // 9
469 const Vec3 d_nXdb = vc.dn_A % pc.db_A + pc.n_A % vc.ddb_A; // 21
470 const Vec3 d_nXdf = vc.dn_A % pc.df_A + pc.n_A % vc.ddf_A; // 21
471 const Real dtf = -pc.sense * ( // 20
472 pc.oos * (~vc.dp_PfPb_A*nXdb + ~pc.p_PfPb_A*d_nXdb)
473 + vc.doos * (~pc.p_PfPb_A*nXdb) );
474 const Real dtb = -pc.sense * ( // 20
475 pc.oos * (~vc.dp_PfPb_A*nXdf + ~pc.p_PfPb_A*d_nXdf)
476 + vc.doos * (~pc.p_PfPb_A*nXdf) );
477
478 const Vec3 dQf = v_APf + dtf * pc.df_A + pc.tf * vc.ddf_A; // 12 flops
479 const Vec3 dQb = v_APb + dtb * pc.db_A + pc.tb * vc.ddb_A; // 12
480 const Vec3 dCo = 0.5*(dQf + dQb); // 6
481 const Vec3 dp_FCo = dCo - v_AF; // 3
482 const Vec3 dp_BCo = dCo - v_AB; // 3
483
484 vc.wXdp_FCo_A = w_AF % dp_FCo; // 9 flops
485 vc.wXdp_BCo_A = w_AB % dp_BCo; // 9
486 vc.ddfXddb2 = 2.*(vc.ddf_A % vc.ddb_A); // 12
487 vc.wXddf_A = w_AF % vc.ddf_A; // 9
488 vc.wXddb_A = w_AB % vc.ddb_A; // 9
489
490 // These are the Coriolis accelerations of Pf and Pb, needed later.
491 vc.wXwX_p_FPf_A = w_AF % wX_p_FPf_A; // 9 flops
492 vc.wXwX_p_BPb_A = w_AB % wX_p_BPb_A; // 9
493
494 // Record derivative of the contact frame.
495 // We have Cx=df, Cz=n, Cy=n x df. Want derivatives in A.
496 vc.dCx_A = vc.ddf_A;
497 vc.dCz_A = vc.dn_A;
498 vc.dCy_A = d_nXdf;
499 vc.dCo_A = dCo;
500 }
501
502 const Constraint::LineOnLineContactImpl::VelocityCache&
503 Constraint::LineOnLineContactImpl::
ensureVelocityCacheRealized(const State & s) const504 ensureVelocityCacheRealized(const State& s) const {
505 if (getMyMatterSubsystemRep().isCacheValueRealized(s, m_velCacheIx))
506 return getVelocityCache(s);
507 VelocityCache& vc = updVelocityCache(s);
508 const SpatialVec& V_AF = getBodyVelocityFromState(s, m_mobod_F);
509 const SpatialVec& V_AB = getBodyVelocityFromState(s, m_mobod_B);
510
511 calcVelocityInfo(s, V_AF, V_AB, vc);
512
513 getMyMatterSubsystemRep().markCacheValueRealized(s, m_velCacheIx);
514 return vc;
515 }
516
517 void Constraint::LineOnLineContactImpl::
calcDecorativeGeometryAndAppendVirtual(const State & s,Stage stage,Array_<DecorativeGeometry> & geom) const518 calcDecorativeGeometryAndAppendVirtual
519 (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const
520 {
521 // We can't generate the artwork until we know the lines' placements,
522 // which might not be until Position stage.
523 if ( stage != Stage::Position
524 || !getMyMatterSubsystemRep().getShowDefaultGeometry())
525 return;
526
527 const Parameters& params = getParameters(s);
528 const Real hf = params.hf;
529 const Real hb = params.hb;
530
531 const PositionCache& pc = ensurePositionCacheRealized(s);
532 const Transform& X_AC = pc.X_AC;
533
534 const MobilizedBody& mobod_A = getAncestorMobilizedBody();
535 const Transform& X_GA = mobod_A.getBodyTransform(s);
536 const Rotation& R_GA = X_GA.R();
537
538 const Transform X_GC = X_GA * X_AC;
539
540 // Convert interesting stuff from A to G.
541 const UnitVec3 df_G = R_GA * X_AC.x();
542 const UnitVec3 db_G = R_GA * pc.db_A;
543 const Vec3 p_GQf = X_GA * pc.p_AQf;
544 const Vec3 p_GQb = X_GA * pc.p_AQb;
545 const Vec3 half_Lf = hf * df_G;
546 const Vec3 half_Lb = hb * db_G;
547
548 const MobilizedBody& bodyF = getMobilizedBodyFromConstrainedBody(m_mobod_F);
549 const MobilizedBody& bodyB = getMobilizedBodyFromConstrainedBody(m_mobod_B);
550
551 const Transform& X_GF = bodyF.getBodyTransform(s);
552 const Transform& X_GB = bodyB.getBodyTransform(s);
553 const Transform X_GEf = X_GF * params.X_FEf;
554 const Transform X_GEb = X_GB * params.X_BEb;
555
556
557 // On body F draw a green line segment around the orange closest point.
558 geom.push_back(DecorativeLine(p_GQf-half_Lf, p_GQf+half_Lf)
559 .setColor(Green));
560 geom.push_back(DecorativeFrame().setTransform(X_GEf)
561 .setColor(Green*.9).setLineThickness(1).setScale(0.5)); // F color
562 geom.push_back(DecorativePoint(p_GQf)
563 .setColor(Orange).setLineThickness(2)); // B color
564
565 // On body B draw an orange line segment around the green closest point.
566 geom.push_back(DecorativeLine(p_GQb-half_Lb, p_GQb+half_Lb)
567 .setColor(Orange));
568 geom.push_back(DecorativeFrame().setTransform(X_GEb)
569 .setColor(Orange*.9).setLineThickness(1).setScale(0.5)); // B color
570 geom.push_back(DecorativePoint(p_GQb)
571 .setColor(Green).setLineThickness(2)); // F color
572
573 // Show the contact frame in red.
574 geom.push_back(DecorativeFrame().setTransform(X_GC)
575 .setColor(Red));
576 }
577
578
579 } // namespace SimTK
580
581