org.scijava.java3d.utils.picking.PickResult Maven / Gradle / Ivy
Show all versions of j3dutils Show documentation
/*
* 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 java.util.ArrayList;
import org.scijava.java3d.BoundingBox;
import org.scijava.java3d.BoundingPolytope;
import org.scijava.java3d.BoundingSphere;
import org.scijava.java3d.Bounds;
import org.scijava.java3d.BranchGroup;
import org.scijava.java3d.CompressedGeometry;
import org.scijava.java3d.Geometry;
import org.scijava.java3d.GeometryArray;
import org.scijava.java3d.Group;
import org.scijava.java3d.IndexedGeometryArray;
import org.scijava.java3d.IndexedLineArray;
import org.scijava.java3d.IndexedLineStripArray;
import org.scijava.java3d.IndexedPointArray;
import org.scijava.java3d.IndexedQuadArray;
import org.scijava.java3d.IndexedTriangleArray;
import org.scijava.java3d.IndexedTriangleFanArray;
import org.scijava.java3d.IndexedTriangleStripArray;
import org.scijava.java3d.LineArray;
import org.scijava.java3d.LineStripArray;
import org.scijava.java3d.Link;
import org.scijava.java3d.Morph;
import org.scijava.java3d.Node;
import org.scijava.java3d.PickBounds;
import org.scijava.java3d.PickCone;
import org.scijava.java3d.PickConeRay;
import org.scijava.java3d.PickConeSegment;
import org.scijava.java3d.PickCylinder;
import org.scijava.java3d.PickCylinderRay;
import org.scijava.java3d.PickCylinderSegment;
import org.scijava.java3d.PickPoint;
import org.scijava.java3d.PickRay;
import org.scijava.java3d.PickSegment;
import org.scijava.java3d.PickShape;
import org.scijava.java3d.PointArray;
import org.scijava.java3d.QuadArray;
import org.scijava.java3d.SceneGraphPath;
import org.scijava.java3d.Shape3D;
import org.scijava.java3d.Switch;
import org.scijava.java3d.Transform3D;
import org.scijava.java3d.TransformGroup;
import org.scijava.java3d.TriangleArray;
import org.scijava.java3d.TriangleFanArray;
import org.scijava.java3d.TriangleStripArray;
import org.scijava.vecmath.Point2d;
import org.scijava.vecmath.Point3d;
import org.scijava.vecmath.Point3f;
import org.scijava.vecmath.Point4d;
import org.scijava.vecmath.Tuple3d;
import org.scijava.vecmath.Vector3d;
import org.scijava.vecmath.Vector4d;
import org.scijava.java3d.internal.Distance;
import org.scijava.java3d.utils.geometry.Primitive;
/**
* Stores information about a pick hit.
* Detailed information about the pick and each intersection of the PickShape
* with the picked Node can be inquired. The PickResult is constructed with
* basic information and more detailed information is generated as needed. The
* additional information is only available if capability bits on the scene
* graph Nodes are set properly;
*
* PickTool.setCapabilties(Node, int)
* can
* be used to ensure correct capabilites are set. Inquiring data which is not
* available due to capabilties not being set will generate a
* CapabilityNotSet
exception.
*
* A PickResult can be used to calculate intersections on Node which is not part
* of a live scene graph using the constructor which takes a local to VWorld
* transformation for the Node.
*
* Pick hits on TriangleStrip primitives will store the triangle points in the
* PickIntersection with
* the verticies in counter-clockwise order. For triangles which start with
* an odd numbered vertex this will be the the opposite of the
* order of the points in the TriangleStrip.
* This way the triangle in
* the PickIntersection will display the same was as the triangle in the
* strip.
*
* If the Shape3D being picked has multiple geometry arrays, the arrays are
* stored in the PickResult and referred to by a geometry index.
*
* If the Shape3D refers to a CompressedGeometry, the geometry is decompressed
* into an array of Shape3D nodes which can be inquired. The geometry
* NodeComponents for the Shape3D nodes are stored and used as if the Shape3D
* had multiple geometries. If there are multiple CompressedGeometries on the
* Shape3D, the decompressed Shape3Ds and GeometryArrays will be stored
* sequentially.
*
* The intersection point for Morph nodes cannot be calculated using the
* displayed geometry
* due to limitations in the current Java3D core API (the current
* geometry of the the Morph cannot be inquired). Instead
* the geometry at index 0 in the Morph is used. This limitation may
* be eliminated in a future release of Java3D.
*/
public class PickResult {
/* OPEN ISSUES:
-- getInterpolatedTextureCoordinates uses the depricated API faor
getTextureCoordinate(), need to update.
-- Bounds tests don't fill in any picking info.
-- Can't do any intersections with the PickPoint shape.
*/
// Externally used constants
/**
* Flag to pass to
* getNode(int)
* to return a
* Shape3D
node from
* the SceneGraphPath
.
*/
public static final int SHAPE3D = 0x1;
/**
* Flag to pass to
* getNode(int)
* to return a
* Morph
node from
* the SceneGraphPath
.
*/
public static final int MORPH = 0x2;
/**
* Flag to pass to
* getNode(int)
* to return a
* Primitive
node from
* the SceneGraphPath
.
*/
public static final int PRIMITIVE = 0x4;
/**
* Flag to pass to
* getNode(int)
* to return a
* Link
node from
* the SceneGraphPath
.
*/
public static final int LINK = 0x8;
/**
* Flag to pass to
* getNode(int)
* to return a
* Group
node from
* the SceneGraphPath
.
*/
public static final int GROUP = 0x10;
/**
* Flag to pass to
* getNode(int)
* to return a
* TransformGroup
node from
* the SceneGraphPath
.
*/
public static final int TRANSFORM_GROUP = 0x20;
/**
* Flag to pass to
* getNode(int)
* to return a
* BranchGroup
node from
* the SceneGraphPath
.
*/
public static final int BRANCH_GROUP = 0x40;
/**
* Flag to pass to
* getNode(int)
* to return a
* Switch
node from
* the SceneGraphPath
.
*/
public static final int SWITCH = 0x80;
/* =================== ATTRIBUTES ======================= */
static boolean debug = false;
/** if true, find only the first intersection */
private boolean firstIntersectOnly = false;
/** Stored SceneGraphPath */
private SceneGraphPath pickedSceneGraphPath = null;
/** Picked node: shape3d, text3d, etc. */
private Node pickedNode = null;
/** GeometryArray(s) of the picked node */
private GeometryArray[] geometryArrays = null;
/** Shape3Ds from CompressedGeometry on the picked node */
private Shape3D[] compressGeomShape3Ds = null;
/** Transform to World Coordinates */
private Transform3D localToVWorld = null;
/** the pick shape to use for intersections */
private PickShape pickShape = null;
/* data derived from the pick shape */
private int pickShapeType = -1;
private Vector3d pickShapeDir = null;
private Point3d pickShapeStart = null;
private Point3d pickShapeEnd = null;
private Bounds pickShapeBounds = null;
static final Point3d zeroPnt = new Point3d();
/** ArrayList to store intersection results
* Used in PickTool
*/
ArrayList intersections = null;
// internal constants used for intersections
static final double FUZZ = 1E-6; /* fuzziness factor used to determine
if two lines are parallel */
static final int PICK_SHAPE_RAY = 1;
static final int PICK_SHAPE_SEGMENT = 2;
static final int PICK_SHAPE_POINT = 3;
static final int PICK_SHAPE_BOUNDING_BOX = 4;
static final int PICK_SHAPE_BOUNDING_SPHERE = 5;
static final int PICK_SHAPE_BOUNDING_POLYTOPE = 6;
static final int PICK_SHAPE_CYLINDER = 7;
static final int PICK_SHAPE_CONE = 8;
static final double EPS = 1.0e-13;
/* =================== METHODS ======================= */
/** Default constructor. */
PickResult () { }
/** Construct a PickResult using a SceneGraphPath
@param sgp SceneGraphPath associated with this PickResult
@param ps The pickShape to intersect against
*/
public PickResult (SceneGraphPath sgp, PickShape ps) {
pickedSceneGraphPath = sgp;
pickedNode = sgp.getObject();
localToVWorld = sgp.getTransform();
pickShape = ps;
initPickShape();
}
/** Construct a PickResult using the Node and localToVWorld transform
@param pn The picked node.
@param l2vw The local to VWorld transformation for the node
@param ps The PickShape to intersect against
@throws IllegalArgumentException If the node is not a Morph or Shape3D.
*/
public PickResult (Node pn, Transform3D l2vw, PickShape ps) {
if ((pn instanceof Shape3D) || (pn instanceof Morph)) {
pickedNode = pn;
localToVWorld = l2vw;
pickShape = ps;
initPickShape();
} else {
throw new IllegalArgumentException();
}
}
void initPickShape() {
if(pickShape instanceof PickRay) {
if (pickShapeStart == null) pickShapeStart = new Point3d();
if (pickShapeDir == null) pickShapeDir = new Vector3d();
((PickRay) pickShape).get (pickShapeStart, pickShapeDir);
pickShapeType = PICK_SHAPE_RAY;
} else if (pickShape instanceof PickSegment) {
if (pickShapeStart == null) pickShapeStart = new Point3d();
if (pickShapeEnd == null) pickShapeEnd = new Point3d();
if (pickShapeDir == null) pickShapeDir = new Vector3d();
((PickSegment)pickShape).get(pickShapeStart, pickShapeEnd);
pickShapeDir.set (pickShapeEnd.x - pickShapeStart.x,
pickShapeEnd.y - pickShapeStart.y,
pickShapeEnd.z - pickShapeStart.z);
pickShapeType = PICK_SHAPE_SEGMENT;
} else if (pickShape instanceof PickBounds) {
pickShapeBounds = ((PickBounds) pickShape).get();
if ( pickShapeBounds instanceof BoundingBox )
pickShapeType = PICK_SHAPE_BOUNDING_BOX;
else if( pickShapeBounds instanceof BoundingSphere )
pickShapeType = PICK_SHAPE_BOUNDING_SPHERE;
else if( pickShapeBounds instanceof BoundingPolytope )
pickShapeType = PICK_SHAPE_BOUNDING_POLYTOPE;
} else if(pickShape instanceof PickPoint) {
throw new RuntimeException ("PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance.");
} else if (pickShape instanceof PickCylinder) {
pickShapeType = PICK_SHAPE_CYLINDER;
} else if (pickShape instanceof PickCone) {
pickShapeType = PICK_SHAPE_CONE;
} else {
throw new
RuntimeException("PickShape not supported for intersection");
}
}
/** Get the SceneGraphPath. This will be null if the non SceneGraphPath
* constructor was used.
*/
public SceneGraphPath getSceneGraphPath() {
/* Q: should this return a copy */
return pickedSceneGraphPath;
}
/** Get the localToVworld transform for the Node
*/
public Transform3D getLocalToVworld() {
return localToVWorld;
}
/** Get the GeometryArray at index 0 for the picked node
*/
public GeometryArray getGeometryArray() {
if (geometryArrays == null) {
storeGeometry();
}
return geometryArrays[0];
}
/** Get the array of GeometryArrays for the picked node
*/
public GeometryArray[] getGeometryArrays() {
if (geometryArrays == null) {
storeGeometry();
}
return geometryArrays;
}
/** Get the number of GeometryArrays for the picked node
*/
public int numGeometryArrays() {
if (geometryArrays == null) {
storeGeometry();
}
return geometryArrays.length;
}
/** Get the number of Shape3Ds that came from decompressing a
CompressedGeometry on the picked node.
*/
public int numCompressedGeometryShape3Ds() {
if (geometryArrays == null) {
storeGeometry();
}
if (compressGeomShape3Ds == null) {
return 0;
} else {
return compressGeomShape3Ds.length;
}
}
/** Get the array of Shape3Ds that came from decompressing a
CompressedGeometry on the picked node.
*/
public Shape3D[] getCompressedGeometryShape3Ds() {
if (geometryArrays == null) {
storeGeometry();
}
if (compressGeomShape3Ds == null) {
return null;
} else {
return compressGeomShape3Ds;
}
}
/** Get the PickShape used for intersections
*/
public PickShape getPickShape() {
return pickShape;
}
/** Set the PickResult to find only the first intersection of the PickShape
* with the Node. The default is false
(all intersections are
* found)
*/
public void setFirstIntersectOnly(boolean flag) {
firstIntersectOnly = flag;
}
/** Return the "first intersection only" value. */
public boolean getFirstPickEnable() {
return firstIntersectOnly;
}
/** Returns the number of PickIntersections in the PickResult.
@return the number of intersections
*/
public int numIntersections () {
if (intersections == null) {
generateIntersections();
}
return intersections.size();
}
/** Returns a specific PickIntersection object
@param index the index number
@return the PickIntersection referenced by the index number
*/
public PickIntersection getIntersection (int index) {
if (intersections == null) {
generateIntersections();
}
return (PickIntersection) intersections.get (index);
}
/** Gets the PickIntersection in this PickResult that is closest to a point
@param pt the point to use for distance calculations
@return the closest PickIntersection object
*/
public PickIntersection getClosestIntersection (Point3d pt) {
PickIntersection pi = null;
PickIntersection curPi = null;
Point3d curPt = null;
double minDist = Double.MAX_VALUE;
double curDist = 0.0;
if (pt == null) return null;
if (intersections == null) {
generateIntersections();
}
for (int i=0;i 0) {
for (int i=0;i=0; j--){
Node pNode = pickedSceneGraphPath.getNode(j);
if (debug) System.out.println("looking at node " + pNode);
if ((pNode instanceof Primitive) &&
((flags & PRIMITIVE) != 0)){
if (debug) System.out.println("Primitive found");
return pNode;
}
else if ((pNode instanceof Link) && ((flags & LINK) != 0)){
if (debug) System.out.println("Link found");
return pNode;
}
else if ((pNode instanceof Switch) && ((flags & SWITCH) != 0)){
if (debug) System.out.println("Switch found");
return pNode;
}
else if ((pNode instanceof TransformGroup) &&
((flags & TRANSFORM_GROUP) != 0)){
if (debug) System.out.println("xform group found");
return pNode;
}
else if ((pNode instanceof BranchGroup) &&
((flags & BRANCH_GROUP) != 0)){
if (debug) System.out.println("Branch group found");
return pNode;
}
else if ((pNode instanceof Group) && ((flags & GROUP) != 0)){
if (debug) System.out.println("Group found");
return pNode;
}
}
}
return null; // should not be reached
}
/** Extract the picked node from the SceneGraphPath */
void storeNode () {
if (pickedSceneGraphPath == null) {
throw new RuntimeException ("SceneGraphPath missing");
}
pickedNode = pickedSceneGraphPath.getObject();
}
/** Fill in the intersections of the Node with the PickShape */
boolean generateIntersections() {
if (geometryArrays == null) {
storeGeometry();
}
intersections = new ArrayList();
int hits = 0;
for (int i = 0; i < geometryArrays.length; i++) {
if (intersect(i, firstIntersectOnly)) {
if (firstIntersectOnly) {
return true;
} else {
hits++;
}
}
}
return (hits > 0);
}
/* Takes a GeometryArray object, determines what actual type
* it is (RTTI) and casts it to call the appropriate intersect method.
*/
final boolean intersect(int geomIndex, boolean firstpick) {
int offset;
GeometryArray geom = geometryArrays[geomIndex];
int numPts = geom.getVertexCount();
double[] doubleData = null;
float[] floatData = null;
Point3d[] p3dData = null;
Point3f[] p3fData = null;
int vformat = geom.getVertexFormat();
int stride;
boolean retFlag = false;
if ((vformat & GeometryArray.BY_REFERENCE) == 0) {
doubleData = new double [numPts * 3];
geom.getCoordinates (0, doubleData);
}
else {
if ((vformat & GeometryArray.INTERLEAVED) == 0) {
doubleData = geom.getCoordRefDouble();
// If data was set as float then ..
if (doubleData == null) {
floatData = geom.getCoordRefFloat();
if (floatData == null) {
p3fData = geom.getCoordRef3f();
if (p3fData == null) {
p3dData = geom.getCoordRef3d();
}
}
}
}
else {
floatData = geom.getInterleavedVertices();
}
}
Point3d[] pnts = new Point3d[numPts];
/*
System.out.println("geomIndex : " + geomIndex);
System.out.println("numPts : " + numPts);
System.out.println("firstpick : " + firstpick);
System.out.println("localToVWorld : ");
System.out.println(localToVWorld);
*/
if (debug) {
System.out.println("localToVWorld = " + localToVWorld);
}
if ((vformat & GeometryArray.INTERLEAVED) == 0) {
if (doubleData != null) {
offset = 0;
for (int i=0; i < numPts; i++) {
// Need to transform each pnt by localToVWorld.
pnts[i] = new Point3d();
pnts[i].x = doubleData[offset++];
pnts[i].y = doubleData[offset++];
pnts[i].z = doubleData[offset++];
localToVWorld.transform(pnts[i]);
}
}
else if (floatData != null) { // by reference and float data is defined ..
offset = 0;
for (int i=0; i < numPts; i++) {
// Need to transform each pnt by localToVWorld.
pnts[i] = new Point3d();
pnts[i].x = floatData[offset++];
pnts[i].y = floatData[offset++];
pnts[i].z = floatData[offset++];
localToVWorld.transform(pnts[i]);
}
}
else if (p3fData != null) {
for (int i=0; i < numPts; i++) {
// Need to transform each pnt by localToVWorld.
pnts[i] = new Point3d();
pnts[i].set(p3fData[i]);
localToVWorld.transform(pnts[i]);
}
}
else { // p3dData
for (int i=0; i < numPts; i++) {
// Need to transform each pnt by localToVWorld.
pnts[i] = new Point3d();
pnts[i].set(p3dData[i]);
localToVWorld.transform(pnts[i]);
}
}
}
// Its an interleaved type ..
else {
offset = 0;
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 * geom.getTexCoordSetCount();
}
else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) == GeometryArray.TEXTURE_COORDINATE_3) {
offset += 3 * geom.getTexCoordSetCount();
}
stride = offset + 3; // for the vertices .
for (int i=0; i < numPts; i++) {
// Need to transform each pnt by localToVWorld.
pnts[i] = new Point3d();
pnts[i].x = floatData[offset];
pnts[i].y = floatData[offset+1];
pnts[i].z = floatData[offset+2];
localToVWorld.transform(pnts[i]);
offset += stride;
}
}
PickIntersection pi = new PickIntersection(this, geom);
if (geom instanceof PointArray) {
retFlag = intersectPA ((PointArray)geom, geomIndex, pnts, firstpick, pi);
} else if (geom instanceof IndexedPointArray) {
pi.iGeom = (IndexedGeometryArray) geom;
retFlag = intersectIPA ((IndexedPointArray)geom, geomIndex, pnts,
firstpick, pi);
} else if (geom instanceof LineArray) {
retFlag = intersectLA ((LineArray)geom, geomIndex, pnts, firstpick, pi);
} else if (geom instanceof LineStripArray) {
retFlag = intersectLSA ((LineStripArray)geom, geomIndex, pnts,
firstpick, pi);
} else if (geom instanceof IndexedLineArray) {
pi.iGeom = (IndexedGeometryArray) geom;
retFlag = intersectILA ((IndexedLineArray)geom, geomIndex, pnts,
firstpick, pi);
} else if (geom instanceof IndexedLineStripArray) {
pi.iGeom = (IndexedGeometryArray) geom;
retFlag = intersectILSA ((IndexedLineStripArray)geom, geomIndex, pnts,
firstpick, pi);
} else if (geom instanceof TriangleArray) {
retFlag = intersectTA ((TriangleArray)geom, geomIndex, pnts,
firstpick, pi);
} else if (geom instanceof TriangleStripArray) {
retFlag = intersectTSA ((TriangleStripArray)geom, geomIndex, pnts,
firstpick, pi);
} else if (geom instanceof TriangleFanArray) {
retFlag = intersectTFA ((TriangleFanArray)geom, geomIndex, pnts,
firstpick, pi);
} else if (geom instanceof IndexedTriangleArray) {
pi.iGeom = (IndexedGeometryArray) geom;
retFlag = intersectITA ((IndexedTriangleArray)geom, geomIndex, pnts,
firstpick, pi);
} else if (geom instanceof IndexedTriangleStripArray) {
pi.iGeom = (IndexedGeometryArray) geom;
retFlag = intersectITSA ((IndexedTriangleStripArray)geom, geomIndex,
pnts, firstpick, pi);
} else if (geom instanceof IndexedTriangleFanArray) {
pi.iGeom = (IndexedGeometryArray) geom;
retFlag = intersectITFA ((IndexedTriangleFanArray)geom, geomIndex,
pnts, firstpick, pi);
} else if (geom instanceof QuadArray) {
retFlag = intersectQA ((QuadArray)geom, geomIndex, pnts, firstpick, pi);
} else if (geom instanceof IndexedQuadArray) {
pi.iGeom = (IndexedGeometryArray) geom;
retFlag = intersectIQA ((IndexedQuadArray)geom, geomIndex, pnts,
firstpick, pi);
} else {
throw new RuntimeException ("incorrect class type");
}
return retFlag;
}
/* ==================================================================== */
/* INTERSECT METHODS BY PRIMITIVE TYPE */
/* ==================================================================== */
boolean intersectPoint(int[] vertidx, int[] coordidx, int geomIndex,
Point3d[] pnts, PickIntersection pi) {
// PickIntersection pi = new PickIntersection(this);
Point3d[] point = new Point3d[1];
point[0] = pnts[coordidx[0]];
if (debug) {
System.out.println("intersect point, point = " + point[0]);
}
boolean intersect = false;
switch(pickShapeType) {
case PICK_SHAPE_RAY:
intersect = intersectPntAndRay(point[0], pickShapeStart,
pickShapeDir, pi);
break;
case PICK_SHAPE_SEGMENT:
if (intersectPntAndRay(point[0], pickShapeStart, pickShapeDir, pi)){
if(pi.getDistance() <= 1.0) { // TODO: why 1.0?
intersect = true;
}
}
break;
/* case PICK_SHAPE_POINT:
intersect = intersectPntAndPnt(point[0],
((PickPoint) pickShape).location );
break;
*/
case PICK_SHAPE_BOUNDING_BOX:
intersect = ((BoundingBox)pickShapeBounds).intersect(point[0]);
pi.setPointCoordinatesVW(point[0]);
break;
case PICK_SHAPE_BOUNDING_SPHERE:
intersect = ((BoundingSphere)pickShapeBounds).intersect(point[0]);
pi.setPointCoordinatesVW(point[0]);
break;
case PICK_SHAPE_BOUNDING_POLYTOPE:
intersect = ((BoundingPolytope)pickShapeBounds).intersect(point[0]);
pi.setPointCoordinatesVW(point[0]);
break;
case PICK_SHAPE_CYLINDER:
intersect = intersectCylinder(point[0], (PickCylinder)pickShape,pi);
break;
case PICK_SHAPE_CONE:
intersect = intersectCone (point[0], (PickCone)pickShape, pi);
break;
}
if (intersect) {
PickIntersection newpi = new PickIntersection(this, pi.geom);
newpi.iGeom = pi.iGeom;
newpi.setDistance(pi.distance);
newpi.setPointCoordinatesVW(pi.getPointCoordinatesVW());
// Set PickIntersection parameters
newpi.setGeomIndex(geomIndex);
newpi.setVertexIndices (vertidx);
newpi.setPrimitiveCoordinatesVW(point);
intersections.add (newpi);
return true;
}
return false;
}
boolean intersectLine(int[] vertidx, int[] coordidx, int geomIndex,
Point3d[] pnts, PickIntersection pi) {
Point3d[] linePts = new Point3d[2];
linePts[0] = pnts[coordidx[0]];
linePts[1] = pnts[coordidx[1]];
boolean intersect = false;
switch(pickShapeType) {
case PICK_SHAPE_RAY:
intersect = intersectLineAndRay(linePts[0], linePts[1],
pickShapeStart, pickShapeDir, pi);
break;
case PICK_SHAPE_SEGMENT:
if (intersectLineAndRay(linePts[0], linePts[1], pickShapeStart,
pickShapeDir, pi)) {
if (pi.getDistance() <= 1.0) {
intersect = true;
}
}
break;
/* case PICK_SHAPE_POINT:
dir.x = linePts[1].x - linePts[0].x;
dir.y = linePts[1].y - linePts[0].y;
dir.z = linePts[1].z - linePts[0].z;
if (intersectPntAndRay(((PickPoint)pickShape).location,
pnts[0], dir, dist)) {
if(dist[0] <= 1.0) {
intersect = true;
}
}
break;
*/
case PICK_SHAPE_BOUNDING_BOX:
intersect = intersectBoundingBox(linePts,
(BoundingBox)pickShapeBounds);
pi.setPointCoordinatesVW(zeroPnt);
break;
case PICK_SHAPE_BOUNDING_SPHERE:
intersect = intersectBoundingSphere(linePts,
(BoundingSphere)pickShapeBounds);
pi.setPointCoordinatesVW(zeroPnt);
break;
case PICK_SHAPE_BOUNDING_POLYTOPE:
intersect = intersectBoundingPolytope(linePts,
(BoundingPolytope)pickShapeBounds);
pi.setPointCoordinatesVW(zeroPnt);
break;
case PICK_SHAPE_CYLINDER:
intersect = intersectCylinder (linePts, (PickCylinder)pickShape,pi);
break;
case PICK_SHAPE_CONE:
intersect = intersectCone (linePts, (PickCone) pickShape, pi);
break;
}
if (intersect) {
PickIntersection newpi = new PickIntersection(this, pi.geom);
newpi.iGeom = pi.iGeom;
newpi.setDistance(pi.distance);
newpi.setPointCoordinatesVW(pi.getPointCoordinatesVW());
// Set PickIntersection parameters
newpi.setGeomIndex(geomIndex);
newpi.setVertexIndices (vertidx);
newpi.setPrimitiveCoordinatesVW(linePts);
intersections.add (newpi);
return true;
}
return false;
}
boolean intersectTri(int[] vertidx, int[] coordidx, int geomIndex,
Point3d[] pnts, PickIntersection pi) {
Point3d[] triPts = new Point3d[3];
triPts[0] = pnts[coordidx[0]];
triPts[1] = pnts[coordidx[1]];
triPts[2] = pnts[coordidx[2]];
boolean intersect = false;
switch(pickShapeType) {
case PICK_SHAPE_RAY:
intersect = intersectRay(triPts, (PickRay) pickShape, pi);
break;
case PICK_SHAPE_SEGMENT:
intersect = intersectSegment(triPts, (PickSegment) pickShape, pi);
break;
/* case PICK_SHAPE_POINT:
if(inside(triPts, (PickPoint) pickShape, ccw)==false)
return false;
break;
*/
case PICK_SHAPE_BOUNDING_BOX:
intersect = intersectBoundingBox (triPts,
(BoundingBox)pickShapeBounds);
pi.setPointCoordinatesVW(zeroPnt);
break;
case PICK_SHAPE_BOUNDING_SPHERE:
intersect = intersectBoundingSphere (triPts,
(BoundingSphere)pickShapeBounds);
pi.setPointCoordinatesVW(zeroPnt);
break;
case PICK_SHAPE_BOUNDING_POLYTOPE:
intersect = intersectBoundingPolytope (triPts,
(BoundingPolytope)pickShapeBounds);
pi.setPointCoordinatesVW(zeroPnt);
break;
case PICK_SHAPE_CYLINDER:
intersect = intersectCylinder (triPts, (PickCylinder) pickShape,pi);
break;
case PICK_SHAPE_CONE:
intersect = intersectCone (triPts, (PickCone)pickShape, pi);
break;
}
if (intersect) {
PickIntersection newpi = new PickIntersection(this, pi.geom);
newpi.iGeom = pi.iGeom;
newpi.setDistance(pi.distance);
newpi.setPointCoordinatesVW(pi.getPointCoordinatesVW());
// Set PickIntersection parameters
newpi.setGeomIndex(geomIndex);
newpi.setVertexIndices (vertidx);
newpi.setPrimitiveCoordinatesVW(triPts);
intersections.add (newpi);
return true;
}
return false;
}
boolean intersectQuad(int[] vertidx, int[] coordidx, int geomIndex,
Point3d[] pnts, PickIntersection pi) {
Point3d[] quadPts = new Point3d[4];
quadPts[0] = pnts[coordidx[0]];
quadPts[1] = pnts[coordidx[1]];
quadPts[2] = pnts[coordidx[2]];
quadPts[3] = pnts[coordidx[3]];
// PickIntersection pi = new PickIntersection(this);
boolean intersect = false;
switch(pickShapeType) {
case PICK_SHAPE_RAY:
intersect = intersectRay(quadPts, (PickRay) pickShape, pi);
break;
case PICK_SHAPE_SEGMENT:
intersect = intersectSegment(quadPts, (PickSegment) pickShape, pi);
break;
/* case PICK_SHAPE_POINT:
if(inside(quadPts, (PickPoint) pickShape, ccw)==false)
return false;
break;
*/
case PICK_SHAPE_BOUNDING_BOX:
intersect = intersectBoundingBox (quadPts,
(BoundingBox)pickShapeBounds);
pi.setPointCoordinatesVW(zeroPnt);
break;
case PICK_SHAPE_BOUNDING_SPHERE:
intersect = intersectBoundingSphere (quadPts,
(BoundingSphere)pickShapeBounds);
pi.setPointCoordinatesVW(zeroPnt);
break;
case PICK_SHAPE_BOUNDING_POLYTOPE:
intersect = intersectBoundingPolytope (quadPts,
(BoundingPolytope)pickShapeBounds);
pi.setPointCoordinatesVW(zeroPnt);
break;
case PICK_SHAPE_CYLINDER:
intersect = intersectCylinder (quadPts, (PickCylinder)pickShape,pi);
break;
case PICK_SHAPE_CONE:
intersect = intersectCone (quadPts, (PickCone)pickShape, pi);
break;
}
if (intersect) {
PickIntersection newpi = new PickIntersection(this, pi.geom);
newpi.iGeom = pi.iGeom;
newpi.setDistance(pi.distance);
newpi.setPointCoordinatesVW(pi.getPointCoordinatesVW());
// Set PickIntersection parameters
newpi.setGeomIndex(geomIndex);
newpi.setVertexIndices (vertidx);
newpi.setPrimitiveCoordinatesVW(quadPts);
intersections.add (newpi);
return true;
}
return false;
}
/* ==================================================================== */
/* INTERSECT METHODS BY GEOMETRY TYPE */
/* ==================================================================== */
/**
Intersect method for PointArray
*/
boolean intersectPA (PointArray geom, int geomIndex, Point3d[] pnts,
boolean firstpick, PickIntersection pi) {
if (debug) System.out.println ("intersect: PointArray");
int[] pntVertIdx = new int[1];
int numint = 0;
for (int i = 0; i < pnts.length; i++) {
pntVertIdx[0] = i;
if (intersectPoint(pntVertIdx, pntVertIdx, geomIndex, pnts, pi)) {
numint++;
if (firstpick) return true;
}
}
if (numint > 0) return true;
return false;
}
/**
Intersect method for IndexedPointArray
*/
boolean intersectIPA (IndexedPointArray geom, int geomIndex, Point3d[] pnts,
boolean firstpick, PickIntersection pi) {
if (debug) System.out.println ("intersect: IndexedPointArray");
int[] pntVertIdx = new int[1];
int[] pntCoordIdx = new int[1];
int numint = 0;
int indexCount = geom.getIndexCount();
for (int i=0; i< indexCount; i++) {
pntVertIdx[0] = i;
pntCoordIdx[0] = geom.getCoordinateIndex(i);
if (intersectPoint(pntVertIdx, pntCoordIdx, geomIndex, pnts, pi)) {
numint++;
if (firstpick) return true;
}
}
if (numint > 0) return true;
return false;
}
/**
Intersect method for LineArray
*/
/**
Intersect method for LineArray
*/
boolean intersectLA (LineArray geom, int geomIndex, Point3d[] pnts,
boolean firstpick, PickIntersection pi) {
if (debug) System.out.println ("intersect: LineArray");
int[] lineVertIdx = new int[2];
int numint = 0;
for (int i=0; i< pnts.length;) {
/* set up the parameters for the current line */
lineVertIdx[0] = i++;
lineVertIdx[1] = i++;
if (intersectLine(lineVertIdx, lineVertIdx, geomIndex, pnts, pi)) {
numint++;
if (firstpick) return true;
}
}
if (numint > 0) return true;
return false;
}
/**
Intersect method for LineStripArray
*/
boolean intersectLSA (LineStripArray geom, int geomIndex, Point3d[] pnts,
boolean firstpick, PickIntersection pi) {
int numint = 0;
int[] stripVertexCounts = new int [geom.getNumStrips()];
geom.getStripVertexCounts (stripVertexCounts);
int stripStart = 0;
if (debug) System.out.println ("intersect: LineStripArray");
int[] lineVertIdx = new int[2];
for (int i=0; i < stripVertexCounts.length; i++) {
lineVertIdx[0] = stripStart;
int end = stripStart + stripVertexCounts[i];
for (int j=stripStart+1; j 0) return true;
return false;
}
/**
Intersect method for IndexedLineArray
*/
boolean intersectILA (IndexedLineArray geom, int geomIndex, Point3d[] pnts,
boolean firstpick, PickIntersection pi) {
int numint = 0;
int indexCount = geom.getIndexCount();
if (debug) System.out.println ("intersect: IndexedLineArray");
int[] lineVertIdx = new int[2];
int[] lineCoordIdx = new int[2];
for (int i=0; i 0) return true;
return false;
}
/**
Intersect method for IndexedLineStripArray
*/
boolean intersectILSA (IndexedLineStripArray geom, int geomIndex,
Point3d[] pnts, boolean firstpick, PickIntersection pi) {
if (debug) System.out.println ("intersect: IndexedLineStripArray");
int[] lineVertIdx = new int[2];
int[] lineCoordIdx = new int[2];
int numint = 0;
int[] stripVertexCounts = new int [geom.getNumStrips()];
geom.getStripIndexCounts (stripVertexCounts);
int stripStart = 0;
for (int i=0; i < stripVertexCounts.length; i++) {
lineVertIdx[0] = stripStart;
lineCoordIdx[0] = geom.getCoordinateIndex(stripStart);
int end = stripStart + stripVertexCounts[i];
for (int j=stripStart+1; j 0) return true;
return false;
}
/**
Intersect method for TriangleArray
*/
boolean intersectTA (TriangleArray geom, int geomIndex, Point3d[] pnts,
boolean firstpick, PickIntersection pi) {
if (debug)
System.out.println ("intersect: TriangleArray");
int[] triVertIdx = new int[3];
int numint = 0;
for (int i=0; i 0) return true;
return false;
}
/**
Intersect method for IndexedTriangleArray
*/
boolean intersectITA (IndexedTriangleArray geom, int geomIndex,
Point3d[] pnts, boolean firstpick, PickIntersection pi) {
if (debug)
System.out.println ("intersect: IndexedTriangleArray");
int[] triVertIdx = new int[3];
int[] triCoordIdx = new int[3];
int numint = 0;
int indexCount = geom.getIndexCount();
for (int i=0; i 0) return true;
return false;
}
/**
Intersect method for TriangleStripArray
*/
boolean intersectTSA (TriangleStripArray geom, int geomIndex,
Point3d[] pnts, boolean firstpick, PickIntersection pi) {
if (debug)
System.out.println ("intersect: TriangleStripArray");
boolean ccw;
int numint = 0;
int[] stripVertexCounts = new int [geom.getNumStrips()];
geom.getStripVertexCounts (stripVertexCounts);
int stripStart = 0;
int start;
int[] triVertIdx = new int[3];
for (int i=0; i 0) return true;
return false;
}
/**
Intersect method for IndexedTriangleStripArray
*/
boolean intersectITSA (IndexedTriangleStripArray geom, int geomIndex,
Point3d[] pnts, boolean firstpick, PickIntersection pi) {
if (debug)
System.out.println ("intersect: IndexedTriangleStripArray");
int numint = 0;
boolean ccw;
int[] stripVertexCounts = new int [geom.getNumStrips()];
geom.getStripIndexCounts (stripVertexCounts);
int stripStart = 0;
int start;
int[] triVertIdx = new int[3];
int[] triCoordIdx = new int[3];
for (int i=0; i 0) return true;
return false;
}
/**
Intersect method for TriangleFanArray
*/
boolean intersectTFA (TriangleFanArray geom, int geomIndex, Point3d[] pnts,
boolean firstpick, PickIntersection pi) {
if (debug) System.out.println("intersect: TriangleFanArray");
int numint = 0;
int[] stripVertexCounts = new int [geom.getNumStrips()];
geom.getStripVertexCounts (stripVertexCounts);
int fanStart = 0;
int start;
int[] triVertIdx = new int[3];
// System.out.println("stripVertexCounts.length " + stripVertexCounts.length);
for (int i=0; i 0) return true;
return false;
}
/**
Intersect method for IndexedTriangleFanArray
*/
boolean intersectITFA (IndexedTriangleFanArray geom, int geomIndex,
Point3d[] pnts, boolean firstpick, PickIntersection pi) {
if (debug) System.out.println ("intersect: IndexedTriangleFanArray");
int numint = 0;
int[] stripVertexCounts = new int [geom.getNumStrips()];
geom.getStripIndexCounts (stripVertexCounts);
int fanStart = 0;
int start;
int[] triVertIdx = new int[3];
int[] triCoordIdx = new int[3];
for (int i=0; i 0) return true;
return false;
}
/**
Intersect method for QuadArray
*/
boolean intersectQA (QuadArray geom, int geomIndex, Point3d[] pnts,
boolean firstpick, PickIntersection pi) {
if (debug) System.out.println ("intersect: QuadArray");
int[] quadVertIdx = new int[4];
int numint = 0;
for (int i=0; i 0) return true;
return false;
}
/**
Intersect method for IndexedQuadArray
*/
final boolean intersectIQA (IndexedQuadArray geom, int geomIndex,
Point3d[] pnts, boolean firstpick,
PickIntersection pi) {
if (debug) System.out.println ("intersect: IndexedQuadArray");
int[] quadVertIdx = new int[4];
int[] quadCoordIdx = new int[4];
int numint = 0;
int indexCount = geom.getIndexCount();
// System.out.println ("intersect: IndexedQuadArray : indexCount " + indexCount);
for (int i=0; i 0) return true;
return false;
}
/* ==================================================================== */
/* GENERAL INTERSECT METHODS */
/* ==================================================================== */
static boolean intersectBoundingBox (Point3d coordinates[],
BoundingBox box) {
int i, j;
int out[] = new int[6];
Point3d lower = new Point3d();
Point3d upper = new Point3d();
box.getLower (lower);
box.getUpper (upper);
//Do trivial vertex test.
for (i=0; i<6; i++) out[i] = 0;
for (i=0; i= lower.x) &&
(coordinates[i].x <= upper.x) &&
(coordinates[i].y >= lower.y) &&
(coordinates[i].y <= upper.y) &&
(coordinates[i].z >= lower.z) &&
(coordinates[i].z <= upper.z)) {
// We're done! It's inside the boundingbox.
return true;
} else {
if (coordinates[i].x < lower.x) out[0]++; // left
if (coordinates[i].y < lower.y) out[1]++; // bottom
if (coordinates[i].z < lower.z) out[2]++; // back
if (coordinates[i].x > upper.x) out[3]++; // right
if (coordinates[i].y > upper.y) out[4]++; // top
if (coordinates[i].z > upper.z) out[5]++; // front
}
}
if ((out[0] == coordinates.length) || (out[1] == coordinates.length) ||
(out[2] == coordinates.length) || (out[3] == coordinates.length) ||
(out[4] == coordinates.length) || (out[5] == coordinates.length)){
// we're done. primitive is outside of boundingbox.
return false;
}
// Setup bounding planes.
Point3d pCoor[] = new Point3d[4];
for (i=0; i<4; i++) pCoor[i] = new Point3d();
// left plane.
pCoor[0].set(lower.x, lower.y, lower.z);
pCoor[1].set(lower.x, lower.y, upper.z);
pCoor[2].set(lower.x, upper.y, upper.z);
pCoor[3].set(lower.x, upper.y, lower.z);
if (intersectPolygon(pCoor, coordinates, false) == true) return true;
// right plane.
pCoor[0].set(upper.x, lower.y, lower.z);
pCoor[1].set(upper.x, upper.y, lower.z);
pCoor[2].set(upper.x, upper.y, upper.z);
pCoor[3].set(upper.x, lower.y, upper.z);
if (intersectPolygon(pCoor, coordinates, false) == true) return true;
// bottom plane.
pCoor[0].set(upper.x, lower.y, upper.z);
pCoor[1].set(lower.x, lower.y, upper.z);
pCoor[2].set(lower.x, lower.y, lower.z);
pCoor[3].set(upper.x, lower.y, lower.z);
if (intersectPolygon(pCoor, coordinates, false) == true) return true;
// top plane.
pCoor[0].set(upper.x, upper.y, upper.z);
pCoor[1].set(upper.x, upper.y, lower.z);
pCoor[2].set(lower.x, upper.y, lower.z);
pCoor[3].set(lower.x, upper.y, upper.z);
if (intersectPolygon(pCoor, coordinates, false) == true) return true;
// front plane.
pCoor[0].set(upper.x, upper.y, upper.z);
pCoor[1].set(lower.x, upper.y, upper.z);
pCoor[2].set(lower.x, lower.y, upper.z);
pCoor[3].set(upper.x, lower.y, upper.z);
if (intersectPolygon(pCoor, coordinates, false) == true) return true;
// back plane.
pCoor[0].set(upper.x, upper.y, lower.z);
pCoor[1].set(upper.x, lower.y, lower.z);
pCoor[2].set(lower.x, lower.y, lower.z);
pCoor[3].set(lower.x, upper.y, lower.z);
if (intersectPolygon(pCoor, coordinates, false) == true) return true;
return false;
}
static boolean intersectBoundingSphere (Point3d coordinates[],
BoundingSphere sphere) {
int i, j;
Vector3d tempV3D = new Vector3d();
boolean esFlag;
Point3d center = new Point3d();
sphere.getCenter (center);
double radius = sphere.getRadius ();
//Do trivial vertex test.
for (i=0; i 0.0) break;
}
for (j=i; j 0.0) break;
}
if (j == (coordinates.length-1)) {
// System.out.println("(1) Degenerated polygon.");
return false; // Degenerated polygon.
}
/*
for (i=0; i radius)
return false;
tq = pNrmDotPa / nLenSq;
q.x = center.x + tq * pNrm.x;
q.y = center.y + tq * pNrm.y;
q.z = center.z + tq * pNrm.z;
// PolyPnt2D Test.
return pointIntersectPolygon2D( pNrm, coordinates, q);
}
static boolean intersectBoundingPolytope (Point3d coordinates[],
BoundingPolytope polytope) {
boolean debug = false;
// this is a multiplier to the halfplane distance coefficients
double distanceSign = -1.0;
// Variable needed for intersection.
Point4d tP4d = new Point4d();
Vector4d[] planes = new Vector4d [polytope.getNumPlanes()];
for(int i=0; i absNrmY)
axis = 0;
else
axis = 1;
if (axis == 0) {
if (absNrmX < absNrmZ)
axis = 2;
}
else if (axis == 1) {
if (absNrmY < absNrmZ)
axis = 2;
}
// System.out.println("Normal " + normal + " axis " + axis );
for (i=0; i0.0)
;
else
return false;
else
if (det2D(coord2D[j], coord2D[0], pnt)>0.0)
;
else
return false;
}
return true;
}
static boolean edgeIntersectPlane(Vector3d normal, Point3d pnt,
Point3d start, Point3d end, Point3d iPnt){
Vector3d tempV3d = new Vector3d();
Vector3d direction = new Vector3d();
double pD, pNrmDotrDir, tr;
// Compute plane D.
tempV3d.set((Tuple3d) pnt);
pD = normal.dot(tempV3d);
direction.x = end.x - start.x;
direction.y = end.y - start.y;
direction.z = end.z - start.z;
pNrmDotrDir = normal.dot(direction);
// edge is parallel to plane.
if (pNrmDotrDir== 0.0) {
// System.out.println("Edge is parallel to plane.");
return false;
}
tempV3d.set((Tuple3d) start);
tr = (pD - normal.dot(tempV3d))/ pNrmDotrDir;
// Edge intersects the plane behind the edge's start.
// or exceed the edge's length.
if ((tr < 0.0 ) || (tr > 1.0 )) {
// System.out.println("Edge intersects the plane behind the start or exceed end.");
return false;
}
iPnt.x = start.x + tr * direction.x;
iPnt.y = start.y + tr * direction.y;
iPnt.z = start.z + tr * direction.z;
return true;
}
// Assume coord is CCW.
static boolean edgeIntersectPolygon2D(Vector3d normal, Point3d[] coord,
Point3d[] seg) {
double absNrmX, absNrmY, absNrmZ;
Point2d coord2D[] = new Point2d[coord.length];
Point2d seg2D[] = new Point2d[2];
int i, j, axis;
// Project 3d points onto 2d plane.
// Note : Area of polygon is not preserve in this projection, but
// it doesn't matter here.
// Find the axis of projection.
absNrmX = Math.abs(normal.x);
absNrmY = Math.abs(normal.y);
absNrmZ = Math.abs(normal.z);
if (absNrmX > absNrmY)
axis = 0;
else
axis = 1;
if (axis == 0) {
if (absNrmX < absNrmZ)
axis = 2;
}
else if (axis == 1) {
if (absNrmY < absNrmZ)
axis = 2;
}
// System.out.println("Normal " + normal + " axis " + axis );
for (i=0; i 0.0)
break;
}
for (j=i; j 0.0)
break;
}
if (j == (coord1.length-1)) {
// System.out.println("(1) Degenerated polygon.");
return false; // Degenerated polygon.
}
/*
for (i=0; i1)
break;
}
}
if (j==0)
return false;
if (coord2.length < 3)
return pointIntersectPolygon2D(pNrm, coord1, seg[0]);
return edgeIntersectPolygon2D(pNrm, coord1, seg);
}
static final boolean isNonZero(double v) {
return ((v > EPS) || (v < -EPS));
}
static boolean intersectRay(Point3d coordinates[],
PickRay ray, PickIntersection pi) {
Point3d origin = new Point3d();
Vector3d direction = new Vector3d();
boolean result;
ray.get (origin, direction);
result = intersectRayOrSegment(coordinates, direction, origin, pi, false);
return result;
}
/**
* Return true if triangle or quad intersects with ray and the distance is
* stored in pr.
* */
static boolean intersectRayOrSegment(Point3d coordinates[],
Vector3d direction, Point3d origin,
PickIntersection pi, boolean isSegment) {
Vector3d vec0, vec1, pNrm, tempV3d;
Point3d iPnt;
vec0 = new Vector3d();
vec1 = new Vector3d();
pNrm = new Vector3d();
double absNrmX, absNrmY, absNrmZ, pD = 0.0;
double pNrmDotrDir = 0.0;
boolean isIntersect = false;
int i, j, k=0, l = 0;
// Compute plane normal.
for (i=0; i 0.0) {
break;
}
}
for (j=l; j 0.0) {
break;
}
}
pNrm.cross(vec0,vec1);
if ((vec1.length() == 0) || (pNrm.length() == 0)) {
// degenerated to line if vec0.length() == 0
// or vec0.length > 0 and vec0 parallel to vec1
k = (l == 0 ? coordinates.length-1: l-1);
isIntersect = intersectLineAndRay(coordinates[l],
coordinates[k],
origin,
direction,
pi);
return isIntersect;
}
// It is possible that Quad is degenerate to Triangle
// at this point
pNrmDotrDir = pNrm.dot(direction);
// Ray is parallel to plane.
if (pNrmDotrDir == 0.0) {
// Ray is parallel to plane
// Check line/triangle intersection on plane.
for (i=0; i < coordinates.length ;i++) {
if (i != coordinates.length-1) {
k = i+1;
} else {
k = 0;
}
if (intersectLineAndRay(coordinates[i],
coordinates[k],
origin,
direction,
pi)) {
isIntersect = true;
break;
}
}
return isIntersect;
}
// Plane equation: (p - p0)*pNrm = 0 or p*pNrm = pD;
tempV3d = new Vector3d();
tempV3d.set((Tuple3d) coordinates[0]);
pD = pNrm.dot(tempV3d);
tempV3d.set((Tuple3d) origin);
// Substitute Ray equation:
// p = origin + pi.distance*direction
// into the above Plane equation
double dist = (pD - pNrm.dot(tempV3d))/ pNrmDotrDir;
// Ray intersects the plane behind the ray's origin.
if ((dist < -EPS ) ||
(isSegment && (dist > 1.0+EPS))) {
// Ray intersects the plane behind the ray's origin
// or intersect point not fall in Segment
return false;
}
// Now, one thing for sure the ray intersect the plane.
// Find the intersection point.
iPnt = new Point3d();
iPnt.x = origin.x + direction.x * dist;
iPnt.y = origin.y + direction.y * dist;
iPnt.z = origin.z + direction.z * dist;
// Project 3d points onto 2d plane.
// Find the axis so that area of projection is maximize.
absNrmX = Math.abs(pNrm.x);
absNrmY = Math.abs(pNrm.y);
absNrmZ = Math.abs(pNrm.z);
// Check out
// http://astronomy.swin.edu.au/~pbourke/geometry/insidepoly/
// Solution 3:
// All sign of (y - y0) (x1 - x0) - (x - x0) (y1 - y0)
// must agree.
double sign, t, lastSign = 0;
Point3d p0 = coordinates[coordinates.length-1];
Point3d p1 = coordinates[0];
isIntersect = true;
if (absNrmX > absNrmY) {
if (absNrmX < absNrmZ) {
for (i=0; i < coordinates.length; i++) {
p0 = coordinates[i];
p1 = (i != coordinates.length-1 ? coordinates[i+1]: coordinates[0]);
sign = (iPnt.y - p0.y)*(p1.x - p0.x) -
(iPnt.x - p0.x)*(p1.y - p0.y);
if (isNonZero(sign)) {
if (sign*lastSign < 0) {
isIntersect = false;
break;
}
lastSign = sign;
} else { // point on line, check inside interval
t = p1.y - p0.y;
if (isNonZero(t)) {
t = (iPnt.y - p0.y)/t;
isIntersect = ((t > -EPS) && (t < 1+EPS));
break;
} else {
t = p1.x - p0.x;
if (isNonZero(t)) {
t = (iPnt.x - p0.x)/t;
isIntersect = ((t > -EPS) && (t < 1+EPS));
break;
} else {
//degenerate line=>point
}
}
}
}
} else {
for (i=0; i -EPS) && (t < 1+EPS));
break;
} else {
t = p1.z - p0.z;
if (isNonZero(t)) {
t = (iPnt.z - p0.z)/t;
isIntersect = ((t > -EPS) && (t < 1+EPS));
break;
} else {
//degenerate line=>point
}
}
}
}
}
} else {
if (absNrmY < absNrmZ) {
for (i=0; i -EPS) && (t < 1+EPS));
break;
} else {
t = p1.x - p0.x;
if (isNonZero(t)) {
t = (iPnt.x - p0.x)/t;
isIntersect = ((t > -EPS) && (t < 1+EPS));
break;
} else {
//degenerate line=>point
}
}
}
}
} else {
for (i=0; i -EPS) && (t < 1+EPS));
break;
} else {
t = p1.z - p0.z;
if (isNonZero(t)) {
t = (iPnt.z - p0.z)/t;
isIntersect = ((t > -EPS) && (t < 1+EPS));
break;
} else {
//degenerate line=>point
}
}
}
}
}
}
if (isIntersect) {
pi.setDistance(dist*direction.length());
pi.setPointCoordinatesVW(iPnt);
}
return isIntersect;
}
/**
Return true if triangle or quad intersects with segment and the distance is
stored in dist.
*/
static boolean intersectSegment (Point3d coordinates[], PickSegment segment,
PickIntersection pi) {
Point3d start = new Point3d();
Point3d end = new Point3d();
Vector3d direction = new Vector3d();
boolean result;
segment.get(start, end);
direction.x = end.x - start.x;
direction.y = end.y - start.y;
direction.z = end.z - start.z;
result = intersectRayOrSegment(coordinates, direction, start, pi, true);
return result;
}
/**
Return true if point is on the inside of halfspace test. The halfspace is
partition by the plane of triangle or quad.
*/
static boolean inside (Point3d coordinates[], PickPoint point, int ccw) {
Vector3d vec0 = new Vector3d(); //Edge vector from point 0 to point 1;
Vector3d vec1 = new Vector3d(); //Edge vector from point 0 to point 2 or 3;
Vector3d pNrm = new Vector3d();
double absNrmX, absNrmY, absNrmZ, pD = 0.0;
Vector3d tempV3d = new Vector3d();
double pNrmDotrDir = 0.0;
double tempD;
int i, j;
Point3d location = new Point3d ();
point.get (location);
// Compute plane normal.
for (i=0; i 0.0)
break;
}
for (j=i; j 0.0)
break;
}
if (j == (coordinates.length-1)) {
// System.out.println("(1) Degenerated polygon.");
return false; // Degenerated polygon.
}
/*
System.out.println("Ray orgin : " + origin + " dir " + direction);
System.out.println("Triangle/Quad :");
for (i=0; i 0.0 ) {
// System.out.println("point is on the outside of plane.");
return false;
}
else
return true;
}
static boolean intersectPntAndPnt (Point3d pnt1, Point3d pnt2,
PickIntersection pi) {
if ((pnt1.x == pnt2.x) && (pnt1.y == pnt2.y) && (pnt1.z == pnt2.z)) {
pi.setPointCoordinatesVW (pnt1);
pi.setDistance (0.0);
return true;
}
else
return false;
}
static boolean intersectPntAndRay (Point3d pnt, Point3d ori, Vector3d dir,
PickIntersection pi) {
int flag = 0;
double temp;
double dist;
if (dir.x != 0.0) {
flag = 0;
dist = (pnt.x - ori.x)/dir.x;
}
else if (dir.y != 0.0) {
if (pnt.x != ori.x)
return false;
flag = 1;
dist = (pnt.y - ori.y)/dir.y;
}
else if (dir.z != 0.0) {
if ((pnt.x != ori.x)||(pnt.y != ori.y))
return false;
flag = 2;
dist = (pnt.z - ori.z)/dir.z;
}
else
return false;
if (dist < 0.0)
return false;
if (flag == 0) {
temp = ori.y + dist * dir.y;
if ((pnt.y < (temp - Double.MIN_VALUE)) || (pnt.y > (temp + Double.MIN_VALUE)))
return false;
}
if (flag < 2) {
temp = ori.z + dist * dir.z;
if ((pnt.z < (temp - Double.MIN_VALUE)) || (pnt.z > (temp + Double.MIN_VALUE)))
return false;
}
pi.setPointCoordinatesVW (pnt);
pi.setDistance (dist);
return true;
}
static boolean intersectLineAndRay(Point3d start, Point3d end,
Point3d ori, Vector3d dir,
PickIntersection pi) {
double m00, m01, m10, m11;
double mInv00, mInv01, mInv10, mInv11;
double dmt, t, s, tmp1, tmp2;
Vector3d lDir;
double dist;
// System.out.println("Intersect : intersectLineAndRay");
// System.out.println("start " + start + " end " + end );
// System.out.println("ori " + ori + " dir " + dir);
lDir = new Vector3d(end.x - start.x, end.y - start.y,
end.z - start.z);
m00 = lDir.x;
m01 = -dir.x;
m10 = lDir.y;
m11 = -dir.y;
// Get the determinant.
dmt = (m00 * m11) - (m10 * m01);
if (dmt==0.0) { // No solution, hence no intersect.
// System.out.println("dmt is zero");
boolean isIntersect = false;
if ((lDir.x == 0) && (lDir.y == 0) && (lDir.z == 0)) {
isIntersect = intersectPntAndRay(start, ori, dir, pi);
if (isIntersect) {
pi.setPointCoordinatesVW(start);
pi.setDistance(0);
}
}
return isIntersect;
}
// Find the inverse.
tmp1 = 1/dmt;
mInv00 = tmp1 * m11;
mInv01 = tmp1 * (-m01);
mInv10 = tmp1 * (-m10);
mInv11 = tmp1 * m00;
tmp1 = ori.x - start.x;
tmp2 = ori.y - start.y;
t = mInv00 * tmp1 + mInv01 * tmp2;
s = mInv10 * tmp1 + mInv11 * tmp2;
if (s<0.0) { // Before the origin of ray.
// System.out.println("Before the origin of ray " + s);
return false;
}
if ((t<0)||(t>1.0)) {// Before or after the end points of line.
// System.out.println("Before or after the end points of line. " + t);
return false;
}
tmp1 = ori.z + s * dir.z;
tmp2 = start.z + t * lDir.z;
if ((tmp1 < (tmp2 - Double.MIN_VALUE)) ||
(tmp1 > (tmp2 + Double.MIN_VALUE))) {
// System.out.println("No intersection : tmp1 " + tmp1 + " tmp2 " + tmp2);
return false;
}
dist = s;
pi.setDistance (dist);
Point3d iPnt = new Point3d ();
iPnt.scaleAdd (s, dir, ori);
pi.setPointCoordinatesVW (iPnt);
// System.out.println("Intersected : tmp1 " + tmp1 + " tmp2 " + tmp2);
return true;
}
/**
Return true if triangle or quad intersects with cylinder and the
distance is stored in pr.
*/
static boolean intersectCylinder (Point3d coordinates[],
PickCylinder cyl, PickIntersection pi) {
Point3d origin = new Point3d();
Point3d end = new Point3d();
Vector3d direction = new Vector3d();
Point3d iPnt1 = new Point3d();
Point3d iPnt2 = new Point3d();
Vector3d originToIpnt = new Vector3d();
// Get cylinder information
cyl.getOrigin (origin);
cyl.getDirection (direction);
double radius = cyl.getRadius ();
if (cyl instanceof PickCylinderSegment) {
((PickCylinderSegment)cyl).getEnd (end);
}
// If the ray intersects, we're good (do not do this if we only have
// a segment
if (coordinates.length > 2) {
if (cyl instanceof PickCylinderRay) {
if (intersectRay (coordinates, new PickRay (origin, direction), pi)) {
return true;
}
}
else {
if (intersectSegment (coordinates, new PickSegment (origin, end), pi)) {
return true;
}
}
}
// Ray doesn't intersect, check distance to edges
double sqDistToEdge;
for (int i=0; i 2) {
if (cone instanceof PickConeRay) {
if (intersectRay (coordinates, new PickRay (origin, direction), pi)) {
return true;
}
}
else {
if (intersectSegment (coordinates, new PickSegment (origin, end),
pi)) {
return true;
}
}
}
// Ray doesn't intersect, check distance to edges
double sqDistToEdge;
for (int i=0; i