Package javax.media.j3d

Source Code of javax.media.j3d.BoundingBox

/*
* 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.Point3d;
import javax.vecmath.Point4d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector4d;

/**
*  This class defines an axis aligned bounding box which is used for
*  bounding regions.
*
*/

public class BoundingBox extends Bounds {

/**
* The corner of the bounding box with the numerically smallest values.
*/
final Point3d lower;

/**
* The corner of the bounding box with the numerically largest values.
*/
final Point3d upper;
    private static final double EPS = 1.0E-8;

/**
* Constructs and initializes a BoundingBox given min,max in x,y,z.
* @param lower the "small" corner
* @param upper the "large" corner
*/
public BoundingBox(Point3d lower, Point3d upper) {
  boundId = BOUNDING_BOX;
  this.lower = new Point3d(lower);
  this.upper = new Point3d(upper);
  updateBoundsStates();
}

/**
* Constructs and initializes a 2X bounding box about the origin. The lower
* corner is initialized to (-1.0d, -1.0d, -1.0d) and the upper corner is
* initialized to (1.0d, 1.0d, 1.0d).
*/
public BoundingBox() {
  boundId = BOUNDING_BOX;
  lower = new Point3d(-1.0d, -1.0d, -1.0d);
  upper = new Point3d( 1.0d1.0d1.0d);
  boundsIsEmpty = false;
  boundsIsInfinite = false;
}

/**
* Constructs a BoundingBox from a bounding object.
* @param boundsObject a bounds object
*/
public BoundingBox(Bounds boundsObject) {
  boundId = BOUNDING_BOX;
  lower = new Point3d();
  upper = new Point3d();

  if (boundsObject == null || boundsObject.boundsIsEmpty) {
    setEmptyBounds();
    return;
  }

  if (boundsObject.boundsIsInfinite) {
    setInfiniteBounds();
    return;
  }

  if( boundsObject.boundId == BOUNDING_BOX){
      BoundingBox box = (BoundingBox)boundsObject;

    lower.set(box.lower);
    upper.set(box.upper);
  }
  else if( boundsObject.boundId == BOUNDING_SPHERE ) {
      BoundingSphere sphere = (BoundingSphere)boundsObject;

    lower.set(sphere.center.x - sphere.radius,
              sphere.center.y - sphere.radius,
              sphere.center.z - sphere.radius);

    upper.set(sphere.center.x + sphere.radius,
              sphere.center.y + sphere.radius,
              sphere.center.z + sphere.radius);
  }
  else if(boundsObject.boundId == BOUNDING_POLYTOPE) {
      BoundingPolytope polytope = (BoundingPolytope)boundsObject;
      if( polytope.nVerts < 1 ) { // handle degenerate case
    lower.set(-1.0d, -1.0d, -1.0d);
    upper.set( 1.0d1.0d1.0d);
      } else {
      lower.set(polytope.verts[0]);
      upper.set(polytope.verts[0]);

    for(int i=1;i<polytope.nVerts;i++) {
        if( polytope.verts[i].x < lower.x )
      lower.x = polytope.verts[i].x;
        if( polytope.verts[i].y < lower.y )
      lower.y = polytope.verts[i].y;
        if( polytope.verts[i].z < lower.z )
      lower.z = polytope.verts[i].z;
        if( polytope.verts[i].x > upper.x )
      upper.x = polytope.verts[i].x;
        if( polytope.verts[i].y > upper.y )
      upper.y = polytope.verts[i].y;
        if( polytope.verts[i].z > upper.z )
      upper.z = polytope.verts[i].z;
    }
      }

  } else {
      throw new IllegalArgumentException(J3dI18N.getString("BoundingBox0"));
  }

        updateBoundsStates();
    }

/**
* Constructs a BoundingBox from an array of bounding objects.
* @param bounds an array of bounding objects
*/
public BoundingBox(Bounds[] bounds) {
  boundId = BOUNDING_BOX;
  upper = new Point3d();
  lower = new Point3d();

  if (bounds == null || bounds.length <= 0) {
    setEmptyBounds();
    return;
  }

  int i = 0;
       // find first non empty bounds object
       while ((i < bounds.length) && ((bounds[i] == null) || bounds[i].boundsIsEmpty)) {
     i++;
       }

  if (i >= bounds.length) {
    // all bounds objects were empty
    setEmptyBounds();
    return;
  }

       this.set(bounds[i++]);
       if(boundsIsInfinite)
     return;

       for(;i<bounds.length;i++) {
           if( bounds[i] == null );   // do nothing
           else if( bounds[i].boundsIsEmpty); // do nothing
     else if( bounds[i].boundsIsInfinite ) {
      setInfiniteBounds();
      return; // We're done.
     }
     else if(bounds[i].boundId == BOUNDING_BOX){
         BoundingBox box = (BoundingBox)bounds[i];

         if( lower.x > box.lower.x) lower.x = box.lower.x;
         if( lower.y > box.lower.y) lower.y = box.lower.y;
         if( lower.z > box.lower.z) lower.z = box.lower.z;
         if( upper.x < box.upper.x) upper.x = box.upper.x;
         if( upper.y < box.upper.y) upper.y = box.upper.y;
         if( upper.z < box.upper.z) upper.z = box.upper.z;

     }
     else if(bounds[i].boundId == BOUNDING_SPHERE) {
         BoundingSphere sphere = (BoundingSphere)bounds[i];
         if( lower.x > (sphere.center.x - sphere.radius))
       lower.x = sphere.center.x - sphere.radius;
         if( lower.y > (sphere.center.y - sphere.radius))
       lower.y = sphere.center.y - sphere.radius;
         if( lower.z > (sphere.center.z - sphere.radius))
       lower.z = sphere.center.z - sphere.radius;
         if( upper.x < (sphere.center.x + sphere.radius))
       upper.x = sphere.center.x + sphere.radius;
         if( upper.y < (sphere.center.y + sphere.radius))
       upper.y = sphere.center.y + sphere.radius;
         if( upper.z < (sphere.center.z + sphere.radius))
       upper.z = sphere.center.z + sphere.radius;
     }
     else if(bounds[i].boundId == BOUNDING_POLYTOPE) {
         BoundingPolytope polytope = (BoundingPolytope)bounds[i];

         for(i=0;i<polytope.nVerts;i++) { // XXXX: handle polytope with no verts
       if( polytope.verts[i].x < lower.x )
           lower.x = polytope.verts[i].x;
       if( polytope.verts[i].y < lower.y )
           lower.y = polytope.verts[i].y;
       if( polytope.verts[i].z < lower.z )
           lower.z = polytope.verts[i].z;
       if( polytope.verts[i].x > upper.x )
           upper.x = polytope.verts[i].x;
       if( polytope.verts[i].y > upper.y )
           upper.y = polytope.verts[i].y;
       if( polytope.verts[i].z > upper.z )
           upper.z = polytope.verts[i].z;
         }
     }
     else {
         throw new IllegalArgumentException(J3dI18N.getString("BoundingBox1"));
     }
       }
       updateBoundsStates();
    }

/**
* Gets the lower corner of this bounding box.
* @param p1 a Point to receive the lower corner of the bounding box
*/
public void getLower(Point3d p1) {
  p1.set(lower);
}

/**
* Sets the lower corner of this bounding box.
* @param xmin minimum x value of bounding box
* @param ymin minimum y value of bounding box
* @param zmin minimum z value of bounding box
*/
public void setLower(double xmin, double ymin, double zmin) {
  lower.set(xmin, ymin, zmin);
  updateBoundsStates();
}

/**
* Sets the lower corner of this bounding box.
* @param p1 a Point defining the new lower corner of the bounding box
*/
public void setLower(Point3d p1) {
  lower.set(p1);
  updateBoundsStates();
}

/**
* Gets the upper corner of this bounding box.
* @param p1 a Point to receive the upper corner of the bounding box
*/
public void getUpper(Point3d p1) {
  p1.set(upper);
}

/**
* Sets the upper corner of this bounding box.
* @param xmax max x value of bounding box
* @param ymax max y value of bounding box
* @param zmax max z value of bounding box
*/
public void setUpper(double xmax, double ymax, double zmax) {
  upper.set(xmax, ymax, zmax);
  updateBoundsStates();
}

/**
* Sets the upper corner of this bounding box.
* @param p1 a Point defining the new upper corner of the bounding box
*/
public void setUpper(Point3d p1) {
  upper.set(p1);
  updateBoundsStates();
}

