001/**
002 * TriangleListShape3D -- A Java 3D Shape3D representation of a TriangleList.
003 *
004 * Copyright (C) 2015-2023, by Joseph A. Huwaldt
005 * All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or modify it under the terms
008 * of the GNU Lesser General Public License as published by the Free Software Foundation;
009 * either version 2.1 of the License, or (at your option) any later version.
010 *
011 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
013 * PARTICULAR PURPOSE. See the GNU Library General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License along with
016 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place -
017 * Suite 330, Boston, MA 02111-1307, USA. Or visit: http://www.gnu.org/licenses/lgpl.html
018 */
019package geomss.j3d;
020
021import org.jogamp.java3d.utils.geometry.GeometryInfo;
022import org.jogamp.java3d.utils.geometry.NormalGenerator;
023import org.jogamp.java3d.utils.geometry.Stripifier;
024import geomss.geom.*;
025import jahuwaldt.js.param.Parameter;
026import static java.util.Objects.requireNonNull;
027import javax.measure.unit.SI;
028import org.jogamp.java3d.*;
029import org.jogamp.vecmath.*;
030
031/**
032 * A Shape3D object based on a {@link geomss.geom.TriangleList TriangleList}. The default
033 * appearance of the geometry is solid filled grey with lighting enabled.
034 *
035 * <p> Modified by: Joseph A. Huwaldt </p>
036 *
037 * @author Joseph A. Huwaldt, Date: August 29, 2015
038 * @version June 4, 2023
039 */
040public class TriangleListShape3D extends GeomShape3D {
041
042    /**
043     * @param parent The GeomSS geometry element that this Shape3D is associated with.
044     */
045    private TriangleListShape3D(GeomElement parent) {
046        super(parent);
047    }
048
049    /**
050     * Construct a TriangleListShape3D object from the specified {@link TriangleList}.
051     *
052     * @param parent The GeomSS geometry element that this Shape3D is associated with.
053     * @param list   The TriangleList to be converted into a J3D Shape3D object.
054     */
055    public TriangleListShape3D(GeomElement parent, TriangleList<? extends GeomTriangle> list) {
056        super(parent);
057
058        setGeometry(createGeometry(requireNonNull(list), true));
059    }
060
061    /**
062     * Construct a TriangleListShape3D object from the specified {@link TriangleList}.
063     *
064     * @param parent     The GeomSS geometry element that this Shape3D is associated with.
065     * @param list       The TriangleList to be converted into a J3D Shape3D object.
066     * @param appearance The Appearance to use when rendering the list of triangles.
067     */
068    public TriangleListShape3D(GeomElement parent, TriangleList<? extends GeomTriangle> list, Appearance appearance) {
069        this(parent, list);
070        setAppearance(requireNonNull(appearance));
071    }
072
073    /**
074     * Construct a TriangleListShape3D object from the specified {@link TriangleList}.
075     *
076     * @param parent     The GeomSS geometry element that this Shape3D is associated with.
077     * @param list       The TriangleList to be converted into a J3D Shape3D object.
078     * @param appearance The Appearance to use when rendering the list of triangles.
079     * @param stripify   Flag indicating if the list of individual triangles should be
080     *                   converted into triangle strips for rendering or not.
081     */
082    public TriangleListShape3D(GeomElement parent, TriangleList<? extends GeomTriangle> list,
083            Appearance appearance, boolean stripify) {
084        super(parent);
085
086        setGeometry(createGeometry(requireNonNull(list), stripify));
087        setAppearance(requireNonNull(appearance));
088    }
089
090    /**
091     * Used to create a new instance of the node.
092     *
093     * @param forceDuplicate when set to <code>true</code>, causes the
094     *                       <code>duplicateOnCloneTree</code> flag to be ignored. When
095     *                       <code>false</code>, the value of each node's
096     *                       <code>duplicateOnCloneTree</code> variable determines whether
097     *                       NodeComponent data is duplicated or copied.
098     * @return A new instance of this Java3D node.
099     */
100    @Override
101    public Node cloneNode(boolean forceDuplicate) {
102        TriangleListShape3D usc = new TriangleListShape3D(this.getGeometryElement());
103        usc.duplicateNode(this, forceDuplicate);
104        return usc;
105    }
106
107    /**
108     * Convert the TriangleList, and an optional list of vertex normals, into a J3D
109     * Geometry object here.
110     */
111    private Geometry createGeometry(TriangleList<? extends GeomTriangle> triLst, boolean stripify) {
112
113        //  Extract a minimal set of vertices and indexes from the triangle list.
114        TriangleVertData triData = triLst.toVertData(Parameter.valueOf(Parameter.SQRT_EPS, triLst.getUnit()));
115        PointString<? extends GeomPoint> verts = triData.vertices;
116        int[] coordIndices = triData.tris;
117
118        // Convert the list of GeomPoint vertices into J3D points.
119        int numDims = triLst.getPhyDimension();
120        int vertexCount = verts.size();
121        Point3f[] coordinates = new Point3f[vertexCount];
122        for (int i = 0; i < vertexCount; ++i) {
123            GeomPoint point = verts.get(i);
124
125            //  Convert all geometry to meters.
126            double x = point.getValue(0, SI.METER);
127            double y = point.getValue(1, SI.METER);
128            double z = (numDims > 2 ? point.getValue(2, SI.METER) : 0);
129            coordinates[i] = new Point3f((float)x, (float)y, (float)z);
130        }
131
132        // Create a GeomInfo object for our geometry.
133        GeometryInfo geomInfo = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY);
134        geomInfo.setCoordinates(coordinates);
135        geomInfo.setCoordinateIndices(coordIndices);
136
137        // Generate vertex normals automatically.
138        NormalGenerator ng = new NormalGenerator(0);    //  Use facet normals only (no smoothing).
139        ng.generateNormals(geomInfo);
140
141        if (stripify) {
142            // Stripify the geometry for increased performance.
143            Stripifier st = new Stripifier();
144            st.stripify(geomInfo);
145        }
146
147        return geomInfo.getGeometryArray();
148    }
149}