001: /*
002: * $RCSfile: PickConeRay.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: * PickConeRay is an infinite cone 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: public final class PickConeRay extends PickCone {
047:
048: /**
049: * Constructs an empty PickConeRay.
050: * The origin and direction of the cone are
051: * initialized to (0,0,0). The spread angle is initialized
052: * to <code>PI/64</code> radians.
053: */
054: public PickConeRay() {
055: }
056:
057: /**
058: * Constructs an infinite cone pick shape from the specified
059: * parameters.
060: * @param origin the origin of the cone
061: * @param direction the direction of the cone
062: * @param spreadAngle the spread angle of the cone in radians
063: */
064: public PickConeRay(Point3d origin, Vector3d direction,
065: double spreadAngle) {
066: this .origin = new Point3d(origin);
067: this .direction = new Vector3d(direction);
068: this .spreadAngle = spreadAngle;
069: }
070:
071: /**
072: * Sets the parameters of this PickCone to the specified values.
073: * @param origin the origin of the cone
074: * @param direction the direction of the cone
075: * @param spreadAngle the spread angle of the cone in radians
076: */
077: public void set(Point3d origin, Vector3d direction,
078: double spreadAngle) {
079: this .origin.set(origin);
080: this .direction.set(direction);
081: this .spreadAngle = spreadAngle;
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:
093: Point4d iPnt = new Point4d();
094: Vector3d vector = new Vector3d();
095: double distance;
096: double radius;
097: Point3d rayPt = new Point3d();
098:
099: //
100: // ================ BOUNDING SPHERE ================
101: //
102: if (bounds instanceof BoundingSphere) {
103: Point3d sphCenter = ((BoundingSphere) bounds).getCenter();
104: double sphRadius = ((BoundingSphere) bounds).getRadius();
105: double sqDist = Distance.pointToRay(sphCenter, origin,
106: direction, rayPt, null);
107: vector.sub(rayPt, origin);
108: distance = vector.length();
109: radius = getRadius(distance);
110: if (sqDist <= (sphRadius + radius) * (sphRadius + radius)) {
111: return true;
112: }
113: return false; // we are too far to intersect
114: }
115: //
116: // ================ BOUNDING BOX ================
117: //
118: else if (bounds instanceof BoundingBox) {
119: // Calculate radius of BoundingBox
120: Point3d lower = new Point3d();
121: ((BoundingBox) bounds).getLower(lower);
122:
123: Point3d center = ((BoundingBox) bounds).getCenter();
124:
125: // First, see if cone is too far away from BoundingBox
126: double sqDist = Distance.pointToRay(center, origin,
127: direction, rayPt, null);
128:
129: vector.sub(rayPt, origin);
130: distance = vector.length();
131: radius = getRadius(distance);
132:
133: double temp = (center.x - lower.x + radius);
134: double boxRadiusSquared = temp * temp;
135: temp = (center.y - lower.y + radius);
136: boxRadiusSquared += temp * temp;
137: temp = (center.z - lower.z + radius);
138: boxRadiusSquared += temp * temp;
139:
140: if (sqDist > boxRadiusSquared) {
141: return false; // we are too far to intersect
142: } else if (sqDist < (radius * radius)) {
143: return true; // center is in cone
144: }
145:
146: // Then, see if ray intersects
147: if (((BoundingBox) bounds).intersect(origin, direction,
148: iPnt)) {
149: return true;
150: }
151:
152: // Ray does not intersect, test for distance with each edge
153: Point3d upper = new Point3d();
154: ((BoundingBox) bounds).getUpper(upper);
155:
156: Point3d[][] edges = {
157: // Top horizontal 4
158: { upper, new Point3d(lower.x, upper.y, upper.z) },
159: { new Point3d(lower.x, upper.y, upper.z),
160: new Point3d(lower.x, lower.y, upper.z) },
161: { new Point3d(lower.x, lower.y, upper.z),
162: new Point3d(upper.x, lower.y, upper.z) },
163: { new Point3d(upper.x, lower.y, upper.z), upper },
164: // Bottom horizontal 4
165: { lower, new Point3d(lower.x, upper.y, lower.z) },
166: { new Point3d(lower.x, upper.y, lower.z),
167: new Point3d(upper.x, upper.y, lower.z) },
168: { new Point3d(upper.x, upper.y, lower.z),
169: new Point3d(upper.x, lower.y, lower.z) },
170: { new Point3d(upper.x, lower.y, lower.z), lower },
171: // Vertical 4
172: { lower, new Point3d(lower.x, lower.y, upper.z) },
173: { new Point3d(lower.x, upper.y, lower.z),
174: new Point3d(lower.x, upper.y, upper.z) },
175: { new Point3d(upper.x, upper.y, lower.z),
176: new Point3d(upper.x, upper.y, upper.z) },
177: { new Point3d(upper.x, lower.y, lower.z),
178: new Point3d(upper.x, lower.y, upper.z) } };
179:
180: for (int i = 0; i < edges.length; i++) {
181: // System.err.println ("Testing edge: "+edges[i][0]+" - "+edges[i][1]);
182: double distToEdge = Distance.rayToSegment(origin,
183: direction, edges[i][0], edges[i][1], rayPt,
184: null, null);
185:
186: vector.sub(rayPt, origin);
187: distance = vector.length();
188: radius = getRadius(distance);
189: // System.err.println ("PickConeRay: distance: "+distance+" radius:"+radius);
190: if (distToEdge <= radius * radius) {
191: // System.err.println ("Intersects!");
192: return true;
193: }
194: }
195: return false; // Not close enough
196: }
197: //
198: // ================ BOUNDING POLYTOPE ================
199: //
200: else if (bounds instanceof BoundingPolytope) {
201: int i, j;
202:
203: // First, check to see if we are too far to intersect the polytope's
204: // bounding sphere
205: Point3d sphCenter = new Point3d();
206: BoundingSphere bsphere = new BoundingSphere(bounds);
207:
208: bsphere.getCenter(sphCenter);
209: double sphRadius = bsphere.getRadius();
210:
211: double sqDist = Distance.pointToRay(sphCenter, origin,
212: direction, rayPt, null);
213: vector.sub(rayPt, origin);
214: distance = vector.length();
215: radius = getRadius(distance);
216: if (sqDist > (sphRadius + radius) * (sphRadius + radius)) {
217: return false; // we are too far to intersect
218: }
219:
220: // Now check to see if ray intersects with polytope
221: if (bounds.intersect(origin, direction, iPnt)) {
222: return true;
223: }
224:
225: // Now check distance to edges. Since we don't know a priori how
226: // the polytope is structured, we will cycle through. We discard edges
227: // when their center is not on the polytope surface.
228: BoundingPolytope ptope = (BoundingPolytope) bounds;
229: Point3d midpt = new Point3d();
230: double distToEdge;
231: for (i = 0; i < ptope.nVerts; i++) {
232: for (j = i; i < ptope.nVerts; i++) {
233: // XXXX: make BoundingPolytope.pointInPolytope available to package
234: // scope
235: midpt.x = (ptope.verts[i].x + ptope.verts[j].x) * 0.5;
236: midpt.y = (ptope.verts[i].y + ptope.verts[j].y) * 0.5;
237: midpt.z = (ptope.verts[i].z + ptope.verts[j].z) * 0.5;
238:
239: if (!PickCylinder.pointInPolytope(ptope, midpt.x,
240: midpt.y, midpt.z)) {
241: continue;
242: }
243: distToEdge = Distance.rayToSegment(origin,
244: direction, ptope.verts[i], ptope.verts[j],
245: rayPt, null, null);
246: vector.sub(rayPt, origin);
247: distance = vector.length();
248: radius = getRadius(distance);
249: if (distToEdge <= radius * radius) {
250: return true;
251: }
252: }
253: }
254: return false;
255: }
256: /*
257: else {
258: throw new RuntimeException("intersect method not implemented");
259: }
260: */
261: return false;
262: }
263:
264: // Only use within J3D.
265: // Return a new PickConeRay that is the transformed (t3d) of this pickConeRay.
266: PickShape transform(Transform3D t3d) {
267:
268: Point3d end = new Point3d();
269:
270: PickConeRay newPCR = new PickConeRay();
271:
272: newPCR.origin.x = origin.x;
273: newPCR.origin.y = origin.y;
274: newPCR.origin.z = origin.z;
275: newPCR.spreadAngle = spreadAngle;
276:
277: end.x = origin.x + direction.x;
278: end.y = origin.y + direction.y;
279: end.z = origin.z + direction.z;
280:
281: t3d.transform(newPCR.origin);
282: t3d.transform(end);
283:
284: newPCR.direction.x = end.x - newPCR.origin.x;
285: newPCR.direction.y = end.y - newPCR.origin.y;
286: newPCR.direction.z = end.z - newPCR.origin.z;
287: newPCR.direction.normalize();
288:
289: return newPCR;
290: }
291: }
|