001: /*
002: * $RCSfile: PickCanvas.java,v $
003: *
004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistribution of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * - Redistribution in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * Neither the name of Sun Microsystems, Inc. or the names of
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * This software is provided "AS IS," without a warranty of any
023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034: * POSSIBILITY OF SUCH DAMAGES.
035: *
036: * You acknowledge that this software is not designed, licensed or
037: * intended for use in the design, construction, operation or
038: * maintenance of any nuclear facility.
039: *
040: * $Revision: 1.4 $
041: * $Date: 2007/02/09 17:20:25 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.utils.picking;
046:
047: import java.awt.event.*;
048: import javax.vecmath.*;
049: import javax.media.j3d.*;
050: import com.sun.j3d.utils.geometry.*; // Cone, Cylinder
051:
052: /**
053: * A subclass of PickTool, simplifies picking using mouse events from a canvas.
054: * This class allows picking using canvas x,y locations by generating the
055: * appropriate pick shape.
056: * <p>
057: * The pick tolerance specifies the distance from the
058: * pick center to include in the pick shape. A tolerance of 0.0 may speedup
059: * picking slightly, but also make it very difficult to pick points and lines.
060: * <p>
061: * The pick canvas can be used to make a series of picks. For example, to
062: * initialize the pick canvas:
063: * <blockquote><pre>
064: * PickCanvas pickCanvas = new PickCanvas(canvas, scene);
065: * pickCanvas.setMode(PickTool.GEOMETRY_INTERSECT_INFO);
066: * pickCanvas.setTolerance(4.0f);
067: * </pre></blockquote>
068: * <p>
069: * Then for each mouse event:
070: * <blockquote><pre>
071: * pickCanvas.setShapeLocation(mouseEvent);
072: * PickResult[] results = pickCanvas.pickAll();
073: * </pre></blockquote>
074: * <p>
075: * NOTE: For the pickAllSorted or pickClosest methods, the picks will be sorted
076: * by the distance from the ViewPlatform to the intersection point.
077: * @see PickTool
078: */
079: public class PickCanvas extends PickTool {
080:
081: /* OPEN ISSUES:
082: -- Should restrict the pick shape to the front/back clip plane
083: */
084:
085: /** The canvas we are picking into */
086: Canvas3D canvas;
087:
088: /* the pick tolerance, default to 2.0 */
089: float tolerance = 2.0f;
090: int save_xpos;
091: int save_ypos;
092:
093: /** Constructor with Canvas3D for mouse events and BranchGroup to be picked.
094: */
095: public PickCanvas(Canvas3D c, BranchGroup b) {
096: super (b);
097: canvas = c;
098: }
099:
100: /** Constructor with Canvas3D for mouse events and Locale to be picked.
101: */
102: public PickCanvas(Canvas3D c, Locale l) {
103: super (l);
104: canvas = c;
105: }
106:
107: /** Inquire the canvas to be used for picking operations.
108: @return the canvas.
109: */
110: public Canvas3D getCanvas() {
111: return canvas;
112: }
113:
114: /** Set the picking tolerance. Objects within this distance
115: * (in pixels)
116: * to the mouse x,y location will be picked. The default tolerance is 2.0.
117: * @param t The tolerance
118: * @exception IllegalArgumentException if the tolerance is less than 0.
119: */
120: public void setTolerance(float t) {
121: if (t < 0.0f) {
122: throw new IllegalArgumentException();
123: }
124: tolerance = t;
125:
126: if ((pickShape != null) && (!userDefineShape)) {
127: // reset pickShape
128: pickShape = null;
129: setShapeLocation(save_xpos, save_ypos);
130: }
131: }
132:
133: /** Get the pick tolerance.
134: */
135: public float getTolerance() {
136: return tolerance;
137: }
138:
139: /** Set the pick location. Defines the location on the canvas where the
140: pick is to be performed.
141: @param mevent The MouseEvent for the picking point
142: */
143: public void setShapeLocation(MouseEvent mevent) {
144: setShapeLocation(mevent.getX(), mevent.getY());
145: }
146:
147: /** Set the pick location. Defines the location on the canvas where the
148: pick is to be performed (upper left corner of canvas is 0,0).
149: @param xpos the X position of the picking point
150: @param ypos the Y position of the picking point
151: */
152: public void setShapeLocation(int xpos, int ypos) {
153: Transform3D motion = new Transform3D();
154: Point3d eyePosn = new Point3d();
155: Point3d mousePosn = new Point3d();
156: Vector3d mouseVec = new Vector3d();
157: boolean isParallel = false;
158: double radius = 0.0;
159: double spreadAngle = 0.0;
160:
161: this .save_xpos = xpos;
162: this .save_ypos = ypos;
163: canvas.getCenterEyeInImagePlate(eyePosn);
164: canvas.getPixelLocationInImagePlate(xpos, ypos, mousePosn);
165:
166: if ((canvas.getView() != null)
167: && (canvas.getView().getProjectionPolicy() == View.PARALLEL_PROJECTION)) {
168: // Correct for the parallel projection: keep the eye's z
169: // coordinate, but make x,y be the same as the mouse, this
170: // simulates the eye being at "infinity"
171: eyePosn.x = mousePosn.x;
172: eyePosn.y = mousePosn.y;
173: isParallel = true;
174: }
175:
176: // Calculate radius for PickCylinderRay and spread angle for PickConeRay
177: Vector3d eyeToCanvas = new Vector3d();
178: eyeToCanvas.sub(mousePosn, eyePosn);
179: double distanceEyeToCanvas = eyeToCanvas.length();
180:
181: Point3d deltaImgPlate = new Point3d();
182: canvas.getPixelLocationInImagePlate(xpos + 1, ypos,
183: deltaImgPlate);
184:
185: Vector3d ptToDelta = new Vector3d();
186: ptToDelta.sub(mousePosn, deltaImgPlate);
187: double distancePtToDelta = ptToDelta.length();
188: distancePtToDelta *= tolerance;
189:
190: canvas.getImagePlateToVworld(motion);
191:
192: /*
193: System.out.println("mouse position " + xpos + " " + ypos);
194: System.out.println("before, mouse " + mousePosn + " eye " + eyePosn);
195: */
196:
197: motion.transform(eyePosn);
198: start = new Point3d(eyePosn); // store the eye position
199: motion.transform(mousePosn);
200: mouseVec.sub(mousePosn, eyePosn);
201: mouseVec.normalize();
202:
203: /*
204: System.out.println(motion + "\n");
205: System.out.println("after, mouse " + mousePosn + " eye " + eyePosn +
206: " mouseVec " + mouseVec);
207: */
208:
209: if (tolerance == 0.0) {
210: if ((pickShape != null) && (pickShape instanceof PickRay)) {
211: ((PickRay) pickShape).set(eyePosn, mouseVec);
212: } else {
213: pickShape = (PickShape) new PickRay(eyePosn, mouseVec);
214: }
215: // pickShape = (PickShape) new PickConeRay (eyePosn,
216: // mouseVec,1.0*Math.PI/180.0);
217: } else {
218: if (isParallel) {
219: // Parallel projection, use a PickCylinderRay
220: distancePtToDelta *= motion.getScale();
221: if ((pickShape != null)
222: && (pickShape instanceof PickCylinderRay)) {
223: ((PickCylinderRay) pickShape).set(eyePosn,
224: mouseVec, distancePtToDelta);
225: } else {
226: pickShape = (PickShape) new PickCylinderRay(
227: eyePosn, mouseVec, distancePtToDelta);
228: }
229: } else {
230: // Perspective projection, use a PickConeRay
231:
232: // Calculate spread angle
233: spreadAngle = Math.atan(distancePtToDelta
234: / distanceEyeToCanvas);
235:
236: if ((pickShape != null)
237: && (pickShape instanceof PickConeRay)) {
238: ((PickConeRay) pickShape).set(eyePosn, mouseVec,
239: spreadAngle);
240: } else {
241: pickShape = (PickShape) new PickConeRay(eyePosn,
242: mouseVec, spreadAngle);
243: }
244: }
245: }
246: }
247: } // PickCanvas
|