001: /*
002: * $RCSfile: PickCylinderRay.java,v $
003: *
004: * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
006: *
007: * This code is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License version 2 only, as
009: * published by the Free Software Foundation. Sun designates this
010: * particular file as subject to the "Classpath" exception as provided
011: * by Sun in the LICENSE file that accompanied this code.
012: *
013: * This code is distributed in the hope that it will be useful, but WITHOUT
014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: * version 2 for more details (a copy is included in the LICENSE file that
017: * accompanied this code).
018: *
019: * You should have received a copy of the GNU General Public License version
020: * 2 along with this work; if not, write to the Free Software Foundation,
021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
024: * CA 95054 USA or visit www.sun.com if you need additional information or
025: * have any questions.
026: *
027: * $Revision: 1.7 $
028: * $Date: 2008/02/28 20:17:27 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import javax.vecmath.*;
035: import com.sun.j3d.internal.Distance;
036:
037: /**
038: * PickCylinderRay is an infinite cylindrical ray pick shape. It can
039: * be used as an argument to the picking methods in BranchGroup and Locale.
040: *
041: * @see BranchGroup#pickAll
042: * @see Locale#pickAll
043: *
044: * @since Java 3D 1.2
045: */
046:
047: public final class PickCylinderRay extends PickCylinder {
048:
049: /**
050: * Constructs an empty PickCylinderRay.
051: * The origin and direction of the cylindrical ray are
052: * initialized to (0,0,0). The radius is initialized
053: * to 0.
054: */
055: public PickCylinderRay() {
056: }
057:
058: /**
059: * Constructs an infinite cylindrical ray pick shape from the specified
060: * parameters.
061: * @param origin the origin of the cylindrical ray.
062: * @param direction the direction of the cylindrical ray.
063: * @param radius the radius of the cylindrical ray.
064: */
065: public PickCylinderRay(Point3d origin, Vector3d direction,
066: double radius) {
067: this .origin = new Point3d(origin);
068: this .direction = new Vector3d(direction);
069: this .radius = radius;
070: }
071:
072: /**
073: * Sets the parameters of this PickCylinderRay to the specified values.
074: * @param origin the origin of the cylindrical ray.
075: * @param direction the direction of the cylindrical ray.
076: * @param radius the radius of the cylindrical ray.
077: */
078: public void set(Point3d origin, Vector3d direction, double radius) {
079: this .origin.set(origin);
080: this .direction.set(direction);
081: this .radius = radius;
082: }
083:
084: /**
085: * Return true if shape intersect with bounds.
086: * The point of intersection is stored in pickPos.
087: * @param bounds the bounds object to check
088: * @param pickPos the location of the point of intersection (not used for
089: * method. Provided for compatibility).
090: */
091: final boolean intersect(Bounds bounds, Point4d pickPos) {
092: Point4d iPnt = new Point4d();
093:
094: //
095: // ================ BOUNDING SPHERE ================
096: //
097: if (bounds instanceof BoundingSphere) {
098: Point3d sphCenter = ((BoundingSphere) bounds).getCenter();
099: double sphRadius = ((BoundingSphere) bounds).getRadius();
100: double sqDist = Distance.pointToRay(sphCenter, origin,
101: direction);
102: if (sqDist <= (sphRadius + radius) * (sphRadius + radius)) {
103: return true;
104: }
105: return false;
106: }
107: //
108: // ================ BOUNDING BOX ================
109: //
110: else if (bounds instanceof BoundingBox) {
111: // Calculate radius of BoundingBox
112: Point3d lower = new Point3d();
113: ((BoundingBox) bounds).getLower(lower);
114:
115: Point3d center = ((BoundingBox) bounds).getCenter();
116:
117: double temp = (center.x - lower.x + radius);
118: double boxRadiusSquared = temp * temp;
119: temp = (center.y - lower.y + radius);
120: boxRadiusSquared += temp * temp;
121: temp = (center.z - lower.z + radius);
122: boxRadiusSquared += temp * temp;
123:
124: // First, see if cylinder is too far away from BoundingBox
125: double sqDist = Distance.pointToRay(center, origin,
126: direction);
127:
128: if (sqDist > boxRadiusSquared) {
129: return false; // we are too far to intersect
130: } else if (sqDist < (radius * radius)) {
131: return true; // center is in cylinder
132: }
133:
134: // Then, see if ray intersects
135: if (bounds.intersect(origin, direction, iPnt)) {
136: return true;
137: }
138:
139: // Ray does not intersect, test for distance with each edge
140: Point3d upper = new Point3d();
141: ((BoundingBox) bounds).getUpper(upper);
142:
143: Point3d[][] edges = {
144: // Top horizontal 4
145: { upper, new Point3d(lower.x, upper.y, upper.z) },
146: { new Point3d(lower.x, upper.y, upper.z),
147: new Point3d(lower.x, lower.y, upper.z) },
148: { new Point3d(lower.x, lower.y, upper.z),
149: new Point3d(upper.x, lower.y, upper.z) },
150: { new Point3d(upper.x, lower.y, upper.z), upper },
151: // Bottom horizontal 4
152: { lower, new Point3d(lower.x, upper.y, lower.z) },
153: { new Point3d(lower.x, upper.y, lower.z),
154: new Point3d(upper.x, upper.y, lower.z) },
155: { new Point3d(upper.x, upper.y, lower.z),
156: new Point3d(upper.x, lower.y, lower.z) },
157: { new Point3d(upper.x, lower.y, lower.z), lower },
158: // Vertical 4
159: { lower, new Point3d(lower.x, lower.y, upper.z) },
160: { new Point3d(lower.x, upper.y, lower.z),
161: new Point3d(lower.x, upper.y, upper.z) },
162: { new Point3d(upper.x, upper.y, lower.z),
163: new Point3d(upper.x, upper.y, upper.z) },
164: { new Point3d(upper.x, lower.y, lower.z),
165: new Point3d(upper.x, lower.y, upper.z) } };
166:
167: for (int i = 0; i < edges.length; i++) {
168: // System.err.println ("Testing edge: "+edges[i][0]+" - "+edges[i][1]);
169: double distToEdge = Distance.rayToSegment(origin,
170: direction, edges[i][0], edges[i][1]);
171: if (distToEdge <= radius * radius) {
172: // System.err.println ("Intersects!");
173: return true;
174: }
175: }
176:
177: return false; // Not close enough
178: }
179: //
180: // ================ BOUNDING POLYTOPE ================
181: //
182: else if (bounds instanceof BoundingPolytope) {
183: int i, j;
184:
185: // First, check to see if we are too far to intersect the polytope's
186: // bounding sphere
187: Point3d sphCenter = new Point3d();
188: BoundingSphere bsphere = new BoundingSphere(bounds);
189:
190: bsphere.getCenter(sphCenter);
191: double sphRadius = bsphere.getRadius();
192:
193: double sqDist = Distance.pointToRay(sphCenter, origin,
194: direction);
195: if (sqDist > (sphRadius + radius) * (sphRadius + radius)) {
196: return false; // we are too far to intersect
197: }
198:
199: // Now check to see if ray intersects with polytope
200: if (bounds.intersect(origin, direction, iPnt)) {
201: return true;
202: }
203:
204: // Now check distance to edges. Since we don't know a priori how
205: // the polytope is structured, we will cycle through. We discard edges
206: // when their center is not on the polytope surface.
207: BoundingPolytope ptope = (BoundingPolytope) bounds;
208: Point3d midpt = new Point3d();
209: double distToEdge;
210: for (i = 0; i < ptope.nVerts; i++) {
211: for (j = i; i < ptope.nVerts; i++) {
212: // XXXX: make BoundingPolytope.pointInPolytope available to package
213: // scope
214: midpt.x = (ptope.verts[i].x + ptope.verts[j].x) * 0.5;
215: midpt.y = (ptope.verts[i].y + ptope.verts[j].y) * 0.5;
216: midpt.z = (ptope.verts[i].z + ptope.verts[j].z) * 0.5;
217:
218: if (!PickCylinder.pointInPolytope(ptope, midpt.x,
219: midpt.y, midpt.z)) {
220: continue;
221: }
222: distToEdge = Distance.rayToSegment(origin,
223: direction, ptope.verts[i], ptope.verts[j]);
224: if (distToEdge <= radius * radius) {
225: return true;
226: }
227: }
228: }
229: return false;
230: }
231: /*
232: else {
233: throw new RuntimeException("intersect method not implemented");
234: }
235: */
236: return false;
237: }
238:
239: // Only use within J3D.
240: // Return a new PickCylinderRay that is the transformed (t3d) of this pickCylinderRay.
241: PickShape transform(Transform3D t3d) {
242:
243: PickCylinderRay newPCR = new PickCylinderRay();
244: Point3d end = new Point3d();
245: /*
246: System.err.println("t3d : ");
247: System.err.println(t3d);
248: */
249: newPCR.origin.x = origin.x;
250: newPCR.origin.y = origin.y;
251: newPCR.origin.z = origin.z;
252: newPCR.radius = radius * t3d.getScale();
253:
254: end.x = origin.x + direction.x;
255: end.y = origin.y + direction.y;
256: end.z = origin.z + direction.z;
257:
258: t3d.transform(newPCR.origin);
259: t3d.transform(end);
260:
261: newPCR.direction.x = end.x - newPCR.origin.x;
262: newPCR.direction.y = end.y - newPCR.origin.y;
263: newPCR.direction.z = end.z - newPCR.origin.z;
264: newPCR.direction.normalize();
265:
266: return newPCR;
267: }
268:
269: }
|