Bug 11982 fixed: ticks computation were made when drawing
[scilab.git] / scilab / modules / renderer / src / java / org / scilab / modules / renderer / JoGLView / label / LabelManager.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-2012 - 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.label;
15
16 import org.scilab.forge.scirenderer.DrawingTools;
17 import org.scilab.forge.scirenderer.SciRendererException;
18 import org.scilab.forge.scirenderer.texture.AnchorPosition;
19 import org.scilab.forge.scirenderer.texture.Texture;
20 import org.scilab.forge.scirenderer.texture.TextureManager;
21 import org.scilab.forge.scirenderer.tranformations.Transformation;
22 import org.scilab.forge.scirenderer.tranformations.Vector3d;
23 import org.scilab.modules.graphic_objects.axes.Axes;
24 import org.scilab.modules.graphic_objects.axes.Camera;
25 import org.scilab.modules.graphic_objects.figure.ColorMap;
26 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
27 import org.scilab.modules.graphic_objects.label.Label;
28 import org.scilab.modules.graphic_objects.utils.Utils;
29 import org.scilab.modules.renderer.JoGLView.axes.AxesDrawer;
30 import org.scilab.modules.renderer.JoGLView.util.ScaleUtils;
31
32 import java.util.Map;
33 import java.util.concurrent.ConcurrentHashMap;
34
35 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_AUTO_POSITION__;
36 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_AUTO_ROTATION__;
37 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_FONT_ANGLE__;
38 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_POSITION__;
39
40 /**
41  *
42  * This class performs the drawing of scilab's Label entity.
43  *
44  * TODO, manage: {font_fractional}
45  *
46  * @author Manuel Juliachs
47  */
48 public class LabelManager {
49
50     /**
51      * The {@see Map} of existing {@see Sprite}.
52      */
53     private final Map<String, Texture> textureMap = new ConcurrentHashMap<String, Texture>();
54
55     /**
56      * The used sprite manager.
57      */
58     private final TextureManager textureManager;
59
60     /**
61      * Default constructor.
62      * @param textureManager the texture manager.
63      */
64     public LabelManager(TextureManager textureManager) {
65         this.textureManager = textureManager;
66     }
67
68     /**
69      * Draws the given {@see Label} with the given {@see DrawingTools}.
70      * @param drawingTools the given {@see DrawingTools}.
71      * @param colorMap the current {@see ColorMap}.
72      * @param label the given Scilab {@see Label}.
73      * @param axesDrawer the Axes drawer used to draw the label's parent Axes.
74      * @throws SciRendererException if the label is not drawable.
75      */
76     public void draw(final DrawingTools drawingTools, final ColorMap colorMap, final Label label, AxesDrawer axesDrawer) throws SciRendererException {
77         /* Only the z-axis Label may not be drawn depending on the view mode */
78         boolean drawnFlag = true;
79         String parentId;
80         String labelId = label.getIdentifier();
81         LabelPositioner labelPositioner;
82
83         parentId = label.getParentAxes();
84
85         if (parentId == null) {
86             return;
87         }
88
89         Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(parentId);
90
91         /* Get the positioner associated to the label */
92         if (parentAxes.getXAxisLabel().equals(label.getIdentifier())) {
93             labelPositioner = axesDrawer.getXAxisLabelPositioner(parentAxes);
94         } else if (parentAxes.getYAxisLabel().equals(label.getIdentifier())) {
95             labelPositioner = axesDrawer.getYAxisLabelPositioner(parentAxes);
96         } else if (parentAxes.getZAxisLabel().equals(label.getIdentifier())) {
97             labelPositioner = axesDrawer.getZAxisLabelPositioner(parentAxes);
98             drawnFlag = (parentAxes.getViewAsEnum() == Camera.ViewType.VIEW_3D);
99         } else if (parentAxes.getTitle().equals(label.getIdentifier())) {
100             labelPositioner = axesDrawer.getTitlePositioner(parentAxes);
101         } else {
102             /* Do not do anything */
103             return;
104         }
105
106         /*
107          * The topmost transformation, which is the data transformation, must be popped before drawing
108          * and restored afterwards because Labels, like Axes rulers, are drawn in box coordinates.
109          */
110         drawingTools.getTransformationManager().getModelViewStack().pop();
111
112         positionAndDraw(drawingTools, colorMap, label, labelPositioner, parentAxes, axesDrawer, drawnFlag);
113
114         drawingTools.getTransformationManager().getModelViewStack().pushRightMultiply(axesDrawer.getDataTransformation());
115     }
116
117     /**
118      * Positions and draws the given Scilab {@see Label} with the given {@see DrawingTools}.
119      * First, it initializes the label positioner's remaining parameters which have not been previously
120      * obtained from the axis ruler drawer. It then asks the positioner the relevant values and
121      * finally draws the label's sprite using these resulting values.
122      * @param drawingTools the given {@see DrawingTools}.
123      * @param colorMap the current {@see ColorMap}.
124      * @param label the given Scilab {@see Label}.
125      * @param labelPositioner the positioner used to compute the label's position.
126      * @param parentAxes the label's parent Axes.
127      * @param axesDrawer the Axes drawer used to draw the label's parent Axes.
128      * @param drawnFlag a flag indicating whether the label must be drawn or not.
129      * @throws SciRendererException if the label is not drawable.
130      */
131     public final void positionAndDraw(final DrawingTools drawingTools, final ColorMap colorMap, final Label label, LabelPositioner labelPositioner, Axes parentAxes, AxesDrawer axesDrawer, boolean drawnFlag) throws SciRendererException {
132         boolean[] logFlags = new boolean[] {parentAxes.getXAxisLogFlag(), parentAxes.getYAxisLogFlag(), parentAxes.getZAxisLogFlag()};
133         Texture labelSprite = getTexture(colorMap, label);
134
135         labelPositioner.setLabelTexture(labelSprite);
136         labelPositioner.setDrawingTools(drawingTools);
137         labelPositioner.setParentAxes(parentAxes);
138         labelPositioner.setAutoPosition(label.getAutoPosition());
139         labelPositioner.setAutoRotation(label.getAutoRotation());
140         labelPositioner.setUserRotationAngle(180.0 * label.getFontAngle() / Math.PI);
141
142         Vector3d labelUserPosition = new Vector3d(label.getPosition());
143
144         /* Logarithmic scaling must be applied to the label's user position to obtain object coordinates */
145         labelUserPosition = ScaleUtils.applyLogScale(labelUserPosition, logFlags);
146
147         labelUserPosition = axesDrawer.getBoxCoordinates(labelUserPosition);
148         labelPositioner.setLabelUserPosition(labelUserPosition);
149
150         /* Computes the label's position values */
151         labelPositioner.positionLabel();
152
153         Vector3d labelPos = labelPositioner.getAnchorPoint();
154         AnchorPosition labelAnchor = labelPositioner.getAnchorPosition();
155
156         /* Set the lower-left corner position if auto-positioned */
157         if (label.getAutoPosition()) {
158             Vector3d cornerPos = labelPositioner.getLowerLeftCornerPosition();
159             Vector3d objectCornerPos = axesDrawer.getObjectCoordinates(cornerPos);
160
161             /* Apply inverse scaling to obtain user coordinates */
162             objectCornerPos = ScaleUtils.applyInverseLogScale(objectCornerPos, logFlags);
163
164             label.setPosition(new Double[] {objectCornerPos.getX(), objectCornerPos.getY(), objectCornerPos.getZ()});
165
166             /*
167              * Must be reset to true as setPosition modifies the label's auto position field.
168              * To be modified.
169              */
170             label.setAutoPosition(true);
171         }
172
173         /* Compute and set the label's corners */
174         Transformation projection = axesDrawer.getProjection();
175
176         Vector3d[] projCorners = labelPositioner.getProjCorners();
177
178         Vector3d[] corners = computeCorners(projection, projCorners, parentAxes);
179         Double[] coordinates = cornersToCoordinateArray(corners);
180
181         /* Set the computed coordinates */
182         label.setCorners(coordinates);
183
184
185         double rotationAngle = 0.0;
186
187         if (label.getAutoRotation()) {
188             rotationAngle = labelPositioner.getRotationAngle();
189
190             label.setFontAngle(Math.PI * rotationAngle / 180.0);
191
192             /*
193              * Must be reset to true as setFontAngle modifies the label's auto rotation field.
194              * To be modified.
195              */
196             label.setAutoRotation(true);
197         } else {
198             rotationAngle = labelPositioner.getUserRotationAngle();
199         }
200
201         /* The label's rotation direction convention is opposite to the standard one. */
202         rotationAngle = -rotationAngle;
203
204         if (label.getVisible() && drawnFlag) {
205             if (Utils.isValid(labelPos.getX(), labelPos.getY(), labelPos.getZ()) && Utils.isValid(rotationAngle)) {
206                 if (labelPositioner.getUseWindowCoordinates()) {
207                     /* Draw in window coordinates */
208                     Transformation canvasProjection = drawingTools.getTransformationManager().getCanvasProjection();
209                     Vector3d projLabelPos = canvasProjection.project(labelPos);
210
211                     drawingTools.getTransformationManager().useWindowCoordinate();
212                     drawingTools.draw(labelSprite, labelAnchor, projLabelPos, rotationAngle);
213                     drawingTools.getTransformationManager().useSceneCoordinate();
214                 } else {
215                     /* Draw using box coordinates */
216                     drawingTools.draw(labelSprite, labelAnchor, labelPos, rotationAngle);
217                 }
218             }
219         }
220
221     }
222
223     /**
224      * Computes and returns the corners (in user coordinates) of a label's bounding box.
225      * @param projection the projection from object coordinates to window coordinates.
226      * @param projCorners the corners of the label's bounding box in window coordinates (4-element array).
227      * @param parentAxes the Axes for which the coordinates are computed.
228      * @return the corners of the label's bounding box in user coordinates (4-element array).
229      */
230     private Vector3d[] computeCorners(Transformation projection, Vector3d[] projCorners, Axes parentAxes) {
231         Vector3d[] corners = new Vector3d[4];
232         boolean[] logFlags = new boolean[] {parentAxes.getXAxisLogFlag(), parentAxes.getYAxisLogFlag(), parentAxes.getZAxisLogFlag()};
233
234         corners[0] = projection.unproject(projCorners[0]);
235         corners[1] = projection.unproject(projCorners[1]);
236         corners[2] = projection.unproject(projCorners[2]);
237         corners[3] = projection.unproject(projCorners[3]);
238
239         /* Apply inverse logarithmic scaling in order to obtain user coordinates */
240         corners[0] = ScaleUtils.applyInverseLogScale(corners[0], logFlags);
241         corners[1] = ScaleUtils.applyInverseLogScale(corners[1], logFlags);
242         corners[2] = ScaleUtils.applyInverseLogScale(corners[2], logFlags);
243         corners[3] = ScaleUtils.applyInverseLogScale(corners[3], logFlags);
244
245         return corners;
246     }
247
248     /**
249      * Returns the positions of a bounding box's corners as an array of (x,y,z) coordinate triplets.
250      * The output corners are reordered to match their order in the {@see Label} object's
251      * equivalent array, respectively: lower-left, lower-right, upper-left, upper-right in the input array,
252      * starting from the lower-left and going in clockwise order in the returned array.
253      * @param corners of the bounding box (4-element array).
254      * @return the corners' coordinates (12-element array).
255      */
256     private Double[] cornersToCoordinateArray(Vector3d[] corners) {
257         Double[] coordinates = new Double[12];
258         coordinates[0] = corners[0].getX();
259         coordinates[1] = corners[0].getY();
260         coordinates[2] = corners[0].getZ();
261
262         coordinates[3] = corners[2].getX();
263         coordinates[4] = corners[2].getY();
264         coordinates[5] = corners[2].getZ();
265
266         coordinates[6] = corners[3].getX();
267         coordinates[7] = corners[3].getY();
268         coordinates[8] = corners[3].getZ();
269
270         coordinates[9] = corners[1].getX();
271         coordinates[10] = corners[1].getY();
272         coordinates[11] = corners[1].getZ();
273
274         return coordinates;
275     }
276
277     /**
278      * Updates the sprite data if needed.
279      * @param id the modified object.
280      * @param property the changed property.
281      */
282     public void update(String id, int property) {
283         if (!(__GO_POSITION__ == property) && !(__GO_AUTO_POSITION__ == property)
284                 && !(__GO_FONT_ANGLE__ == property) && !(__GO_AUTO_ROTATION__ == property)) {
285             dispose(id);
286         }
287     }
288
289     /**
290      * Returns the SciRenderer {@see Sprite} corresponding to the given Scilab {@see Label}.
291      * @param colorMap the current color map.
292      * @param label the given Scilab {@see Label}.
293      * @return the SciRenderer {@see Sprite} corresponding to the given Scilab {@see Label}.
294      */
295     public Texture getTexture(final ColorMap colorMap, final Label label) {
296         Texture texture = textureMap.get(label.getIdentifier());
297         if (texture == null) {
298             texture = createSprite(colorMap, label);
299             textureMap.put(label.getIdentifier(), texture);
300         }
301         return texture;
302     }
303
304     /**
305      * Creates a sprite for the given label.
306      * @param colorMap the current colormap.
307      * @param label the given label.
308      * @return a new sprite for the given label.
309      */
310     private Texture createSprite(final ColorMap colorMap, final Label label) {
311         LabelSpriteDrawer spriteDrawer = new LabelSpriteDrawer(colorMap, label);
312         Texture sprite = textureManager.createTexture();
313         sprite.setMagnificationFilter(Texture.Filter.LINEAR);
314         sprite.setMinifyingFilter(Texture.Filter.LINEAR);
315         sprite.setDrawer(spriteDrawer);
316         return sprite;
317     }
318
319     /**
320      * Disposes the texture corresponding to the given id.
321      * @param id the given id.
322      */
323     public void dispose(String id) {
324         Texture texture = textureMap.get(id);
325         if (texture != null) {
326             textureManager.dispose(texture);
327             textureMap.remove(id);
328         }
329     }
330
331     /**
332      * Disposes all the label text sprites.
333      */
334     public void disposeAll() {
335         textureManager.dispose(textureMap.values());
336         textureMap.clear();
337     }
338 }