6 Finite Element Models

6.12 Rendering and Visualizations

Figure 6.17: Component lists of an FEM muscle model displayed in the navigation panel.

An ArtiSynth FEM model can be rendered in a wide variety of ways, by adjusting the rendering of its nodes, elements, meshes (including the surface and other embedded meshes), and, for FemMuscleModel, muscle bundles. Properties for controlling the rendering include both the standard RenderProps (Section 4.3) as well as more specific properties. These can be set either in code, as described below, or by selecting the desired components (or their lists) and then choosing either Edit render props ... (for standard render properties) or Edit properties ... (for component-specific render properties) from the context menu. As mentioned in Section 4.3, standard render properties are inherited, and so if not explicitly specified within a given component, will assume whatever value has been set in the nearest ancestor component, or their default value. Some component-specific render properties are inherited as well.

One very direct way to control the rendering is to control the visibility of the various component lists. This can be done by selecting them in the navigation panel (Figure 6.17) and then choosing “Set invisible” or “Set visible”, as appropriate. It can also be done in code, as shown in the fragment below making the elements and nodes of an FEM model invisible:

  FemModel3d fem;
  // ... initialize the model ...
  RenderProps.setVisible (fem.getNodes(), false);    // make nodes invisible
  RenderProps.setVisible (fem.getElements(), false); // make elements invisible

6.12.1 Nodes

Node rendering is controlled by the point render properties of the standard RenderProps. By default, nodes are set to render as gray points one pixel wide, and so are not highly visible. To increase their visibility, and make them easier to select in the viewer, one can make them appear as spheres of a specified radius and color. In code, this can be done using the RenderProps.setSphericalPoints() method, as in this example,

import java.awt.Color;
import maspack.render.RenderProps;
   ...
   FemModel3d fem;
   ...
   RenderProps.setSphericalPoints (fem, 0.01, Color.GREEN);

which sets the default rendering for all points within the FEM model (which includes the nodes) to be green spheres of radius 0.01. To restrict this to the node list specifically, one could supply fem.getNodes() instead of fem to setSphericalPoints().

Figure 6.18: FEM model with nodes rendered as spheres.

It is also possible to set render properties for individual nodes. For instance, one may wish to mark nodes that are non-dynamic using a different color:

import java.awt.Color;
  ...
  for (FemNode3d node : fem.getNodes()) {
     if (!node.isDynamic()) {
        RenderProps.setPointColor (node, Color.RED);
     }
  }

Figure 6.18 shows an FEM model with nodes rendered as spheres, with the dynamic nodes colored green and the non-dynamic ones red.

6.12.2 Elements

By default, elements are rendered as wireframe outlines, using the lineColor and lineWidth properties of the standard render properties, with defaults of “gray” and 1. To improve visibility, one may wish the change the line color or size, as illustrated by the following fragment:

import java.awt.Color;
import maspack.render.RenderProps;
   ...
   FemModel3d fem;
   ...
   RenderProps.setLineColor (fem, Color.CYAN);
   RenderProps.setLineWidth (fem, 2);

This will set the default line color and width for all components within the FEM model. To restrict this to the elements only, one can specify fem.getElements() (and/or fem.getShellElements()) to the set methods. The fragment above is illustrated in Figure 6.19 (left) for a model created with a call to FemFactory.createHexTorus().

Figure 6.19: Elements of a torus shaped FEM model, rendered as wireframe (left), and using element widgets with an elementWidgetSize of 0.7 (right).

Elements can also be rendered as widgets that depict an approximation of their shape displayed at some fraction of the element’s size (this shape will be 3D for volumetric elements and 2D for shell elements). This is controlled using the FemModel3d property elementWidgetSize, which is restricted to the range [0,1] and describes the size of the widgets relative to the element size. If elementWidgetSize is 0 then no widgets are displayed. The widget color is controlled using the faceColor and alpha properties of the standard render properties. The following code fragment enables element widget rendering for an FEM model, as illustrated in Figure 6.19 (right):

