Package javax.media.j3d

Source Code of javax.media.j3d.Bounds

/*
* 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 Vector4d1.0, 0.0, 0.0,-box.upper.x);
  planes[2] = new Vector4d0.0,-1.0, 0.0, box.lower.y);
  planes[3] = new Vector4d0.0, 1.0, 0.0,-box.upper.y);
  planes[4] = new Vector4d0.0, 0.0,-1.0, box.lower.z);
  planes[5] = new Vector4d0.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();
}
TOP

Related Classes of javax.media.j3d.Bounds

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.