
us.ihmc.scs2.sessionVisualizer.jfx.definition.JavaFXTriangleMesh3DDefinitionInterpreter Maven / Gradle / Ivy
package us.ihmc.scs2.sessionVisualizer.jfx.definition;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.tuple.Pair;
import gnu.trove.list.array.TIntArrayList;
import javafx.scene.shape.TriangleMesh;
import javafx.scene.shape.VertexFormat;
import us.ihmc.euclid.tuple2D.Point2D32;
import us.ihmc.euclid.tuple2D.interfaces.Tuple2DBasics;
import us.ihmc.euclid.tuple3D.Point3D32;
import us.ihmc.euclid.tuple3D.Vector3D32;
import us.ihmc.euclid.tuple3D.interfaces.Tuple3DBasics;
import us.ihmc.graphicsDescription.MeshDataBuilder;
import us.ihmc.graphicsDescription.MeshDataGenerator;
import us.ihmc.log.LogTools;
import us.ihmc.scs2.definition.geometry.GeometryDefinition;
import us.ihmc.scs2.definition.geometry.TriangleMesh3DDefinition;
import us.ihmc.scs2.definition.visual.TriangleMesh3DFactories;
/**
* This class an automated interpretation of {@link TriangleMesh3DDefinition} into JavaFX
* {@link TriangleMesh} usable via {@link MeshView}. With this tool it is possible to tools from the
* Graphics3DDescription library such {@link MeshDataGenerator} and {@link MeshDataBuilder}. It also
* provides a simple way to optimize meshes for JavaFX.
*
* @author Sylvain Bertrand
*/
public class JavaFXTriangleMesh3DDefinitionInterpreter
{
public static TriangleMesh interpretDefinition(GeometryDefinition definition)
{
return interpretDefinition(TriangleMesh3DFactories.TriangleMesh(definition));
}
/**
* Translates a {@link TriangleMesh3DDefinition} into {@link TriangleMesh}.
*
* @param meshData the mesh data to interpret. Not modified.
* @return the interpreted JavaFX {@link TriangleMesh}. Return {@code null} when the given mesh data
* is {@code null} or empty.
*/
public static TriangleMesh interpretDefinition(TriangleMesh3DDefinition definition)
{
return interpretDefinition(definition, true);
}
/**
* Translates a {@link TriangleMesh3DDefinition} into {@link TriangleMesh}.
*
* @param meshData the mesh data to interpret. Not modified.
* @param optimizeMesh whether to optimize the mesh data or not. The optimization consists in
* removing duplicate vertices, texture coordinates, and vertex normals and
* recomputing triangle indices accordingly. This process can be computationally
* intensive but it is often highly beneficial especially for large meshes and
* does not need to be executed on the rendering thread.
* @return the interpreted JavaFX {@link TriangleMesh}. Return {@code null} when the given mesh data
* is {@code null} or empty.
*/
public static TriangleMesh interpretDefinition(TriangleMesh3DDefinition definition, boolean optimizeMesh)
{
if (definition == null || definition.getTriangleIndices().length == 0)
return null;
Point3D32[] vertices = definition.getVertices();
Point2D32[] texturePoints = definition.getTextures();
int[] triangleIndices = definition.getTriangleIndices();
Vector3D32[] normals = definition.getNormals();
TIntArrayList facesIndices = new TIntArrayList();
if (optimizeMesh)
{
Pair filterDuplicateVertices = filterDuplicates(triangleIndices, vertices);
Pair filterDuplicateNormals = filterDuplicates(triangleIndices, normals);
Pair filterDuplicateTex = filterDuplicates(triangleIndices, texturePoints);
vertices = filterDuplicateVertices.getRight();
normals = filterDuplicateNormals.getRight();
texturePoints = filterDuplicateTex.getRight();
for (int pos = 0; pos < triangleIndices.length; pos++)
{
facesIndices.add(filterDuplicateVertices.getLeft()[pos]); // vertex index
facesIndices.add(filterDuplicateNormals.getLeft()[pos]); // normal index
facesIndices.add(filterDuplicateTex.getLeft()[pos]); // texture index
}
}
else
{
for (int pos = 0; pos < triangleIndices.length; pos++)
{
facesIndices.add(triangleIndices[pos]); // vertex index
facesIndices.add(triangleIndices[pos]); // normal index
facesIndices.add(triangleIndices[pos]); // texture index
}
}
int[] indices = facesIndices.toArray();
TriangleMesh triangleMesh = new TriangleMesh(VertexFormat.POINT_NORMAL_TEXCOORD);
triangleMesh.getPoints().addAll(convertToFloatArray(vertices));
triangleMesh.getTexCoords().addAll(convertToFloatArray(texturePoints));
triangleMesh.getFaces().addAll(indices);
triangleMesh.getFaceSmoothingGroups().addAll(new int[indices.length / triangleMesh.getFaceElementSize()]);
triangleMesh.getNormals().addAll(convertToFloatArray(normals));
return triangleMesh;
}
private static Pair filterDuplicates(int[] originalIndices, T[] valuesWithDuplicates)
{
Map uniqueValueIndices = new HashMap<>();
for (int valueIndex = valuesWithDuplicates.length - 1; valueIndex >= 0; valueIndex--)
uniqueValueIndices.put(valuesWithDuplicates[valueIndex], valueIndex);
@SuppressWarnings("unchecked")
T[] filteredValue = (T[]) Array.newInstance(valuesWithDuplicates[0].getClass(), uniqueValueIndices.size());
int pos = 0;
for (T value : uniqueValueIndices.keySet())
{
uniqueValueIndices.put(value, pos);
filteredValue[pos] = value;
pos++;
}
int[] filteredIndices = new int[originalIndices.length];
pos = 0;
for (int triangleIndex : originalIndices)
filteredIndices[pos++] = uniqueValueIndices.get(valuesWithDuplicates[triangleIndex]);
return Pair.of(filteredIndices, filteredValue);
}
private static float[] convertToFloatArray(Tuple3DBasics[] tuple3fs)
{
float[] array = new float[3 * tuple3fs.length];
int index = 0;
for (Tuple3DBasics tuple : tuple3fs)
{
if (tuple == null)
{
LogTools.error("Got Null, Something is funny here");
array[index++] = Float.NaN;
array[index++] = Float.NaN;
array[index++] = Float.NaN;
}
else
{
array[index++] = tuple.getX32();
array[index++] = tuple.getY32();
array[index++] = tuple.getZ32();
}
}
return array;
}
private static float[] convertToFloatArray(Tuple2DBasics[] tuple2fs)
{
float[] array = new float[2 * tuple2fs.length];
int index = 0;
for (Tuple2DBasics tuple : tuple2fs)
{
if (tuple == null)
{
LogTools.error("Got Null, Something is funny here");
array[index++] = Float.NaN;
array[index++] = Float.NaN;
}
else
{
array[index++] = tuple.getX32();
array[index++] = tuple.getY32();
}
}
return array;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy