6 Finite Element Models

6.12 Rendering and Visualizations

In addition to the standard RenderProps that control how the nodes and surfaces appear, finite element models and their sub-components have a few additional properties that affect rendering. Some of these are listed in Table 6.7.

Table 6.7: FEM-specific rendering properties
Property Description
elementWidgetSize size of element to render \in[0,1]
directionRenderLen relative length to draw fibre direction indicator \in[0,1]
directionRenderType where to draw directions: ELEMENT, INTEGRATION_POINT
surfaceRendering how to render surface: None, Shaded, Stress, Strain, MAPStress, MAPStrain
stressPlotRange range of values for stress/strain plot
stressPlotRanging how to determine stress/strain plot range: Auto, Fixed
colorMap delegate object controlling the map of stress/strain values to color

The property elementWidgetSize applies only to FemModel3d and FemElement3d. It specifies the scale to draw each element volume. For instance, the blue beam in Figure 6.17 uses a widget size of 0.8, resulting in a mosaic-like pattern.

The next two properties in Table 6.7 apply to the muscle classes FemMuscleModel, MuscleBundle, and MuscleElementDesc. When directionRenderLen > 0, lines are drawn inside elements to indicate fibre directions. If directionRenderType = ELEMENT, then one line is drawn per element indicating the average contraction direction. If directionRenderType = INTEGRATION_POINT, a separate direction line is drawn per point.

The last four properties apply to FemModel3d and FemMeshComp. They control how the surface is colored. This can be used to enable stress/strain visualizations. The property surfaceRendering sets what to draw:
None no surface Shaded the face color specified by the mesh’s RenderProps Stress the von Mises stress Strain the von Mises strain MAPStress Maximum absolute value principal stress MAPStrain Maximum absolute value principal strain
The stressPlotRange controls the range of values to use when plotting stress/strain. Values outside this range are truncated. The colorMap is a delegate object that converts those stress and strain values to colors. Various types of maps exist, including GreyscaleColorMap, HueColorMap, RainbowColorMap, and JetColorMap. These all implement the ColorMap interface.

To display values corresponding to colors, a ColorBar needs to be added to the RootModel. Color bars are general Renderable objects that are only used for visualizations. They are added to the display using the

addRenderable (Renderable r);

method in RootModel. Color bars also have a ColorMap associated with it. The following functions are useful for controlling its visualization:

setNumberFormat ( String fmtStr );    // C-like numeric format specification
populateLabels ( double min, double max, int tick );     // initialize labels
updateLabels ( double min, double max );                 // update existing labels
setColorMap ( ColorMap map );                            // set color map
// Control position/size of the bar
setNormalizedLocation (double x, double y, double width, double height);
setLocationOverride (double x, double y, double width, double height)

The normalized location specifies sizes relative to the screen size (1 = screen width/height). The location override, if values are non-zero, will override the normalized location, specifying values in absolute pixels. Negative values for position correspond to distances from the left/top. For instance,

setNormalizedLocation(0, 0.1, 0, 0.8);  // set relative positions
setLocationOverride(-40, 0, 20, 0);     // override with pixel lengths

will create a bar that is 10% up from the bottom of the screen, 40 pixels from the right edge, with a height occupying 80% of the screen, and width 20 pixels.

Note that the color bar is not associated with any mesh or finite element model. Any synchronization of colors and labels must be done manually by the developer. It is recommended to do this in the RootModel’s prerender(...) method, so that colors are updated every time the model’s rendering configuration changes.

6.12.1 Example: stress and strain plotting

Figure 6.18: FemBeamColored model loaded into ArtiSynth.

The following model extends FemBeam to render stress, with an added color bar. The loaded model is shown in Figure 6.18.

