Skip to main content

[JAVA2D] draw/fill mismatch on 1.4.2_02

4 replies [Last post]
Anonymous

I'm working with the JFreeChart library (www.jfree.org) and I am trying
to resolve a discrepancy in the rendering of bars on bar chart.
Basically I have a Rectangle2D shape representing a bar and I fill that
shape and then draw it with a different color. The shape has a couple
of translations applied but I don't think there are any other
transformations. So I should get a filled rectangle on the screen with
an outline. However, sometimes the outline does not match the filled
shape. There are gaps on some occasions on the edges and sometimes the
fill overruns the boundaries of the draw.

I found this message from Jim Graham on mail-archive.com regarding this
problem:
http://www.mail-archive.com/java2d-interest@capra.eng.sun.com/msg02156.h
tml

Jim states that this problem is fixed in the 1.4 runtimes where both
fills and strokes are normalized by default, but that doesn't appear to
be the case for me on 1.4.2_02. When I set KEY_STROKE_CONTROL to
STROKE_PURE, the gaps and overruns disappear, but now some of the edges
of the stroke are thicker than others so it doesn't look uniform. When
I antialias everything, it looks good, but I'd prefer to stay away from
AA for the time being.

Am I missing something or does anyone have any hints on how to resolve
this problem?

I'm working on Windows XP Professional with java 1.4.2_02 and JFreeChart
0.9.16.

The code for this is as simple as:

Rectangle2D bar = ...;
g2.setPaint(gradientPaint);
g2.fill(bar);
g2.setColor(Color.black);
g2.draw(bar);

Thanks,
-Brian

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".
[att1.html]

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Brian Nahas

As a workaround for the discrepancy, I am now using rectangles with a
width of 1.0 for lines and then calling fill instead of draw. Things
seem to align properly when I do that.

-Brian

-----Original Message-----
From: Discussion list for Java 2D API
[mailto:JAVA2D-INTEREST@JAVA.SUN.COM] On Behalf Of Jim Graham
Sent: Sunday, February 15, 2004 6:29 AM
To: JAVA2D-INTEREST@JAVA.SUN.COM
Subject: Re: [JAVA2D] draw/fill mismatch on 1.4.2_02

> So if I wanted the fill and draw of the same shape to align properly,
> I should stick to one type of Paint?

Yes, and as you discovered through your test case, that may not even be
enough because some of our pipelines still don't have agreement between
their fills and draws.

> Fill/Draw status
> ------------------------------------------------
> Color/Color fine
> Gradient/Color appears to be fine**
> Color/Gradient gaps and overlaps under some conditions
> Gradient/Gradient gaps and overlaps under some conditions

I didn't run your code, but I can believe these results. I believe we
use the "wide line" code with a width of 1 pixel when we are drawing
gradient lines, but that pipeline has so much math in it that I wouldn't
doubt that it fails to match the fill of the same path exactly. For
thin lines it would be nice if we hit the same pixels as a simple
bresenham line filler would normally hit but that will take a number of
changes in our code to realize as it is currently architected.

I'd recommend slightly increasing the line width if you are planning to
do Grad/Grad or mixed rendering to make sure the gaps are covered.

...jim

========================================================================
===
To unsubscribe, send email to listserv@java.sun.com and include in the
body of the message "signoff JAVA2D-INTEREST". For general help, send
email to listserv@java.sun.com and include in the body of the message
"help".

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Brian Nahas

Interesting.

So if I wanted the fill and draw of the same shape to align properly, I
should stick to one type of Paint?

I coded up a simple test (code is below my signature) with 4 draw/fill
combinations of Color and GradientPaint.

Fill/Draw status
------------------------------------------------
Color/Color fine
Gradient/Color appears to be fine**
Color/Gradient gaps and overlaps under some conditions
Gradient/Gradient gaps and overlaps under some conditions

**Color/Color is the only one that is properly aligned on my charts.
There are gaps/overlaps with Gradient/Color, and your comments below
apply to this condition.

So it appears that I have a problem if I want to use GradientPaint. Any
insights? Thanks...

-Brian

import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;

public class DrawFillTestFrame extends JFrame {
public DrawFillTestFrame() throws HeadlessException {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel panel = new JPanel() {
protected void paintComponent(Graphics g) {
super.paintComponent(g);

Graphics2D g2 = (Graphics2D) g;

double w = getWidth();
double h = getHeight();

g2.translate(0.53434, 0.55455);
Rectangle2D r1 = new Rectangle2D.Double(.05 * w, .05 *
h, .40 * w, .40 * h);
Rectangle2D r2 = new Rectangle2D.Double(.55 * w, .05 *
h, .40 * w, .40 * h);
Rectangle2D r3 = new Rectangle2D.Double(.05 * w, .55 *
h, .40 * w, .40 * h);
Rectangle2D r4 = new Rectangle2D.Double(.55 * w, .55 *
h, .40 * w, .40 * h);

// Rectangle2D r1 = new Rectangle2D.Double(10.1234,
10.5353, 200.81242, 100.18989);
// Rectangle2D r2 = new Rectangle2D.Double(220.25235,
10.9134, 200.989385, 100.324344);
// Rectangle2D r3 = new Rectangle2D.Double(10.91284,
120.123123, 200.982983, 100.12321);
// Rectangle2D r4 = new Rectangle2D.Double(220.09823,
120.1232, 200.89498, 100.12323);

