001/** 002 * J3DCurve -- A Java3D node that represents a Curve in a J3D scene graph. 003 * 004 * Copyright (C) 2009-2023, 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 Lesser 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 geomss.app.GeomSSCanvas3D; 022import geomss.geom.Curve; 023import geomss.geom.GeomPoint; 024import geomss.geom.PointString; 025import geomss.geom.SubrangePoint; 026import static java.util.Objects.requireNonNull; 027import javax.measure.unit.SI; 028import org.jogamp.java3d.*; 029import org.jogamp.vecmath.*; 030import javolution.context.StackContext; 031 032/** 033 * A Java 3D node that represents a Curve in a Java 3D scene graph. 034 * 035 * <p> Modified by: Joseph A. Huwaldt </p> 036 * 037 * @author Joseph A. Huwaldt, Date: May 16, 2009 038 * @version June 4, 2023 039 */ 040public class J3DCurve extends J3DGeomGroup<Curve> { 041 042 // The switch for main or mirrored geometry. 043 private Switch _symmSG; 044 045 // Store the Shape3D so it could potentially be used again in the future. 046 private Shape3D _oldShape3D; 047 048 /** 049 * Construct a new J3DCurve using the specified Curve as a reference. 050 * 051 * @param canvas The canvas that the geometry is being rendered into. 052 * @param geometry A new J3DCurve using the specified Curve as a reference. 053 */ 054 public J3DCurve(GeomSSCanvas3D canvas, Curve geometry) { 055 super(requireNonNull(canvas), requireNonNull(geometry)); 056 } 057 058 /** 059 * Set the display of a mirrored copy of this geometry. This is called from 060 * "setDisplayed()" to turn on and off the display of mirrored geometry without 061 * changing the "mirrored state" of the object. This call does not affect the output 062 * of "isMirrored()". 063 * 064 * @param mirrored Flag indicating if the mirrored geometry should be displayed or 065 * not. 066 */ 067 @Override 068 protected void internalSetMirrored(boolean mirrored) { 069 if (mirrored) 070 _symmSG.setWhichChild(Switch.CHILD_ALL); 071 else 072 _symmSG.setWhichChild(0); 073 } 074 075 /** 076 * Create a new Java 3D <code>Group</code> that contains the geometry contained in 077 * this object. This method is called from <code>createSceneGraph</code>. Sub-classes 078 * must over-ride this method to provide geometry specific implementations. 079 * 080 * @return New Java 3D Group that contains the geometry in this object. 081 * @see #createSceneGraph 082 */ 083 @Override 084 protected Group createGeometry() { 085 086 J3DRenderingPrefs drawPrefs = getRenderingPrefs(); 087 Shape3D lineShape = null; 088 089 // Try to recycle a previous rendering of this geometry element if at all possible. 090 J3DCurve oldGroup = (J3DCurve)getOldJ3DGeomGroup(); 091 if (oldGroup != null) { 092 J3DRenderingPrefs oldPrefs = oldGroup.getRenderingPrefs(); 093 if (oldPrefs.getDrawTolerance().equals(drawPrefs.getDrawTolerance())) { 094 //System.out.println("Re-using lineShape"); 095 // Draw tolerance is unchanged, so re-use the existing Shape3D. 096 lineShape = (Shape3D)oldGroup._oldShape3D.cloneNode(true); 097 098 // Has the line color changed? 099 if (!oldPrefs.getLineColor().equals(drawPrefs.getLineColor())) { 100 //System.out.println("Changing line color"); 101 Color4f lineColor = drawPrefs.getLineColorJ3D(); 102 LineArray lineA = (LineArray)lineShape.getGeometry(); 103 int size = lineA.getVertexCount(); 104 for (int i = 0; i < size; ++i) { 105 lineA.setColor(i, lineColor); 106 } 107 } 108 109 } 110 } 111 112 // If we couldn't recycle the lineShape, then create a new one. 113 if (lineShape == null) { 114 Curve thisCurve = this.getGeomElement(); 115 LineArray lineA; 116 StackContext.enter(); 117 try { 118 119 // Create a line and a point array. 120 PointString<SubrangePoint> points = thisCurve.gridToTolerance(drawPrefs.getDrawTolerance()); 121 //System.out.println("points.size() = " + points.size()); 122 123 int size = points.size(); 124 int nVerts = 2 * (size - 1); 125 lineA = new LineArray(nVerts, LineArray.COORDINATES | LineArray.COLOR_4); 126 127 // Set the coordinates of the line. 128 Color4f lineColor = drawPrefs.getLineColorJ3D(); 129 Point3d oldPoint = null; 130 int lineIndex = 0; 131 for (int i = 0; i < size; ++i) { 132 GeomPoint point = points.get(i); 133 // Convert all geometry to meters. 134 int dims = point.getPhyDimension(); 135 double x = point.getValue(0, SI.METER); 136 double y = (dims > 1 ? point.getValue(1, SI.METER) : 0); 137 double z = (dims > 2 ? point.getValue(2, SI.METER) : 0); 138 Point3d point3d = new Point3d(x, y, z); 139 140 if (i != 0) { 141 lineA.setCoordinate(lineIndex, oldPoint); // Store start of line segment. 142 lineA.setColor(lineIndex++, lineColor); 143 lineA.setCoordinate(lineIndex, point3d); // Store end of line segment. 144 lineA.setColor(lineIndex++, lineColor); 145 } 146 147 oldPoint = point3d; 148 } 149 150 } finally { 151 StackContext.exit(); 152 } 153 154 // Create a 3D shape from the line array 155 lineShape = new GeomShape3D(thisCurve, lineA); 156 } 157 _oldShape3D = (Shape3D)lineShape.cloneNode(true); // Save off for potential re-use in the future. 158 159 // Define the appearance of the line. 160 Appearance lineAppearance = new Appearance(); 161 LineAttributes lineAttrib = new LineAttributes(); 162 lineAttrib.setLineWidth(drawPrefs.getLineWidth()); 163 lineAppearance.setLineAttributes(lineAttrib); 164 lineShape.setAppearance(lineAppearance); 165 166 // Add the basic unmirrored geometry to the symmetry switch. 167 _symmSG = new Switch(); 168 _symmSG.setCapability(Switch.ALLOW_SWITCH_READ); 169 _symmSG.setCapability(Switch.ALLOW_SWITCH_WRITE); 170 _symmSG.addChild(lineShape); 171 172 // Clone the basic geometry to make the mirrored geometry. 173 Node mirrored = lineShape.cloneTree(); 174 175 // Create a mirror across the XZ plane of symmetry transform. 176 Transform3D symmT = new Transform3D(); 177 symmT.setScale(new Vector3d(1, -1, 1)); 178 TransformGroup symmTG = new TransformGroup(symmT); 179 180 // Add the mirrored geometry to the symmetry transform group. 181 symmTG.addChild(mirrored); 182 183 // Add the mirrored geometry to the symmetry switch. 184 _symmSG.addChild(symmTG); 185 186 // By default, display only the main geometry (not the mirrored). 187 _symmSG.setWhichChild(0); 188 189 return _symmSG; 190 } 191 192 /** 193 * Creates a new instance of the node. This routine is called by 194 * <code>cloneTree</code> to duplicate the current node. 195 * 196 * @param forceDuplicate when set to <code>true</code>, causes the 197 * <code>duplicateOnCloneTree</code> flag to be ignored. When 198 * <code>false</code>, the value of each node's 199 * <code>duplicateOnCloneTree</code> variable determines whether 200 * NodeComponent data is duplicated or copied. 201 * @return A new instance of this Java3D node. 202 */ 203 @Override 204 public Node cloneNode(boolean forceDuplicate) { 205 J3DCurve node = new J3DCurve(this.getCanvas3D(), this.getGeomElement()); 206 node.duplicateNode(this, forceDuplicate); 207 return node; 208 } 209 210}