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