Graphics: fix custom Formatter after JDK8 upgrade
[scilab.git] / scilab / modules / renderer / src / java / org / scilab / modules / renderer / JoGLView / axes / ruler / AxesRulerDrawer.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) 2011 - DIGITEO - Manuel Juliachs
5  * Copyright (C) 2013-2014 - Scilab Enterprises - Calixte DENIZET
6  *
7  * Copyright (C) 2012 - 2016 - Scilab Enterprises
8  *
9  * This file is hereby licensed under the terms of the GNU GPL v2.0,
10  * pursuant to article 5.3.4 of the CeCILL v.2.1.
11  * This file was originally licensed under the terms of the CeCILL v2.1,
12  * and continues to be available under such terms.
13  * For more information, see the COPYING file which you should have received
14  * along with this program.
15  */
16
17 package org.scilab.modules.renderer.JoGLView.axes.ruler;
18
19 import org.scilab.forge.scirenderer.Canvas;
20 import org.scilab.forge.scirenderer.DrawingTools;
21 import org.scilab.forge.scirenderer.SciRendererException;
22 import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
23 import org.scilab.forge.scirenderer.ruler.DefaultRulerModel;
24 import org.scilab.forge.scirenderer.ruler.RulerDrawer;
25 import org.scilab.forge.scirenderer.ruler.RulerDrawingResult;
26 import org.scilab.forge.scirenderer.ruler.RulerModel;
27 import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
28 import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
29 import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
30 import org.scilab.forge.scirenderer.tranformations.DegenerateMatrixException;
31 import org.scilab.forge.scirenderer.tranformations.Transformation;
32 import org.scilab.forge.scirenderer.tranformations.TransformationFactory;
33 import org.scilab.forge.scirenderer.tranformations.Vector3d;
34 import org.scilab.modules.graphic_objects.axes.Axes;
35 import org.scilab.modules.graphic_objects.axes.AxisProperty;
36 import org.scilab.modules.graphic_objects.axes.Camera;
37 import org.scilab.modules.graphic_objects.contouredObject.Line;
38 import org.scilab.modules.graphic_objects.figure.ColorMap;
39 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
40 import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
41 import org.scilab.modules.renderer.JoGLView.axes.AxesDrawer;
42 import org.scilab.modules.renderer.JoGLView.label.AxisLabelPositioner;
43 import org.scilab.modules.renderer.JoGLView.label.TitlePositioner;
44 import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
45
46 import java.awt.Dimension;
47 import java.nio.FloatBuffer;
48 import java.text.DecimalFormat;
49 import java.text.FieldPosition;
50 import java.util.Arrays;
51 import java.util.List;
52
53 /**
54  * @author Pierre Lando
55  */
56 public class AxesRulerDrawer {
57
58     private static final double LINEAR_MINIMAL_SUB_TICKS_DISTANCE = 8;
59     private static final double LOG_MINIMAL_SUB_TICKS_DISTANCE = 2;
60
61     /** Ticks length in pixels. */
62     public static final int TICKS_LENGTH = 6;
63
64     /** Sub-ticks length in pixels. */
65     private static final int SUB_TICKS_LENGTH = 3;
66
67     /**Ticks sprites distance in pixels. */
68     private static final int SPRITE_DISTANCE = 12;
69
70
71     private final RulerDrawerManager rulerDrawerManager;
72
73     public AxesRulerDrawer(Canvas canvas) {
74         this.rulerDrawerManager = new RulerDrawerManager(canvas.getTextureManager());
75     }
76
77     public RulerDrawer getRulerDrawer(Axes axes, int axis) {
78         return rulerDrawerManager.get(axes)[axis];
79     }
80
81     /**
82      * Get default ruler model
83      * @param axes the axes
84      * @param colorMap the colorMap
85      * @return a DefaultRulerModel
86      */
87     private final DefaultRulerModel getDefaultRulerModel(Axes axes, ColorMap colorMap) {
88         DefaultRulerModel rulerModel = new DefaultRulerModel();
89         rulerModel.setTicksLength(TICKS_LENGTH);
90         rulerModel.setSubTicksLength(SUB_TICKS_LENGTH);
91         rulerModel.setLineWidth(axes.getLineThickness());
92         rulerModel.setSpriteDistance(SPRITE_DISTANCE);
93         rulerModel.setColor(ColorFactory.createColor(colorMap, axes.getLineColor()));
94
95         return rulerModel;
96     }
97
98     /**
99      * Compute ticks and subticks on the rulers
100      * @param axes the current {@see Axes}
101      * @param axesDrawer the drawer used to draw the current {@see Axes}
102      * @param colorMap current {@see ColorMap}
103      * @param transformation the current modelView projection
104      * @param canvasProjection the canvas projection
105      * @throws org.scilab.forge.scirenderer.SciRendererException if draw fail.
106      */
107     public void computeRulers(Axes axes, AxesDrawer axesDrawer, ColorMap colorMap, Transformation transformation, Transformation canvasProjection) {
108         Double[] bounds = axes.getDisplayedBounds();
109         double[] matrix = transformation.getMatrix();
110
111         RulerDrawingResult rulerDrawingResult;
112         double[] values;
113
114         RulerDrawer[] rulerDrawers = rulerDrawerManager.get(axes);
115         DefaultRulerModel rulerModel = getDefaultRulerModel(axes, colorMap);
116
117         Vector3d xAxisPosition = computeXAxisPosition(matrix, bounds, axes.getXAxis().getAxisLocation(), axes.getYAxis().getReverse());
118         Vector3d yAxisPosition = computeYAxisPosition(matrix, bounds, axes.getYAxis().getAxisLocation(), axes.getXAxis().getReverse());
119
120         Vector3d px = canvasProjection.projectDirection(new Vector3d(1, 0, 0)).setZ(0);
121         Vector3d py = canvasProjection.projectDirection(new Vector3d(0, 1, 0)).setZ(0);
122         Vector3d pz = canvasProjection.projectDirection(new Vector3d(0, 0, 1)).setZ(0);
123
124         Vector3d xTicksDirection, yTicksDirection;
125         if (py.getNorm2() > pz.getNorm2()) {
126             xTicksDirection = new Vector3d(0, getNonZeroSignum(xAxisPosition.getY()), 0);
127         } else {
128             xTicksDirection = new Vector3d(0, 0, getNonZeroSignum(xAxisPosition.getZ()));
129         }
130
131         if (px.getNorm2() > pz.getNorm2()) {
132             yTicksDirection = new Vector3d(getNonZeroSignum(yAxisPosition.getX()), 0, 0);
133         } else {
134             yTicksDirection = new Vector3d(0, 0, getNonZeroSignum(yAxisPosition.getZ()));
135         }
136
137         // Draw X ruler
138         rulerModel.setTicksDirection(xTicksDirection);
139         rulerModel.setFirstPoint(xAxisPosition.setX(-1));
140         rulerModel.setSecondPoint(xAxisPosition.setX(1));
141         if (!axes.getAutoSubticks()) {
142             rulerModel.setSubticksNumber(axes.getXAxisSubticks());
143         }
144
145         setRulerBounds(axes.getXAxis(), rulerModel, bounds[0], bounds[1]);
146
147         rulerModel.setFormat(axes.getXAxisFormat());
148         rulerModel.setSTFactors(axes.getXAxisSTFactors());
149         rulerModel.setLogarithmic(axes.getXAxis().getLogFlag());
150         rulerModel.setMinimalSubTicksDistance(axes.getXAxis().getLogFlag() ? LOG_MINIMAL_SUB_TICKS_DISTANCE : LINEAR_MINIMAL_SUB_TICKS_DISTANCE);
151
152         if (!axes.getXAxis().getAutoTicks()) {
153             rulerModel.setUserGraduation(new UserDefineGraduation(axes.getXAxis(), bounds[0], bounds[1]));
154             if (axes.getAutoSubticks()) {
155                 rulerModel.setSubticksNumber(axes.getXAxisSubticks());
156             }
157             rulerModel.setAutoTicks(false);
158         } else {
159             rulerModel.setAutoTicks(true);
160         }
161
162         double distanceRatio;
163         AxisLabelPositioner xAxisLabelPositioner = axesDrawer.getXAxisLabelPositioner(axes);
164         xAxisLabelPositioner.setLabelPosition(xAxisPosition);
165
166         if (axes.getXAxisVisible()) {
167             rulerDrawingResult = rulerDrawers[0].computeRuler(rulerModel, canvasProjection);
168             values = rulerDrawingResult.getTicksValues();
169
170             if (axes.getXAxisAutoTicks()) {
171                 Arrays.sort(values);
172                 GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_X_AXIS_TICKS_LOCATIONS__, toDoubleArray(values));
173                 GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_X_AXIS_TICKS_LABELS__, toStringArray(values, rulerDrawingResult.getFormat()));
174                 if (axes.getAutoSubticks()) {
175                     //GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_X_AXIS_SUBTICKS__, rulerDrawingResult.getSubTicksDensity());
176                     axes.setXAxisSubticks(rulerDrawingResult.getSubTicksDensity());
177                 }
178             }
179
180             distanceRatio = rulerDrawingResult.getMaxDistToTicksDirNorm();
181
182             xAxisLabelPositioner.setTicksDirection(xTicksDirection);
183             xAxisLabelPositioner.setDistanceRatio(distanceRatio);
184             xAxisLabelPositioner.setProjectedTicksDirection(rulerDrawingResult.getNormalizedTicksDirection().setZ(0));
185         } else {
186             xAxisLabelPositioner.setTicksDirection(xTicksDirection);
187             Vector3d projTicksDir = canvasProjection.projectDirection(xTicksDirection);
188             xAxisLabelPositioner.setDistanceRatio((double) TICKS_LENGTH / projTicksDir.getNorm());
189             xAxisLabelPositioner.setProjectedTicksDirection(projTicksDir.getNormalized().setZ(0));
190         }
191
192         TitlePositioner titlePositioner = axesDrawer.getTitlePositioner(axes);
193         Dimension xdim = axesDrawer.getLabelManager().getXLabelSize(colorMap, axes, axesDrawer);
194         titlePositioner.setXLabelHeight(xdim.height);
195         titlePositioner.setDistanceRatio(xAxisLabelPositioner.getDistanceRatio());
196
197         // Draw Y ruler
198         rulerModel = getDefaultRulerModel(axes, colorMap);
199         rulerModel.setTicksDirection(yTicksDirection);
200         rulerModel.setFirstPoint(yAxisPosition.setY(-1));
201         rulerModel.setSecondPoint(yAxisPosition.setY(1));
202         if (!axes.getAutoSubticks()) {
203             rulerModel.setSubticksNumber(axes.getYAxisSubticks());
204         }
205
206         setRulerBounds(axes.getYAxis(), rulerModel, bounds[2], bounds[3]);
207         rulerModel.setFormat(axes.getYAxisFormat());
208         rulerModel.setSTFactors(axes.getYAxisSTFactors());
209         rulerModel.setLogarithmic(axes.getYAxis().getLogFlag());
210         rulerModel.setMinimalSubTicksDistance(axes.getYAxis().getLogFlag() ? LOG_MINIMAL_SUB_TICKS_DISTANCE : LINEAR_MINIMAL_SUB_TICKS_DISTANCE);
211
212         if (!axes.getYAxis().getAutoTicks()) {
213             rulerModel.setUserGraduation(new UserDefineGraduation(axes.getYAxis(), bounds[2], bounds[3]));
214             if (axes.getAutoSubticks()) {
215                 rulerModel.setSubticksNumber(axes.getYAxisSubticks());
216             }
217             rulerModel.setAutoTicks(false);
218         } else {
219             rulerModel.setAutoTicks(true);
220         }
221
222         AxisLabelPositioner yAxisLabelPositioner = axesDrawer.getYAxisLabelPositioner(axes);
223         yAxisLabelPositioner.setLabelPosition(yAxisPosition);
224
225         if (axes.getYAxisVisible()) {
226             rulerDrawingResult = rulerDrawers[1].computeRuler(rulerModel, canvasProjection);
227             values = rulerDrawingResult.getTicksValues();
228             if (axes.getYAxisAutoTicks()) {
229                 Arrays.sort(values);
230                 GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_Y_AXIS_TICKS_LOCATIONS__, toDoubleArray(values));
231                 GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_Y_AXIS_TICKS_LABELS__, toStringArray(values, rulerDrawingResult.getFormat()));
232                 if (axes.getAutoSubticks()) {
233                     //GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_Y_AXIS_SUBTICKS__, rulerDrawingResult.getSubTicksDensity());
234                     axes.setYAxisSubticks(rulerDrawingResult.getSubTicksDensity());
235                 }
236             }
237
238             distanceRatio = rulerDrawingResult.getMaxDistToTicksDirNorm();
239
240             yAxisLabelPositioner.setTicksDirection(yTicksDirection);
241             yAxisLabelPositioner.setDistanceRatio(distanceRatio);
242             yAxisLabelPositioner.setProjectedTicksDirection(rulerDrawingResult.getNormalizedTicksDirection().setZ(0));
243         } else {
244             /* y-axis not visible: compute the projected ticks direction and distance ratio (see the x-axis case). */
245             yAxisLabelPositioner.setTicksDirection(yTicksDirection);
246             Vector3d projTicksDir = canvasProjection.projectDirection(yTicksDirection);
247             yAxisLabelPositioner.setDistanceRatio((double) TICKS_LENGTH / projTicksDir.getNorm());
248             yAxisLabelPositioner.setProjectedTicksDirection(projTicksDir.getNormalized().setZ(0));
249         }
250
251         // Draw Z ruler
252         if (axes.getViewAsEnum() == Camera.ViewType.VIEW_3D) {
253             double txs, tys, xs, ys;
254             if (Math.abs(matrix[2]) < Math.abs(matrix[6])) {
255                 xs = matrix[2] > 0 ? 1 : -1;
256                 ys = matrix[6] > 0 ? -1 : 1;
257                 txs = xs;
258                 tys = 0;
259             } else {
260                 xs = matrix[2] > 0 ? -1 : 1;
261                 ys = matrix[6] > 0 ? 1 : -1;
262                 txs = 0;
263                 tys = ys;
264             }
265
266             rulerModel = getDefaultRulerModel(axes, colorMap);
267             rulerModel.setFirstPoint(new Vector3d(xs, ys, -1));
268             rulerModel.setSecondPoint(new Vector3d(xs, ys, 1));
269             rulerModel.setTicksDirection(new Vector3d(txs, tys, 0));
270             if (!axes.getAutoSubticks()) {
271                 rulerModel.setSubticksNumber(axes.getZAxisSubticks());
272             }
273
274             setRulerBounds(axes.getZAxis(), rulerModel, bounds[4], bounds[5]);
275             rulerModel.setFormat(axes.getZAxisFormat());
276             rulerModel.setSTFactors(axes.getZAxisSTFactors());
277             rulerModel.setLogarithmic(axes.getZAxis().getLogFlag());
278             rulerModel.setMinimalSubTicksDistance(axes.getZAxis().getLogFlag() ? LOG_MINIMAL_SUB_TICKS_DISTANCE : LINEAR_MINIMAL_SUB_TICKS_DISTANCE);
279
280             if (!axes.getZAxis().getAutoTicks()) {
281                 rulerModel.setUserGraduation(new UserDefineGraduation(axes.getZAxis(), bounds[4], bounds[5]));
282                 if (axes.getAutoSubticks()) {
283                     rulerModel.setSubticksNumber(axes.getZAxisSubticks());
284                 }
285                 rulerModel.setAutoTicks(false);
286             } else {
287                 rulerModel.setAutoTicks(true);
288             }
289
290             AxisLabelPositioner zAxisLabelPositioner = axesDrawer.getZAxisLabelPositioner(axes);
291             zAxisLabelPositioner.setLabelPosition(new Vector3d(xs, ys, 0));
292
293             if (axes.getZAxisVisible()) {
294                 rulerDrawingResult = rulerDrawers[2].computeRuler(rulerModel, canvasProjection);
295                 values = rulerDrawingResult.getTicksValues();
296                 if (axes.getZAxisAutoTicks()) {
297                     Arrays.sort(values);
298                     GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_Z_AXIS_TICKS_LOCATIONS__, toDoubleArray(values));
299                     GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_Z_AXIS_TICKS_LABELS__, toStringArray(values, rulerDrawingResult.getFormat()));
300                     if (axes.getAutoSubticks()) {
301                         //GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_Z_AXIS_SUBTICKS__, rulerDrawingResult.getSubTicksDensity());
302                         axes.setZAxisSubticks(rulerDrawingResult.getSubTicksDensity());
303                     }
304                 }
305
306                 distanceRatio = rulerDrawingResult.getMaxDistToTicksDirNorm();
307
308                 zAxisLabelPositioner.setTicksDirection(new Vector3d(txs, tys, 0.0));
309                 zAxisLabelPositioner.setDistanceRatio(distanceRatio);
310                 zAxisLabelPositioner.setProjectedTicksDirection(rulerDrawingResult.getNormalizedTicksDirection().setZ(0).setY(1e-7));
311             } else {
312                 /* z-axis not visible: compute the projected ticks direction and distance ratio (see the x-axis case). */
313                 Vector3d zTicksDirection = new Vector3d(txs, tys, 0);
314
315                 zAxisLabelPositioner.setTicksDirection(zTicksDirection);
316                 Vector3d projTicksDir = canvasProjection.projectDirection(zTicksDirection);
317                 zAxisLabelPositioner.setDistanceRatio((double) TICKS_LENGTH / projTicksDir.getNorm());
318                 zAxisLabelPositioner.setProjectedTicksDirection(projTicksDir.getNormalized().setZ(0));
319             }
320         }
321     }
322
323     /**
324      * Draw the ruler.
325      * @param axes the current {@see Axes}
326      * @param axesDrawer the drawer used to draw the current {@see Axes}
327      * @param colorMap current {@see ColorMap}
328      * @param drawingTools the used {@see DrawingTools}
329      * @throws org.scilab.forge.scirenderer.SciRendererException if draw fail.
330      */
331     public void drawRuler(Axes axes, AxesDrawer axesDrawer, ColorMap colorMap, DrawingTools drawingTools) throws SciRendererException {
332         Appearance gridAppearance = new Appearance();
333
334         Double[] bounds = axes.getDisplayedBounds();
335         double[] matrix = drawingTools.getTransformationManager().getModelViewStack().peek().getMatrix();
336
337         RulerDrawer[] rulerDrawers = rulerDrawerManager.get(axes);
338         ElementsBuffer vertexBuffer = drawingTools.getCanvas().getBuffersManager().createElementsBuffer();
339         final boolean is3D = axes.getViewAsEnum() == Camera.ViewType.VIEW_3D;// && axes.getRotationAngles()[1] != 90.0;
340
341         if (rulerDrawers[0].getModel() == null || rulerDrawers[1].getModel() == null || (is3D && rulerDrawers[2].getModel() == null)) {
342             computeRulers(axes, axesDrawer, colorMap, drawingTools.getTransformationManager().getModelViewStack().peek(), drawingTools.getTransformationManager().getCanvasProjection());
343         }
344
345         int gridPosition;
346         if (axes.getGridPositionAsEnum().equals(Axes.GridPosition.FOREGROUND)) {
347             gridPosition = 1;
348         } else {
349             gridPosition = -1;
350         }
351
352         // Draw X ruler
353         if (axes.getXAxisVisible()) {
354             rulerDrawers[0].draw(drawingTools);
355
356             if (axes.getXAxisGridColor() != -1) {
357                 FloatBuffer vertexData;
358                 if (axes.getXAxisLogFlag()) {
359                     List<Double> values = rulerDrawers[0].getSubTicksValue();
360                     if (values == null || values.isEmpty()) {
361                         vertexData = getXGridData(rulerDrawers[0].getTicksValue(), rulerDrawers[0].getModel());
362                     } else {
363                         vertexData = getXGridData(values, rulerDrawers[0].getModel());
364                     }
365                 } else {
366                     vertexData = getXGridData(rulerDrawers[0].getTicksValue(), rulerDrawers[0].getModel());
367                 }
368                 vertexBuffer.setData(vertexData, 4);
369
370                 Transformation mirror;
371                 try {
372                     mirror = TransformationFactory.getScaleTransformation(
373                                  1,
374                                  matrix[6] < 0 ? gridPosition : -gridPosition,
375                                  matrix[10] < 0 ? gridPosition : -gridPosition
376                              );
377                 } catch (DegenerateMatrixException ignored) {
378                     // Should never happens as long as gridPosition the value 1 or -1
379                     mirror = TransformationFactory.getIdentity();
380                 }
381
382                 gridAppearance.setLineColor(ColorFactory.createColor(colorMap, axes.getXAxisGridColor()));
383                 gridAppearance.setLineWidth(axes.getXAxisGridThickness().floatValue());
384                 gridAppearance.setLinePattern(Line.LineType.fromScilabIndex(axes.getXAxisGridStyle()).asPattern());
385                 drawingTools.getTransformationManager().getModelViewStack().pushRightMultiply(mirror);
386                 DefaultGeometry gridGeometry = new DefaultGeometry();
387                 gridGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
388                 gridGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
389                 gridGeometry.setVertices(vertexBuffer);
390                 drawingTools.draw(gridGeometry, gridAppearance);
391                 drawingTools.getTransformationManager().getModelViewStack().pop();
392             }
393         }
394
395         // Draw Y ruler
396         if (axes.getYAxisVisible()) {
397             rulerDrawers[1].draw(drawingTools);
398
399             if (axes.getYAxisGridColor() != -1) {
400                 FloatBuffer vertexData;
401                 if (axes.getYAxisLogFlag()) {
402                     List<Double> values = rulerDrawers[1].getSubTicksValue();
403                     if (values == null || values.isEmpty()) {
404                         vertexData = getYGridData(rulerDrawers[1].getTicksValue(), rulerDrawers[1].getModel());
405                     } else {
406                         vertexData = getYGridData(values, rulerDrawers[1].getModel());
407                     }
408                 } else {
409                     vertexData = getYGridData(rulerDrawers[1].getTicksValue(), rulerDrawers[1].getModel());
410                 }
411                 vertexBuffer.setData(vertexData, 4);
412
413                 Transformation mirror;
414                 try {
415                     mirror = TransformationFactory.getScaleTransformation(
416                                  matrix[2] < 0 ? gridPosition : -gridPosition,
417                                  1,
418                                  matrix[10] < 0 ? gridPosition : -gridPosition
419                              );
420                 } catch (DegenerateMatrixException ignored) {
421                     // Should never happens as long as gridPosition the value 1 or -1
422                     mirror = TransformationFactory.getIdentity();
423                 }
424
425                 gridAppearance.setLineColor(ColorFactory.createColor(colorMap, axes.getYAxisGridColor()));
426                 gridAppearance.setLineWidth(axes.getYAxisGridThickness().floatValue());
427                 gridAppearance.setLinePattern(Line.LineType.fromScilabIndex(axes.getYAxisGridStyle()).asPattern());
428                 drawingTools.getTransformationManager().getModelViewStack().pushRightMultiply(mirror);
429                 DefaultGeometry gridGeometry = new DefaultGeometry();
430                 gridGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
431                 gridGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
432                 gridGeometry.setVertices(vertexBuffer);
433                 drawingTools.draw(gridGeometry, gridAppearance);
434                 drawingTools.getTransformationManager().getModelViewStack().pop();
435             }
436         }
437
438         // Draw Z ruler
439         if (is3D) {
440             if (axes.getZAxisVisible()) {
441                 rulerDrawers[2].draw(drawingTools);
442
443                 if (axes.getZAxisGridColor() != -1) {
444                     FloatBuffer vertexData;
445                     if (axes.getZAxisLogFlag()) {
446                         List<Double> values = rulerDrawers[2].getSubTicksValue();
447                         if (values == null || values.isEmpty()) {
448                             vertexData = getZGridData(rulerDrawers[2].getTicksValue(), rulerDrawers[2].getModel());
449                         } else {
450                             vertexData = getZGridData(values, rulerDrawers[2].getModel());
451                         }
452                     } else {
453                         vertexData = getZGridData(rulerDrawers[2].getTicksValue(), rulerDrawers[2].getModel());
454                     }
455                     vertexBuffer.setData(vertexData, 4);
456
457                     Transformation mirror;
458                     try {
459                         mirror = TransformationFactory.getScaleTransformation(
460                                      matrix[2] < 0 ? gridPosition : -gridPosition,
461                                      matrix[6] < 0 ? gridPosition : -gridPosition,
462                                      1
463                                  );
464                     } catch (DegenerateMatrixException ignored) {
465                         // Should never happens as long as gridPosition the value 1 or -1
466                         mirror = TransformationFactory.getIdentity();
467                     }
468
469                     gridAppearance.setLineColor(ColorFactory.createColor(colorMap, axes.getZAxisGridColor()));
470                     gridAppearance.setLineWidth(axes.getZAxisGridThickness().floatValue());
471                     gridAppearance.setLinePattern(Line.LineType.fromScilabIndex(axes.getZAxisGridStyle()).asPattern());
472                     drawingTools.getTransformationManager().getModelViewStack().pushRightMultiply(mirror);
473                     DefaultGeometry gridGeometry = new DefaultGeometry();
474                     gridGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
475                     gridGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
476                     gridGeometry.setVertices(vertexBuffer);
477                     drawingTools.draw(gridGeometry, gridAppearance);
478                     drawingTools.getTransformationManager().getModelViewStack().pop();
479                 }
480             }
481         }
482
483         drawingTools.getCanvas().getBuffersManager().dispose(vertexBuffer);
484     }
485
486     private static final double getNonZeroSignum(double value) {
487         if (value < 0) {
488             return -1;
489         } else {
490             return 1;
491         }
492     }
493
494     private void setRulerBounds(AxisProperty axis, DefaultRulerModel rulerModel, double axisMin, double axisMax) {
495         double min, max;
496         if (axis.getReverse()) {
497             min = axisMin;
498             max = axisMax;
499         } else {
500             min = axisMax;
501             max = axisMin;
502         }
503
504         if (axis.getLogFlag()) {
505             min = Math.pow(10, min);
506             max = Math.pow(10, max);
507         }
508         rulerModel.setValues(min, max);
509     }
510
511     private Vector3d computeXAxisPosition(double[] projectionMatrix, Double[] bounds, AxisProperty.AxisLocation axisLocation, boolean reverse) {
512         double y, z;
513         switch (axisLocation) {
514             default:
515             case BOTTOM:
516                 z = -Math.signum(projectionMatrix[9]);  // First : switch Z such that Y was minimal.
517                 y = -Math.signum(projectionMatrix[6]) * z * Math.signum(projectionMatrix[10]);
518                 if (y == 0) {
519                     y = +1;
520                 }
521                 break;
522             case MIDDLE:
523                 z = Math.signum(projectionMatrix[9]);  // First : switch Z such that Y was maximal.
524                 y = 0;
525                 break;
526             case TOP:
527                 z = Math.signum(projectionMatrix[9]);  // First : switch Z such that Y was maximal.
528                 y = -Math.signum(projectionMatrix[6]) * z * Math.signum(projectionMatrix[10]);
529                 if (y == 0) {
530                     y = -1;
531                 }
532                 break;
533             case ORIGIN:
534                 z = Math.signum(projectionMatrix[9]);  // First : switch Z such that Y was maximal.
535                 y = (reverse ? -1 : 1) * (bounds[3] + bounds[2]) / (bounds[3] - bounds[2]);
536                 if (Math.abs(y) > 1) {
537                     y = Math.signum(y);
538                 }
539                 break;
540         }
541         return new Vector3d(0, y, z);
542     }
543
544     private Vector3d computeYAxisPosition(double[] matrix, Double[] bounds, AxisProperty.AxisLocation axisLocation, boolean reverse) {
545         double x, z;
546         switch (axisLocation) {
547             default:
548             case LEFT:
549                 z = -Math.signum(matrix[9]);  // First : switch Z such that Y was minimal.
550                 x = -Math.signum(matrix[2]) * z * Math.signum(matrix[10]);
551                 if (x == 0) {
552                     x = +1;
553                 }
554                 break;
555             case MIDDLE:
556                 z = Math.signum(matrix[9]);  // First : switch Z such that Y was minimal.
557                 x = 0;
558                 break;
559             case RIGHT:
560                 z = Math.signum(matrix[9]);  // First : switch Z such that Y was minimal.
561                 x = -Math.signum(matrix[2]) * z * Math.signum(matrix[10]); // Then switch X such that Z max but not in the middle.
562                 if (x == 0) {
563                     x = -1;
564                 }
565                 break;
566             case ORIGIN:
567                 z = Math.signum(matrix[9]);  // First : switch Z such that Y was minimal.
568                 x = (reverse ? -1 : 1) * (bounds[1] + bounds[0]) / (bounds[1] - bounds[0]);
569                 if (Math.abs(x) > 1) {
570                     x = Math.signum(x);
571                 }
572                 break;
573         }
574         return new Vector3d(x, 0, z);
575     }
576
577     private String[] toStringArray(double[] values, DecimalFormat format) {
578         AxesRulerSpriteFactory.setScilabStyle(format);
579         String[] r = new String[values.length];
580         for (int i = 0; i < values.length; i++) {
581             r[i] = format.format(values[i], new StringBuffer(), new FieldPosition(0)).toString();
582         }
583         return r;
584     }
585
586     private Double[] toDoubleArray(double[] values) {
587         Double[] r = new Double[values.length];
588         for (int i = 0; i < values.length; i++) {
589             r[i] = values[i];
590         }
591         return r;
592     }
593
594     /**
595      * Build X grid data.
596      * @param values X values where grid is drawn.
597      * @param rulerModel used rulerModel to compute grid world position.
598      * @return X grid data.
599      */
600     private FloatBuffer getXGridData(List<Double> values, RulerModel rulerModel) {
601         FloatBuffer vertexData = FloatBuffer.allocate(values.size() * 16);
602         for (double value : values) {
603             float p = (float) rulerModel.getPosition(value).getX();
604             vertexData.put(p);
605             vertexData.put(+1);
606             vertexData.put(+1);
607             vertexData.put(1);
608             vertexData.put(p);
609             vertexData.put(-1);
610             vertexData.put(+1);
611             vertexData.put(1);
612             vertexData.put(p);
613             vertexData.put(+1);
614             vertexData.put(+1);
615             vertexData.put(1);
616             vertexData.put(p);
617             vertexData.put(+1);
618             vertexData.put(-1);
619             vertexData.put(1);
620         }
621         vertexData.rewind();
622         return vertexData;
623     }
624
625     /**
626      * Build Y grid data.
627      * @param values Y values where grid is drawn.
628      * @param rulerModel used rulerModel to compute grid world position.
629      * @return Y grid data.
630      */
631     private FloatBuffer getYGridData(List<Double> values, RulerModel rulerModel) {
632         FloatBuffer vertexData = FloatBuffer.allocate(values.size() * 16);
633         for (double value : values) {
634             float p = (float) rulerModel.getPosition(value).getY();
635             vertexData.put(+1);
636             vertexData.put(p);
637             vertexData.put(+1);
638             vertexData.put(1);
639             vertexData.put(-1);
640             vertexData.put(p);
641             vertexData.put(+1);
642             vertexData.put(1);
643             vertexData.put(+1);
644             vertexData.put(p);
645             vertexData.put(+1);
646             vertexData.put(1);
647             vertexData.put(+1);
648             vertexData.put(p);
649             vertexData.put(-1);
650             vertexData.put(1);
651         }
652         vertexData.rewind();
653         return vertexData;
654     }
655
656     /**
657      * Build Z grid data.
658      * @param values Z values where grid is drawn.
659      * @param rulerModel used rulerModel to compute grid world position.
660      * @return Z grid data.
661      */
662     private FloatBuffer getZGridData(List<Double> values, RulerModel rulerModel) {
663         FloatBuffer vertexData = FloatBuffer.allocate(values.size() * 16);
664         int limit = 0;
665         for (double value : values) {
666             float p = (float) rulerModel.getPosition(value).getZ();
667             vertexData.put(+1);
668             vertexData.put(+1);
669             vertexData.put(p);
670             vertexData.put(1);
671             vertexData.put(-1);
672             vertexData.put(+1);
673             vertexData.put(p);
674             vertexData.put(1);
675             vertexData.put(+1);
676             vertexData.put(+1);
677             vertexData.put(p);
678             vertexData.put(1);
679             vertexData.put(+1);
680             vertexData.put(-1);
681             vertexData.put(p);
682             vertexData.put(1);
683             limit += 16;
684         }
685         vertexData.limit(limit);
686         return vertexData;
687     }
688
689     public void disposeAll() {
690         this.rulerDrawerManager.disposeAll();
691     }
692
693     public boolean update(Integer id, int property) {
694         return this.rulerDrawerManager.update(id, property);
695     }
696
697     public void dispose(Integer id) {
698         this.rulerDrawerManager.dispose(id);
699     }
700 }