samskivert / pythagoras

A portable library of geometry classes for Java
Apache License 2.0
44 stars 14 forks source link

Area intersection does not work as expected #21

Open paulis opened 11 years ago

paulis commented 11 years ago

I have a test with two hexagonal shapes and a rectangle intersecting both of those hexagons. I intersect the hexagons separately expecting to have two different intersection areas but I end up with two identical intersection areas.

paulis commented 11 years ago

intersectJavaAreas works but intersectPyhtagorasAreas does not

import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.List;

import org.junit.Assert;
import org.junit.Test;

import pythagoras.f.Area;
import pythagoras.f.Path;
import pythagoras.f.PathIterator;
import pythagoras.f.Point;

/**
 * <pre>
 *  NW _____NE
 *    /hex1 \
 * W /   _   \ E
 *   \  | |  /
 *    \_|_|_/
 *    / | | \
 *   /  |_|  \
 *   \       /
 *    \hex2_/
 *   SW     SE
 * </pre>
 * 
 * 
 */
public class AreaIntersectionTest {
    private final float[] hex1Points = new float[]{240.0f, 238.0f, 260.0f, 272.0f, 240.0f, 306.0f, 200.0f, 306.0f, 180.0f, 272.0f, 200.0f, 238.0f};
    private final float[] hex2Points = new float[]{240.0f, 306.0f, 260.0f, 340.0f, 240.0f, 374.0f, 200.0f, 374.0f, 180.0f, 340.0f, 200.0f, 306.0f};
    private final float[] rectPoints = new float[]{220.0f, 260.0f, 230.0f, 260.0f, 230.0f, 350.0f, 220.0f, 350.0f};

    @Test
    public void intersectJavaAreas() {

        java.awt.geom.Area javaHex1 = toJavaArea(hex1Points);
        java.awt.geom.Area javaHex2 = toJavaArea(hex2Points);
        java.awt.geom.Area javaRect = toJavaArea(rectPoints);

        javaHex1.intersect(javaRect);
        javaHex2.intersect(javaRect);

        // This is as it should be.
        Assert.assertFalse(javaHex1.equals(javaHex2));

        List<Point> corners1 = corners(javaHex1);
        List<Point> corners2 = corners(javaHex2);
        assertRect(corners1, corners2);
    }

    @Test
    public void intersectPyhtagorasAreas() {

        Area hex1 = toArea(hex1Points);
        Area hex2 = toArea(hex2Points);
        Area rectangle = toArea(rectPoints);

        // Intersect both hexes with the rectangle
        hex1.intersect(rectangle);
        hex2.intersect(rectangle);

        // This asserts just fine
        Assert.assertFalse(hex1.equals(hex2));

        List<Point> corners1 = corners(hex1);
        List<Point> corners2 = corners(hex2);
        assertRect(corners1, corners2);

    }

    private void assertRect(List<Point> corners1, List<Point> corners2) {
        Assert.assertEquals(4, corners1.size());
        Assert.assertEquals(4, corners2.size());

        Point p1 = corners1.get(0);
        Point p2 = corners1.get(1);
        Point p3 = corners1.get(2);
        Point p4 = corners1.get(3);

        // All of these should not assert true
        // Assert.assertTrue(p1.equals(corners2.get(0)));
        // Assert.assertTrue(p2.equals(corners2.get(1)));
        // Assert.assertTrue(p3.equals(corners2.get(2)));
        // Assert.assertTrue(p4.equals(corners2.get(3)));

        boolean b1 = corners2.contains(p1);
        boolean b2 = corners2.contains(p2);
        boolean b3 = corners2.contains(p3);
        boolean b4 = corners2.contains(p4);

        // All points in intersection 1 cannot be in the intersection2
        Assert.assertFalse(b1 && b2 && b3 && b4);
    }

    private List<Point> corners(java.awt.geom.Area rect) {
        List<Point> points = new ArrayList<Point>();
        java.awt.geom.PathIterator iter = rect.getPathIterator(null);
        int segment = 0;
        Point p = null;
        do {
            float coords[] = new float[6];
            segment = iter.currentSegment(coords);
            switch (segment) {
                case PathIterator.SEG_CLOSE: 
                    break;
                case PathIterator.SEG_MOVETO: 
                    p = new Point(coords[0], coords[1]);
                    points.add(p);
                    break;
                case PathIterator.SEG_LINETO: 
                    p = new Point(coords[0], coords[1]);
                    points.add(p);
                    break;
                default:break;
            }

            iter.next();
        } while (!iter.isDone());
        return points;
    }

    private List<Point> corners(Area rect) {
        List<Point> points = new ArrayList<Point>();
        PathIterator iter = rect.pathIterator(null);
        int segment = 0;
        Point p = null;
        do {
            float coords[] = new float[6];
            segment = iter.currentSegment(coords);
            switch (segment) {
                case PathIterator.SEG_CLOSE: 
                    break;
                case PathIterator.SEG_MOVETO: 
                    p = new Point(coords[0], coords[1]);
                    points.add(p);
                    break;
                case PathIterator.SEG_LINETO: 
                    p = new Point(coords[0], coords[1]);
                    points.add(p);
                    break;
                default:break;
            }

            iter.next();
        } while (!iter.isDone());
        return points;
    }

    private Area toArea(float[] coords) {
        Path path = new Path();
        path.moveTo(coords[0], coords[1]); // NE
        for (int i = 2; i < coords.length; i++) {
            path.lineTo(coords[i], coords[++i]);
        }
        path.closePath();
        Area area = new Area(path);
        return area;

    }
    private java.awt.geom.Area toJavaArea(float[] coords) {
        Path2D javaPath = new Path2D.Float();
        javaPath.moveTo(coords[0], coords[1]); // NE
        for (int i = 2; i < coords.length; i++) {
            javaPath.lineTo(coords[i], coords[++i]);
        }
        javaPath.closePath();
        java.awt.geom.Area javaArea = new java.awt.geom.Area(javaPath);
        return javaArea;
    }

}