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