    /**
     * Sets the the value of this BoundingBox
     * @param boundsObject another bounds object
     */
    @Override
    public void set(Bounds  boundsObject) {
      int i;

  if (boundsObject == null || boundsObject.boundsIsEmpty) {
    setEmptyBounds();
    return;
  }

  if (boundsObject.boundsIsInfinite) {
    setInfiniteBounds();
    return;
  }

      if( boundsObject.boundId == BOUNDING_BOX){
    BoundingBox box = (BoundingBox)boundsObject;

    lower.x = box.lower.x;
    lower.y = box.lower.y;
    lower.z = box.lower.z;
    upper.x = box.upper.x;
    upper.y = box.upper.y;
    upper.z = box.upper.z;

      } else if( boundsObject.boundId == BOUNDING_SPHERE ) {
    BoundingSphere sphere = (BoundingSphere)boundsObject;
    lower.x = sphere.center.x - sphere.radius;
    lower.y = sphere.center.y - sphere.radius;
    lower.z = sphere.center.z - sphere.radius;
    upper.x = sphere.center.x + sphere.radius;
    upper.y = sphere.center.y + sphere.radius;
    upper.z = sphere.center.z + sphere.radius;

      } else if(boundsObject.boundId == BOUNDING_POLYTOPE) {
    BoundingPolytope polytope = (BoundingPolytope)boundsObject;
    lower.x = upper.x = polytope.verts[0].x;
    lower.y = upper.y = polytope.verts[0].y;
    lower.z = upper.z = polytope.verts[0].z;

    for(i=1;i<polytope.nVerts;i++) {
        if( polytope.verts[i].x < lower.x ) lower.x = polytope.verts[i].x;
        if( polytope.verts[i].y < lower.y ) lower.y = polytope.verts[i].y;
        if( polytope.verts[i].z < lower.z ) lower.z = polytope.verts[i].z;
        if( polytope.verts[i].x > upper.x ) upper.x = polytope.verts[i].x;
        if( polytope.verts[i].y > upper.y ) upper.y = polytope.verts[i].y;
        if( polytope.verts[i].z > upper.z ) upper.z = polytope.verts[i].z;
    }

      } else {
    throw new IllegalArgumentException(J3dI18N.getString("BoundingBox0"));
      }

      updateBoundsStates();
    }


    /**
     * Creates a copy of this bounding box.
     * @return a new bounding box
     */
    @Override
    public Object clone() {
  return new BoundingBox(this.lower, this.upper);
    }


    /**
     * Indicates whether the specified <code>bounds</code> object is
     * equal to this BoundingBox object.  They are equal if the
     * specified <code>bounds</code> object is an instance of
     * BoundingBox and all of the data
     * members of <code>bounds</code> are equal to the corresponding
     * data members in this BoundingBox.
     * @param bounds the object with which the comparison is made.
     * @return true if this BoundingBox is equal to <code>bounds</code>;
     * otherwise false
     *
     * @since Java 3D 1.2
     */
    @Override
    public boolean equals(Object bounds) {
  try {
      BoundingBox box = (BoundingBox)bounds;
      return (lower.equals(box.lower) &&
        upper.equals(box.upper));
  }
  catch (NullPointerException e) {
      return false;
  }
        catch (ClassCastException e) {
      return false;
  }
    }


    /**
     * Returns a hash code value for this BoundingBox object
     * based on the data values in this object.  Two different
     * BoundingBox objects with identical data values (i.e.,
     * BoundingBox.equals returns true) will return the same hash
     * code value.  Two BoundingBox objects with different data
     * members may return the same hash code value, although this is
     * not likely.
     * @return a hash code value for this BoundingBox object.
     *
     * @since Java 3D 1.2
     */
    @Override
    public int hashCode() {
  long bits = 1L;
  bits = J3dHash.mixDoubleBits(bits, lower.x);
  bits = J3dHash.mixDoubleBits(bits, lower.y);
  bits = J3dHash.mixDoubleBits(bits, lower.z);
  bits = J3dHash.mixDoubleBits(bits, upper.x);
  bits = J3dHash.mixDoubleBits(bits, upper.y);
  bits = J3dHash.mixDoubleBits(bits, upper.z);
  return J3dHash.finish(bits);
    }


