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