Allow mutiplie axes within frames.
[scilab.git] / scilab / modules / renderer / src / java / org / scilab / modules / renderer / JoGLView / text / TextManager.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) 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.1-en.txt
11  */
12
13 package org.scilab.modules.renderer.JoGLView.text;
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.DegenerateMatrixException;
21 import org.scilab.forge.scirenderer.tranformations.Transformation;
22 import org.scilab.forge.scirenderer.tranformations.TransformationFactory;
23 import org.scilab.forge.scirenderer.tranformations.Vector3d;
24 import org.scilab.modules.graphic_objects.axes.Axes;
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.graphicObject.GraphicObjectProperties;
28 import org.scilab.modules.graphic_objects.textObject.Text;
29 import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
30 import org.scilab.modules.renderer.JoGLView.util.ScaleUtils;
31
32 import java.awt.Dimension;
33 import java.util.Map;
34 import java.util.concurrent.ConcurrentHashMap;
35
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 manage scilab text entity drawing.
42  *
43  *
44  * TODO, Manage: {auto_dimensionning}
45  *
46  *
47  * @author Pierre Lando
48  */
49 public class TextManager {
50
51     /**
52      * The {@see Map} off existing {@see TextEntity}.
53      */
54     protected final Map<Integer, Texture> spriteMap = new ConcurrentHashMap<Integer, Texture>();
55
56     /**
57      * The used texture manager.
58      */
59     protected final TextureManager textureManager;
60
61     /**
62      * The bounds of the scale factor range for which the texture does not
63      * need to be updated.
64      */
65     protected double[] FACTOR_UPDATE_INTERVAL = {0.99, 1.01};
66
67     /**
68      * Default constructor.
69      * @param textureManager the texture manager.
70      */
71     public TextManager(TextureManager textureManager) {
72         this.textureManager = textureManager;
73     }
74
75     /**
76      * Draw the given Scilab {@see Text} with the given {@see DrawingTools}.
77      * @param drawingTools the given {@see DrawingTools}.
78      * @param colorMap the current {@see ColorMap}
79      * @param text the given Scilab {@see Text}
80      * @throws SciRendererException if the draw fails.
81      */
82     public final void draw(final DrawingTools drawingTools, final ColorMap colorMap, final Text text) throws SciRendererException {
83         Texture texture = getTexture(colorMap, text);
84
85         /* The unscaled texture's dimensions */
86         Dimension spriteDims = getSpriteDims(colorMap, text);
87
88         Transformation projection = drawingTools.getTransformationManager().getCanvasProjection();
89
90         Integer parentAxesId = text.getParentAxes();
91         Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(parentAxesId);
92         double[][] factors = parentAxes.getScaleTranslateFactors();
93         Double[] pos = text.getPosition();
94         pos[0] = pos[0] * factors[0][0] + factors[1][0];
95         pos[1] = pos[1] * factors[0][1] + factors[1][1];
96         pos[2] = pos[2] * factors[0][2] + factors[1][2];
97
98         Vector3d textPosition = new Vector3d(pos);
99
100         /* Compute the text box vectors and the text box to texture dimension ratios */
101         Vector3d[] textBoxVectors =  computeTextBoxVectors(projection, text, texture.getDataProvider().getTextureSize(), parentAxes);
102         double[] ratios = computeRatios(projection, text, textBoxVectors, texture.getDataProvider().getTextureSize(), spriteDims);
103
104         /* If text box mode is equal to filled, the texture must be updated */
105         if (text.getTextBoxMode() == 2 && ratios[0] != 1.0) {
106             texture = updateSprite(colorMap, text, ratios[0], ratios[1]);
107         }
108
109         /* Compute the text texture's actual position, which depends on the object's text box mode property */
110         Vector3d[] cornerPositions = computeTextPosition(projection, text, textBoxVectors, texture.getDataProvider().getTextureSize());
111
112         /* Draw in window coordinates */
113         drawingTools.getTransformationManager().useWindowCoordinate();
114
115         /* The Text object's rotation direction convention is opposite to the standard one, its angle is expressed in radians. */
116         drawingTools.draw(texture, AnchorPosition.LOWER_LEFT, cornerPositions[0], -180.0 * text.getFontAngle() / Math.PI);
117
118         drawingTools.getTransformationManager().useSceneCoordinate();
119
120         /* Compute the corners of the text's bounding box in window coordinates */
121         Vector3d[] projCorners;
122         if (text.getTextBoxMode() == 2) {
123             projCorners = computeProjTextBoxCorners(cornerPositions[1], text.getFontAngle(), textBoxVectors);
124         } else {
125             projCorners = computeProjCorners(cornerPositions[0], text.getFontAngle(), texture.getDataProvider().getTextureSize());
126         }
127
128         Vector3d[] corners = computeCorners(projection, projCorners, parentAxes);
129         Double[] coordinates = cornersToCoordinateArray(corners);
130
131         /* Set the computed coordinates */
132         text.setCorners(coordinates);
133     }
134
135     /**
136      * Computes and returns the two vectors (in window coordinates) respectively corresponding
137      * to the text box's base and side (also named the text box width and height vectors). If the
138      * Text's text box mode is equal to off, the vectors are then equal to the Text label's base
139      * and side vectors.  The Text's rotation is ignored, as it is not required for now.
140      * @param projection the projection from object coordinates to window coordinates.
141      * @param text the Scilab {@see Text}.
142      * @param dimension the current text texture's dimension (in pixels).
143      * @param parentAxes the Axes for which the coordinates are computed.
144      * @return the text box width and height vectors (in window coordinates).
145      */
146     protected Vector3d[] computeTextBoxVectors(Transformation projection, Text text, Dimension dimension, Axes parentAxes) {
147         Double[] textBox = text.getTextBox();
148         Vector3d[] textBoxVectors = new Vector3d[2];
149         double[][] factors = parentAxes.getScaleTranslateFactors();
150         Double[] pos = text.getPosition();
151
152         /* The text position vector before logarithmic scaling */
153         Vector3d textPosition = new Vector3d(pos);
154
155         boolean[] logFlags = new boolean[] {parentAxes.getXAxisLogFlag(), parentAxes.getYAxisLogFlag(), parentAxes.getZAxisLogFlag()};
156
157         /* Apply logarithmic scaling and then project */
158         textPosition = ScaleUtils.applyLogScale(textPosition, logFlags);
159         textPosition = new Vector3d(textPosition.getX() * factors[0][0] + factors[1][0], textPosition.getY() * factors[0][1] + factors[1][1], textPosition.getZ() * factors[0][2] + factors[1][2]);
160         Vector3d projTextPosition = projection.project(textPosition);
161
162         /* Compute the text label vectors in window coordinates */
163         Vector3d width = new Vector3d(dimension.getWidth(), 0.0, 0.0);
164         Vector3d height = new Vector3d(0.0, dimension.getHeight(), 0.0);
165
166         Vector3d projTextWidth = projTextPosition.plus(width);
167         Vector3d projTextHeight = projTextPosition.plus(height);
168
169         /*
170          * Compute the text box's vectors in object coordinates, from the object coordinate text label vectors.
171          * Their norms are unaffected by the text's rotation, which is thus ignored.
172          */
173         Vector3d textWidth = projection.unproject(projTextWidth);
174         Vector3d textHeight = projection.unproject(projTextHeight);
175
176         /* Applies inverse logarithmic scaling */
177         textWidth = ScaleUtils.applyInverseLogScale(textWidth, logFlags);
178         textHeight = ScaleUtils.applyInverseLogScale(textHeight, logFlags);
179
180         textWidth = textWidth.minus(textPosition);
181         textHeight = textHeight.minus(textPosition);
182
183         if (text.getTextBoxMode() >= 1) {
184             textWidth = textWidth.getNormalized().times(textBox[0] * factors[0][0]);
185             textHeight = textHeight.getNormalized().times(textBox[1] * factors[0][1]);
186         }
187
188         /*
189          * We take into account the reverse axes flags in order to
190          * compute the actual text box corners, and hence the correct vectors,
191          * which is necessary when logarithmic scaling is applied.
192          */
193         if (parentAxes.getXAxisReverse()) {
194             textWidth = textWidth.setX(Math.abs(textWidth.getX()));
195             textHeight = textHeight.setX(Math.abs(textHeight.getX()));
196         }
197         if (parentAxes.getYAxisReverse()) {
198             textWidth = textWidth.setY(Math.abs(textWidth.getY()));
199             textHeight = textHeight.setY(Math.abs(textHeight.getY()));
200         }
201         if (parentAxes.getZAxisReverse()) {
202             textWidth = textWidth.setZ(Math.abs(textWidth.getZ()));
203             textHeight = textHeight.setZ(Math.abs(textHeight.getZ()));
204         }
205
206         /* Computes the lower-right and upper-left corners. */
207         textWidth = textWidth.plus(textPosition);
208         textHeight = textHeight.plus(textPosition);
209
210         /* Finally re-apply logarithmic scaling, compute the vectors and project */
211         textWidth = ScaleUtils.applyLogScale(textWidth, logFlags);
212         textHeight = ScaleUtils.applyLogScale(textHeight, logFlags);
213
214         textWidth = textWidth.minus(textPosition);
215         textHeight = textHeight.minus(textPosition);
216
217         projTextWidth = projection.projectDirection(textWidth);
218         projTextHeight = projection.projectDirection(textHeight);
219
220         /*
221          * Ensures that the two window-coordinate base vectors respectively point to the right
222          * and to the top, as taking reversed axes into account may have reversed them (see above).
223          */
224         projTextWidth = projTextWidth.setX(Math.abs(projTextWidth.getX()));
225         projTextHeight = projTextHeight.setX(Math.abs(projTextHeight.getX()));
226         projTextWidth = projTextWidth.setY(Math.abs(projTextWidth.getY()));
227         projTextHeight = projTextHeight.setY(Math.abs(projTextHeight.getY()));
228
229         textBoxVectors[0] = projTextWidth;
230         textBoxVectors[1] = projTextHeight;
231
232         return textBoxVectors;
233     }
234
235     /**
236      * Computes and returns the minimum of the ratios between the text box and the text texture's dimensions.
237      * This minimum ratio is determined for both the current text texture and the unscaled text texture.
238      * @param projection the projection from object coordinates to window coordinates.
239      * @param text the Scilab {@see Text}.
240      * @param textBoxVectors the text box width and height vectors (in window coordinates).
241      * @param spriteDimension the current text texture's dimension (in pixels).
242      * @param baseSpriteDimension the unscaled text texture's dimension (in pixels).
243      * @return the minimum ratios (2 elements: text box to current texture and text box to unscaled texture ratios).
244      */
245     protected double[] computeRatios(Transformation projection, Text text, Vector3d[] textBoxVectors, Dimension spriteDimension,
246                                      Dimension baseSpriteDimension) {
247         /* 1st element: ratio for the current texture, 2nd element: ratio for the unscaled texture */
248         double[] ratios = new double[] {1.0, 1.0};
249
250         /* Ratios are relevant only to the filled text box mode */
251         if (text.getTextBoxMode() == 2) {
252             Vector3d textBoxWidth = textBoxVectors[0];
253             Vector3d textBoxHeight = textBoxVectors[1];
254
255             /* Compute the ratios. */
256             double minRatio = Math.min(Math.abs(textBoxWidth.getX() / spriteDimension.width), Math.abs(textBoxHeight.getY() / spriteDimension.height));
257             double baseMinRatio = Math.min(Math.abs(textBoxWidth.getX() / baseSpriteDimension.width), Math.abs(textBoxHeight.getY() / baseSpriteDimension.height));
258
259             ratios[0] = minRatio;
260             ratios[1] = baseMinRatio;
261         }
262
263         return ratios;
264     }
265
266     /**
267      * Computes and returns the positions of a Scilab {@see Text} object and its text box in window coordinates, as a function
268      * of its text box mode and text box properties. They are the position of the Text's lower-left corner,
269      * which may differ from the text's unmodified position, depending on its text box properties, and
270      * the position of the text box's lower-left corner. If the text box mode is set to off, the text lower-left corner's position
271      * is simply the text's projected position, and its text box's position is equal to the former.
272      * @param projection the projection from object coordinates to window coordinates.
273      * @param text the Scilab {@see Text}.
274      * @param textBoxVectors the text box width and height vectors (in window coordinates).
275      * @param spriteDim the text texture's dimension (in pixels).
276      * @return the lower-left corners of the Scilab {@see Text}'s text and of its text box in window coordinates (2 elements).
277      * @throws DegenerateMatrixException if the projection is not possible.
278      */
279     protected Vector3d[] computeTextPosition(Transformation projection, Text text, Vector3d[] textBoxVectors, Dimension spriteDim) throws DegenerateMatrixException {
280         Vector3d[] cornerPositions = new Vector3d[2];
281         Integer parentAxesId = text.getParentAxes();
282         Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(parentAxesId);
283         double[][] factors = parentAxes.getScaleTranslateFactors();
284         Double[] pos = text.getPosition();
285         Vector3d textPosition = new Vector3d(pos);
286
287         /* Apply logarithmic scaling */
288         boolean[] logFlags = new boolean[] {parentAxes.getXAxisLogFlag(), parentAxes.getYAxisLogFlag(), parentAxes.getZAxisLogFlag()};
289         textPosition = ScaleUtils.applyLogScale(textPosition, logFlags);
290         textPosition = new Vector3d(textPosition.getX() * factors[0][0] + factors[1][0], textPosition.getY() * factors[0][1] + factors[1][1], textPosition.getZ() * factors[0][2] + factors[1][2]);
291
292         textPosition = projection.project(textPosition);
293
294         cornerPositions[0] = new Vector3d(textPosition);
295         cornerPositions[1] = new Vector3d(textPosition);
296
297         if (text.getTextBoxMode() >= 1) {
298             Vector3d textBoxWidth = new Vector3d(textBoxVectors[0]);
299             Vector3d textBoxHeight = new Vector3d(textBoxVectors[1]);
300
301             double[] textBoxWidthData = textBoxWidth.getData();
302             double[] textBoxHeightData = textBoxHeight.getData();
303
304             /* Reversed axes must be taken into account to correctly compute the text texture's lower-left corner. */
305             if (parentAxes.getXAxisReverse()) {
306                 textBoxWidthData[0] = -textBoxWidthData[0];
307                 textBoxHeightData[0] = -textBoxHeightData[0];
308             }
309
310             if (parentAxes.getYAxisReverse()) {
311                 textBoxWidthData[1] = -textBoxWidthData[1];
312                 textBoxHeightData[1] = -textBoxHeightData[1];
313             }
314
315             if (parentAxes.getZAxisReverse()) {
316                 textBoxWidthData[2] = -textBoxWidthData[2];
317                 textBoxHeightData[2] = -textBoxHeightData[2];
318             }
319
320             Vector3d revTextBoxWidth = new Vector3d(textBoxWidthData);
321             Vector3d revTextBoxHeight = new Vector3d(textBoxHeightData);
322
323             Vector3d[] projCorners = computeProjCorners(textPosition, text.getFontAngle(), spriteDim);
324
325             Vector3d textWidth = projCorners[1].minus(projCorners[0]);
326             Vector3d textHeight = projCorners[2].minus(projCorners[0]);
327
328             /*
329              * Compute the final text box's and text's half-length vectors,
330              * using the rotated text label vectors.
331              */
332             revTextBoxWidth = textWidth.getNormalized().times(0.5 * revTextBoxWidth.getX());
333             revTextBoxHeight = textHeight.getNormalized().times(0.5 * revTextBoxHeight.getY());
334
335             textBoxWidth = textWidth.getNormalized().times(0.5 * textBoxWidth.getX());
336             textBoxHeight = textHeight.getNormalized().times(0.5 * textBoxHeight.getY());
337
338             textWidth = textWidth.times(0.5);
339             textHeight = textHeight.times(0.5);
340
341             /* Compute the actual corner positions from the initial projected position and the half-length vectors */
342             textPosition = textPosition.plus(revTextBoxWidth);
343             textPosition = textPosition.plus(revTextBoxHeight);
344
345             Vector3d textBoxCorner = textPosition.minus(textBoxWidth);
346             textBoxCorner = textBoxCorner.minus(textBoxHeight);
347
348             textPosition = textPosition.minus(textWidth);
349             textPosition = textPosition.minus(textHeight);
350
351             cornerPositions[0] = textPosition;
352             cornerPositions[1] = textBoxCorner;
353         }
354
355         return cornerPositions;
356     }
357
358     /**
359      * Computes and returns the corners of a {@see Text} object's bounding box, in window coordinates.
360      * The returned corners are in the following order: lower-left, lower-right, upper-left and upper-right.
361      * @param canvasProj the projection from object coordinates to window coordinates.
362      * @param position the text's position in object coordinates.
363      * @param fontAngle the text's font angle (radians).
364      * @param spriteDim the text texture's dimension (in pixels).
365      * @return the corners' window coordinates (4-element array).
366      * @throws DegenerateMatrixException if the projection is not possible.
367      */
368     protected Vector3d[] computeProjCorners(Transformation canvasProj, Vector3d position, double fontAngle, Dimension spriteDim) throws DegenerateMatrixException {
369         position = canvasProj.project(position);
370         return computeProjCorners(position, fontAngle, spriteDim);
371     }
372
373     /**
374      * Computes the corners of a {@see Text} object's text box, in window coordinates.
375      * @param position the position of the text box's lower-left corner in window cordinates.
376      * @param fontAngle the text's font angle (radians).
377      * @param textBoxVectors the text box width and height vectors (in window coordinates).
378      * @return the corners' window coordinates (4-element array).
379      * @throws DegenerateMatrixException if the projection is not possible.
380      */
381     protected Vector3d[] computeProjTextBoxCorners(Vector3d position, double fontAngle, Vector3d[] textBoxVectors) throws DegenerateMatrixException {
382         double projTextBoxWidth = textBoxVectors[0].getNorm();
383         double projTextBoxHeight = textBoxVectors[1].getNorm();
384
385         return computeProjCorners(position, fontAngle, new Dimension((int) projTextBoxWidth, (int) projTextBoxHeight));
386     }
387
388     /**
389      * Computes and returns the corners of a {@see Text} object's bounding box, in window coordinates.
390      * The returned corners are in the following order: lower-left, lower-right, upper-left and upper-right.
391      * @param projPosition the text's position in window coordinates.
392      * @param fontAngle the text's font angle (radians).
393      * @param spriteDim the text texture's dimension (in pixels).
394      * @return the corners' window coordinates (4-element array).
395      * @throws DegenerateMatrixException if the projection is not possible.
396      */
397     protected Vector3d[] computeProjCorners(Vector3d projPosition, double fontAngle, Dimension spriteDim) throws DegenerateMatrixException {
398         Vector3d[] projCorners = new Vector3d[4];
399
400         /*
401          * Should be -fontAngle, as positive angle values are measured clockwise for texts.
402          * Apparently uses the same convention as the texts (clockwise positive directions).
403          * To be verified.
404          */
405         Transformation projRotation = TransformationFactory.getRotationTransformation(180.0 * fontAngle / Math.PI, 0.0, 0.0, 1.0);
406
407         projCorners[0] = projPosition;
408
409         Vector3d width = new Vector3d(spriteDim.width, 0.0, 0.0);
410         Vector3d height = new Vector3d(0.0, spriteDim.height, 0.0);
411
412         width = projRotation.projectDirection(width);
413         height = projRotation.projectDirection(height);
414
415         projCorners[1] = projCorners[0].plus(width);
416         projCorners[2] = projCorners[0].plus(height);
417         projCorners[3] = projCorners[2].plus(width);
418
419         return projCorners;
420     }
421
422     /**
423      * Computes and returns the corners (in user coordinates) of a text's bounding box.
424      * @param projection the projection from object coordinates to window coordinates.
425      * @param projCorners the corners of the text's bounding box in window coordinates (4-element array).
426      * @param parentAxes the Axes for which the coordinates are computed.
427      * @return the corners of the text's bounding box in user coordinates (4-element array).
428      */
429     protected Vector3d[] computeCorners(Transformation projection, Vector3d[] projCorners, Axes parentAxes) {
430         Vector3d[] corners = new Vector3d[4];
431         boolean[] logFlags = new boolean[] {parentAxes.getXAxisLogFlag(), parentAxes.getYAxisLogFlag(), parentAxes.getZAxisLogFlag()};
432
433         corners[0] = projection.unproject(projCorners[0]);
434         corners[1] = projection.unproject(projCorners[1]);
435         corners[2] = projection.unproject(projCorners[2]);
436         corners[3] = projection.unproject(projCorners[3]);
437
438         /* Apply inverse logarithmic scaling in order to obtain user coordinates */
439         corners[0] = ScaleUtils.applyInverseLogScale(corners[0], logFlags);
440         corners[1] = ScaleUtils.applyInverseLogScale(corners[1], logFlags);
441         corners[2] = ScaleUtils.applyInverseLogScale(corners[2], logFlags);
442         corners[3] = ScaleUtils.applyInverseLogScale(corners[3], logFlags);
443
444         return corners;
445     }
446
447     /**
448      * Returns the positions of a bounding box's corners as an array of (x,y,z) coordinate triplets.
449      * The output corners are reordered to match their order in the {@see Text} object's
450      * equivalent array, respectively: lower-left, lower-right, upper-left, upper-right in the input array,
451      * starting from the lower-left and going in clockwise order in the returned array.
452      * @param corners of the bounding box (4-element array).
453      * @return the corners' coordinates (12-element array).
454      */
455     protected Double[] cornersToCoordinateArray(Vector3d[] corners) {
456         Double[] coordinates = new Double[12];
457         coordinates[0] = corners[0].getX();
458         coordinates[1] = corners[0].getY();
459         coordinates[2] = corners[0].getZ();
460
461         coordinates[3] = corners[2].getX();
462         coordinates[4] = corners[2].getY();
463         coordinates[5] = corners[2].getZ();
464
465         coordinates[6] = corners[3].getX();
466         coordinates[7] = corners[3].getY();
467         coordinates[8] = corners[3].getZ();
468
469         coordinates[9] = corners[1].getX();
470         coordinates[10] = corners[1].getY();
471         coordinates[11] = corners[1].getZ();
472
473         return coordinates;
474     }
475
476     /**
477      * Update the data if needed.
478      * @param id the modified object.
479      * @param property the changed property.
480      */
481     public void update(Integer id, int property) {
482         if (!(__GO_POSITION__ == property) && !(__GO_FONT_ANGLE__ == property)) {
483             dispose(id);
484         }
485     }
486
487     /**
488      * Return the SciRenderer {@see Texture} corresponding to the given Scilab {@see Text}.
489      * @param colorMap the current color map.
490      * @param text the given Scilab {@see Text}.
491      * @return the SciRenderer {@see Texture} corresponding to the given Scilab {@see Text}.
492      */
493     protected Texture getTexture(final ColorMap colorMap, final Text text) {
494         Texture texture = spriteMap.get(text.getIdentifier());
495         if (texture == null) {
496             if (text.getTextBoxMode() == 2) {
497                 /* Create an unscaled texture (scale factor equal to 1) */
498                 texture = createSprite(colorMap, text, 1.0);
499             } else {
500                 texture = createSprite(colorMap, text);
501             }
502             spriteMap.put(text.getIdentifier(), texture);
503         }
504         return texture;
505     }
506
507     /**
508      * Updates a texture according to a scale factor, which is the ratio by which the texture is enlarged.
509      * @param colorMap the current color map.
510      * @param text the Scilab Text.
511      * @param scaleFactor the scale factor relative to the current texture's dimensions.
512      * @param baseScaleFactor the scale factor relative to the unscaled texture's dimensions.
513      * @return the corresponding texture.
514      */
515     protected Texture updateSprite(final ColorMap colorMap, final Text text, double scaleFactor, double baseScaleFactor) {
516         Texture texture = spriteMap.get(text.getIdentifier());
517
518         /* Create a new texture if the scale factor falls outside of the range */
519         if (scaleFactor < FACTOR_UPDATE_INTERVAL[0] || scaleFactor > FACTOR_UPDATE_INTERVAL[1]) {
520             dispose(text.getIdentifier());
521             texture = createSprite(colorMap, text, baseScaleFactor);
522             spriteMap.put(text.getIdentifier(), texture);
523         }
524
525         return texture;
526     }
527
528     /**
529      * Returns the dimensions of the SciRenderer {@see Texture} corresponding to the given Scilab {@see Text}.
530      * The dimensions are in pixels (width, height).
531      * @param colorMap the current color map.
532      * @param text the given Scilab {@see Text}.
533      * @return the texture's dimension.
534      */
535     protected Dimension getSpriteDims(final ColorMap colorMap, final Text text) {
536         TextSpriteDrawer spriteDrawer;
537
538         if (text.getTextBoxMode() == 2) {
539             /* Set the scale factor to 1 in order to return the dimensions of an unscaled texture. */
540             spriteDrawer = new TextSpriteDrawer(colorMap, text, 1.0);
541         } else {
542             spriteDrawer = new TextSpriteDrawer(colorMap, text);
543         }
544
545         return spriteDrawer.getTextureSize();
546     }
547
548     /**
549      * Create a texture for the given text object.
550      * @param colorMap the current colormap.
551      * @param textObject the given text object.
552      * @return a new texture for the given text object.
553      */
554     protected Texture createSprite(final ColorMap colorMap, final Text textObject) {
555         TextSpriteDrawer spriteDrawer = new TextSpriteDrawer(colorMap, textObject);
556         Texture texture = textureManager.createTexture();
557         texture.setMagnificationFilter(Texture.Filter.LINEAR);
558         texture.setMinifyingFilter(Texture.Filter.LINEAR);
559         texture.setDrawer(spriteDrawer);
560         return texture;
561     }
562
563     /**
564      * Creates a texture for the given text object, scaled by the given scale factor.
565      * @param colorMap the current colormap.
566      * @param textObject the given text object.
567      * @param scaleFactor the scale factor to apply.
568      * @return a new texture for the given text object.
569      */
570     protected Texture createSprite(final ColorMap colorMap, final Text textObject, double scaleFactor) {
571         TextSpriteDrawer spriteDrawer = new TextSpriteDrawer(colorMap, textObject, scaleFactor);
572         Texture texture = textureManager.createTexture();
573         texture.setMagnificationFilter(Texture.Filter.LINEAR);
574         texture.setMinifyingFilter(Texture.Filter.LINEAR);
575         texture.setDrawer(spriteDrawer);
576         return texture;
577     }
578
579     /**
580      * Dispose the texture corresponding to the given id.
581      * @param id the given id.
582      */
583     public void dispose(Integer id) {
584         Texture texture = spriteMap.get(id);
585         if (texture != null) {
586             textureManager.dispose(texture);
587             spriteMap.remove(id);
588         }
589     }
590
591     /**
592      * Dispose all the text sprites.
593      */
594     public void disposeAll() {
595         textureManager.dispose(spriteMap.values());
596         spriteMap.clear();
597     }
598
599     /**
600      * Computes and updates the corners of the given Scilab {@see Text}.
601      * @param text the given Scilab {@see Text}.
602      */
603     public static void updateTextCorners(Text text) {
604         Vector3d[] projCorners = null;
605
606         DrawerVisitor currentVisitor = DrawerVisitor.getVisitor(text.getParentFrameOrFigure());
607         Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(text.getParentAxes());
608
609         /* Compute the corners */
610         try {
611             Transformation currentProj = currentVisitor.getAxesDrawer().getCurrentProjection(parentAxes);
612
613             Dimension spriteDim = currentVisitor.getTextManager().getSpriteDims(currentVisitor.getColorMap(), text);
614
615             Vector3d[] textBoxVectors = currentVisitor.getTextManager().computeTextBoxVectors(currentProj, text, spriteDim, parentAxes);
616             Vector3d[] cornerPositions = currentVisitor.getTextManager().computeTextPosition(currentProj, text, textBoxVectors, spriteDim);
617
618             if (text.getTextBoxMode() == 2) {
619                 projCorners = currentVisitor.getTextManager().computeProjTextBoxCorners(cornerPositions[1], text.getFontAngle(), textBoxVectors);
620             } else {
621                 projCorners = currentVisitor.getTextManager().computeProjCorners(cornerPositions[0], text.getFontAngle(), spriteDim);
622             }
623
624             Vector3d[] corners = currentVisitor.getTextManager().computeCorners(currentProj, projCorners, parentAxes);
625             Double[] coordinates = currentVisitor.getTextManager().cornersToCoordinateArray(corners);
626
627             double[][] factors = parentAxes.getScaleTranslateFactors();
628             coordinates[0] = (coordinates[0] - factors[1][0]) / factors[0][0];
629             coordinates[1] = (coordinates[1] - factors[1][1]) / factors[0][1];
630             coordinates[2] = (coordinates[2] - factors[1][2]) / factors[0][2];
631             coordinates[3] = (coordinates[3] - factors[1][0]) / factors[0][0];
632             coordinates[4] = (coordinates[4] - factors[1][1]) / factors[0][1];
633             coordinates[5] = (coordinates[5] - factors[1][2]) / factors[0][2];
634             coordinates[6] = (coordinates[6] - factors[1][0]) / factors[0][0];
635             coordinates[7] = (coordinates[7] - factors[1][1]) / factors[0][1];
636             coordinates[8] = (coordinates[8] - factors[1][2]) / factors[0][2];
637             coordinates[9] = (coordinates[9] - factors[1][0]) / factors[0][0];
638             coordinates[10] = (coordinates[10] - factors[1][1]) / factors[0][1];
639             coordinates[11] = (coordinates[11] - factors[1][2]) / factors[0][2];
640
641             /* Set the computed coordinates */
642             text.setCorners(coordinates);
643
644         } catch (DegenerateMatrixException e) {
645             // TODO Auto-generated catch block
646             e.printStackTrace();
647         }
648     }
649 }