Hello.
I think I have a fix for this bug:
http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=506
Basically, the problem is that if there is a magnifying affine transformation
set on the graphics object and one tries to draw a line with small thickness
and round end caps, the end caps appear jagged. This is because the computation
of the length of the array that contains the points on the "pen" with which the
decoration is drawn does not take into account the size of the pen after the
magnification of the affine transformation. So, for example, if the line length
was set to 1, and the transformation was a scaling by 10, the resulting pen
would have a diameter of 10, but only 3 pen points would be computed
(pi*untransformedLineWidth), so the end cap looks like a triangle.
My fix computes an approximation of the circumference of the transformed pen
(which is an ellipse) and uses that as the number of points on the pen. The
approximation is crude, but it is simple, faster than alternatives
(http://en.wikipedia.org/wiki/Ellipse#Circumference), and I can say from
observations that it works fairly well.
There is also icing on the cake, in the form of slight improvements in
performance when the scaling is a zooming out. Example: if the original line
width was 100, but g2d.scale(0.1,0.1) was set, then the resulting line would
have a width of 10, so only ~31 points are necessary for the decoration to look
like a circle, but without this patch, about 314 points are computed (and a
line is emitted to each one of them).
I appreciate any feedback.
Regards,
Denis Lila.
exporting patch:
# HG changeset patch
# User Denis Lila <dl...@redhat.com>
# Date 1276110761 14400
# Node ID 5cc40c7f2678d320519013b58af6808a0516cd68
# Parent 4d55419ce99e749da5037fa4d8247117f1a5cc2e
Fixed bug http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=506
diff --git a/src/share/classes/sun/java2d/pisces/Stroker.java b/src/share/classes/sun/java2d/pisces/Stroker.java
--- a/src/share/classes/sun/java2d/pisces/Stroker.java
+++ b/src/share/classes/sun/java2d/pisces/Stroker.java
@@ -209,7 +209,34 @@
this.miterLimitSq = (long)(limitSq*65536.0*65536.0);
}
- this.numPenSegments = (int)(3.14159f*lineWidth/65536.0f);
+ // The pen is a circle mapped through the linear transformation
+ // this.transform; therefore, we must calculate the circumference
+ // of the mapped pen, not the pen. If we calculate the
+ // circumference of the pen without taking into account this.transform
+ // the round end caps will look jagged. However, the way I calculate
+ // the circumference of the mapped pen is just a crude approximation, so
+ // if anyone reading this knows how to better compute the circumference
+ // of ellipses, please fix it.
+
+ // So, we map the points (1,0), (0,1), (-1,0), and (0,-1) through
+ // the transformation. The results are (m00,m10), (m01,m11),
+ // (-m00,-m01), and (-m01,-m11). We simply calculate the lengths of
+ // the mapped horizontal and vertical diameters, scale them by the
+ // actual radius of the circle (i.e. lineWidth / 2), calculate the
+ // circumference of a circle whose diameter is the greater of those
+ // two, and pretend this calculation is a good enough approximation
+ // to the circumference of the mapped circle.
+ double dx1 = 2*dm00;
+ double dy1 = 2*dm10;
+ double dx2 = 2*dm01;
+ double dy2 = 2*dm11;
+ double radius = lineWidth / (2 * 65536.0);
+ // The diameters:
+ double mappedD1 = radius * java.lang.Math.sqrt(dx1*dx1 + dy1*dy1);
+ double mappedD2 = radius * java.lang.Math.sqrt(dx2*dx2 + dy2*dy2);
+ double mappedD = (mappedD1 < mappedD2) ? mappedD2 : mappedD1;
+
+ this.numPenSegments = (int) (3.14159 * mappedD);
if (pen_dx == null || pen_dx.length < numPenSegments) {
this.pen_dx = new int[numPenSegments];
this.pen_dy = new int[numPenSegments];