    /**
     * Combines this bounding box with a bounding object   so that the
     * resulting bounding box encloses the original bounding box and the
     * specified bounds object.
     * @param boundsObject another bounds object
     */
    @Override
    public void combine(Bounds boundsObject) {

  if((boundsObject == null) || (boundsObject.boundsIsEmpty)
     || (boundsIsInfinite))
      return;

  if((boundsIsEmpty) || (boundsObject.boundsIsInfinite)) {
      this.set(boundsObject);
      return;
  }

  if( boundsObject.boundId == BOUNDING_BOX){
      BoundingBox box = (BoundingBox)boundsObject;

      if( lower.x > box.lower.x) lower.x = box.lower.x;
      if( lower.y > box.lower.y) lower.y = box.lower.y;
      if( lower.z > box.lower.z) lower.z = box.lower.z;
      if( upper.x < box.upper.x) upper.x = box.upper.x;
      if( upper.y < box.upper.y) upper.y = box.upper.y;
      if( upper.z < box.upper.z) upper.z = box.upper.z;

  }
  else if( boundsObject.boundId == BOUNDING_SPHERE ) {
      BoundingSphere sphere = (BoundingSphere)boundsObject;
      if( lower.x > (sphere.center.x - sphere.radius))
    lower.x = sphere.center.x - sphere.radius;
      if( lower.y > (sphere.center.y - sphere.radius))
    lower.y = sphere.center.y - sphere.radius;
      if( lower.z > (sphere.center.z - sphere.radius))
    lower.z = sphere.center.z - sphere.radius;
      if( upper.x < (sphere.center.x + sphere.radius))
    upper.x = sphere.center.x + sphere.radius;
      if( upper.y < (sphere.center.y + sphere.radius))
    upper.y = sphere.center.y + sphere.radius;
      if( upper.z < (sphere.center.z + sphere.radius))
    upper.z = sphere.center.z + sphere.radius;

  }
  else if(boundsObject.boundId == BOUNDING_POLYTOPE) {
      BoundingPolytope polytope = (BoundingPolytope)boundsObject;
      int i;
      for(i=1;i<polytope.nVerts;i++) {
                if( polytope.verts[i].x < lower.x ) lower.x = polytope.verts[i].x;
                if( polytope.verts[i].y < lower.y ) lower.y = polytope.verts[i].y;
                if( polytope.verts[i].z < lower.z ) lower.z = polytope.verts[i].z;
                if( polytope.verts[i].x > upper.x ) upper.x = polytope.verts[i].x;
                if( polytope.verts[i].y > upper.y ) upper.y = polytope.verts[i].y;
                if( polytope.verts[i].z > upper.z ) upper.z = polytope.verts[i].z;
      }
  } else {
      throw new IllegalArgumentException(J3dI18N.getString("BoundingBox3"));
  }

        updateBoundsStates();
    }

    /**
     * Combines this bounding box with an array of bounding objects
     * so that the resulting bounding box encloses the original bounding
     * box and the array of bounding objects.
     * @param bounds an array of bounds objects
     */
    @Override
    public void combine(Bounds[] bounds) {
       int i=0;

       if( (bounds == null) || (bounds.length <= 0)
     || (boundsIsInfinite))
     return;

       // find first non empty bounds object
       while( (i<bounds.length) && ((bounds[i]==null) || bounds[i].boundsIsEmpty)) {
     i++;
       }
       if( i >= bounds.length)
     return;   // no non empty bounds so do not modify current bounds

       if(boundsIsEmpty)
     this.set(bounds[i++]);

       if(boundsIsInfinite)
     return;

       for(;i<bounds.length;i++) {
          if( bounds[i] == null )// do nothing
          else if( bounds[i].boundsIsEmpty); // do nothing
    else if( bounds[i].boundsIsInfinite ) {
        lower.x = lower.y = lower.z = Double.NEGATIVE_INFINITY;
        upper.x = upper.y = upper.z = Double.POSITIVE_INFINITY;
        break// We're done.
    }
    else if( bounds[i].boundId == BOUNDING_BOX){
         BoundingBox box = (BoundingBox)bounds[i];

              if( lower.x > box.lower.x) lower.x = box.lower.x;
              if( lower.y > box.lower.y) lower.y = box.lower.y;
              if( lower.z > box.lower.z) lower.z = box.lower.z;
              if( upper.x < box.upper.x) upper.x = box.upper.x;
              if( upper.y < box.upper.y) upper.y = box.upper.y;
              if( upper.z < box.upper.z) upper.z = box.upper.z;
    }
    else if( bounds[i].boundId == BOUNDING_SPHERE ) {
        BoundingSphere sphere = (BoundingSphere)bounds[i];
              if( lower.x > (sphere.center.x - sphere.radius))
      lower.x = sphere.center.x - sphere.radius;
              if( lower.y > (sphere.center.y - sphere.radius))
      lower.y = sphere.center.y - sphere.radius;
              if( lower.z > (sphere.center.z - sphere.radius))
      lower.z = sphere.center.z - sphere.radius;
              if( upper.x < (sphere.center.x + sphere.radius))
      upper.x = sphere.center.x + sphere.radius;
              if( upper.y < (sphere.center.y + sphere.radius))
      upper.y = sphere.center.y + sphere.radius;
              if( upper.z < (sphere.center.z + sphere.radius))
      upper.z = sphere.center.z + sphere.radius;
    }
    else if(bounds[i].boundId == BOUNDING_POLYTOPE) {
         BoundingPolytope polytope = (BoundingPolytope)bounds[i];
              for(i=1;i<polytope.nVerts;i++) {
                if( polytope.verts[i].x < lower.x ) lower.x = polytope.verts[i].x;
                if( polytope.verts[i].y < lower.y ) lower.y = polytope.verts[i].y;
                if( polytope.verts[i].z < lower.z ) lower.z = polytope.verts[i].z;
                if( polytope.verts[i].x > upper.x ) upper.x = polytope.verts[i].x;
                if( polytope.verts[i].y > upper.y ) upper.y = polytope.verts[i].y;
                if( polytope.verts[i].z > upper.z ) upper.z = polytope.verts[i].z;
              }
    } else {
        throw new IllegalArgumentException(J3dI18N.getString("BoundingBox4"));
     }
       }

       updateBoundsStates();
    }

    /**
     * Combines this bounding box with a point so that the resulting
     * bounding box encloses the original bounding box and the point.
     * @param point a 3d point in space
     */
    @Override
    public void combine(Point3d point) {

  if( boundsIsInfinite) {
      return;
  }

  if( boundsIsEmpty) {
            upper.x = lower.x = point.x;
            upper.y = lower.y = point.y;
            upper.z = lower.z = point.z;
  } else {
      if( point.x > upper.x) upper.x = point.x;
         if( point.y > upper.y) upper.y = point.y;
      if( point.z > upper.z) upper.z = point.z;

      if( point.x < lower.x) lower.x = point.x;
      if( point.y < lower.y) lower.y = point.y;
      if( point.z < lower.z) lower.z = point.z;
  }

         updateBoundsStates();
    }

    /**
     * Combines this bounding box with an array of points so that the
     * resulting bounding box encloses the original bounding box and the
     * array of points.
     * @param points an array of 3d points in space
     */
    @Override
    public void combine(Point3d[] points) {

  int i;

  if( boundsIsInfinite) {
      return;
  }

  if( boundsIsEmpty) {
      this.setUpper(points[0]);
      this.setLower(points[0]);
  }

  for(i=0;i<points.length;i++) {
      if( points[i].x > upper.x) upper.x = points[i].x;
      if( points[i].y > upper.y) upper.y = points[i].y;
      if( points[i].z > upper.z) upper.z = points[i].z;

      if( points[i].x < lower.x) lower.x = points[i].x;
      if( points[i].y < lower.y) lower.y = points[i].y;
      if( points[i].z < lower.z) lower.z = points[i].z;
  }

        updateBoundsStates();
    }

