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