7 Muscle Wrapping and Via Points

7.4 Initializing the Wrap Path

By default, when a multipoint spring or muscle is initialized (either at the start of the simulation or as a result of calling updateWrapSegments()), each wrappable segment is initialized to a straight line between its via points. This path is then adjusted to avoid and wrap around obstacles, using artificial linear forces as described in Section 7.6. The result is a local shortest path that wraps around obstacles instead of penetrating them. However, in some cases, the initial path may not be the one desired; instead, one may want it to wrap around obstacles some other way. This can be achieved by specifying additional intermediate points to initialize the segment as a piecewise linear path which threads its way around obstacles in the desired manner (Figure 7.10). These are specified using the optional initialPnts argument to the setSegmentWrappable() methods.

Figure 7.10: By default, the path for each wrappable segment is initialized to a straight line between its via points (dotted line, left), which is then adjusted to wrap around obstacles (solid line, middle). To cause the path to wrap around obstacles in a different way, it can instead be initialized using a piecewise-linear path defined by intermediate initial points (dotted line, right), which will then adjust to an alternate configuration.

When initial points are specified, it is recommended to finish construction of the spring or muscle with a call to updateWrapSegments(). This fits the wrappable segments to their correct path around the obstacles, which can then be seen immediately when the model is first loaded. On the other hand, by omitting an initial call to updateWrapSegments(), it is possible to see the initial path as specified by the initial points. This may be useful to verify that they are in the correct locations.

In some cases, initial points may also be necessary to help ensure that the initial path does not penetrate obstacles. While obstacle penetration will normally be resolved by the artificial forces described in Section 7.6, this may not always work correctly if the starting path penetrates an obstacle too deeply.

7.4.1 Example: wrapping around a torus

Figure 7.11: TorusWrapping model loaded into ArtiSynth.

An example of using initial points is given by artisynth.demos.tutorial.TorusWrapping, in which a spring is wrapped completely around the inner section of a torus. The primary code for the build method is given below:

1       MechModel mech = new MechModel ("mech");
2       addModel (mech);
4       mech.setFrameDamping (1.0); // set damping parameters
5       mech.setRotaryDamping (10.0);
7       // create the torus
8       double DTOR = Math.PI/180;
9       double innerRad = 0.75;
10       double outerRad = 2.0;
11       RigidTorus torus =
12          new RigidTorus ("torus", outerRad, innerRad, /*density=*/1);
13       torus.setPose (new RigidTransform3d (2, 0, -2,  0, DTOR*90, 0));
14       mech.addRigidBody (torus);
16       // create start and end points for the spring
17       Particle p0 = new Particle (0, /*x,y,z=*/4, 0.2, 2);
18       p0.setDynamic (false);
19       mech.addParticle (p0);
20       Particle p1 = new Particle (0, /*x,y,z=*/-3, -0.2, 2);
21       p1.setDynamic (false);
22       mech.addParticle (p1);
24       // create a wrappable MultiPointSpring between p0 and p1, with initial
25       // points specified so that it wraps around the torus
26       MultiPointSpring spring =
27          new MultiPointSpring (/*k=*/10, /*d=*/0, /*restlen=*/0);
28       spring.addPoint (p0);
29       spring.setSegmentWrappable (
30          100, new Point3d[] {
31             new Point3d (3, 0, 0),
32             new Point3d (2, 0, -1),
33             new Point3d (1, 0, 0),
34             new Point3d (2, 0, 1),
35             new Point3d (3, 0, 0),
36             new Point3d (2, 0, -1),
37          });
38       spring.addPoint (p1);
39       spring.addWrappable (torus);
40       spring.updateWrapSegments(); // “shrink wrap” around torus
41       mech.addMultiPointSpring (spring);

The mech model is created in the usual way with frame and rotary damping set to 1 and 10 (lines 4-5). The torus is created using the analytic wrappable RigidTorus (lines 8-14). The spring start and end points p0 and p1 are created at lines (17-22), and the spring itself is created at lines (26-41), with six initial points being specified to setSegmentWrappable() to wrap the spring completely around the torus inner section.

To run this example in ArtiSynth, select All demos > tutorial > TorusWrapping from the Models menu. The torus will slide along the wrapped spring until it reaches equilibrium.