/* * $RCSfile: BoundingBox.java,v $ * * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * * Use is subject to license terms. * * $Revision: 1.8 $ * $Date: 2007/04/12 17:34:04 $ * $State: Exp $ */ package org.jcae.geometry; import javax.vecmath.*; /** * 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. */ Point3d lower; /** * The corner of the bounding box with the numerically largest * values. */ Point3d upper; private Point3d centroid; private static final double EPS = 1.0E-8; // reusable temp objects private BoundingSphere tmpSphere; private BoundingBox tmpBox; private BoundingPolytope tmpPolytope; private final Point3d tmpP3d = new Point3d(); /** * 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 opper 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); updateBoundsStates(); } /** * Constructs a BoundingBox from a bounding object. * @param boundsObject a bounds object */ public BoundingBox(Bounds boundsObject) { int i; boundId = BOUNDING_BOX; if( boundsObject == null ) { // Negative volume. lower = new Point3d( 1.0d, 1.0d, 1.0d); upper = new Point3d(-1.0d, -1.0d, -1.0d); } else if( boundsObject.boundsIsInfinite ) { lower = new Point3d( Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY); upper = new Point3d(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); } else if( boundsObject.boundId == BOUNDING_BOX){ BoundingBox box = (BoundingBox)boundsObject; lower = new Point3d(box.lower.x, box.lower.y, box.lower.z); upper = new Point3d(box.upper.x, box.upper.y, box.upper.z); } else if( boundsObject.boundId == BOUNDING_SPHERE ) { BoundingSphere sphere = (BoundingSphere)boundsObject; lower = new Point3d(sphere.center.x-sphere.radius, sphere.center.y-sphere.radius, sphere.center.z-sphere.radius); upper = new Point3d(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 = new Point3d(-1.0d, -1.0d, -1.0d); upper = new Point3d( 1.0d, 1.0d, 1.0d); } else { lower = new Point3d( polytope.verts[0].x, polytope.verts[0].y, polytope.verts[0].z); upper = new Point3d( polytope.verts[0].x, polytope.verts[0].y, 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("BoundingBox0"); } updateBoundsStates(); } /** * Constructs a BoundingBox from an array of bounding objects. * @param bounds an array of bounding objects */ public BoundingBox(Bounds[] bounds) { int i=0; upper = new Point3d(); lower = new Point3d(); boundId = BOUNDING_BOX; if( bounds == null || bounds.length <= 0 ) { // Negative volume. lower = new Point3d( 1.0d, 1.0d, 1.0d); upper = new Point3d(-1.0d, -1.0d, -1.0d); updateBoundsStates(); return; } // find first non empty bounds object while( bounds[i] == null && i < bounds.length) { i++; } if( i >= bounds.length ) { // all bounds objects were empty // Negative volume. lower = new Point3d( 1.0d, 1.0d, 1.0d); upper = new Point3d(-1.0d, -1.0d, -1.0d); updateBoundsStates(); 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 ) { 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=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("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.x = lower.x; p1.y = lower.y; p1.z = lower.z; } /** * Sets the lower corner of this bounding box. * @param xmin minimum x value of boundining box * @param ymin minimum y value of boundining box * @param zmin minimum z value of boundining box */ public void setLower(double xmin, double ymin, double zmin ) { lower.x = xmin; lower.y = ymin; lower.z = 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.x = p1.x; lower.y = p1.y; lower.z = p1.z; 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.x = upper.x; p1.y = upper.y; p1.z = upper.z; } /** * Sets the upper corner of this bounding box. * @param xmax max x value of boundining box * @param ymax max y value of boundining box * @param zmax max z value of boundining box */ public void setUpper(double xmax, double ymax, double zmax ) { upper.x = xmax; upper.y = ymax; upper.z = 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.x = p1.x; upper.y = p1.y; upper.z = p1.z; 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)) { // Negative volume. lower.x = lower.y = lower.z = 1.0d; upper.x = upper.y = upper.z = -1.0d; } else if( boundsObject.boundsIsInfinite ) { lower.x = lower.y = lower.z = Double.NEGATIVE_INFINITY; upper.x = upper.y = upper.z = Double.POSITIVE_INFINITY; } else 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("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 */ 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 */ public int hashCode() { long bits = 1L; bits = 31L * bits + HashCodeUtil.doubleToLongBits(lower.x); bits = 31L * bits + HashCodeUtil.doubleToLongBits(lower.y); bits = 31L * bits + HashCodeUtil.doubleToLongBits(lower.z); bits = 31L * bits + HashCodeUtil.doubleToLongBits(upper.x); bits = 31L * bits + HashCodeUtil.doubleToLongBits(upper.y); bits = 31L * bits + HashCodeUtil.doubleToLongBits(upper.z); return (int) (bits ^ (bits >> 32)); } /** * 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("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("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) { // Negative volume. lower.x = lower.y = lower.z = 1.0d; upper.x = upper.y = upper.z = -1.0d; updateBoundsStates(); return; } if(boundsObject.boundsIsInfinite) { lower.x = lower.y = lower.z = Double.NEGATIVE_INFINITY; upper.x = upper.y = upper.z = Double.POSITIVE_INFINITY; updateBoundsStates(); return; } if(boundsObject.boundId == BOUNDING_BOX){ if (tmpBox == null) { tmpBox = new BoundingBox( (BoundingBox)boundsObject); } else { tmpBox.set((BoundingBox)boundsObject); } tmpBox.transform(matrix); this.set(tmpBox); } else if(boundsObject.boundId == BOUNDING_SPHERE) { if (tmpSphere == null) { tmpSphere = new BoundingSphere( (BoundingSphere)boundsObject); } else { tmpSphere.set((BoundingSphere)boundsObject); } tmpSphere.transform(matrix); this.set(tmpSphere); } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { if (tmpPolytope == null) { tmpPolytope = new BoundingPolytope((BoundingPolytope) boundsObject); } else { tmpPolytope.set((BoundingPolytope)boundsObject); } tmpPolytope.transform(matrix); this.set(tmpPolytope); } else { throw new IllegalArgumentException("BoundingBox5"); } } /** * Transforms this bounding box by the given matrix. * @param matrix a transformation matrix */ @Override public void transform(Transform3D matrix) { if(boundsIsInfinite) return; 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 public 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. */ public 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("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) { double distsq, radsq; 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 ) { // Negative volume. newBoundBox.setLower( 1.0d, 1.0d, 1.0d); newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); 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.setLower( 1.0d, 1.0d, 1.0d); newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); 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.setLower( 1.0d, 1.0d, 1.0d); newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); 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.setLower( 1.0d, 1.0d, 1.0d); newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); return false; } } else { throw new IllegalArgumentException("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.setLower( 1.0d, 1.0d, 1.0d); newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); 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.setLower( 1.0d, 1.0d, 1.0d); newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); 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("BoundingBox6"); } if(newBoundBox.boundsIsInfinite) break; // We're done. } if( status == false ) { // Negative volume. newBoundBox.setLower( 1.0d, 1.0d, 1.0d); newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); } 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; } getCenter(); double dis,far_dis,pdist,x,y,z,rad_sq; 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("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. */ public String toString() { return new String( "Bounding box: Lower="+lower.x+" "+ lower.y+" "+lower.z+" Upper="+upper.x+" "+ upper.y+" "+upper.z ); } 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 (checkBoundsIsNaN()) { 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() { if(centroid == null) { centroid = new Point3d(); } centroid.x = (upper.x+lower.x)*0.5; centroid.y = (upper.y+lower.y)*0.5; centroid.z = (upper.z+lower.z)*0.5; return centroid; } void translate(BoundingBox bbox, Vector3d value) { if (bbox == null || bbox.boundsIsEmpty) { // Negative volume. setLower( 1.0d, 1.0d, 1.0d); setUpper(-1.0d, -1.0d, -1.0d); return; } if(bbox.boundsIsInfinite) { this.set(bbox); 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(); } } // Check is any of the bounds is a NaN, if yes, then // set it an empty bounds boolean checkBoundsIsNaN() { if (Double.isNaN(lower.x+lower.y+lower.z+upper.x+upper.y+upper.z)) { return true; } return false; } }