/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package javax.media.j3d;
import javax.vecmath.Point3d;
import javax.vecmath.Point4d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector4d;
/**
* A BoundingPolytope defines a polyhedral bounding region using the
* intersection of four or more half spaces. The region defined by a
* BoundingPolytope is always convex and must be closed.
* <p>
* Each plane in the BoundingPolytope specifies a half-space defined
* by the equation:
* <ul>
* Ax + By + Cz + D <= 0
* </ul>
* where A, B, C, D are the parameters that specify the plane. The
* parameters are passed in the x, y, z, and w fields, respectively,
* of a Vector4d object. The intersection of the set of half-spaces
* corresponding to the planes in this BoundingPolytope defines the
* bounding region.
*/
public class BoundingPolytope extends Bounds {
/**
* An array of bounding planes.
*/
Vector4d[] planes;
double[] mag; // magnitude of plane vector
double[] pDotN; // point on plane dotted with normal
Point3d[] verts; // vertices of polytope
int nVerts; // number of verts in polytope
Point3d centroid = new Point3d(); // centroid of polytope
Point3d boxVerts[];
boolean allocBoxVerts = false;
/**
* Constructs a BoundingPolytope using the specified planes.
* @param planes a set of planes defining the polytope.
* @exception IllegalArgumentException if the length of the
* specified array of planes is less than 4.
*/
public BoundingPolytope(Vector4d[] planes) {
if (planes.length < 4) {
throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope11"));
}
boundId = BOUNDING_POLYTOPE;
int i;
double invMag;
this.planes = new Vector4d[planes.length];
mag = new double[planes.length];
pDotN = new double[planes.length];
for(i=0;i<planes.length;i++) {
// normalize the plane normals
mag[i] = Math.sqrt(planes[i].x*planes[i].x + planes[i].y*planes[i].y +
planes[i].z*planes[i].z);
invMag = 1.0/mag[i];
this.planes[i] = new Vector4d( planes[i].x*invMag, planes[i].y*invMag,
planes[i].z*invMag, planes[i].w*invMag );
}
computeAllVerts(); // XXXX: lazy evaluate
}
/**
* Constructs a BoundingPolytope and initializes it to a set of 6
* planes that defines a cube such that -1 <= x,y,z <= 1. The
* values of the planes are as follows:
* <ul>
* planes[0] : x <= 1 (1,0,0,-1)<br>
* planes[1] : -x <= 1 (-1,0,0,-1)<br>
* planes[2] : y <= 1 (0,1,0,-1)<br>
* planes[3] : -y <= 1 (0,-1,0,-1)<br>
* planes[4] : z <= 1 (0,0,1,-1)<br>
* planes[5] : -z <= 1 (0,0,-1,-1)<br>
* </ul>
*/
public BoundingPolytope() {
boundId = BOUNDING_POLYTOPE;
planes = new Vector4d[6];
mag = new double[planes.length];
pDotN = new double[planes.length];
planes[0] = new Vector4d( 1.0, 0.0, 0.0, -1.0 );
planes[1] = new Vector4d(-1.0, 0.0, 0.0, -1.0 );
planes[2] = new Vector4d( 0.0, 1.0, 0.0, -1.0 );
planes[3] = new Vector4d( 0.0,-1.0, 0.0, -1.0 );
planes[4] = new Vector4d( 0.0, 0.0, 1.0, -1.0 );
planes[5] = new Vector4d( 0.0, 0.0,-1.0, -1.0 );
mag[0] = 1.0;
mag[1] = 1.0;
mag[2] = 1.0;
mag[3] = 1.0;
mag[4] = 1.0;
mag[5] = 1.0;
computeAllVerts(); // XXXX: lazy evaluate
}
/**
* Constructs a BoundingPolytope from the specified bounds object.
* The new polytope will circumscribe the region specified by the
* input bounds.
* @param boundsObject the bounds object from which this polytope
* is constructed.
*/
public BoundingPolytope(Bounds boundsObject ) {
int i;
boundId = BOUNDING_POLYTOPE;
if( boundsObject == null ) {
boundsIsEmpty = true;
boundsIsInfinite = false;
initEmptyPolytope();
computeAllVerts(); // XXXX: lazy evaluate
return;
}
boundsIsEmpty = boundsObject.boundsIsEmpty;
boundsIsInfinite = boundsObject.boundsIsInfinite;
if( boundsObject.boundId == BOUNDING_SPHERE ) {
BoundingSphere sphere = (BoundingSphere)boundsObject;
planes = new Vector4d[6];
mag = new double[planes.length];
pDotN = new double[planes.length];
planes[0] = new Vector4d( 1.0, 0.0, 0.0, -(sphere.center.x+sphere.radius) );
planes[1] = new Vector4d(-1.0, 0.0, 0.0, sphere.center.x-sphere.radius );
planes[2] = new Vector4d( 0.0, 1.0, 0.0, -(sphere.center.y+sphere.radius) );
planes[3] = new Vector4d( 0.0,-1.0, 0.0, sphere.center.y-sphere.radius );
planes[4] = new Vector4d( 0.0, 0.0, 1.0, -(sphere.center.z+sphere.radius) );
planes[5] = new Vector4d( 0.0, 0.0,-1.0, sphere.center.z-sphere.radius );
mag[0] = 1.0;
mag[1] = 1.0;
mag[2] = 1.0;
mag[3] = 1.0;
mag[4] = 1.0;
mag[5] = 1.0;
computeAllVerts(); // XXXX: lazy evaluate
} else if( boundsObject.boundId == BOUNDING_BOX ){
BoundingBox box = (BoundingBox)boundsObject;
planes = new Vector4d[6];
pDotN = new double[planes.length];
mag = new double[planes.length];
planes[0] = new Vector4d( 1.0, 0.0, 0.0, -box.upper.x );
planes[1] = new Vector4d(-1.0, 0.0, 0.0, box.lower.x );
planes[2] = new Vector4d( 0.0, 1.0, 0.0, -box.upper.y );
planes[3] = new Vector4d( 0.0,-1.0, 0.0, box.lower.y );
planes[4] = new Vector4d( 0.0, 0.0, 1.0, -box.upper.z );
planes[5] = new Vector4d( 0.0, 0.0,-1.0, box.lower.z );
mag[0] = 1.0;
mag[1] = 1.0;
mag[2] = 1.0;
mag[3] = 1.0;
mag[4] = 1.0;
mag[5] = 1.0;
computeAllVerts(); // XXXX: lazy evaluate
} else if( boundsObject.boundId == BOUNDING_POLYTOPE ) {
BoundingPolytope polytope = (BoundingPolytope)boundsObject;
planes = new Vector4d[polytope.planes.length];
mag = new double[planes.length];
pDotN = new double[planes.length];
nVerts = polytope.nVerts;
verts = new Point3d[nVerts];
for(i=0;i<planes.length;i++) {
planes[i] = new Vector4d(polytope.planes[i]);
mag[i] = polytope.mag[i];
pDotN[i] = polytope.pDotN[i];
}
for(i=0;i<verts.length;i++) {
verts[i] = new Point3d(polytope.verts[i]);
}
centroid = polytope.centroid;
} else {
throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope0"));
}
}
/**
* Constructs a BoundingPolytope from the specified array of bounds
* objects. The new polytope will circumscribe the union of the
* regions specified by the input bounds objects.
* @param boundsObjects the array bounds objects from which this
* polytope is constructed.
*/
public BoundingPolytope(Bounds[] boundsObjects) {
int i=0;
boundId = BOUNDING_POLYTOPE;
if( boundsObjects == null || boundsObjects.length <= 0 ) {
boundsIsEmpty = true;
boundsIsInfinite = false;
initEmptyPolytope();
computeAllVerts(); // XXXX: lazy evaluate
return;
}
// find first non empty bounds object
while( boundsObjects[i] == null && i < boundsObjects.length) {
i++;
}
if( i >= boundsObjects.length ) { // all bounds objects were empty
boundsIsEmpty = true;
boundsIsInfinite = false;
initEmptyPolytope();
computeAllVerts(); // XXXX: lazy evaluate
return;
}
boundsIsEmpty = boundsObjects[i].boundsIsEmpty;
boundsIsInfinite = boundsObjects[i].boundsIsInfinite;
if( boundsObjects[i].boundId == BOUNDING_SPHERE ) {
BoundingSphere sphere = (BoundingSphere)boundsObjects[i];
planes = new Vector4d[6];
mag = new double[planes.length];
pDotN = new double[planes.length];
planes[0] = new Vector4d( 1.0, 0.0, 0.0, -(sphere.center.x+sphere.radius) );
planes[1] = new Vector4d(-1.0, 0.0, 0.0, sphere.center.x-sphere.radius );
planes[2] = new Vector4d( 0.0, 1.0, 0.0, -(sphere.center.y+sphere.radius) );
planes[3] = new Vector4d( 0.0,-1.0, 0.0, sphere.center.y-sphere.radius );
planes[4] = new Vector4d( 0.0, 0.0, 1.0, -(sphere.center.z+sphere.radius) );
planes[5] = new Vector4d( 0.0, 0.0,-1.0, sphere.center.z-sphere.radius );
mag[0] = 1.0;
mag[1] = 1.0;
mag[2] = 1.0;
mag[3] = 1.0;
mag[4] = 1.0;
mag[5] = 1.0;
computeAllVerts(); // XXXX: lazy evaluate
} else if( boundsObjects[i].boundId == BOUNDING_BOX ){
BoundingBox box = (BoundingBox)boundsObjects[i];
planes = new Vector4d[6];
mag = new double[planes.length];
pDotN = new double[planes.length];
planes[0] = new Vector4d( 1.0, 0.0, 0.0, -box.upper.x );
planes[1] = new Vector4d(-1.0, 0.0, 0.0, box.lower.x );
planes[2] = new Vector4d( 0.0, 1.0, 0.0, -box.upper.y );
planes[3] = new Vector4d( 0.0,-1.0, 0.0, box.lower.y );
planes[4] = new Vector4d( 0.0, 0.0, 1.0, -box.upper.z );
planes[5] = new Vector4d( 0.0, 0.0,-1.0, box.lower.z );
mag[0] = 1.0;
mag[1] = 1.0;
mag[2] = 1.0;
mag[3] = 1.0;
mag[4] = 1.0;
mag[5] = 1.0;
computeAllVerts(); // XXXX: lazy evaluate
} else if( boundsObjects[i].boundId == BOUNDING_POLYTOPE ) {
BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i];
planes = new Vector4d[polytope.planes.length];
mag = new double[planes.length];
pDotN = new double[planes.length];
nVerts = polytope.nVerts;
verts = new Point3d[nVerts];
for(i=0;i<planes.length;i++) {
planes[i] = new Vector4d(polytope.planes[i]);
pDotN[i] = polytope.pDotN[i];
mag[i] = polytope.mag[i];
}
for(i=0;i<verts.length;i++) {
verts[i] = new Point3d(polytope.verts[i]);
}
centroid = polytope.centroid;
} else {
throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope1"));
}
for(i+=1;i<boundsObjects.length;i++) {
this.combine(boundsObjects[i]);
}
}
/**
* Sets the bounding planes for this polytope.
* @param planes the new set of planes for this polytope
* @exception IllegalArgumentException if the length of the
* specified array of planes is less than 4.
*/
public void setPlanes(Vector4d[] planes) {
if (planes.length < 4) {
throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope11"));
}
int i;
double invMag;
this.planes = new Vector4d[planes.length];
pDotN = new double[planes.length];
mag = new double[planes.length];
boundsIsEmpty = false;
if( planes.length <= 0 ) {
boundsIsEmpty = true;
boundsIsInfinite = false;
computeAllVerts(); // XXXX: lazy evaluate
return;
}
for(i=0;i<planes.length;i++) {
// normalize the plane normals
mag[i] = Math.sqrt(planes[i].x*planes[i].x + planes[i].y*planes[i].y +
planes[i].z*planes[i].z);
invMag = 1.0/mag[i];
this.planes[i] = new Vector4d( planes[i].x*invMag, planes[i].y*invMag,
planes[i].z*invMag, planes[i].w*invMag );
}
computeAllVerts(); // XXXX: lazy evaluate
}
/**
* Returns the equations of the bounding planes for this bounding polytope.
* The equations are copied into the specified array.
* The array must be large enough to hold all of the vectors.
* The individual array elements must be allocated by the caller.
* @param planes an array Vector4d to receive the bounding planes
*/
public void getPlanes(Vector4d[] planes)
{
int i;
for(i=0;i<planes.length;i++) {
planes[i].x = this.planes[i].x*mag[i];
planes[i].y = this.planes[i].y*mag[i];
planes[i].z = this.planes[i].z*mag[i];
planes[i].w = this.planes[i].w*mag[i];
}
}
public int getNumPlanes() {
return planes.length;
}
/**
* Sets the planes for this BoundingPolytope by keeping its current
* number and position of planes and computing new planes positions
* to enclose the given bounds object.
* @param boundsObject another bounds object
*/
@Override
public void set(Bounds boundsObject) {
int i,k;
// no polytope exists yet so initialize one using the boundsObject
if( boundsObject == null ) {
boundsIsEmpty = true;
boundsIsInfinite = false;
computeAllVerts(); // XXXX: lazy evaluate
}else if( boundsObject.boundId == BOUNDING_SPHERE ) {
BoundingSphere sphere = (BoundingSphere)boundsObject;
if( boundsIsEmpty) {
initEmptyPolytope(); // no ptope exist so must initialize to default
computeAllVerts();
}
for(i=0;i<planes.length;i++) { // D = -(N dot C + radius)
planes[i].w = -(sphere.center.x*planes[i].x +
sphere.center.y*planes[i].y +
sphere.center.z*planes[i].z + sphere.radius);
}
boundsIsEmpty = boundsObject.boundsIsEmpty;
boundsIsInfinite = boundsObject.boundsIsInfinite;
computeAllVerts(); // XXXX: lazy evaluate
} else if( boundsObject.boundId == BOUNDING_BOX){
BoundingBox box = (BoundingBox)boundsObject;
double ux,uy,uz,lx,ly,lz,newD;
if( boundsIsEmpty) {
initEmptyPolytope(); // no ptope exist so must initialize to default
computeAllVerts();
}
for(i=0;i<planes.length;i++) {
ux = box.upper.x*planes[i].x;
uy = box.upper.y*planes[i].y;
uz = box.upper.z*planes[i].z;
lx = box.lower.x*planes[i].x;
ly = box.lower.y*planes[i].y;
lz = box.lower.z*planes[i].z;
planes[i].w = -(ux + uy + uz ); // initalize plane to upper vert
if( (newD = ux + uy + lz ) + planes[i].w > 0.0) planes[i].w = -newD;
if( (newD = ux + ly + uz ) + planes[i].w > 0.0) planes[i].w = -newD;
if( (newD = ux + ly + lz ) + planes[i].w > 0.0) planes[i].w = -newD;
if( (newD = lx + uy + uz ) + planes[i].w > 0.0) planes[i].w = -newD;
if( (newD = lx + uy + lz ) + planes[i].w > 0.0) planes[i].w = -newD;
if( (newD = lx + ly + uz ) + planes[i].w > 0.0) planes[i].w = -newD;
if( (newD = lx + ly + lz ) + planes[i].w > 0.0) planes[i].w = -newD;
}
boundsIsEmpty = boundsObject.boundsIsEmpty;
boundsIsInfinite = boundsObject.boundsIsInfinite;
computeAllVerts(); // XXXX: lazy evaluate
} else if(boundsObject.boundId == BOUNDING_POLYTOPE) {
BoundingPolytope polytope = (BoundingPolytope)boundsObject;
if( planes.length != polytope.planes.length) {
planes = new Vector4d[polytope.planes.length];
for(k=0;k<polytope.planes.length;k++) planes[k] = new Vector4d();
mag = new double[polytope.planes.length];
pDotN = new double[polytope.planes.length];
}
for(i=0;i<polytope.planes.length;i++) {
planes[i].x = polytope.planes[i].x;
planes[i].y = polytope.planes[i].y;
planes[i].z = polytope.planes[i].z;
planes[i].w = polytope.planes[i].w;
mag[i] = polytope.mag[i];
}
nVerts = polytope.nVerts;
verts = new Point3d[nVerts];
for (k=0; k<nVerts; k++) {
verts[k] = new Point3d(polytope.verts[k]);
}
boundsIsEmpty = boundsObject.boundsIsEmpty;
boundsIsInfinite = boundsObject.boundsIsInfinite;
} else {
throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope2"));
}
}
/**
* Creates a copy of a polytope.
* @return a new BoundingPolytope
*/
@Override
public Object clone() {
return new BoundingPolytope(planes);
}
/**
* Indicates whether the specified <code>bounds</code> object is
* equal to this BoundingPolytope object. They are equal if the
* specified <code>bounds</code> object is an instance of
* BoundingPolytope and all of the data
* members of <code>bounds</code> are equal to the corresponding
* data members in this BoundingPolytope.
* @param bounds the object with which the comparison is made.
* @return true if this BoundingPolytope is equal to <code>bounds</code>;
* otherwise false
*
* @since Java 3D 1.2
*/
@Override
public boolean equals(Object bounds) {
try {
BoundingPolytope polytope = (BoundingPolytope)bounds;
if (planes.length != polytope.planes.length)
return false;
for (int i = 0; i < planes.length; i++)
if (!planes[i].equals(polytope.planes[i]))
return false;
return true;
}
catch (NullPointerException e) {
return false;
}
catch (ClassCastException e) {
return false;
}
}
/**
* Returns a hash code value for this BoundingPolytope object
* based on the data values in this object. Two different
* BoundingPolytope objects with identical data values (i.e.,
* BoundingPolytope.equals returns true) will return the same hash
* code value. Two BoundingPolytope objects with different data
* members may return the same hash code value, although this is
* not likely.
* @return a hash code value for this BoundingPolytope object.
*
* @since Java 3D 1.2
*/
@Override
public int hashCode() {
long bits = 1L;
for (int i = 0; i < planes.length; i++) {
bits = J3dHash.mixDoubleBits(bits, planes[i].x);
bits = J3dHash.mixDoubleBits(bits, planes[i].y);
bits = J3dHash.mixDoubleBits(bits, planes[i].z);
bits = J3dHash.mixDoubleBits(bits, planes[i].w);
}
return J3dHash.finish(bits);
}
/**
* Combines this bounding polytope with a bounding object so that the
* resulting bounding polytope encloses the original bounding polytope and the
* given bounds object.
* @param boundsObject another bounds object
*/
@Override
public void combine(Bounds boundsObject) {
BoundingSphere sphere;
if((boundsObject == null) || (boundsObject.boundsIsEmpty)
|| (boundsIsInfinite))
return;
if((boundsIsEmpty) || (boundsObject.boundsIsInfinite)) {
this.set(boundsObject);
return;
}
boundsIsEmpty = boundsObject.boundsIsEmpty;
boundsIsInfinite = boundsObject.boundsIsInfinite;
if( boundsObject.boundId == BOUNDING_SPHERE ) {
sphere = (BoundingSphere)boundsObject;
int i;
double dis;
for(i = 0; i < planes.length; i++){
dis = sphere.radius+ sphere.center.x*planes[i].x +
sphere.center.y*planes[i].y + sphere.center.z *
planes[i].z + planes[i].w;
if( dis > 0.0 ) {
planes[i].w += -dis;
}
}
} else if( boundsObject instanceof BoundingBox){
BoundingBox b = (BoundingBox)boundsObject;
if( !allocBoxVerts){
boxVerts = new Point3d[8];
for(int j=0;j<8;j++)boxVerts[j] = new Point3d();
allocBoxVerts = true;
}
boxVerts[0].set(b.lower.x, b.lower.y, b.lower.z );
boxVerts[1].set(b.lower.x, b.upper.y, b.lower.z );
boxVerts[2].set(b.upper.x, b.lower.y, b.lower.z );
boxVerts[3].set(b.upper.x, b.upper.y, b.lower.z );
boxVerts[4].set(b.lower.x, b.lower.y, b.upper.z );
boxVerts[5].set(b.lower.x, b.upper.y, b.upper.z );
boxVerts[6].set(b.upper.x, b.lower.y, b.upper.z );
boxVerts[7].set(b.upper.x, b.upper.y, b.upper.z );
this.combine(boxVerts);
} else if(boundsObject.boundId == BOUNDING_POLYTOPE) {
BoundingPolytope polytope = (BoundingPolytope)boundsObject;
this.combine(polytope.verts);
} else {
throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope3"));
}
computeAllVerts();
}
/**
* Combines this bounding polytope with an array of bounding objects so that the
* resulting bounding polytope encloses the original bounding polytope and the
* given array of bounds object.
* @param boundsObjects an array of bounds objects
*/
@Override
public void combine(Bounds[] boundsObjects) {
int i=0;
double dis;
if( (boundsObjects == null) || (boundsObjects.length <= 0)
|| (boundsIsInfinite))
return;
// find first non empty bounds object
while( (i<boundsObjects.length) && ((boundsObjects[i]==null)
|| boundsObjects[i].boundsIsEmpty)) {
i++;
}
if( i >= boundsObjects.length)
return; // no non empty bounds so do not modify current bounds
if(boundsIsEmpty)
this.set(boundsObjects[i++]);
if(boundsIsInfinite)
return;
for(;i<boundsObjects.length;i++) {
if( boundsObjects[i] == null ); // do nothing
else if( boundsObjects[i].boundsIsEmpty ); // do nothing
else if( boundsObjects[i].boundsIsInfinite ) {
this.set(boundsObjects[i]);
break; // We're done;
}
else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) {
BoundingSphere sphere = (BoundingSphere)boundsObjects[i];
for(int j = 0; j < planes.length; j++){
dis = sphere.radius+ sphere.center.x*planes[j].x +
sphere.center.y*planes[j].y + sphere.center.z*
planes[j].z + planes[j].w;
if( dis > 0.0 ) {
planes[j].w += -dis;
}
}
} else if( boundsObjects[i].boundId == BOUNDING_BOX){
BoundingBox b = (BoundingBox)boundsObjects[i];
if( !allocBoxVerts){
boxVerts = new Point3d[8];
for(int j=0;j<8;j++)boxVerts[j] = new Point3d();
allocBoxVerts = true;
}
boxVerts[0].set(b.lower.x, b.lower.y, b.lower.z );
boxVerts[1].set(b.lower.x, b.upper.y, b.lower.z );
boxVerts[2].set(b.upper.x, b.lower.y, b.lower.z );
boxVerts[3].set(b.upper.x, b.upper.y, b.lower.z );
boxVerts[4].set(b.lower.x, b.lower.y, b.upper.z );
boxVerts[5].set(b.lower.x, b.upper.y, b.upper.z );
boxVerts[6].set(b.upper.x, b.lower.y, b.upper.z );
boxVerts[7].set(b.upper.x, b.upper.y, b.upper.z );
this.combine(boxVerts);
} else if(boundsObjects[i] instanceof BoundingPolytope) {
BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i];
this.combine(polytope.verts);
} else {
throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope4"));
}
computeAllVerts();
}
}
/**
* Combines this bounding polytope with a point.
* @param point a 3d point in space
*/
@Override
public void combine(Point3d point) {
int i;
double dis;
if(boundsIsInfinite) {
return;
}
if( boundsIsEmpty ){
planes = new Vector4d[6];
mag = new double[planes.length];
pDotN = new double[planes.length];
nVerts = 1;
verts = new Point3d[nVerts];
verts[0] = new Point3d( point.x, point.y, point.z);
for(i=0;i<planes.length;i++) {
pDotN[i] = 0.0;
}
planes[0] = new Vector4d( 1.0, 0.0, 0.0, -point.x );
planes[1] = new Vector4d(-1.0, 0.0, 0.0, point.x );
planes[2] = new Vector4d( 0.0, 1.0, 0.0, -point.y );
planes[3] = new Vector4d( 0.0,-1.0, 0.0, point.y );
planes[4] = new Vector4d( 0.0, 0.0, 1.0, -point.z );
planes[5] = new Vector4d( 0.0, 0.0,-1.0, point.z );
mag[0] = 1.0;
mag[1] = 1.0;
mag[2] = 1.0;
mag[3] = 1.0;
mag[4] = 1.0;
mag[5] = 1.0;
centroid.x = point.x;
centroid.y = point.y;
centroid.z = point.z;
boundsIsEmpty = false;
boundsIsInfinite = false;
} else {
for(i = 0; i < planes.length; i++){
dis = point.x*planes[i].x + point.y*planes[i].y + point.z*
planes[i].z + planes[i].w;
if( dis > 0.0 ) {
planes[i].w += -dis;
}
}
computeAllVerts();
}
}
/**
* Combines this bounding polytope with an array of points.
* @param points an array of 3d points in space
*/
@Override
public void combine(Point3d[] points) {
int i,j;
double dis;
if( boundsIsInfinite) {
return;
}
if( boundsIsEmpty ){
planes = new Vector4d[6];
mag = new double[planes.length];
pDotN = new double[planes.length];
nVerts = points.length;
verts = new Point3d[nVerts];
verts[0] = new Point3d( points[0].x, points[0].y, points[0].z);
for(i=0;i<planes.length;i++) {
pDotN[i] = 0.0;
}
planes[0] = new Vector4d( 1.0, 0.0, 0.0, -points[0].x );
planes[1] = new Vector4d(-1.0, 0.0, 0.0, points[0].x );
planes[2] = new Vector4d( 0.0, 1.0, 0.0, -points[0].y );
planes[3] = new Vector4d( 0.0,-1.0, 0.0, points[0].y );
planes[4] = new Vector4d( 0.0, 0.0, 1.0, -points[0].z );
planes[5] = new Vector4d( 0.0, 0.0,-1.0, points[0].z );
mag[0] = 1.0;
mag[1] = 1.0;
mag[2] = 1.0;
mag[3] = 1.0;
mag[4] = 1.0;
mag[5] = 1.0;
centroid.x = points[0].x;
centroid.y = points[0].y;
centroid.z = points[0].z;
boundsIsEmpty = false;
boundsIsInfinite = false;
}
for(j = 0; j < points.length; j++){
for(i = 0; i < planes.length; i++){
dis = points[j].x*planes[i].x + points[j].y*planes[i].y +
points[j].z*planes[i].z + planes[i].w;
if( dis > 0.0 ) {
planes[i].w += -dis;
}
}
}
computeAllVerts();
}
/**
* Modifies the bounding polytope so that it bounds the volume
* generated by transforming the given bounding object.
* @param boundsObject the bounding object to be transformed
* @param matrix a transformation matrix
*/
@Override
public void transform( Bounds boundsObject, Transform3D matrix) {
if( boundsObject == null || boundsObject.boundsIsEmpty) {
boundsIsEmpty = true;
boundsIsInfinite = false;
computeAllVerts();
return;
}
if(boundsObject.boundsIsInfinite) {
this.set(boundsObject);
return;
}
if( boundsObject.boundId == BOUNDING_SPHERE ) {
BoundingSphere sphere = new BoundingSphere(boundsObject);
sphere.transform(matrix);
this.set(sphere);
} else if( boundsObject.boundId == BOUNDING_BOX){
BoundingBox box = new BoundingBox(boundsObject);
box.transform(matrix);
this.set(box);
} else if(boundsObject.boundId == BOUNDING_POLYTOPE) {
BoundingPolytope polytope = new BoundingPolytope(boundsObject);
polytope.transform(matrix);
this.set(polytope);
} else {
throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope5"));
}
}
/**
* Transforms this bounding polytope by the given transformation matrix.
* @param matrix a transformation matrix
*/
@Override
public void transform( Transform3D matrix) {
if(boundsIsInfinite)
return;
int i;
double invMag;
Transform3D invTrans = new Transform3D(matrix);
invTrans.invert();
invTrans.transpose();
for(i = 0; i < planes.length; i++){
planes[i].x = planes[i].x * mag[i];
planes[i].y = planes[i].y * mag[i];
planes[i].z = planes[i].z * mag[i];
planes[i].w = planes[i].w * mag[i];
invTrans.transform( planes[i] );
}
for(i=0;i<planes.length;i++) {
// normalize the plane normals
mag[i] = Math.sqrt(planes[i].x*planes[i].x + planes[i].y*planes[i].y +
planes[i].z*planes[i].z);
invMag = 1.0/mag[i];
this.planes[i] = new Vector4d( planes[i].x*invMag, planes[i].y*invMag,
planes[i].z*invMag, planes[i].w*invMag );
}
for (i=0; i < verts.length; i++) {
matrix.transform(verts[i]);
}
}
/**
* Test for intersection with a ray.
* @param origin is a the starting point of the ray
* @param direction is the direction of the ray
* @param intersectPoint is a point defining the location of the intersection
* @return true or false indicating if an intersection occured
*/
boolean intersect(Point3d origin, Vector3d direction, Point3d intersectPoint ) {
double t,v0,vd,x,y,z,invMag;
double dx, dy, dz;
int i;
if( boundsIsEmpty ) {
return false;
}
if( boundsIsInfinite ) {
intersectPoint.x = origin.x;
intersectPoint.y = origin.y;
intersectPoint.z = origin.z;
return true;
}
invMag = 1.0/Math.sqrt(direction.x*direction.x +
direction.y*direction.y + direction.z*direction.z);
dx = direction.x*invMag;
dy = direction.y*invMag;
dz = direction.z*invMag;
// compute intersection point of ray and each plane then test if point is in polytope
for(i=0;i<planes.length;i++) {
vd = planes[i].x*dx + planes[i].y*dy + planes[i].z*dz;
v0 = -(planes[i].x*origin.x + planes[i].y*origin.y +
planes[i].z*origin.z + planes[i].w);
if(vd != 0.0) { // ray is parallel to plane
t = v0/vd;
if( t >= 0.0) { // plane is behind origin
x = origin.x + dx*t; // compute intersection point
y = origin.y + dy*t;
z = origin.z + dz*t;
if( pointInPolytope(x,y,z) ) {
intersectPoint.x = x;
intersectPoint.y = y;
intersectPoint.z = z;
return true; // ray intersects a face of polytope
}
}
}
}
return false;
}
/**
* Test for intersection with a ray
* @param origin is a the starting point of the ray
* @param direction is the direction of the ray
* @param position is a point defining the location of the pick w= distance to pick
* @return true or false indicating if an intersection occured
*/
@Override
boolean intersect(Point3d origin, Vector3d direction, Point4d position ) {
double t,v0,vd,x,y,z,invMag;
double dx, dy, dz;
int i;
if( boundsIsEmpty ) {
return false;
}
if( boundsIsInfinite ) {
position.x = origin.x;
position.y = origin.y;
position.z = origin.z;
position.w = 0.0;
return true;
}
invMag = 1.0/Math.sqrt(direction.x*direction.x + direction.y*
direction.y + direction.z*direction.z);
dx = direction.x*invMag;
dy = direction.y*invMag;
dz = direction.z*invMag;
for(i=0;i<planes.length;i++) {
vd = planes[i].x*dx + planes[i].y*dy + planes[i].z*dz;
v0 = -(planes[i].x*origin.x + planes[i].y*origin.y +
planes[i].z*origin.z + planes[i].w);
// System.err.println("v0="+v0+" vd="+vd);
if(vd != 0.0) { // ray is parallel to plane
t = v0/vd;
if( t >= 0.0) { // plane is behind origin
x = origin.x + dx*t; // compute intersection point
y = origin.y + dy*t;
z = origin.z + dz*t;
// System.err.println("t="+t+" point="+x+" "+y+" "+z);
if( pointInPolytope(x,y,z) ) {
position.x = x;
position.y = y;
position.z = z;
position.w = t;
return true; // ray intersects a face of polytope
}
}
}
}
return false;
}
/**
* Test for intersection with a point
* @param point is the pick point
* @param position is a point defining the location of the pick w= distance to pick
* @return true or false indicating if an intersection occured
*/
@Override
boolean intersect(Point3d point, Point4d position ) {
int i;
if( boundsIsEmpty ) {
return false;
}
if( boundsIsInfinite ) {
position.x = point.x;
position.y = point.y;
position.z = point.z;
position.w = 0.0;
return true;
}
for(i = 0; i < this.planes.length; i++){
if(( point.x*this.planes[i].x +
point.y*this.planes[i].y +
point.z*this.planes[i].z + planes[i].w ) > 0.0 )
return false;
}
return true;
}
/**
* Test for intersection with a segment
* @param start is a point defining the start of the line segment
* @param end is a point defining the end of the line segment
* @param position is a point defining the location of the pick w= distance to pick
* @return true or false indicating if an intersection occured
*/
@Override
boolean intersect( Point3d start, Point3d end, Point4d position ) {
double t,v0,vd,x,y,z;
int i;
//System.err.println("line segment intersect : planes.length " + planes.length);
if( boundsIsEmpty ) {
return false;
}
if( boundsIsInfinite ) {
position.x = start.x;
position.y = start.y;
position.z = start.z;
position.w = 0.0;
return true;
}
Point3d direction = new Point3d();
direction.x = end.x - start.x;
direction.y = end.y - start.y;
direction.z = end.z - start.z;
for(i=0;i<planes.length;i++) {
vd = planes[i].x*direction.x + planes[i].y*direction.y +
planes[i].z*direction.z;
v0 = -(planes[i].x*start.x + planes[i].y*start.y +
planes[i].z*start.z + planes[i].w);
// System.err.println("v0="+v0+" vd="+vd);
if(vd != 0.0) { // ray is parallel to plane
t = v0/vd;
// System.err.println("t is " + t);
if( t >= 0.0) { // plane is behind start
x = start.x + direction.x*t; // compute intersection point
y = start.y + direction.y*t;
z = start.z + direction.z*t;
// System.err.println("t="+t+" point="+x+" "+y+" "+z);
if( pointInPolytope(x,y,z) ) {
// if((t*t) > (end.x-start.x)*(end.x-start.x) +
// (end.y-start.y)*(end.y-start.y) +
// (end.z-start.z)*(end.z-start.z)) {
if(t <= 1.0) {
position.x = x;
position.y = y;
position.z = z;
position.w = t;
return true; // ray intersects a face of polytope
}
}
}
}
}
return false;
}
/**
* Test for intersection with a ray.
* @param origin the starting point of the ray
* @param direction the direction of the ray
* @return true or false indicating if an intersection occured
*/
@Override
public boolean intersect(Point3d origin, Vector3d direction ) {
// compute intersection point of ray and each plane then test if point is in polytope
double t,v0,vd,x,y,z;
int i;
if( boundsIsEmpty ) {
return false;
}
if( boundsIsInfinite ) {
return true;
}
for(i=0;i<planes.length;i++) {
vd = planes[i].x*direction.x + planes[i].y*direction.y +
planes[i].z*direction.z;
v0 = -(planes[i].x*origin.x + planes[i].y*origin.y +
planes[i].z*origin.z + planes[i].w);
if(vd != 0.0) { // ray is parallel to plane
t = v0/vd;
if( t >= 0.0) { // plane is behind origin
x = origin.x + direction.x*t; // compute intersection point
y = origin.y + direction.y*t;
z = origin.z + direction.z*t;
if( pointInPolytope(x,y,z) ) {
return true; // ray intersects a face of polytope
} else {
// System.err.println("point outside polytope");
}
}
}
}
return false;
}
/**
* Tests whether the bounding polytope is empty. A bounding polytope is
* empty if it is null (either by construction or as the result of
* a null intersection) or if its volume is negative. A bounding polytope
* with a volume of zero is <i>not</i> empty.
* @return true if the bounding polytope is empty;
* otherwise, it returns false
*/
@Override
public boolean isEmpty() {
// if nVerts > 0 after computeAllVerts(), that means
// there is some intersection between 3 planes.
return (boundsIsEmpty || (nVerts <= 0));
}
/**
* Test for intersection with a point.
* @param point a Point defining a position in 3-space
* @return true or false indicating if an intersection occured
*/
@Override
public boolean intersect(Point3d point ) {
int i;
if( boundsIsEmpty ) {
return false;
}
if( boundsIsInfinite ) {
return true;
}
for(i = 0; i < this.planes.length; i++){
if(( point.x*this.planes[i].x +
point.y*this.planes[i].y +
point.z*this.planes[i].z + planes[i].w ) > 0.0 )
return false;
}
return true;
}
/**
* Test for intersection with another bounds object.
* @param boundsObject another bounds object
* @return true or false indicating if an intersection occured
*/
@Override
boolean intersect(Bounds boundsObject, Point4d position) {
return intersect(boundsObject);
}
/**
* Test for intersection with another bounds object.
* @param boundsObject another bounds object
* @return true or false indicating if an intersection occured
*/
@Override
public boolean intersect(Bounds boundsObject) {
if( boundsObject == null ) {
return false;
}
if( boundsIsEmpty || boundsObject.boundsIsEmpty ) {
return false;
}
if( boundsIsInfinite || boundsObject.boundsIsInfinite ) {
return true;
}
if( boundsObject.boundId == BOUNDING_SPHERE ) {
return intersect_ptope_sphere( this, (BoundingSphere)boundsObject);
} else if( boundsObject.boundId == BOUNDING_BOX){
return intersect_ptope_abox( this, (BoundingBox)boundsObject);
} else if(boundsObject.boundId == BOUNDING_POLYTOPE) {
return intersect_ptope_ptope( this, (BoundingPolytope)boundsObject);
} else {
throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope6"));
}
}
/**
* Test for intersection with another bounds object.
* @param boundsObjects an array of bounding objects
* @return true or false indicating if an intersection occured
*/
@Override
public boolean intersect(Bounds[] boundsObjects) {
double distsq, radsq;
BoundingSphere sphere;
int i;
if( boundsObjects == null || boundsObjects.length <= 0 ) {
return false;
}
if( boundsIsEmpty ) {
return false;
}
for(i = 0; i < boundsObjects.length; i++){
if( boundsObjects[i] == null || boundsObjects[i].boundsIsEmpty) ;
else if( boundsIsInfinite || boundsObjects[i].boundsIsInfinite ) {
return true; // We're done here.
}
if( boundsObjects[i].boundId == BOUNDING_SPHERE ) {
sphere = (BoundingSphere)boundsObjects[i];
radsq = sphere.radius;
radsq *= radsq;
distsq = sphere.center.distanceSquared(sphere.center);
if (distsq < radsq) {
return true;
}
} else if(boundsObjects[i].boundId == BOUNDING_BOX){
if( this.intersect(boundsObjects[i])) return true;
} else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) {
if( this.intersect(boundsObjects[i])) return true;
} else {
throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope7"));
}
}
return false;
}
/**
* Test for intersection with another bounds object.
* @param boundsObject another bounds object
* @param newBoundPolytope the new bounding polytope, which is the intersection of
* the boundsObject and this BoundingPolytope
* @return true or false indicating if an intersection occured
*/
public boolean intersect(Bounds boundsObject, BoundingPolytope newBoundPolytope) {
int i;
if((boundsObject == null) || boundsIsEmpty || boundsObject.boundsIsEmpty ) {
newBoundPolytope.boundsIsEmpty = true;
newBoundPolytope.boundsIsInfinite = false;
newBoundPolytope.computeAllVerts();
return false;
}
if(boundsIsInfinite && (!boundsObject.boundsIsInfinite)) {
newBoundPolytope.set(boundsObject);
return true;
}
else if((!boundsIsInfinite) && boundsObject.boundsIsInfinite) {
newBoundPolytope.set(this);
return true;
}
else if(boundsIsInfinite && boundsObject.boundsIsInfinite) {
newBoundPolytope.set(this);
return true;
}
BoundingBox tbox = new BoundingBox(); // convert sphere to box
if( boundsObject.boundId == BOUNDING_SPHERE ) {
BoundingSphere sphere = (BoundingSphere)boundsObject;
if( this.intersect( sphere)) {
BoundingBox sbox = new BoundingBox( sphere ); // convert sphere to box
BoundingBox pbox = new BoundingBox( this ); // convert polytope to box
pbox.intersect(sbox, tbox); // insersect two boxes
newBoundPolytope.set( tbox );
return true;
}
} else if( boundsObject.boundId == BOUNDING_BOX){
BoundingBox box = (BoundingBox)boundsObject;
if( this.intersect( box)) {
BoundingBox pbox = new BoundingBox( this ); // convert polytope to box
pbox.intersect(box, tbox); // insersect two boxes
newBoundPolytope.set( tbox );
return true;
}
} else if(boundsObject.boundId == BOUNDING_POLYTOPE) {
BoundingPolytope polytope = (BoundingPolytope)boundsObject;
if( this.intersect( polytope)) {
Vector4d newPlanes[] = new Vector4d[planes.length + polytope.planes.length];
for(i=0;i<planes.length;i++) {
newPlanes[i] = new Vector4d(planes[i]);
}
for(i=0;i<polytope.planes.length;i++) {
newPlanes[planes.length + i] = new Vector4d(polytope.planes[i]);
}
BoundingPolytope newPtope= new BoundingPolytope( newPlanes );
newBoundPolytope.set(newPtope);
return true;
}
} else {
throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope8"));
}
newBoundPolytope.boundsIsEmpty = true;
newBoundPolytope.boundsIsInfinite = false;
newBoundPolytope.computeAllVerts();
return false;
}
/**
* Test for intersection with an array of bounds objects.
* @param boundsObjects an array of bounds objects
* @param newBoundingPolytope the new bounding polytope, which is the intersection of
* the boundsObject and this BoundingPolytope
* @return true or false indicating if an intersection occured
*/
public boolean intersect(Bounds[] boundsObjects, BoundingPolytope newBoundingPolytope) {
if( boundsObjects == null || boundsObjects.length <= 0 || boundsIsEmpty ) {
newBoundingPolytope.boundsIsEmpty = true;
newBoundingPolytope.boundsIsInfinite = false;
newBoundingPolytope.computeAllVerts();
return false;
}
int i=0;
// find first non null bounds object
while( boundsObjects[i] == null && i < boundsObjects.length) {
i++;
}
if( i >= boundsObjects.length ) { // all bounds objects were empty
newBoundingPolytope.boundsIsEmpty = true;
newBoundingPolytope.boundsIsInfinite = false;
newBoundingPolytope.computeAllVerts();
return false;
}
boolean status = false;
BoundingBox tbox = new BoundingBox(); // convert sphere to box
for(i=0;i<boundsObjects.length;i++) {
if( boundsObjects[i] == null || boundsObjects[i].boundsIsEmpty) ;
else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) {
BoundingSphere sphere = (BoundingSphere)boundsObjects[i];
if( this.intersect( sphere)) {
BoundingBox sbox = new BoundingBox( sphere ); // convert sphere to box
BoundingBox pbox = new BoundingBox( this ); // convert polytope to box
pbox.intersect(sbox, tbox); // insersect two boxes
if ( status ) {
newBoundingPolytope.combine( tbox );
} else {
newBoundingPolytope.set( tbox );
status = true;
}
}
} else if( boundsObjects[i].boundId == BOUNDING_BOX){
BoundingBox box = (BoundingBox)boundsObjects[i];
if( this.intersect( box) ){
BoundingBox pbox = new BoundingBox( this ); // convert polytope to box
pbox.intersect(box,tbox); // insersect two boxes
if ( status ) {
newBoundingPolytope.combine( tbox );
} else {
newBoundingPolytope.set( tbox );
status = true;
}
} else {
}
} else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) {
BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i];
if( this.intersect( polytope)) {
Vector4d newPlanes[] = new Vector4d[planes.length + polytope.planes.length];
for(i=0;i<planes.length;i++) {
newPlanes[i] = new Vector4d(planes[i]);
}
for(i=0;i<polytope.planes.length;i++) {
newPlanes[planes.length + i] = new Vector4d(polytope.planes[i]);
}
BoundingPolytope newPtope= new BoundingPolytope( newPlanes );
if ( status ) {
newBoundingPolytope.combine( newPtope );
} else {
newBoundingPolytope.set( newPtope );
status = true;
}
}
} else {
throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope8"));
}
if(newBoundingPolytope.boundsIsInfinite)
break; // We're done.
}
if( status == false ) {
newBoundingPolytope.boundsIsEmpty = true;
newBoundingPolytope.boundsIsInfinite = false;
newBoundingPolytope.computeAllVerts();
}
return status;
}
/**
* Finds closest bounding object that intersects this bounding polytope.
* @param boundsObjects is an array of bounds objects
* @return closest bounding object
*/
@Override
public Bounds closestIntersection( Bounds[] boundsObjects) {
if( boundsObjects == null || boundsObjects.length <= 0 ) {
return null;
}
if( boundsIsEmpty ) {
return null;
}
double dis,disToPlane;
boolean contains = false;
boolean inside;
double smallest_distance = Double.MAX_VALUE;
int i,j,index=0;
double cenX = 0.0, cenY = 0.0, cenZ = 0.0;
for(i = 0; i < boundsObjects.length; i++){
if( boundsObjects[i] == null );
else if( this.intersect( boundsObjects[i])) {
if( boundsObjects[i] instanceof BoundingSphere ) {
BoundingSphere sphere = (BoundingSphere)boundsObjects[i];
dis = Math.sqrt( (centroid.x-sphere.center.x)*(centroid.x-sphere.center.x) +
(centroid.y-sphere.center.y)*(centroid.y-sphere.center.y) +
(centroid.z-sphere.center.z)*(centroid.z-sphere.center.z) );
inside = true;
for(j=0;j<planes.length;j++) {
if( ( sphere.center.x*planes[j].x +
sphere.center.y*planes[j].y +
sphere.center.z*planes[j].z + planes[i].w ) > 0.0 ) { // check if sphere center in polytope
disToPlane = sphere.center.x*planes[j].x +
sphere.center.y*planes[j].y +
sphere.center.z*planes[j].z + planes[j].w;
// check if distance from center to plane is larger than radius
if( disToPlane > sphere.radius ) inside = false;
}
}
if( inside) { // contains the sphere
if( !contains ){ // initialize smallest_distance for the first containment
index = i;
smallest_distance = dis;
contains = true;
} else{
if( dis < smallest_distance){
index = i;
smallest_distance = dis;
}
}
} else if (!contains) {
if( dis < smallest_distance){
index = i;
smallest_distance = dis;
}
}
} else if( boundsObjects[i] instanceof BoundingBox){
BoundingBox box = (BoundingBox)boundsObjects[i];
cenX = (box.upper.x+box.lower.x)/2.0;
cenY = (box.upper.y+box.lower.y)/2.0;
cenZ = (box.upper.z+box.lower.z)/2.0;
dis = Math.sqrt( (centroid.x-cenX)*(centroid.x-cenX) +
(centroid.y-cenY)*(centroid.y-cenY) +
(centroid.z-cenZ)*(centroid.z-cenZ) );
inside = true;
if( !pointInPolytope( box.upper.x, box.upper.y, box.upper.z ) ) inside = false;
if( !pointInPolytope( box.upper.x, box.upper.y, box.lower.z ) ) inside = false;
if( !pointInPolytope( box.upper.x, box.lower.y, box.upper.z ) ) inside = false;
if( !pointInPolytope( box.upper.x, box.lower.y, box.lower.z ) ) inside = false;
if( !pointInPolytope( box.lower.x, box.upper.y, box.upper.z ) ) inside = false;
if( !pointInPolytope( box.lower.x, box.upper.y, box.lower.z ) ) inside = false;
if( !pointInPolytope( box.lower.x, box.lower.y, box.upper.z ) ) inside = false;
if( !pointInPolytope( box.lower.x, box.lower.y, box.lower.z ) ) inside = false;
if( inside ) { // contains box
if( !contains ){ // initialize smallest_distance for the first containment
index = i;
smallest_distance = dis;
contains = true;
} else{
if( dis < smallest_distance){
index = i;
smallest_distance = dis;
}
}
} else if (!contains) {
if( dis < smallest_distance){
index = i;
smallest_distance = dis;
}
}
} else if(boundsObjects[i] instanceof BoundingPolytope) {
BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i];
dis = Math.sqrt( (centroid.x-polytope.centroid.x)*(centroid.x-polytope.centroid.x) +
(centroid.y-polytope.centroid.y)*(centroid.y-polytope.centroid.y) +
(centroid.z-polytope.centroid.z)*(centroid.z-polytope.centroid.z) );
inside = true;
for(j=0;j<polytope.nVerts;j++) {
if ( !pointInPolytope( polytope.verts[j].x, polytope.verts[j].y, polytope.verts[j].z ) )
inside = false;
}
if( inside ) {
if( !contains ){ // initialize smallest_distance for the first containment
index = i;
smallest_distance = dis;
contains = true;
} else{
if( dis < smallest_distance){
index = i;
smallest_distance = dis;
}
}
} else if (!contains) {
if( dis < smallest_distance){
index = i;
smallest_distance = dis;
}
}
} else {
throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope10"));
}
}
}
return boundsObjects[index];
}
/**
* Returns a string representation of this class
*/
@Override
public String toString() {
int i;
String description = new String("BoundingPolytope:\n Num Planes ="+planes.length);
for(i = 0; i < planes.length; i++){
description = description+"\n"+mag[i]*planes[i].x+" "+
mag[i]*planes[i].y+" "+mag[i]*planes[i].z+" "+mag[i]*planes[i].w;
}
return description;
}
private void computeVertex( int a, int b, int c ) {
double det,x,y,z;
det = planes[a].x*planes[b].y*planes[c].z + planes[a].y*planes[b].z*planes[c].x +
planes[a].z*planes[b].x*planes[c].y - planes[a].z*planes[b].y*planes[c].x -
planes[a].y*planes[b].x*planes[c].z - planes[a].x*planes[b].z*planes[c].y;
// System.err.println("\n det="+det);
if( det*det < EPSILON ){
// System.err.println("parallel planes="+a+" "+b+" "+c);
return; // two planes are parallel
}
det = 1.0/det;
x = (planes[b].y*planes[c].z - planes[b].z*planes[c].y) * pDotN[a];
y = (planes[b].z*planes[c].x - planes[b].x*planes[c].z) * pDotN[a];
z = (planes[b].x*planes[c].y - planes[b].y*planes[c].x) * pDotN[a];
x += (planes[c].y*planes[a].z - planes[c].z*planes[a].y) * pDotN[b];
y += (planes[c].z*planes[a].x - planes[c].x*planes[a].z) * pDotN[b];
z += (planes[c].x*planes[a].y - planes[c].y*planes[a].x) * pDotN[b];
x += (planes[a].y*planes[b].z - planes[a].z*planes[b].y) * pDotN[c];
y += (planes[a].z*planes[b].x - planes[a].x*planes[b].z) * pDotN[c];
z += (planes[a].x*planes[b].y - planes[a].y*planes[b].x) * pDotN[c];
x = x*det;
y = y*det;
z = z*det;
if (pointInPolytope( x, y, z ) ) {
if (nVerts >= verts.length) {
Point3d newVerts[] = new Point3d[nVerts << 1];
for(int i=0;i<nVerts;i++) {
newVerts[i] = verts[i];
}
verts = newVerts;
}
verts[nVerts++] = new Point3d( x,y,z);
}
}
private void computeAllVerts() {
int i,a,b,c;
double x,y,z;
nVerts = 0;
if( boundsIsEmpty) {
verts = null;
return;
}
verts = new Point3d[planes.length*planes.length];
for(i=0;i<planes.length;i++) {
pDotN[i] = -planes[i].x*planes[i].w*planes[i].x -
planes[i].y*planes[i].w*planes[i].y -
planes[i].z*planes[i].w*planes[i].z;
}
for(a=0;a<planes.length-2;a++) {
for(b=a+1;b<planes.length-1;b++) {
for(c=b+1;c<planes.length;c++) {
computeVertex(a,b,c);
}
}
}
// XXXX: correctly compute centroid
x=y=z=0.0;
Point3d newVerts[] = new Point3d[nVerts];
for(i=0;i<nVerts;i++) {
x += verts[i].x;
y += verts[i].y;
z += verts[i].z;
// copy the verts into an array of the correct size
newVerts[i] = verts[i];
}
this.verts = newVerts; // copy the verts into an array of the correct size
centroid.x = x/nVerts;
centroid.y = y/nVerts;
centroid.z = z/nVerts;
checkBoundsIsEmpty();
}
private boolean pointInPolytope( double x, double y, double z ){
for (int i = 0; i < planes.length; i++){
if(( x*planes[i].x +
y*planes[i].y +
z*planes[i].z + planes[i].w ) > EPSILON ) {
return false;
}
}
return true;
}
private void checkBoundsIsEmpty() {
boundsIsEmpty = (planes.length < 4);
}
private void initEmptyPolytope() {
planes = new Vector4d[6];
pDotN = new double[6];
mag = new double[6];
verts = new Point3d[planes.length*planes.length];
nVerts = 0;
planes[0] = new Vector4d( 1.0, 0.0, 0.0, -1.0 );
planes[1] = new Vector4d(-1.0, 0.0, 0.0, -1.0 );
planes[2] = new Vector4d( 0.0, 1.0, 0.0, -1.0 );
planes[3] = new Vector4d( 0.0,-1.0, 0.0, -1.0 );
planes[4] = new Vector4d( 0.0, 0.0, 1.0, -1.0 );
planes[5] = new Vector4d( 0.0, 0.0,-1.0, -1.0 );
mag[0] = 1.0;
mag[1] = 1.0;
mag[2] = 1.0;
mag[3] = 1.0;
mag[4] = 1.0;
mag[5] = 1.0;
checkBoundsIsEmpty();
}
@Override
Point3d getCenter() {
return centroid;
}
@Override
public void getCenter(Point3d center) {
center.set(centroid);
}
/**
* if the passed the "region" is same type as this object
* then do a copy, otherwise clone the Bounds and
* return
*/
@Override
Bounds copy(Bounds r) {
int i, k;
if (r != null && this.boundId == r.boundId) {
BoundingPolytope region = (BoundingPolytope) r;
if( region.planes.length !=planes.length) {
region.planes = new Vector4d[planes.length];
for(k=0;k< region.planes.length;k++)
region.planes[k] = new Vector4d();
region.mag = new double[planes.length];
region.pDotN = new double[planes.length];
region.verts = new Point3d[nVerts];
region.nVerts = nVerts;
for(k=0;k<nVerts;k++)
region.verts[k] = new Point3d(verts[k]);
}
for(i=0;i<planes.length;i++) {
region.planes[i].x = planes[i].x;
region.planes[i].y = planes[i].y;
region.planes[i].z = planes[i].z;
region.planes[i].w = planes[i].w;
region.mag[i] = mag[i];
}
region.boundsIsEmpty = boundsIsEmpty;
region.boundsIsInfinite = boundsIsInfinite;
return region;
}
else {
return (Bounds) this.clone();
}
}
@Override
int getPickType() {
return PickShape.PICKBOUNDINGPOLYTOPE;
}
}