samskivert / pythagoras

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

Intersecting two areas results in an incorrect amount of IntersectionPoints #23

Open paulis opened 11 years ago

paulis commented 11 years ago

I have two areas that I intersect. In the debugger I see that the CrossingHelper.findCrossing returns an incorrect amount of IntersectionPoints. I took the intersection point coordinates and painted them yellow seen in the attached image.

The coordinate array for the hexagon used in the example is: [300.0, 272.0, 320.0, 306.0, 300.0, 340.0, 260.0, 340.0, 240.0, 306.0, 260.0, 272.0]

The coordinate array for the shape used in the example is: [220.0, 260.0, 260.0, 250.0, 265.0, 245.0, 305.9375, 248.4375, 317.73438, 254.60938, 323.75, 263.75, 323.98438, 275.85938, 318.4375, 290.9375, 290.0, 330.0, 285.0, 400.0, 280.0, 400.0, 220.0, 350.0, 240.0, 350.0, 275.0, 380.0, 275.0, 360.0, 274.0, 350.0, 273.0, 349.0, 260.0, 320.0]

intersectionPoints

paulis commented 11 years ago
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;

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

import pythagoras.f.Area;
import pythagoras.f.Path;
import pythagoras.f.Rectangle;

public class AreaIntersectionBoundsTest {

    private final float[] hexPoints = new float[] {300.0f, 272.0f, 320.0f, 306.0f, 300.0f, 340.0f, 260.0f, 340.0f, 240.0f, 306.0f, 260.0f, 272.0f};
    private final float[] areaPoints = new float[] {220.0f, 260.0f, 260.0f, 250.0f, 265.0f, 245.0f, 305.9375f, 248.4375f, 317.73438f, 254.60938f, 323.75f, 263.75f, 323.98438f, 275.85938f, 318.4375f, 290.9375f, 290.0f, 330.0f, 285.0f, 400.0f, 280.0f, 400.0f, 220.0f, 350.0f, 240.0f, 350.0f, 275.0f, 380.0f, 275.0f, 360.0f, 274.0f, 350.0f, 273.0f, 349.0f, 260.0f, 320.0f};

    @Test
    public void intersectAreasAndInvestigateBounds() {

        Area hex = toArea(hexPoints);
        Rectangle hexBounds = hex.bounds();
        java.awt.geom.Area javaHex = toJavaArea(hexPoints);
        assertBounds(hexBounds, javaHex);
        Rectangle2D.Float javaHexBounds = new Rectangle2D.Float(hexBounds.x, hexBounds.y, hexBounds.width, hexBounds.height);

        Area area = toArea(areaPoints);
        java.awt.geom.Area javaArea = toJavaArea(areaPoints);
        assertBounds(area.bounds(), javaArea);

        // Intersect
        hex.intersect(area);
        javaHex.intersect(javaArea);

        // Intersection bounds
        Rectangle intersectionBounds = hex.bounds();
        Rectangle2D.Float javaIntersectionBounds = new Rectangle2D.Float((float)javaHex.getBounds2D().getX(),
                (float)javaHex.getBounds2D().getY(), 
                (float)javaHex.getBounds2D().getWidth(), 
                (float)javaHex.getBounds2D().getHeight());

        // The top part of the intersection matches the hex bounds top.
        Assert.assertEquals(javaHexBounds.y,javaIntersectionBounds.y, 0f);
        Assert.assertEquals(hexBounds.y,intersectionBounds.y, 0f);

        // Java
        // Bottom part of the hex bounds matches the bottom part of the intersection bounds
        Assert.assertEquals(javaHexBounds.y + javaHexBounds.height, javaIntersectionBounds.y  + javaIntersectionBounds.height, 0f);

        // Pythagoras.f
        // This fails. Bottom part of the intersection bounds overflow.
        float diff = intersectionBounds.y + intersectionBounds.height - hexBounds.y + hexBounds.height;
        Assert.assertEquals("Bound sizes do not match. The difference is " + diff, hexBounds.y + hexBounds.height,intersectionBounds.y + intersectionBounds.height, 0f);
    }

    private final void assertBounds(Rectangle r, java.awt.geom.Area javaArea) {
        Assert.assertEquals(r.x, (float)javaArea.getBounds().getX(), .1f);
        Assert.assertEquals(r.y, (float)javaArea.getBounds().getY(), .1f);
        Assert.assertEquals(r.width, (float)javaArea.getBounds().getWidth(), .1f);
        Assert.assertEquals(r.height, (float)javaArea.getBounds().getHeight(), .1f);
    }

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

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