4ed670fec8652c18b8aea99d9c5cbeeb7cd03a0f
[scilab.git] / scilab / modules / renderer / src / java / org / scilab / modules / renderer / JoGLView / interaction / RubberBox.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  */
11
12 package org.scilab.modules.renderer.JoGLView.interaction;
13
14 import org.scilab.forge.scirenderer.DrawingTools;
15 import org.scilab.forge.scirenderer.SciRendererException;
16 import org.scilab.forge.scirenderer.buffers.BuffersManager;
17 import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
18 import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
19 import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
20 import org.scilab.forge.scirenderer.shapes.appearance.Color;
21 import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
22 import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
23 import org.scilab.forge.scirenderer.tranformations.Vector3d;
24 import org.scilab.modules.graphic_objects.axes.Axes;
25 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
26 import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
27 import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
28 import org.scilab.modules.renderer.JoGLView.interaction.util.HelpersGeometry;
29 import org.scilab.modules.renderer.JoGLView.interaction.util.PointAComputer;
30 import org.scilab.modules.renderer.JoGLView.interaction.util.PointBComputer;
31 import org.scilab.modules.renderer.JoGLView.interaction.util.PointCComputer;
32 import org.scilab.modules.renderer.JoGLView.interaction.util.PointComputer;
33 import org.scilab.modules.renderer.JoGLView.interaction.util.PointDComputer;
34 import org.scilab.modules.renderer.JoGLView.postRendering.PostRendered;
35
36 import javax.swing.event.EventListenerList;
37 import java.awt.Component;
38 import java.awt.Point;
39 import java.awt.event.KeyEvent;
40 import java.awt.event.KeyListener;
41 import java.awt.event.MouseEvent;
42 import java.awt.event.MouseListener;
43 import java.awt.event.MouseMotionListener;
44 import java.text.DecimalFormat;
45
46 /**
47  * @author Pierre Lando
48  */
49 public class RubberBox extends FigureInteraction implements PostRendered, MouseListener, MouseMotionListener, KeyListener {
50
51     /** Decimal format used to show info messages */
52     private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.###E0");
53
54     /** Axes name used to show info messages */
55     private static final String[] AXES_NAMES = new String[]{"X", "Y", "Z"};
56
57     /** The cube indices */
58     private static final int[] CUBE_INDICES = {
59         0, 1, 3, 2, 4, 5, 7, 6,
60         0, 3, 1, 2, 4, 7, 5, 6,
61         0, 4, 1, 5, 3, 7, 2, 6
62     };
63
64     /** Rubber box status */
65     public static enum Status {
66         WAIT_POINT_A,
67             WAIT_POINT_B,
68             WAIT_POINT_C,
69             WAIT_POINT_D,
70             }
71
72     /** Rubber box color */
73     private static final Color RUBBER_BOX_COLOR = new Color(.2f, .3f, .4f);
74
75     /** Rubber box thickness */
76     private static final float RUBBER_BOX_THICKNESS = 2;
77
78     /** Rubber box pattern */
79     private static final short RUBBER_BOX_PATTERN = (short) 0xFAFA;
80
81     /** The mouse button used to perform a rubber box */
82     private static final int MOUSE_MODIFIER = MouseEvent.BUTTON1_MASK;
83
84     /** This key stop the rubber box */
85     private static final int STOP_KEY = KeyEvent.VK_ESCAPE;
86
87     /** Helpers appearance */
88     private static Appearance helpersAppearance;
89
90     /** Rubber box cube appearance */
91     private static Appearance cubeAppearance;
92
93     /** The event listener list */
94     private final EventListenerList listenerList = new EventListenerList();
95
96     /** Helpers geometry */
97     private HelpersGeometry helpersGeometry;
98
99     /** Rubber box cube geometry */
100     private DefaultGeometry cubeGeometry;
101
102     /** Current status */
103     private Status status;
104
105     private Axes axes;
106
107     private PointAComputer pointAComputer;
108     private PointBComputer pointBComputer;
109     private PointCComputer pointCComputer;
110     private PointDComputer pointDComputer;
111     private Vector3d firstPoint;
112     private Vector3d secondPoint;
113
114     /**
115      * Default constructor.
116      *
117      * @param drawerVisitor parent drawer visitor.
118      */
119     public RubberBox(DrawerVisitor drawerVisitor) {
120         super(drawerVisitor);
121         status = Status.WAIT_POINT_A;
122     }
123
124     /**
125      * Add a rubber box listener.
126      * The listener will be notified when a rubber box end.
127      * @param rubberBoxListener the new listener.
128      */
129     public final void addListener(RubberBoxListener rubberBoxListener) {
130         listenerList.add(RubberBoxListener.class, rubberBoxListener);
131     }
132
133     /**
134      * Remove a rubber box listener.
135      * The listener will no long be notified on events.
136      * @param rubberBoxListener the removed listener.
137      */
138     public final void removeListener(RubberBoxListener rubberBoxListener) {
139         listenerList.remove(RubberBoxListener.class, rubberBoxListener);
140     }
141
142     /**
143      * Notify all listener that the rubber box have ended
144      */
145     private void fireRubberBoxEnd() {
146         for (RubberBoxListener rubberBoxListener : listenerList.getListeners(RubberBoxListener.class)) {
147             rubberBoxListener.rubberBoxEnd();
148         }
149     }
150
151     @Override
152     public final void draw(DrawingTools drawingTools) throws SciRendererException {
153         if (isEnable() && (axes != null)) {
154             drawingTools.getTransformationManager().useSceneCoordinate();
155             drawingTools.getTransformationManager().getModelViewStack().push(
156                 getDrawerVisitor().getAxesDrawer().getSceneProjection(axes.getIdentifier())
157                 );
158
159             if (status != Status.WAIT_POINT_A) {
160                 drawingTools.draw(getCubeGeometry(drawingTools), getCubeAppearance());
161             }
162
163             if (secondPoint != null) {
164                 drawingTools.draw(getHelpersGeometry(drawingTools), getHelpersAppearance());
165             }
166
167             drawingTools.getTransformationManager().getModelViewStack().pop();
168         }
169     }
170
171     @Override
172     public final void changeEnable(boolean isEnable) {
173         Component component = getDrawerVisitor().getComponent();
174         if (isEnable) {
175             status = Status.WAIT_POINT_A;
176             pointAComputer = null;
177             component.addMouseListener(this);
178             component.addMouseMotionListener(this);
179             component.addKeyListener(this);
180             component.setFocusTraversalKeysEnabled(false);
181             component.setFocusable(true);
182             component.requestFocus();
183         } else {
184             component.removeMouseListener(this);
185             component.removeMouseMotionListener(this);
186             component.removeKeyListener(this);
187         }
188         updateInfoMessage();
189         getDrawerVisitor().getCanvas().redraw();
190     }
191
192     @Override
193     public final void keyTyped(KeyEvent e) {
194         if (e.getKeyChar() == STOP_KEY) {
195             setEnable(false);
196             fireRubberBoxEnd();
197         }
198     }
199
200     @Override
201     public final void mouseClicked(MouseEvent e) {
202         if (e.getModifiers() == MOUSE_MODIFIER) {
203             switch (status) {
204             case WAIT_POINT_A:
205                 if (setPointA(e.getPoint())) {
206                     status = Status.WAIT_POINT_B;
207                 } else {
208                     setEnable(false);
209                     fireRubberBoxEnd();
210                 }
211                 break;
212             case WAIT_POINT_B:
213                 setPointB(e.getPoint());
214                 if (pointBComputer.is2D()) {
215                     setZoomBox();
216                     setEnable(false);
217                     fireRubberBoxEnd();
218                 } else {
219                     status = Status.WAIT_POINT_C;
220                 }
221                 break;
222             case WAIT_POINT_C:
223                 setPointC(e.getPoint());
224                 status = Status.WAIT_POINT_D;
225                 break;
226             case WAIT_POINT_D:
227                 setPointD(e.getPoint());
228                 setZoomBox();
229                 setEnable(false);
230                 fireRubberBoxEnd();
231                 break;
232             default:
233             }
234             updateInfoMessage();
235         }
236     }
237
238     @Override
239     public final void mouseMoved(MouseEvent e) {
240         switch (status) {
241         case WAIT_POINT_A:
242             setPointA(e.getPoint());
243             getDrawerVisitor().getCanvas().redraw();
244             break;
245         case WAIT_POINT_B:
246             setPointB(e.getPoint());
247             getDrawerVisitor().getCanvas().redraw();
248             break;
249         case WAIT_POINT_C:
250             setPointC(e.getPoint());
251             getDrawerVisitor().getCanvas().redraw();
252             break;
253         case WAIT_POINT_D:
254             setPointD(e.getPoint());
255             getDrawerVisitor().getCanvas().redraw();
256             break;
257         default:
258         }
259         updateInfoMessage();
260     }
261
262     /**
263      * Update displayed info message.
264      */
265     private void updateInfoMessage() {
266         if (isEnable()) {
267             switch (status) {
268             case WAIT_POINT_A:
269                 setInfoMessage("Click to set first bounds", pointAComputer, false);
270                 break;
271             case WAIT_POINT_B:
272                 setInfoMessage("Click to set second bounds", pointBComputer, false);
273                 break;
274             case WAIT_POINT_C:
275                 setInfoMessage("Click to set first", pointCComputer, true);
276                 break;
277             case WAIT_POINT_D:
278                 setInfoMessage("Click to set second ", pointDComputer, true);
279                 break;
280             default:
281             }
282         } else {
283             GraphicController.getController().setProperty(
284                 getDrawerVisitor().getFigure().getIdentifier(),
285                 GraphicObjectProperties.__GO_INFO_MESSAGE__,
286                 null
287                 );
288         }
289     }
290
291     /**
292      * Set the info message.
293      * @param baseMessage the base of the message.
294      * @param pointComputer current used point computer.
295      * @param oneAxis true if only one coordinate is currently set.
296      */
297     private void setInfoMessage(String baseMessage, PointComputer pointComputer, boolean oneAxis) {
298         if ((pointComputer != null) && (pointComputer.isValid())) {
299             String message = baseMessage + " ";
300             double[] data = pointComputer.getSecondPosition().getData();
301             String comma;
302             if (oneAxis) {
303                 comma = "";
304             } else {
305                 comma = ", ";
306             }
307
308             for (int i = 0; i < PointComputer.AXIS_NUMBER; i++) {
309                 if ((i != pointComputer.getFirstAxisIndex()) ^ oneAxis) {
310                     message += AXES_NAMES[i] + " = " + DECIMAL_FORMAT.format(data[i]) + comma;
311                     comma = "";
312                 }
313             }
314             GraphicController.getController().setProperty(
315                 getDrawerVisitor().getFigure().getIdentifier(),
316                 GraphicObjectProperties.__GO_INFO_MESSAGE__,
317                 message
318                 );
319         } else {
320             String message = "Move your mouse on an axes box.";
321             GraphicController.getController().setProperty(
322                 getDrawerVisitor().getFigure().getIdentifier(),
323                 GraphicObjectProperties.__GO_INFO_MESSAGE__,
324                 message
325                 );
326         }
327     }
328
329     /**
330      * Actually set the zoom box depending on current value of firstPoint and secondPoint.
331      */
332     private void setZoomBox() {
333         Double[] bounds = {
334             Math.min(firstPoint.getX(), secondPoint.getX()), Math.max(firstPoint.getX(), secondPoint.getX()),
335             Math.min(firstPoint.getY(), secondPoint.getY()), Math.max(firstPoint.getY(), secondPoint.getY()),
336             Math.min(firstPoint.getZ(), secondPoint.getZ()), Math.max(firstPoint.getZ(), secondPoint.getZ()),
337         };
338
339         if (bounds[0].compareTo(bounds[1]) != 0 && bounds[2].compareTo(bounds[3]) != 0 && bounds[4].compareTo(bounds[5]) != 0) {
340             Boolean zoomed = tightZoomBounds(axes, bounds);
341             GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_BOX__, bounds);
342             GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_ENABLED__, zoomed);
343             getDrawerVisitor().getCanvas().redraw();
344         }
345     }
346
347     /**
348      * Set the first point.
349      * @param point first point AWT coordinate.
350      * @return true if the first point is valid.
351      */
352     private boolean setPointA(Point point) {
353         axes = getUnderlyingAxes(point);
354         if (axes != null) {
355             PointAComputer pointComputer = new PointAComputer(axes, point);
356             if (pointComputer.isValid()) {
357                 this.pointAComputer = pointComputer;
358                 firstPoint = pointComputer.getPosition();
359                 secondPoint = firstPoint;
360                 return true;
361             }
362         }
363         return false;
364     }
365
366     /**
367      * Set second point in 3D zoom.
368      * @param point second point.
369      * @return true if the point is valid.
370      */
371     private boolean setPointB(Point point) {
372         PointBComputer pointComputer = new PointBComputer(axes, pointAComputer, point);
373         if (pointComputer.isValid()) {
374             this.pointBComputer = pointComputer;
375             firstPoint = pointComputer.getFirstPosition();
376             secondPoint = pointComputer.getSecondPosition();
377             getDrawerVisitor().getCanvas().redraw();
378             return true;
379         } else {
380             return false;
381         }
382     }
383
384     /**
385      * Set zoom box position in 3D zoom.
386      * @param point mouse position.
387      * @return true if the point is valid.
388      */
389     private boolean setPointC(Point point) {
390         PointCComputer pointComputer = new PointCComputer(axes, pointBComputer, point);
391         if (pointComputer.isValid()) {
392             this.pointCComputer = pointComputer;
393             firstPoint = pointComputer.getFirstPosition();
394             secondPoint = pointComputer.getSecondPosition();
395             getDrawerVisitor().getCanvas().redraw();
396             return true;
397         } else {
398             return false;
399         }
400     }
401
402     /**
403      * Set zoom box position in 3D zoom.
404      * @param point mouse position.
405      * @return true if the point is valid.
406      */
407     private boolean setPointD(Point point) {
408         PointDComputer pointComputer = new PointDComputer(axes, pointCComputer, point);
409         if (pointComputer.isValid()) {
410             this.pointDComputer = pointComputer;
411             firstPoint = pointComputer.getFirstPosition();
412             secondPoint = pointComputer.getSecondPosition();
413             getDrawerVisitor().getCanvas().redraw();
414             return true;
415         } else {
416             return false;
417         }
418     }
419
420     /**
421      * Initialise or update the helpers geometry.
422      * @param drawingTools the drawing tools used to draw the helpers.
423      * @return updated helpers geometry.
424      */
425     private Geometry getHelpersGeometry(DrawingTools drawingTools) {
426         if (helpersGeometry == null) {
427             helpersGeometry = new HelpersGeometry(drawingTools);
428         }
429         helpersGeometry.updateVertex(axes, pointAComputer, secondPoint, status);
430         return helpersGeometry;
431     }
432
433     /**
434      * Helpers appearance getter.
435      * First initialise the helpers appearance.
436      * @return the helpers appearance.
437      */
438     public final Appearance getHelpersAppearance() {
439         if (helpersAppearance == null) {
440             helpersAppearance = new Appearance();
441             helpersAppearance.setLineColor(new Color(1, 0, 0));
442             helpersAppearance.setLineWidth(2);
443         }
444         return helpersAppearance;
445     }
446
447     /**
448      * Rubber box cube geometry getter.
449      * @param drawingTools the drawing tools.
450      * @return the rubber box cubeGeometry.
451      */
452     private Geometry getCubeGeometry(DrawingTools drawingTools) {
453         if (cubeGeometry == null) {
454             cubeGeometry = new DefaultGeometry();
455
456             BuffersManager bufferManager = drawingTools.getCanvas().getBuffersManager();
457             ElementsBuffer vertexBuffer = bufferManager.createElementsBuffer();
458             IndicesBuffer indicesBuffer = bufferManager.createIndicesBuffer();
459             indicesBuffer.setData(CUBE_INDICES);
460
461             cubeGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
462             cubeGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
463             cubeGeometry.setVertices(vertexBuffer);
464             cubeGeometry.setWireIndices(indicesBuffer);
465         }
466
467         cubeGeometry.getVertices().setData(new float[] {
468                 (float) firstPoint.getX(), (float) firstPoint.getY(), (float) firstPoint.getZ(), 1,
469                 (float) firstPoint.getX(), (float) firstPoint.getY(), (float) secondPoint.getZ(), 1,
470                 (float) firstPoint.getX(), (float) secondPoint.getY(), (float) secondPoint.getZ(), 1,
471                 (float) firstPoint.getX(), (float) secondPoint.getY(), (float) firstPoint.getZ(), 1,
472                 (float) secondPoint.getX(), (float) firstPoint.getY(), (float) firstPoint.getZ(), 1,
473                 (float) secondPoint.getX(), (float) firstPoint.getY(), (float) secondPoint.getZ(), 1,
474                 (float) secondPoint.getX(), (float) secondPoint.getY(), (float) secondPoint.getZ(), 1,
475                 (float) secondPoint.getX(), (float) secondPoint.getY(), (float) firstPoint.getZ(), 1
476             }, 4);
477
478         return cubeGeometry;
479     }
480
481     /**
482      * Rubber-box cube appearance getter.
483      * @return the rubber-box cube appearance.
484      */
485     private Appearance getCubeAppearance() {
486         if (cubeAppearance == null) {
487             cubeAppearance = new Appearance();
488             cubeAppearance.setLineColor(RUBBER_BOX_COLOR);
489             cubeAppearance.setLineWidth(RUBBER_BOX_THICKNESS);
490             cubeAppearance.setLinePattern(RUBBER_BOX_PATTERN);
491         }
492         return cubeAppearance;
493     }
494
495     @Override
496     public void mousePressed(MouseEvent e) {
497     }
498
499     @Override
500     public void mouseReleased(MouseEvent e) {
501     }
502
503     @Override
504     public void mouseEntered(MouseEvent e) {
505     }
506
507     @Override
508     public void mouseExited(MouseEvent e) {
509     }
510
511     @Override
512     public void mouseDragged(MouseEvent e) {
513     }
514
515     @Override
516     public void keyPressed(KeyEvent e) {
517     }
518
519     @Override
520     public void keyReleased(KeyEvent e) {
521     }
522 }