Plug rubberbox function :
[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  * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
5  *
6  * This file must be used under the terms of the CeCILL.
7  * This source file is licensed as described in the file COPYING, which
8  * you should have received as part of this distribution.  The terms
9  * are also available at
10  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
11  */
12
13 package org.scilab.modules.renderer.JoGLView.interaction;
14
15 import java.awt.Component;
16 import java.awt.Point;
17 import java.awt.event.KeyEvent;
18 import java.awt.event.KeyListener;
19 import java.awt.event.MouseEvent;
20 import java.awt.event.MouseListener;
21 import java.awt.event.MouseMotionListener;
22 import java.text.DecimalFormat;
23
24 import javax.swing.event.EventListenerList;
25
26 import org.scilab.forge.scirenderer.DrawingTools;
27 import org.scilab.forge.scirenderer.SciRendererException;
28 import org.scilab.forge.scirenderer.buffers.BuffersManager;
29 import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
30 import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
31 import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
32 import org.scilab.forge.scirenderer.shapes.appearance.Color;
33 import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
34 import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
35 import org.scilab.forge.scirenderer.tranformations.Vector3d;
36 import org.scilab.modules.graphic_objects.axes.Axes;
37 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
38 import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
39 import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
40 import org.scilab.modules.renderer.JoGLView.interaction.util.HelpersGeometry;
41 import org.scilab.modules.renderer.JoGLView.interaction.util.PointAComputer;
42 import org.scilab.modules.renderer.JoGLView.interaction.util.PointBComputer;
43 import org.scilab.modules.renderer.JoGLView.interaction.util.PointCComputer;
44 import org.scilab.modules.renderer.JoGLView.interaction.util.PointComputer;
45 import org.scilab.modules.renderer.JoGLView.interaction.util.PointDComputer;
46 import org.scilab.modules.renderer.JoGLView.postRendering.PostRendered;
47
48 /**
49  * @author Pierre Lando
50  */
51 public class RubberBox extends FigureInteraction implements PostRendered, MouseListener, MouseMotionListener, KeyListener {
52
53     /** Decimal format used to show info messages */
54     private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.###E0");
55
56     /** Axes name used to show info messages */
57     private static final String[] AXES_NAMES = new String[]{"X", "Y", "Z"};
58
59     /** The cube indices */
60     private static final int[] CUBE_INDICES = {
61         0, 1, 3, 2, 4, 5, 7, 6,
62         0, 3, 1, 2, 4, 7, 5, 6,
63         0, 4, 1, 5, 3, 7, 2, 6
64     };
65
66     /** Rubber box status */
67     public static enum Status {
68         WAIT_POINT_A,
69         WAIT_POINT_B,
70         WAIT_POINT_C,
71         WAIT_POINT_D,
72     }
73
74     /** Rubber box color */
75     private static final Color RUBBER_BOX_COLOR = new Color(.2f, .3f, .4f);
76
77     /** Rubber box thickness */
78     private static final float RUBBER_BOX_THICKNESS = 2;
79
80     /** Rubber box pattern */
81     private static final short RUBBER_BOX_PATTERN = (short) 0xFAFA;
82
83     /** Helpers appearance */
84     private static Appearance helpersAppearance;
85
86     /** Rubber box cube appearance */
87     private static Appearance cubeAppearance;
88
89     /** The event listener list */
90     private final EventListenerList listenerList = new EventListenerList();
91
92     /** Helpers geometry */
93     private HelpersGeometry helpersGeometry;
94
95     /** Rubber box cube geometry */
96     private DefaultGeometry cubeGeometry;
97
98     /** Current status */
99     protected Status status;
100
101     protected Axes axes;
102
103     private PointComputer pointAComputer;
104     protected PointComputer pointBComputer;
105     private PointComputer pointCComputer;
106     private PointComputer pointDComputer;
107     protected Vector3d firstPoint;
108     protected Vector3d secondPoint;
109
110     protected int mouseButton;
111
112     /**
113      * Default constructor.
114      *
115      * @param drawerVisitor parent drawer visitor.
116      */
117     protected RubberBox(DrawerVisitor drawerVisitor) {
118         super(drawerVisitor);
119         status = Status.WAIT_POINT_A;
120     }
121
122     /**
123      * Add a rubber box listener.
124      * The listener will be notified when a rubber box end.
125      * @param rubberBoxListener the new listener.
126      */
127     public final void addListener(RubberBoxListener rubberBoxListener) {
128         listenerList.add(RubberBoxListener.class, rubberBoxListener);
129     }
130
131     /**
132      * Remove a rubber box listener.
133      * The listener will no long be notified on events.
134      * @param rubberBoxListener the removed listener.
135      */
136     public final void removeListener(RubberBoxListener rubberBoxListener) {
137         listenerList.remove(RubberBoxListener.class, rubberBoxListener);
138     }
139
140     /**
141      * Notify all listener that the rubber box have ended
142      */
143     protected void fireRubberBoxEnd() {
144         for (RubberBoxListener rubberBoxListener : listenerList.getListeners(RubberBoxListener.class)) {
145             rubberBoxListener.rubberBoxEnd();
146         }
147     }
148
149     @Override
150     public final void draw(DrawingTools drawingTools) throws SciRendererException {
151         if (isEnable() && (axes != null)) {
152             drawingTools.getTransformationManager().useSceneCoordinate();
153             drawingTools.getTransformationManager().getModelViewStack().push(
154                     getDrawerVisitor().getAxesDrawer().getSceneProjection(axes.getIdentifier())
155                     );
156
157             if (status != Status.WAIT_POINT_A) {
158                 drawingTools.draw(getCubeGeometry(drawingTools), getCubeAppearance());
159             }
160
161             if (secondPoint != null) {
162                 drawingTools.draw(getHelpersGeometry(drawingTools), getHelpersAppearance());
163             }
164
165             drawingTools.getTransformationManager().getModelViewStack().pop();
166         }
167     }
168
169     @Override
170     public final void changeEnable(boolean isEnable) {
171         Component component = getDrawerVisitor().getComponent();
172         if (isEnable) {
173             //status = Status.WAIT_POINT_A;
174             pointAComputer = null;
175             component.addMouseListener(this);
176             component.addMouseMotionListener(this);
177             component.addKeyListener(this);
178             component.setFocusTraversalKeysEnabled(false);
179             component.setFocusable(true);
180             component.requestFocus();
181         } else {
182             component.removeMouseListener(this);
183             component.removeMouseMotionListener(this);
184             component.removeKeyListener(this);
185         }
186         updateInfoMessage();
187         getDrawerVisitor().getCanvas().redraw();
188     }
189
190     @Override
191     public final void keyTyped(KeyEvent e) {
192         if (e.getKeyChar() == KeyEvent.VK_ESCAPE) {
193             mouseButton = -1;
194             setEnable(false);
195             fireRubberBoxEnd();
196         }
197     }
198
199     @Override
200     public void mouseClicked(MouseEvent e) {
201         mouseButton = e.getButton();
202         switch (status) {
203         case WAIT_POINT_A:
204             if (setPointA(e.getPoint())) {
205                 status = Status.WAIT_POINT_B;
206             } else {
207                 setEnable(false);
208                 fireRubberBoxEnd();
209             }
210             break;
211         case WAIT_POINT_B:
212             setPointB(e.getPoint());
213             if (pointBComputer.is2D()) {
214                 process();
215                 setEnable(false);
216                 fireRubberBoxEnd();
217             } else {
218                 status = Status.WAIT_POINT_C;
219             }
220             break;
221         case WAIT_POINT_C:
222             setPointC(e.getPoint());
223             status = Status.WAIT_POINT_D;
224             break;
225         case WAIT_POINT_D:
226             setPointD(e.getPoint());
227             process();
228             setEnable(false);
229             fireRubberBoxEnd();
230             break;
231         default:
232         }
233         updateInfoMessage();
234
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      protected 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                     ""
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       * Process action on RupperBox
331       * Do nothing by default 
332       */
333      protected void process()
334      {
335          // Do nothing
336      }
337
338      /**
339       * Set the first point.
340       * @param point first point AWT coordinate.
341       * @return true if the first point is valid.
342       */
343      protected boolean setPointA(Point point) {
344          axes = getUnderlyingAxes(point);
345          if (axes != null) {
346              PointAComputer pointComputer = new PointAComputer(axes, point);
347              if (pointComputer.isValid()) {
348                  this.pointAComputer = pointComputer;
349                  firstPoint = pointComputer.getPosition();
350                  secondPoint = firstPoint;
351                  return true;
352              }
353          }
354          return false;
355      }
356
357      /**
358       * Set second point in 3D zoom.
359       * @param point second point.
360       * @return true if the point is valid.
361       */
362      protected boolean setPointB(Point point) {
363          PointBComputer pointComputer = new PointBComputer(axes, pointAComputer, point);
364          if (pointComputer.isValid()) {
365              this.pointBComputer = pointComputer;
366              firstPoint = pointComputer.getFirstPosition();
367              secondPoint = pointComputer.getSecondPosition();
368              getDrawerVisitor().getCanvas().redraw();
369              return true;
370          } else {
371              return false;
372          }
373      }
374
375      /**
376       * Set zoom box position in 3D zoom.
377       * @param point mouse position.
378       * @return true if the point is valid.
379       */
380      protected boolean setPointC(Point point) {
381          PointCComputer pointComputer = new PointCComputer(axes, pointBComputer, point);
382          if (pointComputer.isValid()) {
383              this.pointCComputer = pointComputer;
384              firstPoint = pointComputer.getFirstPosition();
385              secondPoint = pointComputer.getSecondPosition();
386              getDrawerVisitor().getCanvas().redraw();
387              return true;
388          } else {
389              return false;
390          }
391      }
392
393      /**
394       * Set zoom box position in 3D zoom.
395       * @param point mouse position.
396       * @return true if the point is valid.
397       */
398      protected boolean setPointD(Point point) {
399          PointDComputer pointComputer = new PointDComputer(axes, pointCComputer, point);
400          if (pointComputer.isValid()) {
401              this.pointDComputer = pointComputer;
402              firstPoint = pointComputer.getFirstPosition();
403              secondPoint = pointComputer.getSecondPosition();
404              getDrawerVisitor().getCanvas().redraw();
405              return true;
406          } else {
407              return false;
408          }
409      }
410
411      /**
412       * Initialise or update the helpers geometry.
413       * @param drawingTools the drawing tools used to draw the helpers.
414       * @return updated helpers geometry.
415       */
416      private Geometry getHelpersGeometry(DrawingTools drawingTools) {
417          if (helpersGeometry == null) {
418              helpersGeometry = new HelpersGeometry(drawingTools);
419          }
420          helpersGeometry.updateVertex(axes, pointAComputer, secondPoint, status);
421          return helpersGeometry;
422      }
423
424      /**
425       * Helpers appearance getter.
426       * First initialise the helpers appearance.
427       * @return the helpers appearance.
428       */
429      public final Appearance getHelpersAppearance() {
430          if (helpersAppearance == null) {
431              helpersAppearance = new Appearance();
432              helpersAppearance.setLineColor(new Color(1, 0, 0));
433              helpersAppearance.setLineWidth(2);
434          }
435          return helpersAppearance;
436      }
437
438      /**
439       * Rubber box cube geometry getter.
440       * @param drawingTools the drawing tools.
441       * @return the rubber box cubeGeometry.
442       */
443      private Geometry getCubeGeometry(DrawingTools drawingTools) {
444          if (cubeGeometry == null) {
445              cubeGeometry = new DefaultGeometry();
446
447              BuffersManager bufferManager = drawingTools.getCanvas().getBuffersManager();
448              ElementsBuffer vertexBuffer = bufferManager.createElementsBuffer();
449              IndicesBuffer indicesBuffer = bufferManager.createIndicesBuffer();
450              indicesBuffer.setData(CUBE_INDICES);
451
452              cubeGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
453              cubeGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
454              cubeGeometry.setVertices(vertexBuffer);
455              cubeGeometry.setWireIndices(indicesBuffer);
456          }
457
458          cubeGeometry.getVertices().setData(new float[] {
459                  (float) firstPoint.getX(), (float) firstPoint.getY(), (float) firstPoint.getZ(), 1,
460                  (float) firstPoint.getX(), (float) firstPoint.getY(), (float) secondPoint.getZ(), 1,
461                  (float) firstPoint.getX(), (float) secondPoint.getY(), (float) secondPoint.getZ(), 1,
462                  (float) firstPoint.getX(), (float) secondPoint.getY(), (float) firstPoint.getZ(), 1,
463                  (float) secondPoint.getX(), (float) firstPoint.getY(), (float) firstPoint.getZ(), 1,
464                  (float) secondPoint.getX(), (float) firstPoint.getY(), (float) secondPoint.getZ(), 1,
465                  (float) secondPoint.getX(), (float) secondPoint.getY(), (float) secondPoint.getZ(), 1,
466                  (float) secondPoint.getX(), (float) secondPoint.getY(), (float) firstPoint.getZ(), 1
467          }, 4);
468
469          return cubeGeometry;
470      }
471
472      /**
473       * Rubber-box cube appearance getter.
474       * @return the rubber-box cube appearance.
475       */
476      private Appearance getCubeAppearance() {
477          if (cubeAppearance == null) {
478              cubeAppearance = new Appearance();
479              cubeAppearance.setLineColor(RUBBER_BOX_COLOR);
480              cubeAppearance.setLineWidth(RUBBER_BOX_THICKNESS);
481              cubeAppearance.setLinePattern(RUBBER_BOX_PATTERN);
482          }
483          return cubeAppearance;
484      }
485
486      @Override
487      public void mousePressed(MouseEvent e) {
488      }
489
490      @Override
491      public void mouseReleased(MouseEvent e) {
492      }
493
494      @Override
495      public void mouseEntered(MouseEvent e) {
496      }
497
498      @Override
499      public void mouseExited(MouseEvent e) {
500      }
501
502      @Override
503      public void mouseDragged(MouseEvent e) {
504      }
505
506      @Override
507      public void keyPressed(KeyEvent e) {
508      }
509
510      @Override
511      public void keyReleased(KeyEvent e) {
512      }
513 }