1 /* 2 * $RCSfile: Cone.java,v $ 3 * 4 * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * - Redistribution of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * - Redistribution in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 18 * Neither the name of Sun Microsystems, Inc. or the names of 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * This software is provided "AS IS," without a warranty of any 23 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 24 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 25 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY 26 * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 27 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 28 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 29 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 30 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, 31 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND 32 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR 33 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGES. 35 * 36 * You acknowledge that this software is not designed, licensed or 37 * intended for use in the design, construction, operation or 38 * maintenance of any nuclear facility. 39 * 40 * $Revision: 1.6 $ 41 * $Date: 2007/04/24 18:50:59 $ 42 * $State: Exp $ 43 */ 44 45 package com.sun.j3d.utils.geometry; 46 47 import com.sun.j3d.utils.geometry.*; 48 import java.io.*; 49 import java.util.*; 50 import javax.media.j3d.*; 51 import javax.vecmath.*; 52 53 /** 54 * Cone is a geometry primitive defined with a radius and a height. 55 * It is a capped cone centered at the origin with its central axis 56 * aligned along the Y-axis. The center of the cone is defined to be 57 * the center of its bounding box (rather than its centroid). 58 * <p> 59 * If the GENERATE_TEXTURE_COORDS flag is set, the texture coordinates 60 * are generated such that the texture gets mapped onto the cone similarly 61 * to how it gets mapped onto a cylinder, the difference being the top 62 * cap is nonexistent. 63 * <p> 64 * By default all primitives with the same parameters share their 65 * geometry (e.g., you can have 50 shperes in your scene, but the 66 * geometry is stored only once). A change to one primitive will 67 * effect all shared nodes. Another implication of this 68 * implementation is that the capabilities of the geometry are shared, 69 * and once one of the shared nodes is live, the capabilities cannot 70 * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to 71 * share geometry among primitives with the same parameters. 72 */ 73 public class Cone extends Primitive { 74 float radius, height; 75 int xdivisions, ydivisions; 76 static final int MID_REZ_DIV_X = 15; 77 static final int MID_REZ_DIV_Y = 1; 78 79 /** 80 * Designates the body of the cone. Used by <code>getShape</code>. 81 * 82 * @see Cone#getShape 83 */ 84 public static final int BODY = 0; 85 86 /** 87 * Designates the end-cap of the cone. Used by <code>getShape</code>. 88 * 89 * @see Cone#getShape 90 */ 91 public static final int CAP = 1; 92 93 /** 94 * Constructs a default Cone of radius of 1.0 and height 95 * of 2.0. Resolution defaults to 15 divisions along X and axis 96 * and 1 along the Y axis. Normals are generated, texture 97 * coordinates are not. 98 */ Cone()99 public Cone(){ 100 this(1.0f, 2.0f, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, null); 101 } 102 103 /** 104 * 105 * Constructs a default Cone of a given radius and height. Normals 106 * are generated, texture coordinates are not. 107 * @param radius Radius 108 * @param height Height 109 */ Cone(float radius, float height)110 public Cone (float radius, float height) 111 { 112 this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, null); 113 } 114 115 /** 116 * 117 * Constructs a default cone of a given radius, height, 118 * and appearance. Normals are generated, texture coordinates are not. 119 * @param radius Radius 120 * @param height Height 121 * @param ap Appearance 122 * 123 * @since Java 3D 1.2.1 124 */ Cone(float radius, float height, Appearance ap)125 public Cone (float radius, float height, Appearance ap) 126 { 127 this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, ap); 128 } 129 130 /** 131 * 132 * Constructs a default cone of a given radius, height, 133 * primitive flags, and appearance. 134 * @param radius Radius 135 * @param height Height 136 * @param primflags Primitive flags 137 * @param ap Appearance 138 */ Cone(float radius, float height, int primflags, Appearance ap)139 public Cone (float radius, float height, int primflags, Appearance ap) 140 { 141 this(radius, height, primflags, MID_REZ_DIV_X, MID_REZ_DIV_Y, ap); 142 } 143 144 /** 145 * Obtains the Shape3D node associated with one of the parts of the 146 * cone (the body or the cap). This allows users to modify the appearance 147 * or geometry of individual parts. 148 * @param partId The part to return (BODY or CAP). 149 * @return The Shape3D object associated with the partId. If an 150 * invalid partId is passed in, null is returned. 151 */ getShape(int partId)152 public Shape3D getShape(int partId){ 153 if (partId > CAP || partId < BODY) return null; 154 return (Shape3D)getChild(partId); 155 } 156 157 158 /** 159 * Sets appearance of the cone. This will set each part of the 160 * cone (cap & body) to the same appearance. To set each 161 * part's appearance separately, use getShape(partId) to get the 162 * individual shape and call shape.setAppearance(ap). 163 */ setAppearance(Appearance ap)164 public void setAppearance(Appearance ap){ 165 ((Shape3D)getChild(BODY)).setAppearance(ap); 166 ((Shape3D)getChild(CAP)).setAppearance(ap); 167 } 168 169 /** 170 * Gets the appearance of the specified part of the cone. 171 * 172 * @param partId identifier for a given subpart of the cone 173 * 174 * @return The appearance object associated with the partID. If an 175 * invalid partId is passed in, null is returned. 176 * 177 * @since Java 3D 1.2.1 178 */ getAppearance(int partId)179 public Appearance getAppearance(int partId) { 180 if (partId > CAP || partId < BODY) return null; 181 return getShape(partId).getAppearance(); 182 } 183 184 185 /** 186 * Constructs a customized Cone of a given radius, height, flags, 187 * resolution (X and Y dimensions), and appearance. The 188 * resolution is defined in terms of number of subdivisions 189 * along the object's X axis (width) and Y axis (height). More divisions 190 * lead to finer tesselated objects. 191 * <p> 192 * If appearance is null, the default white appearance will be used. 193 * @param radius Radius 194 * @param height Height 195 * @param xdivision Number of divisions along X direction. 196 * @param ydivision Number of divisions along the height of cone. 197 * @param primflags flags 198 * @param ap Appearance 199 */ 200 Cone(float radius, float height, int primflags, int xdivision, int ydivision, Appearance ap)201 public Cone(float radius, float height, int primflags, 202 int xdivision, int ydivision, 203 Appearance ap) 204 { 205 super(); 206 207 Shape3D shape[] = new Shape3D[2]; 208 this.radius = radius; 209 this.height = height; 210 xdivisions = xdivision; 211 ydivisions = ydivision; 212 flags = primflags; 213 boolean outside = (flags & GENERATE_NORMALS_INWARD) == 0; 214 boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0; 215 Quadrics q = new Quadrics(); 216 GeomBuffer gbuf = null; 217 218 GeomBuffer cache = getCachedGeometry(Primitive.CONE, 219 radius, 0.0f, height, 220 xdivision, ydivision, primflags); 221 if (cache != null){ 222 // System.out.println("using cached geometry"); 223 shape[BODY] = new Shape3D(cache.getComputedGeometry()); 224 numVerts += cache.getNumVerts(); 225 numTris += cache.getNumTris(); 226 } 227 else { 228 // the body of the cone consists of the top of the cone and if 229 // ydivisions is greater than 1, the body of the cone. 230 gbuf = q.coneTop((double)(height/2.0 - height/ydivisions), 231 (double)(radius/ydivisions), height/ydivisions, 232 xdivisions, 1.0-1.0/(double)ydivisions, 233 outside, texCoordYUp); 234 shape[BODY] = new Shape3D(gbuf.getGeom(flags)); 235 numVerts += gbuf.getNumVerts(); 236 numTris += gbuf.getNumTris(); 237 if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) { 238 cacheGeometry(Primitive.CONE, 239 radius, 0.0f, height, 240 xdivision, ydivision, primflags, gbuf); 241 } 242 } 243 244 // only need to add a body if the ydivisions is greater than 1 245 if (ydivisions > 1) { 246 cache = getCachedGeometry(Primitive.CONE_DIVISIONS, radius, 0.0f, 247 height, xdivision, ydivision, primflags); 248 if (cache != null) { 249 // System.out.println("using cached divisions"); 250 shape[BODY].addGeometry(cache.getComputedGeometry()); 251 numVerts += cache.getNumVerts(); 252 numTris += cache.getNumTris(); 253 } 254 else { 255 gbuf = q.coneBody(-(double)(height/2.0), 256 (double)(height/2.0-height/ydivisions), 257 (double)radius, (double)(radius/ydivisions), 258 xdivisions, ydivisions-1, 1.0/(double)ydivisions, 259 outside, texCoordYUp); 260 shape[BODY].addGeometry(gbuf.getGeom(flags)); 261 numVerts += gbuf.getNumVerts(); 262 numTris += gbuf.getNumTris(); 263 if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) { 264 cacheGeometry(Primitive.CONE_DIVISIONS, radius, 0.0f, height, 265 xdivision, ydivision, primflags, gbuf); 266 } 267 } 268 } 269 270 if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) { 271 (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_READ); 272 (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); 273 } 274 275 if ((flags & ENABLE_GEOMETRY_PICKING) != 0) { 276 (shape[BODY]).setCapability(Shape3D.ALLOW_GEOMETRY_READ); 277 } 278 279 this.addChild(shape[BODY]); 280 281 // Create bottom cap. 282 cache = getCachedGeometry(Primitive.BOTTOM_DISK, radius, 283 radius, -height/2.0f, xdivision, xdivision, 284 primflags); 285 if (cache != null) { 286 // System.out.println("using cached bottom"); 287 shape[CAP] = new Shape3D(cache.getComputedGeometry()); 288 numVerts += cache.getNumVerts(); 289 numTris += cache.getNumTris(); 290 } 291 else { 292 gbuf = q.disk((double)radius, xdivision, -(double)height/2.0, 293 !outside, texCoordYUp); 294 shape[CAP] = new Shape3D(gbuf.getGeom(flags)); 295 numVerts += gbuf.getNumVerts(); 296 numTris += gbuf.getNumTris(); 297 if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) { 298 cacheGeometry(Primitive.BOTTOM_DISK, radius, radius, -height/2.0f, 299 xdivision, xdivision, primflags, gbuf); 300 } 301 } 302 303 if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) { 304 (shape[CAP]).setCapability(Shape3D.ALLOW_APPEARANCE_READ); 305 (shape[CAP]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); 306 } 307 308 if ((flags & ENABLE_GEOMETRY_PICKING) != 0) { 309 (shape[CAP]).setCapability(Shape3D.ALLOW_GEOMETRY_READ); 310 } 311 312 // Transform3D t2 = new Transform3D(); 313 314 // Flip it to match up the texture coords. 315 /* This causes the bottom not to match up for odd xdivision values 316 objectMat = new Matrix4d(); 317 objectMat.setIdentity(); 318 rotMat = new Matrix4d(); 319 rotMat.setIdentity(); 320 rotMat.rotZ(Math.PI); 321 objectMat.mul(objectMat, rotMat); 322 t2.set(objectMat); 323 */ 324 325 this.addChild(shape[CAP]); 326 327 if (ap == null){ 328 setAppearance(); 329 } 330 else setAppearance(ap); 331 } 332 333 /** 334 * Used to create a new instance of the node. This routine is called 335 * by <code>cloneTree</code> to duplicate the current node. 336 * <code>cloneNode</code> should be overridden by any user subclassed 337 * objects. All subclasses must have their <code>cloneNode</code> 338 * method consist of the following lines: 339 * <P><blockquote><pre> 340 * public Node cloneNode(boolean forceDuplicate) { 341 * UserSubClass usc = new UserSubClass(); 342 * usc.duplicateNode(this, forceDuplicate); 343 * return usc; 344 * } 345 * </pre></blockquote> 346 * @param forceDuplicate when set to <code>true</code>, causes the 347 * <code>duplicateOnCloneTree</code> flag to be ignored. When 348 * <code>false</code>, the value of each node's 349 * <code>duplicateOnCloneTree</code> variable determines whether 350 * NodeComponent data is duplicated or copied. 351 * 352 * @see Node#cloneTree 353 * @see Node#duplicateNode 354 * @see NodeComponent#setDuplicateOnCloneTree 355 */ cloneNode(boolean forceDuplicate)356 public Node cloneNode(boolean forceDuplicate) { 357 Cone c = new Cone(radius, height, flags, xdivisions, 358 ydivisions, getAppearance()); 359 c.duplicateNode(this, forceDuplicate); 360 return c; 361 } 362 363 /** 364 * Copies all node information from <code>originalNode</code> into 365 * the current node. This method is called from the 366 * <code>cloneNode</code> method which is, in turn, called by the 367 * <code>cloneTree</code> method. 368 * <P> 369 * For any <i>NodeComponent</i> objects 370 * contained by the object being duplicated, each <i>NodeComponent</i> 371 * object's <code>duplicateOnCloneTree</code> value is used to determine 372 * whether the <i>NodeComponent</i> should be duplicated in the new node 373 * or if just a reference to the current node should be placed in the 374 * new node. This flag can be overridden by setting the 375 * <code>forceDuplicate</code> parameter in the <code>cloneTree</code> 376 * method to <code>true</code>. 377 * 378 * @param originalNode the original node to duplicate. 379 * @param forceDuplicate when set to <code>true</code>, causes the 380 * <code>duplicateOnCloneTree</code> flag to be ignored. When 381 * <code>false</code>, the value of each node's 382 * <code>duplicateOnCloneTree</code> variable determines whether 383 * NodeComponent data is duplicated or copied. 384 * 385 * @see Node#cloneTree 386 * @see Node#cloneNode 387 * @see NodeComponent#setDuplicateOnCloneTree 388 */ duplicateNode(Node originalNode, boolean forceDuplicate)389 public void duplicateNode(Node originalNode, boolean forceDuplicate) { 390 super.duplicateNode(originalNode, forceDuplicate); 391 } 392 393 /** 394 * Returns the radius of the cone 395 * 396 * @since Java 3D 1.2.1 397 */ getRadius()398 public float getRadius() { 399 return radius; 400 } 401 402 /** 403 * Returns the height of the cone 404 * 405 * @since Java 3D 1.2.1 406 */ getHeight()407 public float getHeight() { 408 return height; 409 } 410 411 /** 412 * Returns the number divisions along the X direction 413 * 414 * @since Java 3D 1.2.1 415 */ getXdivisions()416 public int getXdivisions() { 417 return xdivisions; 418 } 419 420 /** 421 * Returns the number of divisions along the height of the cone 422 * 423 * @since Java 3D 1.2.1 424 */ getYdivisions()425 public int getYdivisions() { 426 return ydivisions; 427 } 428 429 } 430