1 package artisynth.demos.tutorial;
2
3 import java.io.IOException;
4
5 import maspack.render.RenderList;
6 import maspack.util.DoubleInterval;
7 import artisynth.core.femmodels.FemModel.Ranging;
8 import artisynth.core.femmodels.FemModel.SurfaceRender;
9 import artisynth.core.renderables.ColorBar;
10
11 public class FemBeamColored extends FemBeam {
12
13    @Override
14    public void build(String[] args) throws IOException {
15       super.build(args);
16
17       // Show stress on the surface
18       fem.setSurfaceRendering(SurfaceRender.Stress);
19       fem.setStressPlotRanging(Ranging.Auto);
20
21       // Create a colorbar
22       ColorBar cbar = new ColorBar();
23       cbar.setName("colorBar");
24       cbar.setNumberFormat("%.2f");      // 2 decimal places
25       cbar.populateLabels(0.0, 1.0, 10); // Start with range [0,1], 10 ticks
26       cbar.setLocation(-100, 0.1, 20, 0.8);
27       addRenderable(cbar);
28
29    }
30
31    @Override
32    public void prerender(RenderList list) {
33       // Synchronize color bar/values in case they are changed
34       ColorBar cbar = (ColorBar)(renderables().get("colorBar"));
35       cbar.setColorMap(fem.getColorMap());
36       DoubleInterval range = fem.getStressPlotRange();
37       cbar.updateLabels(range.getLowerBound(), range.getUpperBound());
38
39       super.prerender(list);
40    }
41
42 }

6.12.2 Example: rendering contact pressures

As mentioned in Section 4.6.5, it is possible to render the contact pressure involved in the collision between two bodies, and this is often particularly desirable in the case of FEM models. A simple example is defined in

  artisynth.demos.tutorial.ContactPressureRender

which sets the drawColorMap property of the collision behavior to CONTACT_PRESSURE in order to display a color map of the contact pressure. The example is similar to that of Section 4.6.7, which shows how to render penetration depth.

The caveats about color map rendering described in Section 4.6.5 apply. In particular, the resolution of the color map is limited by the resolution of the collision mesh for the collidable on which the map is drawn, and so the application should ensure that this is sufficiently fine. Also, to allow the map to blend properly with the rest of the collidable, the color corresponding to 0 should match the default face color for the collidable.

Figure 6.19: ContactPressureRender showing the contact pressure as a spherical FEM model falls onto an FEM sheet. The color map is drawn on the sheet model, with redder values indicating greater pressure.

The complete source code is shown below:

