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