0001: /*
0002: * $RCSfile: BoundingBox.java,v $
0003: *
0004: * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0006: *
0007: * This code is free software; you can redistribute it and/or modify it
0008: * under the terms of the GNU General Public License version 2 only, as
0009: * published by the Free Software Foundation. Sun designates this
0010: * particular file as subject to the "Classpath" exception as provided
0011: * by Sun in the LICENSE file that accompanied this code.
0012: *
0013: * This code is distributed in the hope that it will be useful, but WITHOUT
0014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0016: * version 2 for more details (a copy is included in the LICENSE file that
0017: * accompanied this code).
0018: *
0019: * You should have received a copy of the GNU General Public License version
0020: * 2 along with this work; if not, write to the Free Software Foundation,
0021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0022: *
0023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0024: * CA 95054 USA or visit www.sun.com if you need additional information or
0025: * have any questions.
0026: *
0027: * $Revision: 1.10 $
0028: * $Date: 2008/02/28 20:17:19 $
0029: * $State: Exp $
0030: */
0031:
0032: package javax.media.j3d;
0033:
0034: import javax.vecmath.*;
0035: import com.sun.j3d.internal.HashCodeUtil;
0036:
0037: /**
0038: * This class defines an axis aligned bounding box which is used for
0039: * bounding regions.
0040: *
0041: */
0042:
0043: public class BoundingBox extends Bounds {
0044:
0045: /**
0046: * The corner of the bounding box with the numerically smallest
0047: * values.
0048: */
0049: Point3d lower;
0050:
0051: /**
0052: * The corner of the bounding box with the numerically largest
0053: * values.
0054: */
0055: Point3d upper;
0056:
0057: private Point3d centroid = null;
0058: private static final double EPS = 1.0E-8;
0059:
0060: // reusable temp objects
0061: private BoundingSphere tmpSphere = null;
0062: private BoundingBox tmpBox = null;
0063: private BoundingPolytope tmpPolytope = null;
0064: private Point3d tmpP3d = null;
0065:
0066: /**
0067: * Constructs and initializes a BoundingBox given min,max in x,y,z.
0068: * @param lower the "small" corner
0069: * @param upper the "large" corner
0070: */
0071: public BoundingBox(Point3d lower, Point3d upper) {
0072: boundId = BOUNDING_BOX;
0073: this .lower = new Point3d(lower);
0074: this .upper = new Point3d(upper);
0075: updateBoundsStates();
0076: }
0077:
0078: /**
0079: * Constructs and initializes a 2X bounding box about the
0080: * origin. The lower corner is initialized to (-1.0d, -1.0d, -1.0d)
0081: * and the opper corner is initialized to (1.0d, 1.0d, 1.0d).
0082: */
0083: public BoundingBox() {
0084: boundId = BOUNDING_BOX;
0085: lower = new Point3d(-1.0d, -1.0d, -1.0d);
0086: upper = new Point3d(1.0d, 1.0d, 1.0d);
0087: updateBoundsStates();
0088: }
0089:
0090: /**
0091: * Constructs a BoundingBox from a bounding object.
0092: * @param boundsObject a bounds object
0093: */
0094: public BoundingBox(Bounds boundsObject) {
0095: int i;
0096: boundId = BOUNDING_BOX;
0097: if (boundsObject == null) {
0098: // Negative volume.
0099: lower = new Point3d(1.0d, 1.0d, 1.0d);
0100: upper = new Point3d(-1.0d, -1.0d, -1.0d);
0101: } else if (boundsObject.boundsIsInfinite) {
0102: lower = new Point3d(Double.NEGATIVE_INFINITY,
0103: Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
0104: upper = new Point3d(Double.POSITIVE_INFINITY,
0105: Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
0106: } else if (boundsObject.boundId == BOUNDING_BOX) {
0107: BoundingBox box = (BoundingBox) boundsObject;
0108:
0109: lower = new Point3d(box.lower.x, box.lower.y, box.lower.z);
0110: upper = new Point3d(box.upper.x, box.upper.y, box.upper.z);
0111:
0112: } else if (boundsObject.boundId == BOUNDING_SPHERE) {
0113: BoundingSphere sphere = (BoundingSphere) boundsObject;
0114:
0115: lower = new Point3d(sphere.center.x - sphere.radius,
0116: sphere.center.y - sphere.radius, sphere.center.z
0117: - sphere.radius);
0118:
0119: upper = new Point3d(sphere.center.x + sphere.radius,
0120: sphere.center.y + sphere.radius, sphere.center.z
0121: + sphere.radius);
0122:
0123: } else if (boundsObject.boundId == BOUNDING_POLYTOPE) {
0124: BoundingPolytope polytope = (BoundingPolytope) boundsObject;
0125: if (polytope.nVerts < 1) { // handle degenerate case
0126: lower = new Point3d(-1.0d, -1.0d, -1.0d);
0127: upper = new Point3d(1.0d, 1.0d, 1.0d);
0128: } else {
0129: lower = new Point3d(polytope.verts[0].x,
0130: polytope.verts[0].y, polytope.verts[0].z);
0131: upper = new Point3d(polytope.verts[0].x,
0132: polytope.verts[0].y, polytope.verts[0].z);
0133:
0134: for (i = 1; i < polytope.nVerts; i++) {
0135: if (polytope.verts[i].x < lower.x)
0136: lower.x = polytope.verts[i].x;
0137: if (polytope.verts[i].y < lower.y)
0138: lower.y = polytope.verts[i].y;
0139: if (polytope.verts[i].z < lower.z)
0140: lower.z = polytope.verts[i].z;
0141: if (polytope.verts[i].x > upper.x)
0142: upper.x = polytope.verts[i].x;
0143: if (polytope.verts[i].y > upper.y)
0144: upper.y = polytope.verts[i].y;
0145: if (polytope.verts[i].z > upper.z)
0146: upper.z = polytope.verts[i].z;
0147: }
0148: }
0149:
0150: } else {
0151: throw new IllegalArgumentException(J3dI18N
0152: .getString("BoundingBox0"));
0153: }
0154:
0155: updateBoundsStates();
0156: }
0157:
0158: /**
0159: * Constructs a BoundingBox from an array of bounding objects.
0160: * @param bounds an array of bounding objects
0161: */
0162: public BoundingBox(Bounds[] bounds) {
0163: int i = 0;
0164:
0165: upper = new Point3d();
0166: lower = new Point3d();
0167: boundId = BOUNDING_BOX;
0168:
0169: if (bounds == null || bounds.length <= 0) {
0170: // Negative volume.
0171: lower = new Point3d(1.0d, 1.0d, 1.0d);
0172: upper = new Point3d(-1.0d, -1.0d, -1.0d);
0173: updateBoundsStates();
0174: return;
0175: }
0176:
0177: // find first non empty bounds object
0178: while (bounds[i] == null && i < bounds.length) {
0179: i++;
0180: }
0181:
0182: if (i >= bounds.length) { // all bounds objects were empty
0183: // Negative volume.
0184: lower = new Point3d(1.0d, 1.0d, 1.0d);
0185: upper = new Point3d(-1.0d, -1.0d, -1.0d);
0186: updateBoundsStates();
0187: return;
0188: }
0189:
0190: this .set(bounds[i++]);
0191: if (boundsIsInfinite)
0192: return;
0193:
0194: for (; i < bounds.length; i++) {
0195: if (bounds[i] == null)
0196: ; // do nothing
0197: else if (bounds[i].boundsIsEmpty)
0198: ; // do nothing
0199: else if (bounds[i].boundsIsInfinite) {
0200: lower.x = lower.y = lower.z = Double.NEGATIVE_INFINITY;
0201: upper.x = upper.y = upper.z = Double.POSITIVE_INFINITY;
0202: break; // We're done.
0203: } else if (bounds[i].boundId == BOUNDING_BOX) {
0204: BoundingBox box = (BoundingBox) bounds[i];
0205:
0206: if (lower.x > box.lower.x)
0207: lower.x = box.lower.x;
0208: if (lower.y > box.lower.y)
0209: lower.y = box.lower.y;
0210: if (lower.z > box.lower.z)
0211: lower.z = box.lower.z;
0212: if (upper.x < box.upper.x)
0213: upper.x = box.upper.x;
0214: if (upper.y < box.upper.y)
0215: upper.y = box.upper.y;
0216: if (upper.z < box.upper.z)
0217: upper.z = box.upper.z;
0218:
0219: } else if (bounds[i].boundId == BOUNDING_SPHERE) {
0220: BoundingSphere sphere = (BoundingSphere) bounds[i];
0221: if (lower.x > (sphere.center.x - sphere.radius))
0222: lower.x = sphere.center.x - sphere.radius;
0223: if (lower.y > (sphere.center.y - sphere.radius))
0224: lower.y = sphere.center.y - sphere.radius;
0225: if (lower.z > (sphere.center.z - sphere.radius))
0226: lower.z = sphere.center.z - sphere.radius;
0227: if (upper.x < (sphere.center.x + sphere.radius))
0228: upper.x = sphere.center.x + sphere.radius;
0229: if (upper.y < (sphere.center.y + sphere.radius))
0230: upper.y = sphere.center.y + sphere.radius;
0231: if (upper.z < (sphere.center.z + sphere.radius))
0232: upper.z = sphere.center.z + sphere.radius;
0233: } else if (bounds[i].boundId == BOUNDING_POLYTOPE) {
0234: BoundingPolytope polytope = (BoundingPolytope) bounds[i];
0235:
0236: for (i = 0; i < polytope.nVerts; i++) { // XXXX: handle polytope with no verts
0237: if (polytope.verts[i].x < lower.x)
0238: lower.x = polytope.verts[i].x;
0239: if (polytope.verts[i].y < lower.y)
0240: lower.y = polytope.verts[i].y;
0241: if (polytope.verts[i].z < lower.z)
0242: lower.z = polytope.verts[i].z;
0243: if (polytope.verts[i].x > upper.x)
0244: upper.x = polytope.verts[i].x;
0245: if (polytope.verts[i].y > upper.y)
0246: upper.y = polytope.verts[i].y;
0247: if (polytope.verts[i].z > upper.z)
0248: upper.z = polytope.verts[i].z;
0249: }
0250: } else {
0251: throw new IllegalArgumentException(J3dI18N
0252: .getString("BoundingBox1"));
0253: }
0254: }
0255: updateBoundsStates();
0256: }
0257:
0258: /**
0259: * Gets the lower corner of this bounding box.
0260: * @param p1 a Point to receive the lower corner of the bounding box
0261: */
0262: public void getLower(Point3d p1) {
0263: p1.x = lower.x;
0264: p1.y = lower.y;
0265: p1.z = lower.z;
0266: }
0267:
0268: /**
0269: * Sets the lower corner of this bounding box.
0270: * @param xmin minimum x value of boundining box
0271: * @param ymin minimum y value of boundining box
0272: * @param zmin minimum z value of boundining box
0273: */
0274: public void setLower(double xmin, double ymin, double zmin) {
0275: lower.x = xmin;
0276: lower.y = ymin;
0277: lower.z = zmin;
0278:
0279: updateBoundsStates();
0280: }
0281:
0282: /**
0283: * Sets the lower corner of this bounding box.
0284: * @param p1 a Point defining the new lower corner of the bounding box
0285: */
0286: public void setLower(Point3d p1) {
0287:
0288: lower.x = p1.x;
0289: lower.y = p1.y;
0290: lower.z = p1.z;
0291:
0292: updateBoundsStates();
0293: }
0294:
0295: /**
0296: * Gets the upper corner of this bounding box.
0297: * @param p1 a Point to receive the upper corner of the bounding box
0298: */
0299: public void getUpper(Point3d p1) {
0300: p1.x = upper.x;
0301: p1.y = upper.y;
0302: p1.z = upper.z;
0303: }
0304:
0305: /**
0306: * Sets the upper corner of this bounding box.
0307: * @param xmax max x value of boundining box
0308: * @param ymax max y value of boundining box
0309: * @param zmax max z value of boundining box
0310: */
0311: public void setUpper(double xmax, double ymax, double zmax) {
0312: upper.x = xmax;
0313: upper.y = ymax;
0314: upper.z = zmax;
0315:
0316: updateBoundsStates();
0317: }
0318:
0319: /**
0320: * Sets the upper corner of this bounding box.
0321: * @param p1 a Point defining the new upper corner of the bounding box
0322: */
0323: public void setUpper(Point3d p1) {
0324: upper.x = p1.x;
0325: upper.y = p1.y;
0326: upper.z = p1.z;
0327:
0328: updateBoundsStates();
0329: }
0330:
0331: /**
0332: * Sets the the value of this BoundingBox
0333: * @param boundsObject another bounds object
0334: */
0335: public void set(Bounds boundsObject) {
0336: int i;
0337:
0338: if ((boundsObject == null) || (boundsObject.boundsIsEmpty)) {
0339: // Negative volume.
0340: lower.x = lower.y = lower.z = 1.0d;
0341: upper.x = upper.y = upper.z = -1.0d;
0342:
0343: } else if (boundsObject.boundsIsInfinite) {
0344: lower.x = lower.y = lower.z = Double.NEGATIVE_INFINITY;
0345: upper.x = upper.y = upper.z = Double.POSITIVE_INFINITY;
0346:
0347: } else if (boundsObject.boundId == BOUNDING_BOX) {
0348: BoundingBox box = (BoundingBox) boundsObject;
0349:
0350: lower.x = box.lower.x;
0351: lower.y = box.lower.y;
0352: lower.z = box.lower.z;
0353: upper.x = box.upper.x;
0354: upper.y = box.upper.y;
0355: upper.z = box.upper.z;
0356:
0357: } else if (boundsObject.boundId == BOUNDING_SPHERE) {
0358: BoundingSphere sphere = (BoundingSphere) boundsObject;
0359: lower.x = sphere.center.x - sphere.radius;
0360: lower.y = sphere.center.y - sphere.radius;
0361: lower.z = sphere.center.z - sphere.radius;
0362: upper.x = sphere.center.x + sphere.radius;
0363: upper.y = sphere.center.y + sphere.radius;
0364: upper.z = sphere.center.z + sphere.radius;
0365:
0366: } else if (boundsObject.boundId == BOUNDING_POLYTOPE) {
0367: BoundingPolytope polytope = (BoundingPolytope) boundsObject;
0368: lower.x = upper.x = polytope.verts[0].x;
0369: lower.y = upper.y = polytope.verts[0].y;
0370: lower.z = upper.z = polytope.verts[0].z;
0371:
0372: for (i = 1; i < polytope.nVerts; i++) {
0373: if (polytope.verts[i].x < lower.x)
0374: lower.x = polytope.verts[i].x;
0375: if (polytope.verts[i].y < lower.y)
0376: lower.y = polytope.verts[i].y;
0377: if (polytope.verts[i].z < lower.z)
0378: lower.z = polytope.verts[i].z;
0379: if (polytope.verts[i].x > upper.x)
0380: upper.x = polytope.verts[i].x;
0381: if (polytope.verts[i].y > upper.y)
0382: upper.y = polytope.verts[i].y;
0383: if (polytope.verts[i].z > upper.z)
0384: upper.z = polytope.verts[i].z;
0385: }
0386:
0387: } else {
0388: throw new IllegalArgumentException(J3dI18N
0389: .getString("BoundingBox0"));
0390: }
0391:
0392: updateBoundsStates();
0393: }
0394:
0395: /**
0396: * Creates a copy of this bounding box.
0397: * @return a new bounding box
0398: */
0399: public Object clone() {
0400: return new BoundingBox(this .lower, this .upper);
0401: }
0402:
0403: /**
0404: * Indicates whether the specified <code>bounds</code> object is
0405: * equal to this BoundingBox object. They are equal if the
0406: * specified <code>bounds</code> object is an instance of
0407: * BoundingBox and all of the data
0408: * members of <code>bounds</code> are equal to the corresponding
0409: * data members in this BoundingBox.
0410: * @param bounds the object with which the comparison is made.
0411: * @return true if this BoundingBox is equal to <code>bounds</code>;
0412: * otherwise false
0413: *
0414: * @since Java 3D 1.2
0415: */
0416: public boolean equals(Object bounds) {
0417: try {
0418: BoundingBox box = (BoundingBox) bounds;
0419: return (lower.equals(box.lower) && upper.equals(box.upper));
0420: } catch (NullPointerException e) {
0421: return false;
0422: } catch (ClassCastException e) {
0423: return false;
0424: }
0425: }
0426:
0427: /**
0428: * Returns a hash code value for this BoundingBox object
0429: * based on the data values in this object. Two different
0430: * BoundingBox objects with identical data values (i.e.,
0431: * BoundingBox.equals returns true) will return the same hash
0432: * code value. Two BoundingBox objects with different data
0433: * members may return the same hash code value, although this is
0434: * not likely.
0435: * @return a hash code value for this BoundingBox object.
0436: *
0437: * @since Java 3D 1.2
0438: */
0439: public int hashCode() {
0440: long bits = 1L;
0441: bits = 31L * bits + HashCodeUtil.doubleToLongBits(lower.x);
0442: bits = 31L * bits + HashCodeUtil.doubleToLongBits(lower.y);
0443: bits = 31L * bits + HashCodeUtil.doubleToLongBits(lower.z);
0444: bits = 31L * bits + HashCodeUtil.doubleToLongBits(upper.x);
0445: bits = 31L * bits + HashCodeUtil.doubleToLongBits(upper.y);
0446: bits = 31L * bits + HashCodeUtil.doubleToLongBits(upper.z);
0447: return (int) (bits ^ (bits >> 32));
0448: }
0449:
0450: /**
0451: * Combines this bounding box with a bounding object so that the
0452: * resulting bounding box encloses the original bounding box and the
0453: * specified bounds object.
0454: * @param boundsObject another bounds object
0455: */
0456: public void combine(Bounds boundsObject) {
0457:
0458: if ((boundsObject == null) || (boundsObject.boundsIsEmpty)
0459: || (boundsIsInfinite))
0460: return;
0461:
0462: if ((boundsIsEmpty) || (boundsObject.boundsIsInfinite)) {
0463: this .set(boundsObject);
0464: return;
0465: }
0466:
0467: if (boundsObject.boundId == BOUNDING_BOX) {
0468: BoundingBox box = (BoundingBox) boundsObject;
0469:
0470: if (lower.x > box.lower.x)
0471: lower.x = box.lower.x;
0472: if (lower.y > box.lower.y)
0473: lower.y = box.lower.y;
0474: if (lower.z > box.lower.z)
0475: lower.z = box.lower.z;
0476: if (upper.x < box.upper.x)
0477: upper.x = box.upper.x;
0478: if (upper.y < box.upper.y)
0479: upper.y = box.upper.y;
0480: if (upper.z < box.upper.z)
0481: upper.z = box.upper.z;
0482:
0483: } else if (boundsObject.boundId == BOUNDING_SPHERE) {
0484: BoundingSphere sphere = (BoundingSphere) boundsObject;
0485: if (lower.x > (sphere.center.x - sphere.radius))
0486: lower.x = sphere.center.x - sphere.radius;
0487: if (lower.y > (sphere.center.y - sphere.radius))
0488: lower.y = sphere.center.y - sphere.radius;
0489: if (lower.z > (sphere.center.z - sphere.radius))
0490: lower.z = sphere.center.z - sphere.radius;
0491: if (upper.x < (sphere.center.x + sphere.radius))
0492: upper.x = sphere.center.x + sphere.radius;
0493: if (upper.y < (sphere.center.y + sphere.radius))
0494: upper.y = sphere.center.y + sphere.radius;
0495: if (upper.z < (sphere.center.z + sphere.radius))
0496: upper.z = sphere.center.z + sphere.radius;
0497:
0498: } else if (boundsObject.boundId == BOUNDING_POLYTOPE) {
0499: BoundingPolytope polytope = (BoundingPolytope) boundsObject;
0500: int i;
0501: for (i = 1; i < polytope.nVerts; i++) {
0502: if (polytope.verts[i].x < lower.x)
0503: lower.x = polytope.verts[i].x;
0504: if (polytope.verts[i].y < lower.y)
0505: lower.y = polytope.verts[i].y;
0506: if (polytope.verts[i].z < lower.z)
0507: lower.z = polytope.verts[i].z;
0508: if (polytope.verts[i].x > upper.x)
0509: upper.x = polytope.verts[i].x;
0510: if (polytope.verts[i].y > upper.y)
0511: upper.y = polytope.verts[i].y;
0512: if (polytope.verts[i].z > upper.z)
0513: upper.z = polytope.verts[i].z;
0514: }
0515: } else {
0516: throw new IllegalArgumentException(J3dI18N
0517: .getString("BoundingBox3"));
0518: }
0519:
0520: updateBoundsStates();
0521: }
0522:
0523: /**
0524: * Combines this bounding box with an array of bounding objects
0525: * so that the resulting bounding box encloses the original bounding
0526: * box and the array of bounding objects.
0527: * @param bounds an array of bounds objects
0528: */
0529: public void combine(Bounds[] bounds) {
0530: int i = 0;
0531:
0532: if ((bounds == null) || (bounds.length <= 0)
0533: || (boundsIsInfinite))
0534: return;
0535:
0536: // find first non empty bounds object
0537: while ((i < bounds.length)
0538: && ((bounds[i] == null) || bounds[i].boundsIsEmpty)) {
0539: i++;
0540: }
0541: if (i >= bounds.length)
0542: return; // no non empty bounds so do not modify current bounds
0543:
0544: if (boundsIsEmpty)
0545: this .set(bounds[i++]);
0546:
0547: if (boundsIsInfinite)
0548: return;
0549:
0550: for (; i < bounds.length; i++) {
0551: if (bounds[i] == null)
0552: ; // do nothing
0553: else if (bounds[i].boundsIsEmpty)
0554: ; // do nothing
0555: else if (bounds[i].boundsIsInfinite) {
0556: lower.x = lower.y = lower.z = Double.NEGATIVE_INFINITY;
0557: upper.x = upper.y = upper.z = Double.POSITIVE_INFINITY;
0558: break; // We're done.
0559: } else if (bounds[i].boundId == BOUNDING_BOX) {
0560: BoundingBox box = (BoundingBox) bounds[i];
0561:
0562: if (lower.x > box.lower.x)
0563: lower.x = box.lower.x;
0564: if (lower.y > box.lower.y)
0565: lower.y = box.lower.y;
0566: if (lower.z > box.lower.z)
0567: lower.z = box.lower.z;
0568: if (upper.x < box.upper.x)
0569: upper.x = box.upper.x;
0570: if (upper.y < box.upper.y)
0571: upper.y = box.upper.y;
0572: if (upper.z < box.upper.z)
0573: upper.z = box.upper.z;
0574: } else if (bounds[i].boundId == BOUNDING_SPHERE) {
0575: BoundingSphere sphere = (BoundingSphere) bounds[i];
0576: if (lower.x > (sphere.center.x - sphere.radius))
0577: lower.x = sphere.center.x - sphere.radius;
0578: if (lower.y > (sphere.center.y - sphere.radius))
0579: lower.y = sphere.center.y - sphere.radius;
0580: if (lower.z > (sphere.center.z - sphere.radius))
0581: lower.z = sphere.center.z - sphere.radius;
0582: if (upper.x < (sphere.center.x + sphere.radius))
0583: upper.x = sphere.center.x + sphere.radius;
0584: if (upper.y < (sphere.center.y + sphere.radius))
0585: upper.y = sphere.center.y + sphere.radius;
0586: if (upper.z < (sphere.center.z + sphere.radius))
0587: upper.z = sphere.center.z + sphere.radius;
0588: } else if (bounds[i].boundId == BOUNDING_POLYTOPE) {
0589: BoundingPolytope polytope = (BoundingPolytope) bounds[i];
0590: for (i = 1; i < polytope.nVerts; i++) {
0591: if (polytope.verts[i].x < lower.x)
0592: lower.x = polytope.verts[i].x;
0593: if (polytope.verts[i].y < lower.y)
0594: lower.y = polytope.verts[i].y;
0595: if (polytope.verts[i].z < lower.z)
0596: lower.z = polytope.verts[i].z;
0597: if (polytope.verts[i].x > upper.x)
0598: upper.x = polytope.verts[i].x;
0599: if (polytope.verts[i].y > upper.y)
0600: upper.y = polytope.verts[i].y;
0601: if (polytope.verts[i].z > upper.z)
0602: upper.z = polytope.verts[i].z;
0603: }
0604: } else {
0605: throw new IllegalArgumentException(J3dI18N
0606: .getString("BoundingBox4"));
0607: }
0608: }
0609:
0610: updateBoundsStates();
0611: }
0612:
0613: /**
0614: * Combines this bounding box with a point so that the resulting
0615: * bounding box encloses the original bounding box and the point.
0616: * @param point a 3d point in space
0617: */
0618: public void combine(Point3d point) {
0619:
0620: if (boundsIsInfinite) {
0621: return;
0622: }
0623:
0624: if (boundsIsEmpty) {
0625: upper.x = lower.x = point.x;
0626: upper.y = lower.y = point.y;
0627: upper.z = lower.z = point.z;
0628: } else {
0629: if (point.x > upper.x)
0630: upper.x = point.x;
0631: if (point.y > upper.y)
0632: upper.y = point.y;
0633: if (point.z > upper.z)
0634: upper.z = point.z;
0635:
0636: if (point.x < lower.x)
0637: lower.x = point.x;
0638: if (point.y < lower.y)
0639: lower.y = point.y;
0640: if (point.z < lower.z)
0641: lower.z = point.z;
0642: }
0643:
0644: updateBoundsStates();
0645: }
0646:
0647: /**
0648: * Combines this bounding box with an array of points so that the
0649: * resulting bounding box encloses the original bounding box and the
0650: * array of points.
0651: * @param points an array of 3d points in space
0652: */
0653: public void combine(Point3d[] points) {
0654:
0655: int i;
0656:
0657: if (boundsIsInfinite) {
0658: return;
0659: }
0660:
0661: if (boundsIsEmpty) {
0662: this .setUpper(points[0]);
0663: this .setLower(points[0]);
0664: }
0665:
0666: for (i = 0; i < points.length; i++) {
0667: if (points[i].x > upper.x)
0668: upper.x = points[i].x;
0669: if (points[i].y > upper.y)
0670: upper.y = points[i].y;
0671: if (points[i].z > upper.z)
0672: upper.z = points[i].z;
0673:
0674: if (points[i].x < lower.x)
0675: lower.x = points[i].x;
0676: if (points[i].y < lower.y)
0677: lower.y = points[i].y;
0678: if (points[i].z < lower.z)
0679: lower.z = points[i].z;
0680: }
0681:
0682: updateBoundsStates();
0683: }
0684:
0685: /**
0686: * Modifies the bounding box so that it bounds the volume
0687: * generated by transforming the given bounding object.
0688: * @param boundsObject the bounding object to be transformed
0689: * @param matrix a transformation matrix
0690: */
0691: public void transform(Bounds boundsObject, Transform3D matrix) {
0692:
0693: if (boundsObject == null || boundsObject.boundsIsEmpty) {
0694: // Negative volume.
0695: lower.x = lower.y = lower.z = 1.0d;
0696: upper.x = upper.y = upper.z = -1.0d;
0697: updateBoundsStates();
0698: return;
0699: }
0700:
0701: if (boundsObject.boundsIsInfinite) {
0702: lower.x = lower.y = lower.z = Double.NEGATIVE_INFINITY;
0703: upper.x = upper.y = upper.z = Double.POSITIVE_INFINITY;
0704: updateBoundsStates();
0705: return;
0706: }
0707:
0708: if (boundsObject.boundId == BOUNDING_BOX) {
0709: if (tmpBox == null) {
0710: tmpBox = new BoundingBox((BoundingBox) boundsObject);
0711: } else {
0712: tmpBox.set((BoundingBox) boundsObject);
0713: }
0714: tmpBox.transform(matrix);
0715: this .set(tmpBox);
0716: } else if (boundsObject.boundId == BOUNDING_SPHERE) {
0717: if (tmpSphere == null) {
0718: tmpSphere = new BoundingSphere(
0719: (BoundingSphere) boundsObject);
0720: } else {
0721: tmpSphere.set((BoundingSphere) boundsObject);
0722: }
0723: tmpSphere.transform(matrix);
0724: this .set(tmpSphere);
0725: } else if (boundsObject.boundId == BOUNDING_POLYTOPE) {
0726: if (tmpPolytope == null) {
0727: tmpPolytope = new BoundingPolytope(
0728: (BoundingPolytope) boundsObject);
0729: } else {
0730: tmpPolytope.set((BoundingPolytope) boundsObject);
0731: }
0732: tmpPolytope.transform(matrix);
0733: this .set(tmpPolytope);
0734:
0735: } else {
0736: throw new IllegalArgumentException(J3dI18N
0737: .getString("BoundingBox5"));
0738: }
0739:
0740: // Release the temporary fields:
0741: if (VirtualUniverse.mc.releaseBoundingBoxMemory) {
0742: tmpSphere = null;
0743: tmpBox = null;
0744: tmpPolytope = null;
0745: }
0746: }
0747:
0748: /**
0749: * Transforms this bounding box by the given matrix.
0750: * @param matrix a transformation matrix
0751: */
0752: public void transform(Transform3D matrix) {
0753:
0754: if (boundsIsInfinite)
0755: return;
0756:
0757: if (tmpP3d == null) {
0758: tmpP3d = new Point3d();
0759: }
0760:
0761: double ux, uy, uz, lx, ly, lz;
0762: ux = upper.x;
0763: uy = upper.y;
0764: uz = upper.z;
0765: lx = lower.x;
0766: ly = lower.y;
0767: lz = lower.z;
0768:
0769: tmpP3d.set(ux, uy, uz);
0770: matrix.transform(tmpP3d);
0771: upper.x = tmpP3d.x;
0772: upper.y = tmpP3d.y;
0773: upper.z = tmpP3d.z;
0774: lower.x = tmpP3d.x;
0775: lower.y = tmpP3d.y;
0776: lower.z = tmpP3d.z;
0777:
0778: tmpP3d.set(lx, uy, uz);
0779: matrix.transform(tmpP3d);
0780: if (tmpP3d.x > upper.x)
0781: upper.x = tmpP3d.x;
0782: if (tmpP3d.y > upper.y)
0783: upper.y = tmpP3d.y;
0784: if (tmpP3d.z > upper.z)
0785: upper.z = tmpP3d.z;
0786: if (tmpP3d.x < lower.x)
0787: lower.x = tmpP3d.x;
0788: if (tmpP3d.y < lower.y)
0789: lower.y = tmpP3d.y;
0790: if (tmpP3d.z < lower.z)
0791: lower.z = tmpP3d.z;
0792:
0793: tmpP3d.set(lx, ly, uz);
0794: matrix.transform(tmpP3d);
0795: if (tmpP3d.x > upper.x)
0796: upper.x = tmpP3d.x;
0797: if (tmpP3d.y > upper.y)
0798: upper.y = tmpP3d.y;
0799: if (tmpP3d.z > upper.z)
0800: upper.z = tmpP3d.z;
0801: if (tmpP3d.x < lower.x)
0802: lower.x = tmpP3d.x;
0803: if (tmpP3d.y < lower.y)
0804: lower.y = tmpP3d.y;
0805: if (tmpP3d.z < lower.z)
0806: lower.z = tmpP3d.z;
0807:
0808: tmpP3d.set(ux, ly, uz);
0809: matrix.transform(tmpP3d);
0810: if (tmpP3d.x > upper.x)
0811: upper.x = tmpP3d.x;
0812: if (tmpP3d.y > upper.y)
0813: upper.y = tmpP3d.y;
0814: if (tmpP3d.z > upper.z)
0815: upper.z = tmpP3d.z;
0816: if (tmpP3d.x < lower.x)
0817: lower.x = tmpP3d.x;
0818: if (tmpP3d.y < lower.y)
0819: lower.y = tmpP3d.y;
0820: if (tmpP3d.z < lower.z)
0821: lower.z = tmpP3d.z;
0822:
0823: tmpP3d.set(lx, uy, lz);
0824: matrix.transform(tmpP3d);
0825: if (tmpP3d.x > upper.x)
0826: upper.x = tmpP3d.x;
0827: if (tmpP3d.y > upper.y)
0828: upper.y = tmpP3d.y;
0829: if (tmpP3d.z > upper.z)
0830: upper.z = tmpP3d.z;
0831: if (tmpP3d.x < lower.x)
0832: lower.x = tmpP3d.x;
0833: if (tmpP3d.y < lower.y)
0834: lower.y = tmpP3d.y;
0835: if (tmpP3d.z < lower.z)
0836: lower.z = tmpP3d.z;
0837:
0838: tmpP3d.set(ux, uy, lz);
0839: matrix.transform(tmpP3d);
0840: if (tmpP3d.x > upper.x)
0841: upper.x = tmpP3d.x;
0842: if (tmpP3d.y > upper.y)
0843: upper.y = tmpP3d.y;
0844: if (tmpP3d.z > upper.z)
0845: upper.z = tmpP3d.z;
0846: if (tmpP3d.x < lower.x)
0847: lower.x = tmpP3d.x;
0848: if (tmpP3d.y < lower.y)
0849: lower.y = tmpP3d.y;
0850: if (tmpP3d.z < lower.z)
0851: lower.z = tmpP3d.z;
0852:
0853: tmpP3d.set(lx, ly, lz);
0854: matrix.transform(tmpP3d);
0855: if (tmpP3d.x > upper.x)
0856: upper.x = tmpP3d.x;
0857: if (tmpP3d.y > upper.y)
0858: upper.y = tmpP3d.y;
0859: if (tmpP3d.z > upper.z)
0860: upper.z = tmpP3d.z;
0861: if (tmpP3d.x < lower.x)
0862: lower.x = tmpP3d.x;
0863: if (tmpP3d.y < lower.y)
0864: lower.y = tmpP3d.y;
0865: if (tmpP3d.z < lower.z)
0866: lower.z = tmpP3d.z;
0867:
0868: tmpP3d.set(ux, ly, lz);
0869: matrix.transform(tmpP3d);
0870: if (tmpP3d.x > upper.x)
0871: upper.x = tmpP3d.x;
0872: if (tmpP3d.y > upper.y)
0873: upper.y = tmpP3d.y;
0874: if (tmpP3d.z > upper.z)
0875: upper.z = tmpP3d.z;
0876: if (tmpP3d.x < lower.x)
0877: lower.x = tmpP3d.x;
0878: if (tmpP3d.y < lower.y)
0879: lower.y = tmpP3d.y;
0880: if (tmpP3d.z < lower.z)
0881: lower.z = tmpP3d.z;
0882:
0883: if (VirtualUniverse.mc.releaseBoundingBoxMemory) {
0884: // Free memory
0885: tmpP3d = null;
0886: }
0887:
0888: }
0889:
0890: /**
0891: * Test for intersection with a ray.
0892: * @param origin the starting point of the ray
0893: * @param direction the direction of the ray
0894: * @param position3 a point defining the location of the pick w= distance to pick
0895: * @return true or false indicating if an intersection occured
0896: */
0897: boolean intersect(Point3d origin, Vector3d direction,
0898: Point4d position) {
0899: double t1, t2, tmp, tnear, tfar, invDir, invMag;
0900: double dirx, diry, dirz;
0901:
0902: /*
0903: System.err.println("BoundingBox.intersect(p,d,p) called\n");
0904: System.err.println("bounds = " + lower + " -> " + upper);
0905: */
0906:
0907: if (boundsIsEmpty) {
0908: return false;
0909: }
0910:
0911: if (boundsIsInfinite) {
0912: position.x = origin.x;
0913: position.y = origin.y;
0914: position.z = origin.z;
0915: position.w = 0.0;
0916: return true;
0917: }
0918:
0919: double dirLen = direction.x * direction.x + direction.y
0920: * direction.y + direction.z * direction.z;
0921:
0922: // Handle zero length direction vector.
0923: if (dirLen == 0.0)
0924: return intersect(origin, position);
0925:
0926: invMag = 1.0 / Math.sqrt(dirLen);
0927: dirx = direction.x * invMag;
0928: diry = direction.y * invMag;
0929: dirz = direction.z * invMag;
0930:
0931: /*
0932: System.err.println("dir = " + dirx + ", " + diry + ", " + dirz);
0933: System.err.println("origin = " + origin);
0934: */
0935:
0936: // initialize tnear and tfar to handle dir.? == 0 cases
0937: tnear = -Double.MAX_VALUE;
0938: tfar = Double.MAX_VALUE;
0939:
0940: if (dirx == 0.0) {
0941: //System.err.println("dirx == 0.0");
0942: if (origin.x < lower.x || origin.x > upper.x) {
0943: //System.err.println( "parallel to x plane and outside");
0944: return false;
0945: }
0946: } else {
0947: invDir = 1.0 / dirx;
0948: t1 = (lower.x - origin.x) * invDir;
0949: t2 = (upper.x - origin.x) * invDir;
0950:
0951: //System.err.println("x t1 = " + t1 + " t2 = " + t2);
0952: if (t1 > t2) {
0953: tnear = t2;
0954: tfar = t1;
0955: } else {
0956: tnear = t1;
0957: tfar = t2;
0958: }
0959: if (tfar < 0.0) {
0960: //System.err.println( "x failed: tnear="+tnear+" tfar="+tfar);
0961: return false;
0962: }
0963: //System.err.println("x tnear = " + tnear + " tfar = " + tfar);
0964: }
0965: // y
0966: if (diry == 0.0) {
0967: //System.err.println("diry == 0.0");
0968: if (origin.y < lower.y || origin.y > upper.y) {
0969: //System.err.println( "parallel to y plane and outside");
0970: return false;
0971: }
0972: } else {
0973: invDir = 1.0 / diry;
0974: //System.err.println("invDir = " + invDir);
0975: t1 = (lower.y - origin.y) * invDir;
0976: t2 = (upper.y - origin.y) * invDir;
0977:
0978: if (t1 > t2) {
0979: tmp = t1;
0980: t1 = t2;
0981: t2 = tmp;
0982: }
0983: //System.err.println("y t1 = " + t1 + " t2 = " + t2);
0984: if (t1 > tnear)
0985: tnear = t1;
0986: if (t2 < tfar)
0987: tfar = t2;
0988:
0989: if ((tfar < 0.0) || (tnear > tfar)) {
0990: //System.err.println( "y failed: tnear="+tnear+" tfar="+tfar);
0991: return false;
0992: }
0993: //System.err.println("y tnear = " + tnear + " tfar = " + tfar);
0994: }
0995:
0996: // z
0997: if (dirz == 0.0) {
0998: //System.err.println("dirz == 0.0");
0999: if (origin.z < lower.z || origin.z > upper.z) {
1000: //System.err.println( "parallel to z plane and outside");
1001: return false;
1002: }
1003: } else {
1004: invDir = 1.0 / dirz;
1005: t1 = (lower.z - origin.z) * invDir;
1006: t2 = (upper.z - origin.z) * invDir;
1007:
1008: if (t1 > t2) {
1009: tmp = t1;
1010: t1 = t2;
1011: t2 = tmp;
1012: }
1013: //System.err.println("z t1 = " + t1 + " t2 = " + t2);
1014: if (t1 > tnear)
1015: tnear = t1;
1016: if (t2 < tfar)
1017: tfar = t2;
1018:
1019: if ((tfar < 0.0) || (tnear > tfar)) {
1020: //System.err.println( "z failed: tnear="+tnear+" tfar="+tfar);
1021: return false;
1022: }
1023: //System.err.println("z tnear = " + tnear + " tfar = " + tfar);
1024: }
1025:
1026: if ((tnear < 0.0) && (tfar >= 0.0)) {
1027: // origin is inside the BBox.
1028: position.x = origin.x + dirx * tfar;
1029: position.y = origin.y + diry * tfar;
1030: position.z = origin.z + dirz * tfar;
1031: position.w = tfar;
1032: } else {
1033: position.x = origin.x + dirx * tnear;
1034: position.y = origin.y + diry * tnear;
1035: position.z = origin.z + dirz * tnear;
1036: position.w = tnear;
1037: }
1038:
1039: return true;
1040:
1041: }
1042:
1043: /**
1044: * Test for intersection with a point.
1045: * @param point the pick point
1046: * @param position a point defining the location of the pick w= distance to pick
1047: * @return true or false indicating if an intersection occured
1048: */
1049: boolean intersect(Point3d point, Point4d position) {
1050:
1051: if (boundsIsEmpty) {
1052: return false;
1053: }
1054:
1055: if (boundsIsInfinite) {
1056: position.x = point.x;
1057: position.y = point.y;
1058: position.z = point.z;
1059: position.w = 0.0;
1060: return true;
1061: }
1062:
1063: if (point.x <= upper.x && point.x >= lower.x
1064: && point.y <= upper.y && point.y >= lower.y
1065: && point.z <= upper.z && point.z >= lower.z) {
1066: position.x = point.x;
1067: position.y = point.y;
1068: position.z = point.z;
1069: position.w = 0.0;
1070: return true;
1071: } else
1072: return false;
1073:
1074: }
1075:
1076: /**
1077: * Test for intersection with a segment.
1078: * @param start a point defining the start of the line segment
1079: * @param end a point defining the end of the line segment
1080: * @param position a point defining the location of the pick w= distance to pick
1081: * @return true or false indicating if an intersection occured
1082: */
1083: boolean intersect(Point3d start, Point3d end, Point4d position) {
1084: double t1, t2, tmp, tnear, tfar, invDir, invMag;
1085: double dirx, diry, dirz;
1086:
1087: if (boundsIsEmpty) {
1088: return false;
1089: }
1090:
1091: if (boundsIsInfinite) {
1092: position.x = start.x;
1093: position.y = start.y;
1094: position.z = start.z;
1095: position.w = 0.0;
1096: return true;
1097: }
1098:
1099: dirx = end.x - start.x;
1100: diry = end.y - start.y;
1101: dirz = end.z - start.z;
1102:
1103: double dirLen = dirx * dirx + diry * diry + dirz * dirz;
1104:
1105: // Optimization : Handle zero length direction vector.
1106: if (dirLen == 0.0)
1107: return intersect(start, position);
1108:
1109: dirLen = Math.sqrt(dirLen);
1110: // System.err.println("dirLen is " + dirLen);
1111: invMag = 1.0 / dirLen;
1112: dirx = dirx * invMag;
1113: diry = diry * invMag;
1114: dirz = dirz * invMag;
1115:
1116: /*
1117: System.err.println("dir = " + dir);
1118: System.err.println("start = " + start);
1119: System.err.println("lower = " + lower);
1120: System.err.println("upper = " + upper);
1121: */
1122:
1123: // initialize tnear and tfar to handle dir.? == 0 cases
1124: tnear = -Double.MAX_VALUE;
1125: tfar = Double.MAX_VALUE;
1126:
1127: if (dirx == 0.0) {
1128: //System.err.println("dirx == 0.0");
1129: if (start.x < lower.x || start.x > upper.x) {
1130: //System.err.println( "parallel to x plane and outside");
1131: return false;
1132: }
1133: } else {
1134: invDir = 1.0 / dirx;
1135: t1 = (lower.x - start.x) * invDir;
1136: t2 = (upper.x - start.x) * invDir;
1137:
1138: //System.err.println("x t1 = " + t1 + " t2 = " + t2);
1139: if (t1 > t2) {
1140: tnear = t2;
1141: tfar = t1;
1142: } else {
1143: tnear = t1;
1144: tfar = t2;
1145: }
1146: if (tfar < 0.0) {
1147: //System.err.println( "x failed: tnear="+tnear+" tfar="+tfar);
1148: return false;
1149: }
1150: //System.err.println("x tnear = " + tnear + " tfar = " + tfar);
1151: }
1152: // y
1153: if (diry == 0.0) {
1154: //System.err.println("diry == 0.0");
1155: if (start.y < lower.y || start.y > upper.y) {
1156: //System.err.println( "parallel to y plane and outside");
1157: return false;
1158: }
1159: } else {
1160: invDir = 1.0 / diry;
1161: //System.err.println("invDir = " + invDir);
1162: t1 = (lower.y - start.y) * invDir;
1163: t2 = (upper.y - start.y) * invDir;
1164:
1165: if (t1 > t2) {
1166: tmp = t1;
1167: t1 = t2;
1168: t2 = tmp;
1169: }
1170: //System.err.println("y t1 = " + t1 + " t2 = " + t2);
1171: if (t1 > tnear)
1172: tnear = t1;
1173: if (t2 < tfar)
1174: tfar = t2;
1175:
1176: if ((tfar < 0.0) || (tnear > tfar)) {
1177: //System.err.println( "y failed: tnear="+tnear+" tfar="+tfar);
1178: return false;
1179: }
1180: //System.err.println("y tnear = " + tnear + " tfar = " + tfar);
1181: }
1182:
1183: // z
1184: if (dirz == 0.0) {
1185: //System.err.println("dirz == 0.0");
1186: if (start.z < lower.z || start.z > upper.z) {
1187: //System.err.println( "parallel to z plane and outside");
1188: return false;
1189: }
1190: } else {
1191: invDir = 1.0 / dirz;
1192: t1 = (lower.z - start.z) * invDir;
1193: t2 = (upper.z - start.z) * invDir;
1194:
1195: if (t1 > t2) {
1196: tmp = t1;
1197: t1 = t2;
1198: t2 = tmp;
1199: }
1200: //System.err.println("z t1 = " + t1 + " t2 = " + t2);
1201: if (t1 > tnear)
1202: tnear = t1;
1203: if (t2 < tfar)
1204: tfar = t2;
1205:
1206: if ((tfar < 0.0) || (tnear > tfar)) {
1207: //System.err.println( "z failed: tnear="+tnear+" tfar="+tfar);
1208: return false;
1209: }
1210: //System.err.println("z tnear = " + tnear + " tfar = " + tfar);
1211: }
1212:
1213: if ((tnear < 0.0) && (tfar >= 0.0)) {
1214: // origin is inside the BBox.
1215: position.x = start.x + dirx * tfar;
1216: position.y = start.y + diry * tfar;
1217: position.z = start.z + dirz * tfar;
1218: position.w = tfar;
1219: } else {
1220: if (tnear > dirLen) {
1221: // Segment is behind BBox.
1222: /*
1223: System.err.println("PickSegment : intersected postion : " + position
1224: + " tnear " + tnear + " tfar " + tfar );
1225: */
1226: return false;
1227: }
1228: position.x = start.x + dirx * tnear;
1229: position.y = start.y + diry * tnear;
1230: position.z = start.z + dirz * tnear;
1231:
1232: position.w = tnear;
1233: }
1234:
1235: /*
1236: System.err.println("tnear = " + tnear + " tfar = " + tfar + " w " +
1237: position.w);
1238: System.err.println("lower = " + lower);
1239: System.err.println("upper = " + upper + "\n");
1240: */
1241: return true;
1242:
1243: }
1244:
1245: /**
1246: * Test for intersection with a ray.
1247: * @param origin the starting point of the ray
1248: * @param direction the direction of the ray
1249: * @return true or false indicating if an intersection occured
1250: */
1251: public boolean intersect(Point3d origin, Vector3d direction) {
1252:
1253: if (boundsIsEmpty) {
1254: return false;
1255: }
1256:
1257: if (boundsIsInfinite) {
1258: return true;
1259: }
1260:
1261: Point3d p = new Point3d();
1262: return intersect(origin, direction, p);
1263: }
1264:
1265: /**
1266: * A protected intersect method that returns the point of intersection.
1267: * Used by Picking methods to sort or return closest picked item.
1268: */
1269: boolean intersect(Point3d origin, Vector3d direction,
1270: Point3d intersect) {
1271: double theta = 0.0;
1272:
1273: if (boundsIsEmpty) {
1274: return false;
1275: }
1276:
1277: if (boundsIsInfinite) {
1278: intersect.x = origin.x;
1279: intersect.y = origin.y;
1280: intersect.z = origin.z;
1281: return true;
1282: }
1283:
1284: if (direction.x > 0.0)
1285: theta = Math.max(theta, (lower.x - origin.x) / direction.x);
1286: if (direction.x < 0.0)
1287: theta = Math.max(theta, (upper.x - origin.x) / direction.x);
1288: if (direction.y > 0.0)
1289: theta = Math.max(theta, (lower.y - origin.y) / direction.y);
1290: if (direction.y < 0.0)
1291: theta = Math.max(theta, (upper.y - origin.y) / direction.y);
1292: if (direction.z > 0.0)
1293: theta = Math.max(theta, (lower.z - origin.z) / direction.z);
1294: if (direction.z < 0.0)
1295: theta = Math.max(theta, (upper.z - origin.z) / direction.z);
1296:
1297: intersect.x = origin.x + theta * direction.x;
1298: intersect.y = origin.y + theta * direction.y;
1299: intersect.z = origin.z + theta * direction.z;
1300:
1301: if (intersect.x < (lower.x - EPS))
1302: return false;
1303: if (intersect.x > (upper.x + EPS))
1304: return false;
1305: if (intersect.y < (lower.y - EPS))
1306: return false;
1307: if (intersect.y > (upper.y + EPS))
1308: return false;
1309: if (intersect.z < (lower.z - EPS))
1310: return false;
1311: if (intersect.z > (upper.z + EPS))
1312: return false;
1313:
1314: return true;
1315:
1316: }
1317:
1318: /**
1319: * Test for intersection with a point.
1320: * @param point a point defining a position in 3-space
1321: * @return true or false indicating if an intersection occured
1322: */
1323: public boolean intersect(Point3d point) {
1324:
1325: if (boundsIsEmpty) {
1326: return false;
1327: }
1328: if (boundsIsInfinite) {
1329: return true;
1330: }
1331:
1332: if (point.x <= upper.x && point.x >= lower.x
1333: && point.y <= upper.y && point.y >= lower.y
1334: && point.z <= upper.z && point.z >= lower.z)
1335: return true;
1336: else
1337: return false;
1338: }
1339:
1340: /**
1341: * Tests whether the bounding box is empty. A bounding box is
1342: * empty if it is null (either by construction or as the result of
1343: * a null intersection) or if its volume is negative. A bounding box
1344: * with a volume of zero is <i>not</i> empty.
1345: * @return true if the bounding box is empty; otherwise, it returns false
1346: */
1347: public boolean isEmpty() {
1348:
1349: return boundsIsEmpty;
1350: }
1351:
1352: /**
1353: * Test for intersection with another bounds object.
1354: * @param boundsObject another bounds object
1355: * @return true or false indicating if an intersection occured
1356: */
1357: boolean intersect(Bounds boundsObject, Point4d position) {
1358: return intersect(boundsObject);
1359: }
1360:
1361: /**
1362: * Test for intersection with another bounds object.
1363: * @param boundsObject another bounds object
1364: * @return true or false indicating if an intersection occured
1365: */
1366: public boolean intersect(Bounds boundsObject) {
1367:
1368: if (boundsObject == null) {
1369: return false;
1370: }
1371:
1372: if (boundsIsEmpty || boundsObject.boundsIsEmpty) {
1373: return false;
1374: }
1375:
1376: if (boundsIsInfinite || boundsObject.boundsIsInfinite) {
1377: return true;
1378: }
1379:
1380: if (boundsObject.boundId == BOUNDING_BOX) {
1381: BoundingBox box = (BoundingBox) boundsObject;
1382: // both boxes are axis aligned
1383: if (upper.x > box.lower.x && box.upper.x > lower.x
1384: && upper.y > box.lower.y && box.upper.y > lower.y
1385: && upper.z > box.lower.z && box.upper.z > lower.z)
1386: return true;
1387: else
1388: return false;
1389: } else if (boundsObject.boundId == BOUNDING_SPHERE) {
1390: BoundingSphere sphere = (BoundingSphere) boundsObject;
1391: double rad_sq = sphere.radius * sphere.radius;
1392: double dis = 0.0;
1393:
1394: if (sphere.center.x < lower.x)
1395: dis = (sphere.center.x - lower.x)
1396: * (sphere.center.x - lower.x);
1397: else if (sphere.center.x > upper.x)
1398: dis = (sphere.center.x - upper.x)
1399: * (sphere.center.x - upper.x);
1400:
1401: if (sphere.center.y < lower.y)
1402: dis += (sphere.center.y - lower.y)
1403: * (sphere.center.y - lower.y);
1404: else if (sphere.center.y > upper.y)
1405: dis += (sphere.center.y - upper.y)
1406: * (sphere.center.y - upper.y);
1407:
1408: if (sphere.center.z < lower.z)
1409: dis += (sphere.center.z - lower.z)
1410: * (sphere.center.z - lower.z);
1411: else if (sphere.center.z > upper.z)
1412: dis += (sphere.center.z - upper.z)
1413: * (sphere.center.z - upper.z);
1414:
1415: if (dis <= rad_sq)
1416: return true;
1417: else
1418: return false;
1419: } else if (boundsObject.boundId == BOUNDING_POLYTOPE) {
1420: // intersect an axis aligned box with a polytope
1421: return intersect_ptope_abox(
1422: (BoundingPolytope) boundsObject, this );
1423: } else {
1424: throw new IllegalArgumentException(J3dI18N
1425: .getString("BoundingBox6"));
1426: }
1427:
1428: }
1429:
1430: /**
1431: * Test for intersection with an array of bounds objects.
1432: * @param boundsObjects an array of bounding objects
1433: * @return true or false indicating if an intersection occured
1434: */
1435: public boolean intersect(Bounds[] boundsObjects) {
1436:
1437: double distsq, radsq;
1438: int i;
1439:
1440: if (boundsObjects == null || boundsObjects.length <= 0) {
1441: return false;
1442: }
1443:
1444: if (boundsIsEmpty) {
1445: return false;
1446: }
1447:
1448: for (i = 0; i < boundsObjects.length; i++) {
1449: if (boundsObjects[i] == null
1450: || boundsObjects[i].boundsIsEmpty)
1451: ;
1452: else if (boundsIsInfinite
1453: || boundsObjects[i].boundsIsInfinite) {
1454: return true; // We're done here.
1455: } else if (boundsObjects[i].boundId == BOUNDING_BOX) {
1456: BoundingBox box = (BoundingBox) boundsObjects[i];
1457: // both boxes are axis aligned
1458: if (upper.x > box.lower.x && box.upper.x > lower.x
1459: && upper.y > box.lower.y
1460: && box.upper.y > lower.y
1461: && upper.z > box.lower.z
1462: && box.upper.z > lower.z)
1463: return true;
1464: } else if (boundsObjects[i].boundId == BOUNDING_SPHERE) {
1465: BoundingSphere sphere = (BoundingSphere) boundsObjects[i];
1466: double rad_sq = sphere.radius * sphere.radius;
1467: double dis = 0.0;
1468:
1469: if (sphere.center.x < lower.x)
1470: dis = (sphere.center.x - lower.x)
1471: * (sphere.center.x - lower.x);
1472: else if (sphere.center.x > upper.x)
1473: dis = (sphere.center.x - upper.x)
1474: * (sphere.center.x - upper.x);
1475:
1476: if (sphere.center.y < lower.y)
1477: dis += (sphere.center.y - lower.y)
1478: * (sphere.center.y - lower.y);
1479: else if (sphere.center.y > upper.y)
1480: dis += (sphere.center.y - upper.y)
1481: * (sphere.center.y - upper.y);
1482:
1483: if (sphere.center.z < lower.z)
1484: dis += (sphere.center.z - lower.z)
1485: * (sphere.center.z - lower.z);
1486: else if (sphere.center.z > upper.z)
1487: dis += (sphere.center.z - upper.z)
1488: * (sphere.center.z - upper.z);
1489:
1490: if (dis <= rad_sq)
1491: return true;
1492:
1493: } else if (boundsObjects[i].boundId == BOUNDING_POLYTOPE) {
1494: if (intersect_ptope_abox(
1495: (BoundingPolytope) boundsObjects[i], this ))
1496: return true;
1497: } else {
1498: // System.err.println("intersect ?? ");
1499: }
1500: }
1501:
1502: return false;
1503: }
1504:
1505: /**
1506: * Test for intersection with another bounding box.
1507: * @param boundsObject another bounding object
1508: * @param newBoundBox the new bounding box which is the intersection of
1509: * the boundsObject and this BoundingBox
1510: * @return true or false indicating if an intersection occured
1511: */
1512: public boolean intersect(Bounds boundsObject,
1513: BoundingBox newBoundBox) {
1514:
1515: if ((boundsObject == null) || boundsIsEmpty
1516: || boundsObject.boundsIsEmpty) {
1517: // Negative volume.
1518: newBoundBox.setLower(1.0d, 1.0d, 1.0d);
1519: newBoundBox.setUpper(-1.0d, -1.0d, -1.0d);
1520: return false;
1521: }
1522:
1523: if (boundsIsInfinite && (!boundsObject.boundsIsInfinite)) {
1524: newBoundBox.set(boundsObject);
1525: return true;
1526: } else if ((!boundsIsInfinite) && boundsObject.boundsIsInfinite) {
1527: newBoundBox.set(this );
1528: return true;
1529: } else if (boundsIsInfinite && boundsObject.boundsIsInfinite) {
1530: newBoundBox.set(this );
1531: return true;
1532: } else if (boundsObject.boundId == BOUNDING_BOX) {
1533: BoundingBox box = (BoundingBox) boundsObject;
1534: // both boxes are axis aligned
1535: if (upper.x > box.lower.x && box.upper.x > lower.x
1536: && upper.y > box.lower.y && box.upper.y > lower.y
1537: && upper.z > box.lower.z && box.upper.z > lower.z) {
1538:
1539: if (upper.x > box.upper.x)
1540: newBoundBox.upper.x = box.upper.x;
1541: else
1542: newBoundBox.upper.x = upper.x;
1543:
1544: if (upper.y > box.upper.y)
1545: newBoundBox.upper.y = box.upper.y;
1546: else
1547: newBoundBox.upper.y = upper.y;
1548:
1549: if (upper.z > box.upper.z)
1550: newBoundBox.upper.z = box.upper.z;
1551: else
1552: newBoundBox.upper.z = upper.z;
1553:
1554: if (lower.x < box.lower.x)
1555: newBoundBox.lower.x = box.lower.x;
1556: else
1557: newBoundBox.lower.x = lower.x;
1558:
1559: if (lower.y < box.lower.y)
1560: newBoundBox.lower.y = box.lower.y;
1561: else
1562: newBoundBox.lower.y = lower.y;
1563:
1564: if (lower.z < box.lower.z)
1565: newBoundBox.lower.z = box.lower.z;
1566: else
1567: newBoundBox.lower.z = lower.z;
1568:
1569: newBoundBox.updateBoundsStates();
1570: return true;
1571: } else {
1572: // Negative volume.
1573: newBoundBox.setLower(1.0d, 1.0d, 1.0d);
1574: newBoundBox.setUpper(-1.0d, -1.0d, -1.0d);
1575: return false;
1576: }
1577: } else if (boundsObject.boundId == BOUNDING_SPHERE) {
1578: BoundingSphere sphere = (BoundingSphere) boundsObject;
1579: if (this .intersect(sphere)) {
1580: BoundingBox sbox = new BoundingBox(sphere);
1581: this .intersect(sbox, newBoundBox);
1582: return true;
1583: } else {
1584: // Negative volume.
1585: newBoundBox.setLower(1.0d, 1.0d, 1.0d);
1586: newBoundBox.setUpper(-1.0d, -1.0d, -1.0d);
1587: return false;
1588: }
1589:
1590: // System.err.println("intersect Sphere ");
1591: } else if (boundsObject.boundId == BOUNDING_POLYTOPE) {
1592: BoundingPolytope polytope = (BoundingPolytope) boundsObject;
1593: if (this .intersect(polytope)) {
1594: BoundingBox pbox = new BoundingBox(polytope); // convert polytope to box
1595: this .intersect(pbox, newBoundBox);
1596: return true;
1597: } else {
1598: // Negative volume.
1599: newBoundBox.setLower(1.0d, 1.0d, 1.0d);
1600: newBoundBox.setUpper(-1.0d, -1.0d, -1.0d);
1601: return false;
1602: }
1603: } else {
1604: throw new IllegalArgumentException(J3dI18N
1605: .getString("BoundingBox7"));
1606: }
1607: }
1608:
1609: /**
1610: * Test for intersection with an array of bounds objects.
1611: * @param boundsObjects an array of bounds objects
1612: * @param newBoundBox the new bounding box which is the intersection of
1613: * the boundsObject and this BoundingBox
1614: * @return true or false indicating if an intersection occured
1615: */
1616: public boolean intersect(Bounds[] boundsObjects,
1617: BoundingBox newBoundBox) {
1618:
1619: if (boundsObjects == null || boundsObjects.length <= 0
1620: || boundsIsEmpty) {
1621: // Negative volume.
1622: newBoundBox.setLower(1.0d, 1.0d, 1.0d);
1623: newBoundBox.setUpper(-1.0d, -1.0d, -1.0d);
1624: return false;
1625: }
1626:
1627: int i = 0;
1628: // find first non null bounds object
1629: while (boundsObjects[i] == null && i < boundsObjects.length) {
1630: i++;
1631: }
1632:
1633: if (i >= boundsObjects.length) { // all bounds objects were empty
1634: // Negative volume.
1635: newBoundBox.setLower(1.0d, 1.0d, 1.0d);
1636: newBoundBox.setUpper(-1.0d, -1.0d, -1.0d);
1637: return false;
1638: }
1639:
1640: boolean status = false;
1641: BoundingBox tbox = new BoundingBox();
1642:
1643: for (; i < boundsObjects.length; i++) {
1644: if (boundsObjects[i] == null
1645: || boundsObjects[i].boundsIsEmpty)
1646: ;
1647: else if (boundsObjects[i].boundId == BOUNDING_BOX) {
1648: BoundingBox box = (BoundingBox) boundsObjects[i];
1649: // both boxes are axis aligned
1650: if (upper.x > box.lower.x && box.upper.x > lower.x
1651: && upper.y > box.lower.y
1652: && box.upper.y > lower.y
1653: && upper.z > box.lower.z
1654: && box.upper.z > lower.z) {
1655:
1656: if (upper.x > box.upper.x)
1657: newBoundBox.upper.x = box.upper.x;
1658: else
1659: newBoundBox.upper.x = upper.x;
1660:
1661: if (upper.y > box.upper.y)
1662: newBoundBox.upper.y = box.upper.y;
1663: else
1664: newBoundBox.upper.y = upper.y;
1665:
1666: if (upper.z > box.upper.z)
1667: newBoundBox.upper.z = box.upper.z;
1668: else
1669: newBoundBox.upper.z = upper.z;
1670:
1671: if (lower.x < box.lower.x)
1672: newBoundBox.lower.x = box.lower.x;
1673: else
1674: newBoundBox.lower.x = lower.x;
1675:
1676: if (lower.y < box.lower.y)
1677: newBoundBox.lower.y = box.lower.y;
1678: else
1679: newBoundBox.lower.y = lower.y;
1680:
1681: if (lower.z < box.lower.z)
1682: newBoundBox.lower.z = box.lower.z;
1683: else
1684: newBoundBox.lower.z = lower.z;
1685: status = true;
1686: newBoundBox.updateBoundsStates();
1687: }
1688: } else if (boundsObjects[i].boundId == BOUNDING_SPHERE) {
1689: BoundingSphere sphere = (BoundingSphere) boundsObjects[i];
1690: if (this .intersect(sphere)) {
1691: BoundingBox sbox = new BoundingBox(sphere); // convert sphere to box
1692: this .intersect(sbox, tbox); // insersect two boxes
1693: if (status) {
1694: newBoundBox.combine(tbox);
1695: } else {
1696: newBoundBox.set(tbox);
1697: status = true;
1698: }
1699: }
1700:
1701: } else if (boundsObjects[i].boundId == BOUNDING_POLYTOPE) {
1702: BoundingPolytope polytope = (BoundingPolytope) boundsObjects[i];
1703: if (this .intersect(polytope)) {
1704: BoundingBox pbox = new BoundingBox(polytope); // convert polytope to box
1705: this .intersect(pbox, tbox); // insersect two boxes
1706: if (status) {
1707: newBoundBox.combine(tbox);
1708: } else {
1709: newBoundBox.set(tbox);
1710: status = true;
1711: }
1712: }
1713: } else {
1714: throw new IllegalArgumentException(J3dI18N
1715: .getString("BoundingBox6"));
1716: }
1717:
1718: if (newBoundBox.boundsIsInfinite)
1719: break; // We're done.
1720: }
1721: if (status == false) {
1722: // Negative volume.
1723: newBoundBox.setLower(1.0d, 1.0d, 1.0d);
1724: newBoundBox.setUpper(-1.0d, -1.0d, -1.0d);
1725: }
1726: return status;
1727: }
1728:
1729: /**
1730: * Finds closest bounding object that intersects this bounding box.
1731: * @param boundsObjects an array of bounds objects
1732: * @return closest bounding object
1733: */
1734: public Bounds closestIntersection(Bounds[] boundsObjects) {
1735:
1736: if (boundsObjects == null || boundsObjects.length <= 0) {
1737: return null;
1738: }
1739:
1740: if (boundsIsEmpty) {
1741: return null;
1742: }
1743:
1744: getCenter();
1745:
1746: double dis, far_dis, pdist, x, y, z, rad_sq;
1747: double cenX = 0.0, cenY = 0.0, cenZ = 0.0;
1748: boolean contains = false;
1749: boolean inside;
1750: boolean intersect = false;
1751: double smallest_distance = Double.MAX_VALUE;
1752: int i, j, index = 0;
1753:
1754: for (i = 0; i < boundsObjects.length; i++) {
1755: if (boundsObjects[i] == null)
1756: ;
1757:
1758: else if (this .intersect(boundsObjects[i])) {
1759: intersect = true;
1760: if (boundsObjects[i].boundId == BOUNDING_BOX) {
1761: BoundingBox box = (BoundingBox) boundsObjects[i];
1762: cenX = (box.upper.x + box.lower.x) / 2.0;
1763: cenY = (box.upper.y + box.lower.y) / 2.0;
1764: cenZ = (box.upper.z + box.lower.z) / 2.0;
1765: dis = Math.sqrt((centroid.x - cenX)
1766: * (centroid.x - cenX) + (centroid.y - cenY)
1767: * (centroid.y - cenY) + (centroid.z - cenZ)
1768: * (centroid.z - cenZ));
1769: inside = false;
1770:
1771: if (lower.x <= box.lower.x
1772: && lower.y <= box.lower.y
1773: && lower.z <= box.lower.z
1774: && upper.x >= box.upper.x
1775: && upper.y >= box.upper.y
1776: && upper.z >= box.upper.z) { // box is contained
1777: inside = true;
1778: }
1779: if (inside) {
1780: if (!contains) { // initialize smallest_distance for the first containment
1781: index = i;
1782: smallest_distance = dis;
1783: contains = true;
1784: } else {
1785: if (dis < smallest_distance) {
1786: index = i;
1787: smallest_distance = dis;
1788: }
1789: }
1790: } else if (!contains) {
1791: if (dis < smallest_distance) {
1792: index = i;
1793: smallest_distance = dis;
1794: }
1795: }
1796:
1797: } else if (boundsObjects[i].boundId == BOUNDING_SPHERE) {
1798: BoundingSphere sphere = (BoundingSphere) boundsObjects[i];
1799: dis = Math.sqrt((centroid.x - sphere.center.x)
1800: * (centroid.x - sphere.center.x)
1801: + (centroid.y - sphere.center.y)
1802: * (centroid.y - sphere.center.y)
1803: + (centroid.z - sphere.center.z)
1804: * (centroid.z - sphere.center.z));
1805:
1806: inside = false;
1807:
1808: // sphere sphere.center is inside box
1809: if (sphere.center.x <= upper.x
1810: && sphere.center.x >= lower.x
1811: && sphere.center.y <= upper.y
1812: && sphere.center.y >= lower.y
1813: && sphere.center.z <= upper.z
1814: && sphere.center.z >= lower.z) {
1815: // check if sphere intersects any side
1816: if (sphere.center.x - lower.x >= sphere.radius
1817: && upper.x - sphere.center.x >= sphere.radius
1818: && sphere.center.y - lower.y >= sphere.radius
1819: && upper.y - sphere.center.y >= sphere.radius
1820: && sphere.center.z - lower.z >= sphere.radius
1821: && upper.z - sphere.center.z >= sphere.radius) {
1822: // contains the sphere
1823: inside = true;
1824: }
1825: }
1826: if (inside) {
1827: // initialize smallest_distance for the first containment
1828: if (!contains) {
1829: index = i;
1830: smallest_distance = dis;
1831: contains = true;
1832: } else {
1833: if (dis < smallest_distance) {
1834: index = i;
1835: smallest_distance = dis;
1836: }
1837: }
1838: } else if (!contains) {
1839: if (dis < smallest_distance) {
1840: index = i;
1841: smallest_distance = dis;
1842: }
1843: }
1844: } else if (boundsObjects[i].boundId == BOUNDING_POLYTOPE) {
1845: BoundingPolytope polytope = (BoundingPolytope) boundsObjects[i];
1846: dis = Math.sqrt((centroid.x - polytope.centroid.x)
1847: * (centroid.x - polytope.centroid.x)
1848: + (centroid.y - polytope.centroid.y)
1849: * (centroid.y - polytope.centroid.y)
1850: + (centroid.z - polytope.centroid.z)
1851: * (centroid.z - polytope.centroid.z));
1852: inside = true;
1853: for (j = 0; j < polytope.nVerts; j++) {
1854: if (polytope.verts[j].x < lower.x
1855: || polytope.verts[j].y < lower.y
1856: || polytope.verts[j].z < lower.z
1857: || polytope.verts[j].x > upper.x
1858: || polytope.verts[j].y > upper.y
1859: || polytope.verts[j].z > upper.z) { // box contains polytope
1860: inside = false;
1861:
1862: }
1863:
1864: }
1865: if (inside) {
1866: if (!contains) { // initialize smallest_distance for the first containment
1867: index = i;
1868: smallest_distance = dis;
1869: contains = true;
1870: } else {
1871: if (dis < smallest_distance) {
1872: index = i;
1873: smallest_distance = dis;
1874: }
1875: }
1876: } else if (!contains) {
1877: if (dis < smallest_distance) {
1878: index = i;
1879: smallest_distance = dis;
1880: }
1881: }
1882:
1883: } else {
1884: throw new IllegalArgumentException(J3dI18N
1885: .getString("BoundingBox9"));
1886: }
1887: }
1888: }
1889:
1890: if (intersect)
1891: return boundsObjects[index];
1892: else
1893: return null;
1894: }
1895:
1896: /**
1897: * Tests for intersection of box and frustum.
1898: * @param frustum
1899: * @return true if they intersect
1900: */
1901: boolean intersect(CachedFrustum frustum) {
1902:
1903: if (boundsIsEmpty)
1904: return false;
1905:
1906: if (boundsIsInfinite)
1907: return true;
1908:
1909: // System.err.println("intersect frustum with box="+this.toString());
1910: // System.err.println("frustum "+frustum.toString());
1911: // check if box and bounding box of frustum intersect
1912: if ((upper.x < frustum.lower.x) || (lower.x > frustum.upper.x)
1913: || (upper.y < frustum.lower.y)
1914: || (lower.y > frustum.upper.y)
1915: || (upper.z < frustum.lower.z)
1916: || (lower.z > frustum.upper.z)) {
1917:
1918: // System.err.println("*** box and bounding box of frustum do not intersect");
1919: return false;
1920: }
1921:
1922: // check if all box points out any frustum plane
1923: int i = 5;
1924: while (i >= 0) {
1925: Vector4d vc = frustum.clipPlanes[i--];
1926: if (((upper.x * vc.x + upper.y * vc.y + upper.z * vc.z + vc.w) < 0.0)
1927: && ((upper.x * vc.x + lower.y * vc.y + upper.z
1928: * vc.z + vc.w) < 0.0)
1929: && ((upper.x * vc.x + lower.y * vc.y + lower.z
1930: * vc.z + vc.w) < 0.0)
1931: && ((upper.x * vc.x + upper.y * vc.y + lower.z
1932: * vc.z + vc.w) < 0.0)
1933: && ((lower.x * vc.x + upper.y * vc.y + upper.z
1934: * vc.z + vc.w) < 0.0)
1935: && ((lower.x * vc.x + lower.y * vc.y + upper.z
1936: * vc.z + vc.w) < 0.0)
1937: && ((lower.x * vc.x + lower.y * vc.y + lower.z
1938: * vc.z + vc.w) < 0.0)
1939: && ((lower.x * vc.x + upper.y * vc.y + lower.z
1940: * vc.z + vc.w) < 0.0)) {
1941: // all corners outside this frustum plane
1942: // System.err.println("*** all corners outside this frustum plane");
1943: return false;
1944: }
1945: }
1946:
1947: return true;
1948: }
1949:
1950: /**
1951: * Returns a string representation of this class.
1952: */
1953: public String toString() {
1954: return new String("Bounding box: Lower=" + lower.x + " "
1955: + lower.y + " " + lower.z + " Upper=" + upper.x + " "
1956: + upper.y + " " + upper.z);
1957: }
1958:
1959: private void updateBoundsStates() {
1960: if ((lower.x == Double.NEGATIVE_INFINITY)
1961: && (lower.y == Double.NEGATIVE_INFINITY)
1962: && (lower.z == Double.NEGATIVE_INFINITY)
1963: && (upper.x == Double.POSITIVE_INFINITY)
1964: && (upper.y == Double.POSITIVE_INFINITY)
1965: && (upper.z == Double.POSITIVE_INFINITY)) {
1966: boundsIsEmpty = false;
1967: boundsIsInfinite = true;
1968: return;
1969: }
1970:
1971: if (checkBoundsIsNaN()) {
1972: boundsIsEmpty = true;
1973: boundsIsInfinite = false;
1974: return;
1975: } else {
1976: boundsIsInfinite = false;
1977: if (lower.x > upper.x || lower.y > upper.y
1978: || lower.z > upper.z) {
1979: boundsIsEmpty = true;
1980: } else {
1981: boundsIsEmpty = false;
1982: }
1983: }
1984: }
1985:
1986: // For a infinite bounds. What is the centroid ?
1987: Point3d getCenter() {
1988: if (centroid == null) {
1989: centroid = new Point3d();
1990: }
1991:
1992: centroid.x = (upper.x + lower.x) * 0.5;
1993: centroid.y = (upper.y + lower.y) * 0.5;
1994: centroid.z = (upper.z + lower.z) * 0.5;
1995:
1996: return centroid;
1997: }
1998:
1999: void translate(BoundingBox bbox, Vector3d value) {
2000: if (bbox == null || bbox.boundsIsEmpty) {
2001: // Negative volume.
2002: setLower(1.0d, 1.0d, 1.0d);
2003: setUpper(-1.0d, -1.0d, -1.0d);
2004: return;
2005: }
2006: if (bbox.boundsIsInfinite) {
2007: this .set(bbox);
2008: return;
2009: }
2010:
2011: lower.x = bbox.lower.x + value.x;
2012: lower.y = bbox.lower.y + value.y;
2013: lower.z = bbox.lower.z + value.z;
2014: upper.x = bbox.upper.x + value.x;
2015: upper.y = bbox.upper.y + value.y;
2016: upper.z = bbox.upper.z + value.z;
2017: }
2018:
2019: /**
2020: * if the passed the "region" is same type as this object
2021: * then do a copy, otherwise clone the Bounds and
2022: * return
2023: */
2024: Bounds copy(Bounds r) {
2025: if (r != null && this .boundId == r.boundId) {
2026: BoundingBox region = (BoundingBox) r;
2027: region.lower.x = lower.x;
2028: region.lower.y = lower.y;
2029: region.lower.z = lower.z;
2030: region.upper.x = upper.x;
2031: region.upper.y = upper.y;
2032: region.upper.z = upper.z;
2033: region.boundsIsEmpty = boundsIsEmpty;
2034: region.boundsIsInfinite = boundsIsInfinite;
2035: return region;
2036: } else {
2037: return (Bounds) this .clone();
2038: }
2039: }
2040:
2041: // Check is any of the bounds is a NaN, if yes, then
2042: // set it an empty bounds
2043: boolean checkBoundsIsNaN() {
2044: if (Double.isNaN(lower.x + lower.y + lower.z + upper.x
2045: + upper.y + upper.z)) {
2046: return true;
2047: }
2048:
2049: return false;
2050: }
2051:
2052: int getPickType() {
2053: return PickShape.PICKBOUNDINGBOX;
2054: }
2055: }
|