Bug 1751 fixed: Margins were not computed according to contents 22/13622/1
Calixte DENIZET [Mon, 20 Jan 2014 14:00:46 +0000 (15:00 +0100)]
Change-Id: I8de65e736a987df4f01df7ec3e29b4211e60722a

18 files changed:
scilab/CHANGES_5.5.X
scilab/modules/graphic_objects/src/java/org/scilab/modules/graphic_objects/legend/Legend.java
scilab/modules/graphics/demos/cmplxfunc/MacCmplx.sci
scilab/modules/graphics/demos/cmplxfunc/demo_custom.dem.sce
scilab/modules/graphics/tests/nonreg_tests/bug_1751.tst [new file with mode: 0644]
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/DrawerVisitor.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/AxesDrawer.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/AxesRulerDrawer.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/AxisLabelPositioner.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelManager.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelPositioner.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/TitlePositioner.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/YAxisLabelPositioner.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/legend/LegendDrawer.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/legend/LegendSpriteDrawer.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/TextObjectSpriteDrawer.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerDrawer.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/BufferedImageTextureDrawingTools.java

index 903f8e0..9ec0683 100644 (file)
@@ -36,6 +36,8 @@ Obsolete & Removed Functions
 Scilab Bug Fixes
 ================
 
+* Bug #1751 fixed - Margins were not computed according to contents.
+
 * Bug #2067 fixed - Scilab crashed when plot was called with a large numerical value.
 
 * Bug #4401 fixed - isnum did not recognize all constants or some complex numbers.
index 5fc8e94..bd6d33f 100644 (file)
@@ -95,8 +95,6 @@ function []=PlotCmplxFunc(R,e,TypeDomain,TypeCut,n,StrFunc,theta,alpha,DomReal)
     // make axes transparent
     my_title_axes.filled = "off";
 
-    my_title_axes.margins = [ 0.08 0.08 0.08 0.08 ]
-
     Rs = string(R);
 
     if TypeDomain == "Square" then
@@ -116,6 +114,7 @@ function []=PlotCmplxFunc(R,e,TypeDomain,TypeCut,n,StrFunc,theta,alpha,DomReal)
     my_title_axes.title.text       = the_title;
     my_title_axes.title.font_size  = 3;
     my_title_axes.title.font_style = 2;
+    my_title_axes.margins = [ 0.08 0.08 0.08 0.08 ]
 
     // plot Im(z)
     // ============================================
index ab48ec1..1b74c69 100644 (file)
@@ -649,7 +649,6 @@ function []=PlotCmplxFunc(R,e,TypeDomain,TypeCut,n,StrFunc,theta,alpha,DomReal)
 
     my_title_axes             = newaxes();
     my_title_axes.axes_bounds = [1/3,0,2/3,1];
-    my_title_axes.margins     = [ 0.08 0.08 0.08 0.08 ]
 
     // make axes transparent
     my_title_axes.filled = "off";
@@ -672,6 +671,7 @@ function []=PlotCmplxFunc(R,e,TypeDomain,TypeCut,n,StrFunc,theta,alpha,DomReal)
 
     my_title_axes.title.text       = the_title;
     my_title_axes.title.font_size  = 3;
+    my_title_axes.margins     = [ 0.08 0.08 0.08 0.08 ]
 
     // plot Im(z)
     // ============================================
@@ -681,11 +681,11 @@ function []=PlotCmplxFunc(R,e,TypeDomain,TypeCut,n,StrFunc,theta,alpha,DomReal)
 
     my_IM_axes = gca();
     my_IM_axes.axes_bounds = [0.1, 0.05, 1, 0.5];
-    my_IM_axes.margins     = [0.2, 0.2, 0.2, 0.2];
     my_IM_plot             = my_IM_axes.children;
     my_IM_plot.color_flag  = 1;
 
     xtitle("Im("+StrFunc+"(z))");
+    my_IM_axes.margins     = [0.2, 0.2, 0.2, 0.2];
 
     // plot Re(z) + the real restriction
     // ============================================
@@ -695,11 +695,12 @@ function []=PlotCmplxFunc(R,e,TypeDomain,TypeCut,n,StrFunc,theta,alpha,DomReal)
 
     my_RE_axes = gca();
     my_RE_axes.axes_bounds = [0.1, 0.5, 1, 0.5];
-    my_RE_axes.margins     = [ 0.2 0.2 0.2 0.2 ];
+    my_RE_axes.margins      = [ 0.2 0.2 0.2 0.2 ];
     my_RE_plot             = my_RE_axes.children;
     my_RE_plot.color_flag  = 1;
 
     xtitle("Re("+StrFunc+"(z))");
+    my_RE_axes.margins     = [ 0.2 0.2 0.2 0.2 ];
 
     // real function in yellow
     // ============================================
diff --git a/scilab/modules/graphics/tests/nonreg_tests/bug_1751.tst b/scilab/modules/graphics/tests/nonreg_tests/bug_1751.tst
new file mode 100644 (file)
index 0000000..c973811
--- /dev/null
@@ -0,0 +1,38 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+
+// <-- TEST WITH GRAPHIC -->
+
+// <-- INTERACTIVE TEST -->
+
+// <-- Non-regression test for bug 1751 -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/1751
+//
+// <-- Short Description -->
+// Margins were not computed according to contents
+
+clf();
+plot([1:2]',[3:4;5:6;7:8;9:10]');
+// margins should be resized to let axis labels fit them
+xtitle("$\scalebox{12}{Title}$","$\scalebox{12}{1}$","$\scalebox{12}{2}$")
+
+// Now we make six subplots with titles, labels and legends
+// It must not have object overlapping another one
+clf();
+M=3;
+N=2;
+for i=1:M
+    for j=1:N
+        k=i+(j-1)*M;
+        subplot(M,N,k);
+        plot([1:2]',[3:4;5:6;7:8;9:10]');
+        xtitle("title " + string(k),"x-axis " + string(k),"y-axis " + string(k));
+        legend(["AAAA", "BBBB", "CCCC", "DDDD"],"out_upper_right");
+    end
+end
index 7baa651..ea408a0 100755 (executable)
@@ -226,6 +226,13 @@ public class DrawerVisitor implements Visitor, Drawer, GraphicView {
     }
 
     /**
+     * @return the LegendDrawer
+     */
+    public LegendDrawer getLegendDrawer() {
+        return legendDrawer;
+    }
+
+    /**
      * Mark manager getter.
      * @return the mark manager.
      */