import java.awt.Color;
import maspack.render.RenderProps;
   ...
   FemModel3d fem;
   ...
   fem.setElementWidgetSize (0.7);
   RenderProps.setFaceColor (fem, new Color(0.7f, 0.7f, 1f));
   RenderProps.setLineWidth (fem, 0); // turn off element wire frame

Since setting faceColor for the whole FEM model will also set the default face color for its meshes, one may wish to restrict setting this to the elements only, by specifying fem.getElements() and/or fem.getShellElements() to setFaceColor().

Element widgets can provide a easy way to select specific elements. The elementWidgetSize property is also present as an inherited property in the volumetric and shell element lists (elements and shellElements), as well as individual elements, and so widget rendering can be controlled on a per-element basis.

6.12.3 Surface and other meshes

Figure 6.20: Surface mesh of a torus rendered as a regular mesh (left, with surfaceRendering set to Shaded), and as a color map of the von Mises stress (right, with surfaceRendering set to Stress).

A FEM model can also be rendered using its surface mesh and/or other mesh geometry (Section 6.19). How meshes are rendered is controlled by the property surfaceRendering, which can be assigned any of the values shown in Table 6.5. The value None causes nothing to be rendered, while Shaded causes a mesh to be rendered using the standard rendering properties appropriate to that mesh. For polygonal meshes (which include the surface mesh), this will be done according to the face rendering properties in same way as for rigid bodies (Section 3.2.8). These properties include faceColor, shading, alpha, faceStyle, drawEdges, edgeWidth, and edgeColor (or lineColor if the former is not set). The following code fragment sets an FEM surface to be rendered with blue-gray faces and dark blue edges (Figure 6.20, left):

import java.awt.Color;
import maspack.render.RenderProps;
import artisynth.core.femmodels.FemModel.SurfaceRender;
   ...
   FemModel3d fem;
   ...
   fem.setSurfaceRendering (SurfaceRender.Shaded);
   RenderProps.setFaceColor (fem, new Color (0.7f. 0.7f, 1f));
   RenderProps.setDrawEdges (fem, true);
   RenderProps.setEdgeColor (fem, Color.BLUE);
Table 6.5: Values of the surfaceRendering property controlling how a polygonal FEM is displayed. Scalar stress/strain measures are described in Section 6.11.2
Value Description
None mesh is not rendered
Shaded rendered as a mesh using the standard rendering properties
Stress color map of the von Mises stress
Strain color map the von Mises strain
MAPStress color map of the maximum absolute value principal stress
MAPStrain color map of the maximum absolute value principal strain
MaxShearStress color map of the maximum shear stress
MaxStearStrain color map of the maximum sheer strain
EnergyDensity color map of the strain energy density

Other values of surfaceRendering cause polygonal meshes to be displayed as a color map showing the various stress or strain measures shown in Table 6.5 and described in greater detail in Section 6.11.2. The fragment below sets an FEM surface to be rendered to show the von Mises stress (Figure 6.20, right), while also rendering the edges as dark blue:

import java.awt.Color;
import maspack.render.RenderProps;
import artisynth.core.femmodels.FemModel.SurfaceRender;
   ...
  FemModel3d fem;
   ...
   fem.setSurfaceRendering (SurfaceRender.Stress);
   RenderProps.setDrawEdges (fem, true);
   RenderProps.setEdgeColor (fem, Color.BLUE);

The color maps used in stress/strain rendering are controlled using the following additional properties:

stressPlotRange

The range of numeric values associated with the color map. These are either fixed or updated automatically, according to the property stressPlotRanging. Values outside the range are truncated.

stressPlotRanging

Describes if and how stressPlotRange is updated:

Fixed

Range does not change and should be set by the application.

Auto

Range automatically expands to contain the most recently computed values. Note that this does not cause the range to contract.

colorMap

Value is a delegate object that converts stress and strain values to colors. Various types of maps exist, including HueColorMap (the default), GreyscaleColorMap, RainbowColorMap, and JetColorMap. These all implement the ColorMap interface.