    /**
     * Modifies the bounding box 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) {
    setEmptyBounds();
    return;
  }

  if (boundsObject.boundsIsInfinite) {
    setInfiniteBounds();
    return;
  }

  if(boundsObject.boundId == BOUNDING_BOX){
    this.set(boundsObject);
    this.transform(matrix);
  }
  else if(boundsObject.boundId == BOUNDING_SPHERE) {
    BoundingSphere tmpSphere = new BoundingSphere(boundsObject);
    tmpSphere.transform(matrix);
    this.set(tmpSphere);
  }
  else if(boundsObject.boundId == BOUNDING_POLYTOPE) {
    BoundingPolytope tmpPolytope = new BoundingPolytope(boundsObject);
    tmpPolytope.transform(matrix);
    this.set(tmpPolytope);
  }
  else {
      throw new IllegalArgumentException(J3dI18N.getString("BoundingBox5"));
  }
    }

    /**
     * Transforms this bounding box by the given matrix.
     * @param matrix a transformation matrix
     */
    @Override
    public void transform(Transform3D matrix) {

  if (boundsIsInfinite)
    return;

  Point3d tmpP3d = new Point3d();

  double ux, uy, uz, lx, ly, lz;
  ux = upper.x; uy = upper.y; uz = upper.z;
  lx = lower.x; ly = lower.y; lz = lower.z;

  tmpP3d.set(ux, uy, uz);
  matrix.transform( tmpP3d );
  upper.x = tmpP3d.x;
  upper.y = tmpP3d.y;
  upper.z = tmpP3d.z;
  lower.x = tmpP3d.x;
  lower.y = tmpP3d.y;
  lower.z = tmpP3d.z;

  tmpP3d.set(lx, uy, uz);
  matrix.transform( tmpP3d );
  if ( tmpP3d.x  > upper.x ) upper.x = tmpP3d.x;
  if ( tmpP3d.y  > upper.y ) upper.y = tmpP3d.y;
  if ( tmpP3d.z  > upper.z ) upper.z = tmpP3d.z;
  if ( tmpP3d.x  < lower.x ) lower.x = tmpP3d.x;
  if ( tmpP3d.y  < lower.y ) lower.y = tmpP3d.y;
  if ( tmpP3d.z  < lower.z ) lower.z = tmpP3d.z;

  tmpP3d.set(lx, ly, uz);
  matrix.transform( tmpP3d );
  if ( tmpP3d.x  > upper.x ) upper.x = tmpP3d.x;
  if ( tmpP3d.y  > upper.y ) upper.y = tmpP3d.y;
  if ( tmpP3d.z  > upper.z ) upper.z = tmpP3d.z;
  if ( tmpP3d.x  < lower.x ) lower.x = tmpP3d.x;
  if ( tmpP3d.y  < lower.y ) lower.y = tmpP3d.y;
  if ( tmpP3d.z  < lower.z ) lower.z = tmpP3d.z;

  tmpP3d.set(ux, ly, uz);
  matrix.transform( tmpP3d );
  if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x;
  if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y;
  if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z;
  if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x;
  if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y;
  if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z;

  tmpP3d.set(lx, uy, lz);
  matrix.transform( tmpP3d );
  if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x;
  if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y;
  if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z;
  if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x;
  if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y;
  if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z;

  tmpP3d.set(ux, uy, lz);
  matrix.transform( tmpP3d );
  if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x;
  if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y;
  if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z;
  if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x;
  if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y;
  if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z;

  tmpP3d.set(lx, ly, lz);
  matrix.transform( tmpP3d );
  if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x;
  if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y;
  if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z;
  if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x;
  if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y;
  if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z;

  tmpP3d.set(ux, ly, lz);
  matrix.transform( tmpP3d );
  if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x;
  if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y;
  if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z;
  if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x;
  if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y;
  if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z;

    }

    /**
     * Test for intersection with a ray.
     * @param origin the starting point of the ray
     * @param direction the direction of the ray
     * @param position3 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 t1,t2,tmp,tnear,tfar,invDir,invMag;
  double dirx, diry, dirz;

  /*
    System.err.println("BoundingBox.intersect(p,d,p) called\n");
    System.err.println("bounds = " + lower + " -> " + upper);
    */

  if( boundsIsEmpty ) {
      return false;
  }

  if( boundsIsInfinite ) {
      position.x = origin.x;
      position.y = origin.y;
      position.z = origin.z;
      position.w = 0.0;
      return true;
  }

  double dirLen = direction.x*direction.x + direction.y*direction.y +
      direction.z*direction.z;

  // Handle zero length direction vector.
  if(dirLen == 0.0)
      return intersect(origin, position);

  invMag = 1.0/Math.sqrt(dirLen);
  dirx = direction.x*invMag;
  diry = direction.y*invMag;
  dirz = direction.z*invMag;

  /*
    System.err.println("dir = " + dirx + ", " + diry + ", " + dirz);
    System.err.println("origin = " + origin);
    */

  // initialize tnear and tfar to handle dir.? == 0 cases
  tnear = -Double.MAX_VALUE;
  tfar = Double.MAX_VALUE;

  if(dirx == 0.0) {
      //System.err.println("dirx == 0.0");
      if (origin.x < lower.x || origin.x > upper.x ) {
    //System.err.println( "parallel to x plane and outside");
    return false;
      }
  } else {
      invDir = 1.0/dirx;
      t1 = (lower.x-origin.x)*invDir;
      t2 = (upper.x-origin.x)*invDir;

      //System.err.println("x t1 = " + t1 + " t2 = " + t2);
      if( t1 > t2) {
    tnear = t2;
    tfar = t1;
      }else {
    tnear = t1;
    tfar = t2;
      }
      if( tfar < 0.0 ) {
    //System.err.println( "x failed: tnear="+tnear+"  tfar="+tfar);
    return false;
      }
      //System.err.println("x tnear = " + tnear + " tfar = " + tfar);
  }
  // y
  if (diry == 0.0) {
      //System.err.println("diry == 0.0");
      if( origin.y < lower.y || origin.y > upper.y ){
    //System.err.println( "parallel to y plane and outside");
    return false;
            }
  } else {
      invDir = 1.0/diry;
      //System.err.println("invDir = " + invDir);
      t1 = (lower.y-origin.y)*invDir;
      t2 = (upper.y-origin.y)*invDir;

      if( t1 > t2) {
    tmp = t1;
    t1 = t2;
    t2 = tmp;
      }
      //System.err.println("y t1 = " + t1 + " t2 = " + t2);
      if( t1 > tnear) tnear = t1;
      if( t2 < tfar ) tfar  = t2;

      if( (tfar < 0.0) ||  (tnear > tfar)){
    //System.err.println( "y failed: tnear="+tnear+"  tfar="+tfar);
    return false;
      }
      //System.err.println("y tnear = " + tnear + " tfar = " + tfar);
  }

