147277c0e8dafbfd36457f63043c5042618d0ca5
[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                     vertexData = getXGridData(rulerDrawers[0].getSubTicksValue(), rulerDrawers[0].getModel());
337                 } else {
338                     vertexData = getXGridData(rulerDrawers[0].getTicksValue(), rulerDrawers[0].getModel());
339                 }
340                 vertexBuffer.setData(vertexData, 4);
341
342                 Transformation mirror;
343                 try {
344                     mirror = TransformationFactory.getScaleTransformation(
345                                  1,
346                                  matrix[6] < 0 ? gridPosition : -gridPosition,
347                                  matrix[10] < 0 ? gridPosition : -gridPosition
348                              );
349                 } catch (DegenerateMatrixException ignored) {
350                     // Should never happens as long as gridPosition the value 1 or -1
351                     mirror = TransformationFactory.getIdentity();
352                 }
353
354                 gridAppearance.setLineColor(ColorFactory.createColor(colorMap, axes.getXAxisGridColor()));
355                 drawingTools.getTransformationManager().getModelViewStack().pushRightMultiply(mirror);
356                 DefaultGeometry gridGeometry = new DefaultGeometry();
357                 gridGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
358                 gridGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
359                 gridGeometry.setVertices(vertexBuffer);
360                 drawingTools.draw(gridGeometry, gridAppearance);
361                 drawingTools.getTransformationManager().getModelViewStack().pop();
362             }
363         }
364
365         // Draw Y ruler
366         if (axes.getYAxisVisible()) {
367             rulerDrawers[1].draw(drawingTools);
368
369             if (axes.getYAxisGridColor() != -1) {
370                 FloatBuffer vertexData;
371                 if (axes.getYAxisLogFlag()) {
372                     vertexData = getYGridData(rulerDrawers[1].getSubTicksValue(), rulerDrawers[1].getModel());
373                 } else {
374                     vertexData = getYGridData(rulerDrawers[1].getTicksValue(), rulerDrawers[1].getModel());
375                 }
376                 vertexBuffer.setData(vertexData, 4);
377
378                 Transformation mirror;
379                 try {
380                     mirror = TransformationFactory.getScaleTransformation(
381                                  matrix[2] < 0 ? gridPosition : -gridPosition,
382                                  1,
383                                  matrix[10] < 0 ? gridPosition : -gridPosition
384                              );
385                 } catch (DegenerateMatrixException ignored) {
386                     // Should never happens as long as gridPosition the value 1 or -1
387                     mirror = TransformationFactory.getIdentity();
388                 }
389
390                 gridAppearance.setLineColor(ColorFactory.createColor(colorMap, axes.getYAxisGridColor()));
391                 drawingTools.getTransformationManager().getModelViewStack().pushRightMultiply(mirror);
392                 DefaultGeometry gridGeometry = new DefaultGeometry();
393                 gridGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
394                 gridGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
395                 gridGeometry.setVertices(vertexBuffer);
396                 drawingTools.draw(gridGeometry, gridAppearance);
397                 drawingTools.getTransformationManager().getModelViewStack().pop();
398             }
399         }
400
401         // Draw Z ruler
402         if (is3D) {
403             if (axes.getZAxisVisible()) {
404                 rulerDrawers[2].draw(drawingTools);
405
406                 if (axes.getZAxisGridColor() != -1 || !axes.getZAxisVisible()) {
407                     FloatBuffer vertexData;
408                     if (axes.getZAxisLogFlag()) {
409                         vertexData = getZGridData(rulerDrawers[2].getSubTicksValue(), rulerDrawers[2].getModel());
410                     } else {
411                         vertexData = getZGridData(rulerDrawers[2].getTicksValue(), rulerDrawers[2].getModel());
412                     }
413                     vertexBuffer.setData(vertexData, 4);
414
415                     Transformation mirror;
416                     try {
417                         mirror = TransformationFactory.getScaleTransformation(
418                                      matrix[2] < 0 ? gridPosition : -gridPosition,
419                                      matrix[6] < 0 ? gridPosition : -gridPosition,
420                                      1
421                                  );
422                     } catch (DegenerateMatrixException ignored) {
423                         // Should never happens as long as gridPosition the value 1 or -1
424                         mirror = TransformationFactory.getIdentity();
425                     }
426
427                     gridAppearance.setLineColor(ColorFactory.createColor(colorMap, axes.getZAxisGridColor()));
428                     drawingTools.getTransformationManager().getModelViewStack().pushRightMultiply(mirror);
429                     DefaultGeometry gridGeometry = new DefaultGeometry();
430                     gridGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
431                     gridGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
432                     gridGeometry.setVertices(vertexBuffer);
433                     drawingTools.draw(gridGeometry, gridAppearance);
434                     drawingTools.getTransformationManager().getModelViewStack().pop();
435                 }
436             }
437         }
438
439         drawingTools.getCanvas().getBuffersManager().dispose(vertexBuffer);
440     }
441
442     private double getNonZeroSignum(double value) {
443         if (value < 0) {
444             return -1;
445         } else {
446             return 1;
447         }
448     }
449
450     private void setRulerBounds(AxisProperty axis, DefaultRulerModel rulerModel, double axisMin, double axisMax) {
451         double min, max;
452         if (axis.getReverse()) {
453             min = axisMin;
454             max = axisMax;
455         } else {
456             min = axisMax;
457             max = axisMin;
458         }
459
460         if (axis.getLogFlag()) {
461             min = Math.pow(10, min);
462             max = Math.pow(10, max);
463         }
464         rulerModel.setValues(min, max);
465     }
466
467     private Vector3d computeXAxisPosition(double[] projectionMatrix, Double[] bounds, AxisProperty.AxisLocation axisLocation) {
468         double y, z;
469         switch (axisLocation) {
470             default:
471             case BOTTOM:
472                 z = -Math.signum(projectionMatrix[9]);  // First : switch Z such that Y was minimal.
473                 y = -Math.signum(projectionMatrix[6]) * z * Math.signum(projectionMatrix[10]);
474                 if (y == 0) {
475                     y = +1;
476                 }
477                 break;
478             case MIDDLE:
479                 z = Math.signum(projectionMatrix[9]);  // First : switch Z such that Y was maximal.
480                 y = 0;
481                 break;
482             case TOP:
483                 z = Math.signum(projectionMatrix[9]);  // First : switch Z such that Y was maximal.
484                 y = -Math.signum(projectionMatrix[6]) * z * Math.signum(projectionMatrix[10]);
485                 if (y == 0) {
486                     y = -1;
487                 }
488                 break;
489             case ORIGIN:
490                 z = Math.signum(projectionMatrix[9]);  // First : switch Z such that Y was maximal.
491                 y = (bounds[3] + bounds[2]) / (bounds[3] - bounds[2]);
492                 if (Math.abs(y) > 1) {
493                     y = Math.signum(y);
494                 }
495                 break;
496         }
497         return new Vector3d(0, y, z);
498     }
499
500     private Vector3d computeYAxisPosition(double[] matrix, Double[] bounds, AxisProperty.AxisLocation axisLocation) {
501         double x, z;
502         switch (axisLocation) {
503             default:
504             case LEFT:
505                 z = -Math.signum(matrix[9]);  // First : switch Z such that Y was minimal.
506                 x = -Math.signum(matrix[2]) * z * Math.signum(matrix[10]);
507                 if (x == 0) {
508                     x = +1;
509                 }
510                 break;
511             case MIDDLE:
512                 z = Math.signum(matrix[9]);  // First : switch Z such that Y was minimal.
513                 x = 0;
514                 break;
515             case RIGHT:
516                 z = Math.signum(matrix[9]);  // First : switch Z such that Y was minimal.
517                 x = -Math.signum(matrix[2]) * z * Math.signum(matrix[10]); // Then switch X such that Z max but not in the middle.
518                 if (x == 0) {
519                     x = -1;
520                 }
521                 break;
522             case ORIGIN:
523                 z = Math.signum(matrix[9]);  // First : switch Z such that Y was minimal.
524                 x = (bounds[1] + bounds[0]) / (bounds[1] - bounds[0]);
525                 if (Math.abs(x) > 1) {
526                     x = Math.signum(x);
527                 }
528                 break;
529         }
530         return new Vector3d(x, 0, z);
531     }
532
533     private String[] toStringArray(double[] values, DecimalFormat format) {
534         AxesRulerSpriteFactory.setScilabStyle(format);
535         String[] r = new String[values.length];
536         for (int i = 0; i < values.length; i++) {
537             r[i] = format.format(values[i]);
538         }
539         return r;
540     }
541
542     private Double[] toDoubleArray(double[] values) {
543         Double[] r = new Double[values.length];
544         for (int i = 0; i < values.length; i++) {
545             r[i] = values[i];
546         }
547         return r;
548     }
549
550     /**
551      * Build X grid data.
552      * @param values X values where grid is drawn.
553      * @param rulerModel used rulerModel to compute grid world position.
554      * @return X grid data.
555      */
556     private FloatBuffer getXGridData(List<Double> values, RulerModel rulerModel) {
557         FloatBuffer vertexData = FloatBuffer.allocate(values.size() * 16);
558         for (double value : values) {
559             float p = (float) rulerModel.getPosition(value).getX();
560             vertexData.put(p);
561             vertexData.put(+1);
562             vertexData.put(+1);
563             vertexData.put(1);
564             vertexData.put(p);
565             vertexData.put(-1);
566             vertexData.put(+1);
567             vertexData.put(1);
568             vertexData.put(p);
569             vertexData.put(+1);
570             vertexData.put(+1);
571             vertexData.put(1);
572             vertexData.put(p);
573             vertexData.put(+1);
574             vertexData.put(-1);
575             vertexData.put(1);
576         }
577         vertexData.rewind();
578         return vertexData;
579     }
580
581     /**
582      * Build Y grid data.
583      * @param values Y values where grid is drawn.
584      * @param rulerModel used rulerModel to compute grid world position.
585      * @return Y grid data.
586      */
587     private FloatBuffer getYGridData(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).getY();
591             vertexData.put(+1);
592             vertexData.put(p);
593             vertexData.put(+1);
594             vertexData.put(1);
595             vertexData.put(-1);
596             vertexData.put(p);
597             vertexData.put(+1);
598             vertexData.put(1);
599             vertexData.put(+1);
600             vertexData.put(p);
601             vertexData.put(+1);
602             vertexData.put(1);
603             vertexData.put(+1);
604             vertexData.put(p);
605             vertexData.put(-1);
606             vertexData.put(1);
607         }
608         vertexData.rewind();
609         return vertexData;
610     }
611
612     /**
613      * Build Z grid data.
614      * @param values Z values where grid is drawn.
615      * @param rulerModel used rulerModel to compute grid world position.
616      * @return Z grid data.
617      */
618     private FloatBuffer getZGridData(List<Double> values, RulerModel rulerModel) {
619         FloatBuffer vertexData = FloatBuffer.allocate(values.size() * 16);
620         int limit = 0;
621         for (double value : values) {
622             float p = (float) rulerModel.getPosition(value).getZ();
623             vertexData.put(+1);
624             vertexData.put(+1);
625             vertexData.put(p);
626             vertexData.put(1);
627             vertexData.put(-1);
628             vertexData.put(+1);
629             vertexData.put(p);
630             vertexData.put(1);
631             vertexData.put(+1);
632             vertexData.put(+1);
633             vertexData.put(p);
634             vertexData.put(1);
635             vertexData.put(+1);
636             vertexData.put(-1);
637             vertexData.put(p);
638             vertexData.put(1);
639             limit += 16;
640         }
641         vertexData.limit(limit);
642         return vertexData;
643     }
644
645     public void disposeAll() {
646         this.rulerDrawerManager.disposeAll();
647     }
648
649     public boolean update(String id, int property) {
650         return this.rulerDrawerManager.update(id, property);
651     }
652
653     public void dispose(String id) {
654         this.rulerDrawerManager.dispose(id);
655     }
656 }