aboutsummaryrefslogtreecommitdiffstats
path: root/src/javax/media/j3d/Bounds.java
diff options
context:
space:
mode:
authorHarvey Harrison <[email protected]>2015-04-19 21:02:06 -0700
committerHarvey Harrison <[email protected]>2015-04-19 21:02:06 -0700
commit7a2e20caac9db6f789a7b3fab344b9758af45335 (patch)
treeb5236ff2570178de356eab569225108948eb4d30 /src/javax/media/j3d/Bounds.java
parentf76ce302c4bb2a9f03bbee571ec5d05c29633023 (diff)
j3dcore: flatten the directory structure a bit
Signed-off-by: Harvey Harrison <[email protected]>
Diffstat (limited to 'src/javax/media/j3d/Bounds.java')
-rw-r--r--src/javax/media/j3d/Bounds.java673
1 files changed, 673 insertions, 0 deletions
diff --git a/src/javax/media/j3d/Bounds.java b/src/javax/media/j3d/Bounds.java
new file mode 100644
index 0000000..9672859
--- /dev/null
+++ b/src/javax/media/j3d/Bounds.java
@@ -0,0 +1,673 @@
+/*
+ * 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.Matrix3d;
+import javax.vecmath.Point3d;
+import javax.vecmath.Point4d;
+import javax.vecmath.Vector3d;
+import javax.vecmath.Vector4d;
+
+/**
+ * The abstract base class for bounds objects. Bounds objects define
+ * a convex, closed volume that is used for various intersection and
+ * culling operations.
+ */
+
+public abstract class Bounds extends Object implements Cloneable {
+ static final double EPSILON = .000001;
+ static final boolean debug = false;
+
+ static final int BOUNDING_BOX = 0x1;
+ static final int BOUNDING_SPHERE = 0x2;
+ static final int BOUNDING_POLYTOPE = 0x4;
+
+ boolean boundsIsEmpty = false;
+ boolean boundsIsInfinite = false;
+ int boundId = 0;
+
+ /**
+ * Constructs a new Bounds object.
+ */
+ public Bounds() {
+ }
+
+
+ /**
+ * Makes a copy of a bounds object.
+ */
+ @Override
+ public abstract Object clone();
+
+
+ /**
+ * Indicates whether the specified <code>bounds</code> object is
+ * equal to this Bounds object. They are equal if both the
+ * specified <code>bounds</code> object and this Bounds are
+ * instances of the same Bounds subclass and all of the data
+ * members of <code>bounds</code> are equal to the corresponding
+ * data members in this Bounds.
+ * @param bounds the object with which the comparison is made.
+ * @return true if this Bounds object is equal to <code>bounds</code>;
+ * otherwise false
+ *
+ * @since Java 3D 1.2
+ */
+ @Override
+ public abstract boolean equals(Object bounds);
+
+
+ /**
+ * Returns a hash code for this Bounds object based on the
+ * data values in this object. Two different Bounds objects of
+ * the same type with identical data values (i.e., Bounds.equals
+ * returns true) will return the same hash code. Two Bounds
+ * objects with different data members may return the same hash code
+ * value, although this is not likely.
+ * @return a hash code for this Bounds object.
+ *
+ * @since Java 3D 1.2
+ */
+ @Override
+ public abstract int hashCode();
+
+
+ /**
+ * 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
+ */
+ public abstract boolean intersect( Point3d origin, Vector3d direction );
+
+ /**
+ * 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
+ */
+ public abstract boolean intersect( Point3d point );
+
+ /**
+ * 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
+ */
+ abstract boolean intersect( Point3d origin, Vector3d direction, Point4d position );
+
+ /**
+ * Test for intersection with a point
+ * @param point is a point defining a position in 3-space
+ * @param position is a point defining the location of the pick w= distance to pick
+ * @return true or false indicating if an intersection occured
+ */
+ abstract boolean intersect( Point3d point, Point4d position);
+
+ /**
+ * 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
+ */
+ abstract boolean intersect( Point3d start, Point3d end, Point4d position );
+
+ /**
+ * Test for intersection with another bounds object
+ *
+ * Test for intersection with another bounds object
+ * @param boundsObject is another bounds object
+ * @return true or false indicating if an intersection occured
+ */
+ abstract boolean intersect( Bounds boundsObject, Point4d position );
+
+ /**
+ * Test for intersection with another bounds object.
+ * @param boundsObject another bounds object
+ * @return true or false indicating if an intersection occurred
+ */
+ public abstract boolean intersect( Bounds boundsObject );
+
+ /**
+ * Test for intersection with another bounds object.
+ * @param boundsObjects an array of bounding objects
+ * @return true or false indicating if an intersection occured
+ */
+ public abstract boolean intersect( Bounds[] boundsObjects );
+
+
+ /**
+ * Finds closest bounding object that intersects this bounding object.
+ * @param boundsObjects an array of bounds objects
+ * @return closest bounding object
+ */
+ public abstract Bounds closestIntersection( Bounds[] boundsObjects);
+
+/**
+ * Returns the center of the bounds
+ * @return bounds center
+ */
+abstract Point3d getCenter();
+
+/**
+ * Gets the centroid of this bounding region.
+ * @param center a Point to receive the centroid of the bounding region
+ */
+public abstract void getCenter(Point3d center);
+
+ /**
+ * Combines this bounding object with a bounding object so that the
+ * resulting bounding object encloses the original bounding object and the
+ * given bounds object.
+ * @param boundsObject another bounds object
+ */
+ public abstract void combine( Bounds boundsObject );
+
+
+ /**
+ * Combines this bounding object with an array of bounding objects so that the
+ * resulting bounding object encloses the original bounding object and the
+ * given array of bounds object.
+ * @param boundsObjects an array of bounds objects
+ */
+ public abstract void combine( Bounds[] boundsObjects);
+
+ /**
+ * Combines this bounding object with a point.
+ * @param point a 3d point in space
+ */
+ public abstract void combine( Point3d point);
+
+ /**
+ * Combines this bounding object with an array of points.
+ * @param points an array of 3d points in space
+ */
+ public abstract void combine( Point3d[] points);
+
+ /**
+ * Transforms this bounding object by the given matrix.
+ * @param trans the transformation matrix
+ */
+ public abstract void transform(Transform3D trans);
+
+ /**
+ * Modifies the bounding object so that it bounds the volume
+ * generated by transforming the given bounding object.
+ * @param bounds the bounding object to be transformed
+ * @param trans the transformation matrix
+ */
+ public abstract void transform( Bounds bounds, Transform3D trans);
+
+ /**
+ * Tests whether the bounds is empty. A bounds is
+ * empty if it is null (either by construction or as the result of
+ * a null intersection) or if its volume is negative. A bounds
+ * with a volume of zero is <i>not</i> empty.
+ * @return true if the bounds is empty; otherwise, it returns false
+ */
+ public abstract boolean isEmpty();
+
+ /**
+ * Sets the value of this Bounds object.
+ * @param boundsObject another bounds object.
+ */
+ public abstract void set( Bounds boundsObject);
+
+
+ abstract Bounds copy(Bounds region);
+
+
+ private void test_point(Vector4d[] planes, Point3d new_point) {
+ for (int i = 0; i < planes.length; i++){
+ double dist = (new_point.x*planes[i].x + new_point.y*planes[i].y +
+ new_point.z*planes[i].z + planes[i].w ) ;
+ if (dist > EPSILON ){
+ System.err.println("new point is outside of" +
+ " plane["+i+"] dist = " + dist);
+ }
+ }
+ }
+
+ /**
+ * computes the closest point from the given point to a set of planes
+ * (polytope)
+ * @param g the point
+ * @param planes array of bounding planes
+ * @param new_point point on planes closest g
+ */
+ boolean closest_point( Point3d g, Vector4d[] planes, Point3d new_point ) {
+
+ double t,s,dist,w;
+ boolean converged, inside, firstPoint, firstInside;
+ int i,count;
+ double ab,ac,bc,ad,bd,cd,aa,bb,cc;
+ double b1,b2,b3,d1,d2,d3,y1,y2,y3;
+ double h11,h12,h13,h22,h23,h33;
+ double l12,l13,l23;
+ Point3d n = new Point3d();
+ Point3d p = new Point3d();
+ Vector3d delta = null;
+
+ // These are temporary until the solve code is working
+
+
+ /*
+ * The algorithm:
+ * We want to find the point "n", closest to "g", while still within
+ * the the polytope defined by "planes". We find the solution by
+ * minimizing the value for a "penalty function";
+ *
+ * f = distance(n,g)^2 + sum for each i: w(distance(n, planes[i]))
+ *
+ * Where "w" is a weighting which indicates how much more important
+ * it is to be close to the planes than it is to be close to "g".
+ *
+ * We minimize this function by taking it's derivitive, and then
+ * solving for the value of n when the derivitive equals 0.
+ *
+ * For the 1D case with a single plane (a,b,c,d), x = n.x and g = g.x,
+ * this looks like:
+ *
+ * f(x) = (x - g) ^ 2 + w(ax + d)^2
+ * f'(x) = 2x -2g + 2waax + 2wad
+ *
+ * (note aa = a^2) setting f'(x) = 0 gives:
+ *
+ * (1 + waa)x = g - wad
+ *
+ * Note that the solution is just outside the plane [a, d]. With the
+ * correct choice of w, this should be inside of the EPSILON tolerance
+ * outside the planes.
+ *
+ * Extending to 3D gives the matrix solution:
+ *
+ * | (1 + waa) wab wac |
+ * H = | wab (1 + wbb) wbc |
+ * | wac wbc (1 + wcc) |
+ *
+ * b = [g.x - wad, g.y - wbd, g.z - wcd]
+ *
+ * H * n = b
+ *
+ * n = b * H.inverse()
+ *
+ * The implementation speeds this process up by recognizing that
+ * H is symmetric, so that it can be decomposed into three matrices:
+ *
+ * H = L * D * L.transpose()
+ *
+ * 1.0 0.0 0.0 d1 0.0 0.0
+ * L = l12 1.0 0.0 D = 0.0 d2 0.0
+ * l13 l23 1.0 0.0 0.0 d3
+ *
+ * n can then be derived by back-substitution, where the original
+ * problem is decomposed as:
+ *
+ * H * n = b
+ * L * D * L.transpose() * n = b
+ * L * D * y = b; L.transpose() * n = y
+ *
+ * We can then multiply out the terms of L * D and solve for y, and
+ * then use y to solve for n.
+ */
+
+ w=100.0 / EPSILON; // must be large enough to ensure that solution
+ // is within EPSILON of planes
+
+ count = 0;
+ p.set(g);
+
+ if (debug) {
+ System.err.println("closest_point():\nincoming g="+" "+g.x+" "+g.y+
+ " "+g.z);
+ }
+
+ converged = false;
+ firstPoint = true;
+ firstInside = false;
+
+ Vector4d pln;
+
+ while( !converged ) {
+ if (debug) {
+ System.err.println("start: p="+" "+p.x+" "+p.y+" "+p.z);
+ }
+
+ // test the current point against the planes, for each
+ // plane that is violated, add it's contribution to the
+ // penalty function
+ inside = true;
+ aa=0.0; bb=0.0; cc=0.0;
+ ab=0.0; ac=0.0; bc=0.0; ad=0.0; bd=0.0; cd=0.0;
+ for(i = 0; i < planes.length; i++){
+ pln = planes[i];
+ dist = (p.x*pln.x + p.y*pln.y +
+ p.z*pln.z + pln.w ) ;
+ // if point is outside or within EPSILON of the boundary, add
+ // the plane to the penalty matrix. We do this even if the
+ // point is already inside the polytope to prevent numerical
+ // instablity in cases where the point is just outside the
+ // boundary of several planes of the polytope
+ if (dist > -EPSILON ){
+ aa = aa + pln.x * pln.x;
+ bb = bb + pln.y * pln.y;
+ cc = cc + pln.z * pln.z;
+ ab = ab + pln.x * pln.y;
+ ac = ac + pln.x * pln.z;
+ bc = bc + pln.y * pln.z;
+ ad = ad + pln.x * pln.w;
+ bd = bd + pln.y * pln.w;
+ cd = cd + pln.z * pln.w;
+ }
+ // If the point is inside if dist is <= EPSILON
+ if (dist > EPSILON ){
+ inside = false;
+ if (debug) {
+ System.err.println("point outside plane["+i+"]=("+
+ pln.x+ ","+pln.y+",\n\t"+pln.z+
+ ","+ pln.w+")\ndist = " + dist);
+ }
+ }
+ }
+ // see if we are done
+ if (inside) {
+ if (debug) {
+ System.err.println("p is inside");
+ }
+ if (firstPoint) {
+ firstInside = true;
+ }
+ new_point.set(p);
+ converged = true;
+ } else { // solve for a closer point
+ firstPoint = false;
+
+ // this is the upper right corner of H, which is all we
+ // need to do the decomposition since the matrix is symetric
+ h11 = 1.0 + aa * w;
+ h12 = ab * w;
+ h13 = ac * w;
+ h22 = 1.0 + bb * w;
+ h23 = bc * w;
+ h33 = 1.0 + cc * w;
+
+ if (debug) {
+ System.err.println(" hessin= ");
+ System.err.println(h11+" "+h12+" "+h13);
+ System.err.println(" "+h22+" "+h23);
+ System.err.println(" "+h33);
+ }
+
+ // these are the constant terms
+ b1 = g.x - w * ad;
+ b2 = g.y - w * bd;
+ b3 = g.z - w * cd;
+
+ if (debug) {
+ System.err.println(" b1,b2,b3 = "+b1+" "+b2+" " +b3);
+ }
+
+ // solve, d1, d2, d3 actually 1/dx, which is more useful
+ d1 = 1/h11;
+ l12 = d1 * h12;
+ l13 = d1 * h13;
+ s = h22-l12*h12;
+ d2 = 1/s;
+ t = h23-h12*l13;
+ l23 = d2 * t;
+ d3 = 1/(h33 - h13*l13 - t*l23);
+
+ if (debug) {
+ System.err.println(" l12,l13,l23 "+l12+" "+l13+" "+l23);
+ System.err.println(" d1,d2,d3 "+ d1+" "+d2+" "+d3);
+ }
+
+ // we have L and D, now solve for y
+ y1 = d1 * b1;
+ y2 = d2 * (b2 - h12*y1);
+ y3 = d3 * (b3 - h13*y1 - t*y2);
+
+ if (debug) {
+ System.err.println(" y1,y2,y3 = "+y1+" "+y2+" "+y3);
+ }
+
+ // we have y, solve for n
+ n.z = y3;
+ n.y = (y2 - l23*n.z);
+ n.x = (y1 - l13*n.z - l12*n.y);
+
+ if (debug) {
+ System.err.println("new point = " + n.x+" " + n.y+" " +
+ n.z);
+ test_point(planes, n);
+
+ if (delta == null) delta = new Vector3d();
+ delta.sub(n, p);
+ delta.normalize();
+ System.err.println("p->n direction: " + delta);
+ Matrix3d hMatrix = new Matrix3d();
+ // check using the the javax.vecmath routine
+ hMatrix.m00 = h11;
+ hMatrix.m01 = h12;
+ hMatrix.m02 = h13;
+ hMatrix.m10 = h12; // h21 = h12
+ hMatrix.m11 = h22;
+ hMatrix.m12 = h23;
+ hMatrix.m20 = h13; // h31 = h13
+ hMatrix.m21 = h23; // h32 = h22
+ hMatrix.m22 = h33;
+ hMatrix.invert();
+ Point3d check = new Point3d(b1, b2, b3);
+ hMatrix.transform(check);
+
+ System.err.println("check point = " + check.x+" " +
+ check.y+" " + check.z);
+ }
+
+ // see if we have converged yet
+ dist = (p.x-n.x)*(p.x-n.x) + (p.y-n.y)*(p.y-n.y) +
+ (p.z-n.z)*(p.z-n.z);
+
+ if (debug) {
+ System.err.println("p->n distance =" + dist );
+ }
+
+ if( dist < EPSILON) { // close enough
+ converged = true;
+ new_point.set(n);
+ } else {
+ p.set(n);
+ count++;
+ if(count > 4 ){ // watch for cycling between two minimums
+ new_point.set(n);
+ converged = true;
+ }
+ }
+ }
+ }
+ if (debug) {
+ System.err.println("returning pnt ("+new_point.x+" "+
+ new_point.y+" "+new_point.z+")");
+
+ if(firstInside) System.err.println("input point inside polytope ");
+ }
+ return firstInside;
+ }
+
+ boolean intersect_ptope_sphere( BoundingPolytope polyTope,
+ BoundingSphere sphere) {
+ Point3d p = new Point3d();
+ boolean inside;
+
+
+ if (debug) {
+ System.err.println("ptope_sphere intersect sphere ="+sphere);
+ }
+ inside = closest_point( sphere.center, polyTope.planes, p );
+ if (debug) {
+ System.err.println("ptope sphere intersect point ="+p);
+ }
+ if (!inside){
+ // if distance between polytope and sphere center is greater than
+ // radius then no intersection
+ if (p.distanceSquared( sphere.center) >
+ sphere.radius*sphere.radius){
+ if (debug) {
+ System.err.println("ptope_sphere returns false");
+ }
+ return false;
+ } else {
+ if (debug) {
+ System.err.println("ptope_sphere returns true");
+ }
+ return true;
+ }
+ } else {
+ if (debug) {
+ System.err.println("ptope_sphere returns true");
+ }
+ return true;
+ }
+ }
+
+ boolean intersect_ptope_abox( BoundingPolytope polyTope, BoundingBox box) {
+ Vector4d planes[] = new Vector4d[6];
+
+ if (debug) {
+ System.err.println("ptope_abox, box = " + box);
+ }
+ planes[0] = new Vector4d( -1.0, 0.0, 0.0, box.lower.x);
+ planes[1] = new Vector4d( 1.0, 0.0, 0.0,-box.upper.x);
+ planes[2] = new Vector4d( 0.0,-1.0, 0.0, box.lower.y);
+ planes[3] = new Vector4d( 0.0, 1.0, 0.0,-box.upper.y);
+ planes[4] = new Vector4d( 0.0, 0.0,-1.0, box.lower.z);
+ planes[5] = new Vector4d( 0.0, 0.0, 1.0,-box.upper.z);
+
+
+ BoundingPolytope pbox = new BoundingPolytope( planes);
+
+ boolean result = intersect_ptope_ptope( polyTope, pbox );
+ if (debug) {
+ System.err.println("ptope_abox returns " + result);
+ }
+ return(result);
+ }
+
+
+ boolean intersect_ptope_ptope( BoundingPolytope poly1,
+ BoundingPolytope poly2) {
+ boolean intersect;
+ Point3d p = new Point3d();
+ Point3d g = new Point3d();
+ Point3d gnew = new Point3d();
+ Point3d pnew = new Point3d();
+
+ intersect = false;
+
+ p.x = 0.0;
+ p.y = 0.0;
+ p.z = 0.0;
+
+ // start from an arbitrary point on poly1
+ closest_point( p, poly1.planes, g);
+
+ // get the closest points on each polytope
+ if (debug) {
+ System.err.println("ptope_ptope: first g = "+g);
+ }
+ intersect = closest_point( g, poly2.planes, p);
+
+ if (intersect) {
+ return true;
+ }
+
+ if (debug) {
+ System.err.println("first p = "+p+"\n");
+ }
+ intersect = closest_point( p, poly1.planes, gnew);
+ if (debug) {
+ System.err.println("gnew = "+gnew+" intersect="+intersect);
+ }
+
+ // loop until the closest points on the two polytopes are not changing
+
+ double prevDist = p.distanceSquared(g);
+ double dist;
+
+ while( !intersect ) {
+
+ dist = p.distanceSquared(gnew);
+
+ if (dist < prevDist) {
+ g.set(gnew);
+ intersect = closest_point( g, poly2.planes, pnew );
+ if (debug) {
+ System.err.println("pnew = "+pnew+" intersect="+intersect);
+ }
+ } else {
+ g.set(gnew);
+ break;
+ }
+ prevDist = dist;
+ dist = pnew.distanceSquared(g);
+
+ if (dist < prevDist) {
+ p.set(pnew);
+ if( !intersect ) {
+ intersect = closest_point( p, poly1.planes, gnew );
+ if (debug) {
+ System.err.println("gnew = "+gnew+" intersect="+
+ intersect);
+ }
+ }
+ } else {
+ p.set(pnew);
+ break;
+ }
+ prevDist = dist;
+ }
+
+ if (debug) {
+ System.err.println("gnew="+" "+gnew.x+" "+gnew.y+" "+gnew.z);
+ System.err.println("pnew="+" "+pnew.x+" "+pnew.y+" "+pnew.z);
+ }
+ return intersect;
+ }
+
+
+ synchronized void setWithLock(Bounds b) {
+ this.set(b);
+ }
+
+ synchronized void getWithLock(Bounds b) {
+ b.set(this);
+ }
+
+ // Return one of Pick Bounds type define in PickShape
+ abstract int getPickType();
+}