  // z
  if (dirz == 0.0) {
      //System.err.println("dirz == 0.0");
      if( origin.z < lower.z || origin.z > upper.z ) {
    //System.err.println( "parallel to z plane and outside");
    return false;
      }
  }  else {
      invDir = 1.0/dirz;
      t1 = (lower.z-origin.z)*invDir;
      t2 = (upper.z-origin.z)*invDir;

      if( t1 > t2) {
    tmp = t1;
    t1 = t2;
    t2 = tmp;
      }
      //System.err.println("z t1 = " + t1 + " t2 = " + t2);
      if( t1 > tnear) tnear = t1;
      if( t2 < tfar ) tfar  = t2;

      if( (tfar < 0.0) ||  (tnear > tfar)){
    //System.err.println( "z failed: tnear="+tnear+"  tfar="+tfar);
    return false;
      }
      //System.err.println("z tnear = " + tnear + " tfar = " + tfar);
  }

  if((tnear < 0.0) && (tfar >= 0.0)) {
      // origin is inside the BBox.
      position.x = origin.x + dirx*tfar;
      position.y = origin.y + diry*tfar;
      position.z = origin.z + dirz*tfar;
      position.w = tfar;
  }
  else {
      position.x = origin.x + dirx*tnear;
      position.y = origin.y + diry*tnear;
      position.z = origin.z + dirz*tnear;
      position.w = tnear;
  }

