package java3d; 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; public Bounds(){ } // public Bounds clone() { // return new Bounds(); // } @Override public abstract Object clone(); public abstract void combine(Bounds boundsObject); public abstract void transform(Transform3D trans); public abstract boolean intersect(Bounds boundsObject); // //浸食確認メソッド。radius(半径)を利用した円の接触であると仮定してみるといいかも // public boolean intersect(BoundingSphere bs) { // // TODO Auto-generated method stub // return false; // } 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; } }