I am attempting to get the intersection of two polygons via Area.intersect(), but in some cases I am getting a strange result.
My code:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setResizable(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
JPanel panel = new Panel();
frame.add(panel);
}
static class Panel extends JPanel
{
Panel()
{
setBackground(new Color(0, 50, 0));
setFocusable(true);
}
@Override
public void paintComponent(Graphics g1)
{
super.paintComponent(g1);
Graphics2D g = (Graphics2D) g1;
AffineTransform at = new AffineTransform();
at.scale(3,3);
g.transform(at);
g.setColor(Color.blue);
Path2D.Double path1 = new Path2D.Double();
path1.append(new Line2D.Double(76, 62, 31, 62 ),true);
path1.append(new Line2D.Double(31, 62, 31, 70.00000000000001 ),true);
path1.append(new Line2D.Double(31, 70.00000000000001, 76, 70 ),true);
Area area1 = new Area(path1);
Path2D.Double path2 = new Path2D.Double();
path2.append(new Line2D.Double(52, 10,52,130),true);
path2.append(new Line2D.Double(52, 130,60,130),true);
path2.append(new Line2D.Double(60, 130,60.0,10),true);
Area area2 = new Area(path2);
g.fill(area1);
g.setColor(Color.red);
g.fill(area2);
Area areaIntersect = new Area(path1);
areaIntersect.intersect(area2);
g.setColor(Color.yellow);
g.draw(areaIntersect);
PathIterator pi = areaIntersect.getPathIterator(null);
while(!pi.isDone())
{
double[] coords = new double[6];
switch(pi.currentSegment(coords))
{
case PathIterator.SEG_CLOSE:
break;
case PathIterator.SEG_CUBICTO:
System.out.println(coords[4] + "," + coords[5]);
case PathIterator.SEG_QUADTO:
System.out.println(coords[2] + "," + coords[3]);
case PathIterator.SEG_MOVETO:
case PathIterator.SEG_LINETO:
System.out.println(coords[0] + "," + coords[1]);
}
pi.next();
}
}
}
}
and the result:
The intersection should just be a yellow square; the long yellow horizontal line should not be part of the result.
I know that the problem relates to the very tiny angle of the bottom of the blue box:
Line2D.Double(31,70.00000000000001,76,70). If I change 70.00000000000001 to nearly any other value, the intersection box displays correctly. For example, changing both of them to 70.000000000001:
path1.append(new Line2D.Double(31, 62, 31, 70.000000000001 ),true);
path1.append(new Line2D.Double(31, 70.000000000001, 76, 70 ),true);
I printed the coordinates of the generated intersect, to make sure what I was seeing was not a display problem, but it clearly shows the line from 31.0 to 76.0 on the x axis, whereas it should only be 52.0 to 60.0.
52.0,60.0
52.0,70.00000000000001
31.0,70.00000000000001
76.0,70.0
60.0,70.0
60.0,60.0
I am doing some trigonometry to generate the polygons, so values like .00000000000001 are expected. I could round them off, but without knowing what's causing the problem, I'm worried that it might occur with other values.
Update using MadProgrammer's answer but changing path1 to:
Path2D.Double path1 = new Path2D.Double();
path1.append(new Line2D.Double(31, 62, 76, 62), true);
path1.append(new Line2D.Double(76, 62, 76, 70.0000000000001), true);
path1.append(new Line2D.Double(76, 70.0000000000001, 31, 70), true);
path1.append(new Line2D.Double(31, 70, 31, 62), true);
path1.closePath();
..produces a slightly less-wrong result:



First, I removed the scaling, that didn't help.
Next I added
closePathto both the paths, that didn't help.Next, I add an additional line to each path to ensure that the paths were closed correctly, that didn't help.
Next I used
Rectangle2Dinstead ofPathand solved the issue. So the problem lies with thePaths.Next, I changed the intersection to use the pre-existing
Areas instead of the firstPathand the secondArea.this didn't help.
Now I'm scratching my head. I went back and compared the
Pathwith theRectangle2Dand noted that path one "seems" to have a counter clock wise winding, so I changed it to have a clock wise winding instead...and that worked!
There also could be an issue with the difference between
70and70.00000000000001although in my updated test, it doesn't seem to make a difference.Why would the winding matter? In this case, I can't say, but it just seems to make a difference.