  return true;

    }


    /**
     * Test for intersection with a point.
     * @param point the pick point
     * @param position 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 ) {

        if( boundsIsEmpty ) {
     return false;
        }

       if( boundsIsInfinite ) {
     position.x = point.x;
     position.y = point.y;
     position.z = point.z;
     position.w = 0.0;
     return true;
       }

       if( point.x <= upper.x && point.x >= lower.x &&
     point.y <= upper.y && point.y >= lower.y &&
     point.z <= upper.z && point.z >= lower.z)  {
     position.x = point.x;
     position.y = point.y;
     position.z = point.z;
     position.w = 0.0;
     return true;
       } else
     return false;

    }

   /**
    * Test for intersection with a segment.
    * @param start a point defining  the start of the line segment
    * @param end a point defining the end of the line segment
    * @param position 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 t1,t2,tmp,tnear,tfar,invDir,invMag;
      double dirx, diry, dirz;

      if( boundsIsEmpty ) {
    return false;
      }

      if( boundsIsInfinite ) {
    position.x = start.x;
    position.y = start.y;
    position.z = start.z;
    position.w = 0.0;
    return true;
      }

      dirx = end.x - start.x;
      diry = end.y - start.y;
      dirz = end.z - start.z;

      double dirLen = dirx*dirx + diry*diry + dirz*dirz;

      // Optimization : Handle zero length direction vector.
      if(dirLen == 0.0)
    return intersect(start, position);

      dirLen = Math.sqrt(dirLen);
      // System.err.println("dirLen is " + dirLen);
      invMag = 1.0/dirLen;
      dirx = dirx*invMag;
      diry = diry*invMag;
      dirz = dirz*invMag;

      /*
  System.err.println("dir = " + dir);
  System.err.println("start = " + start);
  System.err.println("lower = " + lower);
  System.err.println("upper = " + upper);
  */

      // initialize tnear and tfar to handle dir.? == 0 cases
      tnear = -Double.MAX_VALUE;
      tfar = Double.MAX_VALUE;

        if(dirx == 0.0) {
            //System.err.println("dirx == 0.0");
            if (start.x < lower.x || start.x > upper.x ) {
    //System.err.println( "parallel to x plane and outside");
    return false;
            }
  } else {
            invDir = 1.0/dirx;
            t1 = (lower.x-start.x)*invDir;
            t2 = (upper.x-start.x)*invDir;

            //System.err.println("x t1 = " + t1 + " t2 = " + t2);
      if( t1 > t2) {
    tnear = t2;
    tfar = t1;
      }else {
    tnear = t1;
    tfar = t2;
      }
      if( tfar < 0.0 ) {
    //System.err.println( "x failed: tnear="+tnear+"  tfar="+tfar);
    return false;
      }
            //System.err.println("x tnear = " + tnear + " tfar = " + tfar);
        }
  // y
        if (diry == 0.0) {
            //System.err.println("diry == 0.0");
            if( start.y < lower.y || start.y > upper.y ){
    //System.err.println( "parallel to y plane and outside");
    return false;
            }
        } else {
            invDir = 1.0/diry;
            //System.err.println("invDir = " + invDir);
            t1 = (lower.y-start.y)*invDir;
            t2 = (upper.y-start.y)*invDir;

            if( t1 > t2) {
    tmp = t1;
    t1 = t2;
    t2 = tmp;
            }
            //System.err.println("y t1 = " + t1 + " t2 = " + t2);
            if( t1 > tnear) tnear = t1;
            if( t2 < tfar ) tfar  = t2;

            if( (tfar < 0.0) ||  (tnear > tfar)){
    //System.err.println( "y failed: tnear="+tnear+"  tfar="+tfar);
    return false;
            }
            //System.err.println("y tnear = " + tnear + " tfar = " + tfar);
        }

  // z
        if (dirz == 0.0) {
            //System.err.println("dirz == 0.0");
            if( start.z < lower.z || start.z > upper.z ) {
    //System.err.println( "parallel to z plane and outside");
    return false;
            }
        }  else {
            invDir = 1.0/dirz;
            t1 = (lower.z-start.z)*invDir;
            t2 = (upper.z-start.z)*invDir;

            if( t1 > t2) {
    tmp = t1;
    t1 = t2;
    t2 = tmp;
            }
            //System.err.println("z t1 = " + t1 + " t2 = " + t2);
            if( t1 > tnear) tnear = t1;
            if( t2 < tfar ) tfar  = t2;

            if( (tfar < 0.0) ||  (tnear > tfar)){
    //System.err.println( "z failed: tnear="+tnear+"  tfar="+tfar);
    return false;
            }
            //System.err.println("z tnear = " + tnear + " tfar = " + tfar);
        }

  if((tnear < 0.0) && (tfar >= 0.0)) {
      // origin is inside the BBox.
       position.x = start.x + dirx*tfar;
      position.y = start.y + diry*tfar;
      position.z = start.z + dirz*tfar;
      position.w = tfar;
  }
  else {
      if(tnear>dirLen) {
    // Segment is behind BBox.
    /*
      System.err.println("PickSegment : intersected postion : " + position
      + " tnear " + tnear + " tfar " + tfar );
      */
    return false;
      }
      position.x = start.x + dirx*tnear;
            position.y = start.y + diry*tnear;
            position.z = start.z + dirz*tnear;

            position.w = tnear;
        }

  /*
      System.err.println("tnear = " + tnear + " tfar = " + tfar + " w " +
      position.w);
      System.err.println("lower = " + lower);
      System.err.println("upper = " + upper + "\n");
  */
        return true;

  }

    /**
     * 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 ) {

        if( boundsIsEmpty ) {
      return false;
        }

  if( boundsIsInfinite ) {
      return true;
  }

  Point3d p=new Point3d();
  return intersect( origin, direction, p );
    }

    /**
     * A protected intersect method that returns the point of intersection.
     * Used by Picking methods to sort or return closest picked item.
     */
    boolean intersect(Point3d origin, Vector3d direction, Point3d intersect ) {
  double theta=0.0;

        if( boundsIsEmpty ) {
     return false;
        }

  if( boundsIsInfinite ) {
    intersect.x = origin.x;
    intersect.y = origin.y;
    intersect.z = origin.z;
    return true;
  }

  if (direction.x > 0.0 )
      theta = Math.max( theta, (lower.x - origin.x)/direction.x );
  if (direction.x < 0.0 )
      theta = Math.max( theta, (upper.x - origin.x)/direction.x );
  if (direction.y > 0.0 )
      theta = Math.max( theta, (lower.y - origin.y)/direction.y );
  if (direction.y < 0.0 )
      theta = Math.max( theta, (upper.y - origin.y)/direction.y );
  if (direction.z > 0.0 )
      theta = Math.max( theta, (lower.z - origin.z)/direction.z );
  if (direction.z < 0.0 )
      theta = Math.max( theta, (upper.z - origin.z)/direction.z );

  intersect.x = origin.x + theta*direction.x;
  intersect.y = origin.y + theta*direction.y;
  intersect.z = origin.z + theta*direction.z;

  if (intersect.x < (lower.x-EPS)) return false;
  if (intersect.x > (upper.x+EPS)) return false;
  if (intersect.y < (lower.y-EPS)) return false;
  if (intersect.y > (upper.y+EPS)) return false;
  if (intersect.z < (lower.z-EPS)) return false;
  if (intersect.z > (upper.z+EPS)) return false;

        return true;

    }

    /**
     * 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 ) {

        if( boundsIsEmpty ) {
     return false;
        }
  if( boundsIsInfinite ) {
    return true;
  }

  if( point.x <= upper.x && point.x >= lower.x &&
      point.y <= upper.y && point.y >= lower.y &&
      point.z <= upper.z && point.z >= lower.z)
      return true;
        else
      return false;
    }
    /**
     * Tests whether the bounding box is empty.  A bounding box 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 box
     * with a volume of zero is <i>not</i> empty.
     * @return true if the bounding box is empty; otherwise, it returns false
     */
    @Override
    public boolean isEmpty() {

   return boundsIsEmpty;
    }

   /**
     * 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_BOX){
      BoundingBox box = (BoundingBox)boundsObject;
      // both boxes are axis aligned
      if( upper.x > box.lower.x && box.upper.x > lower.x &&
    upper.y > box.lower.y && box.upper.y > lower.y &&
    upper.z > box.lower.z && box.upper.z > lower.z )
    return true;
      else
    return false;
  } else if( boundsObject.boundId == BOUNDING_SPHERE) {
      BoundingSphere sphere = (BoundingSphere)boundsObject;
      double rad_sq = sphere.radius*sphere.radius;
      double dis = 0.0;

      if( sphere.center.x < lower.x )
    dis = (sphere.center.x-lower.x)*(sphere.center.x-lower.x);
      else
    if( sphere.center.x > upper.x )
        dis = (sphere.center.x-upper.x)*(sphere.center.x-upper.x);

      if( sphere.center.y < lower.y )
    dis += (sphere.center.y-lower.y)*(sphere.center.y-lower.y);
      else
    if( sphere.center.y > upper.y )
        dis += (sphere.center.y-upper.y)*(sphere.center.y-upper.y);

      if( sphere.center.z < lower.z )
    dis += (sphere.center.z-lower.z)*(sphere.center.z-lower.z);
      else
    if( sphere.center.z > upper.z )
        dis += (sphere.center.z-upper.z)*(sphere.center.z-upper.z);

      if( dis <= rad_sq )
    return true;
      else
    return false;
        } else if(boundsObject.boundId == BOUNDING_POLYTOPE) {
      // intersect an axis aligned box with a polytope
      return intersect_ptope_abox ( (BoundingPolytope)boundsObject, this );
        } else {
            throw new IllegalArgumentException(J3dI18N.getString("BoundingBox6"));
        }

    }

    /**
     * Test for intersection with an array of bounds objects.
     * @param boundsObjects an array of bounding objects
     * @return true or false indicating if an intersection occured
     */
    @Override
    public boolean intersect(Bounds[] boundsObjects) {

  int i;

  if( boundsObjects == null || boundsObjects.length <= )  {
      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.
      }
      else if( boundsObjects[i].boundId == BOUNDING_BOX){
    BoundingBox box = (BoundingBox)boundsObjects[i];
    // both boxes are axis aligned
    if( upper.x > box.lower.x && box.upper.x > lower.x &&
        upper.y > box.lower.y && box.upper.y > lower.y &&
        upper.z > box.lower.z && box.upper.z > lower.z )
        return true;
      }
      else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) {
    BoundingSphere sphere = (BoundingSphere)boundsObjects[i];
    double rad_sq = sphere.radius*sphere.radius;
    double dis = 0.0;

    if( sphere.center.x < lower.x )
        dis = (sphere.center.x-lower.x)*(sphere.center.x-lower.x);
    else
        if( sphere.center.x > upper.x )
      dis = (sphere.center.x-upper.x)*(sphere.center.x-upper.x);

    if( sphere.center.y < lower.y )
        dis += (sphere.center.y-lower.y)*(sphere.center.y-lower.y);
    else
        if( sphere.center.y > upper.y )
      dis += (sphere.center.y-upper.y)*(sphere.center.y-upper.y);

    if( sphere.center.z < lower.z )
        dis += (sphere.center.z-lower.z)*(sphere.center.z-lower.z);
    else
        if( sphere.center.z > upper.z )
      dis += (sphere.center.z-upper.z)*(sphere.center.z-upper.z);

    if( dis <= rad_sq )
        return true;

      }
      else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) {
    if( intersect_ptope_abox ( (BoundingPolytope)boundsObjects[i], this ))
        return true;
      }
      else {
    //         System.err.println("intersect ?? ");
      }
  }

  return false;
    }

    /**
     * Test for intersection with another bounding box.
     * @param boundsObject another bounding object
     * @param newBoundBox the new bounding box which is the intersection of
     *        the boundsObject and this BoundingBox
     * @return true or false indicating if an intersection occured
     */
    public boolean intersect(Bounds boundsObject, BoundingBox newBoundBox) {

  if((boundsObject == null) || boundsIsEmpty || boundsObject.boundsIsEmpty ) {
    newBoundBox.set((Bounds)null);
      return false;
        }


  if(boundsIsInfinite && (!boundsObject.boundsIsInfinite)) {
      newBoundBox.set(boundsObject);
      return true;
  }
  else if((!boundsIsInfinite) && boundsObject.boundsIsInfinite) {
      newBoundBox.set(this);
      return true;
  }
  else if(boundsIsInfinite && boundsObject.boundsIsInfinite) {
      newBoundBox.set(this);
      return true;
  }
  else if( boundsObject.boundId == BOUNDING_BOX){
      BoundingBox box = (BoundingBox)boundsObject;
      // both boxes are axis aligned
      if( upper.x > box.lower.x && box.upper.x > lower.x &&
    upper.y > box.lower.y && box.upper.y > lower.y &&
    upper.z > box.lower.z && box.upper.z > lower.z ){


    if(upper.x > box.upper.x)
        newBoundBox.upper.x = box.upper.x;
    else
        newBoundBox.upper.x = upper.x;

    if(upper.y > box.upper.y)
        newBoundBox.upper.y = box.upper.y;
    else
        newBoundBox.upper.y = upper.y;

    if(upper.z > box.upper.z)
        newBoundBox.upper.z = box.upper.z;
    else
        newBoundBox.upper.z = upper.z;

    if(lower.x < box.lower.x)
        newBoundBox.lower.x = box.lower.x;
    else
        newBoundBox.lower.x = lower.x;

    if(lower.y < box.lower.y)
        newBoundBox.lower.y = box.lower.y;
    else
        newBoundBox.lower.y = lower.y;

    if(lower.z < box.lower.z)
        newBoundBox.lower.z = box.lower.z;
    else
        newBoundBox.lower.z = lower.z;

    newBoundBox.updateBoundsStates();
    return true;
      } else {
    // Negative volume.
      newBoundBox.set((Bounds)null);
    return false;
      }
        }
  else if( boundsObject.boundId == BOUNDING_SPHERE) {
      BoundingSphere sphere = (BoundingSphere)boundsObject;
      if( this.intersect( sphere) ) {
    BoundingBox sbox = new BoundingBox( sphere );
    this.intersect( sbox, newBoundBox );
    return true;
      } else {
    // Negative volume.
      newBoundBox.set((Bounds)null);
    return false;
      }

            //      System.err.println("intersect Sphere ");
        }
  else if(boundsObject.boundId == BOUNDING_POLYTOPE) {
      BoundingPolytope polytope = (BoundingPolytope)boundsObject;
      if( this.intersect( polytope)) {
    BoundingBox pbox = new BoundingBox( polytope); // convert polytope to box
    this.intersect( pbox, newBoundBox );
    return true;
      } else {
    // Negative volume.
      newBoundBox.set((Bounds)null);
    return false;
      }
        } else {
            throw new IllegalArgumentException(J3dI18N.getString("BoundingBox7"));
        }
    }

    /**
     * Test for intersection with an array of  bounds objects.
     * @param boundsObjects an array of  bounds objects
     * @param newBoundBox the new bounding box which is the intersection of
     *        the boundsObject and this BoundingBox
     * @return true or false indicating if an intersection occured
     */
    public boolean intersect(Bounds[] boundsObjects, BoundingBox newBoundBox) {

       if( boundsObjects == null || boundsObjects.length <= 0 ||  boundsIsEmpty ) {
    // Negative volume.
    newBoundBox.set((Bounds)null);
    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
    // Negative volume.
    newBoundBox.set((Bounds)null);
     return false;
       }


       boolean status = false;
       BoundingBox tbox = new BoundingBox();

       for(;i<boundsObjects.length;i++) {
     if( boundsObjects[i] == null || boundsObjects[i].boundsIsEmpty) ;
     else if( boundsObjects[i].boundId == BOUNDING_BOX){
         BoundingBox box = (BoundingBox)boundsObjects[i];
         // both boxes are axis aligned
         if( upper.x > box.lower.x && box.upper.x > lower.x &&
       upper.y > box.lower.y && box.upper.y > lower.y &&
       upper.z > box.lower.z && box.upper.z > lower.z ){

       if(upper.x > box.upper.x)
           newBoundBox.upper.x = box.upper.x;
       else
           newBoundBox.upper.x = upper.x;

       if(upper.y > box.upper.y)
           newBoundBox.upper.y = box.upper.y;
       else
           newBoundBox.upper.y = upper.y;

       if(upper.z > box.upper.z)
           newBoundBox.upper.z = box.upper.z;
       else
           newBoundBox.upper.z = upper.z;

       if(lower.x < box.lower.x)
           newBoundBox.lower.x = box.lower.x;
       else
           newBoundBox.lower.x = lower.x;

       if(lower.y < box.lower.y)
           newBoundBox.lower.y = box.lower.y;
       else
           newBoundBox.lower.y = lower.y;

       if(lower.z < box.lower.z)
           newBoundBox.lower.z = box.lower.z;
       else
           newBoundBox.lower.z = lower.z;
       status = true;
       newBoundBox.updateBoundsStates();
         }
     }
     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
       this.intersect(sbox,tbox); // insersect two boxes
       if( status ) {
           newBoundBox.combine( tbox );
       } else {
           newBoundBox.set( tbox );
           status = true;
       }
         }

     }
     else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) {
         BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i];
         if( this.intersect( polytope)) {
       BoundingBox pbox = new BoundingBox( polytope ); // convert polytope to box
       this.intersect(pbox,tbox); // insersect two boxes
       if ( status ) {
           newBoundBox.combine( tbox );
       } else {
           newBoundBox.set( tbox );
           status = true;
       }
         }
     } else {
         throw new IllegalArgumentException(J3dI18N.getString("BoundingBox6"));
     }

     if(newBoundBox.boundsIsInfinite)
         break; // We're done.
       }
       if( status == false ) {
     // Negative volume.
    newBoundBox.set((Bounds)null);
       }
       return status;
    }


    /**
     * Finds closest bounding object that intersects this bounding box.
     * @param boundsObjects an array of bounds objects
     * @return closest bounding object
     */
    @Override
    public Bounds closestIntersection( Bounds[] boundsObjects) {

  if( boundsObjects == null || boundsObjects.length <= ) {
      return null;
        }

        if( boundsIsEmpty ) {
      return null;
        }

  Point3d centroid = getCenter();

  double dis;
  double cenX = 0.0, cenY = 0.0, cenZ = 0.0;
  boolean contains = false;
  boolean inside;
  boolean intersect = false;
  double smallest_distance = Double.MAX_VALUE;
  int i,j,index=0;

  for(i = 0; i < boundsObjects.length; i++){
      if( boundsObjects[i] == null ) ;

      else if( this.intersect( boundsObjects[i])) {
    intersect = true;
    if( boundsObjects[i].boundId == BOUNDING_BOX){
        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 = false;

        if( lower.x <= box.lower.x &&
      lower.y <= box.lower.y &&
      lower.z <= box.lower.z &&
      upper.x >= box.upper.x &&
      upper.y >= box.upper.y &&
      upper.z >= box.upper.z ) { // box is contained
      inside = true;
        }
        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 if( boundsObjects[i].boundId == BOUNDING_SPHERE ) {
        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 = false;

        // sphere sphere.center is inside box
        if(sphere.center.x <= upper.x && sphere.center.x >= lower.x &&
           sphere.center.y <= upper.y && sphere.center.y >= lower.y &&
           sphere.center.z <= upper.z && sphere.center.z >= lower.z ) {
      // check if sphere intersects any side
      if (sphere.center.x - lower.x >= sphere.radius &&
          upper.x - sphere.center.x >= sphere.radius &&
          sphere.center.y - lower.y >= sphere.radius &&
          upper.y - sphere.center.y >= sphere.radius &&
          sphere.center.z - lower.z >= sphere.radius &&
          upper.z - sphere.center.z >= sphere.radius  ) {
          // contains the sphere
          inside = true;
      }
        }
        if (inside ) {
      // initialize smallest_distance for the first containment
      if( !contains ){
          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].boundId == BOUNDING_POLYTOPE) {
        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( polytope.verts[j].x < lower.x ||
          polytope.verts[j].y < lower.y ||
          polytope.verts[j].z < lower.z ||
          polytope.verts[j].x > upper.x ||
          polytope.verts[j].y > upper.y ||
          polytope.verts[j].z > upper.z ) { // box contains polytope
          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("BoundingBox9"));
    }
      }
  }

  if ( intersect )
            return boundsObjects[index];
  else
      return null;
    }

    /**
     * Tests for intersection of box and frustum.
     * @param frustum
     * @return true if they intersect
     */
    boolean intersect(CachedFrustum frustum ) {

  if (boundsIsEmpty)
      return false;

  if(boundsIsInfinite)
      return true;

  // System.err.println("intersect frustum with box="+this.toString());
  // System.err.println("frustum "+frustum.toString());
  // check if box and bounding box  of frustum intersect
        if ((upper.x < frustum.lower.x) ||
      (lower.x > frustum.upper.x) ||
            (upper.y < frustum.lower.y) ||
      (lower.y > frustum.upper.y) ||
            (upper.z < frustum.lower.z) ||
      (lower.z > frustum.upper.z) ) {

      // System.err.println("*** box and bounding box of frustum do not intersect");
      return false;
  }

  // check if all box points out any frustum plane
  int i = 5;
  while (i>=0){
      Vector4d vc = frustum.clipPlanes[i--];
      if ((( upper.x*vc.x + upper.y*vc.y +
       upper.z*vc.z + vc.w ) < 0.0 ) &&
    (( upper.x*vc.x + lower.y*vc.y +
       upper.z*vc.z + vc.w ) < 0.0 ) &&
    (( upper.x*vc.x + lower.y*vc.y +
       lower.z*vc.z + vc.w ) < 0.0 ) &&
    (( upper.x*vc.x + upper.y*vc.y +
       lower.z*vc.z + vc.w ) < 0.0 ) &&
    (( lower.x*vc.x + upper.y*vc.y +
       upper.z*vc.z + vc.w ) < 0.0 ) &&
    (( lower.x*vc.x + lower.y*vc.y +
       upper.z*vc.z + vc.w ) < 0.0 ) &&
    (( lower.x*vc.x + lower.y*vc.y +
       lower.z*vc.z + vc.w ) < 0.0 ) &&
    (( lower.x*vc.x +  upper.y*vc.y +
       lower.z*vc.z + vc.w ) < 0.0 )) {
    // all corners outside this frustum plane
    // System.err.println("*** all corners outside this frustum plane");
    return false;
      }
  }

  return true;
    }

    /**
     * Returns a string representation of this class.
     */
    @Override
    public String toString() {
  return new String( "Bounding box: Lower="+lower.x+" "+
         lower.y+" "+lower.z+" Upper="+upper.x+" "+
         upper.y+" "+upper.z  );
    }

private void setEmptyBounds() {
  lower.set( 1.0d1.0d1.0d);
  upper.set(-1.0d, -1.0d, -1.0d);
  boundsIsInfinite = false;
  boundsIsEmpty = true;
}

private void setInfiniteBounds() {
  lower.set(Double.NEGATIVE_INFINITY,
            Double.NEGATIVE_INFINITY,
            Double.NEGATIVE_INFINITY);
  upper.set(Double.POSITIVE_INFINITY,
            Double.POSITIVE_INFINITY,
            Double.POSITIVE_INFINITY);

  boundsIsInfinite = true;
  boundsIsEmpty = false;
}

    private void updateBoundsStates() {
  if((lower.x == Double.NEGATIVE_INFINITY) &&
     (lower.y == Double.NEGATIVE_INFINITY) &&
     (lower.z == Double.NEGATIVE_INFINITY) &&
     (upper.x == Double.POSITIVE_INFINITY) &&
     (upper.y == Double.POSITIVE_INFINITY) &&
     (upper.z == Double.POSITIVE_INFINITY)) {
      boundsIsEmpty = false;
      boundsIsInfinite = true;
      return;
  }

  if (Double.isNaN(lower.x + lower.y + lower.z + upper.x + upper.y + upper.z)) {
       boundsIsEmpty = true;
       boundsIsInfinite = false;
       return;
  }
  else {
      boundsIsInfinite = false;
      if( lower.x > upper.x ||
    lower.y > upper.y ||
    lower.z > upper.z ) {
    boundsIsEmpty = true;
      } else {
    boundsIsEmpty = false;
      }
  }
    }

// For a infinite bounds. What is the centroid ?
@Override
Point3d getCenter() {
  Point3d cent = new Point3d();
  cent.add(upper, lower);
  cent.scale(0.5d);
  return cent;
}

@Override
public void getCenter(Point3d center) {
  center.add(lower, upper);
  center.scale(0.5d);
}

    void translate(BoundingBox bbox, Vector3d value) {
  if (bbox == null || bbox.boundsIsEmpty) {
    setEmptyBounds();
    return;
  }

  if (bbox.boundsIsInfinite) {
    setInfiniteBounds();
    return;
  }

  lower.x = bbox.lower.x + value.x;
  lower.y = bbox.lower.y + value.y;
  lower.z = bbox.lower.z + value.z;
  upper.x = bbox.upper.x + value.x;
  upper.y = bbox.upper.y + value.y;
  upper.z = bbox.upper.z + value.z;
    }


    /**
     * 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) {
  if (r != null && this.boundId == r.boundId) {
      BoundingBox region = (BoundingBox) r;
      region.lower.x = lower.x;
      region.lower.y = lower.y;
      region.lower.z = lower.z;
      region.upper.x = upper.x;
      region.upper.y = upper.y;
      region.upper.z = upper.z;
      region.boundsIsEmpty = boundsIsEmpty;
      region.boundsIsInfinite = boundsIsInfinite;
      return region;
  }
  else {
      return (Bounds) this.clone();
  }
    }

    @Override
    int getPickType() {
  return PickShape.PICKBOUNDINGBOX;
    }
}
TOP

Related Classes of javax.media.j3d.BoundingBox

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.