diff options
Diffstat (limited to 'src/javax/media/j3d/BoundingBox.java')
-rw-r--r-- | src/javax/media/j3d/BoundingBox.java | 1904 |
1 files changed, 1904 insertions, 0 deletions
diff --git a/src/javax/media/j3d/BoundingBox.java b/src/javax/media/j3d/BoundingBox.java new file mode 100644 index 0000000..304e43b --- /dev/null +++ b/src/javax/media/j3d/BoundingBox.java @@ -0,0 +1,1904 @@ +/* + * 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<polytope.nVerts;i++) { + if( polytope.verts[i].x < lower.x ) + lower.x = polytope.verts[i].x; + if( polytope.verts[i].y < lower.y ) + lower.y = polytope.verts[i].y; + if( polytope.verts[i].z < lower.z ) + lower.z = polytope.verts[i].z; + if( polytope.verts[i].x > 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<bounds.length;i++) { + if( bounds[i] == null ); // do nothing + else if( bounds[i].boundsIsEmpty); // do nothing + else if( bounds[i].boundsIsInfinite ) { + setInfiniteBounds(); + return; // We're done. + } + else if(bounds[i].boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)bounds[i]; + + 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(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<polytope.nVerts;i++) { // XXXX: handle polytope with no verts + if( polytope.verts[i].x < lower.x ) + lower.x = polytope.verts[i].x; + if( polytope.verts[i].y < lower.y ) + lower.y = polytope.verts[i].y; + if( polytope.verts[i].z < lower.z ) + lower.z = polytope.verts[i].z; + if( polytope.verts[i].x > 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<polytope.nVerts;i++) { + if( polytope.verts[i].x < lower.x ) lower.x = polytope.verts[i].x; + if( polytope.verts[i].y < lower.y ) lower.y = polytope.verts[i].y; + if( polytope.verts[i].z < lower.z ) lower.z = polytope.verts[i].z; + if( polytope.verts[i].x > 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 <code>bounds</code> object is + * equal to this BoundingBox object. They are equal if the + * specified <code>bounds</code> object is an instance of + * BoundingBox and all of the data + * members of <code>bounds</code> 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 <code>bounds</code>; + * 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<polytope.nVerts;i++) { + if( polytope.verts[i].x < lower.x ) lower.x = polytope.verts[i].x; + if( polytope.verts[i].y < lower.y ) lower.y = polytope.verts[i].y; + if( polytope.verts[i].z < lower.z ) lower.z = polytope.verts[i].z; + if( polytope.verts[i].x > 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) && ((bounds[i]==null) || bounds[i].boundsIsEmpty)) { + i++; + } + if( 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<bounds.length;i++) { + if( bounds[i] == null ); // do nothing + else if( bounds[i].boundsIsEmpty); // do nothing + else if( bounds[i].boundsIsInfinite ) { + lower.x = lower.y = lower.z = Double.NEGATIVE_INFINITY; + upper.x = upper.y = upper.z = Double.POSITIVE_INFINITY; + break; // We're done. + } + else if( bounds[i].boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)bounds[i]; + + 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( 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<polytope.nVerts;i++) { + if( polytope.verts[i].x < lower.x ) lower.x = polytope.verts[i].x; + if( polytope.verts[i].y < lower.y ) lower.y = polytope.verts[i].y; + if( polytope.verts[i].z < lower.z ) lower.z = polytope.verts[i].z; + if( polytope.verts[i].x > 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<points.length;i++) { + if( points[i].x > 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 <i>not</i> 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<boundsObjects.length;i++) { + if( boundsObjects[i] == null || boundsObjects[i].boundsIsEmpty) ; + 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 ){ + + 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<polytope.nVerts;j++) { + if( polytope.verts[j].x < lower.x || + polytope.verts[j].y < lower.y || + polytope.verts[j].z < lower.z || + polytope.verts[j].x > 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; + } +} + |