g2.setPaint(Color.red);g2.fill(r1);g2.setPaint(Color.black);g2.draw(r1);

GradientPaint gp = new GradientPaint(1, 10, Color.black,
0, 400, Color.yellow);
GradientPaint gp2 = new GradientPaint(1, 10,
Color.black, 0, 400, Color.lightGray);

g2.setPaint(gp);g2.fill(r2);g2.setPaint(Color.red);g2.draw(r2);

g2.setPaint(gp);g2.fill(r3);g2.setPaint(gp2);g2.draw(r3);

g2.setPaint(Color.red);g2.fill(r4);g2.setPaint(gp2);g2.draw(r4);
}
};
panel.setBackground(Color.white);
panel.setPreferredSize(new Dimension(450, 250));
getContentPane().setLayout(new BorderLayout());
getContentPane().add(panel, BorderLayout.CENTER);
pack();
}

public static void main(String[] args) {
DrawFillTestFrame frame = new DrawFillTestFrame();
frame.show();
}
}

-----Original Message-----
From: Discussion list for Java 2D API
[mailto:JAVA2D-INTEREST@JAVA.SUN.COM] On Behalf Of Jim Graham
Sent: Thursday, February 12, 2004 3:15 PM
To: JAVA2D-INTEREST@JAVA.SUN.COM
Subject: Re: [JAVA2D] draw/fill mismatch on 1.4.2_02

> Rectangle2D bar = ...;
> g2.setPaint(gradientPaint);
> g2.fill(bar);
> g2.setColor(Color.black);
> g2.draw(bar);

The issue here is that we could use completely different implementations
to handle gradients vs. solid colors and while each of those pipelines
enforces consistency between its own fills and draws, they may do so in
different ways.

In particular, if this is drawing to the screen or to an accelerated
offscreen, the draw with the black color may be handled by GDI or X11 or
some other platform rendering API, but the Gradients are not handled
directly by most of those platform APIs so we need to switch to software
to do it. Most of the platform APIs use "round subpixel coordinates to
the nearest integer because the API only allows int coordinates in the
first place" as their technique for controlling the stroke consistency
whereas our software renderers use a more sophisticated "normalize the
coords to a specific sub-pixel offset that will tend to create less
pigeon-holing of wide-line widths" (similar to the processing done to
improve consistency of strokes in other floating-point capable rendering
APIs)...

...jim

========================================================================
===
To unsubscribe, send email to listserv@java.sun.com and include in the
body of the message "signoff JAVA2D-INTEREST". For general help, send
email to listserv@java.sun.com and include in the body of the message
"help".

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Jim Graham

> So if I wanted the fill and draw of the same shape to align properly,
> I should stick to one type of Paint?

Yes, and as you discovered through your test case, that may not even
be enough because some of our pipelines still don't have agreement
between their fills and draws.

> Fill/Draw status
> ------------------------------------------------
> Color/Color fine
> Gradient/Color appears to be fine**
> Color/Gradient gaps and overlaps under some conditions
> Gradient/Gradient gaps and overlaps under some conditions

I didn't run your code, but I can believe these results. I believe
we use the "wide line" code with a width of 1 pixel when we are
drawing gradient lines, but that pipeline has so much math in it
that I wouldn't doubt that it fails to match the fill of the same
path exactly. For thin lines it would be nice if we hit the same
pixels as a simple bresenham line filler would normally hit but
that will take a number of changes in our code to realize as it
is currently architected.

I'd recommend slightly increasing the line width if you are planning
to do Grad/Grad or mixed rendering to make sure the gaps are
covered.

...jim

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Jim Graham

> Rectangle2D bar = ...;
> g2.setPaint(gradientPaint);
> g2.fill(bar);
> g2.setColor(Color.black);
> g2.draw(bar);

The issue here is that we could use completely different implementations
to handle gradients vs. solid colors and while each of those pipelines
enforces consistency between its own fills and draws, they may do so
in different ways.

In particular, if this is drawing to the screen or to an accelerated
offscreen, the draw with the black color may be handled by GDI or
X11 or some other platform rendering API, but the Gradients are not
handled directly by most of those platform APIs so we need to switch
to software to do it. Most of the platform APIs use "round subpixel
coordinates to the nearest integer because the API only allows int
coordinates in the first place" as their technique for controlling
the stroke consistency whereas our software renderers use a more
sophisticated "normalize the coords to a specific sub-pixel offset
that will tend to create less pigeon-holing of wide-line widths"
(similar to the processing done to improve consistency of strokes
in other floating-point capable rendering APIs)...

...jim

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".