0001: /*
0002: * $RCSfile: PickIntersection.java,v $
0003: *
0004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: *
0010: * - Redistribution of source code must retain the above copyright
0011: * notice, this list of conditions and the following disclaimer.
0012: *
0013: * - Redistribution in binary form must reproduce the above copyright
0014: * notice, this list of conditions and the following disclaimer in
0015: * the documentation and/or other materials provided with the
0016: * distribution.
0017: *
0018: * Neither the name of Sun Microsystems, Inc. or the names of
0019: * contributors may be used to endorse or promote products derived
0020: * from this software without specific prior written permission.
0021: *
0022: * This software is provided "AS IS," without a warranty of any
0023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
0024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
0025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
0026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
0027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
0028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
0029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
0030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
0031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
0032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
0033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
0034: * POSSIBILITY OF SUCH DAMAGES.
0035: *
0036: * You acknowledge that this software is not designed, licensed or
0037: * intended for use in the design, construction, operation or
0038: * maintenance of any nuclear facility.
0039: *
0040: * $Revision: 1.5 $
0041: * $Date: 2007/03/02 21:27:15 $
0042: * $State: Exp $
0043: */
0044:
0045: package com.sun.j3d.utils.picking;
0046:
0047: import javax.vecmath.*;
0048: import javax.media.j3d.*;
0049: import com.sun.j3d.utils.geometry.Primitive;
0050:
0051: /**
0052: * Holds information about an intersection of a PickShape with a Node
0053: * as part of a PickResult. Information about
0054: * the intersected geometry, intersected primitive, intersection point, and
0055: * closest vertex can be inquired.
0056: * <p>
0057: * The intersected geometry is indicated by an index into the list of
0058: * geometry arrays on the PickResult. It can also be inquired from this
0059: * object.
0060: * <p>
0061: * The intersected primitive indicates which primitive out of the GeometryArray
0062: * was intersected (where the primitive is a point, line, triangle or quad,
0063: * not a
0064: * <code>com.sun.j3d.utils.geometry.Primitive)</code>.
0065: * For example, the intersection would indicate which triangle out of a
0066: * triangle strip was intersected.
0067: * The methods which return primitive data will have one value if the primitive
0068: * is
0069: * a point, two values if the primitive is a line, three values if the primitive
0070: * is a triangle and four values if the primitive is quad.
0071: * <p>
0072: * The primitive's VWorld coordinates are saved when then intersection is
0073: * calculated. The local coordinates, normal, color and texture coordinates
0074: * for the primitive can also be inquired if they are present and readable.
0075: * <p>
0076: * The intersection point is the location on the primitive which intersects the
0077: * pick shape closest to the center of the pick shape. The intersection point's
0078: * location in VWorld coordinates is saved when the intersection is calculated.
0079: * The local coordinates, normal, color and texture coordiantes of at the
0080: * intersection can be interpolated if they are present and readable.
0081: * <p>
0082: * The closest vertex is the vertex of the primitive closest to the intersection
0083: * point. The vertex index, VWorld coordinates and local coordinates of the
0084: * closest vertex can be inquired. The normal, color and texture coordinate
0085: * of the closest vertex can be inquired from the geometry array:
0086: * <p><blockquote><pre>
0087: * Vector3f getNormal(PickIntersection pi, int vertexIndex) {
0088: * int index;
0089: * Vector3d normal = new Vector3f();
0090: * GeometryArray ga = pickIntersection.getGeometryArray();
0091: * if (pickIntersection.geometryIsIndexed()) {
0092: * index = ga.getNormalIndex(vertexIndex);
0093: * } else {
0094: * index = vertexIndex;
0095: * }
0096: * ga.getNormal(index, normal);
0097: * return normal;
0098: * }
0099: * </pre></blockquote>
0100: * <p>
0101: * The color, normal
0102: * and texture coordinate information for the intersected primitive and the
0103: * intersection point
0104: * can be inquired
0105: * the geometry includes them and the corresponding READ capibility bits are
0106: * set.
0107: * <A HREF="PickTool.html#setCapabilities(javax.media.j3d.Node, int)">
0108: * <code>PickTool.setCapabilties(Node, int)</code></A>
0109: * can be used to set the capability bits
0110: * to allow this data to be inquired.
0111: */
0112: public class PickIntersection {
0113:
0114: /* OPEN ISSUES:
0115: -- Tex coordinates always use texCoordSet == 0.
0116: */
0117:
0118: /* =================== ATTRIBUTES ======================= */
0119:
0120: // init by constructor:
0121: /** PickResult for intersection is part of */
0122: PickResult pickResult = null;
0123:
0124: // init by intersection:
0125: /** Distance between start point and intersection point (see comment above)*/
0126: double distance = -1;
0127:
0128: /** index of GeometryArray in PickResult */
0129: int geomIndex = 0;
0130:
0131: /** Indices of the intersected primitive */
0132: int[] primitiveVertexIndices = null;
0133:
0134: /** VWorld coordinates of intersected primitive */
0135: Point3d[] primitiveCoordinatesVW = null;
0136:
0137: /** VWorld Coordinates of the intersection point */
0138: Point3d pointCoordinatesVW = null;
0139:
0140: // Derived data
0141:
0142: // Geometry
0143: GeometryArray geom = null;
0144: IndexedGeometryArray iGeom = null;
0145: boolean hasNormals = false;
0146: boolean hasColors = false;
0147: boolean hasTexCoords = false;
0148:
0149: // Primitive
0150: /* indices for the different data types */
0151: int[] primitiveCoordinateIndices;
0152: int[] primitiveNormalIndices;
0153: int[] primitiveColorIndices;
0154: int[] primitiveTexCoordIndices;
0155:
0156: /* Local coordinates of the intersected primitive */
0157: Point3d[] primitiveCoordinates = null;
0158:
0159: /* Normals of the intersected primitive */
0160: Vector3f[] primitiveNormals = null;
0161:
0162: /* Colors of the intersected primitive */
0163: Color4f[] primitiveColors = null;
0164:
0165: /* TextureCoordinates of the intersected primitive */
0166: TexCoord3f[] primitiveTexCoords = null;
0167:
0168: // Intersection point
0169:
0170: /** Local Coordinates of the intersection point */
0171: Point3d pointCoordinates = null;
0172:
0173: /** Normal at the intersection point */
0174: Vector3f pointNormal = null;
0175:
0176: /** Color at the intersection point */
0177: Color4f pointColor = null;
0178:
0179: /** TexCoord at the intersection point */
0180: TexCoord3f pointTexCoord = null;
0181:
0182: // Closest Vertex
0183: /** Index of the closest vertex */
0184: int closestVertexIndex = -1;
0185:
0186: /** Coordinates of the closest vertex */
0187: Point3d closestVertexCoordinates = null;
0188:
0189: /** Coordinates of the closest vertex (World coordinates) */
0190: Point3d closestVertexCoordinatesVW = null;
0191:
0192: /** Weight factors for interpolation, values correspond to vertex indices,
0193: * sum == 1
0194: */
0195: double[] interpWeights;
0196:
0197: static final boolean debug = false;
0198:
0199: // Axis constants
0200: static final int X_AXIS = 1;
0201: static final int Y_AXIS = 2;
0202: static final int Z_AXIS = 3;
0203:
0204: // Tolerance for numerical stability
0205: static final double TOL = 1.0e-5;
0206:
0207: /* =================== METHODS ======================= */
0208:
0209: /** Constructor
0210: @param pickResult The pickResult this intersection is part of.
0211: */
0212: PickIntersection(PickResult pr, GeometryArray geomArr) {
0213:
0214: // pr can't be null.
0215: pickResult = pr;
0216: geom = geomArr;
0217: if (geom == null) {
0218: GeometryArray[] ga = pickResult.getGeometryArrays();
0219: geom = ga[geomIndex];
0220:
0221: }
0222:
0223: if (geom instanceof IndexedGeometryArray) {
0224: iGeom = (IndexedGeometryArray) geom;
0225: }
0226: int vertexFormat = geom.getVertexFormat();
0227: hasColors = (0 != (vertexFormat & (GeometryArray.COLOR_3 | GeometryArray.COLOR_4)));
0228: hasNormals = (0 != (vertexFormat & GeometryArray.NORMALS));
0229: hasTexCoords = (0 != (vertexFormat & (GeometryArray.TEXTURE_COORDINATE_2 | GeometryArray.TEXTURE_COORDINATE_3)));
0230: }
0231:
0232: /**
0233: String representation of this object
0234: */
0235: public String toString() {
0236: String rt = new String("PickIntersection: ");
0237: rt += " pickResult = " + pickResult + "\n";
0238: rt += " geomIndex = " + geomIndex + "\n";
0239: if (distance != -1)
0240: rt += " dist:" + distance + "\n";
0241: if (pointCoordinates != null)
0242: rt += " pt:" + pointCoordinates + "\n";
0243: if (pointCoordinatesVW != null)
0244: rt += " ptVW:" + pointCoordinatesVW + "\n";
0245:
0246: if (primitiveCoordinateIndices != null) {
0247: rt += " prim coordinate ind:" + "\n";
0248: for (int i = 0; i < primitiveCoordinateIndices.length; i++) {
0249: rt += " " + primitiveCoordinateIndices[i] + "\n";
0250: }
0251: }
0252:
0253: if (primitiveColorIndices != null) {
0254: rt += " prim color ind:" + "\n";
0255: for (int i = 0; i < primitiveColorIndices.length; i++) {
0256: rt += " " + primitiveColorIndices[i] + "\n";
0257: }
0258: }
0259:
0260: if (primitiveNormalIndices != null) {
0261: rt += " prim normal ind:" + "\n";
0262: for (int i = 0; i < primitiveNormalIndices.length; i++) {
0263: rt += " " + primitiveNormalIndices[i] + "\n";
0264: }
0265: }
0266:
0267: if (primitiveTexCoordIndices != null) {
0268: rt += " prim texture ind:" + "\n";
0269: for (int i = 0; i < primitiveTexCoordIndices.length; i++) {
0270: rt += " " + primitiveTexCoordIndices[i] + "\n";
0271: }
0272: }
0273:
0274: if (closestVertexCoordinates != null) {
0275: rt += " clos. vert:" + closestVertexCoordinates + "\n";
0276: }
0277:
0278: if (closestVertexCoordinatesVW != null) {
0279: rt += " clos. vert:" + closestVertexCoordinatesVW + "\n";
0280: }
0281:
0282: if (closestVertexIndex != -1) {
0283: rt += " clos. vert. ind.:" + closestVertexIndex + "\n";
0284: }
0285: return rt;
0286: }
0287:
0288: /* Call only by PickResult */
0289: String toString2() {
0290: String rt = new String("PickIntersection: ");
0291: // rt += " pickResult = "+pickResult;
0292: rt += " geomIndex = " + geomIndex + "\n";
0293: if (distance != -1)
0294: rt += " dist:" + distance + "\n";
0295: if (pointCoordinates != null)
0296: rt += " pt:" + pointCoordinates + "\n";
0297: if (pointCoordinatesVW != null)
0298: rt += " ptVW:" + pointCoordinatesVW + "\n";
0299:
0300: if (primitiveCoordinateIndices != null) {
0301: rt += " prim coordinate ind:" + "\n";
0302: for (int i = 0; i < primitiveCoordinateIndices.length; i++) {
0303: rt += " " + primitiveCoordinateIndices[i] + "\n";
0304: }
0305: }
0306:
0307: if (primitiveColorIndices != null) {
0308: rt += " prim color ind:" + "\n";
0309: for (int i = 0; i < primitiveColorIndices.length; i++) {
0310: rt += " " + primitiveColorIndices[i] + "\n";
0311: }
0312: }
0313:
0314: if (primitiveNormalIndices != null) {
0315: rt += " prim normal ind:" + "\n";
0316: for (int i = 0; i < primitiveNormalIndices.length; i++) {
0317: rt += " " + primitiveNormalIndices[i] + "\n";
0318: }
0319: }
0320:
0321: if (primitiveTexCoordIndices != null) {
0322: rt += " prim texture ind:" + "\n";
0323: for (int i = 0; i < primitiveTexCoordIndices.length; i++) {
0324: rt += " " + primitiveTexCoordIndices[i] + "\n";
0325: }
0326: }
0327:
0328: if (closestVertexCoordinates != null) {
0329: rt += " clos. vert:" + closestVertexCoordinates + "\n";
0330: }
0331:
0332: if (closestVertexCoordinatesVW != null) {
0333: rt += " clos. vert:" + closestVertexCoordinatesVW + "\n";
0334: }
0335:
0336: if (closestVertexIndex != -1) {
0337: rt += " clos. vert. ind.:" + closestVertexIndex + "\n";
0338: }
0339: return rt;
0340: }
0341:
0342: /**
0343: Gets the PickResult this intersection is part of
0344: */
0345: PickResult getPickResult() {
0346: return pickResult;
0347: }
0348:
0349: /**
0350: Sets the geom index into the pick result
0351: */
0352: void setGeomIndex(int gi) {
0353:
0354: if (geomIndex != gi) {
0355: GeometryArray[] ga = pickResult.getGeometryArrays();
0356: geom = ga[gi];
0357:
0358: if (geom instanceof IndexedGeometryArray) {
0359: iGeom = (IndexedGeometryArray) geom;
0360: }
0361: int vertexFormat = geom.getVertexFormat();
0362: hasColors = (0 != (vertexFormat & (GeometryArray.COLOR_3 | GeometryArray.COLOR_4)));
0363: hasNormals = (0 != (vertexFormat & GeometryArray.NORMALS));
0364: hasTexCoords = (0 != (vertexFormat & (GeometryArray.TEXTURE_COORDINATE_2 | GeometryArray.TEXTURE_COORDINATE_3)));
0365: }
0366:
0367: geomIndex = gi;
0368: }
0369:
0370: /**
0371: Sets the coordinates of the intersection point (world coordinates).
0372: @param pt the coordinates
0373: */
0374: void setPointCoordinatesVW(Point3d pt) {
0375: if (pointCoordinatesVW == null) {
0376: pointCoordinatesVW = new Point3d();
0377: }
0378: pointCoordinatesVW.x = pt.x;
0379: pointCoordinatesVW.y = pt.y;
0380: pointCoordinatesVW.z = pt.z;
0381: }
0382:
0383: /**
0384: Returns the coordinates of the intersection point (world coordinates),
0385: if available.
0386: @return coordinates of the point
0387: */
0388: public Point3d getPointCoordinatesVW() {
0389: return pointCoordinatesVW;
0390: }
0391:
0392: /**
0393: Get the distance from the PickShape start point to the intersection point
0394: @return the distance to the intersection point, if available.
0395: */
0396: public double getDistance() {
0397: return distance;
0398: }
0399:
0400: /**
0401: Set the distance to intersection point
0402: @param dist the distance to the intersection point
0403: */
0404: void setDistance(double dist) {
0405: distance = dist;
0406: }
0407:
0408: /** Set VWorld coordinates of the picked primtive
0409: @param coords
0410: */
0411: void setPrimitiveCoordinatesVW(Point3d[] coords) {
0412: primitiveCoordinatesVW = new Point3d[coords.length];
0413: System.arraycopy(coords, 0, primitiveCoordinatesVW, 0,
0414: coords.length);
0415: }
0416:
0417: /**
0418: Get VWorld coordinates of the intersected primitive
0419: @return an array of Point3d's for the primitive that was picked
0420: */
0421: public Point3d[] getPrimitiveCoordinatesVW() {
0422: return primitiveCoordinatesVW;
0423: }
0424:
0425: /** Set vertex indices of primitive's vertices
0426: @param verts array of coordinate indices
0427: */
0428: void setVertexIndices(int[] verts) {
0429: primitiveVertexIndices = new int[verts.length];
0430: System.arraycopy(verts, 0, primitiveVertexIndices, 0,
0431: verts.length);
0432: }
0433:
0434: /**
0435: Get vertex indices of the intersected primitive
0436: @return an array which contains the list of indices
0437: */
0438: public int[] getPrimitiveVertexIndices() {
0439: return primitiveVertexIndices;
0440: }
0441:
0442: /**
0443: Returns the index of the intersected GeometryArray into the geometry
0444: arrays in the PickResult
0445: */
0446: public int getGeometryArrayIndex() {
0447: return geomIndex;
0448: }
0449:
0450: /* ================================================================== */
0451: /* Derived Data: GeometryArray */
0452: /* ================================================================== */
0453:
0454: /** Returns the GeometryArray for the intersection */
0455: public GeometryArray getGeometryArray() {
0456: if (geom == null) {
0457: GeometryArray[] ga = pickResult.getGeometryArrays();
0458: geom = ga[geomIndex];
0459: if (geom instanceof IndexedGeometryArray) {
0460: iGeom = (IndexedGeometryArray) geom;
0461: }
0462: int vertexFormat = geom.getVertexFormat();
0463: hasColors = (0 != (vertexFormat & (GeometryArray.COLOR_3 | GeometryArray.COLOR_4)));
0464: hasNormals = (0 != (vertexFormat & GeometryArray.NORMALS));
0465: hasTexCoords = (0 != (vertexFormat & (GeometryArray.TEXTURE_COORDINATE_2 | GeometryArray.TEXTURE_COORDINATE_3)));
0466: }
0467: return geom;
0468: }
0469:
0470: /** Returns true if the geometry is indexed */
0471: public boolean geometryIsIndexed() {
0472: GeometryArray ga = getGeometryArray();
0473: if (iGeom != null) {
0474: return true;
0475: } else {
0476: return false;
0477: }
0478: }
0479:
0480: /* ================================================================== */
0481: /* Derived Data: Closest Vertex */
0482: /* ================================================================== */
0483:
0484: /** Get coordinates of closest vertex (local)
0485: @return the coordinates of the vertex closest to the intersection point
0486: */
0487: public Point3d getClosestVertexCoordinates() {
0488: // System.out.println("closestVertexCoordinates " + closestVertexCoordinates);
0489: if (closestVertexCoordinates == null) {
0490: int vertexIndex = getClosestVertexIndex();
0491: int vformat = geom.getVertexFormat();
0492: int val;
0493:
0494: int[] indices = getPrimitiveCoordinateIndices();
0495: if ((vformat & GeometryArray.BY_REFERENCE) == 0) {
0496: closestVertexCoordinates = new Point3d();
0497: geom.getCoordinate(indices[vertexIndex],
0498: closestVertexCoordinates);
0499: /* System.out.println("PickIntersection : closestVertexCoordinates " +
0500: closestVertexCoordinates + " vertexIndex " +
0501: vertexIndex);
0502: */
0503: } else {
0504: if ((vformat & GeometryArray.INTERLEAVED) == 0) {
0505: double[] doubleData = geom.getCoordRefDouble();
0506: // If data was set as float then ..
0507: if (doubleData == null) {
0508: float[] floatData = geom.getCoordRefFloat();
0509: if (floatData == null) {
0510: Point3f[] p3fData = geom.getCoordRef3f();
0511: if (p3fData == null) {
0512: Point3d[] p3dData = geom
0513: .getCoordRef3d();
0514: closestVertexCoordinates = new Point3d(
0515: p3dData[indices[vertexIndex]].x,
0516: p3dData[indices[vertexIndex]].y,
0517: p3dData[indices[vertexIndex]].z);
0518: } else {
0519: closestVertexCoordinates = new Point3d(
0520: p3fData[indices[vertexIndex]].x,
0521: p3fData[indices[vertexIndex]].y,
0522: p3fData[indices[vertexIndex]].z);
0523: }
0524: } else {
0525: val = indices[vertexIndex] * 3; // for x,y,z
0526: closestVertexCoordinates = new Point3d(
0527: floatData[val], floatData[val + 1],
0528: floatData[val + 2]);
0529: }
0530: } else {
0531: val = indices[vertexIndex] * 3; // for x,y,z
0532: closestVertexCoordinates = new Point3d(
0533: doubleData[val], doubleData[val + 1],
0534: doubleData[val + 2]);
0535: }
0536: } else {
0537: float[] floatData = geom.getInterleavedVertices();
0538: int offset = getInterleavedVertexOffset(geom);
0539: int stride = offset + 3; // for the vertices .
0540: val = stride * indices[vertexIndex] + offset;
0541: closestVertexCoordinates = new Point3d(
0542: floatData[val], floatData[val + 1],
0543: floatData[val + 2]);
0544: }
0545: }
0546: }
0547:
0548: return closestVertexCoordinates;
0549: }
0550:
0551: /** Get coordinates of closest vertex (world)
0552: @return the coordinates of the vertex closest to the intersection point
0553: */
0554: public Point3d getClosestVertexCoordinatesVW() {
0555: if (closestVertexCoordinatesVW == null) {
0556: int vertexIndex = getClosestVertexIndex();
0557: Point3d[] coordinatesVW = getPrimitiveCoordinatesVW();
0558: closestVertexCoordinatesVW = coordinatesVW[vertexIndex];
0559: }
0560: return closestVertexCoordinatesVW;
0561: }
0562:
0563: /** Get index of closest vertex
0564: @return the index of the closest vertex
0565: */
0566: public int getClosestVertexIndex() {
0567: if (closestVertexIndex == -1) {
0568: storeClosestVertex();
0569: }
0570: return closestVertexIndex;
0571: }
0572:
0573: /** Calculates and stores the closest vertex information */
0574: void storeClosestVertex() {
0575: if (closestVertexIndex == -1) {
0576: double maxDist = Double.MAX_VALUE;
0577: double curDist = Double.MAX_VALUE;
0578: int closestIndex = -1;
0579: /* System.out.println("primitiveCoordinatesVW.length " +
0580: primitiveCoordinatesVW.length);
0581: */
0582: for (int i = 0; i < primitiveCoordinatesVW.length; i++) {
0583: curDist = pointCoordinatesVW
0584: .distance(primitiveCoordinatesVW[i]);
0585: /* System.out.println("pointCoordinatesVW " + pointCoordinatesVW);
0586: System.out.println("primitiveCoordinatesVW[" + i + "] " +
0587: primitiveCoordinatesVW[i]);
0588: System.out.println("curDist " + curDist);
0589: */
0590: if (curDist < maxDist) {
0591: closestIndex = i;
0592: maxDist = curDist;
0593: }
0594: }
0595: closestVertexIndex = closestIndex;
0596: }
0597: }
0598:
0599: /* ================================================================== */
0600: /* Derived Data: Primitive */
0601: /* ================================================================== */
0602:
0603: /**
0604: Get the coordinates indices for the intersected primitive. For a non-indexed
0605: primitive, this will be the same as the primitive vertex indices
0606: @return an array indices
0607: */
0608: public int[] getPrimitiveCoordinateIndices() {
0609:
0610: if (primitiveCoordinateIndices == null) {
0611: if (geometryIsIndexed()) {
0612: primitiveCoordinateIndices = new int[primitiveVertexIndices.length];
0613: for (int i = 0; i < primitiveVertexIndices.length; i++) {
0614: primitiveCoordinateIndices[i] = iGeom
0615: .getCoordinateIndex(primitiveVertexIndices[i]);
0616: }
0617: } else {
0618: primitiveCoordinateIndices = primitiveVertexIndices;
0619: }
0620: }
0621: return primitiveCoordinateIndices;
0622: }
0623:
0624: /**
0625: Get the local coordinates intersected primitive
0626: @return an array of Point3d's for the primitive that was intersected
0627: */
0628: public Point3d[] getPrimitiveCoordinates() {
0629: if (primitiveCoordinates == null) {
0630: primitiveCoordinates = new Point3d[primitiveVertexIndices.length];
0631: int[] indices = getPrimitiveCoordinateIndices();
0632: int vformat = geom.getVertexFormat();
0633: int val;
0634:
0635: // System.out.println("PickIntersection : indices.length - " + indices.length);
0636: if ((vformat & GeometryArray.BY_REFERENCE) == 0) {
0637: for (int i = 0; i < indices.length; i++) {
0638: primitiveCoordinates[i] = new Point3d();
0639: // System.out.println("PickIntersection : indices["+i+"] = " + indices[i]);
0640: geom.getCoordinate(indices[i],
0641: primitiveCoordinates[i]);
0642: }
0643: } else {
0644: if ((vformat & GeometryArray.INTERLEAVED) == 0) {
0645: double[] doubleData = geom.getCoordRefDouble();
0646: // If data was set as float then ..
0647: if (doubleData == null) {
0648: float[] floatData = geom.getCoordRefFloat();
0649: if (floatData == null) {
0650: Point3f[] p3fData = geom.getCoordRef3f();
0651: if (p3fData == null) {
0652: Point3d[] p3dData = geom
0653: .getCoordRef3d();
0654: for (int i = 0; i < indices.length; i++) {
0655: primitiveCoordinates[i] = new Point3d(
0656: p3dData[indices[i]].x,
0657: p3dData[indices[i]].y,
0658: p3dData[indices[i]].z);
0659: }
0660: } else {
0661: for (int i = 0; i < indices.length; i++) {
0662: primitiveCoordinates[i] = new Point3d(
0663: p3fData[indices[i]].x,
0664: p3fData[indices[i]].y,
0665: p3fData[indices[i]].z);
0666: }
0667: }
0668:
0669: } else {
0670: for (int i = 0; i < indices.length; i++) {
0671: val = indices[i] * 3;
0672: primitiveCoordinates[i] = new Point3d(
0673: floatData[val],
0674: floatData[val + 1],
0675: floatData[val + 2]);
0676: }
0677: }
0678: } else {
0679: for (int i = 0; i < indices.length; i++) {
0680: val = indices[i] * 3;
0681: primitiveCoordinates[i] = new Point3d(
0682: doubleData[val],
0683: doubleData[val + 1],
0684: doubleData[val + 2]);
0685: }
0686: }
0687: } else {
0688: float[] floatData = geom.getInterleavedVertices();
0689: int offset = getInterleavedVertexOffset(geom);
0690: int stride = offset + 3; // for the vertices .
0691: for (int i = 0; i < indices.length; i++) {
0692: val = stride * indices[i] + offset;
0693: primitiveCoordinates[i] = new Point3d(
0694: floatData[val], floatData[val + 1],
0695: floatData[val + 2]);
0696: }
0697: }
0698: }
0699:
0700: }
0701: return primitiveCoordinates;
0702: }
0703:
0704: int getInterleavedVertexOffset(GeometryArray geo) {
0705: int offset = 0;
0706: int vformat = geo.getVertexFormat();
0707: if ((vformat & GeometryArray.COLOR_3) == GeometryArray.COLOR_3) {
0708: offset += 3;
0709: } else if ((vformat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
0710: offset += 4;
0711: }
0712: if ((vformat & GeometryArray.NORMALS) != 0)
0713: offset += 3;
0714: if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == GeometryArray.TEXTURE_COORDINATE_2) {
0715: offset += 2 * geo.getTexCoordSetCount();
0716: } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) == GeometryArray.TEXTURE_COORDINATE_3) {
0717: offset += 3 * geo.getTexCoordSetCount();
0718: }
0719:
0720: return offset;
0721: }
0722:
0723: int getInterleavedStride(GeometryArray geo) {
0724: int offset = 3; // Add 3 for vertices
0725: int vformat = geo.getVertexFormat();
0726: if ((vformat & GeometryArray.COLOR_3) == GeometryArray.COLOR_3) {
0727: offset += 3;
0728: } else if ((vformat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
0729: offset += 4;
0730: }
0731: if ((vformat & GeometryArray.NORMALS) != 0)
0732: offset += 3;
0733: if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == GeometryArray.TEXTURE_COORDINATE_2) {
0734: offset += 2 * geo.getTexCoordSetCount();
0735: } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) == GeometryArray.TEXTURE_COORDINATE_3) {
0736: offset += 3 * geo.getTexCoordSetCount();
0737: }
0738:
0739: return offset;
0740: }
0741:
0742: int getInterleavedColorOffset(GeometryArray geo) {
0743: int offset = 0;
0744: int vformat = geo.getVertexFormat();
0745: if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == GeometryArray.TEXTURE_COORDINATE_2) {
0746: offset += 2 * geo.getTexCoordSetCount();
0747: } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) == GeometryArray.TEXTURE_COORDINATE_3) {
0748: offset += 3 * geo.getTexCoordSetCount();
0749: }
0750:
0751: return offset;
0752: }
0753:
0754: int getInterleavedNormalOffset(GeometryArray geo) {
0755: int offset = 0;
0756: int vformat = geo.getVertexFormat();
0757: if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == GeometryArray.TEXTURE_COORDINATE_2) {
0758: offset += 2 * geo.getTexCoordSetCount();
0759: } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) == GeometryArray.TEXTURE_COORDINATE_3) {
0760: offset += 3 * geo.getTexCoordSetCount();
0761: }
0762: if ((vformat & GeometryArray.COLOR_3) == GeometryArray.COLOR_3) {
0763: offset += 3;
0764: } else if ((vformat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
0765: offset += 4;
0766: }
0767: return offset;
0768: }
0769:
0770: /**
0771: Get the normal indices for the intersected primitive. For a non-indexed
0772: primitive, this will be the same as the primitive vertex indices
0773: If the geometry array does not contain normals this will return null
0774: @return an array indices
0775: */
0776: public int[] getPrimitiveNormalIndices() {
0777: if (hasNormals && (primitiveNormalIndices == null)) {
0778: if (geometryIsIndexed()) {
0779: primitiveNormalIndices = new int[primitiveVertexIndices.length];
0780: for (int i = 0; i < primitiveVertexIndices.length; i++) {
0781: primitiveNormalIndices[i] = iGeom
0782: .getNormalIndex(primitiveVertexIndices[i]);
0783: }
0784: } else {
0785: primitiveNormalIndices = primitiveVertexIndices;
0786: }
0787: }
0788: return primitiveNormalIndices;
0789: }
0790:
0791: /**
0792: Get the normals of the intersected primitive. This will return null if
0793: the primitive does not contain normals.
0794: @return an array of Point3d's for the primitive that was intersected
0795: */
0796: public Vector3f[] getPrimitiveNormals() {
0797: if (hasNormals && (primitiveNormals == null)) {
0798: primitiveNormals = new Vector3f[primitiveVertexIndices.length];
0799: int[] indices = getPrimitiveNormalIndices();
0800: int vformat = geom.getVertexFormat();
0801: int val;
0802:
0803: if ((vformat & GeometryArray.BY_REFERENCE) == 0) {
0804: for (int i = 0; i < indices.length; i++) {
0805: primitiveNormals[i] = new Vector3f();
0806: geom.getNormal(indices[i], primitiveNormals[i]);
0807: }
0808: } else {
0809: if ((vformat & GeometryArray.INTERLEAVED) == 0) {
0810: float[] floatNormals = geom.getNormalRefFloat();
0811: if (floatNormals != null) {
0812: for (int i = 0; i < indices.length; i++) {
0813: val = indices[i] * 3;
0814: primitiveNormals[i] = new Vector3f(
0815: floatNormals[val],
0816: floatNormals[val + 1],
0817: floatNormals[val + 2]);
0818: }
0819: } else {
0820: Vector3f[] normal3f = geom.getNormalRef3f();
0821: for (int i = 0; i < indices.length; i++) {
0822: primitiveNormals[i] = new Vector3f(
0823: normal3f[indices[i]].x,
0824: normal3f[indices[i]].y,
0825: normal3f[indices[i]].z);
0826: }
0827: }
0828: } else {
0829: float[] floatData = geom.getInterleavedVertices();
0830: int offset = getInterleavedColorOffset(geom);
0831: int stride = getInterleavedStride(geom);
0832: for (int i = 0; i < indices.length; i++) {
0833: val = stride * indices[i] + offset;
0834: primitiveNormals[i] = new Vector3f(
0835: floatData[val], floatData[val + 1],
0836: floatData[val + 2]);
0837:
0838: }
0839: }
0840: }
0841: }
0842: return primitiveNormals;
0843: }
0844:
0845: /**
0846: Get the color indices for the intersected primitive. For a non-indexed
0847: primitive, this will be the same as the primitive vertex indices
0848: If the geometry array does not contain colors this will return null.
0849: @return an array indices
0850: */
0851: public int[] getPrimitiveColorIndices() {
0852: if (hasColors && (primitiveColorIndices == null)) {
0853: if (geometryIsIndexed()) {
0854: primitiveColorIndices = new int[primitiveVertexIndices.length];
0855: for (int i = 0; i < primitiveVertexIndices.length; i++) {
0856: primitiveColorIndices[i] = iGeom
0857: .getColorIndex(primitiveVertexIndices[i]);
0858: }
0859: } else {
0860: primitiveColorIndices = primitiveVertexIndices;
0861: }
0862: }
0863: return primitiveColorIndices;
0864: }
0865:
0866: /**
0867: Get the colors of the intersected primitive. This will return null if
0868: the primitive does not contain colors. If the geometry was defined
0869: using GeometryArray.COLOR_3, the 'w' value of the color will be set to 1.0.
0870: @return an array of Point3d's for the primitive that was intersected
0871: */
0872: public Color4f[] getPrimitiveColors() {
0873: if (hasColors && (primitiveColors == null)) {
0874: primitiveColors = new Color4f[primitiveVertexIndices.length];
0875: int[] indices = getPrimitiveColorIndices();
0876: int vformat = geom.getVertexFormat();
0877: if ((vformat & GeometryArray.BY_REFERENCE) == 0) {
0878: if ((vformat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
0879: for (int i = 0; i < indices.length; i++) {
0880: primitiveColors[i] = new Color4f();
0881: geom.getColor(indices[i], primitiveColors[i]);
0882: }
0883: } else {
0884: Color3f color = new Color3f();
0885: for (int i = 0; i < indices.length; i++) {
0886: primitiveColors[i] = new Color4f();
0887: geom.getColor(indices[i], color);
0888: primitiveColors[i].x = color.x;
0889: primitiveColors[i].y = color.y;
0890: primitiveColors[i].z = color.z;
0891: primitiveColors[i].w = 1.0f;
0892: }
0893: }
0894: } else {
0895: if ((vformat & GeometryArray.INTERLEAVED) == 0) {
0896: float[] floatData = geom.getColorRefFloat();
0897: // If data was set as float then ..
0898: if (floatData == null) {
0899: byte[] byteData = geom.getColorRefByte();
0900: if (byteData == null) {
0901: Color3f[] c3fData = geom.getColorRef3f();
0902: if (c3fData == null) {
0903: Color4f[] c4fData = geom
0904: .getColorRef4f();
0905: if (c4fData == null) {
0906: Color3b[] c3bData = geom
0907: .getColorRef3b();
0908: if (c3bData == null) {
0909: Color4b[] c4bData = geom
0910: .getColorRef4b();
0911: for (int i = 0; i < indices.length; i++) {
0912: primitiveColors[i] = new Color4f(
0913: c4bData[indices[i]].x,
0914: c4bData[indices[i]].y,
0915: c4bData[indices[i]].z,
0916: c4bData[indices[i]].w);
0917:
0918: }
0919: } else {
0920: for (int i = 0; i < indices.length; i++) {
0921: primitiveColors[i] = new Color4f(
0922: c3bData[indices[i]].x,
0923: c3bData[indices[i]].y,
0924: c3bData[indices[i]].z,
0925: 1.0f);
0926:
0927: }
0928: }
0929: } else {
0930: for (int i = 0; i < indices.length; i++) {
0931: primitiveColors[i] = new Color4f(
0932: c4fData[indices[i]].x,
0933: c4fData[indices[i]].y,
0934: c4fData[indices[i]].z,
0935: c4fData[indices[i]].w);
0936: }
0937: }
0938: } else {
0939: for (int i = 0; i < indices.length; i++) {
0940: primitiveColors[i] = new Color4f(
0941: c3fData[indices[i]].x,
0942: c3fData[indices[i]].y,
0943: c3fData[indices[i]].z, 1.0f);
0944:
0945: }
0946: }
0947: } else {
0948: // Could be color3 or color4
0949: int val;
0950: if ((vformat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
0951: for (int i = 0; i < indices.length; i++) {
0952: val = indices[i] << 2; // for color4f
0953: primitiveColors[i] = new Color4f(
0954: byteData[val],
0955: byteData[val + 1],
0956: byteData[val + 2],
0957: byteData[val + 3]);
0958:
0959: }
0960: } else {
0961: for (int i = 0; i < indices.length; i++) {
0962: val = indices[i] * 3; // for color3f
0963: primitiveColors[i] = new Color4f(
0964: byteData[val],
0965: byteData[val + 1],
0966: byteData[val + 2], 1.0f);
0967:
0968: }
0969: }
0970: }
0971: } else {
0972: // Could be color3 or color4
0973: int val;
0974: if ((vformat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
0975: for (int i = 0; i < indices.length; i++) {
0976: val = indices[i] << 2; // for color4f
0977: primitiveColors[i] = new Color4f(
0978: floatData[val],
0979: floatData[val + 1],
0980: floatData[val + 2],
0981: floatData[val + 3]);
0982: }
0983: } else {
0984: for (int i = 0; i < indices.length; i++) {
0985: val = indices[i] * 3; // for color3f
0986: primitiveColors[i] = new Color4f(
0987: floatData[val],
0988: floatData[val + 1],
0989: floatData[val + 2], 1.0f);
0990:
0991: }
0992: }
0993: }
0994:
0995: } else {
0996: float[] floatData = geom.getInterleavedVertices();
0997: int offset = getInterleavedColorOffset(geom);
0998: int stride = getInterleavedStride(geom);
0999: for (int i = 0; i < indices.length; i++) {
1000: int val = stride * indices[i] + offset;
1001: if ((vformat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
1002: primitiveColors[i] = new Color4f(
1003: floatData[val], floatData[val + 1],
1004: floatData[val + 2],
1005: floatData[val + 3]);
1006: } else {
1007: primitiveColors[i] = new Color4f(
1008: floatData[val], floatData[val + 1],
1009: floatData[val + 2], 1.0f);
1010: }
1011: }
1012: }
1013: }
1014: }
1015: return primitiveColors;
1016: }
1017:
1018: /**
1019: Get the texture coordinate indices for the intersected primitive at the specifed
1020: index in the specified texture coordinate set. For a non-indexed
1021: primitive, this will be the same as the primitive vertex indices
1022: If the geometry array does not contain texture coordinates, this will
1023: return null.
1024: @return an array indices
1025: */
1026: public int[] getPrimitiveTexCoordIndices(int index) {
1027: if (hasTexCoords && (primitiveTexCoordIndices == null)) {
1028: if (geometryIsIndexed()) {
1029: primitiveTexCoordIndices = new int[primitiveVertexIndices.length];
1030: for (int i = 0; i < primitiveVertexIndices.length; i++) {
1031: primitiveTexCoordIndices[i] = iGeom
1032: .getTextureCoordinateIndex(index,
1033: primitiveVertexIndices[i]);
1034: }
1035: } else {
1036: primitiveTexCoordIndices = primitiveVertexIndices;
1037: }
1038: }
1039: return primitiveTexCoordIndices;
1040: }
1041:
1042: /**
1043: Get the texture coordinates of the intersected primitive at the specifed
1044: index in the specified texture coordinate set.
1045: null if the primitive does not contain texture coordinates.
1046: If the geometry was defined
1047: using GeometryArray.TEXTURE_COORDINATE_2, the 'z' value of the texture
1048: coordinate will be set to 0.0.
1049: @return an array of TexCoord3f's for the primitive that was intersected
1050: */
1051: public TexCoord3f[] getPrimitiveTexCoords(int index) {
1052: if (primitiveTexCoords == null) {
1053: primitiveTexCoords = new TexCoord3f[primitiveVertexIndices.length];
1054: TexCoord2f primitiveTexCoords2DTmp = new TexCoord2f();
1055:
1056: int[] indices = getPrimitiveTexCoordIndices(index);
1057: int vformat = geom.getVertexFormat();
1058: if ((vformat & GeometryArray.BY_REFERENCE) == 0) {
1059: for (int i = 0; i < indices.length; i++) {
1060: primitiveTexCoords[i] = new TexCoord3f();
1061: geom.getTextureCoordinate(index, indices[i],
1062: primitiveTexCoords2DTmp);
1063: primitiveTexCoords[i].set(
1064: primitiveTexCoords2DTmp.x,
1065: primitiveTexCoords2DTmp.y, 0.0f);
1066: }
1067: } else {
1068: if ((vformat & GeometryArray.INTERLEAVED) == 0) {
1069: int val;
1070: float[] floatTexCoords = geom
1071: .getTexCoordRefFloat(index);
1072: if (floatTexCoords != null) {
1073: if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == GeometryArray.TEXTURE_COORDINATE_2) {
1074: for (int i = 0; i < indices.length; i++) {
1075: val = indices[i] << 1; // t2f
1076: primitiveTexCoords[i] = new TexCoord3f(
1077: floatTexCoords[val],
1078: floatTexCoords[val + 1], 0.0f);
1079: }
1080: } else {
1081: for (int i = 0; i < indices.length; i++) {
1082: val = indices[i] * 3; // t3f
1083: primitiveTexCoords[i] = new TexCoord3f(
1084: floatTexCoords[val],
1085: floatTexCoords[val + 1],
1086: floatTexCoords[val + 2]);
1087: }
1088: }
1089: } else {
1090: TexCoord2f[] texCoord2f = geom
1091: .getTexCoordRef2f(index);
1092: if (texCoord2f != null) {
1093: for (int i = 0; i < indices.length; i++) {
1094: primitiveTexCoords[i] = new TexCoord3f(
1095: texCoord2f[indices[i]].x,
1096: texCoord2f[indices[i]].y, 0.0f);
1097: }
1098: } else {
1099: TexCoord3f[] texCoord3f = geom
1100: .getTexCoordRef3f(index);
1101: for (int i = 0; i < indices.length; i++) {
1102: primitiveTexCoords[i] = new TexCoord3f(
1103: texCoord3f[indices[i]].x,
1104: texCoord3f[indices[i]].y,
1105: texCoord3f[indices[i]].z);
1106: }
1107: }
1108:
1109: }
1110: } else {
1111: float[] floatData = geom.getInterleavedVertices();
1112: int stride = getInterleavedStride(geom);
1113: int offset;
1114: // Get the correct tex coord set
1115: if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == GeometryArray.TEXTURE_COORDINATE_2) {
1116: offset = index << 1;
1117: } else {
1118: offset = index * 3;
1119: }
1120: for (int i = 0; i < indices.length; i++) {
1121: int val = stride * indices[i];
1122: if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == GeometryArray.TEXTURE_COORDINATE_2) {
1123: primitiveTexCoords[i] = new TexCoord3f(
1124: floatData[val + offset],
1125: floatData[val + 1 + offset], 0.0f);
1126: } else {
1127: primitiveTexCoords[i] = new TexCoord3f(
1128: floatData[val + offset],
1129: floatData[val + 1 + offset],
1130: floatData[val + 2 + offset]);
1131: }
1132: }
1133: }
1134: }
1135: }
1136: return primitiveTexCoords;
1137: }
1138:
1139: /* ================================================================== */
1140: /* Derived Data: Intersection Point */
1141: /* ================================================================== */
1142:
1143: /**
1144: Returns the coordinates of the intersection point (local coordinates),
1145: if available.
1146: @return coordinates of the intersection point
1147: */
1148: public Point3d getPointCoordinates() {
1149: if (pointCoordinates == null) {
1150: double[] weights = getInterpWeights();
1151: Point3d[] coords = getPrimitiveCoordinates();
1152: pointCoordinates = new Point3d();
1153: for (int i = 0; i < weights.length; i++) {
1154: pointCoordinates.x += weights[i] * coords[i].x;
1155: pointCoordinates.y += weights[i] * coords[i].y;
1156: pointCoordinates.z += weights[i] * coords[i].z;
1157: }
1158: }
1159: return pointCoordinates;
1160: }
1161:
1162: /**
1163: Returns the normal of the intersection point. Returns null if the geometry
1164: does not contain normals.
1165: @return normal at the intersection point.
1166: */
1167: public Vector3f getPointNormal() {
1168: if (hasNormals && (pointNormal == null)) {
1169: double[] weights = getInterpWeights();
1170: Vector3f[] normals = getPrimitiveNormals();
1171: pointNormal = new Vector3f();
1172: for (int i = 0; i < weights.length; i++) {
1173: pointNormal.x += (float) weights[i] * normals[i].x;
1174: pointNormal.y += (float) weights[i] * normals[i].y;
1175: pointNormal.z += (float) weights[i] * normals[i].z;
1176: }
1177: }
1178: return pointNormal;
1179: }
1180:
1181: /**
1182: Returns the color of the intersection point. Returns null if the geometry
1183: does not contain colors. If the geometry was defined with
1184: GeometryArray.COLOR_3, the 'w' component of the color will initialized to
1185: 1.0
1186: @return color at the intersection point.
1187: */
1188: public Color4f getPointColor() {
1189: if (hasColors && (pointColor == null)) {
1190: double[] weights = getInterpWeights();
1191: Color4f[] colors = getPrimitiveColors();
1192: pointColor = new Color4f();
1193: for (int i = 0; i < weights.length; i++) {
1194: pointColor.x += (float) weights[i] * colors[i].x;
1195: pointColor.y += (float) weights[i] * colors[i].y;
1196: pointColor.z += (float) weights[i] * colors[i].z;
1197: pointColor.w += (float) weights[i] * colors[i].w;
1198: }
1199: }
1200: return pointColor;
1201: }
1202:
1203: /**
1204: Returns the texture coordinate of the intersection point at the specifed
1205: index in the specified texture coordinate set.
1206: Returns null if the geometry
1207: does not contain texture coordinates. If the geometry was defined with
1208: GeometryArray.TEXTURE_COORDINATE_3, the 'z' component of the texture
1209: coordinate will initialized to 0.0
1210: @return texture coordinate at the intersection point.
1211: */
1212: public TexCoord3f getPointTextureCoordinate(int index) {
1213: if (hasTexCoords && (pointTexCoord == null)) {
1214: double[] weights = getInterpWeights();
1215: TexCoord3f[] texCoords = getPrimitiveTexCoords(index);
1216: pointTexCoord = new TexCoord3f();
1217: for (int i = 0; i < weights.length; i++) {
1218: pointTexCoord.x += (float) weights[i] * texCoords[i].x;
1219: pointTexCoord.y += (float) weights[i] * texCoords[i].y;
1220: pointTexCoord.z += (float) weights[i] * texCoords[i].z;
1221: }
1222: }
1223: return pointTexCoord;
1224: }
1225:
1226: /* ================================================================== */
1227: /* Utility code for interpolating intersection point data */
1228: /* ================================================================== */
1229:
1230: /* absolute value */
1231: double abs(double value) {
1232: if (value < 0.0) {
1233: return -value;
1234: } else {
1235: return value;
1236: }
1237: }
1238:
1239: /* return the axis corresponding to the largest component of delta */
1240: int maxAxis(Vector3d delta) {
1241: int axis = X_AXIS;
1242: double max = abs(delta.x);
1243: if (abs(delta.y) > max) {
1244: axis = Y_AXIS;
1245: max = abs(delta.y);
1246: }
1247: if (abs(delta.z) > max) {
1248: axis = Z_AXIS;
1249: }
1250: return axis;
1251: }
1252:
1253: /* Triangle interpolation. Basic idea:
1254: * Map the verticies of the triangle to the form:
1255: *
1256: * L--------R
1257: * \ /
1258: * IL+--P-+IR
1259: * \ /
1260: * Base
1261: *
1262: where P is the intersection point Base, L and R and the triangle
1263: points. IL and IR are the projections if P along the Base-L and Base-R
1264: edges using an axis:
1265:
1266: IL = leftFactor * L + (1- leftFactor) * Base
1267: IR = rightFactor * R + (1-rightFactor) * Base
1268:
1269: then find the interp factor, midFactor, for P between IL and IR. If
1270: this is outside the range 0->1 then we have the wrong triangle of a
1271: quad and we return false.
1272:
1273: Else, the weighting is:
1274:
1275: IP = midFactor * IL + (1 - midFactor) * IR;
1276:
1277: Solving for weights for the formula:
1278: IP = BaseWeight * Base + LeftWeight * L + RightWeight * R;
1279: We get:
1280: BaseWeight = 1 - midFactor * leftFactor
1281: - rightFactor + midFactor * rightFactor;
1282: LeftWeight = midFactor * leftFactor;
1283: RightWeight = righFactor - midFactor * rightFactor;
1284: As a check, note that the sum of the weights is 1.0.
1285: */
1286:
1287: boolean interpTriangle(int index0, int index1, int index2,
1288: Point3d[] coords, Point3d intPt) {
1289:
1290: // find the longest edge, we'll use that to pick the axis */
1291: Vector3d delta0 = new Vector3d();
1292: Vector3d delta1 = new Vector3d();
1293: Vector3d delta2 = new Vector3d();
1294: delta0.sub(coords[index1], coords[index0]);
1295: delta1.sub(coords[index2], coords[index0]);
1296: delta2.sub(coords[index2], coords[index1]);
1297: double len0 = delta0.lengthSquared();
1298: double len1 = delta1.lengthSquared();
1299: double len2 = delta2.lengthSquared();
1300: Vector3d longest = delta0;
1301: double maxLen = len0;
1302: if (len1 > maxLen) {
1303: longest = delta1;
1304: maxLen = len1;
1305: }
1306: if (len2 > maxLen) {
1307: longest = delta2;
1308: }
1309: int mainAxis = maxAxis(longest);
1310:
1311: /*
1312: System.out.println("index0 = " + index0 + " index1 = " + index1 +
1313: " index2 = " + index2);
1314:
1315: System.out.println("coords[index0] = " + coords[index0]);
1316: System.out.println("coords[index1] = " + coords[index1]);
1317: System.out.println("coords[index2] = " + coords[index2]);
1318: System.out.println("intPt = " + intPt);
1319:
1320: System.out.println("delta0 = " + delta0 + " len0 " + len0);
1321: System.out.println("delta1 = " + delta1 + " len1 " + len1);
1322: System.out.println("delta2 = " + delta2 + " len2 " + len2);
1323: */
1324:
1325: /* now project the intersection point along the axis onto the edges */
1326: double[] factor = new double[3];
1327: /* the factor is for the projection opposide the vertex 0 = 1->2, etc*/
1328: factor[0] = getInterpFactorForBase(intPt, coords[index1],
1329: coords[index2], mainAxis);
1330: factor[1] = getInterpFactorForBase(intPt, coords[index2],
1331: coords[index0], mainAxis);
1332: factor[2] = getInterpFactorForBase(intPt, coords[index0],
1333: coords[index1], mainAxis);
1334:
1335: if (debug) {
1336: System.out.println("intPt = " + intPt);
1337: switch (mainAxis) {
1338: case X_AXIS:
1339: System.out.println("mainAxis = X_AXIS");
1340: break;
1341: case Y_AXIS:
1342: System.out.println("mainAxis = Y_AXIS");
1343: break;
1344: case Z_AXIS:
1345: System.out.println("mainAxis = Z_AXIS");
1346: break;
1347: }
1348: System.out.println("factor[0] = " + factor[0]);
1349: System.out.println("factor[1] = " + factor[1]);
1350: System.out.println("factor[2] = " + factor[2]);
1351: }
1352:
1353: /* Find the factor that is out of range, it will tell us which
1354: * vertex to use for base
1355: */
1356: int base, left, right;
1357: double leftFactor, rightFactor;
1358: if ((factor[0] < 0.0) || (factor[0] > 1.0)) {
1359: base = index0;
1360: right = index1;
1361: left = index2;
1362: rightFactor = factor[2];
1363: leftFactor = 1.0 - factor[1];
1364: if (debug) {
1365: System.out.println("base 0, rightFactor = "
1366: + rightFactor + " leftFactor = " + leftFactor);
1367: }
1368: } else if ((factor[1] < 0.0) || (factor[1] > 1.0)) {
1369: base = index1;
1370: right = index2;
1371: left = index0;
1372: rightFactor = factor[0];
1373: leftFactor = 1.0 - factor[2];
1374: if (debug) {
1375: System.out.println("base 1, rightFactor = "
1376: + rightFactor + " leftFactor = " + leftFactor);
1377: }
1378: } else {
1379: base = index2;
1380: right = index0;
1381: left = index1;
1382: rightFactor = factor[1];
1383: leftFactor = 1.0 - factor[0];
1384: if (debug) {
1385: System.out.println("base 2, rightFactor = "
1386: + rightFactor + " leftFactor = " + leftFactor);
1387: }
1388: }
1389: if (debug) {
1390: System.out.println("base = " + coords[base]);
1391: System.out.println("left = " + coords[left]);
1392: System.out.println("right = " + coords[right]);
1393: }
1394: /* find iLeft and iRight */
1395: Point3d iLeft = new Point3d(leftFactor * coords[left].x
1396: + (1.0 - leftFactor) * coords[base].x, leftFactor
1397: * coords[left].y + (1.0 - leftFactor) * coords[base].y,
1398: leftFactor * coords[left].z + (1.0 - leftFactor)
1399: * coords[base].z);
1400:
1401: Point3d iRight = new Point3d(rightFactor * coords[right].x
1402: + (1.0 - rightFactor) * coords[base].x, rightFactor
1403: * coords[right].y + (1.0 - rightFactor)
1404: * coords[base].y, rightFactor * coords[right].z
1405: + (1.0 - rightFactor) * coords[base].z);
1406:
1407: if (debug) {
1408: System.out.println("iLeft = " + iLeft);
1409: System.out.println("iRight = " + iRight);
1410: }
1411:
1412: /* now find an axis and solve for midFactor */
1413: delta0.sub(iLeft, iRight);
1414: int midAxis = maxAxis(delta0);
1415: double midFactor = getInterpFactor(intPt, iRight, iLeft,
1416: midAxis);
1417:
1418: if (debug) {
1419: switch (midAxis) {
1420: case X_AXIS:
1421: System.out.println("midAxis = X_AXIS");
1422: break;
1423: case Y_AXIS:
1424: System.out.println("midAxis = Y_AXIS");
1425: break;
1426: case Z_AXIS:
1427: System.out.println("midAxis = Z_AXIS");
1428: break;
1429: }
1430: System.out.println("midFactor = " + midFactor);
1431: }
1432:
1433: if (midFactor < 0.0) {
1434: // System.out.println("midFactor = " + midFactor);
1435: if ((midFactor + TOL) >= 0.0) {
1436: // System.out.println("In Tol case : midFactor = " + midFactor);
1437: midFactor = 0.0;
1438: } else {
1439: /* int point is outside triangle */
1440: return false;
1441: }
1442: } else if (midFactor > 1.0) {
1443: // System.out.println("midFactor = " + midFactor);
1444: if ((midFactor - TOL) <= 1.0) {
1445: // System.out.println("In Tol case : midFactor = " + midFactor);
1446: midFactor = 1.0;
1447: } else {
1448: /* int point is outside triangle */
1449: return false;
1450: }
1451: }
1452:
1453: // Assign the weights
1454: interpWeights[base] = 1.0 - midFactor * leftFactor
1455: - rightFactor + midFactor * rightFactor;
1456: interpWeights[left] = midFactor * leftFactor;
1457: interpWeights[right] = rightFactor - midFactor * rightFactor;
1458: return true;
1459:
1460: }
1461:
1462: /* Get the interpolation weights for each of the verticies of the
1463: * primitive.
1464: */
1465: double[] getInterpWeights() {
1466:
1467: Point3d pt = getPointCoordinatesVW();
1468: Point3d[] coordinates = getPrimitiveCoordinatesVW();
1469: double factor;
1470: int axis;
1471:
1472: if (interpWeights != null) {
1473: return interpWeights;
1474: }
1475:
1476: interpWeights = new double[coordinates.length];
1477:
1478: // Interpolate
1479: switch (coordinates.length) {
1480: case 1:
1481: // Nothing to interpolate
1482: interpWeights[0] = 1.0;
1483: break;
1484: case 2: // edge
1485: Vector3d delta = new Vector3d();
1486: delta.sub(coordinates[1], coordinates[0]);
1487: axis = maxAxis(delta);
1488: factor = getInterpFactor(pt, coordinates[1],
1489: coordinates[0], axis);
1490: interpWeights[0] = factor;
1491: interpWeights[1] = 1.0 - factor;
1492: break;
1493: case 3: // triangle
1494: if (!interpTriangle(0, 1, 2, coordinates, pt)) {
1495: throw new RuntimeException(
1496: "Interp point outside triangle");
1497: }
1498: break;
1499: case 4: // quad
1500: if (!interpTriangle(0, 1, 2, coordinates, pt)) {
1501: if (!interpTriangle(0, 2, 3, coordinates, pt)) {
1502: throw new RuntimeException(
1503: "Interp point outside quad");
1504: }
1505: }
1506: break;
1507: default:
1508: throw new RuntimeException("Unexpected number of points.");
1509: }
1510: return interpWeights;
1511: }
1512:
1513: /**
1514: Calculate the interpolation factor for point p by projecting it along
1515: an axis (x,y,z) onto the edge between p1 and p2. If the result is
1516: in the 0->1 range, point is between p1 and p2 (0 = point is at p1,
1517: 1 => point is at p2).
1518: */
1519: private static float getInterpFactor(Point3d p, Point3d p1,
1520: Point3d p2, int axis) {
1521: float t;
1522: switch (axis) {
1523: case X_AXIS:
1524: if (p1.x == p2.x)
1525: //t = Float.MAX_VALUE; // TODO: should be 0?
1526: t = 0.0f;
1527: else
1528: t = (float) ((p1.x - p.x) / (p1.x - p2.x));
1529: break;
1530: case Y_AXIS:
1531: if (p1.y == p2.y)
1532: // t = Float.MAX_VALUE;
1533: t = 0.0f;
1534: else
1535: t = (float) ((p1.y - p.y) / (p1.y - p2.y));
1536: break;
1537: case Z_AXIS:
1538: if (p1.z == p2.z)
1539: // t = Float.MAX_VALUE;
1540: t = 0.0f;
1541: else
1542: t = (float) ((p1.z - p.z) / (p1.z - p2.z));
1543: break;
1544: default:
1545: throw new RuntimeException("invalid axis parameter " + axis
1546: + " (must be 0-2)");
1547: }
1548: return t;
1549: }
1550:
1551: /**
1552: Calculate the interpolation factor for point p by projecting it along
1553: an axis (x,y,z) onto the edge between p1 and p2. If the result is
1554: in the 0->1 range, point is between p1 and p2 (0 = point is at p1,
1555: 1 => point is at p2).
1556: return MAX_VALUE if component of vertices are the same.
1557: */
1558: private static float getInterpFactorForBase(Point3d p, Point3d p1,
1559: Point3d p2, int axis) {
1560: float t;
1561: switch (axis) {
1562: case X_AXIS:
1563: if (p1.x == p2.x)
1564: t = Float.MAX_VALUE;
1565: else
1566: t = (float) ((p1.x - p.x) / (p1.x - p2.x));
1567: break;
1568: case Y_AXIS:
1569: if (p1.y == p2.y)
1570: t = Float.MAX_VALUE;
1571: else
1572: t = (float) ((p1.y - p.y) / (p1.y - p2.y));
1573: break;
1574: case Z_AXIS:
1575: if (p1.z == p2.z)
1576: t = Float.MAX_VALUE;
1577: else
1578: t = (float) ((p1.z - p.z) / (p1.z - p2.z));
1579: break;
1580: default:
1581: throw new RuntimeException("invalid axis parameter " + axis
1582: + " (must be 0-2)");
1583: }
1584: return t;
1585: }
1586:
1587: } // PickIntersection
|