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