As mentioned in Section 7.1, segments between pairs of via points can be declared wrappable, allowing them to interact with wrappable obstacles. This can be done as via points are added to the spring, using the methods
These make wrappable the next segment to be created (i.e., the segment between the most recently added point and the next point to be added), with numKnots specifying the number of knots that should be used to implement the wrapping. Knots are points that divide the wrappable segment into a piecewise linear curve, and are used to check for collisions with the wrapping surfaces (Figure 7.5). The argument initialPoints used by the second method is an optional argument which, if non-null, can be used to specify intermediate guide points to give the segment an initial path around around any obstacles (for more details, see Section 7.4).
Each wrappable segment will be capable of colliding with any of the wrappable obstacles that are known to the spring. Wrappables can be added, queried and removed using the following methods:
Unlike points, however, there is no implied ordering and wrappables can be added in any order and at any time during the spring’s construction.
Wrappable spring construction is illustrated by the following code fragment:
This creates a new MultiPointSpring with a linear material and three points p0, p1, and p2, forming a start point, via point, and stop point. The segment between p0 and p1 is set to be wrappable with 50 knot points. Two wrappable obstacles are added next, each of which will interact with the p0-p1 segment, but not with the non-wrappable p1-p2 segment. Finally, updateWrapSegments() is called to do an initial solve for the wrapping segments, so that they will be “pulled tight” around any obstacles before simulation begins.
It is also possible to make a segment wrappable after spring construction, using the method
where segIdx identifies the segment between points and .
How many knots should be specified for a wrappable segment? Enough so that the resulting piecewise-linear approximation to the wrapping curve is sufficiently "smooth", and also enough to adequately detect contact with the obstacles without passing through them. Values between 50 and 100 generally give good results. Obstacles that are small with respect to the segment length may necessitate more knots. Making the number of knots very large will slow down the computation (although the computational cost is only with respect to the number of knots).
At the time of this writing, ArtiSynth implements two types of Wrappable object, both of which are instances of RigidBody. The first are specialized analytic subclasses of RigidBody, listed in Table 7.1, which define specific geometries and use analytic methods for the collision handling with the knot points. The use of analytic methods allows for greater accuracy and (possibly) computational efficiency, and so because of this, these special geometry wrappables should be used whenever possible.
|RigidCylinder||A cylinder with a specified height and radius|
|RigidSphere||A sphere with a specified radius|
|RigidEllipsoid||An ellipsoid with specified semi-axis lengths|
|RigidTorus||A torus with specified inner and outer radii|
The second are general rigid bodies which are not analytic subclasses, and for which the wrapping surface is determined directly from the geometry of its collision mesh returned by getCollisionMesh(). (Typically the collision mesh corresponds to the surface mesh, but it is possible to specify alternates; see Section 3.2.8.) This is useful in that it permits wrapping around arbitrary mesh geometries (Figure 7.7), but in order for the wrapping to work well, these geometries should be smooth, without sharp edges or corners. Wrapping around general meshes is implemented using a quadratically interpolated signed-distance grid (Section 4.7), and the resolution of this grid also affects the effective smoothness of the wrapping surface. More details on this are given in Section 7.3.
A example showing multipoint spring wrapping is given by artisynth.demos.tutorial.CylinderWrapping. It consists of a MultiPointSpring passing through a single via point, with both segments on either side of the point made wrappable. Two analytic wrappables are used: a fixed RigidCylinder, and a moving RigidEllipsoid attached to the end of the spring. The code, excluding include directives, is given below:
Lines 4-17 of the build() method create a MechModel with two fixed particles via0 and p1 to be used as via and stop points. Next, two analytic wrappables are created: a RigidCylinder and a RigidEllipsoid, with the former fixed in place and the latter connected to the start of the spring via the marker p0 (lines 20-37). Collisions are enabled between these two wrappables at line 40. The spring itself is created (lines 44-52), using setSegmentWrappable() to make the segments (p0, via0) and (via0, p1) wrappable with 50 knots each, and addWrappable() to make it aware of the two wrappables. Finally, render properties at set (lines 55-58), and a control panel (Section 5.1) is added that allows the spring’s drawKnots and drawABPoints properties to be interactively set.
To run this example in ArtiSynth, select All demos > tutorial > CylinderWrapping from the Models menu. The model should load and initially appear as in Figure 7.8. Running the model will cause the ellipsoid to fall and the spring to wrap around the cylinder. Using the pull tool (Section “Pull Manipulation” in the ArtiSynth User Interface Guide) on the ellipsoid can cause additional motions and make it also collide with the spring. Selecting drawKnots or drawABPoints in the control panel will cause the spring to render its knots and/or A/B points.