JDK-4489667 : Graphics draw() and fill() don't always line up polygons
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.4.0
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2001-08-08
  • Updated: 2001-08-24
  • Resolved: 2001-08-22
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.0Resolved
Related Reports
Duplicate :  
Description

Name: nt126004			Date: 08/08/2001


java version "1.4.0-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta-b65)
Java HotSpot(TM) Client VM (build 1.4.0-beta-b65, mixed mode)


It seems there are some cases where Graphics draw() and fill() don't always
line up correctly.  In particular, I know that if a draw(myPolygon) and fill
(myPolygon) are done on the graphics object of a BufferedImage, this outline
drawn with draw(myPolygon) will not correctly outline the filled polygon drawn
with fill(myPolygon).  However, if these same operations are performed directly
on a graphics object of a JComponent in jdk1.4-beta, this problem does not
occur.

I have created a program to demonstrate this.  On the left will be the polygon
drawn directly to the JPanel, and on the right the polygon drawn in a
BufferedImage, where the BufferedImage is drawn on the panel.  Note that when
looking at the polygon on the right, white pixels are escaping the black
border, and red pixels are somehow staying inside.  These white pixels always
escape up and left by one pixel.  Because of this, the bottom right pixels of
the polygon that should be white end up being red.  I suspect somehow something
is off by one pixel in the second case.  Maybe has to do with aliasing (as
antialiasing might not show the problem)?

I have a screenshot showing the program running from jdk1.3.1 and jdk1.4-beta
and how they differ.  To sum it up, in 1.4-beta, left looks good, right looks
bad.  In 1.3.1, both look bad.  I will send this screenshot upon request.

*NOTE ABOUT TEST PROGRAM*  The way the cursor-like polygons are created is not
obvious.  It should be noted that the way the polygon is made does not matter,
as long as the polygon is made (just added Points to a Polygon).  I kept this
cursor-like polygon because I thought it showed the problem well.  Also note
that uncommenting the while loop in main() can make the polygons spin, showing
the problem at different angles.  As they spin you'll note that white pixels
only escape the black border up and left 1 pixel.

I am running a completely up-to-date Windows 2000 Professional box.  My video
card is a 3dfx Voodoo 3 3000.  My driver has the following info:

Driver Provider: 3dfx Interactive, Inc.
Driver Date:     11/2/2000
Driver Version:  5.0.2195.232
Digital Signer:  Microsoft Windows Hardware Compatibility Publisher

Here is driver files info:
--File--                               --Version--
C:\WINNT\System32\3dfxOGL.dll          1.0.0.0734 ICD
C:\WINNT\System32\3dfxSpl2.dll         1.00.00.0004
C:\WINNT\System32\3dfxSpl3.dll         1.00.00.0004
C:\WINNT\System32\3dfxvs.dll           5.00.2195.0232
C:\WINNT\System32\DRIVERS\3dfxvsm.sys  5.00.2195.0232
C:\WINNT\System32\glide2x.dll          2.61.00.0658
C:\WINNT\System32\glide3x.dll          3.10.00.0658



=-=-=-=-=-=-=-=-= TestFill.java =-=-=-=-=-=-=-=-=
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;

public class TestFill extends JPanel
{
    // the angle the polygon is facing
    private static double angle = .75;
    // the buffered image which polygon will be drawn (badly) on
    private BufferedImage image;
    // the seven points of the polygon
    private Point p1;
    private Point p2;
    private Point p3;
    private Point p4;
    private Point p5;
    private Point p6;
    private Point p7;

    public static void main(String[] argv)
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new TestFill());
        f.setSize(100,80);
        f.show();
// uncomment this to see the polygons at different angles
/*       while (true)
        {
            // change this amount to make the rotation faster/slower
            angle += 0.000002;
            f.repaint();
        }*/
    }

    public void paintComponent(Graphics g)
    {
        setBackground(Color.red);
        super.paintComponent(g);
        // length of both sides of buffered image
        int size = 32;
        // x and y coordinates of center of image
        int x = size / 2;
        int y = x;
        // make the new buffered image to draw stuff to
        image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
        // graphics 2d object of the buffered image, shown on right
        Graphics2D rightGraphics = image.createGraphics();
        // graphics 2d object for the polygon drawn directly to the JPanel
        Graphics2D leftGraphics = (Graphics2D) g;
        // ensure antialiasing is OFF (or problem will be blurred out)
        leftGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                      RenderingHints.VALUE_ANTIALIAS_OFF);
        // make the points of the polygon (depending on current angle)
        // note that it doesn't really matter what these points are, they are
        // merely points added to a polygon (which happen to make a familiar
        // cursor picture)
        p1 = makePoint(0, 15);
        p2 = makePoint(-105.9, 7.28);
        p3 = makePoint(-90, 1+.5);
        p4 = makePoint(-174.3+2, 10.05+.5);
        p5 = makePoint(174.3-2, 10.05+.5);
        p6 = makePoint(90, 1+.5);
        p7 = makePoint(105.9, 7.28);
        // put the points in the polygon
        Polygon p = new Polygon();
        p.addPoint(x + p1.x, y - p1.y);
        p.addPoint(x + p2.x, y - p2.y);
        p.addPoint(x + p3.x, y - p3.y);
        p.addPoint(x + p4.x, y - p4.y);
        p.addPoint(x + p5.x, y - p5.y);
        p.addPoint(x + p6.x, y - p6.y);
        p.addPoint(x + p7.x, y - p7.y);
        
        // here's the meat of the test.. do same calls to leftGraphics and
        // rightGraphics, and note that they do not look identical...
        
        // fill with white background of polygon (for left and right)
        leftGraphics.setColor(Color.white);
        leftGraphics.fill(p);
        rightGraphics.setColor(Color.white);
        rightGraphics.fill(p);
        // outline polygon with black (for left and right)
        leftGraphics.setColor(Color.black);
        leftGraphics.draw(p);
        rightGraphics.setColor(Color.black);
        rightGraphics.draw(p);
        // draw this buffered image on the right (which shows the problem)
        g.drawImage(image, 50, 0, this);
    }

    // create point from angle and distance from center (all that matters is
    // this returns a point to be put in the polygon (i.e. not worth debugging))
    private Point makePoint(double angleOffset, double dist)
    {
        return new Point((int)(dist * Math.cos(angle +
                                               Math.toRadians(angleOffset))),
                         (int)(dist * Math.sin(angle +
                                               Math.toRadians(angleOffset))));
    }
}
=-=-=-=-=-=-=-=-= END TestFill.java =-=-=-=-=-=-=-=-=
(Review ID: 129586) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: merlin-beta3 FIXED IN: merlin-beta3 INTEGRATED IN: merlin-beta3
14-06-2004

WORK AROUND Name: nt126004 Date: 08/08/2001 Use antialiasing (might work) if that fits what you need. However, antialiasing is not always wanted. In my case, antialiasing is unacceptable. ======================================================================
11-06-2004

EVALUATION The draw routines were honoring the STROKE_CONTROL hint, but the fill routines were using the raw geometry as if the hint were set to STROKE_PURE so there was a mismatch. The fill routines were adjusted to perform the same sub-pixel normalization as the draw routines when the STROKE_CONTROL hint is set. ###@###.### 2001-08-21
21-08-2001