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