org.scijava.java3d.utils.pickfast.PickTool 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.pickfast;
import org.scijava.java3d.Bounds;
import org.scijava.java3d.BranchGroup;
import org.scijava.java3d.Group;
import org.scijava.java3d.Link;
import org.scijava.java3d.Locale;
import org.scijava.java3d.Morph;
import org.scijava.java3d.Node;
import org.scijava.java3d.PickBounds;
import org.scijava.java3d.PickConeRay;
import org.scijava.java3d.PickConeSegment;
import org.scijava.java3d.PickCylinderRay;
import org.scijava.java3d.PickCylinderSegment;
import org.scijava.java3d.PickInfo;
import org.scijava.java3d.PickRay;
import org.scijava.java3d.PickSegment;
import org.scijava.java3d.PickShape;
import org.scijava.java3d.SceneGraphPath;
import org.scijava.java3d.Shape3D;
import org.scijava.java3d.Switch;
import org.scijava.java3d.TransformGroup;
import org.scijava.vecmath.Point3d;
import org.scijava.vecmath.Vector3d;
import org.scijava.java3d.utils.geometry.Primitive;
/**
* The base class for optimized picking operations.
* The picking methods will return a PickInfo object for each object picked,
* which can then be queried to
* obtain more detailed information about the specific objects that were
* picked.
*
* The pick mode specifies the detail level of picking before the PickInfo
* is returned:
*
*
* - PickInfo.PICK_BOUNDS - Pick using the only bounds of the pickable nodes.
*
* - PickInfo.PICK_GEOMETRY will pick using the geometry of the pickable nodes.
* Geometry nodes in the scene must have the ALLOW_INTERSECT capability set for
* this mode.
*
* The pick flags specifies the content of the PickInfo(s) returned by the
* pick methods. This is specified as one or more individual bits that are
* bitwise "OR"ed together to describe the PickInfo data. The flags include :
*
* PickInfo.SCENEGRAPHPATH
- request for computed SceneGraphPath.
* PickInfo.NODE
- request for computed intersected Node.
* PickInfo.LOCAL_TO_VWORLD
- request for computed local to virtual world transform.
* PickInfo.CLOSEST_INTERSECTION_POINT
- request for closest intersection point.
* PickInfo.CLOSEST_DISTANCE
- request for the distance of closest intersection.
* PickInfo.CLOSEST_GEOM_INFO
- request for only the closest intersection geometry information.
* PickInfo.ALL_GEOM_INFO
- request for all intersection geometry information.
*
*
*
* When using pickAllSorted or pickClosest methods, the picks
* will be sorted by the distance from the start point of the pick shape to
* the intersection point.
*
* @see Locale#pickClosest(int,int,org.scijava.java3d.PickShape)
*/
public class PickTool {
/**
* Flag to pass to
* getNode(int)
* to return a
* Shape3D
node from
* the SceneGraphPath
.
*/
public static final int TYPE_SHAPE3D = 0x1;
/**
* Flag to pass to
* getNode(int)
* to return a
* Morph
node from
* the SceneGraphPath
.
*/
public static final int TYPE_MORPH = 0x2;
/**
* Flag to pass to
* getNode(int)
* to return a
* Primitive
node from
* the SceneGraphPath
.
*/
public static final int TYPE_PRIMITIVE = 0x4;
/**
* Flag to pass to
* getNode(int)
* to return a
* Link
node from
* the SceneGraphPath
.
*/
public static final int TYPE_LINK = 0x8;
/**
* Flag to pass to
* getNode(int)
* to return a
* Group
node from
* the SceneGraphPath
.
*/
public static final int TYPE_GROUP = 0x10;
/**
* Flag to pass to
* getNode(int)
* to return a
* TransformGroup
node from
* the SceneGraphPath
.
*/
public static final int TYPE_TRANSFORM_GROUP = 0x20;
/**
* Flag to pass to
* getNode(int)
* to return a
* BranchGroup
node from
* the SceneGraphPath
.
*/
public static final int TYPE_BRANCH_GROUP = 0x40;
/**
* Flag to pass to
* getNode(int)
* to return a
* Switch
node from
* the SceneGraphPath
.
*/
public static final int TYPE_SWITCH = 0x80;
private static final int ALL_FLAGS =
PickInfo.SCENEGRAPHPATH |
PickInfo.NODE |
PickInfo.LOCAL_TO_VWORLD |
PickInfo.CLOSEST_INTERSECTION_POINT |
PickInfo.CLOSEST_DISTANCE |
PickInfo.CLOSEST_GEOM_INFO |
PickInfo.ALL_GEOM_INFO;
private final boolean debug = false;
protected boolean userDefineShape = false;
PickShape pickShape;
/** Used to store the BranchGroup used for picking */
BranchGroup pickRootBG = null;
/** Used to store the Locale used for picking */
Locale pickRootL = null;
/** Used to store a reference point used in determining how "close" points
are.
*/
Point3d start = null;
int mode = PickInfo.PICK_BOUNDS;
int flags = PickInfo.NODE;
/* ============================ METHODS ============================ */
/**
* Constructor with BranchGroup to be picked.
*/
public PickTool (BranchGroup b) {
pickRootBG = b;
}
/**
* Constructor with the Locale to be picked.
*/
public PickTool (Locale l) {
pickRootL = l;
}
/** Returns the BranchGroup to be picked if the tool was initialized
with a BranchGroup, null otherwise.
*/
public BranchGroup getBranchGroup() {
return pickRootBG;
}
/**
* Returns the Locale to be picked if the tool was initialized with
* a Locale, null otherwise.
*/
public Locale getLocale () {
return pickRootL;
}
// Methods used to define the pick shape
/** Sets the pick shape to a user-provided PickShape object
* @param ps The pick shape to pick against.
* @param startPt The start point to use for distance calculations
*/
public void setShape (PickShape ps, Point3d startPt) {
this.pickShape = ps;
this.start = startPt;
userDefineShape = (ps != null);
}
/** Sets the pick shape to use a user-provided Bounds object
* @param bounds The bounds to pick against.
* @param startPt The start point to use for distance calculations
*/
public void setShapeBounds (Bounds bounds, Point3d startPt) {
this.pickShape = (PickShape) new PickBounds (bounds);
this.start = startPt;
userDefineShape = true;
}
/** Sets the picking detail mode. The default is PickInfo.PICK_BOUNDS.
* @param mode One of PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY.
* @exception IllegalArgumentException if mode is not a legal value
*/
public void setMode (int mode) {
if ((mode != PickInfo.PICK_BOUNDS) && (mode != PickInfo.PICK_GEOMETRY)) {
throw new java.lang.IllegalArgumentException();
}
this.mode = mode;
}
/** Gets the picking detail mode.
*/
public int getMode () {
return mode;
}
/** Sets the PickInfo content flags. The default is PickInfo.NODE.
* @param flags specified as one or more individual bits that are
* bitwise "OR"ed together :
*
* PickInfo.SCENEGRAPHPATH
- request for computed SceneGraphPath.
* PickInfo.NODE
- request for computed intersected Node.
* PickInfo.LOCAL_TO_VWORLD
- request for computed local to virtual world transform.
* PickInfo.CLOSEST_INTERSECTION_POINT
- request for closest intersection point.
* PickInfo.CLOSEST_DISTANCE
- request for the distance of closest intersection.
* PickInfo.CLOSEST_GEOM_INFO
- request for only the closest intersection geometry information.
* PickInfo.ALL_GEOM_INFO
- request for all intersection geometry information.
*
* @exception IllegalArgumentException if any other bits besides the above are set.
*/
public void setFlags (int flags) {
if ((flags & ~ALL_FLAGS) != 0) {
throw new java.lang.IllegalArgumentException();
}
this.flags = flags;
}
/** Gets the PickInfo content flags.
*/
public int getFlags () {
return flags;
}
/** Sets the pick shape to a PickRay.
* @param start The start of the ray
* @param dir The direction of the ray
*/
public void setShapeRay (Point3d start, Vector3d dir) {
this.pickShape = (PickShape) new PickRay (start, dir);
this.start = start;
userDefineShape = true;
}
/** Sets the pick shape to a PickSegment.
@param start The start of the segment
@param end The end of the segment
*/
public void setShapeSegment (Point3d start, Point3d end) {
this.pickShape = (PickShape) new PickSegment (start, end);
this.start = start;
userDefineShape = true;
}
/** Sets the pick shape to a capped PickCylinder
* @param start The start of axis of the cylinder
* @param end The end of the axis of the cylinder
* @param radius The radius of the cylinder
*/
public void setShapeCylinderSegment (Point3d start, Point3d end,
double radius) {
this.pickShape = (PickShape)
new PickCylinderSegment (start, end, radius);
this.start = start;
userDefineShape = true;
}
/** Sets the pick shape to an infinite PickCylinder.
* @param start The start of axis of the cylinder
* @param dir The direction of the axis of the cylinder
* @param radius The radius of the cylinder
*/
public void setShapeCylinderRay (Point3d start, Vector3d dir,
double radius) {
this.pickShape = (PickShape) new PickCylinderRay (start, dir, radius);
this.start = start;
userDefineShape = true;
}
/** Sets the pick shape to a capped PickCone
* @param start The start of axis of the cone
* @param end The end of the axis of the cone
* @param angle The angle of the cone
*/
public void setShapeConeSegment (Point3d start, Point3d end,
double angle) {
this.pickShape = (PickShape) new PickConeSegment (start, end, angle);
this.start = start;
userDefineShape = true;
}
/** Sets the pick shape to an infinite PickCone.
* @param start The start of axis of the cone
* @param dir The direction of the axis of the cone
* @param angle The angle of the cone
*/
public void setShapeConeRay (Point3d start, Vector3d dir,
double angle) {
this.pickShape = (PickShape) new PickConeRay (start, dir, angle);
this.start = start;
userDefineShape = true;
}
/** Returns the PickShape for this object. */
public PickShape getPickShape () {
return pickShape;
}
/** Returns the start postion used for distance measurement. */
public Point3d getStartPosition () {
return start;
}
/** Selects all the nodes that intersect the PickShape.
@return An array of PickInfo
objects which will contain
information about the picked instances. null
if nothing was
picked.
*/
public PickInfo[] pickAll () {
PickInfo[] pickInfos = null;
if (pickRootBG != null) {
pickInfos = pickRootBG.pickAll(mode, flags, pickShape);
} else if (pickRootL != null) {
pickInfos = pickRootL.pickAll(mode, flags, pickShape);
}
return pickInfos;
}
/** Select one of the nodes that intersect the PickShape
@return A PickInfo
object which will contain
information about the picked instance. null
if nothing
was picked.
*/
public PickInfo pickAny () {
PickInfo pickInfo = null;
if (pickRootBG != null) {
pickInfo = pickRootBG.pickAny(mode, flags, pickShape);
} else if (pickRootL != null) {
pickInfo = pickRootL.pickAny(mode, flags, pickShape);
}
return pickInfo;
}
/** Select all the nodes that intersect the
PickShape, returned sorted. The "closest" object will be returned first.
See note above to see how "closest" is determined.
@return An array of PickInfo
objects which will contain
information
about the picked instances. null
if nothing was picked.
*/
public PickInfo[] pickAllSorted () {
PickInfo[] pickInfos = null;
if (pickRootBG != null) {
pickInfos = pickRootBG.pickAllSorted(mode, flags, pickShape);
} else if (pickRootL != null) {
pickInfos = pickRootL.pickAllSorted(mode, flags, pickShape);
}
return pickInfos;
}
/** Select the closest node that
intersects the PickShape. See note above to see how "closest" is
determined.
@return A PickInfo
object which will contain
information about the picked instance. null
if nothing
was picked.
*/
public PickInfo pickClosest () {
// System.out.println("PickTool : pickClosest ...");
PickInfo pickInfo = null;
if (pickRootBG != null) {
pickInfo = pickRootBG.pickClosest(mode, flags, pickShape);
} else if (pickRootL != null) {
pickInfo = pickRootL.pickClosest(mode, flags, pickShape);
}
// System.out.println(" -- pickInfo is " + pickInfo);
return pickInfo;
}
/** Get the first node of a certain type up the SceneGraphPath
*@param type the type of node we are interested in
*@return a Node object
*
* @exception NullPointerException if pickInfo does not contain a
* Scenegraphpath or a picked node
*/
public Node getNode (PickInfo pickInfo, int type) {
// System.out.println("pickInfo is " + pickInfo);
if (pickInfo == null) {
return null;
}
SceneGraphPath sgp = pickInfo.getSceneGraphPath();
Node pickedNode = pickInfo.getNode();
// System.out.println("sgp = " + sgp + " pickedNode = " + pickedNode);
/*
* Do not check for null for pickNode and sgp.
* Will throw NPE if pickedNode or sgp isn't set in pickInfo
*/
if ((pickedNode instanceof Shape3D) && ((type & TYPE_SHAPE3D) != 0)){
if (debug) System.out.println("Shape3D found");
return pickedNode;
}
else if ((pickedNode instanceof Morph) && ((type & TYPE_MORPH) != 0)){
if (debug) System.out.println("Morph found");
return pickedNode;
}
else {
for (int j=sgp.nodeCount()-1; j>=0; j--){
Node pNode = sgp.getNode(j);
if (debug) System.out.println("looking at node " + pNode);
if ((pNode instanceof Primitive) &&
((type & TYPE_PRIMITIVE) != 0)){
if (debug) System.out.println("Primitive found");
return pNode;
}
else if ((pNode instanceof Link) && ((type & TYPE_LINK) != 0)){
if (debug) System.out.println("Link found");
return pNode;
}
else if ((pNode instanceof Switch) && ((type & TYPE_SWITCH) != 0)){
if (debug) System.out.println("Switch found");
return pNode;
}
else if ((pNode instanceof TransformGroup) &&
((type & TYPE_TRANSFORM_GROUP) != 0)){
if (debug) System.out.println("xform group found");
return pNode;
}
else if ((pNode instanceof BranchGroup) &&
((type & TYPE_BRANCH_GROUP) != 0)){
if (debug) System.out.println("Branch group found");
return pNode;
}
else if ((pNode instanceof Group) && ((type & TYPE_GROUP) != 0)){
if (debug) System.out.println("Group found");
return pNode;
}
}
}
return null; // should not be reached
}
} // PickTool