Search code examples
javaswinggraphicsgraphics2dcustom-painting

Graphics2D line and shape drawing issues (rendered in wrong place)


I've drawn three arrows using Graphics2D.

  1. three drawLines
  2. draw(Shape)
  3. fill(Shape)

Here's what it looks like enlarged:

drawn arrows

I cannot understand two things:

  1. Why is the filled one smaller and shifted?
  2. Secondly, why do arrows 1. and 3. look different? Both consist of 3 antialiased lines. Shouldn't they (potentially) differ only in vertices?

Here's the whole code:

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

public class ShapeTest extends JPanel
{
    public static void main(String [] args)
    {
        JFrame frame = new JFrame();
        frame.setSize(new Dimension(220, 200));
        frame.add(new ShapeTest());
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    @Override
    protected void paintComponent(Graphics graphics)
    {
        super.paintComponent(graphics);

        Graphics2D graphics2D = (Graphics2D)graphics;

        graphics.setColor(Color.white);
        graphics.fillRect(0, 0, this.getWidth(), this.getHeight());

        graphics2D.setColor(Color.black);
        graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graphics2D.drawLine(100, 40, 103, 46);
        graphics2D.drawLine(103, 46, 106, 40);
        graphics2D.drawLine(100, 40, 106, 40);

        graphics2D.fill(new Polygon(
                new int[]{100, 103, 106},
                new int[]{50, 56, 50},
                3
        ));

        graphics2D.draw(new Polygon(
                new int[]{100, 103, 106},
                new int[]{60, 66, 60},
                3
        ));
    }
}

Solution

  • It seems I have found the answers to my question. I post them for other poeple who may face the same problem.

    Smaller, because, as MadProgrammer said in a comment below the question, stokes are drawn along the edges through the middle, so a 1px stroke edges will be 0.5px to the each side of the shape edges.

    Shifted because of rounding. When you draw a line with a float-precision coordinates it can be normalized in some way on some platforms. On Windows, at least for Path2D.Float and Line2D.Float, it rounds coords to integer numbers. I guess that the same goes for fill(Shape). Fotrunatelly, you can disable stroke normalization by:

    g2D.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
    

    It solves the problem:

    arrows

    Different, because of different rendering algorithms.