@@ -1009,7 +1016,22 @@ public class DrawerVisitor implements Visitor, Drawer, GraphicView {
                 }
             }
 
-            if (object instanceof Figure) {
+            if (object instanceof Label || object instanceof Legend) {
+                GraphicObject parent = GraphicController.getController().getObjectFromId(object.getParent());
+                if (parent instanceof Axes) {
+                    Axes axes = (Axes) parent;
+                    if (axes.getXAxisLabel().equals(id) ||
+                            axes.getYAxisLabel().equals(id) ||
+                            axes.getZAxisLabel().equals(id) ||
+                            axes.getTitle().equals(id)) {
+                        labelManager.update(id, property);
+                        axesDrawer.computeMargins(axes);
+                    } else if (object instanceof Legend && property == GraphicObjectProperties.__GO_LEGEND_LOCATION__) {
+                        legendDrawer.update(id, property);
+                        axesDrawer.computeMargins(axes);
+                    }
+                }
+            } else if (object instanceof Figure) {
                 if (property == GraphicObjectProperties.__GO_SIZE__ || property == GraphicObjectProperties.__GO_AXES_SIZE__ || property == GraphicObjectProperties.__GO_CHILDREN__) {
                     Figure fig = (Figure) object;
                     for (Integer gid : fig.getChildren()) {
index af7f1a8..fa1c466 100644 (file)
@@ -24,6 +24,7 @@ import org.scilab.forge.scirenderer.tranformations.TransformationStack;
 import org.scilab.forge.scirenderer.tranformations.Vector3d;
 import org.scilab.forge.scirenderer.tranformations.Vector4d;
 import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.axes.AxisProperty;
 import org.scilab.modules.graphic_objects.axes.Box;
 import org.scilab.modules.graphic_objects.axes.Camera.ViewType;
 import org.scilab.modules.graphic_objects.contouredObject.Line;
@@ -32,6 +33,8 @@ import org.scilab.modules.graphic_objects.graphicObject.GraphicObject;
 import org.scilab.modules.graphic_objects.graphicObject.ClippableProperty;
 import org.scilab.modules.graphic_objects.graphicObject.ClippableProperty.ClipStateType;
 import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.legend.Legend;
+import org.scilab.modules.graphic_objects.legend.Legend.LegendLocation;
 import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
 import org.scilab.modules.renderer.JoGLView.axes.ruler.AxesRulerDrawer;
 import org.scilab.modules.renderer.JoGLView.label.AxisLabelPositioner;
@@ -39,6 +42,7 @@ import org.scilab.modules.renderer.JoGLView.label.LabelManager;
 import org.scilab.modules.renderer.JoGLView.label.LabelPositioner;
 import org.scilab.modules.renderer.JoGLView.label.TitlePositioner;
 import org.scilab.modules.renderer.JoGLView.label.YAxisLabelPositioner;
+import org.scilab.modules.renderer.JoGLView.legend.LegendDrawer;
 import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
 import org.scilab.modules.renderer.JoGLView.util.ScaleUtils;
 
@@ -152,6 +156,9 @@ public class AxesDrawer {
             Integer[] size = visitor.getFigure().getAxesSize();
             double w = ((double) (int) size[0]) / 2;
             double h = ((double) (int) size[1]) / 2;
+
+            //computeMargins(axes);
+
             Transformation windowTrans = TransformationFactory.getAffineTransformation(new Vector3d(w, h, 1), new Vector3d(w, h, 0));
             Transformation zoneProjection = computeZoneProjection(axes);
             Transformation transformation = computeBoxTransformation(axes, new Dimension(size[0], size[1]), false);
@@ -163,6 +170,132 @@ public class AxesDrawer {
         }
     }
 
+    public void computeMargins(Axes axes) {
+        if (axes.getViewAsEnum() == ViewType.VIEW_2D) {
+            ColorMap colorMap = visitor.getColorMap();
+            Dimension[] marginLabels = labelManager.getLabelsSize(colorMap, axes, this);
+            Integer[] size = visitor.getFigure().getAxesSize();
+            // [x_left, y_up, w, h]
+            Double[] axesBounds = axes.getAxesBounds();
+            // [l, r, t, b]
+            Double[] margins = axes.getMargins();
+            // m is a copy of margins
+            Double[] mt = new Double[] { 0., 0., 0., 0. };
+            Double[] ml = new Double[] { 0., 0., 0., 0. };
+            Double[] ma = new Double[] { 0., 0., 0., 0. };
+            Double[] m = new Double[] { 0., 0., 0., 0. };
+            AxisProperty.AxisLocation xloc = axes.getXAxis().getAxisLocation();
+            AxisProperty.AxisLocation yloc = axes.getYAxis().getAxisLocation();
+            final double DEFAULT_MARGIN = 0.125;
+
+            // We compute the adapted margins for axes titles.
+            if (marginLabels[0].height != 0 || marginLabels[2].height != 0 || marginLabels[1].width != 0) {
+                if (marginLabels[2].height != 0) {
+                    final double th = (marginLabels[2].height + 2 + TitlePositioner.TITLEOFFSET) / (size[1] * axesBounds[3]);
+                    mt[2] = th;
+                }
+
+                if (marginLabels[0].height != 0 && (xloc == AxisProperty.AxisLocation.BOTTOM || xloc == AxisProperty.AxisLocation.TOP)) {
+                    final double xh = (marginLabels[0].height + 2) / (size[1] * axesBounds[3]);
+                    if (xloc == AxisProperty.AxisLocation.BOTTOM) {
+                        mt[3] = xh;
+                    } else {
+                        mt[2] = xh;
+                    }
+                }
+
+                if (marginLabels[1].width != 0 && (yloc == AxisProperty.AxisLocation.LEFT || yloc == AxisProperty.AxisLocation.RIGHT)) {
+                    final double yh = (marginLabels[1].width + 2) / (size[0] * axesBounds[2]);
+                    if (yloc == AxisProperty.AxisLocation.LEFT) {
+                        mt[0] = yh;
+                    } else {
+                        mt[1] = yh;
+                    }
+                }
+            }
+
+            computeRulers(axes);
+            final double xratio = rulerDrawer.getRulerDrawer(axes, 0).getDistanceRatio();
+            final double yratio = rulerDrawer.getRulerDrawer(axes, 1).getDistanceRatio();
+
+            if (xloc == AxisProperty.AxisLocation.BOTTOM) {
+                ma[3] = (1 - margins[2] - margins[3]) * xratio / 2.;
+            } else if (xloc == AxisProperty.AxisLocation.TOP) {
+                ma[2] = (1 - margins[2] - margins[3]) * xratio / 2.;
+            }
+
+            if (yloc == AxisProperty.AxisLocation.LEFT) {
+                ma[0] = (1 - margins[0] - margins[1]) * yratio / 2.;
+            } else if (yloc == AxisProperty.AxisLocation.RIGHT) {
+                ma[1] = (1 - margins[0] - margins[1]) * yratio / 2.;
+            }
+
+            // Get the legend if any (only one ???)
+            if (axes.getChildren() != null) {
+                for (Integer i : axes.getChildren()) {
+                    GraphicObject child = GraphicController.getController().getObjectFromId(i);
+                    if (child instanceof Legend) {
+                        Legend legend = (Legend) child;
+                        Dimension legDims = visitor.getLegendDrawer().computeDimensions(axes, legend);
+                        if (legDims != null) {
+                            LegendLocation legLoc = legend.getLegendLocationAsEnum();
+                            double C;
+                            /*
+                             * Legends dimension are linearly dependent of margins... so we need to solve an equation
+                             * to find a good value for margins.
+                             * For example:
+                             *  legend.w = texture.w + 3/8 * line.w + line.w
+                             *  where line.w = LINE_WIDTH * ab[2] * (1 - m[0] - m[1]) * size[0];
+                             *  the minimal value for m[1] is the solution of the equation (where unknown is m[1]):
+                             *   legend.w = ab[2] * m[1] * size[0].
+                             */
+                            switch (legLoc) {
+                                case OUT_UPPER_RIGHT:
+                                case OUT_LOWER_RIGHT:
+                                    // 1/8 of LINE_WIDTH is xOffset
+                                    // see legendDims[0] = ... in LegendDrawer::draw
+                                    // we add 2*xoffset to have a little space around the box
+                                    C = LegendDrawer.LINE_WIDTH * (3. / 8. + 1 + 2. / 8.);
+                                    m[0] = Math.max(ma[0] + mt[0], DEFAULT_MARGIN);
+                                    m[1] = Math.max(((legDims.width + 2) / (axesBounds[2] * size[0]) + C * (1 - m[0])) / (1 + C) + ma[1] + mt[1], DEFAULT_MARGIN);
+                                    break;
+                                case OUT_UPPER_LEFT:
+                                case OUT_LOWER_LEFT:
+                                    C = LegendDrawer.LINE_WIDTH * (3. / 8. + 1 + 2. / 8.);
+                                    m[1] = Math.max(ma[1] + mt[1], DEFAULT_MARGIN);
+                                    m[0] = Math.max(((legDims.width + 2) / (axesBounds[2] * size[0]) + C * (1 - m[1])) / (1 + C) + ma[0] + mt[0], DEFAULT_MARGIN);
+                                    break;
+                                case UPPER_CAPTION:
+                                    C = LegendDrawer.Y_OFFSET * (3. + 2.);
+                                    m[3] = Math.max(ma[3] + mt[3], DEFAULT_MARGIN);
+                                    m[2] = Math.max(Math.max(((legDims.height + 2) / (axesBounds[3] * size[1]) + C * (1 - m[3])) / (1 + C), mt[2]) + ma[2], DEFAULT_MARGIN);
+                                    break;
+                                case LOWER_CAPTION:
+                                    C = LegendDrawer.Y_OFFSET * (3. + 2.);
+                                    m[2] = Math.max(ma[2] + mt[2], DEFAULT_MARGIN);
+                                    m[3] = Math.max(Math.max(((legDims.height + 2) / (axesBounds[3] * size[1]) + C * (1 - m[2])) / (1 + C), mt[3]) + ma[3], DEFAULT_MARGIN);
+                                    break;
+                                default:
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+
+            for (int i = 0; i < m.length; i++) {
+                if (m[i] == 0) {
+                    m[i] = Math.max(ma[i] + mt[i], DEFAULT_MARGIN);
+                }
+            }
+
+            if (!m[0].equals(margins[0]) || !m[1].equals(margins[1]) || !m[2].equals(margins[2]) || !m[3].equals(margins[3])) {
+                axes.setMargins(m);
+                computeRulers(axes);
+            }
+        }
+    }
+
     /**
      * Draw the given {@see Axes}.
      * @param axes {@see Axes} to draw.
index 7103adc..69d475d 100644 (file)
@@ -57,7 +57,7 @@ public class AxesRulerDrawer {
     private static final double LOG_MINIMAL_SUB_TICKS_DISTANCE = 2;
 
     /** Ticks length in pixels. */
-    private static final int TICKS_LENGTH = 6;
+    public static final int TICKS_LENGTH = 6;
 
     /** Sub-ticks length in pixels. */
     private static final int SUB_TICKS_LENGTH = 3;
@@ -72,6 +72,10 @@ public class AxesRulerDrawer {
         this.rulerDrawerManager = new RulerDrawerManager(canvas.getTextureManager());
     }
 
+    public RulerDrawer getRulerDrawer(Axes axes, int axis) {
+        return rulerDrawerManager.get(axes)[axis];
+    }
+
     /**
      * Get default ruler model
      * @param axes the axes
index ff7fda2..284747d 100644 (file)
@@ -178,7 +178,6 @@ public class AxisLabelPositioner extends LabelPositioner {
 
         /* Compute the label displacement and set it */
         labelDisplacement = ticksDirection.times(distRatio);
-
         position = position.plus(labelDisplacement);
 
         return position;
index 5123106..8639956 100644 (file)
@@ -29,6 +29,7 @@ import org.scilab.modules.graphic_objects.utils.Utils;
 import org.scilab.modules.renderer.JoGLView.axes.AxesDrawer;
 import org.scilab.modules.renderer.JoGLView.util.ScaleUtils;
 
+import java.awt.Dimension;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -65,6 +66,31 @@ public class LabelManager {
         this.textureManager = textureManager;
     }
 
+    public Dimension[] getLabelsSize(ColorMap colorMap, Axes axes, AxesDrawer drawer) {
+        final Label xl = (Label) GraphicController.getController().getObjectFromId(axes.getXAxisLabel());
+        final Label yl = (Label) GraphicController.getController().getObjectFromId(axes.getYAxisLabel());
+        final Label tl = (Label) GraphicController.getController().getObjectFromId(axes.getTitle());
+        final Dimension[] dims = new Dimension[3];
+        final Label[] labels = new Label[] {xl, yl, tl};
+        final LabelPositioner[] positioners = new LabelPositioner[] {drawer.getXAxisLabelPositioner(axes), drawer.getYAxisLabelPositioner(axes), drawer.getTitlePositioner(axes) };
+        for (int i = 0; i < 3; i++) {
+            if (!labels[i].isEmpty() && labels[i].getAutoPosition() && labels[i].getAutoRotation()) {
+                final Texture texture = getTexture(colorMap, labels[i]);
+                dims[i] = texture.getDataProvider().getTextureSize();
+                final double a = positioners[i].getAutoRotationAngle();
+                if (a == 90 || a == 270) {
+                    final int t = dims[i].width;
+                    dims[i].width = dims[i].height;
+                    dims[i].height = t;
+                }
+            } else {
+                dims[i] = new Dimension();
+            }
+        }
+
+        return dims;
+    }
+
     /**
      * Draws the given {@see Label} with the given {@see DrawingTools}.
      * @param drawingTools the given {@see DrawingTools}.
@@ -143,8 +169,6 @@ public class LabelManager {
         /* Un scale/translate the label position to be drawn */
         Vector3d labelUserPosition = computeUnscaledAxesCoords(new Vector3d(label.getPosition()), factors);
 
-
-
         /* Logarithmic scaling must be applied to the label's user position to obtain object coordinates */
         labelUserPosition = ScaleUtils.applyLogScale(labelUserPosition, logFlags);
 
@@ -161,7 +185,6 @@ public class LabelManager {
         if (label.getAutoPosition()) {
             Vector3d cornerPos = labelPositioner.getLowerLeftCornerPosition();
             Vector3d objectCornerPos = axesDrawer.getObjectCoordinates(cornerPos);
-
             /* Apply inverse scaling to obtain user coordinates */
             objectCornerPos = ScaleUtils.applyInverseLogScale(objectCornerPos, logFlags);
 
@@ -177,22 +200,17 @@ public class LabelManager {
 
         /* Compute and set the label's corners */
         Transformation projection = axesDrawer.getProjection();
-
         Vector3d[] projCorners = labelPositioner.getProjCorners();
-
         Vector3d[] corners = computeCorners(projection, projCorners, parentAxes);
-
         Double[] coordinates = cornersToCoordinateArray(corners);
 
         /* Set the computed coordinates */
         label.setCorners(coordinates);
 
-
         double rotationAngle = 0.0;
 
         if (label.getAutoRotation()) {
             rotationAngle = labelPositioner.getRotationAngle();
-
             label.setFontAngle(Math.PI * rotationAngle / 180.0);
 
             /*
@@ -213,7 +231,7 @@ public class LabelManager {
                     /* Draw in window coordinates */
                     Transformation canvasProjection = drawingTools.getTransformationManager().getCanvasProjection();
                     Vector3d projLabelPos = canvasProjection.project(labelPos);
-
+                    projLabelPos = new Vector3d(Math.round(projLabelPos.getX()), Math.round(projLabelPos.getY()), Math.round(projLabelPos.getZ()));
                     drawingTools.getTransformationManager().useWindowCoordinate();
                     drawingTools.draw(labelSprite, labelAnchor, projLabelPos, rotationAngle);
                     drawingTools.getTransformationManager().useSceneCoordinate();
@@ -223,7 +241,6 @@ public class LabelManager {
                 }
             }
         }
-
     }
 
     /**
index a9494fb..61ce19b 100644 (file)
@@ -23,7 +23,7 @@ import org.scilab.modules.graphic_objects.axes.Axes;
 import java.awt.Dimension;
 
 /**
- * LabelPositioner class.
+ * LabelPositioner class
  *
  * Computes the position of a Label in box coordinates [-1, +1]^3, as used
  * when rulers are drawn {@see AxesDrawer}, where -1 and +1 respectively map
@@ -304,7 +304,6 @@ public abstract class LabelPositioner {
      */
     public void positionLabel() {
         computeAnchorPoint();
-
         computeRotationAngle();
 
         /* Depends on the rotation angle and must therefore be computed afterwards. */
@@ -339,8 +338,6 @@ public abstract class LabelPositioner {
         /* Compute and set a zero displacement */
         labelDisplacement = new Vector3d(0.0, 0.0, 0.0);
 
-        position = position.plus(labelDisplacement);
-
         return position;
     }
 
@@ -351,9 +348,9 @@ public abstract class LabelPositioner {
      */
     private void computeRotationAngle() {
         if (autoRotation) {
-            rotationAngle = getAutoRotationAngle();
+            setRotationAngle(getAutoRotationAngle());
         } else {
-            rotationAngle = userRotationAngle;
+            setRotationAngle(userRotationAngle);
         }
     }
 
@@ -435,7 +432,6 @@ public abstract class LabelPositioner {
     public Vector3d getLowerLeftCornerPosition() {
         Transformation canvasProjection = drawingTools.getTransformationManager().getCanvasProjection();
         Vector3d labelPoint = new Vector3d(anchorPoint);
-
         Vector3d projLabelPoint = new Vector3d(projAnchorPoint);
 
         Vector3d projRightPoint = projLabelPoint.plus(projHalfWidth);
index 6d6f45b..2d6bfa2 100644 (file)
@@ -40,7 +40,7 @@ public class TitlePositioner extends LabelPositioner {
      * to the Title label's anchor point. Relevant only to
      * automatic positioning.
      */
-    private static final double TITLEOFFSET = 8.0;
+    public static final double TITLEOFFSET = 8.0;
 
     /**
      * The minimum z value in window coordinates.
@@ -76,8 +76,8 @@ public class TitlePositioner extends LabelPositioner {
         }
 
         /* Compute the anchor point's position in window coordinates */
-        double xmid = (axesBounds[0] + axesBounds[2] * margins[0] + 0.5 * axesBounds[2] * (1.0 - margins[0] - margins[1]));
-        double ymid = (1.0 - axesBounds[1] + (margins[3] - 1.0) * axesBounds[3] + axesBounds[3] * (1.0 - margins[2] - margins[3]));
+        double xmid = axesBounds[0] + axesBounds[2] * margins[0] + 0.5 * axesBounds[2] * (1.0 - margins[0] - margins[1]);
+        double ymid = 1.0 - axesBounds[1] - axesBounds[3] * margins[2];
 
         Vector3d projAnchorPoint = new Vector3d(Math.floor((xmid) * (double) drawingTools.getCanvas().getWidth()),
                                                 Math.floor((ymid) * (double) drawingTools.getCanvas().getHeight()),
@@ -106,6 +106,4 @@ public class TitlePositioner extends LabelPositioner {
     protected AnchorPosition getAutoAnchorPosition() {
         return AnchorPosition.DOWN;
     }
-
 }
-
index 8631f8d..2d6a762 100644 (file)
@@ -91,10 +91,10 @@ public class LegendDrawer {
     private LegendSpriteDrawer legendSpriteDrawer;
 
     /** The relative line width */
-    private static final double LINE_WIDTH = 0.1;
+    public static final double LINE_WIDTH = 0.1;
 
     /** The relative y-offset */
-    private static final double Y_OFFSET = 0.01;
+    public static final double Y_OFFSET = 0.01;
 
     /** The relative tick and label size (arbitrarily chosen) */
     private static final double TICK_LABEL_SIZE = 0.055;
@@ -145,6 +145,27 @@ public class LegendDrawer {
         lineIndices.setData(lineIndexData);
     }
 
+    public Dimension computeDimensions(Axes parentAxes, Legend legend) {
+        LegendLocation loc = legend.getLegendLocationAsEnum();
+        if (loc != LegendLocation.IN_UPPER_RIGHT && loc != LegendLocation.IN_UPPER_LEFT &&
+                loc != LegendLocation.IN_LOWER_RIGHT && loc != LegendLocation.IN_LOWER_LEFT) {
+            final ColorMap colorMap = visitor.getColorMap();
+            final Integer[] links = legend.getLinks();
+            final int nbValidLinks = getNumberValidLinks(legend);
+            if (nbValidLinks < links.length) {
+                dispose(legend.getIdentifier());
+                updateLinks(legend, nbValidLinks);
+            }
+
+            if (nbValidLinks > 0) {
+                Texture legendSprite = getTexture(colorMap, legend);
+                return legendSprite.getDataProvider().getTextureSize();
+            }
+        }
+
+        return null;
+    }
+
     /**
      * Draws the given Legend.
      * @param legend the Legend to draw.
@@ -152,13 +173,13 @@ public class LegendDrawer {
      */
     public void draw(Legend legend) throws SciRendererException {
         /* The coordinates of the legend box's lower-left corner */
-        double [] legendCorner = new double[] {0.25, 0.75, Z_FRONT};
+        double[] legendCorner = new double[] {0.25, 0.75, Z_FRONT};
 
         DrawingTools drawingTools = visitor.getDrawingTools();
         ColorMap colorMap = visitor.getColorMap();
         Canvas canvas = visitor.getCanvas();
 
-        Integer [] links = legend.getLinks();
+        Integer[] links = legend.getLinks();
 
         /*
          * Determine whether any links have become invalid,
@@ -193,8 +214,8 @@ public class LegendDrawer {
         Integer parentAxesID = legend.getParentAxes();
         Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(parentAxesID);
 
-        Double [] axesBounds = parentAxes.getAxesBounds();
-        Double [] margins = parentAxes.getMargins();
+        Double[] axesBounds = parentAxes.getAxesBounds();
+        Double[] margins = parentAxes.getMargins();
 
         int xAxisLocation = parentAxes.getXAxisLocation();
         int yAxisLocation = parentAxes.getYAxisLocation();
@@ -212,15 +233,11 @@ public class LegendDrawer {
         }
 
         Texture legendSprite = null;
-
-        if (nbValidLinks > 0) {
-            legendSprite = getTexture(colorMap, legend);
-        }
-
         double normSpriteWidth = 0;
         double normSpriteHeight = 0;
 
         if (nbValidLinks > 0) {
+            legendSprite = getTexture(colorMap, legend);
             Dimension textureSize = legendSprite.getDataProvider().getTextureSize();
             normSpriteWidth = textureSize.getWidth() / (double) canvasWidth;
             normSpriteHeight = textureSize.getHeight() / (double) canvasHeight;
@@ -229,16 +246,19 @@ public class LegendDrawer {
         double lineWidth;
 
         /* The legend box's width and height */
-        double [] legendDims = new double[2];
+        double[] legendDims = new double[2];
 
-        double [] axesPos = new double[2];
-        double [] axesDims = new double[2];
+        double[] axesPos = new double[2];
+        double[] axesDims = new double[2];
 
         lineWidth = LINE_WIDTH * (axesBounds[2]) * (1.0 - margins[0] - margins[1]);
 
         double xOffset = lineWidth / 8.0;
         double yOffset = (Y_OFFSET * (axesBounds[3]) * (1.0 - margins[2] - margins[3]));
 
+        /*
+         * If one of these relations is modified, then AxesDrawer::computeMargins should be modified too
+         */
         legendDims[0] = normSpriteWidth + lineWidth + 3.0 * xOffset;
         legendDims[1] = normSpriteHeight + 2.0 * yOffset;
 
@@ -253,8 +273,8 @@ public class LegendDrawer {
         axesDims[1] = axesBounds[3];
 
         /* The {x, y} coordinates of the axes box's lower-left and upper-right corners (as defined by bounds and margins) */
-        double [] llBoxCorner = new double[2];
-        double [] urBoxCorner = new double[2];
+        double[] llBoxCorner = new double[2];
+        double[] urBoxCorner = new double[2];
 
         LegendLocation legendLocation = legend.getLegendLocationAsEnum();
 
@@ -264,53 +284,65 @@ public class LegendDrawer {
         urBoxCorner[0] = axesPos[0] + (1.0 - margins[1]) * axesDims[0];
         urBoxCorner[1] = axesPos[1] + (1.0 - margins[2]) * axesDims[1];
 
-        if (legendLocation == LegendLocation.IN_UPPER_RIGHT) {
-            legendCorner[0] = (float) (urBoxCorner[0] - xOffset - legendDims[0]);
-            legendCorner[1] = (float) (urBoxCorner[1] - yOffset - legendDims[1]);
-        } else if (legendLocation == LegendLocation.IN_UPPER_LEFT) {
-            legendCorner[0] = (float) (llBoxCorner[0] + xOffset);
-            legendCorner[1] = (float) (urBoxCorner[1] - yOffset - legendDims[1]);
-        } else if (legendLocation == LegendLocation.IN_LOWER_RIGHT) {
-            legendCorner[0] = (float) (urBoxCorner[0] - xOffset - legendDims[0]);
-            legendCorner[1] = (float) (llBoxCorner[1] + yOffset);
-        } else if (legendLocation == LegendLocation.IN_LOWER_LEFT) {
-            legendCorner[0] = (float) (llBoxCorner[0] + xOffset);
-            legendCorner[1] = (float) (llBoxCorner[1] + yOffset);
-        } else if (legendLocation == LegendLocation.OUT_UPPER_RIGHT) {
-            legendCorner[0] = (float) (urBoxCorner[0] + xOffset);
-            legendCorner[1] = (float) (urBoxCorner[1] - legendDims[1]);
-        } else if (legendLocation == LegendLocation.OUT_UPPER_LEFT) {
-            legendCorner[0] = (float) (llBoxCorner[0] - xOffset - legendDims[0]);
-            legendCorner[1] = (float) (urBoxCorner[1] - legendDims[1]);
-        } else if (legendLocation == LegendLocation.OUT_LOWER_RIGHT) {
-            legendCorner[0] = (float) (urBoxCorner[0] + xOffset);
-            legendCorner[1] = (float) (llBoxCorner[1]);
-        } else if (legendLocation == LegendLocation.OUT_LOWER_LEFT) {
-            legendCorner[0] = (float) (llBoxCorner[0] - xOffset - legendDims[0]);
-            legendCorner[1] = (float) (llBoxCorner[1]);
-        } else if (legendLocation == LegendLocation.UPPER_CAPTION) {
-            legendCorner[0] = (float) (llBoxCorner[0]);
-            legendCorner[1] = (float) (urBoxCorner[1] + yOffset);
-
-            /* x-axis at the top */
-            if (xAxisLocation == 1) {
-                /* To do: use the actual label+tick bounding box height */
-                legendCorner[1] += TICK_LABEL_SIZE;
-            }
-        } else if (legendLocation == LegendLocation.LOWER_CAPTION) {
-            legendCorner[0] = (float) (llBoxCorner[0]);
-            legendCorner[1] = (float) (llBoxCorner[1] - yOffset - legendDims[1]);
-
-            /* x-axis at the bottom */
-            if (xAxisLocation == 0) {
-                /* To do: use the actual label+tick bounding box height */
-                legendCorner[1] -= TICK_LABEL_SIZE;
-            }
-        } else if (legendLocation == LegendLocation.BY_COORDINATES) {
-            Double [] legPos = legend.getPosition();
-
-            legendCorner[0] = (float) (axesPos[0] + legPos[0] * axesBounds[2]);
-            legendCorner[1] = (float) (axesPos[1] + (1.0 - legPos[1]) * axesBounds[3] - legendDims[1]);
+        switch (legendLocation) {
+            case IN_UPPER_RIGHT:
+                legendCorner[0] = (float) (urBoxCorner[0] - xOffset - legendDims[0]);
+                legendCorner[1] = (float) (urBoxCorner[1] - yOffset - legendDims[1]);
+                break;
+            case IN_UPPER_LEFT:
+                legendCorner[0] = (float) (llBoxCorner[0] + xOffset);
+                legendCorner[1] = (float) (urBoxCorner[1] - yOffset - legendDims[1]);
+                break;
+            case IN_LOWER_RIGHT:
+                legendCorner[0] = (float) (urBoxCorner[0] - xOffset - legendDims[0]);
+                legendCorner[1] = (float) (llBoxCorner[1] + yOffset);
+                break;
+            case IN_LOWER_LEFT:
+                legendCorner[0] = (float) (llBoxCorner[0] + xOffset);
+                legendCorner[1] = (float) (llBoxCorner[1] + yOffset);
+                break;
+            case OUT_UPPER_RIGHT:
+                legendCorner[0] = (float) (urBoxCorner[0] + xOffset);
+                legendCorner[1] = (float) (urBoxCorner[1] - legendDims[1]);
+                break;
+            case OUT_UPPER_LEFT:
+                legendCorner[0] = (float) (llBoxCorner[0] - xOffset - legendDims[0]);
+                legendCorner[1] = (float) (urBoxCorner[1] - legendDims[1]);
+                break;
+            case OUT_LOWER_RIGHT:
+                legendCorner[0] = (float) (urBoxCorner[0] + xOffset);
+                legendCorner[1] = (float) (llBoxCorner[1]);
+                break;
+            case OUT_LOWER_LEFT:
+                legendCorner[0] = (float) (llBoxCorner[0] - xOffset - legendDims[0]);
+                legendCorner[1] = (float) (llBoxCorner[1]);
+                break;
+            case UPPER_CAPTION:
+                legendCorner[0] = (float) (llBoxCorner[0]);
+                legendCorner[1] = (float) (urBoxCorner[1] + yOffset);
+
+                /* x-axis at the top */
+                if (xAxisLocation == 1) {
+                    /* To do: use the actual label+tick bounding box height */
+                    legendCorner[1] += TICK_LABEL_SIZE;
+                }
+                break;
+            case LOWER_CAPTION:
+                legendCorner[0] = (float) (llBoxCorner[0]);
+                legendCorner[1] = (float) (llBoxCorner[1] - yOffset - legendDims[1]);
+
+                /* x-axis at the bottom */
+                if (xAxisLocation == 0) {
+                    /* To do: use the actual label+tick bounding box height */
+                    legendCorner[1] -= TICK_LABEL_SIZE;
+                }
+                break;
+            case BY_COORDINATES:
+                Double[] legPos = legend.getPosition();
+
+                legendCorner[0] = (float) (axesPos[0] + legPos[0] * axesBounds[2]);
+                legendCorner[1] = (float) (axesPos[1] + (1.0 - legPos[1]) * axesBounds[3] - legendDims[1]);
+                break;
         }
 
         /* y-axis positioned to the left */
@@ -327,7 +359,7 @@ public class LegendDrawer {
         /* Afterwards, draw the elements making up the Legend using the previously computed values */
 
         /* Legend background vertex data: lower-left, lower-right, upper-left and upper-right corners */
-        float [] rectangleVertexData = new float[] {
+        float[] rectangleVertexData = new float[] {
             (float)legendCorner[0], (float)legendCorner[1], Z_FRONT, 1.0f,
             (float)(legendCorner[0] + legendDims[0]), (float)legendCorner[1], Z_FRONT, 1.0f,
             (float)legendCorner[0], (float)(legendCorner[1] + legendDims[1]), Z_FRONT, 1.0f,
@@ -372,10 +404,10 @@ public class LegendDrawer {
         drawingTools.draw(legendRectangle, appearance);
 
         /* Lines: 3 vertices each, left, middle, and right */
-        float [] lineVertexData = new float[] {0.25f, 0.75f, Z_FRONT, 1.0f,
-                                               0.5f, 0.75f, Z_FRONT, 1.0f,
-                                               0.75f, 0.75f, Z_FRONT, 1.0f
-                                              };
+        float[] lineVertexData = new float[] {0.25f, 0.75f, Z_FRONT, 1.0f,
+                                              0.5f, 0.75f, Z_FRONT, 1.0f,
+                                              0.75f, 0.75f, Z_FRONT, 1.0f
+                                             };
 
         double normSpriteMargin = 0.0;
 
@@ -403,11 +435,11 @@ public class LegendDrawer {
         lineVertexData[9] = lineVertexData[9] + 0.5f * deltaHeight;
 
         /* Bar vertex data: lower-left, lower-right, upper-left and upper-right corners */
-        float [] barVertexData = new float[] {0.25f, 0.75f, Z_FRONT, 1.0f,
-                                              0.75f, 0.75f, Z_FRONT, 1.0f,
-                                              0.25f, 1.00f, Z_FRONT, 1.0f,
-                                              0.75f, 1.00f, Z_FRONT, 1.0f
-                                             };
+        float[] barVertexData = new float[] {0.25f, 0.75f, Z_FRONT, 1.0f,
+                                             0.75f, 0.75f, Z_FRONT, 1.0f,
+                                             0.25f, 1.00f, Z_FRONT, 1.0f,
+                                             0.75f, 1.00f, Z_FRONT, 1.0f
+                                            };
 
         float barHeight = BAR_HEIGHT * deltaHeight;
 
@@ -440,7 +472,7 @@ public class LegendDrawer {
         }
 
         /* Legend text */
-        float [] spritePosition = new float[] {lineVertexData[8] + (float) xOffset, (float) (legendCorner[1] + yOffset), Z_FRONT};
+        float[] spritePosition = new float[] {lineVertexData[8] + (float) xOffset, (float) (legendCorner[1] + yOffset), Z_FRONT};
 
         /* Draw the sprite only if there are valid links */
         if (nbValidLinks > 0) {
@@ -452,7 +484,7 @@ public class LegendDrawer {
         projectionStack.pop();
 
         /* Output the position if required */
-        Double [] legendPosition = new Double[2];
+        Double[] legendPosition = new Double[2];
 
         if (axesDims[0] == 0.0) {
             axesDims[0] = 1.0;
@@ -628,7 +660,7 @@ public class LegendDrawer {
      */
     private int getNumberValidLinks(Legend legend) {
         int nbValidLinks = 0;
-        Integer [] links = legend.getLinks();
+        Integer[] links = legend.getLinks();
 
         for (Integer link : links) {
             Polyline currentLine = (Polyline) GraphicController.getController().getObjectFromId(link);
@@ -652,7 +684,7 @@ public class LegendDrawer {
      */
     private void updateLinks(Legend legend, int nbValidLinks) {
         int i1 = 0;
-        ArrayList <Integer> newLinks = new ArrayList<Integer>(0);
+        ArrayList <Integer> newLinks = new ArrayList<Integer>(legend.getLinks().length);
         String[] newStrings;
         Integer[] newDims = new Integer[2];
 
index c8c6cb8..ff84b3b 100644 (file)
@@ -65,7 +65,6 @@ public class LegendSpriteDrawer extends TextObjectSpriteDrawer implements Textur
         return a;
     }
 
-
     /**
      * Compute and return the matrix of text string from the given {@see Legend} object.
      * The legend text array is treated as a 1D-array.
@@ -94,6 +93,4 @@ public class LegendSpriteDrawer extends TextObjectSpriteDrawer implements Textur
 
         return texts;
     }
-
-
 }
index b4b0bd5..0094cc7 100644 (file)
@@ -162,7 +162,7 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
                         textEntity.setFont(font);
                         entities[column][line] = textEntity;
                         dimension = textEntity.getSize();
-                        ascent = textEntity.getLayout().getAscent();
+                        ascent = textEntity.isValid() ? textEntity.getLayout().getAscent() : 0;
                     }
 
                     lineAscent[line] = Math.max(lineAscent[line], ascent);
@@ -217,9 +217,9 @@ public class TextObjectSpriteDrawer implements TextureDrawer {
                 if (entity != null) {
                     if (entity instanceof TextEntity) {
                         TextEntity textEntity = (TextEntity) entity;
-                        TextLayout layout = textEntity.getLayout();
+                        float ascent = textEntity.isValid() ? textEntity.getLayout().getAscent() : 0.f;
                         double deltaX = alignmentFactor * (columnWidth[column] - textEntity.getSize().getWidth());
-                        drawingTools.draw(textEntity, (int) (x + deltaX), Math.round(y - layout.getAscent() + lineAscent[line]));
+                        drawingTools.draw(textEntity, (int) (x + deltaX), Math.round(y - ascent + lineAscent[line]));
                         y += lineHeight[line] + currentVMargin;
                         line++;
                     } else if (entity instanceof Icon) {
index bc58870..bcd60ba 100644 (file)
@@ -80,6 +80,14 @@ public class RulerDrawer {
     }
 
     /**
+     * Get the sprite factory
+     * @return the sprite factory
+     */
+    public RulerSpriteFactory getSpriteFactory() {
+        return this.spriteFactory;
+    }
+
+    /**
      * Draw the ruler
      * @param drawingTools the {@link DrawingTools} of the canvas where the ruler will be drawn.
      */
@@ -140,6 +148,10 @@ public class RulerDrawer {
         oneShotRulerDrawer.dispose();
     }
 
+    public double getDistanceRatio() {
+        return oneShotRulerDrawer.getDistanceRatio();
+    }
+
     /**
      * This class actually perform all the rendering of one ruler.
      */
@@ -170,6 +182,7 @@ public class RulerDrawer {
         private List<Double> subTicksValue;
         private List<Double> ticksValue;
         private int density;
+        private double distRatio;
 
         public OneShotRulerDrawer() { }
 
@@ -185,6 +198,10 @@ public class RulerDrawer {
             rulerModel = null;
         }
 
+        public double getDistanceRatio() {
+            return distRatio;
+        }
+
         /**
          * Compute different parameters on a ruler
          * @param drawingTools the {@link DrawingTools} of the canvas where the ruler will be drawn.
@@ -208,7 +225,6 @@ public class RulerDrawer {
             windowSubTicksDelta = normalizedProjectedTicksDirection.times(rulerModel.getSubTicksLength());
             windowTicksDelta = normalizedProjectedTicksDirection.times(rulerModel.getTicksLength());
 
-
             DecimalFormat format;
             if (rulerModel.isAutoTicks()) {
                 format = computeAutoGraduation();
@@ -257,12 +273,11 @@ public class RulerDrawer {
         }
 
         /**
-         * Compute the ratio between windows ticks norm and the sprite distance.
-         * @param windowTicksNorm the windows tics norm.
-         * @return the ratio between windows ticks norm and the sprite distance.
-         */
+             * Compute the ratio between windows ticks norm and the sprite distance.
+             * @param windowTicksNorm the windows tics norm.
+             * @return the ratio between windows ticks norm and the sprite distance.
+             */
         private double computeTicksDistanceRatio(double windowTicksNorm) {
-            double distRatio;
             if (windowTicksNorm == 0) {
                 distRatio = 1.0;
             } else if (maximalSpritesDistance == 0) {
@@ -334,7 +349,6 @@ public class RulerDrawer {
                     Vector3d delta = projectCenterToEdge(textureSize, windowTicksDelta);
                     PositionedSprite newSprite = new PositionedSprite(sprite, textureSize, windowPosition.plus(windowTicksDelta.plus(delta)));
                     newSpritesList.add(newSprite);
-
                     Vector3d farDelta = windowTicksDelta.plus(delta.times(2.0));
                     currentMaximalSpritesDistance = Math.max(currentMaximalSpritesDistance, farDelta.getNorm());
                 }
@@ -354,7 +368,6 @@ public class RulerDrawer {
                 }
             }
 
-
             this.graduations = ticksGraduation;
             this.maximalSpritesDistance = maxSpritesDistance;
 
@@ -522,10 +535,11 @@ public class RulerDrawer {
 
             /* +1 is used to have a space between the tick and its label */
             Dimension textureSize = sprite.getDataProvider().getTextureSize();
-            double ratioX = textureSize.width / Math.abs(usedDirection.getX()) + 1;
-            double ratioY = textureSize.height / Math.abs(usedDirection.getY()) + 1;
+            double ratioX = textureSize.width / Math.abs(usedDirection.getX());
+            double ratioY = textureSize.height / Math.abs(usedDirection.getY());
             double ratio = Math.min(ratioY, ratioX) / 2;
-            return usedDirection.times(ratio);
+
+            return usedDirection.times((ratio + 1) / 2);
         }
 
         /**
@@ -544,11 +558,11 @@ public class RulerDrawer {
                 usedDirection = direction;
             }
 
-            /* +1 is used to have a space between the tick and its label */
-            double ratioX = textureSize.width / Math.abs(usedDirection.getX()) + 1;
-            double ratioY = textureSize.height / Math.abs(usedDirection.getY()) + 1;
-            double ratio = Math.min(ratioY, ratioX) / 2;
-            return usedDirection.times(ratio);
+            double ratioX = textureSize.width / Math.abs(usedDirection.getX());
+            double ratioY = textureSize.height / Math.abs(usedDirection.getY());
+            double ratio = Math.min(ratioY, ratioX);
+
+            return usedDirection.times((ratio + 1) / 2);
         }
 
         /**
index e225f18..573cb61 100644 (file)
@@ -173,7 +173,7 @@ public class BufferedImageTextureDrawingTools implements TextureDrawingTools {
             g2d.setColor(textEntity.getTextColor());
             TextLayout textLayout = new TextLayout(textEntity.getText(), textEntity.getFont(), g2d.getFontRenderContext());
             Rectangle2D bounds = textLayout.getBounds();
-            textLayout.draw(g2d, (float) (x + 1 - bounds.getX()), (float) (y + textLayout.getAscent()));
+            textLayout.draw(g2d, (float) (x + 1 - bounds.getX()), y + textLayout.getAscent());
         }
     }