1 package artisynth.demos.tutorial;
2
3 import java.awt.Color;
4
5 import artisynth.core.femmodels.FemFactory;
6 import artisynth.core.femmodels.FemModel.SurfaceRender;
7 import artisynth.core.femmodels.FemModel3d;
8 import artisynth.core.femmodels.FemNode3d;
9 import artisynth.core.materials.LinearMaterial;
10 import artisynth.core.mechmodels.CollisionBehavior;
11 import artisynth.core.mechmodels.CollisionBehavior.ColorMapType;
12 import artisynth.core.mechmodels.CollisionManager;
13 import artisynth.core.mechmodels.MechModel;
14 import artisynth.core.renderables.ColorBar;
15 import artisynth.core.util.ScalarRange;
16 import artisynth.core.workspace.RootModel;
17 import maspack.matrix.RigidTransform3d;
18 import maspack.render.RenderList;
19 import maspack.render.RenderProps;
20 import maspack.render.color.JetColorMap;
21
22 public class ContactPressureRender extends RootModel {
23
24    double density = 1000;
25    double EPS = 1e-10;
26
27    // Convenience method for creating colors from [0-255] RGB values
28    private static Color createColor (int r, int g, int b) {
29       return new Color (r/255.0f, g/255.0f, b/255.0f);
30    }
31
32    private static Color CREAM = createColor (255, 255, 200);
33    private static Color BLUE_GRAY = createColor (153, 153, 255);
34
35    // Creates and returns a ColorBar renderable object
36    public ColorBar createColorBar() {
37       ColorBar cbar = new ColorBar();
38       cbar.setName("colorBar");
39       cbar.setNumberFormat("%.2f");      // 2 decimal places
40       cbar.populateLabels(0.0, 1.0, 10); // Start with range [0,1], 10 ticks
41       cbar.setLocation(-100, 0.1, 20, 0.8);
42       cbar.setTextColor (Color.WHITE);
43       addRenderable(cbar);               // add to root model’s renderables
44       return cbar;
45    }
46
47    public void build (String[] args) {
48       MechModel mech = new MechModel ("mech");
49       addModel (mech);
50
51       // create FEM ball
52       FemModel3d ball = new FemModel3d("ball");
53       ball.setDensity (density);
54       FemFactory.createIcosahedralSphere (ball, /*radius=*/0.1, /*ndivs=*/2, 1);
55       ball.setMaterial (new LinearMaterial (100000, 0.4));
56       mech.addModel (ball);
57
58       // create FEM sheet
59       FemModel3d sheet = new FemModel3d("sheet");
60       sheet.setDensity (density);
61       FemFactory.createHexGrid (
62          sheet, /*wx*/0.5, /*wy*/0.3, /*wz*/0.05, /*nx*/20, /*ny*/10, /*nz*/1);
63       sheet.transformGeometry (new RigidTransform3d (0, 0, -0.2));
64       sheet.setMaterial (new LinearMaterial (500000, 0.4));
65       sheet.setSurfaceRendering (SurfaceRender.Shaded);
66       mech.addModel (sheet);
67
68       // fix the side nodes of the surface
69       for (FemNode3d n : sheet.getNodes()) {
70          double x = n.getPosition().x;
71          if (Math.abs(x-(-0.25)) <= EPS || Math.abs(x-(0.25)) <= EPS) {
72             n.setDynamic (false);
73          }
74       }
75
76       // create and set a collision behavior between the ball and surface.
77       CollisionBehavior behav = new CollisionBehavior (true, 0);
78       behav.setDrawColorMap (ColorMapType.CONTACT_PRESSURE);
79       behav.setColorMapCollidable (1); // show color map on collidable 1 (sheet);
80       behav.setColorMapRange (new ScalarRange(0, 1.3));
81       mech.setCollisionBehavior (ball, sheet, behav);
82
83       CollisionManager cm = mech.getCollisionManager();
84       // set rendering properties in the collision manager:
85       RenderProps.setVisible (cm, true);    // enable collision rendering
86       // create a custom color map for rendering the penetration depth
87       JetColorMap map = new JetColorMap();
88       map.setColorArray (
89          new Color[] {
90             CREAM,                       // no penetration
91             createColor (255, 204, 153),
92             createColor (255, 153, 102),
93             createColor (255, 102, 51),
94             createColor (255, 51, 0),
95             createColor (204, 0, 0),     // most penetration
96          });
97       cm.setColorMap (map);
98
99       // create a separate color bar to show color map pressure values
100       ColorBar cbar = createColorBar();
101       cbar.updateLabels(0, 1.3);
102       cbar.setColorMap (map);
103
104       // set color for all bodies
105       RenderProps.setFaceColor (mech, CREAM);
106       RenderProps.setLineColor (mech, BLUE_GRAY);
107    }
108 }

To begin, the demo creates two FEM models: a spherical ball (lines 52-56) and a rectangular sheet (lines 59-66), and then fixes the end nodes of the sheet (lines 69-74). Surface rendering is enabled for the sheet (line 65), but not for the ball, in order to improve the visibility of the color map.

Lines 77-81 create and set a collision behavior between the two models, with the drawColorMap property set to CONTACT_PRESSURE. Because for this example we want the color map to be drawn on the second collidable (the sheet), we set the setColorMapCollidable property to 1 (line 79); otherwise, the default value of 0 would cause the color map to be drawn on the first collidable (the ball). (Alternatively, we could have simply defined the collision behavior as being between the surface and the ball instead of the ball and the sheet.) The color map range is explicitly set to lie between [0,1.3] (line 80); this is in contrast to the example in Section 4.6.7, where the range is auto-updated on each step. Other rendering properties are set for the collision manager at lines 83-97, including a custom color map that varies between CREAM (the color of the mesh) for no pressure and dark red for maximum pressure.

At line 100, a color bar is created and added to the scene, using the method createColorBar() (lines 36-45), to explicitly show the pressure that corresponds to the different colors. The color bar is given the same color map and value range used to render the pressure. Finally, default face and line colors for all components in the model are set at lines 105-106.

To run this example in ArtiSynth, select All demos > tutorial > ContactPressureRender from the Models menu. When run, the FEM models will collide and render the contact pressure on the sheet, as shown in Figure 6.19.