aboutsummaryrefslogtreecommitdiffstats
path: root/src/javax/media/j3d/BoundingPolytope.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/javax/media/j3d/BoundingPolytope.java')
-rw-r--r--src/javax/media/j3d/BoundingPolytope.java1783
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;
+ }
+}