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