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