5 Simulation Control

5.1 Control Panels

A control panel is an editing panel that allows for the interactive adjustment of component properties.

It is always possible to adjust component properties through the GUI by selecting one or more components and then choosing Edit properties ... in the right-click context menu. However, it may be tedious to repeatedly select the required components, and the resulting panels present the user with all properties common to the selection. A control panel allows an application to provide a customized editing panel for selected properties.

5.1.1 General principles

Control panels are implemented by the ControlPanel model component. They can be set up within a model’s build() method by creating an instance of ControlPanel, populating it with widgets for editing the desired properties, and then adding it to the root model using the latter’s addControlPanel() method.

One of the most commonly used means of adding widgets to a control panel is the method addWidget(comp,propertyPath), which creates a widget for a property specified by propertyPath with respect to the component comp. Property paths are discussed in the Section 1.4.2, and can consist solely of a property name, or, for properties located in descendant components, a component path followed by a colon ‘:’ and the property name.

Other flavors of addWidget() also exist, as described in the API documentation for ControlPanel. In addition to property widgets, any type of Swing or awt component can be added using the method addWidget(awtcomp).

Control panels can also be created interactively using the GUI; see the section “Control Panels” in the ArtiSynth User Interface Guide.

5.1.2 Example: Creating a simple control panel

Figure 5.1: Control panel created by the model SimpleMuscleWithPanel.

An application model showing a control panel is defined in

  artisynth.demos.tutorial.SimpleMuscleWithPanel

This model simply extends SimpleMuscle (Section 4.4.2) to provide a control panel for adjusting gravity, the mass and color of the box, and the muscle excitation. The class definition, excluding include statements, is shown below:

1 public class SimpleMuscleWithPanel extends SimpleMuscle {
2    ControlPanel panel;
3
4    public void build (String[] args) throws IOException {
5
6       super.build (args);
7
8       // add control panel for gravity, rigid body mass and color, and excitation
9       panel = new ControlPanel("controls");
10       panel.addWidget (mech, "gravity");
11       panel.addWidget (mech, "rigidBodies/box:mass");
12       panel.addWidget (mech, "rigidBodies/box:renderProps.faceColor");
13       panel.addWidget (new JSeparator());
14       panel.addWidget (muscle, "excitation");
15
16       addControlPanel (panel);
17    }
18 }

The build() method calls super.build() to create the model used by SimpleMuscle. It then proceeds to create a ControlPanel, populate it with widgets, and add it to the root model (lines 8-15). The panel is given the name "controls" in the constructor (line 8); this is its component name and is also used as the title for the panel’s window frame. A control panel does not need to be named, but if it is, then that name must be unique among the control panels.

Lines 9-11 create widgets for three properties located relative to the MechModel referenced by mech. The first is the MechModel’s gravity. The second is the mass of the box, which is a component located relative to mech by the path name (Section 1.1.3) "rigidBodies/box". The third is the box’s face color, which is the sub-property faceColor of the box’s renderProps property.

Line 12 adds a JSeparator to the panel, using the addWidget() method that accepts general components, and line 13 adds a widget to control the excitation property for muscle.

It should be noted that there are different ways to specify target properties in addWidget(). First, component paths may contain numbers instead of names, and so the box’s mass property could be specified using "rigidBodies/0:mass" instead of "rigidBodies/box:mass" since the box’s number is 0. Second, if a reference to a sub-component is available, one can specify properties directly with respect to that, instead of indicating the sub-component in the property path. For example, if the box was referenced by a variable body, then one could use the construction

   panel.addWidget (body, "mass");

in place of

   panel.addWidget (mech, "rigidBodies/box:mass");

To run this example in ArtiSynth, select All demos > tutorial > SimpleMuscleWithPanel from the Models menu. The properties shown in the panel can be adjusted interactively by the user, while the model is either stationary or running.