All of these properties are inherited and exported both by FemModel3d and the individual mesh components (which are instances of FemMeshComp), allowing mesh rendering to be controlled on a per-mesh basis.

6.12.4 FEM-based muscles

FemMuscleModel and its subcomponents MuscleBundle export additional properties to control the rendering of muscle bundles and their associated fibre directions. These include:

directionRenderLen

A scalar in the range [0,1], which if >0 causes the fibre directions to be rendered within the elements associated with a MuscleBundle (Section 6.9.3). The directions are rendered as line segments, controlled by the standard line render properties lineColor and lineWidth, and the value of directionRenderLen specifies the length of this segment relative to the size of the element.

directionRenderType

If directionRenderLen >0, this property specifics where the fibre directions should be rendered within muscle bundle elements. The value ELEMENT causes a single direction to be rendered at the element center, while INTEGRATION_POINTS causes directions to be rendered at each of the element’s integration points.

elementWidgetSize

A scalar in the range [0,1], which if >0 causes the elements within a muscle bundle to be rendered using an element widget (Section 6.12.2).

Since these properties are inherited and exported by both FemMuscleModel and MuscleBundle, they can be set for the FEM muscle model as a whole or for individual muscle bundles.

The code fragment below sets the element fibre directions for two muscle bundles to be drawn, one in red and one in green, using a directionRenderLen of 0.5. Each bundle runs horizontally along an FEM beam, one at the top and the other at the bottom (Figure 6.21, left):

   FemModel3d fem;
   ...
   // set line width and directionRenderLen for all bundles and lines
   RenderProps.setLineWidth (fem, 2);
   fem.setDirectionRenderLen (0.5);
   // set line color for FEM elements
   RenderProps.setLineColor (fem, new Color(0.7f, 0.7f, 1f));
   // set line colors for top and bottom bundles
   MuscleBundle top = fem.getMuscleBundles().get("top");
   MuscleBundle bot = fem.getMuscleBundles().get("bot");
   RenderProps.setLineColor (top, Color.RED);
   RenderProps.setLineColor (bot, new Color(0f, 0.8f, 0f));

By default, directionRenderType is set to ELEMENT and so directions are drawn at the element centers. Setting directionRenderType to INTEGRATION_POINT causes the directions to be drawn at each integration points (Figure 6.21, right), which is useful when directions are specified at integration points (Section 6.9.3).

If we are only interested in seeing the elements associated with a muscle bundle, we can use its elementWidgetSize property to draw the elements as widgets (Figure 6.22, left). For this, the last two lines of the fragment above could be replaced with

   RenderProps.setFaceColor (top, Color.RED);
   top.setElementWidgetSize (0.6);
   RenderProps.setFaceColor (bot, new Color(0f, 0.8f, 0f));
   bot.setElementWidgetSize (0.6);

Finally, if the muscle bundle contains point-to-point fibres (Section 6.9.2), these can be rendered by setting the line properties of the standard render properties. For example, the fibre rendering of Figure 6.22 (right) can be set up using the code

   RenderProps.setSpindleLines (top, /*radius=*/0.13, Color.RED);
   RenderProps.setSpindleLines (bot, /*radius=*/0.13, new Color(0f, 0.8f, 0f));
Figure 6.21: Rendering the element fibre directions for two muscle bundles, one in red and one in green, with directionRenderLen of 0.5 and directionRenderType set to ELEMENT (left) and INTEGRATION_POINT (right).
Figure 6.22: Left: rendering muscle bundle elements using element widgets with elementWidgetSize set to 0.6 (left). Right: rendering muscle bundle fibres.

6.12.5 Color bars

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.6 Example: stress/strain plotting with color bars

