0

I have 2 arrays of coordinates, basing on which i construct a polygon. Later if I draw this polygon, i get drawing 5x5 pixels (as it should be). BUT when i construct java.awt.geom.Area using the polygon as an argument, resulting area is 4x4 pixels. For some reason height and width of resulting area are 1 pixel smaller

Why does it happen? How to fix this? And I can't just add 1 pixel to some of polygon vertices' coordinates. Once more, what do i need is to create from an existing Polygon an Area object that INCLUDES ALL vertices of the polygon

int[] xpoints={50,54,54,50};
int[] ypoints={50,50,54,54};
int npoints=4;
Polygon p=new Polygon(xpoints,ypoints,npoints);
visible= new Area(p);
blackArea.subtract(visible);

Moreover, if i am not mistaking, if i create and draw a Rectangle2D.Float 5x5 then it will take 6x6 area. I am clearly missing something. Thank you sooo much for any help

Stas
  • 1,203
  • 1
  • 8
  • 7

1 Answers1

1

You mentioned that you draw the polygon. In this case, you have to take into account that you are drawing with the line just between (!) the pixels. And if the line has a width of 1.0 (with the default stroke), this will cause 5x5 pixels to be touched. In contrast to that, when you really fill the polygon, then it should really occupy only 4x4 pixels.

In any case, the result computed by the Area should be in line with the definition of "insideness" in the Shape class.

The following image shows the "pixels" enlarged: The red pixels in the center are the pixels that are contained in a rectangular polygon (position (2,2), size (4,4)). The blue pixels are the pixels that are contained in the Area from which the polygon was subtracted. IF there were any pixels contained in both shapes, then these would be painted in magenta.

The green, semi-transparent "overlay" shows what drawing the polygon actually would produce (if the display was capable to show this): The lines are at the border between the pixels, but with a width of 1.0.

enter image description here

The code:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Point2D;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ContainsTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new ContainsTestPanel());
        f.setSize(500, 500);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

}

class ContainsTestPanel extends JPanel
{
    @Override
    protected void paintComponent(Graphics gr)
    {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D)gr;
        g.setColor(Color.WHITE);
        g.fillRect(0,0,getWidth(), getHeight());

        int[] xpoints={2,6,6,2};
        int[] ypoints={2,2,6,6};
        int npoints=4;
        Polygon p=new Polygon(xpoints,ypoints,npoints);
        Area visible = new Area(p);
        Area blackArea = new Area(new Rectangle(0,0,8,8));
        blackArea.subtract(visible);

        int size = 50;
        for (int x=0; x<8; x++)
        {
            for (int y=0; y<8; y++)
            {
                Point2D point = new Point(x,y);
                boolean inPoly = p.contains(point);
                boolean inArea = blackArea.contains(point);
                System.out.println(x+" "+y+" inPoly: "+inPoly+" inArea "+inArea);

                if (!inPoly && !inArea)
                {
                    g.setColor(Color.GRAY);
                }
                if (inPoly && !inArea)
                {
                    g.setColor(Color.RED);
                }
                if (!inPoly && inArea)
                {
                    g.setColor(Color.BLUE);
                }
                if (inPoly && inArea)
                {
                    g.setColor(Color.MAGENTA);
                }
                int rx = x * size;
                int ry = y * size;
                g.fillRect(rx, ry, size, size);
                g.setColor(Color.BLACK);
                g.drawString(x+","+y, rx, ry);
                g.drawRect(rx, ry, size, size);
            }
        }

        //g.setStroke(new BasicStroke(1.0f/size));
        AffineTransform at = g.getTransform();
        g.scale(size, size);
        g.setColor(new Color(0,255,0,128));
        g.draw(p);
        g.setTransform(at);

    }
}

If you only want to handle pixels in rectangles, there might be a "manual" solution for what you want to achieve.

Marco13
  • 53,703
  • 9
  • 80
  • 159