diff options
Diffstat (limited to 'src/javax/media/j3d/BoundingSphere.java')
-rw-r--r-- | src/javax/media/j3d/BoundingSphere.java | 1737 |
1 files changed, 1737 insertions, 0 deletions
diff --git a/src/javax/media/j3d/BoundingSphere.java b/src/javax/media/j3d/BoundingSphere.java new file mode 100644 index 0000000..f3e01f5 --- /dev/null +++ b/src/javax/media/j3d/BoundingSphere.java @@ -0,0 +1,1737 @@ +/* + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package javax.media.j3d; + +import javax.vecmath.Point3d; +import javax.vecmath.Point4d; +import javax.vecmath.Vector3d; +import javax.vecmath.Vector4d; + +/** + * This class defines a spherical bounding region which is defined by a + * center point and a radius. + */ + +public class BoundingSphere extends Bounds { + +/** + * The center of the bounding sphere. + */ +final Point3d center; + +/** + * The radius of the bounding sphere. + */ +double radius; + +/** + * Constructs and initializes a BoundingSphere from a center and radius. + * @param center the center of the bounding sphere + * @param radius the radius of the bounding sphere + */ +public BoundingSphere(Point3d center, double radius) { + boundId = BOUNDING_SPHERE; + this.center = new Point3d(center); + this.radius = radius; + updateBoundsStates(); +} + +/** + * Constructs and initializes a BoundingSphere with radius = 1 at 0 0 0. + */ +public BoundingSphere() { + boundId = BOUNDING_SPHERE; + center = new Point3d(); + radius = 1.0; +} + +/** + * Constructs and initializes a BoundingSphere from a bounding object. + * @param boundsObject a bounds object + */ +public BoundingSphere(Bounds boundsObject) { + boundId = BOUNDING_SPHERE; + center = new Point3d(); + + if (boundsObject == null || boundsObject.boundsIsEmpty) { + setEmptyBounds(); + return; + } + + if (boundsObject.boundsIsInfinite) { + setInfiniteBounds(); + return; + } + + if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObject; + center.x = (box.upper.x+box.lower.x)/2.0; + center.y = (box.upper.y+box.lower.y)/2.0; + center.z = (box.upper.z+box.lower.z)/2.0; + radius = 0.5*(Math.sqrt((box.upper.x-box.lower.x)* + (box.upper.x-box.lower.x)+ + (box.upper.y-box.lower.y)* + (box.upper.y-box.lower.y)+ + (box.upper.z-box.lower.z)* + (box.upper.z-box.lower.z))); + + } else if (boundsObject.boundId == BOUNDING_SPHERE) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + center.set(sphere.center); + radius = sphere.radius; + + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + double t,dis,dis_sq,rad_sq,oldc_to_new_c; + center.x = polytope.centroid.x; + center.y = polytope.centroid.y; + center.z = polytope.centroid.z; + radius = Math.sqrt( (polytope.verts[0].x - center.x)* + (polytope.verts[0].x - center.x) + + (polytope.verts[0].y - center.y)* + (polytope.verts[0].y - center.y) + + (polytope.verts[0].z - center.z)* + (polytope.verts[0].z - center.z)); + + for (int i = 1; i < polytope.nVerts; i++) { + rad_sq = radius * radius; + + dis_sq = (polytope.verts[i].x - center.x)* + (polytope.verts[i].x - center.x) + + (polytope.verts[i].y - center.y)* + (polytope.verts[i].y - center.y) + + (polytope.verts[i].z - center.z)* + (polytope.verts[i].z - center.z); + + // change sphere so one side passes through the point + // and other passes through the old sphere + if( dis_sq > rad_sq) { + dis = Math.sqrt( dis_sq); + radius = (radius + dis)*.5; + oldc_to_new_c = dis - radius; + t = oldc_to_new_c/dis; + center.x = center.x + (polytope.verts[i].x - center.x)*t; + center.y = center.y + (polytope.verts[i].y - center.y)*t; + center.z = center.z + (polytope.verts[i].z - center.z)*t; + } + } + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere0")); + } + + updateBoundsStates(); + } + +/** + * Constructs and initializes a BoundingSphere from an array of bounding + * objects. + * @param boundsObjects an array of bounds objects + */ +public BoundingSphere(Bounds[] boundsObjects) { + boundId = BOUNDING_SPHERE; + center = new Point3d(); + + if (boundsObjects == null || boundsObjects.length <= 0) { + setEmptyBounds(); + return; + } + + // find first non empty bounds object + int i = 0; + while( boundsObjects[i] == null && i < boundsObjects.length) { + i++; + } + + if (i >= boundsObjects.length) { // all bounds objects were empty + setEmptyBounds(); + return; + } + + this.set(boundsObjects[i++]); + if(boundsIsInfinite) + return; + + Point3d[] boxVerts = null; + for(;i<boundsObjects.length;i++) { + if( boundsObjects[i] == null ); // do nothing + else if( boundsObjects[i].boundsIsEmpty); // do nothing + else if( boundsObjects[i].boundsIsInfinite ) { + setInfiniteBounds(); + return; // We're done. + } + else if( boundsObjects[i].boundId == BOUNDING_BOX){ + BoundingBox b = (BoundingBox)boundsObjects[i]; + if (boxVerts == null) { + boxVerts = new Point3d[8]; + for (int j = 0; j < 8; j++) + boxVerts[j] = new Point3d(); + + } + 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].boundId == BOUNDING_SPHERE ) { + double dis, t, d1; + BoundingSphere sphere = (BoundingSphere)boundsObjects[i]; + dis = Math.sqrt( (center.x - sphere.center.x)* + (center.x - sphere.center.x) + + (center.y - sphere.center.y)* + (center.y - sphere.center.y) + + (center.z - sphere.center.z)* + (center.z - sphere.center.z) ); + if( radius > sphere.radius) { + if( (dis+sphere.radius) > radius) { + d1 = .5*(radius-sphere.radius+dis); + t = d1/dis; + radius = d1+sphere.radius; + center.x = sphere.center.x + (center.x-sphere.center.x)*t; + center.y = sphere.center.y + (center.y-sphere.center.y)*t; + center.z = sphere.center.z + (center.z-sphere.center.z)*t; + } + }else { + if( (dis+radius) <= sphere.radius) { + center.x = sphere.center.x; + center.y = sphere.center.y; + center.z = sphere.center.z; + radius = sphere.radius; + }else { + d1 = .5*(sphere.radius-radius+dis); + t = d1/dis; + radius = d1+radius; + center.x = center.x + (sphere.center.x-center.x)*t; + center.y = center.y + (sphere.center.y-center.y)*t; + center.z = center.z + (sphere.center.z-center.z)*t; + } + } + } + else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; + this.combine(polytope.verts); + + } + else { + if( boundsObjects[i] != null ) + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere0")); + } + } + updateBoundsStates(); + } + + /** + * Returns the radius of this bounding sphere as a double. + * @return the radius of the bounding sphere + */ + public double getRadius() { + return radius; + } + + /** + * Sets the radius of this bounding sphere from a double. + * @param r the new radius for the bounding sphere + */ + public void setRadius(double r) { + radius = r; + updateBoundsStates(); + } + +/** + * Returns the position of this bounding sphere as a point. + * @param center a Point to receive the center of the bounding sphere + */ +@Override +public void getCenter(Point3d center) { + center.set(this.center); +} + +/** + * Sets the position of this bounding sphere from a point. + * @param center a Point defining the new center of the bounding sphere + */ +public void setCenter(Point3d center) { + this.center.set(center); + updateBoundsStates(); +} + + /** + * Sets the value of this BoundingSphere. + * @param boundsObject another bounds object + */ + @Override + public void set(Bounds boundsObject){ + int i; + + if (boundsObject == null || boundsObject.boundsIsEmpty) { + setEmptyBounds(); + return; + } + + if( boundsObject.boundsIsInfinite ) { + setInfiniteBounds(); + return; + } + + if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObject; + center.x = (box.upper.x + box.lower.x )/2.0; + center.y = (box.upper.y + box.lower.y )/2.0; + center.z = (box.upper.z + box.lower.z )/2.0; + radius = 0.5*Math.sqrt((box.upper.x-box.lower.x)* + (box.upper.x-box.lower.x)+ + (box.upper.y-box.lower.y)* + (box.upper.y-box.lower.y)+ + (box.upper.z-box.lower.z)* + (box.upper.z-box.lower.z)); + } else if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + radius = sphere.radius; + center.x = sphere.center.x; + center.y = sphere.center.y; + center.z = sphere.center.z; + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + double t,dis,dis_sq,rad_sq,oldc_to_new_c; + center.x = polytope.centroid.x; + center.y = polytope.centroid.y; + center.z = polytope.centroid.z; + radius = Math.sqrt((polytope.verts[0].x - center.x)* + (polytope.verts[0].x - center.x) + + (polytope.verts[0].y - center.y)* + (polytope.verts[0].y - center.y) + + (polytope.verts[0].z - center.z)* + (polytope.verts[0].z - center.z)); + + for(i=1;i<polytope.nVerts;i++) { + rad_sq = radius * radius; + + dis_sq = (polytope.verts[i].x - center.x)* + (polytope.verts[i].x - center.x) + + (polytope.verts[i].y - center.y)* + (polytope.verts[i].y - center.y) + + (polytope.verts[i].z - center.z)* + (polytope.verts[i].z - center.z); + + // change sphere so one side passes through the point + // and other passes through the old sphere + if( dis_sq > rad_sq) { // point is outside sphere + dis = Math.sqrt( dis_sq); + radius = (radius + dis)*.5; + oldc_to_new_c = dis - radius; + t = oldc_to_new_c/dis; + center.x = center.x + (polytope.verts[i].x - center.x)*t; + center.y = center.y + (polytope.verts[i].y - center.y)*t; + center.z = center.z + (polytope.verts[i].z - center.z)*t; + } + } + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere2")); + } + updateBoundsStates(); + } + + /** + * Creates a copy of the bounding sphere. + * @return a BoundingSphere + */ + @Override + public Object clone() { + return new BoundingSphere(this.center, this.radius); + } + + + /** + * Indicates whether the specified <code>bounds</code> object is + * equal to this BoundingSphere object. They are equal if the + * specified <code>bounds</code> object is an instance of + * BoundingSphere and all of the data + * members of <code>bounds</code> are equal to the corresponding + * data members in this BoundingSphere. + * @param bounds the object with which the comparison is made. + * @return true if this BoundingSphere is equal to <code>bounds</code>; + * otherwise false + * + * @since Java 3D 1.2 + */ + @Override + public boolean equals(Object bounds) { + try { + BoundingSphere sphere = (BoundingSphere)bounds; + return (center.equals(sphere.center) && + radius == sphere.radius); + } + catch (NullPointerException e) { + return false; + } + catch (ClassCastException e) { + return false; + } + } + + + /** + * Returns a hash code value for this BoundingSphere object + * based on the data values in this object. Two different + * BoundingSphere objects with identical data values (i.e., + * BoundingSphere.equals returns true) will return the same hash + * code value. Two BoundingSphere objects with different data + * members may return the same hash code value, although this is + * not likely. + * @return a hash code value for this BoundingSphere object. + * + * @since Java 3D 1.2 + */ + @Override + public int hashCode() { + long bits = 1L; + bits = J3dHash.mixDoubleBits(bits, radius); + bits = J3dHash.mixDoubleBits(bits, center.x); + bits = J3dHash.mixDoubleBits(bits, center.y); + bits = J3dHash.mixDoubleBits(bits, center.z); + return J3dHash.finish(bits); + } + + + /** + * Combines this bounding sphere with a bounding object so that the + * resulting bounding sphere encloses the original bounding sphere and the + * given bounds object. + * @param boundsObject another bounds object + */ + @Override + public void combine(Bounds boundsObject) { + double t,dis,d1,u,l,x,y,z,oldc_to_new_c; + BoundingSphere sphere; + + if((boundsObject == null) || (boundsObject.boundsIsEmpty) + || (boundsIsInfinite)) + return; + + if((boundsIsEmpty) || (boundsObject.boundsIsInfinite)) { + this.set(boundsObject); + return; + } + + + if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox b = (BoundingBox)boundsObject; + + // start with point furthest from sphere + u = b.upper.x-center.x; + l = b.lower.x-center.x; + if( u*u > l*l) + x = b.upper.x; + else + x = b.lower.x; + + u = b.upper.y-center.y; + l = b.lower.y-center.y; + if( u*u > l*l) + y = b.upper.y; + else + y = b.lower.y; + + u = b.upper.z-center.z; + l = b.lower.z-center.z; + if( u*u > l*l) + z = b.upper.z; + else + z = b.lower.z; + + dis = Math.sqrt( (x - center.x)*(x - center.x) + + (y - center.y)*(y - center.y) + + (z - center.z)*(z - center.z) ); + + if( dis > radius) { + radius = (dis + radius)*.5; + oldc_to_new_c = dis - radius; + center.x = (radius*center.x + oldc_to_new_c*x)/dis; + center.y = (radius*center.y + oldc_to_new_c*y)/dis; + center.z = (radius*center.z + oldc_to_new_c*z)/dis; + combinePoint( b.upper.x, b.upper.y, b.upper.z); + combinePoint( b.upper.x, b.upper.y, b.lower.z); + combinePoint( b.upper.x, b.lower.y, b.upper.z); + combinePoint( b.upper.x, b.lower.y, b.lower.z); + combinePoint( b.lower.x, b.upper.y, b.upper.z); + combinePoint( b.lower.x, b.upper.y, b.lower.z); + combinePoint( b.lower.x, b.lower.y, b.upper.z); + combinePoint( b.lower.x, b.lower.y, b.lower.z); + } + } else if( boundsObject.boundId == BOUNDING_SPHERE ) { + sphere = (BoundingSphere)boundsObject; + dis = Math.sqrt( (center.x - sphere.center.x)* + (center.x - sphere.center.x) + + (center.y - sphere.center.y)* + (center.y - sphere.center.y) + + (center.z - sphere.center.z)* + (center.z - sphere.center.z) ); + if( radius > sphere.radius) { + if( (dis+sphere.radius) > radius) { + d1 = .5*(radius-sphere.radius+dis); + t = d1/dis; + radius = d1+sphere.radius; + center.x = sphere.center.x + (center.x-sphere.center.x)*t; + center.y = sphere.center.y + (center.y-sphere.center.y)*t; + center.z = sphere.center.z + (center.z-sphere.center.z)*t; + } + }else { + if( (dis+radius) <= sphere.radius) { + center.x = sphere.center.x; + center.y = sphere.center.y; + center.z = sphere.center.z; + radius = sphere.radius; + }else { + d1 = .5*(sphere.radius-radius+dis); + t = d1/dis; + radius = d1+radius; + center.x = center.x + (sphere.center.x-center.x)*t; + center.y = center.y + (sphere.center.y-center.y)*t; + center.z = center.z + (sphere.center.z-center.z)*t; + } + } + + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + this.combine(polytope.verts); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere3")); + } + updateBoundsStates(); + } + + private void combinePoint( double x, double y, double z) { + double dis,oldc_to_new_c; + dis = Math.sqrt( (x - center.x)*(x - center.x) + + (y - center.y)*(y - center.y) + + (z - center.z)*(z - center.z) ); + + if( dis > radius) { + radius = (dis + radius)*.5; + oldc_to_new_c = dis - radius; + center.x = (radius*center.x + oldc_to_new_c*x)/dis; + center.y = (radius*center.y + oldc_to_new_c*y)/dis; + center.z = (radius*center.z + oldc_to_new_c*z)/dis; + } + } + + /** + * Combines this bounding sphere with an array of bounding objects so that the + * resulting bounding sphere encloses the original bounding sphere and the + * given array of bounds object. + * @param boundsObjects an array of bounds objects + */ + @Override + public void combine(Bounds[] boundsObjects) { + BoundingSphere sphere; + BoundingBox b; + BoundingPolytope polytope; + double t,dis,d1,u,l,x,y,z,oldc_to_new_c; + int i=0; + + + 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 ) { + setInfiniteBounds(); + return; // We're done. + } else if( boundsObjects[i].boundId == BOUNDING_BOX){ + b = (BoundingBox)boundsObjects[i]; + + // start with point furthest from sphere + u = b.upper.x-center.x; + l = b.lower.x-center.x; + if( u*u > l*l) + x = b.upper.x; + else + x = b.lower.x; + + u = b.upper.y-center.y; + l = b.lower.y-center.y; + if( u*u > l*l) + y = b.upper.y; + else + y = b.lower.y; + + u = b.upper.z-center.z; + l = b.lower.z-center.z; + if( u*u > l*l) + z = b.upper.z; + else + z = b.lower.z; + + dis = Math.sqrt( (x - center.x)*(x - center.x) + + (y - center.y)*(y - center.y) + + (z - center.z)*(z - center.z) ); + + if( dis > radius) { + radius = (dis + radius)*.5; + oldc_to_new_c = dis - radius; + center.x = (radius*center.x + oldc_to_new_c*x)/dis; + center.y = (radius*center.y + oldc_to_new_c*y)/dis; + center.z = (radius*center.z + oldc_to_new_c*z)/dis; + combinePoint( b.upper.x, b.upper.y, b.upper.z); + combinePoint( b.upper.x, b.upper.y, b.lower.z); + combinePoint( b.upper.x, b.lower.y, b.upper.z); + combinePoint( b.upper.x, b.lower.y, b.lower.z); + combinePoint( b.lower.x, b.upper.y, b.upper.z); + combinePoint( b.lower.x, b.upper.y, b.lower.z); + combinePoint( b.lower.x, b.lower.y, b.upper.z); + combinePoint( b.lower.x, b.lower.y, b.lower.z); + } + } else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { + sphere = (BoundingSphere)boundsObjects[i]; + dis = Math.sqrt( (center.x - sphere.center.x)* + (center.x - sphere.center.x) + + (center.y - sphere.center.y)* + (center.y - sphere.center.y) + + (center.z - sphere.center.z)* + (center.z - sphere.center.z) ); + if( radius > sphere.radius) { + if( (dis+sphere.radius) > radius) { + d1 = .5*(radius-sphere.radius+dis); + t = d1/dis; + radius = d1+sphere.radius; + center.x = sphere.center.x + (center.x-sphere.center.x)*t; + center.y = sphere.center.y + (center.y-sphere.center.y)*t; + center.z = sphere.center.z + (center.z-sphere.center.z)*t; + } + }else { + if( (dis+radius) <= sphere.radius) { + center.x = sphere.center.x; + center.y = sphere.center.y; + center.z = sphere.center.z; + radius = sphere.radius; + }else { + d1 = .5*(sphere.radius-radius+dis); + t = d1/dis; + radius = d1+radius; + center.x = center.x + (sphere.center.x-center.x)*t; + center.y = center.y + (sphere.center.y-center.y)*t; + center.z = center.z + (sphere.center.z-center.z)*t; + } + } + } else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + polytope = (BoundingPolytope)boundsObjects[i]; + this.combine(polytope.verts); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere4")); + } + } + + updateBoundsStates(); + } + + /** + * Combines this bounding sphere with a point. + * @param point a 3D point in space + */ + @Override + public void combine(Point3d point) { + double dis,oldc_to_new_c; + + if( boundsIsInfinite) { + return; + } + + if( boundsIsEmpty) { + radius = 0.0; + center.x = point.x; + center.y = point.y; + center.z = point.z; + } else { + dis = Math.sqrt( (point.x - center.x)*(point.x - center.x) + + (point.y - center.y)*(point.y - center.y) + + (point.z - center.z)*(point.z - center.z) ); + + if( dis > radius) { + radius = (dis + radius)*.5; + oldc_to_new_c = dis - radius; + center.x = (radius*center.x + oldc_to_new_c*point.x)/dis; + center.y = (radius*center.y + oldc_to_new_c*point.y)/dis; + center.z = (radius*center.z + oldc_to_new_c*point.z)/dis; + } + } + + updateBoundsStates(); + } + + /** + * Combines this bounding sphere with an array of points. + * @param points an array of 3D points in space + */ + @Override + public void combine(Point3d[] points) { + int i; + double dis,dis_sq,rad_sq,oldc_to_new_c; + + if( boundsIsInfinite) { + return; + } + + if( boundsIsEmpty ) { + center.x = points[0].x; + center.y = points[0].y; + center.z = points[0].z; + radius = 0.0; + } + + for(i=0;i<points.length;i++) { + rad_sq = radius * radius; + dis_sq = (points[i].x - center.x)*(points[i].x - center.x) + + (points[i].y - center.y)*(points[i].y - center.y) + + (points[i].z - center.z)*(points[i].z - center.z); + + // change sphere so one side passes through the point and + // other passes through the old sphere + if( dis_sq > rad_sq) { + dis = Math.sqrt( dis_sq); + radius = (radius + dis)*.5; + oldc_to_new_c = dis - radius; + center.x = (radius*center.x + oldc_to_new_c*points[i].x)/dis; + center.y = (radius*center.y + oldc_to_new_c*points[i].y)/dis; + center.z = (radius*center.z + oldc_to_new_c*points[i].z)/dis; + } + } + + updateBoundsStates(); + } + + + /** + * Modifies the bounding sphere so that it bounds the volume + * generated by transforming the given bounding object. + * @param boundsObject the bounding object to be transformed + * @param matrix a transformation matrix + */ + @Override + public void transform( Bounds boundsObject, Transform3D matrix) { + if (boundsObject == null || boundsObject.boundsIsEmpty) { + setEmptyBounds(); + return; + } + + if (boundsObject.boundsIsInfinite) { + setInfiniteBounds(); + return; + } + + if (boundsObject.boundId == BOUNDING_BOX) { + BoundingBox tmpBox = new BoundingBox(boundsObject); + tmpBox.transform(matrix); + this.set(tmpBox); + } + else if (boundsObject.boundId == BOUNDING_SPHERE) { + this.set(boundsObject); + this.transform(matrix); + } + else if (boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope tmpPolytope = new BoundingPolytope(boundsObject); + tmpPolytope.transform(matrix); + this.set(tmpPolytope); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere5")); + } + } + + /** + * Transforms this bounding sphere by the given matrix. + */ + @Override + public void transform( Transform3D trans) { + double scale; + + if(boundsIsInfinite) + return; + + trans.transform(center); + scale = trans.getDistanceScale(); + radius = radius * scale; + if (Double.isNaN(radius)) { + setEmptyBounds(); + return; + } + } + + /** + * Test for intersection with a ray + * @param origin the starting point of the ray + * @param direction the direction of the ray + * @param position3 a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + @Override + boolean intersect(Point3d origin, Vector3d direction, Point4d position ) { + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = origin.x; + position.y = origin.y; + position.z = origin.z; + position.w = 0.0; + return true; + } + + double l2oc,rad2,tca,t2hc,t,invMag; + Vector3d dir = new Vector3d(); // normalized direction of ray + Point3d oc = new Point3d(); // vector from sphere center to ray origin + + oc.x = center.x - origin.x; + oc.y = center.y - origin.y; + oc.z = center.z - origin.z; + + l2oc = oc.x*oc.x + oc.y*oc.y + oc.z*oc.z; // center to origin squared + + rad2 = radius*radius; + if( l2oc < rad2 ){ + // System.err.println("ray origin inside sphere" ); + return true; // ray origin inside sphere + } + + invMag = 1.0/Math.sqrt(direction.x*direction.x + + direction.y*direction.y + + direction.z*direction.z); + dir.x = direction.x*invMag; + dir.y = direction.y*invMag; + dir.z = direction.z*invMag; + tca = oc.x*dir.x + oc.y*dir.y + oc.z*dir.z; + + if( tca <= 0.0 ) { + // System.err.println("ray points away from sphere" ); + return false; // ray points away from sphere + } + + t2hc = rad2 - l2oc + tca*tca; + + if( t2hc > 0.0 ){ + t = tca - Math.sqrt(t2hc); + // System.err.println("ray hits sphere:"+this.toString()+" t="+t+" direction="+dir ); + position.x = origin.x + dir.x*t; + position.y = origin.y + dir.y*t; + position.z = origin.z + dir.z*t; + position.w = t; + return true; // ray hits sphere + }else { + // System.err.println("ray does not hit sphere" ); + return false; + } + + } + + /** + * Test for intersection with a point + * @param point the pick point + * @param position a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + @Override + boolean intersect(Point3d point, Point4d position ) { + double x,y,z,dist; + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = point.x; + position.y = point.y; + position.z = point.z; + position.w = 0.0; + return true; + } + + x = point.x - center.x; + y = point.y - center.y; + z = point.z - center.z; + + dist = x*x + y*y + z*z; + if( dist > radius*radius) + return false; + else { + position.x = point.x; + position.y = point.y; + position.z = point.z; + position.w = Math.sqrt(dist); + return true; + } + + } + + /** + * Test for intersection with a segment + * @param start a point defining the start of the line segment + * @param end a point defining the end of the line segment + * @param position a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + @Override + boolean intersect( Point3d start, Point3d end, Point4d position ) { + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = start.x; + position.y = start.y; + position.z = start.z; + position.w = 0.0; + return true; + } + + double l2oc,rad2,tca,t2hc,invMag,t; + Vector3d dir = new Vector3d(); // normalized direction of ray + Point3d oc = new Point3d(); // vector from sphere center to ray origin + Vector3d direction = new Vector3d(); + + oc.x = center.x - start.x; + oc.y = center.y - start.y; + oc.z = center.z - start.z; + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + invMag = 1.0/Math.sqrt( direction.x*direction.x + + direction.y*direction.y + + direction.z*direction.z); + dir.x = direction.x*invMag; + dir.y = direction.y*invMag; + dir.z = direction.z*invMag; + + + l2oc = oc.x*oc.x + oc.y*oc.y + oc.z*oc.z; // center to origin squared + + rad2 = radius*radius; + if( l2oc < rad2 ){ + // System.err.println("ray origin inside sphere" ); + return true; // ray origin inside sphere + } + + tca = oc.x*dir.x + oc.y*dir.y + oc.z*dir.z; + + if( tca <= 0.0 ) { + // System.err.println("ray points away from sphere" ); + return false; // ray points away from sphere + } + + t2hc = rad2 - l2oc + tca*tca; + + if( t2hc > 0.0 ){ + t = tca - Math.sqrt(t2hc); + 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))){ + + position.x = start.x + dir.x*t; + position.y = start.y + dir.x*t; + position.z = start.z + dir.x*t; + position.w = t; + return true; // segment hits sphere + } + } + 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 ) { + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + return true; + } + + double l2oc,rad2,tca,t2hc,mag; + Vector3d dir = new Vector3d(); // normalized direction of ray + Point3d oc = new Point3d(); // vector from sphere center to ray origin + + oc.x = center.x - origin.x; + oc.y = center.y - origin.y; + oc.z = center.z - origin.z; + + l2oc = oc.x*oc.x + oc.y*oc.y + oc.z*oc.z; // center to origin squared + + rad2 = radius*radius; + if( l2oc < rad2 ){ + // System.err.println("ray origin inside sphere" ); + return true; // ray origin inside sphere + } + + mag = Math.sqrt(direction.x*direction.x + + direction.y*direction.y + + direction.z*direction.z); + dir.x = direction.x/mag; + dir.y = direction.y/mag; + dir.z = direction.z/mag; + tca = oc.x*dir.x + oc.y*dir.y + oc.z*dir.z; + + if( tca <= 0.0 ) { + // System.err.println("ray points away from sphere" ); + return false; // ray points away from sphere + } + + t2hc = rad2 - l2oc + tca*tca; + + if( t2hc > 0.0 ){ + // System.err.println("ray hits sphere" ); + return true; // ray hits sphere + }else { + // System.err.println("ray does not hit sphere" ); + return false; + } + } + + + /** + * Returns the position of the intersect point if the ray intersects with + * the sphere. + * + */ + boolean intersect(Point3d origin, Vector3d direction, Point3d intersectPoint ) { + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + intersectPoint.x = origin.x; + intersectPoint.y = origin.y; + intersectPoint.z = origin.z; + return true; + } + + double l2oc,rad2,tca,t2hc,mag,t; + Point3d dir = new Point3d(); // normalized direction of ray + Point3d oc = new Point3d(); // vector from sphere center to ray origin + + oc.x = center.x - origin.x; // XXXX: check if this method is still needed + oc.y = center.y - origin.y; + oc.z = center.z - origin.z; + + l2oc = oc.x*oc.x + oc.y*oc.y + oc.z*oc.z; // center to origin squared + + rad2 = radius*radius; + if( l2oc < rad2 ){ + // System.err.println("ray origin inside sphere" ); + return true; // ray origin inside sphere + } + + mag = Math.sqrt(direction.x*direction.x + + direction.y*direction.y + + direction.z*direction.z); + dir.x = direction.x/mag; + dir.y = direction.y/mag; + dir.z = direction.z/mag; + tca = oc.x*dir.x + oc.y*dir.y + oc.z*dir.z; + + if( tca <= 0.0 ) { + // System.err.println("ray points away from sphere" ); + return false; // ray points away from sphere + } + + t2hc = rad2 - l2oc + tca*tca; + + if( t2hc > 0.0 ){ + t = tca - Math.sqrt(t2hc); + intersectPoint.x = origin.x + direction.x*t; + intersectPoint.y = origin.y + direction.y*t; + intersectPoint.z = origin.z + direction.z*t; + // System.err.println("ray hits sphere" ); + return true; // ray hits sphere + }else { + // System.err.println("ray does not hit sphere" ); + return false; + } + } + + + /** + * 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 ) { + double x,y,z,dist; + + if( boundsIsEmpty ) { + return false; + } + if( boundsIsInfinite ) { + return true; + } + + x = point.x - center.x; + y = point.y - center.y; + z = point.z - center.z; + + dist = x*x + y*y + z*z; + if( dist > radius*radius) + return false; + else + return true; + + } + + /** + * Tests whether the bounding sphere is empty. A bounding sphere 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 sphere + * with a volume of zero is <i>not</i> empty. + * @return true if the bounding sphere is empty; + * otherwise, it returns false + */ + @Override + public boolean isEmpty() { + return boundsIsEmpty; + } + + /** + * Test for intersection with another bounds object. + * @param boundsObject another bounds object + * @return true or false indicating if an intersection occured + */ + @Override + boolean intersect(Bounds boundsObject, Point4d position) { + return intersect(boundsObject); + } + + /** + * Test for intersection with another bounds object. + * @param boundsObject another bounds object + * @return true or false indicating if an intersection occured + */ + @Override + public boolean intersect(Bounds boundsObject) { + double distsq, radsq; + BoundingSphere sphere; + + if( boundsObject == null ) { + return false; + } + + if( boundsIsEmpty || boundsObject.boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite || boundsObject.boundsIsInfinite ) { + return true; + } + + if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObject; + double dis = 0.0; + double rad_sq = radius*radius; + + // find the corner closest to the center of sphere + + if( center.x < box.lower.x ) + dis = (center.x-box.lower.x)*(center.x-box.lower.x); + else + if( center.x > box.upper.x ) + dis = (center.x-box.upper.x)*(center.x-box.upper.x); + + if( center.y < box.lower.y ) + dis += (center.y-box.lower.y)*(center.y-box.lower.y); + else + if( center.y > box.upper.y ) + dis += (center.y-box.upper.y)*(center.y-box.upper.y); + + if( center.z < box.lower.z ) + dis += (center.z-box.lower.z)*(center.z-box.lower.z); + else + if( center.z > box.upper.z ) + dis += (center.z-box.upper.z)*(center.z-box.upper.z); + + return ( dis <= rad_sq ); + } else if( boundsObject.boundId == BOUNDING_SPHERE ) { + sphere = (BoundingSphere)boundsObject; + radsq = radius + sphere.radius; + radsq *= radsq; + distsq = center.distanceSquared(sphere.center); + return (distsq <= radsq); + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + return intersect_ptope_sphere( (BoundingPolytope)boundsObject, this); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere6")); + } + } + + /** + * 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. + } else if( boundsObjects[i].boundId == BOUNDING_BOX){ + if( this.intersect( boundsObjects[i])) return true; + } else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { + sphere = (BoundingSphere)boundsObjects[i]; + radsq = radius + sphere.radius; + radsq *= radsq; + distsq = center.distanceSquared(sphere.center); + if (distsq <= radsq) { + return true; + } + } else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + if( this.intersect( boundsObjects[i])) return true; + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere7")); + } + } + + return false; + + } + + /** + * Test for intersection with another bounds object. + * @param boundsObject another bounds object + * @param newBoundSphere the new bounding sphere which is the intersection of + * the boundsObject and this BoundingSphere + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds boundsObject, BoundingSphere newBoundSphere) { + + if (boundsObject == null || boundsIsEmpty || boundsObject.boundsIsEmpty) { + newBoundSphere.set(null); + return false; + } + + if (boundsIsInfinite && !boundsObject.boundsIsInfinite) { + newBoundSphere.set(boundsObject); + return true; + } + + if (boundsObject.boundsIsInfinite) { + newBoundSphere.set(this); + return true; + } + + if(boundsObject.boundId == BOUNDING_BOX){ + BoundingBox tbox = new BoundingBox(); + BoundingBox box = (BoundingBox)boundsObject; + if( this.intersect( box) ){ + BoundingBox sbox = new BoundingBox( this ); // convert sphere to box + sbox.intersect(box, tbox); // insersect two boxes + newBoundSphere.set( tbox ); // set sphere to the intersection of 2 boxes + return true; + } else { + newBoundSphere.set(null); + return false; + } + } else if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + double dis,t,d2; + dis = Math.sqrt( (center.x-sphere.center.x)*(center.x-sphere.center.x) + + (center.y-sphere.center.y)*(center.y-sphere.center.y) + + (center.z-sphere.center.z)*(center.z-sphere.center.z) ); + if ( dis > radius+sphere.radius) { + newBoundSphere.set(null); + return false; + } else if( dis+radius <= sphere.radius ) { // this sphere is contained within boundsObject + newBoundSphere.center.x = center.x; + newBoundSphere.center.y = center.y; + newBoundSphere.center.z = center.z; + newBoundSphere.radius = radius; + } else if( dis+sphere.radius <= radius ) { // boundsObject is containted within this sphere + newBoundSphere.center.x = sphere.center.x; + newBoundSphere.center.y = sphere.center.y; + newBoundSphere.center.z = sphere.center.z; + newBoundSphere.radius = sphere.radius; + } else { + // distance from this center to center of overlapped volume + d2 = (dis*dis + radius*radius - sphere.radius*sphere.radius)/(2.0*dis); + newBoundSphere.radius = Math.sqrt( radius*radius - d2*d2); + t = d2/dis; + newBoundSphere.center.x = center.x + (sphere.center.x - center.x)*t; + newBoundSphere.center.y = center.y + (sphere.center.y - center.y)*t; + newBoundSphere.center.z = center.z + (sphere.center.z - center.z)*t; + } + + newBoundSphere.updateBoundsStates(); + return true; + + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingBox tbox = new BoundingBox(); + + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + if( this.intersect( polytope) ){ + BoundingBox sbox = new BoundingBox( this ); // convert sphere to box + BoundingBox pbox = new BoundingBox( polytope ); // convert polytope to box + sbox.intersect(pbox,tbox); // insersect two boxes + newBoundSphere.set( tbox ); // set sphere to the intersection of 2 boxesf + return true; + } else { + newBoundSphere.set(null); + return false; + } + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere8")); + } + } + + /** + * Test for intersection with an array of bounds objects. + * @param boundsObjects an array of bounds objects + * @param newBoundSphere the new bounding sphere which is the intersection of + * the boundsObject and this BoundingSphere + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds[] boundsObjects, BoundingSphere newBoundSphere) { + + if (boundsObjects == null || boundsObjects.length <= 0 || boundsIsEmpty) { + newBoundSphere.set(null); + return false; + } + + int i=0; + + // find first non null bounds object + while( boundsObjects[i] == null && i < boundsObjects.length) { + i++; + } + + if (i >= boundsObjects.length) { // all bounds objects were empty + newBoundSphere.set(null); + return false; + } + + boolean status = false; + double newRadius; + Point3d newCenter = new Point3d(); + BoundingBox tbox = new BoundingBox(); + + for(i=0;i<boundsObjects.length;i++) { + if( boundsObjects[i] == null || boundsObjects[i].boundsIsEmpty) ; + else if( boundsObjects[i].boundId == BOUNDING_BOX) { + BoundingBox box = (BoundingBox)boundsObjects[i]; + if( this.intersect( box) ){ + BoundingBox sbox = new BoundingBox( this ); // convert sphere to box + sbox.intersect(box,tbox); // insersect two boxes + if( status ) { + newBoundSphere.combine( tbox ); + } else { + newBoundSphere.set( tbox ); // set sphere to the intersection of 2 boxesf + status = true; + } + } + } else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObjects[i]; + double dis,t,d2; + dis = Math.sqrt( (center.x-sphere.center.x)*(center.x-sphere.center.x) + + (center.y-sphere.center.y)*(center.y-sphere.center.y) + + (center.z-sphere.center.z)*(center.z-sphere.center.z) ); + if ( dis > radius+sphere.radius) { + } else if( dis+radius <= sphere.radius ) { // this sphere is contained within boundsObject + if( status ) { + newBoundSphere.combine( this ); + } else { + newBoundSphere.center.x = center.x; + newBoundSphere.center.y = center.y; + newBoundSphere.center.z = center.z; + newBoundSphere.radius = radius; + status = true; + newBoundSphere.updateBoundsStates(); + } + } else if( dis+sphere.radius <= radius ) { // boundsObject is containted within this sphere + if( status ) { + newBoundSphere.combine( sphere ); + } else { + newBoundSphere.center.x = center.x; + newBoundSphere.center.y = center.y; + newBoundSphere.center.z = center.z; + newBoundSphere.radius = sphere.radius; + status = true; + newBoundSphere.updateBoundsStates(); + } + } else { + // distance from this center to center of overlapped volume + d2 = (dis*dis + radius*radius - sphere.radius*sphere.radius)/(2.0*dis); + newRadius = Math.sqrt( radius*radius - d2*d2); + t = d2/dis; + newCenter.x = center.x + (sphere.center.x - center.x)*t; + newCenter.y = center.y + (sphere.center.y - center.y)*t; + newCenter.z = center.z + (sphere.center.z - center.z)*t; + if( status ) { + BoundingSphere newSphere = new BoundingSphere( newCenter, + newRadius ); + newBoundSphere.combine( newSphere ); + } else { + newBoundSphere.setRadius( newRadius ); + newBoundSphere.setCenter( newCenter ); + status = true; + } + } + + } else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; + if( this.intersect( polytope) ){ + BoundingBox sbox = new BoundingBox( this ); // convert sphere to box + BoundingBox pbox = new BoundingBox( polytope ); // convert polytope to box + sbox.intersect(pbox, tbox); // insersect two boxes + if( status ) { + newBoundSphere.combine( tbox ); + } else { + newBoundSphere.set( tbox ); // set sphere to the intersection of 2 boxesf + status = true; + } + } + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere9")); + } + } + if (status == false) + newBoundSphere.set(null); + return status; + } + + /** + * Finds closest bounding object that intersects this bounding sphere. + * @param boundsObjects an array of bounds objects + * @return closest bounding object + */ + @Override + public Bounds closestIntersection( Bounds[] boundsObjects) { + + if( boundsObjects == null || boundsObjects.length <= 0 ) { + return null; + } + + if( boundsIsEmpty ) { + return null; + } + + double dis,far_dis,pdist,x,y,z,rad_sq; + double cenX = 0.0, cenY = 0.0, cenZ = 0.0; + boolean contains = false; + boolean inside; + boolean intersect = false; + double smallest_distance = Double.MAX_VALUE; + int i,j,index=0; + + + for(i = 0; i < boundsObjects.length; i++){ + if( boundsObjects[i] == null ) ; + + else if( this.intersect( boundsObjects[i])) { + intersect = true; + if(boundsObjects[i].boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObjects[i]; + cenX = (box.upper.x+box.lower.x)/2.0; + cenY = (box.upper.y+box.lower.y)/2.0; + cenZ = (box.upper.z+box.lower.z)/2.0; + dis = Math.sqrt( (center.x-cenX)*(center.x-cenX) + + (center.y-cenY)*(center.y-cenY) + + (center.z-cenZ)*(center.z-cenZ) ); + if( (center.x-box.lower.x)*(center.x-box.lower.x) > + (center.x-box.upper.x)*(center.x-box.upper.x) ) + far_dis = (center.x-box.lower.x)*(center.x-box.lower.x); + else + far_dis = (center.x-box.upper.x)*(center.x-box.upper.x); + + if( (center.y-box.lower.y)*(center.y-box.lower.y) > + (center.y-box.upper.y)*(center.y-box.upper.y) ) + far_dis += (center.y-box.lower.y)*(center.y-box.lower.y); + else + far_dis += (center.y-box.upper.y)*(center.y-box.upper.y); + + if( (center.z-box.lower.z)*(center.z-box.lower.z) > + (center.z-box.upper.z)*(center.z-box.upper.z) ) + far_dis += (center.z-box.lower.z)*(center.z-box.lower.z); + else + far_dis += (center.z-box.upper.z)*(center.z-box.upper.z); + + rad_sq = radius * radius; + if( far_dis <= rad_sq ) { // 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].boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObjects[i]; + dis = Math.sqrt( (center.x-sphere.center.x)*(center.x-sphere.center.x) + + (center.y-sphere.center.y)*(center.y-sphere.center.y) + + (center.z-sphere.center.z)*(center.z-sphere.center.z) ); + if( (dis+sphere.radius) <= radius) { // 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].boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; + dis = Math.sqrt( (center.x-polytope.centroid.x)*(center.x-polytope.centroid.x) + + (center.y-polytope.centroid.y)*(center.y-polytope.centroid.y) + + (center.z-polytope.centroid.z)*(center.z-polytope.centroid.z) ); + inside = true; + for(j=0;j<polytope.nVerts;j++) { + x = polytope.verts[j].x - center.x; + y = polytope.verts[j].y - center.y; + z = polytope.verts[j].z - center.z; + + pdist = x*x + y*y + z*z; + if( pdist > radius*radius) + 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("BoundingSphere10")); + } + } + } + + if ( intersect ) + return boundsObjects[index]; + else + return null; + + } + + + /** + * Intersects this bounding sphere with preprocessed frustum. + * @return true if the bounding sphere and frustum intersect. + */ + boolean intersect(CachedFrustum frustum) { + int i; + double dist; + + if( boundsIsEmpty ) { + return false; + } + + if(boundsIsInfinite) + return true; + + for (i=0; i<6; i++) { + dist = frustum.clipPlanes[i].x*center.x + frustum.clipPlanes[i].y*center.y + + frustum.clipPlanes[i].z*center.z + frustum.clipPlanes[i].w; + if (dist < 0.0 && (dist + radius) < 0.0) { + return(false); + } + } + return true; + } + + /** + * This intersects this bounding sphere with 6 frustum plane equations + * @return returns true if the bounding sphere and frustum intersect. + */ + boolean intersect(Vector4d[] planes) { + int i; + double dist; + + if( boundsIsEmpty ) { + return false; + } + + if(boundsIsInfinite) + return true; + + for (i=0; i<6; i++) { + dist = planes[i].x*center.x + planes[i].y*center.y + + planes[i].z*center.z + planes[i].w; + if (dist < 0.0 && (dist + radius) < 0.0) { + //System.err.println("Tossing " + i + " " + dist + " " + radius); + return(false); + } + } + return true; + } + + /** + * Returns a string representation of this class. + */ + @Override + public String toString() { + return new String( "Center="+center+" Radius="+radius); + } + +private void setEmptyBounds() { + center.set(0.0d, 0.0d, 0.0d); + radius = -1.0; + boundsIsInfinite = false; + boundsIsEmpty = true; +} + +private void setInfiniteBounds() { + center.set(0.0d, 0.0d, 0.0d); + radius = Double.POSITIVE_INFINITY; + boundsIsEmpty = false; + boundsIsInfinite = true; +} + + private void updateBoundsStates() { + + if (Double.isNaN(radius + center.x + center.y + center.z)) { + boundsIsEmpty = true; + boundsIsInfinite = false; + return; + } + + if(radius == Double.POSITIVE_INFINITY) { + boundsIsEmpty = false; + boundsIsInfinite = true; + } + else { + boundsIsInfinite = false; + if( radius < 0.0 ) { + boundsIsEmpty = true; + } else { + boundsIsEmpty = false; + } + } + } + + @Override + Point3d getCenter() { + return center; + } + + /** + * if the passed the "region" is same type as this object + * then do a copy, otherwise clone the Bounds and + * return + */ + @Override + Bounds copy(Bounds r) { + if (r != null && this.boundId == r.boundId) { + BoundingSphere region = (BoundingSphere)r; + region.radius = radius; + region.center.x = center.x; + region.center.y = center.y; + region.center.z = center.z; + region.boundsIsEmpty = boundsIsEmpty; + region.boundsIsInfinite = boundsIsInfinite; + return region; + } + else { + return (Bounds) this.clone(); + } + } + + @Override + int getPickType() { + return PickShape.PICKBOUNDINGSPHERE; + } +} + + + + |