/* * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. * */ package javax.media.j3d; import javax.vecmath.Point3d; import javax.vecmath.Point4d; import javax.vecmath.Vector3d; import javax.vecmath.Vector4d; /** * This class defines an axis aligned bounding box which is used for * bounding regions. * */ public class BoundingBox extends Bounds { /** * The corner of the bounding box with the numerically smallest values. */ final Point3d lower; /** * The corner of the bounding box with the numerically largest values. */ final Point3d upper; private static final double EPS = 1.0E-8; /** * Constructs and initializes a BoundingBox given min,max in x,y,z. * @param lower the "small" corner * @param upper the "large" corner */ public BoundingBox(Point3d lower, Point3d upper) { boundId = BOUNDING_BOX; this.lower = new Point3d(lower); this.upper = new Point3d(upper); updateBoundsStates(); } /** * Constructs and initializes a 2X bounding box about the origin. The lower * corner is initialized to (-1.0d, -1.0d, -1.0d) and the upper corner is * initialized to (1.0d, 1.0d, 1.0d). */ public BoundingBox() { boundId = BOUNDING_BOX; lower = new Point3d(-1.0d, -1.0d, -1.0d); upper = new Point3d( 1.0d, 1.0d, 1.0d); boundsIsEmpty = false; boundsIsInfinite = false; } /** * Constructs a BoundingBox from a bounding object. * @param boundsObject a bounds object */ public BoundingBox(Bounds boundsObject) { boundId = BOUNDING_BOX; lower = new Point3d(); upper = new Point3d(); if (boundsObject == null || boundsObject.boundsIsEmpty) { setEmptyBounds(); return; } if (boundsObject.boundsIsInfinite) { setInfiniteBounds(); return; } if( boundsObject.boundId == BOUNDING_BOX){ BoundingBox box = (BoundingBox)boundsObject; lower.set(box.lower); upper.set(box.upper); } else if( boundsObject.boundId == BOUNDING_SPHERE ) { BoundingSphere sphere = (BoundingSphere)boundsObject; lower.set(sphere.center.x - sphere.radius, sphere.center.y - sphere.radius, sphere.center.z - sphere.radius); upper.set(sphere.center.x + sphere.radius, sphere.center.y + sphere.radius, sphere.center.z + sphere.radius); } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { BoundingPolytope polytope = (BoundingPolytope)boundsObject; if( polytope.nVerts < 1 ) { // handle degenerate case lower.set(-1.0d, -1.0d, -1.0d); upper.set( 1.0d, 1.0d, 1.0d); } else { lower.set(polytope.verts[0]); upper.set(polytope.verts[0]); for(int i=1;i upper.x ) upper.x = polytope.verts[i].x; if( polytope.verts[i].y > upper.y ) upper.y = polytope.verts[i].y; if( polytope.verts[i].z > upper.z ) upper.z = polytope.verts[i].z; } } } else { throw new IllegalArgumentException(J3dI18N.getString("BoundingBox0")); } updateBoundsStates(); } /** * Constructs a BoundingBox from an array of bounding objects. * @param bounds an array of bounding objects */ public BoundingBox(Bounds[] bounds) { boundId = BOUNDING_BOX; upper = new Point3d(); lower = new Point3d(); if (bounds == null || bounds.length <= 0) { setEmptyBounds(); return; } int i = 0; // find first non empty bounds object while ((i < bounds.length) && ((bounds[i] == null) || bounds[i].boundsIsEmpty)) { i++; } if (i >= bounds.length) { // all bounds objects were empty setEmptyBounds(); return; } this.set(bounds[i++]); if(boundsIsInfinite) return; for(;i box.lower.x) lower.x = box.lower.x; if( lower.y > box.lower.y) lower.y = box.lower.y; if( lower.z > box.lower.z) lower.z = box.lower.z; if( upper.x < box.upper.x) upper.x = box.upper.x; if( upper.y < box.upper.y) upper.y = box.upper.y; if( upper.z < box.upper.z) upper.z = box.upper.z; } else if(bounds[i].boundId == BOUNDING_SPHERE) { BoundingSphere sphere = (BoundingSphere)bounds[i]; if( lower.x > (sphere.center.x - sphere.radius)) lower.x = sphere.center.x - sphere.radius; if( lower.y > (sphere.center.y - sphere.radius)) lower.y = sphere.center.y - sphere.radius; if( lower.z > (sphere.center.z - sphere.radius)) lower.z = sphere.center.z - sphere.radius; if( upper.x < (sphere.center.x + sphere.radius)) upper.x = sphere.center.x + sphere.radius; if( upper.y < (sphere.center.y + sphere.radius)) upper.y = sphere.center.y + sphere.radius; if( upper.z < (sphere.center.z + sphere.radius)) upper.z = sphere.center.z + sphere.radius; } else if(bounds[i].boundId == BOUNDING_POLYTOPE) { BoundingPolytope polytope = (BoundingPolytope)bounds[i]; for(i=0;i upper.x ) upper.x = polytope.verts[i].x; if( polytope.verts[i].y > upper.y ) upper.y = polytope.verts[i].y; if( polytope.verts[i].z > upper.z ) upper.z = polytope.verts[i].z; } } else { throw new IllegalArgumentException(J3dI18N.getString("BoundingBox1")); } } updateBoundsStates(); } /** * Gets the lower corner of this bounding box. * @param p1 a Point to receive the lower corner of the bounding box */ public void getLower(Point3d p1) { p1.set(lower); } /** * Sets the lower corner of this bounding box. * @param xmin minimum x value of bounding box * @param ymin minimum y value of bounding box * @param zmin minimum z value of bounding box */ public void setLower(double xmin, double ymin, double zmin) { lower.set(xmin, ymin, zmin); updateBoundsStates(); } /** * Sets the lower corner of this bounding box. * @param p1 a Point defining the new lower corner of the bounding box */ public void setLower(Point3d p1) { lower.set(p1); updateBoundsStates(); } /** * Gets the upper corner of this bounding box. * @param p1 a Point to receive the upper corner of the bounding box */ public void getUpper(Point3d p1) { p1.set(upper); } /** * Sets the upper corner of this bounding box. * @param xmax max x value of bounding box * @param ymax max y value of bounding box * @param zmax max z value of bounding box */ public void setUpper(double xmax, double ymax, double zmax) { upper.set(xmax, ymax, zmax); updateBoundsStates(); } /** * Sets the upper corner of this bounding box. * @param p1 a Point defining the new upper corner of the bounding box */ public void setUpper(Point3d p1) { upper.set(p1); updateBoundsStates(); } /** * Sets the the value of this BoundingBox * @param boundsObject another bounds object */ @Override public void set(Bounds boundsObject) { int i; if (boundsObject == null || boundsObject.boundsIsEmpty) { setEmptyBounds(); return; } if (boundsObject.boundsIsInfinite) { setInfiniteBounds(); return; } if( boundsObject.boundId == BOUNDING_BOX){ BoundingBox box = (BoundingBox)boundsObject; lower.x = box.lower.x; lower.y = box.lower.y; lower.z = box.lower.z; upper.x = box.upper.x; upper.y = box.upper.y; upper.z = box.upper.z; } else if( boundsObject.boundId == BOUNDING_SPHERE ) { BoundingSphere sphere = (BoundingSphere)boundsObject; lower.x = sphere.center.x - sphere.radius; lower.y = sphere.center.y - sphere.radius; lower.z = sphere.center.z - sphere.radius; upper.x = sphere.center.x + sphere.radius; upper.y = sphere.center.y + sphere.radius; upper.z = sphere.center.z + sphere.radius; } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { BoundingPolytope polytope = (BoundingPolytope)boundsObject; lower.x = upper.x = polytope.verts[0].x; lower.y = upper.y = polytope.verts[0].y; lower.z = upper.z = polytope.verts[0].z; for(i=1;i upper.x ) upper.x = polytope.verts[i].x; if( polytope.verts[i].y > upper.y ) upper.y = polytope.verts[i].y; if( polytope.verts[i].z > upper.z ) upper.z = polytope.verts[i].z; } } else { throw new IllegalArgumentException(J3dI18N.getString("BoundingBox0")); } updateBoundsStates(); } /** * Creates a copy of this bounding box. * @return a new bounding box */ @Override public Object clone() { return new BoundingBox(this.lower, this.upper); } /** * Indicates whether the specified bounds object is * equal to this BoundingBox object. They are equal if the * specified bounds object is an instance of * BoundingBox and all of the data * members of bounds are equal to the corresponding * data members in this BoundingBox. * @param bounds the object with which the comparison is made. * @return true if this BoundingBox is equal to bounds; * otherwise false * * @since Java 3D 1.2 */ @Override public boolean equals(Object bounds) { try { BoundingBox box = (BoundingBox)bounds; return (lower.equals(box.lower) && upper.equals(box.upper)); } catch (NullPointerException e) { return false; } catch (ClassCastException e) { return false; } } /** * Returns a hash code value for this BoundingBox object * based on the data values in this object. Two different * BoundingBox objects with identical data values (i.e., * BoundingBox.equals returns true) will return the same hash * code value. Two BoundingBox objects with different data * members may return the same hash code value, although this is * not likely. * @return a hash code value for this BoundingBox object. * * @since Java 3D 1.2 */ @Override public int hashCode() { long bits = 1L; bits = J3dHash.mixDoubleBits(bits, lower.x); bits = J3dHash.mixDoubleBits(bits, lower.y); bits = J3dHash.mixDoubleBits(bits, lower.z); bits = J3dHash.mixDoubleBits(bits, upper.x); bits = J3dHash.mixDoubleBits(bits, upper.y); bits = J3dHash.mixDoubleBits(bits, upper.z); return J3dHash.finish(bits); } /** * Combines this bounding box with a bounding object so that the * resulting bounding box encloses the original bounding box and the * specified bounds object. * @param boundsObject another bounds object */ @Override public void combine(Bounds boundsObject) { if((boundsObject == null) || (boundsObject.boundsIsEmpty) || (boundsIsInfinite)) return; if((boundsIsEmpty) || (boundsObject.boundsIsInfinite)) { this.set(boundsObject); return; } if( boundsObject.boundId == BOUNDING_BOX){ BoundingBox box = (BoundingBox)boundsObject; if( lower.x > box.lower.x) lower.x = box.lower.x; if( lower.y > box.lower.y) lower.y = box.lower.y; if( lower.z > box.lower.z) lower.z = box.lower.z; if( upper.x < box.upper.x) upper.x = box.upper.x; if( upper.y < box.upper.y) upper.y = box.upper.y; if( upper.z < box.upper.z) upper.z = box.upper.z; } else if( boundsObject.boundId == BOUNDING_SPHERE ) { BoundingSphere sphere = (BoundingSphere)boundsObject; if( lower.x > (sphere.center.x - sphere.radius)) lower.x = sphere.center.x - sphere.radius; if( lower.y > (sphere.center.y - sphere.radius)) lower.y = sphere.center.y - sphere.radius; if( lower.z > (sphere.center.z - sphere.radius)) lower.z = sphere.center.z - sphere.radius; if( upper.x < (sphere.center.x + sphere.radius)) upper.x = sphere.center.x + sphere.radius; if( upper.y < (sphere.center.y + sphere.radius)) upper.y = sphere.center.y + sphere.radius; if( upper.z < (sphere.center.z + sphere.radius)) upper.z = sphere.center.z + sphere.radius; } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { BoundingPolytope polytope = (BoundingPolytope)boundsObject; int i; for(i=1;i upper.x ) upper.x = polytope.verts[i].x; if( polytope.verts[i].y > upper.y ) upper.y = polytope.verts[i].y; if( polytope.verts[i].z > upper.z ) upper.z = polytope.verts[i].z; } } else { throw new IllegalArgumentException(J3dI18N.getString("BoundingBox3")); } updateBoundsStates(); } /** * Combines this bounding box with an array of bounding objects * so that the resulting bounding box encloses the original bounding * box and the array of bounding objects. * @param bounds an array of bounds objects */ @Override public void combine(Bounds[] bounds) { int i=0; if( (bounds == null) || (bounds.length <= 0) || (boundsIsInfinite)) return; // find first non empty bounds object while( (i= bounds.length) return; // no non empty bounds so do not modify current bounds if(boundsIsEmpty) this.set(bounds[i++]); if(boundsIsInfinite) return; for(;i box.lower.x) lower.x = box.lower.x; if( lower.y > box.lower.y) lower.y = box.lower.y; if( lower.z > box.lower.z) lower.z = box.lower.z; if( upper.x < box.upper.x) upper.x = box.upper.x; if( upper.y < box.upper.y) upper.y = box.upper.y; if( upper.z < box.upper.z) upper.z = box.upper.z; } else if( bounds[i].boundId == BOUNDING_SPHERE ) { BoundingSphere sphere = (BoundingSphere)bounds[i]; if( lower.x > (sphere.center.x - sphere.radius)) lower.x = sphere.center.x - sphere.radius; if( lower.y > (sphere.center.y - sphere.radius)) lower.y = sphere.center.y - sphere.radius; if( lower.z > (sphere.center.z - sphere.radius)) lower.z = sphere.center.z - sphere.radius; if( upper.x < (sphere.center.x + sphere.radius)) upper.x = sphere.center.x + sphere.radius; if( upper.y < (sphere.center.y + sphere.radius)) upper.y = sphere.center.y + sphere.radius; if( upper.z < (sphere.center.z + sphere.radius)) upper.z = sphere.center.z + sphere.radius; } else if(bounds[i].boundId == BOUNDING_POLYTOPE) { BoundingPolytope polytope = (BoundingPolytope)bounds[i]; for(i=1;i upper.x ) upper.x = polytope.verts[i].x; if( polytope.verts[i].y > upper.y ) upper.y = polytope.verts[i].y; if( polytope.verts[i].z > upper.z ) upper.z = polytope.verts[i].z; } } else { throw new IllegalArgumentException(J3dI18N.getString("BoundingBox4")); } } updateBoundsStates(); } /** * Combines this bounding box with a point so that the resulting * bounding box encloses the original bounding box and the point. * @param point a 3d point in space */ @Override public void combine(Point3d point) { if( boundsIsInfinite) { return; } if( boundsIsEmpty) { upper.x = lower.x = point.x; upper.y = lower.y = point.y; upper.z = lower.z = point.z; } else { if( point.x > upper.x) upper.x = point.x; if( point.y > upper.y) upper.y = point.y; if( point.z > upper.z) upper.z = point.z; if( point.x < lower.x) lower.x = point.x; if( point.y < lower.y) lower.y = point.y; if( point.z < lower.z) lower.z = point.z; } updateBoundsStates(); } /** * Combines this bounding box with an array of points so that the * resulting bounding box encloses the original bounding box and the * array of points. * @param points an array of 3d points in space */ @Override public void combine(Point3d[] points) { int i; if( boundsIsInfinite) { return; } if( boundsIsEmpty) { this.setUpper(points[0]); this.setLower(points[0]); } for(i=0;i upper.x) upper.x = points[i].x; if( points[i].y > upper.y) upper.y = points[i].y; if( points[i].z > upper.z) upper.z = points[i].z; if( points[i].x < lower.x) lower.x = points[i].x; if( points[i].y < lower.y) lower.y = points[i].y; if( points[i].z < lower.z) lower.z = points[i].z; } updateBoundsStates(); } /** * Modifies the bounding box so that it bounds the volume * generated by transforming the given bounding object. * @param boundsObject the bounding object to be transformed * @param matrix a transformation matrix */ @Override public void transform( Bounds boundsObject, Transform3D matrix) { if (boundsObject == null || boundsObject.boundsIsEmpty) { setEmptyBounds(); return; } if (boundsObject.boundsIsInfinite) { setInfiniteBounds(); return; } if(boundsObject.boundId == BOUNDING_BOX){ this.set(boundsObject); this.transform(matrix); } else if(boundsObject.boundId == BOUNDING_SPHERE) { BoundingSphere tmpSphere = new BoundingSphere(boundsObject); tmpSphere.transform(matrix); this.set(tmpSphere); } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { BoundingPolytope tmpPolytope = new BoundingPolytope(boundsObject); tmpPolytope.transform(matrix); this.set(tmpPolytope); } else { throw new IllegalArgumentException(J3dI18N.getString("BoundingBox5")); } } /** * Transforms this bounding box by the given matrix. * @param matrix a transformation matrix */ @Override public void transform(Transform3D matrix) { if (boundsIsInfinite) return; Point3d tmpP3d = new Point3d(); double ux, uy, uz, lx, ly, lz; ux = upper.x; uy = upper.y; uz = upper.z; lx = lower.x; ly = lower.y; lz = lower.z; tmpP3d.set(ux, uy, uz); matrix.transform( tmpP3d ); upper.x = tmpP3d.x; upper.y = tmpP3d.y; upper.z = tmpP3d.z; lower.x = tmpP3d.x; lower.y = tmpP3d.y; lower.z = tmpP3d.z; tmpP3d.set(lx, uy, uz); matrix.transform( tmpP3d ); if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; tmpP3d.set(lx, ly, uz); matrix.transform( tmpP3d ); if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; tmpP3d.set(ux, ly, uz); matrix.transform( tmpP3d ); if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; tmpP3d.set(lx, uy, lz); matrix.transform( tmpP3d ); if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; tmpP3d.set(ux, uy, lz); matrix.transform( tmpP3d ); if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; tmpP3d.set(lx, ly, lz); matrix.transform( tmpP3d ); if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; tmpP3d.set(ux, ly, lz); matrix.transform( tmpP3d ); if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; } /** * Test for intersection with a ray. * @param origin the starting point of the ray * @param direction the direction of the ray * @param position3 a point defining the location of the pick w= distance to pick * @return true or false indicating if an intersection occured */ @Override boolean intersect(Point3d origin, Vector3d direction, Point4d position ) { double t1,t2,tmp,tnear,tfar,invDir,invMag; double dirx, diry, dirz; /* System.err.println("BoundingBox.intersect(p,d,p) called\n"); System.err.println("bounds = " + lower + " -> " + upper); */ if( boundsIsEmpty ) { return false; } if( boundsIsInfinite ) { position.x = origin.x; position.y = origin.y; position.z = origin.z; position.w = 0.0; return true; } double dirLen = direction.x*direction.x + direction.y*direction.y + direction.z*direction.z; // Handle zero length direction vector. if(dirLen == 0.0) return intersect(origin, position); invMag = 1.0/Math.sqrt(dirLen); dirx = direction.x*invMag; diry = direction.y*invMag; dirz = direction.z*invMag; /* System.err.println("dir = " + dirx + ", " + diry + ", " + dirz); System.err.println("origin = " + origin); */ // initialize tnear and tfar to handle dir.? == 0 cases tnear = -Double.MAX_VALUE; tfar = Double.MAX_VALUE; if(dirx == 0.0) { //System.err.println("dirx == 0.0"); if (origin.x < lower.x || origin.x > upper.x ) { //System.err.println( "parallel to x plane and outside"); return false; } } else { invDir = 1.0/dirx; t1 = (lower.x-origin.x)*invDir; t2 = (upper.x-origin.x)*invDir; //System.err.println("x t1 = " + t1 + " t2 = " + t2); if( t1 > t2) { tnear = t2; tfar = t1; }else { tnear = t1; tfar = t2; } if( tfar < 0.0 ) { //System.err.println( "x failed: tnear="+tnear+" tfar="+tfar); return false; } //System.err.println("x tnear = " + tnear + " tfar = " + tfar); } // y if (diry == 0.0) { //System.err.println("diry == 0.0"); if( origin.y < lower.y || origin.y > upper.y ){ //System.err.println( "parallel to y plane and outside"); return false; } } else { invDir = 1.0/diry; //System.err.println("invDir = " + invDir); t1 = (lower.y-origin.y)*invDir; t2 = (upper.y-origin.y)*invDir; if( t1 > t2) { tmp = t1; t1 = t2; t2 = tmp; } //System.err.println("y t1 = " + t1 + " t2 = " + t2); if( t1 > tnear) tnear = t1; if( t2 < tfar ) tfar = t2; if( (tfar < 0.0) || (tnear > tfar)){ //System.err.println( "y failed: tnear="+tnear+" tfar="+tfar); return false; } //System.err.println("y tnear = " + tnear + " tfar = " + tfar); } // z if (dirz == 0.0) { //System.err.println("dirz == 0.0"); if( origin.z < lower.z || origin.z > upper.z ) { //System.err.println( "parallel to z plane and outside"); return false; } } else { invDir = 1.0/dirz; t1 = (lower.z-origin.z)*invDir; t2 = (upper.z-origin.z)*invDir; if( t1 > t2) { tmp = t1; t1 = t2; t2 = tmp; } //System.err.println("z t1 = " + t1 + " t2 = " + t2); if( t1 > tnear) tnear = t1; if( t2 < tfar ) tfar = t2; if( (tfar < 0.0) || (tnear > tfar)){ //System.err.println( "z failed: tnear="+tnear+" tfar="+tfar); return false; } //System.err.println("z tnear = " + tnear + " tfar = " + tfar); } if((tnear < 0.0) && (tfar >= 0.0)) { // origin is inside the BBox. position.x = origin.x + dirx*tfar; position.y = origin.y + diry*tfar; position.z = origin.z + dirz*tfar; position.w = tfar; } else { position.x = origin.x + dirx*tnear; position.y = origin.y + diry*tnear; position.z = origin.z + dirz*tnear; position.w = tnear; } return true; } /** * Test for intersection with a point. * @param point the pick point * @param position a point defining the location of the pick w= distance to pick * @return true or false indicating if an intersection occured */ @Override boolean intersect(Point3d point, Point4d position ) { if( boundsIsEmpty ) { return false; } if( boundsIsInfinite ) { position.x = point.x; position.y = point.y; position.z = point.z; position.w = 0.0; return true; } if( point.x <= upper.x && point.x >= lower.x && point.y <= upper.y && point.y >= lower.y && point.z <= upper.z && point.z >= lower.z) { position.x = point.x; position.y = point.y; position.z = point.z; position.w = 0.0; return true; } else return false; } /** * Test for intersection with a segment. * @param start a point defining the start of the line segment * @param end a point defining the end of the line segment * @param position a point defining the location of the pick w= distance to pick * @return true or false indicating if an intersection occured */ @Override boolean intersect( Point3d start, Point3d end, Point4d position ) { double t1,t2,tmp,tnear,tfar,invDir,invMag; double dirx, diry, dirz; if( boundsIsEmpty ) { return false; } if( boundsIsInfinite ) { position.x = start.x; position.y = start.y; position.z = start.z; position.w = 0.0; return true; } dirx = end.x - start.x; diry = end.y - start.y; dirz = end.z - start.z; double dirLen = dirx*dirx + diry*diry + dirz*dirz; // Optimization : Handle zero length direction vector. if(dirLen == 0.0) return intersect(start, position); dirLen = Math.sqrt(dirLen); // System.err.println("dirLen is " + dirLen); invMag = 1.0/dirLen; dirx = dirx*invMag; diry = diry*invMag; dirz = dirz*invMag; /* System.err.println("dir = " + dir); System.err.println("start = " + start); System.err.println("lower = " + lower); System.err.println("upper = " + upper); */ // initialize tnear and tfar to handle dir.? == 0 cases tnear = -Double.MAX_VALUE; tfar = Double.MAX_VALUE; if(dirx == 0.0) { //System.err.println("dirx == 0.0"); if (start.x < lower.x || start.x > upper.x ) { //System.err.println( "parallel to x plane and outside"); return false; } } else { invDir = 1.0/dirx; t1 = (lower.x-start.x)*invDir; t2 = (upper.x-start.x)*invDir; //System.err.println("x t1 = " + t1 + " t2 = " + t2); if( t1 > t2) { tnear = t2; tfar = t1; }else { tnear = t1; tfar = t2; } if( tfar < 0.0 ) { //System.err.println( "x failed: tnear="+tnear+" tfar="+tfar); return false; } //System.err.println("x tnear = " + tnear + " tfar = " + tfar); } // y if (diry == 0.0) { //System.err.println("diry == 0.0"); if( start.y < lower.y || start.y > upper.y ){ //System.err.println( "parallel to y plane and outside"); return false; } } else { invDir = 1.0/diry; //System.err.println("invDir = " + invDir); t1 = (lower.y-start.y)*invDir; t2 = (upper.y-start.y)*invDir; if( t1 > t2) { tmp = t1; t1 = t2; t2 = tmp; } //System.err.println("y t1 = " + t1 + " t2 = " + t2); if( t1 > tnear) tnear = t1; if( t2 < tfar ) tfar = t2; if( (tfar < 0.0) || (tnear > tfar)){ //System.err.println( "y failed: tnear="+tnear+" tfar="+tfar); return false; } //System.err.println("y tnear = " + tnear + " tfar = " + tfar); } // z if (dirz == 0.0) { //System.err.println("dirz == 0.0"); if( start.z < lower.z || start.z > upper.z ) { //System.err.println( "parallel to z plane and outside"); return false; } } else { invDir = 1.0/dirz; t1 = (lower.z-start.z)*invDir; t2 = (upper.z-start.z)*invDir; if( t1 > t2) { tmp = t1; t1 = t2; t2 = tmp; } //System.err.println("z t1 = " + t1 + " t2 = " + t2); if( t1 > tnear) tnear = t1; if( t2 < tfar ) tfar = t2; if( (tfar < 0.0) || (tnear > tfar)){ //System.err.println( "z failed: tnear="+tnear+" tfar="+tfar); return false; } //System.err.println("z tnear = " + tnear + " tfar = " + tfar); } if((tnear < 0.0) && (tfar >= 0.0)) { // origin is inside the BBox. position.x = start.x + dirx*tfar; position.y = start.y + diry*tfar; position.z = start.z + dirz*tfar; position.w = tfar; } else { if(tnear>dirLen) { // Segment is behind BBox. /* System.err.println("PickSegment : intersected postion : " + position + " tnear " + tnear + " tfar " + tfar ); */ return false; } position.x = start.x + dirx*tnear; position.y = start.y + diry*tnear; position.z = start.z + dirz*tnear; position.w = tnear; } /* System.err.println("tnear = " + tnear + " tfar = " + tfar + " w " + position.w); System.err.println("lower = " + lower); System.err.println("upper = " + upper + "\n"); */ return true; } /** * Test for intersection with a ray. * @param origin the starting point of the ray * @param direction the direction of the ray * @return true or false indicating if an intersection occured */ @Override public boolean intersect(Point3d origin, Vector3d direction ) { if( boundsIsEmpty ) { return false; } if( boundsIsInfinite ) { return true; } Point3d p=new Point3d(); return intersect( origin, direction, p ); } /** * A protected intersect method that returns the point of intersection. * Used by Picking methods to sort or return closest picked item. */ boolean intersect(Point3d origin, Vector3d direction, Point3d intersect ) { double theta=0.0; if( boundsIsEmpty ) { return false; } if( boundsIsInfinite ) { intersect.x = origin.x; intersect.y = origin.y; intersect.z = origin.z; return true; } if (direction.x > 0.0 ) theta = Math.max( theta, (lower.x - origin.x)/direction.x ); if (direction.x < 0.0 ) theta = Math.max( theta, (upper.x - origin.x)/direction.x ); if (direction.y > 0.0 ) theta = Math.max( theta, (lower.y - origin.y)/direction.y ); if (direction.y < 0.0 ) theta = Math.max( theta, (upper.y - origin.y)/direction.y ); if (direction.z > 0.0 ) theta = Math.max( theta, (lower.z - origin.z)/direction.z ); if (direction.z < 0.0 ) theta = Math.max( theta, (upper.z - origin.z)/direction.z ); intersect.x = origin.x + theta*direction.x; intersect.y = origin.y + theta*direction.y; intersect.z = origin.z + theta*direction.z; if (intersect.x < (lower.x-EPS)) return false; if (intersect.x > (upper.x+EPS)) return false; if (intersect.y < (lower.y-EPS)) return false; if (intersect.y > (upper.y+EPS)) return false; if (intersect.z < (lower.z-EPS)) return false; if (intersect.z > (upper.z+EPS)) return false; return true; } /** * Test for intersection with a point. * @param point a point defining a position in 3-space * @return true or false indicating if an intersection occured */ @Override public boolean intersect(Point3d point ) { if( boundsIsEmpty ) { return false; } if( boundsIsInfinite ) { return true; } if( point.x <= upper.x && point.x >= lower.x && point.y <= upper.y && point.y >= lower.y && point.z <= upper.z && point.z >= lower.z) return true; else return false; } /** * Tests whether the bounding box is empty. A bounding box is * empty if it is null (either by construction or as the result of * a null intersection) or if its volume is negative. A bounding box * with a volume of zero is not empty. * @return true if the bounding box is empty; otherwise, it returns false */ @Override public boolean isEmpty() { return boundsIsEmpty; } /** * Test for intersection with another bounds object. * @param boundsObject another bounds object * @return true or false indicating if an intersection occured */ @Override boolean intersect(Bounds boundsObject, Point4d position) { return intersect(boundsObject); } /** * Test for intersection with another bounds object. * @param boundsObject another bounds object * @return true or false indicating if an intersection occured */ @Override public boolean intersect(Bounds boundsObject) { if( boundsObject == null ) { return false; } if( boundsIsEmpty || boundsObject.boundsIsEmpty ) { return false; } if( boundsIsInfinite || boundsObject.boundsIsInfinite ) { return true; } if( boundsObject.boundId == BOUNDING_BOX){ BoundingBox box = (BoundingBox)boundsObject; // both boxes are axis aligned if( upper.x > box.lower.x && box.upper.x > lower.x && upper.y > box.lower.y && box.upper.y > lower.y && upper.z > box.lower.z && box.upper.z > lower.z ) return true; else return false; } else if( boundsObject.boundId == BOUNDING_SPHERE) { BoundingSphere sphere = (BoundingSphere)boundsObject; double rad_sq = sphere.radius*sphere.radius; double dis = 0.0; if( sphere.center.x < lower.x ) dis = (sphere.center.x-lower.x)*(sphere.center.x-lower.x); else if( sphere.center.x > upper.x ) dis = (sphere.center.x-upper.x)*(sphere.center.x-upper.x); if( sphere.center.y < lower.y ) dis += (sphere.center.y-lower.y)*(sphere.center.y-lower.y); else if( sphere.center.y > upper.y ) dis += (sphere.center.y-upper.y)*(sphere.center.y-upper.y); if( sphere.center.z < lower.z ) dis += (sphere.center.z-lower.z)*(sphere.center.z-lower.z); else if( sphere.center.z > upper.z ) dis += (sphere.center.z-upper.z)*(sphere.center.z-upper.z); if( dis <= rad_sq ) return true; else return false; } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { // intersect an axis aligned box with a polytope return intersect_ptope_abox ( (BoundingPolytope)boundsObject, this ); } else { throw new IllegalArgumentException(J3dI18N.getString("BoundingBox6")); } } /** * Test for intersection with an array of bounds objects. * @param boundsObjects an array of bounding objects * @return true or false indicating if an intersection occured */ @Override public boolean intersect(Bounds[] boundsObjects) { int i; if( boundsObjects == null || boundsObjects.length <= 0 ) { return false; } if( boundsIsEmpty ) { return false; } for(i = 0; i < boundsObjects.length; i++){ if( boundsObjects[i] == null || boundsObjects[i].boundsIsEmpty) ; else if( boundsIsInfinite || boundsObjects[i].boundsIsInfinite ) { return true; // We're done here. } else if( boundsObjects[i].boundId == BOUNDING_BOX){ BoundingBox box = (BoundingBox)boundsObjects[i]; // both boxes are axis aligned if( upper.x > box.lower.x && box.upper.x > lower.x && upper.y > box.lower.y && box.upper.y > lower.y && upper.z > box.lower.z && box.upper.z > lower.z ) return true; } else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { BoundingSphere sphere = (BoundingSphere)boundsObjects[i]; double rad_sq = sphere.radius*sphere.radius; double dis = 0.0; if( sphere.center.x < lower.x ) dis = (sphere.center.x-lower.x)*(sphere.center.x-lower.x); else if( sphere.center.x > upper.x ) dis = (sphere.center.x-upper.x)*(sphere.center.x-upper.x); if( sphere.center.y < lower.y ) dis += (sphere.center.y-lower.y)*(sphere.center.y-lower.y); else if( sphere.center.y > upper.y ) dis += (sphere.center.y-upper.y)*(sphere.center.y-upper.y); if( sphere.center.z < lower.z ) dis += (sphere.center.z-lower.z)*(sphere.center.z-lower.z); else if( sphere.center.z > upper.z ) dis += (sphere.center.z-upper.z)*(sphere.center.z-upper.z); if( dis <= rad_sq ) return true; } else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { if( intersect_ptope_abox ( (BoundingPolytope)boundsObjects[i], this )) return true; } else { // System.err.println("intersect ?? "); } } return false; } /** * Test for intersection with another bounding box. * @param boundsObject another bounding object * @param newBoundBox the new bounding box which is the intersection of * the boundsObject and this BoundingBox * @return true or false indicating if an intersection occured */ public boolean intersect(Bounds boundsObject, BoundingBox newBoundBox) { if((boundsObject == null) || boundsIsEmpty || boundsObject.boundsIsEmpty ) { newBoundBox.set((Bounds)null); return false; } if(boundsIsInfinite && (!boundsObject.boundsIsInfinite)) { newBoundBox.set(boundsObject); return true; } else if((!boundsIsInfinite) && boundsObject.boundsIsInfinite) { newBoundBox.set(this); return true; } else if(boundsIsInfinite && boundsObject.boundsIsInfinite) { newBoundBox.set(this); return true; } else if( boundsObject.boundId == BOUNDING_BOX){ BoundingBox box = (BoundingBox)boundsObject; // both boxes are axis aligned if( upper.x > box.lower.x && box.upper.x > lower.x && upper.y > box.lower.y && box.upper.y > lower.y && upper.z > box.lower.z && box.upper.z > lower.z ){ if(upper.x > box.upper.x) newBoundBox.upper.x = box.upper.x; else newBoundBox.upper.x = upper.x; if(upper.y > box.upper.y) newBoundBox.upper.y = box.upper.y; else newBoundBox.upper.y = upper.y; if(upper.z > box.upper.z) newBoundBox.upper.z = box.upper.z; else newBoundBox.upper.z = upper.z; if(lower.x < box.lower.x) newBoundBox.lower.x = box.lower.x; else newBoundBox.lower.x = lower.x; if(lower.y < box.lower.y) newBoundBox.lower.y = box.lower.y; else newBoundBox.lower.y = lower.y; if(lower.z < box.lower.z) newBoundBox.lower.z = box.lower.z; else newBoundBox.lower.z = lower.z; newBoundBox.updateBoundsStates(); return true; } else { // Negative volume. newBoundBox.set((Bounds)null); return false; } } else if( boundsObject.boundId == BOUNDING_SPHERE) { BoundingSphere sphere = (BoundingSphere)boundsObject; if( this.intersect( sphere) ) { BoundingBox sbox = new BoundingBox( sphere ); this.intersect( sbox, newBoundBox ); return true; } else { // Negative volume. newBoundBox.set((Bounds)null); return false; } // System.err.println("intersect Sphere "); } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { BoundingPolytope polytope = (BoundingPolytope)boundsObject; if( this.intersect( polytope)) { BoundingBox pbox = new BoundingBox( polytope); // convert polytope to box this.intersect( pbox, newBoundBox ); return true; } else { // Negative volume. newBoundBox.set((Bounds)null); return false; } } else { throw new IllegalArgumentException(J3dI18N.getString("BoundingBox7")); } } /** * Test for intersection with an array of bounds objects. * @param boundsObjects an array of bounds objects * @param newBoundBox the new bounding box which is the intersection of * the boundsObject and this BoundingBox * @return true or false indicating if an intersection occured */ public boolean intersect(Bounds[] boundsObjects, BoundingBox newBoundBox) { if( boundsObjects == null || boundsObjects.length <= 0 || boundsIsEmpty ) { // Negative volume. newBoundBox.set((Bounds)null); return false; } int i=0; // find first non null bounds object while( boundsObjects[i] == null && i < boundsObjects.length) { i++; } if( i >= boundsObjects.length ) { // all bounds objects were empty // Negative volume. newBoundBox.set((Bounds)null); return false; } boolean status = false; BoundingBox tbox = new BoundingBox(); for(;i box.lower.x && box.upper.x > lower.x && upper.y > box.lower.y && box.upper.y > lower.y && upper.z > box.lower.z && box.upper.z > lower.z ){ if(upper.x > box.upper.x) newBoundBox.upper.x = box.upper.x; else newBoundBox.upper.x = upper.x; if(upper.y > box.upper.y) newBoundBox.upper.y = box.upper.y; else newBoundBox.upper.y = upper.y; if(upper.z > box.upper.z) newBoundBox.upper.z = box.upper.z; else newBoundBox.upper.z = upper.z; if(lower.x < box.lower.x) newBoundBox.lower.x = box.lower.x; else newBoundBox.lower.x = lower.x; if(lower.y < box.lower.y) newBoundBox.lower.y = box.lower.y; else newBoundBox.lower.y = lower.y; if(lower.z < box.lower.z) newBoundBox.lower.z = box.lower.z; else newBoundBox.lower.z = lower.z; status = true; newBoundBox.updateBoundsStates(); } } else if( boundsObjects[i].boundId == BOUNDING_SPHERE) { BoundingSphere sphere = (BoundingSphere)boundsObjects[i]; if( this.intersect(sphere)) { BoundingBox sbox = new BoundingBox( sphere ); // convert sphere to box this.intersect(sbox,tbox); // insersect two boxes if( status ) { newBoundBox.combine( tbox ); } else { newBoundBox.set( tbox ); status = true; } } } else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; if( this.intersect( polytope)) { BoundingBox pbox = new BoundingBox( polytope ); // convert polytope to box this.intersect(pbox,tbox); // insersect two boxes if ( status ) { newBoundBox.combine( tbox ); } else { newBoundBox.set( tbox ); status = true; } } } else { throw new IllegalArgumentException(J3dI18N.getString("BoundingBox6")); } if(newBoundBox.boundsIsInfinite) break; // We're done. } if( status == false ) { // Negative volume. newBoundBox.set((Bounds)null); } return status; } /** * Finds closest bounding object that intersects this bounding box. * @param boundsObjects an array of bounds objects * @return closest bounding object */ @Override public Bounds closestIntersection( Bounds[] boundsObjects) { if( boundsObjects == null || boundsObjects.length <= 0 ) { return null; } if( boundsIsEmpty ) { return null; } Point3d centroid = getCenter(); double dis; double cenX = 0.0, cenY = 0.0, cenZ = 0.0; boolean contains = false; boolean inside; boolean intersect = false; double smallest_distance = Double.MAX_VALUE; int i,j,index=0; for(i = 0; i < boundsObjects.length; i++){ if( boundsObjects[i] == null ) ; else if( this.intersect( boundsObjects[i])) { intersect = true; if( boundsObjects[i].boundId == BOUNDING_BOX){ BoundingBox box = (BoundingBox)boundsObjects[i]; cenX = (box.upper.x+box.lower.x)/2.0; cenY = (box.upper.y+box.lower.y)/2.0; cenZ = (box.upper.z+box.lower.z)/2.0; dis = Math.sqrt( (centroid.x-cenX)*(centroid.x-cenX) + (centroid.y-cenY)*(centroid.y-cenY) + (centroid.z-cenZ)*(centroid.z-cenZ) ); inside = false; if( lower.x <= box.lower.x && lower.y <= box.lower.y && lower.z <= box.lower.z && upper.x >= box.upper.x && upper.y >= box.upper.y && upper.z >= box.upper.z ) { // box is contained inside = true; } if( inside ) { if( !contains ){ // initialize smallest_distance for the first containment index = i; smallest_distance = dis; contains = true; } else{ if( dis < smallest_distance){ index = i; smallest_distance = dis; } } } else if (!contains) { if( dis < smallest_distance){ index = i; smallest_distance = dis; } } } else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { BoundingSphere sphere = (BoundingSphere)boundsObjects[i]; dis = Math.sqrt( (centroid.x-sphere.center.x)* (centroid.x-sphere.center.x) + (centroid.y-sphere.center.y)* (centroid.y-sphere.center.y) + (centroid.z-sphere.center.z)* (centroid.z-sphere.center.z) ); inside = false; // sphere sphere.center is inside box if(sphere.center.x <= upper.x && sphere.center.x >= lower.x && sphere.center.y <= upper.y && sphere.center.y >= lower.y && sphere.center.z <= upper.z && sphere.center.z >= lower.z ) { // check if sphere intersects any side if (sphere.center.x - lower.x >= sphere.radius && upper.x - sphere.center.x >= sphere.radius && sphere.center.y - lower.y >= sphere.radius && upper.y - sphere.center.y >= sphere.radius && sphere.center.z - lower.z >= sphere.radius && upper.z - sphere.center.z >= sphere.radius ) { // contains the sphere inside = true; } } if (inside ) { // initialize smallest_distance for the first containment if( !contains ){ index = i; smallest_distance = dis; contains = true; } else{ if( dis < smallest_distance){ index = i; smallest_distance = dis; } } } else if (!contains) { if( dis < smallest_distance){ index = i; smallest_distance = dis; } } } else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; dis = Math.sqrt( (centroid.x-polytope.centroid.x)* (centroid.x-polytope.centroid.x) + (centroid.y-polytope.centroid.y)* (centroid.y-polytope.centroid.y) + (centroid.z-polytope.centroid.z)* (centroid.z-polytope.centroid.z) ); inside = true; for(j=0;j upper.x || polytope.verts[j].y > upper.y || polytope.verts[j].z > upper.z ) { // box contains polytope inside = false; } } if( inside ) { if( !contains ){ // initialize smallest_distance for the first containment index = i; smallest_distance = dis; contains = true; } else{ if( dis < smallest_distance){ index = i; smallest_distance = dis; } } } else if (!contains) { if( dis < smallest_distance){ index = i; smallest_distance = dis; } } } else { throw new IllegalArgumentException(J3dI18N.getString("BoundingBox9")); } } } if ( intersect ) return boundsObjects[index]; else return null; } /** * Tests for intersection of box and frustum. * @param frustum * @return true if they intersect */ boolean intersect(CachedFrustum frustum ) { if (boundsIsEmpty) return false; if(boundsIsInfinite) return true; // System.err.println("intersect frustum with box="+this.toString()); // System.err.println("frustum "+frustum.toString()); // check if box and bounding box of frustum intersect if ((upper.x < frustum.lower.x) || (lower.x > frustum.upper.x) || (upper.y < frustum.lower.y) || (lower.y > frustum.upper.y) || (upper.z < frustum.lower.z) || (lower.z > frustum.upper.z) ) { // System.err.println("*** box and bounding box of frustum do not intersect"); return false; } // check if all box points out any frustum plane int i = 5; while (i>=0){ Vector4d vc = frustum.clipPlanes[i--]; if ((( upper.x*vc.x + upper.y*vc.y + upper.z*vc.z + vc.w ) < 0.0 ) && (( upper.x*vc.x + lower.y*vc.y + upper.z*vc.z + vc.w ) < 0.0 ) && (( upper.x*vc.x + lower.y*vc.y + lower.z*vc.z + vc.w ) < 0.0 ) && (( upper.x*vc.x + upper.y*vc.y + lower.z*vc.z + vc.w ) < 0.0 ) && (( lower.x*vc.x + upper.y*vc.y + upper.z*vc.z + vc.w ) < 0.0 ) && (( lower.x*vc.x + lower.y*vc.y + upper.z*vc.z + vc.w ) < 0.0 ) && (( lower.x*vc.x + lower.y*vc.y + lower.z*vc.z + vc.w ) < 0.0 ) && (( lower.x*vc.x + upper.y*vc.y + lower.z*vc.z + vc.w ) < 0.0 )) { // all corners outside this frustum plane // System.err.println("*** all corners outside this frustum plane"); return false; } } return true; } /** * Returns a string representation of this class. */ @Override public String toString() { return new String( "Bounding box: Lower="+lower.x+" "+ lower.y+" "+lower.z+" Upper="+upper.x+" "+ upper.y+" "+upper.z ); } private void setEmptyBounds() { lower.set( 1.0d, 1.0d, 1.0d); upper.set(-1.0d, -1.0d, -1.0d); boundsIsInfinite = false; boundsIsEmpty = true; } private void setInfiniteBounds() { lower.set(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY); upper.set(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); boundsIsInfinite = true; boundsIsEmpty = false; } private void updateBoundsStates() { if((lower.x == Double.NEGATIVE_INFINITY) && (lower.y == Double.NEGATIVE_INFINITY) && (lower.z == Double.NEGATIVE_INFINITY) && (upper.x == Double.POSITIVE_INFINITY) && (upper.y == Double.POSITIVE_INFINITY) && (upper.z == Double.POSITIVE_INFINITY)) { boundsIsEmpty = false; boundsIsInfinite = true; return; } if (Double.isNaN(lower.x + lower.y + lower.z + upper.x + upper.y + upper.z)) { boundsIsEmpty = true; boundsIsInfinite = false; return; } else { boundsIsInfinite = false; if( lower.x > upper.x || lower.y > upper.y || lower.z > upper.z ) { boundsIsEmpty = true; } else { boundsIsEmpty = false; } } } // For a infinite bounds. What is the centroid ? @Override Point3d getCenter() { Point3d cent = new Point3d(); cent.add(upper, lower); cent.scale(0.5d); return cent; } @Override public void getCenter(Point3d center) { center.add(lower, upper); center.scale(0.5d); } void translate(BoundingBox bbox, Vector3d value) { if (bbox == null || bbox.boundsIsEmpty) { setEmptyBounds(); return; } if (bbox.boundsIsInfinite) { setInfiniteBounds(); return; } lower.x = bbox.lower.x + value.x; lower.y = bbox.lower.y + value.y; lower.z = bbox.lower.z + value.z; upper.x = bbox.upper.x + value.x; upper.y = bbox.upper.y + value.y; upper.z = bbox.upper.z + value.z; } /** * if the passed the "region" is same type as this object * then do a copy, otherwise clone the Bounds and * return */ @Override Bounds copy(Bounds r) { if (r != null && this.boundId == r.boundId) { BoundingBox region = (BoundingBox) r; region.lower.x = lower.x; region.lower.y = lower.y; region.lower.z = lower.z; region.upper.x = upper.x; region.upper.y = upper.y; region.upper.z = upper.z; region.boundsIsEmpty = boundsIsEmpty; region.boundsIsInfinite = boundsIsInfinite; return region; } else { return (Bounds) this.clone(); } } @Override int getPickType() { return PickShape.PICKBOUNDINGBOX; } }