diff options
Diffstat (limited to 'src/javax/media/j3d/BoundingPolytope.java')
-rw-r--r-- | src/javax/media/j3d/BoundingPolytope.java | 1783 |
1 files changed, 1783 insertions, 0 deletions
diff --git a/src/javax/media/j3d/BoundingPolytope.java b/src/javax/media/j3d/BoundingPolytope.java new file mode 100644 index 0000000..37d47c0 --- /dev/null +++ b/src/javax/media/j3d/BoundingPolytope.java @@ -0,0 +1,1783 @@ +/* + * Copyright 1997-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; + +/** + * A BoundingPolytope defines a polyhedral bounding region using the + * intersection of four or more half spaces. The region defined by a + * BoundingPolytope is always convex and must be closed. + * <p> + * Each plane in the BoundingPolytope specifies a half-space defined + * by the equation: + * <ul> + * Ax + By + Cz + D <= 0 + * </ul> + * where A, B, C, D are the parameters that specify the plane. The + * parameters are passed in the x, y, z, and w fields, respectively, + * of a Vector4d object. The intersection of the set of half-spaces + * corresponding to the planes in this BoundingPolytope defines the + * bounding region. + */ + +public class BoundingPolytope extends Bounds { + + /** + * An array of bounding planes. + */ + Vector4d[] planes; + double[] mag; // magnitude of plane vector + double[] pDotN; // point on plane dotted with normal + Point3d[] verts; // vertices of polytope + int nVerts; // number of verts in polytope + Point3d centroid = new Point3d(); // centroid of polytope + + Point3d boxVerts[]; + boolean allocBoxVerts = false; + + /** + * Constructs a BoundingPolytope using the specified planes. + * @param planes a set of planes defining the polytope. + * @exception IllegalArgumentException if the length of the + * specified array of planes is less than 4. + */ + public BoundingPolytope(Vector4d[] planes) { + if (planes.length < 4) { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope11")); + } + + boundId = BOUNDING_POLYTOPE; + int i; + double invMag; + this.planes = new Vector4d[planes.length]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + + for(i=0;i<planes.length;i++) { + + // normalize the plane normals + mag[i] = Math.sqrt(planes[i].x*planes[i].x + planes[i].y*planes[i].y + + planes[i].z*planes[i].z); + invMag = 1.0/mag[i]; + this.planes[i] = new Vector4d( planes[i].x*invMag, planes[i].y*invMag, + planes[i].z*invMag, planes[i].w*invMag ); + + } + computeAllVerts(); // XXXX: lazy evaluate + } + + /** + * Constructs a BoundingPolytope and initializes it to a set of 6 + * planes that defines a cube such that -1 <= x,y,z <= 1. The + * values of the planes are as follows: + * <ul> + * planes[0] : x <= 1 (1,0,0,-1)<br> + * planes[1] : -x <= 1 (-1,0,0,-1)<br> + * planes[2] : y <= 1 (0,1,0,-1)<br> + * planes[3] : -y <= 1 (0,-1,0,-1)<br> + * planes[4] : z <= 1 (0,0,1,-1)<br> + * planes[5] : -z <= 1 (0,0,-1,-1)<br> + * </ul> + */ + public BoundingPolytope() { + boundId = BOUNDING_POLYTOPE; + planes = new Vector4d[6]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -1.0 ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, -1.0 ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -1.0 ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, -1.0 ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -1.0 ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, -1.0 ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + + computeAllVerts(); // XXXX: lazy evaluate + } + + + /** + * Constructs a BoundingPolytope from the specified bounds object. + * The new polytope will circumscribe the region specified by the + * input bounds. + * @param boundsObject the bounds object from which this polytope + * is constructed. + */ + public BoundingPolytope(Bounds boundsObject ) { + int i; + + boundId = BOUNDING_POLYTOPE; + + if( boundsObject == null ) { + boundsIsEmpty = true; + boundsIsInfinite = false; + initEmptyPolytope(); + computeAllVerts(); // XXXX: lazy evaluate + return; + } + + boundsIsEmpty = boundsObject.boundsIsEmpty; + boundsIsInfinite = boundsObject.boundsIsInfinite; + + if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + planes = new Vector4d[6]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -(sphere.center.x+sphere.radius) ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, sphere.center.x-sphere.radius ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -(sphere.center.y+sphere.radius) ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, sphere.center.y-sphere.radius ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -(sphere.center.z+sphere.radius) ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, sphere.center.z-sphere.radius ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + computeAllVerts(); // XXXX: lazy evaluate + + } else if( boundsObject.boundId == BOUNDING_BOX ){ + BoundingBox box = (BoundingBox)boundsObject; + planes = new Vector4d[6]; + pDotN = new double[planes.length]; + mag = new double[planes.length]; + + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -box.upper.x ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, box.lower.x ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -box.upper.y ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, box.lower.y ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -box.upper.z ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, box.lower.z ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + computeAllVerts(); // XXXX: lazy evaluate + + } else if( boundsObject.boundId == BOUNDING_POLYTOPE ) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + planes = new Vector4d[polytope.planes.length]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + nVerts = polytope.nVerts; + verts = new Point3d[nVerts]; + for(i=0;i<planes.length;i++) { + planes[i] = new Vector4d(polytope.planes[i]); + mag[i] = polytope.mag[i]; + pDotN[i] = polytope.pDotN[i]; + } + for(i=0;i<verts.length;i++) { + verts[i] = new Point3d(polytope.verts[i]); + } + centroid = polytope.centroid; + + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope0")); + } + } + + /** + * Constructs a BoundingPolytope from the specified array of bounds + * objects. The new polytope will circumscribe the union of the + * regions specified by the input bounds objects. + * @param boundsObjects the array bounds objects from which this + * polytope is constructed. + */ + public BoundingPolytope(Bounds[] boundsObjects) { + int i=0; + + boundId = BOUNDING_POLYTOPE; + if( boundsObjects == null || boundsObjects.length <= 0 ) { + boundsIsEmpty = true; + boundsIsInfinite = false; + initEmptyPolytope(); + computeAllVerts(); // XXXX: lazy evaluate + return; + } + // find first non empty bounds object + while( boundsObjects[i] == null && i < boundsObjects.length) { + i++; + } + + if( i >= boundsObjects.length ) { // all bounds objects were empty + boundsIsEmpty = true; + boundsIsInfinite = false; + initEmptyPolytope(); + computeAllVerts(); // XXXX: lazy evaluate + return; + } + + boundsIsEmpty = boundsObjects[i].boundsIsEmpty; + boundsIsInfinite = boundsObjects[i].boundsIsInfinite; + + if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObjects[i]; + planes = new Vector4d[6]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -(sphere.center.x+sphere.radius) ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, sphere.center.x-sphere.radius ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -(sphere.center.y+sphere.radius) ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, sphere.center.y-sphere.radius ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -(sphere.center.z+sphere.radius) ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, sphere.center.z-sphere.radius ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + + computeAllVerts(); // XXXX: lazy evaluate + } else if( boundsObjects[i].boundId == BOUNDING_BOX ){ + BoundingBox box = (BoundingBox)boundsObjects[i]; + planes = new Vector4d[6]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -box.upper.x ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, box.lower.x ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -box.upper.y ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, box.lower.y ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -box.upper.z ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, box.lower.z ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + + computeAllVerts(); // XXXX: lazy evaluate + } else if( boundsObjects[i].boundId == BOUNDING_POLYTOPE ) { + BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; + planes = new Vector4d[polytope.planes.length]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + nVerts = polytope.nVerts; + verts = new Point3d[nVerts]; + for(i=0;i<planes.length;i++) { + planes[i] = new Vector4d(polytope.planes[i]); + pDotN[i] = polytope.pDotN[i]; + mag[i] = polytope.mag[i]; + } + for(i=0;i<verts.length;i++) { + verts[i] = new Point3d(polytope.verts[i]); + } + centroid = polytope.centroid; + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope1")); + } + for(i+=1;i<boundsObjects.length;i++) { + this.combine(boundsObjects[i]); + } + } + + /** + * Sets the bounding planes for this polytope. + * @param planes the new set of planes for this polytope + * @exception IllegalArgumentException if the length of the + * specified array of planes is less than 4. + */ + public void setPlanes(Vector4d[] planes) { + if (planes.length < 4) { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope11")); + } + + int i; + double invMag; + + this.planes = new Vector4d[planes.length]; + pDotN = new double[planes.length]; + mag = new double[planes.length]; + boundsIsEmpty = false; + + if( planes.length <= 0 ) { + boundsIsEmpty = true; + boundsIsInfinite = false; + computeAllVerts(); // XXXX: lazy evaluate + return; + } + + for(i=0;i<planes.length;i++) { + // normalize the plane normals + mag[i] = Math.sqrt(planes[i].x*planes[i].x + planes[i].y*planes[i].y + + planes[i].z*planes[i].z); + invMag = 1.0/mag[i]; + this.planes[i] = new Vector4d( planes[i].x*invMag, planes[i].y*invMag, + planes[i].z*invMag, planes[i].w*invMag ); + } + computeAllVerts(); // XXXX: lazy evaluate + + } + + /** + * Returns the equations of the bounding planes for this bounding polytope. + * The equations are copied into the specified array. + * The array must be large enough to hold all of the vectors. + * The individual array elements must be allocated by the caller. + * @param planes an array Vector4d to receive the bounding planes + */ + public void getPlanes(Vector4d[] planes) + { + int i; + + for(i=0;i<planes.length;i++) { + planes[i].x = this.planes[i].x*mag[i]; + planes[i].y = this.planes[i].y*mag[i]; + planes[i].z = this.planes[i].z*mag[i]; + planes[i].w = this.planes[i].w*mag[i]; + } + } + + public int getNumPlanes() { + return planes.length; + } + + /** + * Sets the planes for this BoundingPolytope by keeping its current + * number and position of planes and computing new planes positions + * to enclose the given bounds object. + * @param boundsObject another bounds object + */ + @Override + public void set(Bounds boundsObject) { + int i,k; + + // no polytope exists yet so initialize one using the boundsObject + if( boundsObject == null ) { + boundsIsEmpty = true; + boundsIsInfinite = false; + computeAllVerts(); // XXXX: lazy evaluate + + }else if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + + if( boundsIsEmpty) { + initEmptyPolytope(); // no ptope exist so must initialize to default + computeAllVerts(); + } + + for(i=0;i<planes.length;i++) { // D = -(N dot C + radius) + planes[i].w = -(sphere.center.x*planes[i].x + + sphere.center.y*planes[i].y + + sphere.center.z*planes[i].z + sphere.radius); + } + + boundsIsEmpty = boundsObject.boundsIsEmpty; + boundsIsInfinite = boundsObject.boundsIsInfinite; + computeAllVerts(); // XXXX: lazy evaluate + + } else if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObject; + double ux,uy,uz,lx,ly,lz,newD; + + if( boundsIsEmpty) { + initEmptyPolytope(); // no ptope exist so must initialize to default + computeAllVerts(); + } + + for(i=0;i<planes.length;i++) { + ux = box.upper.x*planes[i].x; + uy = box.upper.y*planes[i].y; + uz = box.upper.z*planes[i].z; + lx = box.lower.x*planes[i].x; + ly = box.lower.y*planes[i].y; + lz = box.lower.z*planes[i].z; + planes[i].w = -(ux + uy + uz ); // initalize plane to upper vert + if( (newD = ux + uy + lz ) + planes[i].w > 0.0) planes[i].w = -newD; + if( (newD = ux + ly + uz ) + planes[i].w > 0.0) planes[i].w = -newD; + if( (newD = ux + ly + lz ) + planes[i].w > 0.0) planes[i].w = -newD; + + if( (newD = lx + uy + uz ) + planes[i].w > 0.0) planes[i].w = -newD; + if( (newD = lx + uy + lz ) + planes[i].w > 0.0) planes[i].w = -newD; + if( (newD = lx + ly + uz ) + planes[i].w > 0.0) planes[i].w = -newD; + if( (newD = lx + ly + lz ) + planes[i].w > 0.0) planes[i].w = -newD; + } + + boundsIsEmpty = boundsObject.boundsIsEmpty; + boundsIsInfinite = boundsObject.boundsIsInfinite; + computeAllVerts(); // XXXX: lazy evaluate + + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + if( planes.length != polytope.planes.length) { + planes = new Vector4d[polytope.planes.length]; + for(k=0;k<polytope.planes.length;k++) planes[k] = new Vector4d(); + mag = new double[polytope.planes.length]; + pDotN = new double[polytope.planes.length]; + } + + + for(i=0;i<polytope.planes.length;i++) { + planes[i].x = polytope.planes[i].x; + planes[i].y = polytope.planes[i].y; + planes[i].z = polytope.planes[i].z; + planes[i].w = polytope.planes[i].w; + mag[i] = polytope.mag[i]; + } + nVerts = polytope.nVerts; + verts = new Point3d[nVerts]; + for (k=0; k<nVerts; k++) { + verts[k] = new Point3d(polytope.verts[k]); + } + + boundsIsEmpty = boundsObject.boundsIsEmpty; + boundsIsInfinite = boundsObject.boundsIsInfinite; + + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope2")); + } + + } + + + /** + * Creates a copy of a polytope. + * @return a new BoundingPolytope + */ + @Override + public Object clone() { + return new BoundingPolytope(planes); + } + + + /** + * Indicates whether the specified <code>bounds</code> object is + * equal to this BoundingPolytope object. They are equal if the + * specified <code>bounds</code> object is an instance of + * BoundingPolytope and all of the data + * members of <code>bounds</code> are equal to the corresponding + * data members in this BoundingPolytope. + * @param bounds the object with which the comparison is made. + * @return true if this BoundingPolytope is equal to <code>bounds</code>; + * otherwise false + * + * @since Java 3D 1.2 + */ + @Override + public boolean equals(Object bounds) { + try { + BoundingPolytope polytope = (BoundingPolytope)bounds; + if (planes.length != polytope.planes.length) + return false; + for (int i = 0; i < planes.length; i++) + if (!planes[i].equals(polytope.planes[i])) + return false; + + return true; + } + catch (NullPointerException e) { + return false; + } + catch (ClassCastException e) { + return false; + } + } + + + /** + * Returns a hash code value for this BoundingPolytope object + * based on the data values in this object. Two different + * BoundingPolytope objects with identical data values (i.e., + * BoundingPolytope.equals returns true) will return the same hash + * code value. Two BoundingPolytope objects with different data + * members may return the same hash code value, although this is + * not likely. + * @return a hash code value for this BoundingPolytope object. + * + * @since Java 3D 1.2 + */ + @Override + public int hashCode() { + long bits = 1L; + + for (int i = 0; i < planes.length; i++) { + bits = J3dHash.mixDoubleBits(bits, planes[i].x); + bits = J3dHash.mixDoubleBits(bits, planes[i].y); + bits = J3dHash.mixDoubleBits(bits, planes[i].z); + bits = J3dHash.mixDoubleBits(bits, planes[i].w); + } + + return J3dHash.finish(bits); + } + + + /** + * Combines this bounding polytope with a bounding object so that the + * resulting bounding polytope encloses the original bounding polytope and the + * given bounds object. + * @param boundsObject another bounds object + */ + @Override + public void combine(Bounds boundsObject) { + BoundingSphere sphere; + + if((boundsObject == null) || (boundsObject.boundsIsEmpty) + || (boundsIsInfinite)) + return; + + + if((boundsIsEmpty) || (boundsObject.boundsIsInfinite)) { + this.set(boundsObject); + return; + } + + boundsIsEmpty = boundsObject.boundsIsEmpty; + boundsIsInfinite = boundsObject.boundsIsInfinite; + + if( boundsObject.boundId == BOUNDING_SPHERE ) { + sphere = (BoundingSphere)boundsObject; + int i; + double dis; + for(i = 0; i < planes.length; i++){ + dis = sphere.radius+ sphere.center.x*planes[i].x + + sphere.center.y*planes[i].y + sphere.center.z * + planes[i].z + planes[i].w; + if( dis > 0.0 ) { + planes[i].w += -dis; + } + } + } else if( boundsObject instanceof BoundingBox){ + BoundingBox b = (BoundingBox)boundsObject; + if( !allocBoxVerts){ + boxVerts = new Point3d[8]; + for(int j=0;j<8;j++)boxVerts[j] = new Point3d(); + allocBoxVerts = true; + } + boxVerts[0].set(b.lower.x, b.lower.y, b.lower.z ); + boxVerts[1].set(b.lower.x, b.upper.y, b.lower.z ); + boxVerts[2].set(b.upper.x, b.lower.y, b.lower.z ); + boxVerts[3].set(b.upper.x, b.upper.y, b.lower.z ); + boxVerts[4].set(b.lower.x, b.lower.y, b.upper.z ); + boxVerts[5].set(b.lower.x, b.upper.y, b.upper.z ); + boxVerts[6].set(b.upper.x, b.lower.y, b.upper.z ); + boxVerts[7].set(b.upper.x, b.upper.y, b.upper.z ); + this.combine(boxVerts); + + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + this.combine(polytope.verts); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope3")); + } + + computeAllVerts(); + } + + /** + * Combines this bounding polytope with an array of bounding objects so that the + * resulting bounding polytope encloses the original bounding polytope and the + * given array of bounds object. + * @param boundsObjects an array of bounds objects + */ + @Override + public void combine(Bounds[] boundsObjects) { + int i=0; + double dis; + + if( (boundsObjects == null) || (boundsObjects.length <= 0) + || (boundsIsInfinite)) + return; + + // find first non empty bounds object + while( (i<boundsObjects.length) && ((boundsObjects[i]==null) + || boundsObjects[i].boundsIsEmpty)) { + i++; + } + if( i >= boundsObjects.length) + return; // no non empty bounds so do not modify current bounds + + if(boundsIsEmpty) + this.set(boundsObjects[i++]); + + if(boundsIsInfinite) + return; + + for(;i<boundsObjects.length;i++) { + if( boundsObjects[i] == null ); // do nothing + else if( boundsObjects[i].boundsIsEmpty ); // do nothing + else if( boundsObjects[i].boundsIsInfinite ) { + this.set(boundsObjects[i]); + break; // We're done; + } + else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObjects[i]; + for(int j = 0; j < planes.length; j++){ + dis = sphere.radius+ sphere.center.x*planes[j].x + + sphere.center.y*planes[j].y + sphere.center.z* + planes[j].z + planes[j].w; + if( dis > 0.0 ) { + planes[j].w += -dis; + } + } + } else if( boundsObjects[i].boundId == BOUNDING_BOX){ + BoundingBox b = (BoundingBox)boundsObjects[i]; + if( !allocBoxVerts){ + boxVerts = new Point3d[8]; + for(int j=0;j<8;j++)boxVerts[j] = new Point3d(); + allocBoxVerts = true; + } + boxVerts[0].set(b.lower.x, b.lower.y, b.lower.z ); + boxVerts[1].set(b.lower.x, b.upper.y, b.lower.z ); + boxVerts[2].set(b.upper.x, b.lower.y, b.lower.z ); + boxVerts[3].set(b.upper.x, b.upper.y, b.lower.z ); + boxVerts[4].set(b.lower.x, b.lower.y, b.upper.z ); + boxVerts[5].set(b.lower.x, b.upper.y, b.upper.z ); + boxVerts[6].set(b.upper.x, b.lower.y, b.upper.z ); + boxVerts[7].set(b.upper.x, b.upper.y, b.upper.z ); + this.combine(boxVerts); + + } else if(boundsObjects[i] instanceof BoundingPolytope) { + BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; + this.combine(polytope.verts); + + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope4")); + } + + computeAllVerts(); + } + } + + /** + * Combines this bounding polytope with a point. + * @param point a 3d point in space + */ + @Override + public void combine(Point3d point) { + int i; + double dis; + + if(boundsIsInfinite) { + return; + } + + if( boundsIsEmpty ){ + planes = new Vector4d[6]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + nVerts = 1; + verts = new Point3d[nVerts]; + verts[0] = new Point3d( point.x, point.y, point.z); + + for(i=0;i<planes.length;i++) { + pDotN[i] = 0.0; + } + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -point.x ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, point.x ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -point.y ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, point.y ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -point.z ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, point.z ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + centroid.x = point.x; + centroid.y = point.y; + centroid.z = point.z; + boundsIsEmpty = false; + boundsIsInfinite = false; + } else { + + for(i = 0; i < planes.length; i++){ + dis = point.x*planes[i].x + point.y*planes[i].y + point.z* + planes[i].z + planes[i].w; + if( dis > 0.0 ) { + planes[i].w += -dis; + } + } + computeAllVerts(); + } + } + + /** + * Combines this bounding polytope with an array of points. + * @param points an array of 3d points in space + */ + @Override + public void combine(Point3d[] points) { + int i,j; + double dis; + + if( boundsIsInfinite) { + return; + } + + if( boundsIsEmpty ){ + planes = new Vector4d[6]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + nVerts = points.length; + verts = new Point3d[nVerts]; + verts[0] = new Point3d( points[0].x, points[0].y, points[0].z); + + for(i=0;i<planes.length;i++) { + pDotN[i] = 0.0; + } + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -points[0].x ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, points[0].x ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -points[0].y ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, points[0].y ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -points[0].z ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, points[0].z ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + centroid.x = points[0].x; + centroid.y = points[0].y; + centroid.z = points[0].z; + boundsIsEmpty = false; + boundsIsInfinite = false; + } + + for(j = 0; j < points.length; j++){ + for(i = 0; i < planes.length; i++){ + dis = points[j].x*planes[i].x + points[j].y*planes[i].y + + points[j].z*planes[i].z + planes[i].w; + if( dis > 0.0 ) { + planes[i].w += -dis; + } + } + } + + computeAllVerts(); + } + + /** + * Modifies the bounding polytope 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) { + boundsIsEmpty = true; + boundsIsInfinite = false; + computeAllVerts(); + return; + } + + if(boundsObject.boundsIsInfinite) { + this.set(boundsObject); + return; + } + + if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = new BoundingSphere(boundsObject); + sphere.transform(matrix); + this.set(sphere); + } else if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = new BoundingBox(boundsObject); + box.transform(matrix); + this.set(box); + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = new BoundingPolytope(boundsObject); + polytope.transform(matrix); + this.set(polytope); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope5")); + } + } + + /** + * Transforms this bounding polytope by the given transformation matrix. + * @param matrix a transformation matrix + */ + @Override + public void transform( Transform3D matrix) { + + if(boundsIsInfinite) + return; + + int i; + double invMag; + Transform3D invTrans = new Transform3D(matrix); + + invTrans.invert(); + invTrans.transpose(); + + for(i = 0; i < planes.length; i++){ + planes[i].x = planes[i].x * mag[i]; + planes[i].y = planes[i].y * mag[i]; + planes[i].z = planes[i].z * mag[i]; + planes[i].w = planes[i].w * mag[i]; + invTrans.transform( planes[i] ); + } + + for(i=0;i<planes.length;i++) { + + // normalize the plane normals + mag[i] = Math.sqrt(planes[i].x*planes[i].x + planes[i].y*planes[i].y + + planes[i].z*planes[i].z); + invMag = 1.0/mag[i]; + this.planes[i] = new Vector4d( planes[i].x*invMag, planes[i].y*invMag, + planes[i].z*invMag, planes[i].w*invMag ); + + } + + for (i=0; i < verts.length; i++) { + matrix.transform(verts[i]); + } + + } + + /** + * Test for intersection with a ray. + * @param origin is a the starting point of the ray + * @param direction is the direction of the ray + * @param intersectPoint is a point defining the location of the intersection + * @return true or false indicating if an intersection occured + */ + boolean intersect(Point3d origin, Vector3d direction, Point3d intersectPoint ) { + + double t,v0,vd,x,y,z,invMag; + double dx, dy, dz; + int i; + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + intersectPoint.x = origin.x; + intersectPoint.y = origin.y; + intersectPoint.z = origin.z; + return true; + } + + invMag = 1.0/Math.sqrt(direction.x*direction.x + + direction.y*direction.y + direction.z*direction.z); + dx = direction.x*invMag; + dy = direction.y*invMag; + dz = direction.z*invMag; + + // compute intersection point of ray and each plane then test if point is in polytope + for(i=0;i<planes.length;i++) { + vd = planes[i].x*dx + planes[i].y*dy + planes[i].z*dz; + v0 = -(planes[i].x*origin.x + planes[i].y*origin.y + + planes[i].z*origin.z + planes[i].w); + if(vd != 0.0) { // ray is parallel to plane + t = v0/vd; + + if( t >= 0.0) { // plane is behind origin + + x = origin.x + dx*t; // compute intersection point + y = origin.y + dy*t; + z = origin.z + dz*t; + + if( pointInPolytope(x,y,z) ) { + intersectPoint.x = x; + intersectPoint.y = y; + intersectPoint.z = z; + return true; // ray intersects a face of polytope + } + } + } + } + + return false; + } + + /** + * Test for intersection with a ray + * @param origin is a the starting point of the ray + * @param direction is the direction of the ray + * @param position is 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 t,v0,vd,x,y,z,invMag; + double dx, dy, dz; + int i; + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = origin.x; + position.y = origin.y; + position.z = origin.z; + position.w = 0.0; + return true; + } + + invMag = 1.0/Math.sqrt(direction.x*direction.x + direction.y* + direction.y + direction.z*direction.z); + dx = direction.x*invMag; + dy = direction.y*invMag; + dz = direction.z*invMag; + + for(i=0;i<planes.length;i++) { + vd = planes[i].x*dx + planes[i].y*dy + planes[i].z*dz; + v0 = -(planes[i].x*origin.x + planes[i].y*origin.y + + planes[i].z*origin.z + planes[i].w); + // System.err.println("v0="+v0+" vd="+vd); + if(vd != 0.0) { // ray is parallel to plane + t = v0/vd; + + if( t >= 0.0) { // plane is behind origin + + x = origin.x + dx*t; // compute intersection point + y = origin.y + dy*t; + z = origin.z + dz*t; + // System.err.println("t="+t+" point="+x+" "+y+" "+z); + + if( pointInPolytope(x,y,z) ) { + position.x = x; + position.y = y; + position.z = z; + position.w = t; + return true; // ray intersects a face of polytope + } + } + } + } + + return false; + + } + + /** + * Test for intersection with a point + * @param point is the pick point + * @param position is 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 ) { + int i; + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = point.x; + position.y = point.y; + position.z = point.z; + position.w = 0.0; + return true; + } + + for(i = 0; i < this.planes.length; i++){ + if(( point.x*this.planes[i].x + + point.y*this.planes[i].y + + point.z*this.planes[i].z + planes[i].w ) > 0.0 ) + return false; + + } + return true; + + } + + /** + * Test for intersection with a segment + * @param start is a point defining the start of the line segment + * @param end is a point defining the end of the line segment + * @param position is 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 t,v0,vd,x,y,z; + int i; + + //System.err.println("line segment intersect : planes.length " + planes.length); + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = start.x; + position.y = start.y; + position.z = start.z; + position.w = 0.0; + return true; + } + + Point3d direction = new Point3d(); + + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + + for(i=0;i<planes.length;i++) { + vd = planes[i].x*direction.x + planes[i].y*direction.y + + planes[i].z*direction.z; + v0 = -(planes[i].x*start.x + planes[i].y*start.y + + planes[i].z*start.z + planes[i].w); + // System.err.println("v0="+v0+" vd="+vd); + if(vd != 0.0) { // ray is parallel to plane + t = v0/vd; + + // System.err.println("t is " + t); + + if( t >= 0.0) { // plane is behind start + + x = start.x + direction.x*t; // compute intersection point + y = start.y + direction.y*t; + z = start.z + direction.z*t; + // System.err.println("t="+t+" point="+x+" "+y+" "+z); + + if( pointInPolytope(x,y,z) ) { + // if((t*t) > (end.x-start.x)*(end.x-start.x) + + // (end.y-start.y)*(end.y-start.y) + + // (end.z-start.z)*(end.z-start.z)) { + if(t <= 1.0) { + position.x = x; + position.y = y; + position.z = z; + position.w = t; + return true; // ray intersects a face of polytope + } + } + } + } + } + + return false; + + } + + /** + * 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 ) { + + // compute intersection point of ray and each plane then test if point is in polytope + + double t,v0,vd,x,y,z; + int i; + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + return true; + } + + for(i=0;i<planes.length;i++) { + vd = planes[i].x*direction.x + planes[i].y*direction.y + + planes[i].z*direction.z; + v0 = -(planes[i].x*origin.x + planes[i].y*origin.y + + planes[i].z*origin.z + planes[i].w); + if(vd != 0.0) { // ray is parallel to plane + t = v0/vd; + + if( t >= 0.0) { // plane is behind origin + + x = origin.x + direction.x*t; // compute intersection point + y = origin.y + direction.y*t; + z = origin.z + direction.z*t; + + if( pointInPolytope(x,y,z) ) { + return true; // ray intersects a face of polytope + } else { + // System.err.println("point outside polytope"); + } + } + } + } + + return false; + + } + + /** + * Tests whether the bounding polytope is empty. A bounding polytope 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 polytope + * with a volume of zero is <i>not</i> empty. + * @return true if the bounding polytope is empty; + * otherwise, it returns false + */ + @Override + public boolean isEmpty() { + // if nVerts > 0 after computeAllVerts(), that means + // there is some intersection between 3 planes. + return (boundsIsEmpty || (nVerts <= 0)); + } + + /** + * 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 ) { + + int i; + if( boundsIsEmpty ) { + return false; + } + if( boundsIsInfinite ) { + return true; + } + + for(i = 0; i < this.planes.length; i++){ + if(( point.x*this.planes[i].x + + point.y*this.planes[i].y + + point.z*this.planes[i].z + planes[i].w ) > 0.0 ) + return false; + + } + return true; + } + + + /** + * 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_SPHERE ) { + return intersect_ptope_sphere( this, (BoundingSphere)boundsObject); + } else if( boundsObject.boundId == BOUNDING_BOX){ + return intersect_ptope_abox( this, (BoundingBox)boundsObject); + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + return intersect_ptope_ptope( this, (BoundingPolytope)boundsObject); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope6")); + } + } + + /** + * Test for intersection with another bounds object. + * @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; + BoundingSphere sphere; + 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. + } + if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { + sphere = (BoundingSphere)boundsObjects[i]; + radsq = sphere.radius; + radsq *= radsq; + distsq = sphere.center.distanceSquared(sphere.center); + if (distsq < radsq) { + return true; + } + } else if(boundsObjects[i].boundId == BOUNDING_BOX){ + if( this.intersect(boundsObjects[i])) return true; + } else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + if( this.intersect(boundsObjects[i])) return true; + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope7")); + } + } + + return false; + } + /** + * Test for intersection with another bounds object. + * @param boundsObject another bounds object + * @param newBoundPolytope the new bounding polytope, which is the intersection of + * the boundsObject and this BoundingPolytope + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds boundsObject, BoundingPolytope newBoundPolytope) { + int i; + + if((boundsObject == null) || boundsIsEmpty || boundsObject.boundsIsEmpty ) { + newBoundPolytope.boundsIsEmpty = true; + newBoundPolytope.boundsIsInfinite = false; + newBoundPolytope.computeAllVerts(); + return false; + } + if(boundsIsInfinite && (!boundsObject.boundsIsInfinite)) { + newBoundPolytope.set(boundsObject); + return true; + } + else if((!boundsIsInfinite) && boundsObject.boundsIsInfinite) { + newBoundPolytope.set(this); + return true; + } + else if(boundsIsInfinite && boundsObject.boundsIsInfinite) { + newBoundPolytope.set(this); + return true; + } + + + BoundingBox tbox = new BoundingBox(); // convert sphere to box + + if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + if( this.intersect( sphere)) { + BoundingBox sbox = new BoundingBox( sphere ); // convert sphere to box + BoundingBox pbox = new BoundingBox( this ); // convert polytope to box + pbox.intersect(sbox, tbox); // insersect two boxes + newBoundPolytope.set( tbox ); + return true; + } + } else if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObject; + if( this.intersect( box)) { + BoundingBox pbox = new BoundingBox( this ); // convert polytope to box + pbox.intersect(box, tbox); // insersect two boxes + newBoundPolytope.set( tbox ); + return true; + } + + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + if( this.intersect( polytope)) { + Vector4d newPlanes[] = new Vector4d[planes.length + polytope.planes.length]; + for(i=0;i<planes.length;i++) { + newPlanes[i] = new Vector4d(planes[i]); + } + for(i=0;i<polytope.planes.length;i++) { + newPlanes[planes.length + i] = new Vector4d(polytope.planes[i]); + } + BoundingPolytope newPtope= new BoundingPolytope( newPlanes ); + + newBoundPolytope.set(newPtope); + return true; + } + + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope8")); + } + + newBoundPolytope.boundsIsEmpty = true; + newBoundPolytope.boundsIsInfinite = false; + newBoundPolytope.computeAllVerts(); + + return false; + } + + /** + * Test for intersection with an array of bounds objects. + * @param boundsObjects an array of bounds objects + * @param newBoundingPolytope the new bounding polytope, which is the intersection of + * the boundsObject and this BoundingPolytope + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds[] boundsObjects, BoundingPolytope newBoundingPolytope) { + + if( boundsObjects == null || boundsObjects.length <= 0 || boundsIsEmpty ) { + newBoundingPolytope.boundsIsEmpty = true; + newBoundingPolytope.boundsIsInfinite = false; + newBoundingPolytope.computeAllVerts(); + 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 + newBoundingPolytope.boundsIsEmpty = true; + newBoundingPolytope.boundsIsInfinite = false; + newBoundingPolytope.computeAllVerts(); + return false; + } + + boolean status = false; + BoundingBox tbox = new BoundingBox(); // convert sphere to box + + for(i=0;i<boundsObjects.length;i++) { + if( boundsObjects[i] == null || boundsObjects[i].boundsIsEmpty) ; + 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 + BoundingBox pbox = new BoundingBox( this ); // convert polytope to box + pbox.intersect(sbox, tbox); // insersect two boxes + if ( status ) { + newBoundingPolytope.combine( tbox ); + } else { + newBoundingPolytope.set( tbox ); + status = true; + } + } + } else if( boundsObjects[i].boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObjects[i]; + if( this.intersect( box) ){ + BoundingBox pbox = new BoundingBox( this ); // convert polytope to box + pbox.intersect(box,tbox); // insersect two boxes + if ( status ) { + newBoundingPolytope.combine( tbox ); + } else { + newBoundingPolytope.set( tbox ); + status = true; + } + } else { + } + + } else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; + if( this.intersect( polytope)) { + Vector4d newPlanes[] = new Vector4d[planes.length + polytope.planes.length]; + for(i=0;i<planes.length;i++) { + newPlanes[i] = new Vector4d(planes[i]); + } + for(i=0;i<polytope.planes.length;i++) { + newPlanes[planes.length + i] = new Vector4d(polytope.planes[i]); + } + BoundingPolytope newPtope= new BoundingPolytope( newPlanes ); + if ( status ) { + newBoundingPolytope.combine( newPtope ); + } else { + newBoundingPolytope.set( newPtope ); + status = true; + } + } + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope8")); + } + + if(newBoundingPolytope.boundsIsInfinite) + break; // We're done. + + } + + if( status == false ) { + newBoundingPolytope.boundsIsEmpty = true; + newBoundingPolytope.boundsIsInfinite = false; + newBoundingPolytope.computeAllVerts(); + } + return status; + + } + /** + * Finds closest bounding object that intersects this bounding polytope. + * @param boundsObjects is 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; + } + + double dis,disToPlane; + boolean contains = false; + boolean inside; + double smallest_distance = Double.MAX_VALUE; + int i,j,index=0; + double cenX = 0.0, cenY = 0.0, cenZ = 0.0; + + for(i = 0; i < boundsObjects.length; i++){ + if( boundsObjects[i] == null ); + + else if( this.intersect( boundsObjects[i])) { + if( boundsObjects[i] instanceof BoundingSphere ) { + 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 = true; + for(j=0;j<planes.length;j++) { + if( ( sphere.center.x*planes[j].x + + sphere.center.y*planes[j].y + + sphere.center.z*planes[j].z + planes[i].w ) > 0.0 ) { // check if sphere center in polytope + disToPlane = sphere.center.x*planes[j].x + + sphere.center.y*planes[j].y + + sphere.center.z*planes[j].z + planes[j].w; + + // check if distance from center to plane is larger than radius + if( disToPlane > sphere.radius ) inside = false; + } + } + if( inside) { // contains the sphere + 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] instanceof BoundingBox){ + 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 = true; + if( !pointInPolytope( box.upper.x, box.upper.y, box.upper.z ) ) inside = false; + if( !pointInPolytope( box.upper.x, box.upper.y, box.lower.z ) ) inside = false; + if( !pointInPolytope( box.upper.x, box.lower.y, box.upper.z ) ) inside = false; + if( !pointInPolytope( box.upper.x, box.lower.y, box.lower.z ) ) inside = false; + if( !pointInPolytope( box.lower.x, box.upper.y, box.upper.z ) ) inside = false; + if( !pointInPolytope( box.lower.x, box.upper.y, box.lower.z ) ) inside = false; + if( !pointInPolytope( box.lower.x, box.lower.y, box.upper.z ) ) inside = false; + if( !pointInPolytope( box.lower.x, box.lower.y, box.lower.z ) ) inside = false; + + if( inside ) { // contains box + 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] instanceof BoundingPolytope) { + 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 ( !pointInPolytope( polytope.verts[j].x, polytope.verts[j].y, polytope.verts[j].z ) ) + 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("BoundingPolytope10")); + } + } + } + + return boundsObjects[index]; + } + + /** + * Returns a string representation of this class + */ + @Override + public String toString() { + int i; + + String description = new String("BoundingPolytope:\n Num Planes ="+planes.length); + for(i = 0; i < planes.length; i++){ + description = description+"\n"+mag[i]*planes[i].x+" "+ + mag[i]*planes[i].y+" "+mag[i]*planes[i].z+" "+mag[i]*planes[i].w; + } + + return description; + } + + private void computeVertex( int a, int b, int c ) { + double det,x,y,z; + + det = planes[a].x*planes[b].y*planes[c].z + planes[a].y*planes[b].z*planes[c].x + + planes[a].z*planes[b].x*planes[c].y - planes[a].z*planes[b].y*planes[c].x - + planes[a].y*planes[b].x*planes[c].z - planes[a].x*planes[b].z*planes[c].y; + + // System.err.println("\n det="+det); + if( det*det < EPSILON ){ + // System.err.println("parallel planes="+a+" "+b+" "+c); + return; // two planes are parallel + } + + det = 1.0/det; + + x = (planes[b].y*planes[c].z - planes[b].z*planes[c].y) * pDotN[a]; + y = (planes[b].z*planes[c].x - planes[b].x*planes[c].z) * pDotN[a]; + z = (planes[b].x*planes[c].y - planes[b].y*planes[c].x) * pDotN[a]; + + x += (planes[c].y*planes[a].z - planes[c].z*planes[a].y) * pDotN[b]; + y += (planes[c].z*planes[a].x - planes[c].x*planes[a].z) * pDotN[b]; + z += (planes[c].x*planes[a].y - planes[c].y*planes[a].x) * pDotN[b]; + + x += (planes[a].y*planes[b].z - planes[a].z*planes[b].y) * pDotN[c]; + y += (planes[a].z*planes[b].x - planes[a].x*planes[b].z) * pDotN[c]; + z += (planes[a].x*planes[b].y - planes[a].y*planes[b].x) * pDotN[c]; + + x = x*det; + y = y*det; + z = z*det; + + if (pointInPolytope( x, y, z ) ) { + if (nVerts >= verts.length) { + Point3d newVerts[] = new Point3d[nVerts << 1]; + for(int i=0;i<nVerts;i++) { + newVerts[i] = verts[i]; + } + verts = newVerts; + } + verts[nVerts++] = new Point3d( x,y,z); + } + } + + + private void computeAllVerts() { + int i,a,b,c; + double x,y,z; + + nVerts = 0; + + if( boundsIsEmpty) { + verts = null; + return; + } + + verts = new Point3d[planes.length*planes.length]; + + for(i=0;i<planes.length;i++) { + pDotN[i] = -planes[i].x*planes[i].w*planes[i].x - + planes[i].y*planes[i].w*planes[i].y - + planes[i].z*planes[i].w*planes[i].z; + } + + for(a=0;a<planes.length-2;a++) { + for(b=a+1;b<planes.length-1;b++) { + for(c=b+1;c<planes.length;c++) { + computeVertex(a,b,c); + } + } + } + // XXXX: correctly compute centroid + + x=y=z=0.0; + Point3d newVerts[] = new Point3d[nVerts]; + + for(i=0;i<nVerts;i++) { + x += verts[i].x; + y += verts[i].y; + z += verts[i].z; + // copy the verts into an array of the correct size + newVerts[i] = verts[i]; + } + + this.verts = newVerts; // copy the verts into an array of the correct size + + centroid.x = x/nVerts; + centroid.y = y/nVerts; + centroid.z = z/nVerts; + + checkBoundsIsEmpty(); + + } + + private boolean pointInPolytope( double x, double y, double z ){ + + for (int i = 0; i < planes.length; i++){ + if(( x*planes[i].x + + y*planes[i].y + + z*planes[i].z + planes[i].w ) > EPSILON ) { + return false; + } + + } + return true; + } + + private void checkBoundsIsEmpty() { + boundsIsEmpty = (planes.length < 4); + } + + private void initEmptyPolytope() { + planes = new Vector4d[6]; + pDotN = new double[6]; + mag = new double[6]; + verts = new Point3d[planes.length*planes.length]; + nVerts = 0; + + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -1.0 ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, -1.0 ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -1.0 ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, -1.0 ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -1.0 ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, -1.0 ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + + checkBoundsIsEmpty(); + } + + @Override + Point3d getCenter() { + return centroid; + } + +@Override +public void getCenter(Point3d center) { + center.set(centroid); +} + + /** + * 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) { + int i, k; + + if (r != null && this.boundId == r.boundId) { + BoundingPolytope region = (BoundingPolytope) r; + if( region.planes.length !=planes.length) { + region.planes = new Vector4d[planes.length]; + + for(k=0;k< region.planes.length;k++) + region.planes[k] = new Vector4d(); + + region.mag = new double[planes.length]; + region.pDotN = new double[planes.length]; + region.verts = new Point3d[nVerts]; + region.nVerts = nVerts; + for(k=0;k<nVerts;k++) + region.verts[k] = new Point3d(verts[k]); + } + + + for(i=0;i<planes.length;i++) { + region.planes[i].x = planes[i].x; + region.planes[i].y = planes[i].y; + region.planes[i].z = planes[i].z; + region.planes[i].w = planes[i].w; + region.mag[i] = mag[i]; + } + + region.boundsIsEmpty = boundsIsEmpty; + region.boundsIsInfinite = boundsIsInfinite; + return region; + } + else { + return (Bounds) this.clone(); + } + } + + @Override + int getPickType() { + return PickShape.PICKBOUNDINGPOLYTOPE; + } +} |