4 Mechanical Models II

4.9 General component arrangements

As discussed in Section 1.1.5 and elsewhere, a MechModel provides a number of predefined child components for storing particles, rigid bodies, springs, constraints, and other components. However, applications are not required to store their components in these containers, and may instead create any sort of component arrangement desired.

For example, suppose that one wishes to create a biomechanical model of both the right and left human arms, consisting of bones, point-to-point muscles, and joints. The standard containers supplied by MechModel would require that all the components be placed within the following containers:

   rigidBodies          // all bones
   axialSprings         // all point-to-point muscles
   connectors           // all joints

Instead of this, one may wish to set up a more appropriate component hierarchy, such as

   leftArm              // left-arm components
      bones             //   left bones
      muscles           //   left muscles
      joints            //   left joints
   rightArm             // right-arm components
      bones             //   right bones
      muscles           //   right muscles
      joints            //   right joints

To do this, the application build() method can create the necessary hierarchy and then populate it with whatever components are desired. Before simulation begins (or whenever the model structure is changed), the MechModel will recursively traverse the component hierarchy and update whatever internal structures are needed to run the simulation.

4.9.1 Container components

The generic class ComponentList can be used as a container for model components of a specific type. It can be created using a declaration of the form

   ComponentList<Particle> list = new ComponentList<Type> (Type.class, name);

where Type is the class type of the components and name is the name for the container. Once the container is created, it should be added to the MechModel (or another internal container) and populated with child components of the specified type. For example,

   MechModel mech;
   ...
   ComponentList<Particle> parts =
      new ComponentList<Particle> (Particle.class, "parts");
   ComponentList<Frame> frames =
      new ComponentList<Frame> (Frame.class, "frames");
   // add containers to the mech model
   mech.add (parts);
   mech.add (frames);

creates two containers named "parts" and "frames" for storing components of type Particle and Frame, respectively, and adds them to a MechModel referenced by mech.

In addition to ComponentList, applications may use several "specialty" container types which are subclasses of ComponentList:

RenderableComponentList

A subclass of ComponentList, that has its own set of render properties which can be inherited by its children. This can be useful for compartmentalizing render behavior. Note that it is not necessary to store renderable components in a RenderableComponentList; components stored in a ComponentList will be rendered too.

PointList

A RenderableComponentList that is optimized for rendering points, and also contains its own pointDamping property that can be inherited by its children.

PointSpringList

A RenderableComponentList designed for storing point-based springs. It contains a material property that specifies a default axial material that can be used by its children.

AxialSpringList

A PointSpringList that is optimized for rendering two-point axial springs.

If necessary, it is relatively easy to define one’s own customized list by subclassing one of the other list types. One of the main reasons for doing so, as suggested above, is to supply default properties to be inherited by the list’s descendants.

A component list which declares ModelComponent as its type can be used to store any type of component, including other component lists. This allows the creation of arbitrary component hierarchies. Generally eitherComponentList<ModelComponent> or RenderableComponentList<ModelComponent> are best suited to implement hierarchical groupings.

4.9.2 Example: a net formed from balls and springs

Figure 4.16: NetDemo model loaded into ArtiSynth.

A simple example showing an arrangement of balls and springs formed into a net is defined in

  artisynth.demos.tutorial.NetDemo

The build() method and some of the supporting definitions for this example are shown below.

