diff options
-rw-r--r-- | src/classes/share/com/sun/j3d/utils/pickfast/PickIntersection.java | 1396 |
1 files changed, 1179 insertions, 217 deletions
diff --git a/src/classes/share/com/sun/j3d/utils/pickfast/PickIntersection.java b/src/classes/share/com/sun/j3d/utils/pickfast/PickIntersection.java index 6403f89..5987ca8 100644 --- a/src/classes/share/com/sun/j3d/utils/pickfast/PickIntersection.java +++ b/src/classes/share/com/sun/j3d/utils/pickfast/PickIntersection.java @@ -105,313 +105,1275 @@ import com.sun.j3d.utils.geometry.Primitive; public class PickIntersection { - /* =================== METHODS ======================= */ - - /** Constructor - @param intersectionInfo The IntersectionInfo this intersection is part of. - */ - //PickIntersection (PickResult pr, GeometryArray geomArr) { - public PickIntersection (PickInfo.IntersectionInfo intersectionInfo) { - - } + /* The intersection point */ + // Point3d getIntersectionPoint() + + /* Distance between start point of pickShape and intersection point */ + // double getDistance() - /** Returns true if the geometry is indexed - - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported + /* The vertex indices of the intersected primitive in the geometry */ + // int[] getVertexIndices() - */ - public boolean geometryIsIndexed() { - throw new UnsupportedOperationException(); - } + /*************************/ - /** Get coordinates of closest vertex (local) - @return the coordinates of the vertex closest to the intersection point + /** Weight factors for interpolation, values correspond to vertex indices, + * sum == 1 + */ + private double[] interpWeights; - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported + private static final boolean debug = false; - */ - public Point3d getClosestVertexCoordinates () { - throw new UnsupportedOperationException(); - } + // Axis constants + private static final int X_AXIS = 1; + private static final int Y_AXIS = 2; + private static final int Z_AXIS = 3; - /** Get coordinates of closest vertex (world) - @return the coordinates of the vertex closest to the intersection point + // Tolerance for numerical stability + static final double TOL = 1.0e-5; - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported + /* The references to the intersectionInfo object */ + private PickInfo.IntersectionInfo iInfo = null; + private Transform3D l2vw = null; + private Geometry geometry = null; + private boolean geometryIsIndexed = false; + private double distance; - */ - public Point3d getClosestVertexCoordinatesVW () { - throw new UnsupportedOperationException(); - } + private boolean hasColors; + private boolean hasNormals; + private boolean hasTexCoords; - /** Get index of closest vertex - @return the index of the closest vertex + // Primitive + /* indices for the different data types */ + private int[] primitiveCoordinateIndices; + private int[] primitiveNormalIndices; + private int[] primitiveColorIndices; + private int[] primitiveTexCoordIndices; + + /** Indices of the intersected primitive */ + private int[] primitiveVertexIndices = null; - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported + /* Local coordinates of the intersected primitive */ + private Point3d[] primitiveCoordinates = null; - */ - public int getClosestVertexIndex () { - throw new UnsupportedOperationException(); - } + /** VWorld coordinates of intersected primitive */ + private Point3d[] primitiveCoordinatesVW = null; - /** - Get the distance from the PickShape start point to the intersection point - @return the distance to the intersection point, if available. + /* Normals of the intersected primitive */ + private Vector3f[] primitiveNormals = null; + + /* Colors of the intersected primitive */ + private Color4f[] primitiveColors = null; - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported + /* TextureCoordinates of the intersected primitive */ + private TexCoord3f[] primitiveTexCoords = null; - */ - public double getDistance () { - throw new UnsupportedOperationException(); + // Intersection point + /** VWorld Coordinates of the intersection point */ + private Point3d pointCoordinatesVW = null; + + /** Local Coordinates of the intersection point */ + private Point3d pointCoordinates = null; + + /** Normal at the intersection point */ + private Vector3f pointNormal = null; + + /** Color at the intersection point */ + private Color4f pointColor = null; + + /** TexCoord at the intersection point */ + private TexCoord3f pointTexCoord = null; + + // Closest Vertex + /** Index of the closest vertex */ + private int closestVertexIndex = -1; + + /** Coordinates of the closest vertex */ + private Point3d closestVertexCoordinates = null; + + /** Coordinates of the closest vertex (World coordinates) */ + private Point3d closestVertexCoordinatesVW = null; + + /* =================== METHODS ======================= */ + + /** + * Constructor + * @param intersectionInfo The IntersectionInfo this intersection is part of. + */ + public PickIntersection (Transform3D localToVWorld, + PickInfo.IntersectionInfo intersectionInfo) { + + // Should check and throw NPE if the following is null. + // localToVWorld can't be null. + l2vw = localToVWorld; + // intersectionInfo can't be null. + iInfo = intersectionInfo; + // geometry can't be null. + geometry = iInfo.getGeometry(); + + pointCoordinates = iInfo.getIntersectionPoint(); + distance = iInfo.getDistance(); + primitiveVertexIndices = iInfo.getVertexIndices(); + + if (geometry instanceof GeometryArray) { + + int vertexFormat = ((GeometryArray)geometry).getVertexFormat(); + hasColors = (0 != (vertexFormat & + (GeometryArray.COLOR_3 | GeometryArray.COLOR_4))); + hasNormals = (0 != (vertexFormat & GeometryArray.NORMALS)); + hasTexCoords = (0 != (vertexFormat & + (GeometryArray.TEXTURE_COORDINATE_2 | + GeometryArray.TEXTURE_COORDINATE_3))); + + if (geometry instanceof IndexedGeometryArray) { + geometryIsIndexed = true; + } + } + } + + /** + * Returns true if the geometry is indexed + * + */ + public boolean geometryIsIndexed() { + return geometryIsIndexed; } + /** + * Get coordinates of closest vertex (local) + * @return the coordinates of the vertex closest to the intersection point + * + */ + public Point3d getClosestVertexCoordinates() { + // System.out.println("PI.closestVertexCoordinates " + closestVertexCoordinates); + GeometryArray geom = (GeometryArray) geometry; + + if (closestVertexCoordinates == null) { + int vertexIndex = getClosestVertexIndex(); + int vformat = geom.getVertexFormat(); + int val; + + int[] indices = getPrimitiveCoordinateIndices(); + if ((vformat & GeometryArray.BY_REFERENCE) == 0) { + closestVertexCoordinates = new Point3d(); + geom.getCoordinate(indices[vertexIndex], closestVertexCoordinates); + // System.out.println("PI.closestVertexCoordinates " + +// closestVertexCoordinates + " vertexIndex " + +// vertexIndex); + } + else { + if ((vformat & GeometryArray.INTERLEAVED) == 0) { + double[] doubleData = geom.getCoordRefDouble(); + // If data was set as float then .. + if (doubleData == null) { + float[] floatData = geom.getCoordRefFloat(); + if (floatData == null) { + throw new UnsupportedOperationException("Deprecated : BY_REF - p3f and p3d"); + } + else { + val = indices[vertexIndex] * 3; // for x,y,z + closestVertexCoordinates = new Point3d(floatData[val], + floatData[val+1], + floatData[val+2]); + } + } + else { + val = indices[vertexIndex] * 3; // for x,y,z + closestVertexCoordinates = new Point3d(doubleData[val], + doubleData[val+1], + doubleData[val+2]); + } + } + else { + float[] floatData = geom.getInterleavedVertices(); + int offset = getInterleavedVertexOffset(geom); + int stride = offset + 3; // for the vertices . + val = stride * indices[vertexIndex]+offset; + closestVertexCoordinates = new Point3d(floatData[val], + floatData[val+1], + floatData[val+2]); + } + } + } + + return closestVertexCoordinates; + } /** - Returns the color of the intersection point. Returns null if the geometry - does not contain colors. If the geometry was defined with - GeometryArray.COLOR_3, the 'w' component of the color will initialized to - 1.0 - @return color at the intersection point. - - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported + * Get coordinates of closest vertex (world) + * @return the coordinates of the vertex closest to the intersection point + * + */ + public Point3d getClosestVertexCoordinatesVW() { + if (closestVertexCoordinatesVW == null) { + int vertexIndex = getClosestVertexIndex(); + Point3d[] coordinatesVW = getPrimitiveCoordinatesVW(); + closestVertexCoordinatesVW = coordinatesVW[vertexIndex]; + } + return closestVertexCoordinatesVW; + } - */ - public Color4f getPointColor() { - throw new UnsupportedOperationException(); + /** + * Get index of closest vertex + * @return the index of the closest vertex + */ + public int getClosestVertexIndex() { + if (closestVertexIndex == -1) { + double maxDist = Double.MAX_VALUE; + double curDist = Double.MAX_VALUE; + int closestIndex = -1; + primitiveCoordinates = getPrimitiveCoordinates(); + + assert(primitiveCoordinates != null); + +// System.out.println("PI.getClosestVertexIndex : primitiveCoordinates.length " + +// primitiveCoordinates.length); + + for (int i=0;i<primitiveCoordinates.length;i++) { + curDist = pointCoordinates.distance (primitiveCoordinates[i]); + +// System.out.println("pointCoordinates " + pointCoordinates); +// System.out.println("primitiveCoordinates[" + i + "] " + +// primitiveCoordinates[i]); +// System.out.println("curDist " + curDist); + + if (curDist < maxDist) { + closestIndex = i; + maxDist = curDist; + } + } + closestVertexIndex = closestIndex; + } + return closestVertexIndex; + } + + /** + * Get the distance from the PickShape start point to the intersection point + * @return the distance to the intersection point, if available. + */ + public double getDistance() { + return distance; } /** - Returns the coordinates of the intersection point (local coordinates), - if available. - @return coordinates of the intersection point + * Returns the color of the intersection point. Returns null if the geometry + * does not contain colors. If the geometry was defined with + * GeometryArray.COLOR_3, the 'w' component of the color will initialized to + * 1.0 + * @return color at the intersection point. + */ + public Color4f getPointColor() { + if (hasColors && (pointColor == null)) { + double[] weights = getInterpWeights(); + Color4f[] colors = getPrimitiveColors(); + pointColor = new Color4f(); + for (int i = 0; i < weights.length; i++) { + pointColor.x += (float) weights[i] * colors[i].x; + pointColor.y += (float) weights[i] * colors[i].y; + pointColor.z += (float) weights[i] * colors[i].z; + pointColor.w += (float) weights[i] * colors[i].w; + } + } + return pointColor; + } - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported - */ + /** + * Returns the coordinates of the intersection point (local coordinates), + * if available. + * @return coordinates of the intersection point + */ public Point3d getPointCoordinates() { - throw new UnsupportedOperationException(); + return pointCoordinates; } - + /** - Returns the coordinates of the intersection point (world coordinates), - if available. - @return coordinates of the point + * Returns the coordinates of the intersection point (world coordinates), + * if available. + * @return coordinates of the point + */ + public Point3d getPointCoordinatesVW() { - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported + if (pointCoordinatesVW != null) { + return pointCoordinatesVW; + } - */ - public Point3d getPointCoordinatesVW() { - throw new UnsupportedOperationException(); + pointCoordinatesVW = new Point3d(); + + pointCoordinatesVW.x = pointCoordinates.x; + pointCoordinatesVW.y = pointCoordinates.y; + pointCoordinatesVW.z = pointCoordinates.z; + + l2vw.transform(pointCoordinatesVW); + return pointCoordinatesVW; } /** - Returns the normal of the intersection point. Returns null if the geometry - does not contain normals. - @return normal at the intersection point. - - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported - - */ + * Returns the normal of the intersection point. Returns null if the geometry + * does not contain normals. + * @return normal at the intersection point. + */ public Vector3f getPointNormal() { - throw new UnsupportedOperationException(); + if (hasNormals && (pointNormal == null)) { + double[] weights = getInterpWeights(); + Vector3f[] normals = getPrimitiveNormals(); + pointNormal = new Vector3f(); + for (int i = 0; i < weights.length; i++) { + pointNormal.x += (float) weights[i] * normals[i].x; + pointNormal.y += (float) weights[i] * normals[i].y; + pointNormal.z += (float) weights[i] * normals[i].z; + } + } + return pointNormal; } /** - Returns the texture coordinate of the intersection point at the specifed - index in the specified texture coordinate set. - Returns null if the geometry - does not contain texture coordinates. If the geometry was defined with - GeometryArray.TEXTURE_COORDINATE_3, the 'z' component of the texture - coordinate will initialized to 0.0 - @return texture coordinate at the intersection point. - - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported - - */ + * Returns the texture coordinate of the intersection point at the specifed + * index in the specified texture coordinate set. + * Returns null if the geometry + * does not contain texture coordinates. If the geometry was defined with + * GeometryArray.TEXTURE_COORDINATE_3, the 'z' component of the texture + * coordinate will initialized to 0.0 + * @return texture coordinate at the intersection point. + */ public TexCoord3f getPointTextureCoordinate(int index) { - throw new UnsupportedOperationException(); + if (hasTexCoords && (pointTexCoord == null)) { + double[] weights = getInterpWeights(); + TexCoord3f[] texCoords = getPrimitiveTexCoords(index); + pointTexCoord = new TexCoord3f(); + for (int i = 0; i < weights.length; i++) { + pointTexCoord.x += (float) weights[i] * texCoords[i].x; + pointTexCoord.y += (float) weights[i] * texCoords[i].y; + pointTexCoord.z += (float) weights[i] * texCoords[i].z; + } + } + return pointTexCoord; } /** - Get the color indices for the intersected primitive. For a non-indexed - primitive, this will be the same as the primitive vertex indices - If the geometry array does not contain colors this will return null. - @return an array indices - - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported - - */ - public int[] getPrimitiveColorIndices () { - throw new UnsupportedOperationException(); + * Get the color indices for the intersected primitive. For a non-indexed + * primitive, this will be the same as the primitive vertex indices + * If the geometry array does not contain colors this will return null. + * @return an array indices + */ + public int[] getPrimitiveColorIndices() { + if (hasColors && (primitiveColorIndices == null)) { + if (geometryIsIndexed()) { + primitiveColorIndices = + new int[primitiveVertexIndices.length]; + for (int i = 0; i < primitiveVertexIndices.length; i++) { + primitiveColorIndices[i] = + ((IndexedGeometryArray)(geometry)).getColorIndex(primitiveVertexIndices[i]); + } + } else { + primitiveColorIndices = primitiveVertexIndices; + } + } + return primitiveColorIndices; } /** - Get the colors of the intersected primitive. This will return null if - the primitive does not contain colors. If the geometry was defined - using GeometryArray.COLOR_3, the 'w' value of the color will be set to 1.0. - @return an array of Point3d's for the primitive that was intersected - - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported - - */ - public Color4f[] getPrimitiveColors () { - throw new UnsupportedOperationException(); + * Get the colors of the intersected primitive. This will return null if + * the primitive does not contain colors. If the geometry was defined + * using GeometryArray.COLOR_3, the 'w' value of the color will be set to 1.0. + * @return an array of Point3d's for the primitive that was intersected + */ + public Color4f[] getPrimitiveColors() { +// System.out.println("PI.getPrimitiveColors " + primitiveColors); + GeometryArray geom = (GeometryArray) geometry; + + if (hasColors && (primitiveColors == null)) { + primitiveColors = new Color4f[primitiveVertexIndices.length]; + int[] indices = getPrimitiveColorIndices(); + int vformat = geom.getVertexFormat(); + if ((vformat & GeometryArray.BY_REFERENCE) == 0) { + if ((vformat & GeometryArray.COLOR_4) == + GeometryArray.COLOR_4) { + for (int i = 0; i < indices.length; i++) { + primitiveColors[i] = new Color4f(); + geom.getColor(indices[i], primitiveColors[i]); + } + } else { + Color3f color = new Color3f(); + for (int i = 0; i < indices.length; i++) { + primitiveColors[i] = new Color4f(); + geom.getColor(indices[i], color); + primitiveColors[i].x = color.x; + primitiveColors[i].y = color.y; + primitiveColors[i].z = color.z; + primitiveColors[i].w = 1.0f; + } + } + } + else { + if ((vformat & GeometryArray.INTERLEAVED) == 0) { + float[] floatData = geom.getColorRefFloat(); + // If data was set as float then .. + if (floatData == null) { + byte[] byteData = geom.getColorRefByte(); + if (byteData == null) { + throw new UnsupportedOperationException("Deprecated : BY_REF - c3b and c3f"); + } + else { + // Could be color3 or color4 + int val; + if ((vformat & GeometryArray.COLOR_4) == + GeometryArray.COLOR_4) { + for (int i = 0; i < indices.length; i++) { + val = indices[i] << 2; // for color4f + primitiveColors[i] = new Color4f(byteData[val], + byteData[val+1], + byteData[val+2], + byteData[val+3]); + + } + } + else { + for (int i = 0; i < indices.length; i++) { + val = indices[i] * 3; // for color3f + primitiveColors[i] = new Color4f(byteData[val], + byteData[val+1], + byteData[val+2], + 1.0f); + + } + } + } + } + else { + // Could be color3 or color4 + int val; + if ((vformat & GeometryArray.COLOR_4) == + GeometryArray.COLOR_4) { + for (int i = 0; i < indices.length; i++) { + val = indices[i] << 2; // for color4f + primitiveColors[i] = new Color4f(floatData[val], + floatData[val+1], + floatData[val+2], + floatData[val+3]); + } + } + else { + for (int i = 0; i < indices.length; i++) { + val = indices[i] * 3; // for color3f + primitiveColors[i] = new Color4f(floatData[val], + floatData[val+1], + floatData[val+2], + 1.0f); + + } + } + } + + } + else { + float[] floatData = geom.getInterleavedVertices(); + int offset = getInterleavedColorOffset(geom); + int stride = getInterleavedStride(geom); + for (int i = 0; i < indices.length; i++) { + int val = stride * indices[i]+offset; + if ((vformat & GeometryArray.COLOR_4) == + GeometryArray.COLOR_4) { + primitiveColors[i] = new Color4f(floatData[val], + floatData[val+1], + floatData[val+2], + floatData[val+3]); + } + else { + primitiveColors[i] = new Color4f(floatData[val], + floatData[val+1], + floatData[val+2], + 1.0f); + } + } + } + } + } + return primitiveColors; } /** - Get the coordinates indices for the intersected primitive. For a non-indexed - primitive, this will be the same as the primitive vertex indices - @return an array indices - - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported - - */ - public int[] getPrimitiveCoordinateIndices () { - throw new UnsupportedOperationException(); + * Get the coordinates indices for the intersected primitive. For a non-indexed + * primitive, this will be the same as the primitive vertex indices + * @return an array indices + */ + public int[] getPrimitiveCoordinateIndices() { + if (primitiveCoordinateIndices == null) { + if (geometryIsIndexed()) { + primitiveCoordinateIndices = + new int[primitiveVertexIndices.length]; + for (int i = 0; i < primitiveVertexIndices.length; i++) { + primitiveCoordinateIndices[i] = + ((IndexedGeometryArray)(geometry)).getCoordinateIndex(primitiveVertexIndices[i]); + } + } else { + primitiveCoordinateIndices = primitiveVertexIndices; + } + } + return primitiveCoordinateIndices; } /** - Get the local coordinates intersected primitive - @return an array of Point3d's for the primitive that was intersected - - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported - - */ - public Point3d[] getPrimitiveCoordinates () { - throw new UnsupportedOperationException(); + * Get the local coordinates intersected primitive + * @return an array of Point3d's for the primitive that was intersected + */ + public Point3d[] getPrimitiveCoordinates() { +// System.out.println("PI.getPrimitiveCoordinates " + primitiveCoordinates); + GeometryArray geom = (GeometryArray) geometry; + + if (primitiveCoordinates == null) { + primitiveCoordinates = new Point3d[primitiveVertexIndices.length]; + int[] indices = getPrimitiveCoordinateIndices(); + int vformat = geom.getVertexFormat(); + int val; + +// System.out.println("---- indices.length - " + indices.length); + if ((vformat & GeometryArray.BY_REFERENCE) == 0) { + for (int i = 0; i < indices.length; i++) { + primitiveCoordinates[i] = new Point3d(); + // System.out.println("PickIntersection : indices["+i+"] = " + indices[i]); + geom.getCoordinate(indices[i], primitiveCoordinates[i]); + } + } + else { + if ((vformat & GeometryArray.INTERLEAVED) == 0) { + double[] doubleData = geom.getCoordRefDouble(); + // If data was set as float then .. + if (doubleData == null) { + float[] floatData = geom.getCoordRefFloat(); + if (floatData == null) { + throw new UnsupportedOperationException("Deprecated : BY_REF - c3f and c3d"); + } + else { + for (int i = 0; i < indices.length; i++) { + val = indices[i] * 3; + primitiveCoordinates[i] = new Point3d(floatData[val], + floatData[val+1], + floatData[val+2]); + } + } + } + else { + for (int i = 0; i < indices.length; i++) { + val = indices[i] * 3; + primitiveCoordinates[i] = new Point3d(doubleData[val], + doubleData[val+1], + doubleData[val+2]); + } + } + } + else { + float[] floatData = geom.getInterleavedVertices(); + int offset = getInterleavedVertexOffset(geom); + int stride = offset + 3; // for the vertices . + for (int i = 0; i < indices.length; i++) { + val = stride * indices[i]+offset; + primitiveCoordinates[i] = new Point3d(floatData[val], + floatData[val+1], + floatData[val+2]); + } + } + } + + } + return primitiveCoordinates; } /** - Get VWorld coordinates of the intersected primitive - @return an array of Point3d's for the primitive that was picked + * Get VWorld coordinates of the intersected primitive + * @return an array of Point3d's for the primitive that was picked + */ + public Point3d[] getPrimitiveCoordinatesVW() { + +// System.out.println("PI.getPrimitiveCoordinatesVW " + primitiveCoordinatesVW); + + if (primitiveCoordinatesVW == null) { + // We need to call getPrimitiveCoordinates first. + Point3d[] coords = getPrimitiveCoordinates(); - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported + primitiveCoordinatesVW = new Point3d[coords.length]; + for (int i = 0; i < coords.length; i++) { + primitiveCoordinatesVW[i] = new Point3d(); - */ - public Point3d[] getPrimitiveCoordinatesVW () { - throw new UnsupportedOperationException(); + primitiveCoordinatesVW[i].x = coords[i].x; + primitiveCoordinatesVW[i].y = coords[i].y; + primitiveCoordinatesVW[i].z = coords[i].z; + + l2vw.transform(primitiveCoordinatesVW[i]); + } + } + return primitiveCoordinatesVW; } /** - Get the normal indices for the intersected primitive. For a non-indexed - primitive, this will be the same as the primitive vertex indices - If the geometry array does not contain normals this will return null - @return an array indices - - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported - - */ - public int[] getPrimitiveNormalIndices () { - throw new UnsupportedOperationException(); + * Get the normal indices for the intersected primitive. For a non-indexed + * primitive, this will be the same as the primitive vertex indices + * If the geometry array does not contain normals this will return null + * @return an array indices + */ + public int[] getPrimitiveNormalIndices() { + if (hasNormals && (primitiveNormalIndices == null)) { + if (geometryIsIndexed()) { + primitiveNormalIndices = + new int[primitiveVertexIndices.length]; + for (int i = 0; i < primitiveVertexIndices.length; i++) { + primitiveNormalIndices[i] = + ((IndexedGeometryArray)(geometry)).getNormalIndex(primitiveVertexIndices[i]); + } + } else { + primitiveNormalIndices = primitiveVertexIndices; + } + } + return primitiveNormalIndices; } /** - Get the normals of the intersected primitive. This will return null if - the primitive does not contain normals. - @return an array of Point3d's for the primitive that was intersected - - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported - - */ - public Vector3f[] getPrimitiveNormals () { - throw new UnsupportedOperationException(); + * Get the normals of the intersected primitive. This will return null if + * the primitive does not contain normals. + * @return an array of Point3d's for the primitive that was intersected + */ + public Vector3f[] getPrimitiveNormals() { +// System.out.println("PI.getPrimitiveNormals " + primitiveNormals); + GeometryArray geom = (GeometryArray) geometry; + + if (hasNormals && (primitiveNormals == null)) { + primitiveNormals = new Vector3f[primitiveVertexIndices.length]; + int[] indices = getPrimitiveNormalIndices(); + int vformat = geom.getVertexFormat(); + int val; + + if ((vformat & GeometryArray.BY_REFERENCE) == 0) { + for (int i = 0; i < indices.length; i++) { + primitiveNormals[i] = new Vector3f(); + geom.getNormal(indices[i], primitiveNormals[i]); + } + } + else { + if ((vformat & GeometryArray.INTERLEAVED) == 0) { + float[] floatNormals = geom.getNormalRefFloat(); + if (floatNormals != null) { + for (int i = 0; i < indices.length; i++) { + val = indices[i] * 3; + primitiveNormals[i] = new Vector3f(floatNormals[val], + floatNormals[val+1], + floatNormals[val+2]); + } + } + else { + throw new UnsupportedOperationException("Deprecated : BY_REF - n3f"); + } + } + else { + float[] floatData = geom.getInterleavedVertices(); + int offset = getInterleavedColorOffset(geom); + int stride = getInterleavedStride(geom); + for (int i = 0; i < indices.length; i++) { + val = stride * indices[i]+offset; + primitiveNormals[i] = new Vector3f(floatData[val],floatData[val+1],floatData[val+2]); + + } + } + } + } + return primitiveNormals; } /** - Get the texture coordinate indices for the intersected primitive at the specifed - index in the specified texture coordinate set. For a non-indexed - primitive, this will be the same as the primitive vertex indices - If the geometry array does not contain texture coordinates, this will - return null. - @return an array indices - - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported - - */ - public int[] getPrimitiveTexCoordIndices (int index) { - throw new UnsupportedOperationException(); + * Get the texture coordinate indices for the intersected primitive at the specifed + * index in the specified texture coordinate set. For a non-indexed + * primitive, this will be the same as the primitive vertex indices + * If the geometry array does not contain texture coordinates, this will + * return null. + * @return an array indices + */ + public int[] getPrimitiveTexCoordIndices(int index) { + if (hasTexCoords && (primitiveTexCoordIndices == null)) { + if (geometryIsIndexed()) { + primitiveTexCoordIndices = + new int[primitiveVertexIndices.length]; + for (int i = 0; i < primitiveVertexIndices.length; i++) { + primitiveTexCoordIndices[i] = + ((IndexedGeometryArray)(geometry)).getTextureCoordinateIndex(index, primitiveVertexIndices[i]); + } + } else { + primitiveTexCoordIndices = primitiveVertexIndices; + } + } + return primitiveTexCoordIndices; } /** - Get the texture coordinates of the intersected primitive at the specifed - index in the specified texture coordinate set. - null if the primitive does not contain texture coordinates. - If the geometry was defined - using GeometryArray.TEXTURE_COORDINATE_2, the 'z' value of the texture - coordinate will be set to 0.0. - @return an array of TexCoord3f's for the primitive that was intersected - - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported - - */ + * Get the texture coordinates of the intersected primitive at the specifed + * index in the specified texture coordinate set. + * null if the primitive does not contain texture coordinates. + * If the geometry was defined + * using GeometryArray.TEXTURE_COORDINATE_2, the 'z' value of the texture + * coordinate will be set to 0.0. + * @return an array of TexCoord3f's for the primitive that was intersected + */ public TexCoord3f[] getPrimitiveTexCoords (int index) { - throw new UnsupportedOperationException(); +// System.out.println("PI.getPrimitiveTexCoords " + primitiveTexCoords); + GeometryArray geom = (GeometryArray) geometry; + + if (primitiveTexCoords == null) { + primitiveTexCoords = new TexCoord3f[primitiveVertexIndices.length]; + int[] indices = getPrimitiveTexCoordIndices(index); + int vformat = geom.getVertexFormat(); + if ((vformat & GeometryArray.BY_REFERENCE) == 0) { + for (int i = 0; i < indices.length; i++) { + primitiveTexCoords[i] = new TexCoord3f(); + geom.getTextureCoordinate(index, indices[i], primitiveTexCoords[i]); + } + } + else { + if ((vformat & GeometryArray.INTERLEAVED) == 0) { + int val; + float[] floatTexCoords = geom.getTexCoordRefFloat(index); + if (floatTexCoords != null) { + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == GeometryArray.TEXTURE_COORDINATE_2) { + for (int i = 0; i < indices.length; i++) { + val = indices[i] << 1; // t2f + primitiveTexCoords[i] = new TexCoord3f(floatTexCoords[val], + floatTexCoords[val+1], + 0.0f); + } + } + else { + for (int i = 0; i < indices.length; i++) { + val = indices[i] * 3; // t3f + primitiveTexCoords[i] = new TexCoord3f(floatTexCoords[val], + floatTexCoords[val+1], + floatTexCoords[val+2]); + } + } + } + else { + throw new UnsupportedOperationException("Deprecated : BY_REF - t2f and t3f"); + } + } + else { + float[] floatData = geom.getInterleavedVertices(); + int stride = getInterleavedStride(geom); + int offset; + // Get the correct tex coord set + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == + GeometryArray.TEXTURE_COORDINATE_2) { + offset = index << 1; + } + else { + offset = index * 3; + } + for (int i = 0; i < indices.length; i++) { + int val = stride * indices[i]; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == + GeometryArray.TEXTURE_COORDINATE_2) { + primitiveTexCoords[i] = + new TexCoord3f(floatData[val+offset], + floatData[val+1+offset], + 0.0f); + } + else { + primitiveTexCoords[i] = + new TexCoord3f(floatData[val+offset], + floatData[val+1+offset], + floatData[val+2+offset]); + } + } + } + } + } + return primitiveTexCoords; } /** - Get vertex indices of the intersected primitive - @return an array which contains the list of indices - - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported + * Get vertex indices of the intersected primitive + * @return an array which contains the list of indices + */ + public int [] getPrimitiveVertexIndices() { + return primitiveVertexIndices; + } - */ - public int [] getPrimitiveVertexIndices () { - throw new UnsupportedOperationException(); + /** + * Gets the IntersectionInfo this intersection is part of. + */ + public PickInfo.IntersectionInfo getIntersectionInfo() { + return iInfo; } /** - String representation of this object + * String representation of this object + */ + public String toString() { + String rt = new String ("PickIntersection: "); + rt += " IntersectionInfo = "+ iInfo + "\n"; + rt += " geometry = "+ geometry + "\n"; + if (distance != -1) rt += " dist:"+distance + "\n"; + if (pointCoordinates != null) rt += " pt:" + pointCoordinates + "\n"; + if (pointCoordinatesVW != null) rt += " ptVW:" + pointCoordinatesVW + "\n"; + + if (primitiveCoordinateIndices != null) { + rt += " prim coordinate ind:" + "\n"; + for (int i=0;i<primitiveCoordinateIndices.length;i++) { + rt += " "+primitiveCoordinateIndices[i] + "\n"; + } + } + + if (primitiveColorIndices != null) { + rt += " prim color ind:" + "\n"; + for (int i=0;i<primitiveColorIndices.length;i++) { + rt += " "+primitiveColorIndices[i] + "\n"; + } + } + + if (primitiveNormalIndices != null) { + rt += " prim normal ind:" + "\n"; + for (int i=0;i<primitiveNormalIndices.length;i++) { + rt += " "+primitiveNormalIndices[i] + "\n"; + } + } + + if (primitiveTexCoordIndices != null) { + rt += " prim texture ind:" + "\n"; + for (int i=0;i<primitiveTexCoordIndices.length;i++) { + rt += " "+primitiveTexCoordIndices[i] + "\n"; + } + } + + if (closestVertexCoordinates != null) { + rt += " clos. vert:" + closestVertexCoordinates + "\n"; + } + + if (closestVertexCoordinatesVW != null) { + rt += " clos. vert:" + closestVertexCoordinatesVW + "\n"; + } + + if (closestVertexIndex != -1) { + rt += " clos. vert. ind.:" + closestVertexIndex + "\n"; + } + return rt; + } - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported - */ - public String toString () { - throw new UnsupportedOperationException(); - } + /******************** Helper methods ***************************************/ - /** - Gets the IntersectionInfo this intersection is part of. + int getInterleavedVertexOffset(GeometryArray geo) { + int offset = 0; + int vformat = geo.getVertexFormat(); + if ((vformat & GeometryArray.COLOR_3) == GeometryArray.COLOR_3) { + offset += 3; + } else if ((vformat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4){ + offset += 4; + } + if ((vformat & GeometryArray.NORMALS) != 0) + offset += 3; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == GeometryArray.TEXTURE_COORDINATE_2) { + offset += 2 * geo.getTexCoordSetCount(); + } + else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) == GeometryArray.TEXTURE_COORDINATE_3) { + offset += 3 * geo.getTexCoordSetCount(); + } - * This method is currently not supported. - * @exception UnsupportedOperationException this method is not supported + return offset; + } - */ - public PickInfo.IntersectionInfo getIntersectionInfo() { - throw new UnsupportedOperationException(); + int getInterleavedStride(GeometryArray geo) { + int offset = 3; // Add 3 for vertices + int vformat = geo.getVertexFormat(); + if ((vformat & GeometryArray.COLOR_3) == GeometryArray.COLOR_3) { + offset += 3; + } else if ((vformat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4){ + offset += 4; + } + if ((vformat & GeometryArray.NORMALS) != 0) + offset += 3; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == GeometryArray.TEXTURE_COORDINATE_2) { + offset += 2 * geo.getTexCoordSetCount(); + } + else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) == GeometryArray.TEXTURE_COORDINATE_3) { + offset += 3 * geo.getTexCoordSetCount(); + } + + return offset; } - -} // PickIntersection + int getInterleavedColorOffset(GeometryArray geo) { + int offset = 0; + int vformat = geo.getVertexFormat(); + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == GeometryArray.TEXTURE_COORDINATE_2) { + offset += 2 * geo.getTexCoordSetCount(); + } + else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) == GeometryArray.TEXTURE_COORDINATE_3) { + offset += 3 * geo.getTexCoordSetCount(); + } + + return offset; + } + /* ================================================================== */ + /* Utility code for interpolating intersection point data */ + /* ================================================================== */ + /* absolute value */ + double + abs(double value) { + if (value < 0.0) { + return -value; + } else { + return value; + } + } + + /* return the axis corresponding to the largest component of delta */ + int + maxAxis(Vector3d delta) { + int axis = X_AXIS; + double max = abs(delta.x); + if (abs(delta.y) > max) { + axis = Y_AXIS; + max = abs(delta.y); + } + if (abs(delta.z) > max) { + axis = Z_AXIS; + } + return axis; + } + /* Triangle interpolation. Basic idea: + * Map the verticies of the triangle to the form: + * + * L--------R + * \ / + * IL+--P-+IR + * \ / + * Base + * + where P is the intersection point Base, L and R and the triangle + points. IL and IR are the projections if P along the Base-L and Base-R + edges using an axis: + + IL = leftFactor * L + (1- leftFactor) * Base + IR = rightFactor * R + (1-rightFactor) * Base + + then find the interp factor, midFactor, for P between IL and IR. If + this is outside the range 0->1 then we have the wrong triangle of a + quad and we return false. + + Else, the weighting is: + + IP = midFactor * IL + (1 - midFactor) * IR; + + Solving for weights for the formula: + IP = BaseWeight * Base + LeftWeight * L + RightWeight * R; + We get: + BaseWeight = 1 - midFactor * leftFactor + - rightFactor + midFactor * rightFactor; + LeftWeight = midFactor * leftFactor; + RightWeight = righFactor - midFactor * rightFactor; + As a check, note that the sum of the weights is 1.0. + */ + + boolean + interpTriangle(int index0, int index1, int index2, Point3d[] coords, + Point3d intPt) { + + // find the longest edge, we'll use that to pick the axis */ + Vector3d delta0 = new Vector3d(); + Vector3d delta1 = new Vector3d(); + Vector3d delta2 = new Vector3d(); + delta0.sub(coords[index1], coords[index0]); + delta1.sub(coords[index2], coords[index0]); + delta2.sub(coords[index2], coords[index1]); + double len0 = delta0.lengthSquared(); + double len1 = delta1.lengthSquared(); + double len2 = delta2.lengthSquared(); + Vector3d longest = delta0; + double maxLen = len0; + if (len1 > maxLen) { + longest = delta1; + maxLen = len1; + } + if (len2 > maxLen) { + longest = delta2; + } + int mainAxis = maxAxis(longest); + + /* + System.out.println("index0 = " + index0 + " index1 = " + index1 + + " index2 = " + index2); + + System.out.println("coords[index0] = " + coords[index0]); + System.out.println("coords[index1] = " + coords[index1]); + System.out.println("coords[index2] = " + coords[index2]); + System.out.println("intPt = " + intPt); + + System.out.println("delta0 = " + delta0 + " len0 " + len0); + System.out.println("delta1 = " + delta1 + " len1 " + len1); + System.out.println("delta2 = " + delta2 + " len2 " + len2); + */ + + /* now project the intersection point along the axis onto the edges */ + double[] factor = new double[3]; + /* the factor is for the projection opposide the vertex 0 = 1->2, etc*/ + factor[0] = + getInterpFactorForBase(intPt, coords[index1], coords[index2], mainAxis); + factor[1] = + getInterpFactorForBase(intPt, coords[index2], coords[index0], mainAxis); + factor[2] = + getInterpFactorForBase(intPt, coords[index0], coords[index1], mainAxis); + + if (debug) { + System.out.println("intPt = " + intPt); + switch(mainAxis) { + case X_AXIS: + System.out.println("mainAxis = X_AXIS"); + break; + case Y_AXIS: + System.out.println("mainAxis = Y_AXIS"); + break; + case Z_AXIS: + System.out.println("mainAxis = Z_AXIS"); + break; + } + System.out.println("factor[0] = " + factor[0]); + System.out.println("factor[1] = " + factor[1]); + System.out.println("factor[2] = " + factor[2]); + } + + /* Find the factor that is out of range, it will tell us which + * vertex to use for base + */ + int base, left, right; + double leftFactor, rightFactor; + if ((factor[0] < 0.0) || (factor[0] > 1.0)) { + base = index0; + right = index1; + left = index2; + rightFactor = factor[2]; + leftFactor = 1.0 - factor[1]; + if (debug) { + System.out.println("base 0, rightFactor = " + rightFactor + + " leftFactor = " + leftFactor); + } + } else if ((factor[1] < 0.0) || (factor[1] > 1.0)) { + base = index1; + right = index2; + left = index0; + rightFactor = factor[0]; + leftFactor = 1.0 - factor[2]; + if (debug) { + System.out.println("base 1, rightFactor = " + rightFactor + + " leftFactor = " + leftFactor); + } + } else { + base = index2; + right = index0; + left = index1; + rightFactor = factor[1]; + leftFactor = 1.0 - factor[0]; + if (debug) { + System.out.println("base 2, rightFactor = " + rightFactor + + " leftFactor = " + leftFactor); + } + } + if (debug) { + System.out.println("base = " + coords[base]); + System.out.println("left = " + coords[left]); + System.out.println("right = " + coords[right]); + } + /* find iLeft and iRight */ + Point3d iLeft = new Point3d(leftFactor * coords[left].x + + (1.0-leftFactor)*coords[base].x, + leftFactor * coords[left].y + + (1.0-leftFactor)*coords[base].y, + leftFactor * coords[left].z + + (1.0-leftFactor)*coords[base].z); + + Point3d iRight = new Point3d(rightFactor * coords[right].x + + (1.0-rightFactor)*coords[base].x, + rightFactor * coords[right].y + + (1.0-rightFactor)*coords[base].y, + rightFactor * coords[right].z + + (1.0-rightFactor)*coords[base].z); + + if (debug) { + System.out.println("iLeft = " + iLeft); + System.out.println("iRight = " + iRight); + } + + /* now find an axis and solve for midFactor */ + delta0.sub(iLeft, iRight); + int midAxis = maxAxis(delta0); + double midFactor = getInterpFactor(intPt, iRight, iLeft, midAxis); + + if (debug) { + switch(midAxis) { + case X_AXIS: + System.out.println("midAxis = X_AXIS"); + break; + case Y_AXIS: + System.out.println("midAxis = Y_AXIS"); + break; + case Z_AXIS: + System.out.println("midAxis = Z_AXIS"); + break; + } + System.out.println("midFactor = " + midFactor); + } + + if (midFactor < 0.0) { + // System.out.println("midFactor = " + midFactor); + if ((midFactor + TOL) >= 0.0) { + // System.out.println("In Tol case : midFactor = " + midFactor); + midFactor = 0.0; + } + else { + /* int point is outside triangle */ + return false; + } + } + else if (midFactor > 1.0) { + // System.out.println("midFactor = " + midFactor); + if ((midFactor-TOL) <= 1.0) { + // System.out.println("In Tol case : midFactor = " + midFactor); + midFactor = 1.0; + } + else { + /* int point is outside triangle */ + return false; + } + } + + // Assign the weights + interpWeights[base] = 1.0 - midFactor * leftFactor - + rightFactor + midFactor * rightFactor; + interpWeights[left] = midFactor * leftFactor; + interpWeights[right] = rightFactor - midFactor * rightFactor; + return true; + } + /* Get the interpolation weights for each of the verticies of the + * primitive. + */ + double[] getInterpWeights() { + + Point3d pt = getPointCoordinates(); + Point3d[] coordinates = getPrimitiveCoordinates(); + double factor; + int axis; + + if (interpWeights != null) { + return interpWeights; + } + + interpWeights = new double[coordinates.length]; + + // Interpolate + switch (coordinates.length) { + case 1: + // Nothing to interpolate + interpWeights[0] = 1.0; + break; + case 2: // edge + Vector3d delta = new Vector3d(); + delta.sub (coordinates[1], coordinates[0]); + axis = maxAxis(delta); + factor = getInterpFactor (pt, coordinates[1], coordinates[0], axis); + interpWeights[0] = factor; + interpWeights[1] = 1.0 - factor; + break; + case 3: // triangle + if (!interpTriangle(0, 1, 2, coordinates, pt)) { + throw new RuntimeException ("Interp point outside triangle"); + } + break; + case 4: // quad + if (!interpTriangle(0, 1, 2, coordinates, pt)) { + if (!interpTriangle(0, 2, 3, coordinates, pt)) { + throw new RuntimeException ("Interp point outside quad"); + } + } + break; + default: + throw new RuntimeException ("Unexpected number of points."); + } + return interpWeights; + } + /** + Calculate the interpolation factor for point p by projecting it along + an axis (x,y,z) onto the edge between p1 and p2. If the result is + in the 0->1 range, point is between p1 and p2 (0 = point is at p1, + 1 => point is at p2). + */ + private static float getInterpFactor (Point3d p, Point3d p1, Point3d p2, + int axis) { + float t; + switch (axis) { + case X_AXIS: + if (p1.x == p2.x) + //t = Float.MAX_VALUE; // TODO: should be 0? + t = 0.0f; + else + t = (float) ((p1.x - p.x) / (p1.x - p2.x)); + break; + case Y_AXIS: + if (p1.y == p2.y) + // t = Float.MAX_VALUE; + t = 0.0f; + else + t = (float) ((p1.y - p.y) / (p1.y - p2.y)); + break; + case Z_AXIS: + if (p1.z == p2.z) + // t = Float.MAX_VALUE; + t = 0.0f; + else + t = (float)((p1.z - p.z) / (p1.z - p2.z)); + break; + default: + throw new RuntimeException ("invalid axis parameter "+axis+" (must be 0-2)"); + } + return t; + } + /** + Calculate the interpolation factor for point p by projecting it along + an axis (x,y,z) onto the edge between p1 and p2. If the result is + in the 0->1 range, point is between p1 and p2 (0 = point is at p1, + 1 => point is at p2). + return MAX_VALUE if component of vertices are the same. + */ + private static float getInterpFactorForBase (Point3d p, Point3d p1, Point3d p2, + int axis) { + float t; + switch (axis) { + case X_AXIS: + if (p1.x == p2.x) + t = Float.MAX_VALUE; + else + t = (float) ((p1.x - p.x) / (p1.x - p2.x)); + break; + case Y_AXIS: + if (p1.y == p2.y) + t = Float.MAX_VALUE; + else + t = (float) ((p1.y - p.y) / (p1.y - p2.y)); + break; + case Z_AXIS: + if (p1.z == p2.z) + t = Float.MAX_VALUE; + else + t = (float)((p1.z - p.z) / (p1.z - p2.z)); + break; + default: + throw new RuntimeException ("invalid axis parameter "+axis+" (must be 0-2)"); + } + return t; + } + +} // PickIntersection |