Figure 6.23: 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.23.

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       super.prerender(list);
34       // Synchronize color bar/values in case they are changed. Do this *after*
35       // super.prerender(), in case values are changed there.
36       ColorBar cbar = (ColorBar)(renderables().get("colorBar"));
37       cbar.setColorMap(fem.getColorMap());
38       DoubleInterval range = fem.getStressPlotRange();
39       cbar.updateLabels(range.getLowerBound(), range.getUpperBound());
40
41
42    }
43
44 }

6.12.7 Cut planes

In addition to stress/strain visualization on its meshes, FEM models can be supplied with one or more cut planes that allow stress or strain values to be visualized on the cross section of the model with the plane.

Cut plane components are implemented by FemCutPlane and can be created with the following constructors:

FemCutPlane()

Creates a cut plane aligned with the world origin.

FemCutPlane (double res)

Creates an origin-aligned cut plane with grid resolution res.

FemCutPlane (RigidTransform3d TPW)

Creates a cut plane with pose TPW a specified grid resolution.

FemCutPlane (double res, RigidTransform3d TPW)

Creates a cut plane with pose TPW and grid resolution res.

The pose and resolution are described further below. Once created, a cut plane can be added to an FEM model using its addCutPlane() method:

  FemModel3d fem;
  RigidTransform3d TPW; // desired pose of the plane
  ... initialize fem and TPW ...
  FemCutPlane cplane = new FemCutPlane (TPW);
  fem.addCutPlane (cplane);

The FEM model methods for handling cut planes include:

void addCutPlane(FemCutPlane cp)

Adds a cut plane to the model.

int numCutPlanes()

Queries number of cut planes in the model.

FemCutPlane getCutPlanes(int idx)

Gets the idx-th cut plane in the model.

boolean removeCutPlane(FemCutPlane cp)

Removes a cut plane from the model.

void clearCutPlanes()

Removes all cut planes from the model.

As with rigid and mesh bodies, the pose of the cut plane gives its position and orientation relative to world coordinates and is described by a RigidTransform3d. The plane itself is aligned with the x-y plane of this local coordinate system. More specifically, if the pose is given by {\bf T}_{PW} such that

{\bf T}_{PW}\,=\,\left(\begin{matrix}{\bf R}_{PW}&{\bf p}_{PW}\\
0&1\end{matrix}\right) (6.38)

then the plane passes through point {\bf p}_{PW} and its normal is given by the z axis (third column) of {\bf R}_{PW}. When rendered in the viewer, FEM model stress/strain values are displayed as a color map within the polygonal region formed by the intersection between the plane and the model’s surface mesh.

The following properties of FemCutPlane are used to control how it is rendered in the viewer:

squareSize

A double value, which if >0 specifies the size of a square that shows the position of the plane.

resolution

A double value, which if >0 specifies an explicit size (in units of distance) for the grid cells created within the FEM surface/plane intersection to interpolate stress/strain values. Smaller values will give more accurate results but may slow down the rendering time. Accuracy will also not be improved if the resolution is significantly less that the size of the FEM elements. If resolution \leq 0, the grid size is determined automatically based on the element sizes.

axisLength, axisDrawStyle

Identical in function to the axisLength and axisDrawStyle properties for rigid bodies (Section 3.2.8). Specifies the length and style for rendering the local coordinate frame of the cut plane.

surfaceRendering

Describes what is rendered on the surface/plane intersection polygon, according to table 6.5.

stressPlotRange, stressPlotRanging, colorMap

Identical in function to the stressPlotRange, stressPlotRanging and colorMap properties exported by FemModel3d and FemMeshComp (Section 6.12.3). Controls the range and color map associated with the surface rendering.

As with all properties, the values of the above can be accessed either in code using set/get accessors named after the property (e.g., setSurfaceRendering(), getSurfaceRendering()), or within the GUI by selecting the cut plane and then choosing Edit properties ... from the context menu.

6.12.8 Example: FEM model with a cut plane

Figure 6.24: FemCutPlaneDemo, showing stress values within the plane after the model has run and settled into an equilibrium state.

Cut planes are illustrated by the application model defined in

  artisynth.demos.tutorial.FemCutPlaneDemo

