JDK-4465509 : drawPolygon/fillPolygon behaviour different in 1.4 compared to previous releases
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.3.0,1.4.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux,solaris_8,windows_2000
  • CPU: x86,sparc
  • Submitted: 2001-06-03
  • Updated: 2001-08-24
  • Resolved: 2001-08-24
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.0 beta3Fixed
Related Reports
Duplicate :  
Duplicate :  
Description

Name: boT120536			Date: 06/03/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)

When a polygon is filled and drawn using the same
parameters in JDK 1.4.0 beta on Linux the outline and fill
don't match.  This behaviour is different from all previous
releases.

I want to use small circles as markers on a map.  Since
this is in an applet I want to support JDK 1.0 and 1.1.
As previously reported (4151279), since JDK 1.2 there is
a difference between the way ovals are drawn when drawing
directly to a canvas and when drawing to an offscreen
image.  This bug has been open for nearly three years and
still hasn't been fixed in JDK 1.4.0.

  To produce acceptable-looking circles in JDK 1.2 and above
I've been forced to draw them by hand using polygons.
This no longer works in JDK 1.4.0 beta, as the polygon
outline and fill don't match.

The program below illustrates the problem.  It fills and
draws a number of small circles.  When the mouse is clicked
in the canvas it cycles through three different ways of
drawing:  directly to the canvas; to an offscreen image
using fillOval/drawOval; to an offscreen image with the
circles drawn as polygons.

In JDK 1.0 and 1.1 these three methods all produce the same
result.  In JDK 1.2 and 1.3 the second method results in
horrible-looking circles, while drawing by hand gives the
same result as drawing direct to the canvas.  In JDK 1.4.0
beta drawing by hand also produces unacceptable results
because of the offset between the polygon fill and draw.


import java.awt.* ;

public class PolygonBug extends Canvas {
    private Image offscreen = null ;
    private Graphics g0 = null ;
    private int click = 0 ;

    // offsets used to draw circles as polygons
    static private final int xcircle[][] = {
        null,
        null,
        null,
        { 0,1,2,2,1,0,-1,-1,0 },
        { -1,1,2,2,1,-1,-2,-2,-1 },
        { 0,1,3,3,1,0,-2,-2,0 },
        { -1,1,3,3,1,-1,-3,-3,-1 },
        { -1,2,4,4,2,-1,-3,-3,-1 },
        { -1,1,2,3,3,4,4,3,3,2,1,-1,-2,-3,-3,-4,-4,-3,-3,-2,-1},
    } ;

    static private final int ycircle[][] = {
        null,
        null,
        null,
        { -1,-1,0,1,2,2,1,0,-1 },
        { -2,-2,-1,1,2,2,1,-1,-2 },
        { -2,-2,0,1,3,3,1,0,-2 },
        { -3,-3,-1,1,3,3,1,-1,-3 },
        { -3,-3,-1,2,4,4,2,-1,-3 },
        { -4,-4,-3,-3,-2,-1,1,2,3,3,4,4,3,3,2,1,-1,-2,-3,-3,-4},
    } ;

    static String[] message = { "direct", "offscreen", "by hand" } ;

    public void addNotify() {
        super.addNotify() ;

        // create an offscreen image to draw into
        Rectangle r = bounds() ;
        offscreen = createImage(r.width, r.height) ;
        g0 = offscreen.getGraphics() ;
    }

    public void paint(Graphics g) {
        g.clearRect(0, 0, 100, 100) ;

        // draw crosshairs
        g.setColor(Color.black) ;
        g.drawLine(60, 70, 80, 70) ;
        g.drawLine(70, 60, 70, 80) ;

        boolean byHand = (click%3 == 2) ;

        // fill some circles
        g.setColor(Color.white) ;
        fillCircle(g, 10, 10, 4, byHand) ;
        fillCircle(g, 20, 20, 5, byHand) ;
        fillCircle(g, 35, 35, 6, byHand) ;
        fillCircle(g, 50, 50, 7, byHand) ;
        fillCircle(g, 70, 70, 8, byHand) ;

        // draw some circles
        g.setColor(Color.black) ;
        drawCircle(g, 10, 10, 4, byHand) ;
        drawCircle(g, 20, 20, 5, byHand) ;
        drawCircle(g, 35, 35, 6, byHand) ;
        drawCircle(g, 50, 50, 7, byHand) ;
        drawCircle(g, 70, 70, 8, byHand) ;

        // indicate how we drew the circles
        g.drawString(message[click%3], 5, 90) ;
    }

    public boolean mouseDown(Event ev, int x, int y ) {
        ++click ;

        if ( click%3 == 0 ) {
            // draw directly to canvas
            repaint() ;
        }
        else {
            // draw to offscreen image
            if ( offscreen != null ) {
                paint(g0) ;

                Graphics g = getGraphics() ;
                g.drawImage(offscreen, 0, 0, this) ;
                g.dispose() ;
            }
        }

        return true ;
    }



    void drawCircle(Graphics g, int x, int y, int d, boolean byHand) {
        if ( byHand ) {
            circleByHand(g, x, y, d, true) ;
        }
        else {
            int d2 = d/2 ;

            g.drawOval(x-d2, y-d2, d, d) ;
        }
    }

    void fillCircle(Graphics g, int x, int y, int d, boolean byHand) {
        if ( byHand ) {
            circleByHand(g, x, y, d, false) ;
        }
        else {
            int d2 = d/2 ;

            g.fillOval(x-d2, y-d2, d, d) ;
        }
    }

    // draw or fill a circle using a polygon
    void circleByHand(Graphics g, int x, int y, int d, boolean draw) {
        int xc[] = xcircle[d] ;
        int yc[] = ycircle[d] ;
        int len = xc.length ;
        int px[] = new int[len] ;
        int py[] = new int[len] ;

        for ( int j=0; j<len; ++j ) {
            px[j] = x + xc[j] ;
            py[j] = y + yc[j] ;
        }

        if ( draw ) {
            g.drawPolygon(px, py, len) ;
        }
        else {
            g.fillPolygon(px, py, len) ;
        }
    }

    public static void main(String argv[]) {
        Frame f = new Frame("PolygonBug") ;
        Canvas c = new PolygonBug() ;
        c.resize(100,100) ;

        f.add("Center", c) ;
        f.pack() ;
        f.show() ;
    }
}
(Review ID: 125186) 
======================================================================

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: boT120536 Date: 06/03/2001 By detecting the JDK version it would be possible to add an offset to the polygon fill in JDK 1.4.0. But that's a horrible hack. ======================================================================
11-06-2004

EVALUATION Issues with java.awt.Polygon are generally handled by 2D. eric.hawkes@eng 2001-06-07 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