[OpenJDK 2D-Dev] Fix for drawing round endcaps on scaled lines.
dlila at redhat.com
Thu Jun 17 20:17:31 UTC 2010
So, I have been thinking about this, and I can't see a good
way to do it that wouldn't involve heavy changes to Pisces.
In order for Stroker to generate Bezier quarter circles, it would
have to implement a curveTo method, which means Stroker should
start implementing PathConsumer2D and instead of using a LineSink
output it would have to use a PathConsumer2D output (either that, or
LineSink should include a curveTo method, but then there won't really
be any difference between a LineSink and a PathConsumer2D. By the way,
LineSink doesn't have any implemented methods, so why is it an abstract
class as opposed to an interface?)
Stroker is used in 3 ways:
1. As an implementation of BasicStroke's createStrokedShape method. This
uses a Path2D object as output.
2. As a way of feeding a PathConsumer2D without calling createStrokedShape
to generate an intermediate Shape. This uses a PathConsumer2D output.
3. As a way of feeding lines to a Renderer object, which generates alpha
tiles used for anti-aliasing that are fed to a cache and extracted as needed
by an AATileGenerator. Obviously, Stroker's output here is a Renderer.
1 and 2 aren't problems, because the underlying output objects support
Bezier curves. 3, however, doesn't, and it seems like implementing a
curveTo method for Renderer would be very difficult because the way it
generates alpha tiles is by scanning the drawn edges with horizontal
scan lines, and for each scan line finding the x-intersections of the scan
lines and the edges. Then it determines the alpha values (I'm not too sure
how it does this).
In order to implement Bezier curves in Renderer, we would have to have
a quick way of computing, for each scan line, all its intersections with
however many Bezier curves are being drawn.
I haven't given much thought to how this could be done, as I am not very
familiar with Bezier curves, but it doesn't seem easy enough to justify
fixing such a small bug.
----- Original Message -----
From: "Jim Graham" <james.graham at oracle.com>
To: "Denis Lila" <dlila at redhat.com>
Cc: 2d-dev at openjdk.java.net
Sent: Wednesday, June 9, 2010 7:42:33 PM GMT -05:00 US/Canada Eastern
Subject: Re: [OpenJDK 2D-Dev] Fix for drawing round endcaps on scaled lines.
I don't understand - why do we generate sample points based on the size
of the cap? Why not generate a pair of bezier quarter-circles and let
the rasterizer deal with sampling?
Denis Lila wrote:
> I think I have a fix for this bug:
> 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.
> Denis Lila.
More information about the 2d-dev