which creates a simple FEM model in the shape of a half-torus, and then adds a cut plane to render its internal stresses. Its build() method is give below:

1    public void build (String[] args) {
2       // create a MechModel to contain the FEM model
3       MechModel mech = new MechModel ("mech");
4       addModel (mech);
5
6       // create a half-torus shaped FEM to illustrate the cut plane
7       FemModel3d fem = FemFactory.createPartialHexTorus (
8         null, 0.1, 0.0, 0.05, 8, 16, 3, Math.PI);
9       fem.setMaterial (new LinearMaterial (20000, 0.49));
10       fem.setName ("fem");
11       mech.addModel (fem);
12       // fix the bottom nodes, which lie on the z=0 plane, to support it
13       for (FemNode3d n : fem.getNodes()) {
14          Point3d pos = n.getPosition();
15          if (Math.abs(pos.z) < 1e-8) {
16             n.setDynamic (false);
17          }
18       }
19
20       // create a cut plane, with stress rendering enabled and a pose that
21       // situates it in the z-x plane
22       FemCutPlane cplane =
23          new FemCutPlane (new RigidTransform3d (0,0,0.03,  0,0,Math.PI/2));
24       fem.addCutPlane (cplane);
25
26       // set stress rendering with a fixed range of (0, 1500)
27       cplane.setSurfaceRendering (SurfaceRender.Stress);
28       cplane.setStressPlotRange (new DoubleInterval (0, 1500.0));
29       cplane.setStressPlotRanging (Ranging.Fixed);
30
31       // create a panel to control cut plane properties
32       ControlPanel panel = new ControlPanel();
33       panel.addWidget (cplane, "squareSize");
34       panel.addWidget (cplane, "axisLength");
35       panel.addWidget (cplane, "stressPlotRanging");
36       panel.addWidget (cplane, "stressPlotRange");
37       panel.addWidget (cplane, "colorMap");
38       addControlPanel (panel);
39
40       // set other render properites ...
41       // make FEM line color white:
42       RenderProps.setLineColor (fem, Color.WHITE);
43       // make FEM elements invisible so they’re not in the way:
44       RenderProps.setVisible (fem.getElements(), false);
45       // render FEM using a wireframe surface mesh so we can see through it:
46       fem.setSurfaceRendering (SurfaceRender.Shaded);
47       RenderProps.setDrawEdges (fem.getSurfaceMeshComp(), true);
48       RenderProps.setFaceStyle (fem.getSurfaceMeshComp(), FaceStyle.NONE);
49       RenderProps.setEdgeWidth (fem.getSurfaceMeshComp(), 2);
50       // render cut plane using both square outline and its axes:
51       cplane.setSquareSize (0.12); // size of the square
52       cplane.setAxisLength (0.08); // length of the axes
53       RenderProps.setLineWidth (cplane, 2); // boost line width for visibility
54    }

After a MechModel is created (lines 27-29), an FEM model consisting of a half-torus is created, with the bottom nodes set non-dynamic to provide support (lines 31-43). A cut plane is then created with a pose that centers it on the world origin and aligns it with the world z-x plane (lines 47-49). Surface rendering is set to Stress, with a fixed color plot range of (0,1500) (lines 52-54). A control panel is created to expose various properties of the plane (lines 57-63), and then other rendering properties are set: the default FEM line color is made white (line 67); to avoid visual clutter FEM elements are made invisible and instead the FEM is rendered using a wireframe representation of its surface mesh (lines 69-74); and in addition to its render surface, the cut plane is also displayed using its coordinate axes (with length 0.08) and a square of size 0.12 (lines 76-78).

To run this example in ArtiSynth, select All demos > tutorial > FemCutPlaneDemo from the Models menu. When loaded and run, the model should appear as in Figure 6.24. The plane can be repositioned by selecting it in the viewer (by clicking on its square, coordinate axes, or render surface) and then using one of the transformer tools to change its position and/or orientation (see the section “Transformer Tools” in the ArtiSynth User Interface Guide).