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