001/** 002 * J3DGeomPlane -- A Java3D node that represents a GeomPlane 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.*; 023import static java.util.Objects.requireNonNull; 024import javax.measure.quantity.Dimensionless; 025import javax.measure.unit.SI; 026import org.jogamp.java3d.*; 027import org.jogamp.java3d.PointArray; 028import org.jogamp.vecmath.*; 029import javolution.context.StackContext; 030 031/** 032 * A Java 3D node that represents a <code>GeomPlane</code> in a Java 3D scene graph. 033 * 034 * <p> Modified by: Joseph A. Huwaldt </p> 035 * 036 * @author Joseph A. Huwaldt, Date: June 14, 2009 037 * @version June 4, 2023 038 */ 039public class J3DGeomPlane extends J3DGeomGroup<GeomPlane> { 040 041 // The switch for main or mirrored geometry. 042 private Switch _symmSG; 043 044 /** 045 * Construct a J3DGeomPlane using the specified GeomPlane as a reference. 046 * 047 * @param canvas The canvas that the geometry is being rendered into. 048 * @param geometry The GeomSS plane to be turned into a Java3D node. 049 */ 050 public J3DGeomPlane(GeomSSCanvas3D canvas, GeomPlane geometry) { 051 super(requireNonNull(canvas), requireNonNull(geometry)); 052 } 053 054 /** 055 * Set the display of a mirrored copy of this geometry. This is called from 056 * "setDisplayed()" to turn on and off the display of mirrored geometry without 057 * changing the "mirrored state" of the object. This call does not affect the output 058 * of "isMirrored()". 059 */ 060 @Override 061 protected void internalSetMirrored(boolean mirrored) { 062 if (mirrored) 063 _symmSG.setWhichChild(Switch.CHILD_ALL); 064 else 065 _symmSG.setWhichChild(0); 066 } 067 068 /** 069 * Create a new Java 3D <code>Group</code> that contains the geometry contained in 070 * this object. This method is called from <code>createSceneGraph</code>. Sub-classes 071 * must over-ride this method to provide geometry specific implementations. 072 * 073 * @return New Java 3D Group that contains the geometry in this object. 074 * @see #createSceneGraph 075 */ 076 @Override 077 protected Group createGeometry() { 078 079 StackContext.enter(); 080 try { 081 // Create a line and a point array. 082 GeomPlane thisPlane = this.getGeomElement(); 083 GeomVector normalV = thisPlane.getNormal(); 084 085 // Set the coordinates of the line. 086 J3DRenderingPrefs drawPrefs = getRenderingPrefs(); 087 Color4f pointColor = drawPrefs.getPointColorJ3D(); 088 Color4f lineColor = drawPrefs.getLineColorJ3D(); 089 090 // *** First create the vector display elements (a point and a line). 091 GeomPoint o = normalV.getOrigin().to(SI.METER); // Convert all geometry to meters. 092 int dims = o.getPhyDimension(); 093 double x = o.getValue(0); 094 double y = (dims > 1 ? o.getValue(1) : 0); 095 double z = (dims > 2 ? o.getValue(2) : 0); 096 Point3d point3d = new Point3d(x, y, z); 097 098 LineArray lineA = new LineArray(2, LineArray.COORDINATES | LineArray.COLOR_4); 099 PointArray pointA = new PointArray(1, PointArray.COORDINATES | PointArray.COLOR_4); 100 lineA.setCoordinate(0, point3d); // Store start of line segment. 101 lineA.setColor(0, lineColor); 102 pointA.setCoordinate(0, point3d); 103 pointA.setColor(0, pointColor); 104 105 // Create a point representing the other end of the vector. 106 if (!normalV.getUnit().equals(Dimensionless.UNIT)) 107 normalV = (GeomVector)normalV.to(SI.METER); // Convert all geometry to meters. 108 109 x += normalV.getValue(0); 110 y += (dims > 1 ? normalV.getValue(1) : 0); 111 z += (dims > 2 ? normalV.getValue(2) : 0); 112 point3d = new Point3d(x, y, z); 113 114 lineA.setCoordinate(1, point3d); // Store start of line segment. 115 lineA.setColor(1, lineColor); 116 117 // Create a 3D shape from the line array 118 Shape3D vectorLineShape = new GeomShape3D(thisPlane, lineA); 119 120 // Define the appearance of the line. 121 Appearance lineAppearance = new Appearance(); 122 LineAttributes lineAttrib = new LineAttributes(); 123 lineAttrib.setLineWidth(drawPrefs.getLineWidth()); 124 lineAppearance.setLineAttributes(lineAttrib); 125 vectorLineShape.setAppearance(lineAppearance); 126 127 // Create a 3D shape from the point array 128 Shape3D vectorPointShape = new GeomShape3D(thisPlane, pointA); 129 Appearance appearance = new Appearance(); 130 vectorPointShape.setAppearance(appearance); 131 appearance.setPointAttributes(new PointAttributes(drawPrefs.getPointSize(), true)); 132 133 // *** Now create a box around the vector that is in the plane. 134 GeomVector<Dimensionless> yhat = GeomUtil.calcYHat(normalV); 135 GeomVector<Dimensionless> xhat = GeomUtil.calcXHat(normalV, yhat); 136 lineA = new LineArray(8, LineArray.COORDINATES | LineArray.COLOR_4); 137 138 // Set 0 (upper right) and 2 (lower left) points. 139 Point p = Point.valueOf(xhat.plus(yhat)).plus(o); 140 x = p.getValue(0); 141 y = (dims > 1 ? p.getValue(1) : 0); 142 z = (dims > 2 ? p.getValue(2) : 0); 143 point3d = new Point3d(x, y, z); 144 lineA.setCoordinate(0, point3d); 145 lineA.setCoordinate(7, point3d); 146 lineA.setColor(0, lineColor); 147 lineA.setColor(7, lineColor); 148 149 p = Point.valueOf(xhat.plus(yhat)).opposite().plus(o); 150 x = p.getValue(0); 151 y = (dims > 1 ? p.getValue(1) : 0); 152 z = (dims > 2 ? p.getValue(2) : 0); 153 point3d = new Point3d(x, y, z); 154 lineA.setCoordinate(3, point3d); 155 lineA.setCoordinate(4, point3d); 156 lineA.setColor(3, lineColor); 157 lineA.setColor(4, lineColor); 158 159 // Set 1 (upper left) and 3 (lower right) points. 160 p = Point.valueOf(xhat.opposite().plus(yhat)).plus(o); 161 x = p.getValue(0); 162 y = (dims > 1 ? p.getValue(1) : 0); 163 z = (dims > 2 ? p.getValue(2) : 0); 164 point3d = new Point3d(x, y, z); 165 lineA.setCoordinate(1, point3d); 166 lineA.setCoordinate(2, point3d); 167 lineA.setColor(1, lineColor); 168 lineA.setColor(2, lineColor); 169 170 p = Point.valueOf(xhat.opposite().plus(yhat)).opposite().plus(o); 171 x = p.getValue(0); 172 y = (dims > 1 ? p.getValue(1) : 0); 173 z = (dims > 2 ? p.getValue(2) : 0); 174 point3d = new Point3d(x, y, z); 175 lineA.setCoordinate(5, point3d); 176 lineA.setCoordinate(6, point3d); 177 lineA.setColor(5, lineColor); 178 lineA.setColor(6, lineColor); 179 180 // Create a 3D shape from the line array 181 Shape3D planeLineShape = new GeomShape3D(thisPlane, lineA); 182 planeLineShape.setAppearance(lineAppearance); 183 184 // Create a group for the main geometry (unmirrored) 185 // that contains each part of the display properties of a GeomPlane. 186 Group renderGroup = new Switch(Switch.CHILD_ALL); 187 renderGroup.setCapability(Switch.ALLOW_SWITCH_READ); 188 renderGroup.setCapability(Switch.ALLOW_SWITCH_WRITE); 189 190 // Add the geometry to the display switch. 191 renderGroup.addChild(vectorLineShape); 192 renderGroup.addChild(vectorPointShape); 193 renderGroup.addChild(planeLineShape); 194 195 // Add the basic unmirrored geometry to the symmetry switch. 196 _symmSG = new Switch(); 197 _symmSG.setCapability(Switch.ALLOW_SWITCH_READ); 198 _symmSG.setCapability(Switch.ALLOW_SWITCH_WRITE); 199 _symmSG.addChild(renderGroup); 200 201 // Clone the basic geometry to make the mirrored geometry. 202 Node mirrored = renderGroup.cloneTree(); 203 204 // Create a mirror across the XZ plane of symmetry transform. 205 Transform3D symmT = new Transform3D(); 206 symmT.setScale(new Vector3d(1, -1, 1)); 207 TransformGroup symmTG = new TransformGroup(symmT); 208 209 // Add the mirrored geometry to the symmetry transform group. 210 symmTG.addChild(mirrored); 211 212 // Add the mirrored geometry to the symmetry switch. 213 _symmSG.addChild(symmTG); 214 215 // By default, display only the main geometry (not the mirrored). 216 _symmSG.setWhichChild(0); 217 218 return _symmSG; 219 220 } finally { 221 StackContext.exit(); 222 } 223 } 224 225 /** 226 * Creates a new instance of the node. This routine is called by 227 * <code>cloneTree</code> to duplicate the current node. 228 * 229 * @param forceDuplicate when set to <code>true</code>, causes the 230 * <code>duplicateOnCloneTree</code> flag to be ignored. When 231 * <code>false</code>, the value of each node's 232 * <code>duplicateOnCloneTree</code> variable determines whether 233 * NodeComponent data is duplicated or copied. 234 * @return A new instance of this Java3D node. 235 */ 236 @Override 237 public Node cloneNode(boolean forceDuplicate) { 238 J3DGeomPlane node = new J3DGeomPlane(this.getCanvas3D(), this.getGeomElement()); 239 node.duplicateNode(this, forceDuplicate); 240 return node; 241 } 242}