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::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));
    }
}