001: /*
002: * $RCSfile: QuadArrayRetained.java,v $
003: *
004: * Copyright 1997-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.8 $
028: * $Date: 2008/02/28 20:17:28 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import javax.vecmath.*;
035: import java.lang.Math;
036:
037: /**
038: * The QuadArray object draws the array of vertices as individual
039: * quadrilaterals. Each group
040: * of four vertices defines a quadrilateral to be drawn.
041: */
042:
043: class QuadArrayRetained extends GeometryArrayRetained {
044:
045: QuadArrayRetained() {
046: this .geoType = GEO_TYPE_QUAD_SET;
047: }
048:
049: boolean intersect(PickShape pickShape, PickInfo pickInfo,
050: int flags, Point3d iPnt, GeometryRetained geom,
051: int geomIndex) {
052:
053: Point3d pnts[] = new Point3d[4];
054: double sdist[] = new double[1];
055: double minDist = Double.MAX_VALUE;
056: double x = 0, y = 0, z = 0;
057: int[] vtxIndexArr = new int[4];
058:
059: int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? initialVertexIndex
060: : initialCoordIndex);
061: pnts[0] = new Point3d();
062: pnts[1] = new Point3d();
063: pnts[2] = new Point3d();
064: pnts[3] = new Point3d();
065:
066: switch (pickShape.getPickType()) {
067: case PickShape.PICKRAY:
068: PickRay pickRay = (PickRay) pickShape;
069:
070: while (i < validVertexCount) {
071: for (int j = 0; j < 4; j++) {
072: vtxIndexArr[j] = i;
073: getVertexData(i++, pnts[j]);
074: }
075: if (intersectRay(pnts, pickRay, sdist, iPnt)) {
076: if (flags == 0) {
077: return true;
078: }
079: if (sdist[0] < minDist) {
080: minDist = sdist[0];
081: x = iPnt.x;
082: y = iPnt.y;
083: z = iPnt.z;
084: if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) {
085: storeInterestData(pickInfo, flags, geom,
086: geomIndex, vtxIndexArr, iPnt,
087: sdist[0]);
088: }
089: }
090: if ((flags & PickInfo.ALL_GEOM_INFO) != 0) {
091: storeInterestData(pickInfo, flags, geom,
092: geomIndex, vtxIndexArr, iPnt, sdist[0]);
093: }
094: }
095: }
096: break;
097: case PickShape.PICKSEGMENT:
098: PickSegment pickSegment = (PickSegment) pickShape;
099:
100: while (i < validVertexCount) {
101: for (int j = 0; j < 4; j++) {
102: vtxIndexArr[j] = i;
103: getVertexData(i++, pnts[j]);
104: }
105: if (intersectSegment(pnts, pickSegment.start,
106: pickSegment.end, sdist, iPnt)) {
107: if (flags == 0) {
108: return true;
109: }
110: if (sdist[0] < minDist) {
111: minDist = sdist[0];
112: x = iPnt.x;
113: y = iPnt.y;
114: z = iPnt.z;
115: if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) {
116: storeInterestData(pickInfo, flags, geom,
117: geomIndex, vtxIndexArr, iPnt,
118: sdist[0]);
119: }
120: }
121: if ((flags & PickInfo.ALL_GEOM_INFO) != 0) {
122: storeInterestData(pickInfo, flags, geom,
123: geomIndex, vtxIndexArr, iPnt, sdist[0]);
124: }
125: }
126: }
127: break;
128: case PickShape.PICKBOUNDINGBOX:
129: BoundingBox bbox = (BoundingBox) ((PickBounds) pickShape).bounds;
130: while (i < validVertexCount) {
131: for (int j = 0; j < 4; j++) {
132: vtxIndexArr[j] = i;
133: getVertexData(i++, pnts[j]);
134: }
135: if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) {
136: if (flags == 0) {
137: return true;
138: }
139: if (sdist[0] < minDist) {
140: minDist = sdist[0];
141: x = iPnt.x;
142: y = iPnt.y;
143: z = iPnt.z;
144: if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) {
145: storeInterestData(pickInfo, flags, geom,
146: geomIndex, vtxIndexArr, iPnt,
147: sdist[0]);
148: }
149: }
150: if ((flags & PickInfo.ALL_GEOM_INFO) != 0) {
151: storeInterestData(pickInfo, flags, geom,
152: geomIndex, vtxIndexArr, iPnt, sdist[0]);
153: }
154: }
155: }
156: break;
157: case PickShape.PICKBOUNDINGSPHERE:
158: BoundingSphere bsphere = (BoundingSphere) ((PickBounds) pickShape).bounds;
159:
160: while (i < validVertexCount) {
161: for (int j = 0; j < 4; j++) {
162: vtxIndexArr[j] = i;
163: getVertexData(i++, pnts[j]);
164: }
165: if (intersectBoundingSphere(pnts, bsphere, sdist, iPnt)) {
166: if (flags == 0) {
167: return true;
168: }
169: if (sdist[0] < minDist) {
170: minDist = sdist[0];
171: x = iPnt.x;
172: y = iPnt.y;
173: z = iPnt.z;
174: if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) {
175: storeInterestData(pickInfo, flags, geom,
176: geomIndex, vtxIndexArr, iPnt,
177: sdist[0]);
178: }
179: }
180: if ((flags & PickInfo.ALL_GEOM_INFO) != 0) {
181: storeInterestData(pickInfo, flags, geom,
182: geomIndex, vtxIndexArr, iPnt, sdist[0]);
183: }
184: }
185: }
186: break;
187: case PickShape.PICKBOUNDINGPOLYTOPE:
188:
189: BoundingPolytope bpolytope = (BoundingPolytope) ((PickBounds) pickShape).bounds;
190:
191: while (i < validVertexCount) {
192: for (int j = 0; j < 4; j++) {
193: vtxIndexArr[j] = i;
194: getVertexData(i++, pnts[j]);
195: }
196: if (intersectBoundingPolytope(pnts, bpolytope, sdist,
197: iPnt)) {
198: if (flags == 0) {
199: return true;
200: }
201: if (sdist[0] < minDist) {
202: minDist = sdist[0];
203: x = iPnt.x;
204: y = iPnt.y;
205: z = iPnt.z;
206: if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) {
207: storeInterestData(pickInfo, flags, geom,
208: geomIndex, vtxIndexArr, iPnt,
209: sdist[0]);
210: }
211: }
212: if ((flags & PickInfo.ALL_GEOM_INFO) != 0) {
213: storeInterestData(pickInfo, flags, geom,
214: geomIndex, vtxIndexArr, iPnt, sdist[0]);
215: }
216: }
217: }
218: break;
219: case PickShape.PICKCYLINDER:
220: PickCylinder pickCylinder = (PickCylinder) pickShape;
221:
222: while (i < validVertexCount) {
223: for (int j = 0; j < 4; j++) {
224: vtxIndexArr[j] = i;
225: getVertexData(i++, pnts[j]);
226: }
227: if (intersectCylinder(pnts, pickCylinder, sdist, iPnt)) {
228: if (flags == 0) {
229: return true;
230: }
231: if (sdist[0] < minDist) {
232: minDist = sdist[0];
233: x = iPnt.x;
234: y = iPnt.y;
235: z = iPnt.z;
236: if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) {
237: storeInterestData(pickInfo, flags, geom,
238: geomIndex, vtxIndexArr, iPnt,
239: sdist[0]);
240: }
241: }
242: if ((flags & PickInfo.ALL_GEOM_INFO) != 0) {
243: storeInterestData(pickInfo, flags, geom,
244: geomIndex, vtxIndexArr, iPnt, sdist[0]);
245: }
246: }
247: }
248: break;
249: case PickShape.PICKCONE:
250: PickCone pickCone = (PickCone) pickShape;
251:
252: while (i < validVertexCount) {
253: for (int j = 0; j < 4; j++) {
254: vtxIndexArr[j] = i;
255: getVertexData(i++, pnts[j]);
256: }
257: if (intersectCone(pnts, pickCone, sdist, iPnt)) {
258: if (flags == 0) {
259: return true;
260: }
261: if (sdist[0] < minDist) {
262: minDist = sdist[0];
263: x = iPnt.x;
264: y = iPnt.y;
265: z = iPnt.z;
266: if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) {
267: storeInterestData(pickInfo, flags, geom,
268: geomIndex, vtxIndexArr, iPnt,
269: sdist[0]);
270: }
271: }
272: if ((flags & PickInfo.ALL_GEOM_INFO) != 0) {
273: storeInterestData(pickInfo, flags, geom,
274: geomIndex, vtxIndexArr, iPnt, sdist[0]);
275: }
276: }
277: }
278: break;
279: case PickShape.PICKPOINT:
280: // Should not happen since API already check for this
281: throw new IllegalArgumentException(J3dI18N
282: .getString("QuadArrayRetained0"));
283: default:
284: throw new RuntimeException(
285: "PickShape not supported for intersection ");
286: }
287:
288: if (minDist < Double.MAX_VALUE) {
289: iPnt.x = x;
290: iPnt.y = y;
291: iPnt.z = z;
292: return true;
293: }
294: return false;
295:
296: }
297:
298: // intersect pnts[] with every quad in this object
299: boolean intersect(Point3d[] pnts) {
300: Point3d[] points = new Point3d[4];
301: double dist[] = new double[1];
302: int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? initialVertexIndex
303: : initialCoordIndex);
304:
305: points[0] = new Point3d();
306: points[1] = new Point3d();
307: points[2] = new Point3d();
308: points[3] = new Point3d();
309:
310: switch (pnts.length) {
311: case 3: // Triangle
312: while (i < validVertexCount) {
313: getVertexData(i++, points[0]);
314: getVertexData(i++, points[1]);
315: getVertexData(i++, points[2]);
316: getVertexData(i++, points[3]);
317: if (intersectTriTri(points[0], points[1], points[2],
318: pnts[0], pnts[1], pnts[2])
319: || intersectTriTri(points[0], points[2],
320: points[3], pnts[0], pnts[1], pnts[2])) {
321: return true;
322: }
323: }
324: break;
325: case 4: // Quad
326:
327: while (i < validVertexCount) {
328: getVertexData(i++, points[0]);
329: getVertexData(i++, points[1]);
330: getVertexData(i++, points[2]);
331: getVertexData(i++, points[3]);
332: if (intersectTriTri(points[0], points[1], points[2],
333: pnts[0], pnts[1], pnts[2])
334: || intersectTriTri(points[0], points[1],
335: points[2], pnts[0], pnts[2], pnts[3])
336: || intersectTriTri(points[0], points[2],
337: points[3], pnts[0], pnts[1], pnts[2])
338: || intersectTriTri(points[0], points[2],
339: points[3], pnts[0], pnts[2], pnts[3])) {
340: return true;
341: }
342: }
343: break;
344: case 2: // Line
345: while (i < validVertexCount) {
346: getVertexData(i++, points[0]);
347: getVertexData(i++, points[1]);
348: getVertexData(i++, points[2]);
349: getVertexData(i++, points[3]);
350: if (intersectSegment(points, pnts[0], pnts[1], dist,
351: null)) {
352: return true;
353: }
354: }
355: break;
356: case 1: // Point
357: while (i < validVertexCount) {
358: getVertexData(i++, points[0]);
359: getVertexData(i++, points[1]);
360: getVertexData(i++, points[2]);
361: getVertexData(i++, points[3]);
362: if (intersectTriPnt(points[0], points[1], points[2],
363: pnts[0])
364: || intersectTriPnt(points[0], points[2],
365: points[3], pnts[0])) {
366: return true;
367: }
368: }
369: break;
370: }
371: return false;
372: }
373:
374: boolean intersect(Transform3D this ToOtherVworld,
375: GeometryRetained geom) {
376:
377: Point3d[] points = new Point3d[4];
378: int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? initialVertexIndex
379: : initialCoordIndex);
380:
381: points[0] = new Point3d();
382: points[1] = new Point3d();
383: points[2] = new Point3d();
384: points[3] = new Point3d();
385:
386: while (i < validVertexCount) {
387: getVertexData(i++, points[0]);
388: getVertexData(i++, points[1]);
389: getVertexData(i++, points[2]);
390: getVertexData(i++, points[3]);
391: this ToOtherVworld.transform(points[0]);
392: this ToOtherVworld.transform(points[1]);
393: this ToOtherVworld.transform(points[2]);
394: this ToOtherVworld.transform(points[3]);
395: if (geom.intersect(points)) {
396: return true;
397: }
398: } // for each quad
399: return false;
400: }
401:
402: // the bounds argument is already transformed
403: boolean intersect(Bounds targetBound) {
404: Point3d[] points = new Point3d[4];
405: int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? initialVertexIndex
406: : initialCoordIndex);
407:
408: points[0] = new Point3d();
409: points[1] = new Point3d();
410: points[2] = new Point3d();
411: points[3] = new Point3d();
412:
413: switch (targetBound.getPickType()) {
414: case PickShape.PICKBOUNDINGBOX:
415: BoundingBox box = (BoundingBox) targetBound;
416:
417: while (i < validVertexCount) {
418: getVertexData(i++, points[0]);
419: getVertexData(i++, points[1]);
420: getVertexData(i++, points[2]);
421: getVertexData(i++, points[3]);
422: if (intersectBoundingBox(points, box, null, null)) {
423: return true;
424: }
425: }
426: break;
427: case PickShape.PICKBOUNDINGSPHERE:
428: BoundingSphere bsphere = (BoundingSphere) targetBound;
429:
430: while (i < validVertexCount) {
431: getVertexData(i++, points[0]);
432: getVertexData(i++, points[1]);
433: getVertexData(i++, points[2]);
434: getVertexData(i++, points[3]);
435: if (intersectBoundingSphere(points, bsphere, null, null)) {
436: return true;
437: }
438: }
439: break;
440: case PickShape.PICKBOUNDINGPOLYTOPE:
441: BoundingPolytope bpolytope = (BoundingPolytope) targetBound;
442:
443: while (i < validVertexCount) {
444: getVertexData(i++, points[0]);
445: getVertexData(i++, points[1]);
446: getVertexData(i++, points[2]);
447: getVertexData(i++, points[3]);
448: if (intersectBoundingPolytope(points, bpolytope, null,
449: null)) {
450: return true;
451: }
452: }
453: break;
454: default:
455: throw new RuntimeException(
456: "Bounds not supported for intersection "
457: + targetBound);
458: }
459: return false;
460: }
461:
462: // From Graphics Gems IV (pg5) and Graphics Gems II, Pg170
463: // The centroid is the area-weighted sum of the centroids of
464: // disjoint triangles that make up the polygon.
465: void computeCentroid() {
466: int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? initialVertexIndex
467: : initialCoordIndex);
468:
469: Point3d pnt0 = new Point3d();
470: Point3d pnt1 = new Point3d();
471: Point3d pnt2 = new Point3d();
472: Point3d pnt3 = new Point3d();
473: Vector3d vec = new Vector3d();
474: Vector3d normal = new Vector3d();
475: Vector3d tmpvec = new Vector3d();
476:
477: double area;
478: double totalarea = 0;
479:
480: centroid.x = 0;
481: centroid.y = 0;
482: centroid.z = 0;
483:
484: while (i < validVertexCount) {
485: getVertexData(i++, pnt0);
486: getVertexData(i++, pnt1);
487: getVertexData(i++, pnt2);
488: getVertexData(i++, pnt3);
489:
490: // Determine the normal
491: tmpvec.sub(pnt0, pnt1);
492: vec.sub(pnt1, pnt2);
493:
494: // Do the cross product
495: normal.cross(tmpvec, vec);
496: normal.normalize();
497: // If a degenerate triangle, don't include
498: if (Double.isNaN(normal.x + normal.y + normal.z))
499: continue;
500: tmpvec.set(0, 0, 0);
501: // compute the area of each triangle
502: getCrossValue(pnt0, pnt1, tmpvec);
503: getCrossValue(pnt1, pnt2, tmpvec);
504: getCrossValue(pnt2, pnt0, tmpvec);
505: area = normal.dot(tmpvec);
506: totalarea += area;
507: centroid.x += (pnt0.x + pnt1.x + pnt2.x) * area;
508: centroid.y += (pnt0.y + pnt1.y + pnt2.y) * area;
509: centroid.z += (pnt0.z + pnt1.z + pnt2.z) * area;
510:
511: // compute the area of each triangle
512: tmpvec.set(0, 0, 0);
513: getCrossValue(pnt0, pnt2, tmpvec);
514: getCrossValue(pnt2, pnt3, tmpvec);
515: getCrossValue(pnt3, pnt0, tmpvec);
516: area = normal.dot(tmpvec);
517: totalarea += area;
518: centroid.x += (pnt3.x + pnt0.x + pnt2.x) * area;
519: centroid.y += (pnt3.y + pnt0.y + pnt2.y) * area;
520: centroid.z += (pnt3.z + pnt0.z + pnt2.z) * area;
521: }
522: if (totalarea != 0.0) {
523: area = 1.0 / (3.0 * totalarea);
524: centroid.x *= area;
525: centroid.y *= area;
526: centroid.z *= area;
527: }
528: }
529:
530: int getClassType() {
531: return QUAD_TYPE;
532: }
533: }
|