// This costs about 154 flops. const Constraint::SphereOnSphereContactImpl::PositionCache& Constraint::SphereOnSphereContactImpl:: ensurePositionCacheRealized(const State& s) const { if (getMyMatterSubsystemRep().isCacheValueRealized(s, m_posCacheIx)) return getPositionCache(s); const Parameters& params = getParameters(s); const Vec3& p_FSf = params.m_p_FSf; const Vec3& p_BSb = params.m_p_BSb; const Real rf = params.m_radius_F; const Real rb = params.m_radius_B; PositionCache& pc = updPositionCache(s); pc.kf = rf/(rf+rb); // we'll put Co at Sf + kf*p_SfSb, ~10 flops const Transform& X_AF = getBodyTransformFromState(s, m_mobod_F); const Transform& X_AB = getBodyTransformFromState(s, m_mobod_B); const Vec3& p_AF = X_AF.p(); const Vec3& p_AB = X_AB.p(); pc.p_FSf_A = X_AF.R() * p_FSf; // exp. in A, 15 flops const Vec3 p_ASf = X_AF.p() + pc.p_FSf_A; // meas. from Ao, 3 flops pc.p_BSb_A = X_AB.R() * p_BSb; // exp. in A, 15 flops const Vec3 p_ASb = X_AB.p() + pc.p_BSb_A; // meas. from Ao, 3 flops pc.p_SfSb_A = p_ASb - p_ASf; // vec from Sf to Sb, exp. in A, 3 flops pc.r = pc.p_SfSb_A.norm(); // ~20 flops pc.oor = 1/pc.r; // ~10 flops (might be Infinity) // Assume non-singular. UnitVec3 Cz_A(pc.p_SfSb_A * pc.oor, true); // 3 flops pc.isSingular = false; if (pc.r < TinyReal) { pc.isSingular = true; Cz_A = X_AF.z(); // arbitrary } // Now compute the contact frame C, in A. It would be somewhat more elegant // to compute it in F, so that the x-y axis directions would depend only // on the relative pose between the two bodies. However, that is more // expensive than working in A and since the x-y axes are arbitrary and // ephemeral anyway doing it faster seems like the way to go (sherm 140502). // Place the contact point along the center-to-center line. const Vec3 p_ACo(p_ASf + pc.kf*pc.p_SfSb_A); // 6 flops pc.X_AC.updP() = p_ACo; pc.X_AC.updR().setRotationFromOneAxis(Cz_A, ZAxis); // ~60 flops // We'll need contact point Co measured from F and from B. pc.p_FCo_A = p_ACo - p_AF; // 3 flops pc.p_BCo_A = p_ACo - p_AB; // 3 flops getMyMatterSubsystemRep().markCacheValueRealized(s, m_posCacheIx); return pc; }
const Constraint::LineOnLineContactImpl::VelocityCache& Constraint::LineOnLineContactImpl:: ensureVelocityCacheRealized(const State& s) const { if (getMyMatterSubsystemRep().isCacheValueRealized(s, m_velCacheIx)) return getVelocityCache(s); VelocityCache& vc = updVelocityCache(s); const SpatialVec& V_AF = getBodyVelocityFromState(s, m_mobod_F); const SpatialVec& V_AB = getBodyVelocityFromState(s, m_mobod_B); calcVelocityInfo(s, V_AF, V_AB, vc); getMyMatterSubsystemRep().markCacheValueRealized(s, m_velCacheIx); return vc; }
const Constraint::LineOnLineContactImpl::PositionCache& Constraint::LineOnLineContactImpl:: ensurePositionCacheRealized(const State& s) const { if (getMyMatterSubsystemRep().isCacheValueRealized(s, m_posCacheIx)) return getPositionCache(s); PositionCache& pc = updPositionCache(s); const Transform& X_AF = getBodyTransformFromState(s, m_mobod_F); const Transform& X_AB = getBodyTransformFromState(s, m_mobod_B); calcPositionInfo(s, X_AF, X_AB, pc); getMyMatterSubsystemRep().markCacheValueRealized(s, m_posCacheIx); return pc; }
// The default parameters may be overridden by setting a discrete variable in // the state, and we need a couple of cache entries to hold expensive // computations. We allocate the state resources here. void Constraint::LineOnLineContactImpl:: realizeTopologyVirtual(State& state) const { m_parametersIx = getMyMatterSubsystemRep(). allocateDiscreteVariable(state, Stage::Position, new Value<Parameters>(Parameters(m_def_X_FEf, m_def_hf, m_def_X_BEb, m_def_hb))); m_posCacheIx = getMyMatterSubsystemRep(). allocateLazyCacheEntry(state, Stage::Position, new Value<PositionCache>()); m_velCacheIx = getMyMatterSubsystemRep(). allocateLazyCacheEntry(state, Stage::Velocity, new Value<VelocityCache>()); }
// The default plane and sphere parameters may be overridden by setting // a discrete variable in the state. We allocate the state resources here. void Constraint::SphereOnSphereContactImpl:: realizeTopologyVirtual(State& state) const { m_parametersIx = getMyMatterSubsystemRep(). allocateDiscreteVariable(state, Stage::Position, new Value<Parameters>(Parameters(m_def_p_FSf, m_def_radius_F, m_def_p_BSb, m_def_radius_B))); m_posCacheIx = getMyMatterSubsystemRep(). allocateLazyCacheEntry(state, Stage::Position, new Value<PositionCache>()); m_velCacheIx = getMyMatterSubsystemRep(). allocateLazyCacheEntry(state, Stage::Velocity, new Value<VelocityCache>()); }
void Constraint::SphereOnPlaneContactImpl:: calcDecorativeGeometryAndAppendVirtual (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const { // We can't generate the artwork until we know the plane frame and the // sphere center and radius, which might not be until Position stage. if ( stage == Stage::Position && getMyMatterSubsystemRep().getShowDefaultGeometry()) { const SimbodyMatterSubsystemRep& matterRep = getMyMatterSubsystemRep(); const Parameters& params = getParameters(s); const Transform& X_FP = params.m_X_FP; const Vec3& p_BO = params.m_p_BO; const Real r = params.m_radius; // TODO: should be instance-stage data from State rather than // topological data. // This makes z axis point along plane normal const MobilizedBodyIndex planeMBIx = getMobilizedBodyIndexOfConstrainedBody(m_planeBody_F); const MobilizedBodyIndex ballMBIx = getMobilizedBodyIndexOfConstrainedBody(m_ballBody_B); if (m_planeHalfWidth > 0) { // On the inboard body, draw a gray transparent rectangle, // outlined in black lines. geom.push_back(DecorativeBrick (Vec3(m_planeHalfWidth,m_planeHalfWidth,r/10)) .setColor(Gray) .setRepresentation(DecorativeGeometry::DrawSurface) .setOpacity(Real(0.3)) .setBodyId(planeMBIx) .setTransform(X_FP)); geom.push_back(DecorativeFrame(m_planeHalfWidth/5) .setColor(Gray) .setBodyId(planeMBIx) .setTransform(X_FP)); } // On the ball body draw an orange mesh sphere. geom.push_back(DecorativeSphere(r) .setColor(Orange) .setRepresentation(DecorativeGeometry::DrawWireframe) .setBodyId(ballMBIx) .setTransform(p_BO)); } }
void Constraint::LineOnLineContactImpl:: calcDecorativeGeometryAndAppendVirtual (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const { // We can't generate the artwork until we know the lines' placements, // which might not be until Position stage. if ( stage != Stage::Position || !getMyMatterSubsystemRep().getShowDefaultGeometry()) return; const Parameters& params = getParameters(s); const Real hf = params.hf; const Real hb = params.hb; const PositionCache& pc = ensurePositionCacheRealized(s); const Transform& X_AC = pc.X_AC; const MobilizedBody& mobod_A = getAncestorMobilizedBody(); const Transform& X_GA = mobod_A.getBodyTransform(s); const Rotation& R_GA = X_GA.R(); const Transform X_GC = X_GA * X_AC; // Convert interesting stuff from A to G. const UnitVec3 df_G = R_GA * X_AC.x(); const UnitVec3 db_G = R_GA * pc.db_A; const Vec3 p_GQf = X_GA * pc.p_AQf; const Vec3 p_GQb = X_GA * pc.p_AQb; const Vec3 half_Lf = hf * df_G; const Vec3 half_Lb = hb * db_G; const MobilizedBody& bodyF = getMobilizedBodyFromConstrainedBody(m_mobod_F); const MobilizedBody& bodyB = getMobilizedBodyFromConstrainedBody(m_mobod_B); const Transform& X_GF = bodyF.getBodyTransform(s); const Transform& X_GB = bodyB.getBodyTransform(s); const Transform X_GEf = X_GF * params.X_FEf; const Transform X_GEb = X_GB * params.X_BEb; // On body F draw a green line segment around the orange closest point. geom.push_back(DecorativeLine(p_GQf-half_Lf, p_GQf+half_Lf) .setColor(Green)); geom.push_back(DecorativeFrame().setTransform(X_GEf) .setColor(Green*.9).setLineThickness(1).setScale(0.5)); // F color geom.push_back(DecorativePoint(p_GQf) .setColor(Orange).setLineThickness(2)); // B color // On body B draw an orange line segment around the green closest point. geom.push_back(DecorativeLine(p_GQb-half_Lb, p_GQb+half_Lb) .setColor(Orange)); geom.push_back(DecorativeFrame().setTransform(X_GEb) .setColor(Orange*.9).setLineThickness(1).setScale(0.5)); // B color geom.push_back(DecorativePoint(p_GQb) .setColor(Green).setLineThickness(2)); // F color // Show the contact frame in red. geom.push_back(DecorativeFrame().setTransform(X_GC) .setColor(Red)); }
// The default plane and sphere parameters may be overridden by setting // a discrete variable in the state. We allocate the state resources here. void Constraint::SphereOnPlaneContactImpl:: realizeTopologyVirtual(State& state) const { parametersIx = getMyMatterSubsystemRep(). allocateDiscreteVariable(state, Stage::Position, new Value<Parameters> (Parameters(m_def_X_FP, m_def_p_BO, m_def_radius))); }
void Constraint::SphereOnSphereContactImpl:: calcDecorativeGeometryAndAppendVirtual (const State& s, Stage stage, Array_<DecorativeGeometry>& geom) const { // We can't generate the artwork until we know the spheres' centers and // radii, which might not be until Position stage. if ( stage == Stage::Position && getMyMatterSubsystemRep().getShowDefaultGeometry()) { const SimbodyMatterSubsystemRep& matterRep = getMyMatterSubsystemRep(); const Parameters& params = getParameters(s); const Vec3& p_FSf = params.m_p_FSf; const Real rf = params.m_radius_F; const Vec3& p_BSb = params.m_p_BSb; const Real rb = params.m_radius_B; const MobilizedBodyIndex mobodFIx = getMobilizedBodyIndexOfConstrainedBody(m_mobod_F); const MobilizedBodyIndex mobodBIx = getMobilizedBodyIndexOfConstrainedBody(m_mobod_B); // On body F draw a green mesh sphere. geom.push_back(DecorativeSphere(rf) .setColor(Green) .setRepresentation(DecorativeGeometry::DrawWireframe) .setBodyId(mobodFIx) .setTransform(p_FSf)); // On the ball body draw an orange mesh sphere. geom.push_back(DecorativeSphere(rb) .setColor(Orange) .setRepresentation(DecorativeGeometry::DrawWireframe) .setBodyId(mobodBIx) .setTransform(p_BSb)); } }
Constraint::LineOnLineContactImpl::VelocityCache& Constraint::LineOnLineContactImpl:: updVelocityCache(const State& state) const { return Value<VelocityCache>::updDowncast (getMyMatterSubsystemRep().updCacheEntry(state,m_velCacheIx)); }
Constraint::LineOnLineContactImpl::PositionCache& Constraint::LineOnLineContactImpl:: updPositionCache(const State& state) const { return Value<PositionCache>::updDowncast (getMyMatterSubsystemRep().updCacheEntry(state,m_posCacheIx)); }
Constraint::LineOnLineContactImpl::Parameters& Constraint::LineOnLineContactImpl:: updParameters(State& state) const { return Value<Parameters>::updDowncast (getMyMatterSubsystemRep().updDiscreteVariable(state,m_parametersIx)); }
// Return the pair of constrained station points, with the first expressed // in the body 1 frame and the second in the body 2 frame. Note that although // these are used to define the position error, only the station on body 2 // is used to generate constraint forces; the point of body 1 that is // coincident with the body 2 point receives the equal and opposite force. const Constraint::SphereOnPlaneContactImpl::Parameters& Constraint::SphereOnPlaneContactImpl:: getParameters(const State& state) const { return Value<Parameters>::downcast (getMyMatterSubsystemRep().getDiscreteVariable(state,parametersIx)); }
// This costs about 175 flops if position info has already been calculated, // otherwise we also pay for ensurePositionCacheRealized(). const Constraint::SphereOnSphereContactImpl::VelocityCache& Constraint::SphereOnSphereContactImpl:: ensureVelocityCacheRealized(const State& s) const { if (getMyMatterSubsystemRep().isCacheValueRealized(s, m_velCacheIx)) return getVelocityCache(s); const PositionCache& pc = ensurePositionCacheRealized(s); VelocityCache& vc = updVelocityCache(s); const UnitVec3& Cx_A = pc.X_AC.x(); const UnitVec3& Cy_A = pc.X_AC.y(); const UnitVec3& Cz_A = pc.X_AC.z(); const SpatialVec& V_AF = getBodyVelocityFromState(s, m_mobod_F); const Vec3& w_AF = V_AF[0]; const Vec3& v_AF = V_AF[1]; const SpatialVec& V_AB = getBodyVelocityFromState(s, m_mobod_B); const Vec3& w_AB = V_AB[0]; const Vec3& v_AB = V_AB[1]; // These are d/dt_A p_FSf and d/dt_A p_BSb const Vec3 wX_p_FSf_A = w_AF % pc.p_FSf_A; // 9 flops const Vec3 wX_p_BSb_A = w_AB % pc.p_BSb_A; // 9 flops const Vec3 v_ASf = v_AF + wX_p_FSf_A; // 3 flops const Vec3 v_ASb = v_AB + wX_p_BSb_A; // 3 flops vc.pd_SfSb_A = v_ASb - v_ASf; // 3 flops // These are the Coriolis accelerations of Sf and Sb, needed later. vc.wXwX_p_FSf_A = w_AF % wX_p_FSf_A; // 9 flops vc.wXwX_p_BSb_A = w_AB % wX_p_BSb_A; // 9 flops // Calculate the velocity of B's material point (station) at Co, // measured in the F frame and expressed in A. const Vec3 pd_FB_A = v_AB - v_AF; // 3 flops const Vec3 vA_BCo_A = v_AB + w_AB % pc.p_BCo_A; // 12 flops const Vec3 vA_FCo_A = v_AF + w_AF % pc.p_FCo_A; // 12 flops vc.vF_BCo_A = vA_BCo_A - vA_FCo_A; // 3 flops // These are the velocities in the A frame of the *contact point* locations // measured from F's and B's origins; these are not stations since the // contact point moves relative to the F and B frame. const Vec3 pd_FCo_A = w_AF % pc.p_FSf_A + pc.kf*vc.pd_SfSb_A; // 15 flops const Vec3 pd_BCo_A = pd_FCo_A - pd_FB_A; // 3 flops vc.wXpd_FCo_A = w_AF % pd_FCo_A; // 9 flops vc.wXpd_BCo_A = w_AB % pd_BCo_A; // 9 flops // Calculate d/dt_A Cz. vc.Czd_A = pc.isSingular ? w_AF % Cz_A // rare : pc.oor*(vc.pd_SfSb_A - (~vc.pd_SfSb_A*Cz_A)*Cz_A); // 12 flops // We also need d/dt_A of Cx and Cy, which we'll call Cxd and Cyd. Here's // how to get those. Since the x-y directions are arbitrary in the plane, we // can assume that they are not rotating about z, that is, w_FC is in the // x-y plane. Our strategy will be to work in the F frame here, because we // know that CzdF = d/dt_F Cz = w_FC % Cz, a vector perpendicular to both // w_FC and Cz. But that means CzdF is in the x-y plane and since there // was no z component of w_FC it is just w_FC rotated 90 degrees. Since x // and y are also 90 degrees apart, we can get the derivatives we need: // CxdF = -CzdF x Cy // CydF = CzdF x Cx // We can then convert those to A-frame derivatives. To get CzdF: // CzdF = Czd - w_AF % Cz const Vec3 CzdF_A = vc.Czd_A - w_AF % Cz_A; // 12 flops const Vec3 CxdF_A = -CzdF_A % Cy_A; // 12 flops const Vec3 CydF_A = CzdF_A % Cx_A; // 9 flops vc.Cxd_A = CxdF_A + w_AF % Cx_A; // 12 flops vc.Cyd_A = CydF_A + w_AF % Cy_A; // 12 flops getMyMatterSubsystemRep().markCacheValueRealized(s, m_velCacheIx); return vc; }
const Constraint::SphereOnSphereContactImpl::VelocityCache& Constraint::SphereOnSphereContactImpl:: getVelocityCache(const State& state) const { return Value<VelocityCache>::downcast (getMyMatterSubsystemRep().getCacheEntry(state,m_velCacheIx)); }
const Constraint::SphereOnSphereContactImpl::PositionCache& Constraint::SphereOnSphereContactImpl:: getPositionCache(const State& state) const { return Value<PositionCache>::downcast (getMyMatterSubsystemRep().getCacheEntry(state,m_posCacheIx)); }