diff options
author | Harvey Harrison <[email protected]> | 2015-04-19 21:02:06 -0700 |
---|---|---|
committer | Harvey Harrison <[email protected]> | 2015-04-19 21:02:06 -0700 |
commit | 7a2e20caac9db6f789a7b3fab344b9758af45335 (patch) | |
tree | b5236ff2570178de356eab569225108948eb4d30 /src/javax/media/j3d/Bounds.java | |
parent | f76ce302c4bb2a9f03bbee571ec5d05c29633023 (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.java | 673 |
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(); +} |