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