All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scijava.java3d.utils.picking.PickIntersection Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistribution of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistribution in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of
 * contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any
 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
 * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or
 * intended for use in the design, construction, operation or
 * maintenance of any nuclear facility.
 *
 */

package org.scijava.java3d.utils.picking;

import org.scijava.java3d.GeometryArray;
import org.scijava.java3d.IndexedGeometryArray;
import org.scijava.vecmath.Color3b;
import org.scijava.vecmath.Color3f;
import org.scijava.vecmath.Color4b;
import org.scijava.vecmath.Color4f;
import org.scijava.vecmath.Point3d;
import org.scijava.vecmath.Point3f;
import org.scijava.vecmath.TexCoord2f;
import org.scijava.vecmath.TexCoord3f;
import org.scijava.vecmath.Vector3d;
import org.scijava.vecmath.Vector3f;

/**
 * Holds information about an intersection of a PickShape with a Node
 * as part of a PickResult. Information about
 * the intersected geometry, intersected primitive, intersection point, and
 * closest vertex can be inquired.
 * 

* The intersected geometry is indicated by an index into the list of * geometry arrays on the PickResult. It can also be inquired from this * object. *

* The intersected primitive indicates which primitive out of the GeometryArray * was intersected (where the primitive is a point, line, triangle or quad, * not a * org.scijava.java3d.utils.geometry.Primitive). * For example, the intersection would indicate which triangle out of a * triangle strip was intersected. * The methods which return primitive data will have one value if the primitive * is * a point, two values if the primitive is a line, three values if the primitive * is a triangle and four values if the primitive is quad. *

* The primitive's VWorld coordinates are saved when then intersection is * calculated. The local coordinates, normal, color and texture coordinates * for the primitive can also be inquired if they are present and readable. *

* The intersection point is the location on the primitive which intersects the * pick shape closest to the center of the pick shape. The intersection point's * location in VWorld coordinates is saved when the intersection is calculated. * The local coordinates, normal, color and texture coordiantes of at the * intersection can be interpolated if they are present and readable. *

* The closest vertex is the vertex of the primitive closest to the intersection * point. The vertex index, VWorld coordinates and local coordinates of the * closest vertex can be inquired. The normal, color and texture coordinate * of the closest vertex can be inquired from the geometry array: *

 *      Vector3f getNormal(PickIntersection pi, int vertexIndex) {
 *          int index;
 *          Vector3d normal = new Vector3f();
 *          GeometryArray ga = pickIntersection.getGeometryArray();
 *          if (pickIntersection.geometryIsIndexed()) {
 *              index = ga.getNormalIndex(vertexIndex);
 *          } else {
 *              index = vertexIndex;
 *          }
 *          ga.getNormal(index, normal);
 *          return normal;
 *      }
 * 
*

* The color, normal * and texture coordinate information for the intersected primitive and the * intersection point * can be inquired * the geometry includes them and the corresponding READ capibility bits are * set. * * PickTool.setCapabilties(Node, int) * can be used to set the capability bits * to allow this data to be inquired. */ public class PickIntersection { /* OPEN ISSUES: -- Tex coordinates always use texCoordSet == 0. */ /* =================== ATTRIBUTES ======================= */ // init by constructor: /** PickResult for intersection is part of */ PickResult pickResult = null; // init by intersection: /** Distance between start point and intersection point (see comment above)*/ double distance = -1; /** index of GeometryArray in PickResult */ int geomIndex = 0; /** Indices of the intersected primitive */ int[] primitiveVertexIndices = null; /** VWorld coordinates of intersected primitive */ Point3d[] primitiveCoordinatesVW = null; /** VWorld Coordinates of the intersection point */ Point3d pointCoordinatesVW = null; // Derived data // Geometry GeometryArray geom = null; IndexedGeometryArray iGeom = null; boolean hasNormals = false; boolean hasColors = false; boolean hasTexCoords = false; // Primitive /* indices for the different data types */ int[] primitiveCoordinateIndices; int[] primitiveNormalIndices; int[] primitiveColorIndices; int[] primitiveTexCoordIndices; /* Local coordinates of the intersected primitive */ Point3d[] primitiveCoordinates = null; /* Normals of the intersected primitive */ Vector3f[] primitiveNormals = null; /* Colors of the intersected primitive */ Color4f[] primitiveColors = null; /* TextureCoordinates of the intersected primitive */ TexCoord3f[] primitiveTexCoords = null; // Intersection point /** Local Coordinates of the intersection point */ Point3d pointCoordinates = null; /** Normal at the intersection point */ Vector3f pointNormal = null; /** Color at the intersection point */ Color4f pointColor = null; /** TexCoord at the intersection point */ TexCoord3f pointTexCoord = null; // Closest Vertex /** Index of the closest vertex */ int closestVertexIndex = -1; /** Coordinates of the closest vertex */ Point3d closestVertexCoordinates = null; /** Coordinates of the closest vertex (World coordinates) */ Point3d closestVertexCoordinatesVW = null; /** Weight factors for interpolation, values correspond to vertex indices, * sum == 1 */ double[] interpWeights; static final boolean debug = false; // Axis constants static final int X_AXIS = 1; static final int Y_AXIS = 2; static final int Z_AXIS = 3; // Tolerance for numerical stability static final double TOL = 1.0e-5; /* =================== METHODS ======================= */ /** Constructor @param pickResult The pickResult this intersection is part of. */ PickIntersection (PickResult pr, GeometryArray geomArr) { // pr can't be null. pickResult = pr; geom = geomArr; if (geom == null) { GeometryArray[] ga = pickResult.getGeometryArrays(); geom = ga[geomIndex]; } if (geom instanceof IndexedGeometryArray) { iGeom = (IndexedGeometryArray)geom; } int vertexFormat = geom.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))); } /** String representation of this object */ @Override public String toString () { String rt = new String ("PickIntersection: "); rt += " pickResult = "+pickResult + "\n"; rt += " geomIndex = "+geomIndex + "\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;i2, 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 = getPointCoordinatesVW(); Point3d[] coordinates = getPrimitiveCoordinatesVW(); 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





© 2015 - 2024 Weber Informatics LLC | Privacy Policy