/*
* 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;
}
}