1    protected double stiffness = 1000.0;   // spring stiffness
2    protected double damping = 10.0;       // spring damping
3    protected double maxForce = 5000.0;    // max force with excitation = 1
4    protected double mass = 1.0;           // mass of each ball
5    protected double widthx = 20.0;        // width of the net along x
6    protected double widthy = 20.0;        // width of the net along y
7    protected int numx = 8;                // num balls along x
8    protected int numy = 8;                // num balls along y
9
10    // custom component containers
11    protected MechModel mech;
12    protected PointList<Particle> balls;
13    protected ComponentList<ModelComponent> springs;
14    protected RenderableComponentList<AxialSpring> greenSprings;
15    protected RenderableComponentList<AxialSpring> blueSprings;
16
17    private AxialSpring createSpring (
18       PointList<Particle> parts, int idx0, int idx1) {
19       // create a "muscle" spring connecting particles indexed by ’idx0’ and
20       // ’idx1’ in the list ’parts’
21       Muscle spr = new Muscle (parts.get(idx0), parts.get(idx1));
22       spr.setMaterial (new SimpleAxialMuscle (stiffness, damping, maxForce));
23       return spr;
24    }
25
26    public void build (String[] args) {
27
28       // create MechModel and add to RootModel
29       mech = new MechModel ("mech");
30       mech.setGravity (0, 0, -980.0);
31       mech.setPointDamping (1.0);
32       addModel (mech);
33
34       int nump = (numx+1)*(numy+1); // nump = total number of balls
35
36       // create custom containers:
37       balls = new PointList<Particle> (Particle.class, "balls");
38       springs = new ComponentList<ModelComponent>(ModelComponent.class,"springs");
39       greenSprings = new RenderableComponentList<AxialSpring> (
40          AxialSpring.class, "greenSprings");
41       blueSprings = new RenderableComponentList<AxialSpring> (
42          AxialSpring.class, "blueSprings");
43
44       // create balls in a grid pattern and add to the list ’balls’
45       for (int i=0; i<=numx; i++) {
46          for (int j=0; j<=numy; j++) {
47             double x = widthx*(-0.5+i/(double)numx);
48             double y = widthy*(-0.5+j/(double)numy);
49             Particle p = new Particle (mass, x, y, /*z=*/0);
50             balls.add (p);
51             // fix balls along the edges parallel to y
52             if (i == 0 || i == numx) {
53                p.setDynamic (false);
54             }
55          }
56       }
57
58       // connect balls by green springs parallel to y
59       for (int i=0; i<=numx; i++) {
60          for (int j=0; j<numy; j++) {
61             greenSprings.add (
62                createSpring (balls, i*(numy+1)+j, i*(numy+1)+j+1));
63          }
64       }
65       // connect balls by blue springs parallel to x
66       for (int j=0; j<=numy; j++) {
67          for (int i=0; i<numx; i++) {
68             blueSprings.add (
69                createSpring (balls, i*(numy+1)+j, (i+1)*(numy+1)+j));
70          }
71       }
72
73       // add containers to the mechModel
74       springs.add (greenSprings);
75       springs.add (blueSprings);
76       mech.add (balls);
77       mech.add (springs);
78
79       // set render properties for the components
80       RenderProps.setLineColor (greenSprings, new Color(0f, 0.5f, 0f));
81       RenderProps.setLineColor (blueSprings, Color.BLUE);
82       RenderProps.setSphericalPoints (mech, widthx/50.0, Color.RED);
83       RenderProps.setCylindricalLines (mech, widthx/100.0, Color.BLUE);
84    }

The build() method begins by creating a MechModel in the usual way (lines 29-30). It then creates a net composed of a set of balls arranged as a uniform grid in the x-y plane, connected by a set of green colored springs running parallel to the y axis and a set of blue colored springs running parallel to the x axis. These are arranged into a component hierarchy of the form

   balls
   springs
      greenSprings
      blueSprings

using containers created at lines 37-42. The balls are then created and added to balls (lines 45-56), the springs are created and added to greenSprings and blueSprings (lines 59-71), and the containers are added to the MechModel at lines 74-77. The balls along the edges parallel to the y axis are fixed. Render properties are set at lines 80-83, with the colors for greenSprings and blueSprings being explicitly set to dark green and blue.

MechModel, along with other classes derived from ModelBase, enforces reference containment. That means that all components referenced by components within a MechModel must themselves be contained within the MechModel. This condition is checked whenever a component is added directly to a MechModel or one of its ancestors. This means that the components must be added to the MechModel in an order that ensures any referenced components are already present. For example, in the NetDemo example above, adding the particle list after the spring list would generate an error.

To run this example in ArtiSynth, select All demos > tutorial > NetDemo from the Models menu. The model should load and initially appear as in Figure 4.16. Running the model will cause the net to fall and sway under gravity. When the ArtiSynth navigation panel is opened and expanded, the component hierarchy will appear as in Figure 4.17. While the standard MechModel containers are still present, they are not displayed by default because they are empty.

Figure 4.17: NetDemo components displayed in the ArtiSynth navigation panel.

4.9.3 Adding containers to other models

In addition to MechModel, application-defined containers can be added to any model that inherits from ModelBase. This includes RootModel and FemModel. However, at the present time, components added to such containers won’t do anything, other than be rendered in the viewer if they are Renderable.