package nodebox.graphics; import org.junit.Test; import java.util.List; import static junit.framework.TestCase.*; import static nodebox.graphics.GraphicsTestUtils.addRect; import static nodebox.graphics.GraphicsTestUtils.assertPointEquals; public class ContourTest { public static final double SIDE = GraphicsTestUtils.SIDE; @Test public void testPointAt() { Contour c1 = new Contour(); c1.addPoint(0, 0); c1.addPoint(100, 0); assertPointEquals(0, 0, c1.pointAt(0)); assertPointEquals(50, 0, c1.pointAt(0.5)); assertPointEquals(100, 0, c1.pointAt(1)); assertPointEquals(-50, 0, c1.pointAt(-0.5)); assertPointEquals(150, 0, c1.pointAt(1.5)); Contour c2 = new Contour(); c2.addPoint(new Point(0, 0, Point.LINE_TO)); c2.addPoint(new Point(0, 0, Point.CURVE_DATA)); c2.addPoint(new Point(100, 0, Point.CURVE_DATA)); c2.addPoint(new Point(100, 0, Point.CURVE_TO)); assertPointEquals(0, 0, c2.pointAt(0)); assertPointEquals(50, 0, c2.pointAt(0.5)); assertPointEquals(100, 0, c2.pointAt(1)); //assertEquals(new Point(-50, 0), c2.pointAt(-0.5)); //assertEquals(new Point(150, 0), c2.pointAt(1.5)); } @Test public void testPointAtEmptyPath() { Contour c = new Contour(); try { c.pointAt(0.1); fail("Should have thrown an error."); } catch (NodeBoxError e) { } c.addPoint(33, 44); assertPointEquals(33, 44, c.pointAt(0.1)); assertPointEquals(33, 44, c.pointAt(100)); assertPointEquals(33, 44, c.pointAt(-12)); } @Test public void testPointAtClosed() { Contour c = new Contour(); c.addPoint(0, 0); c.addPoint(SIDE, 0); c.addPoint(SIDE, SIDE); c.addPoint(0, SIDE); assertEquals(SIDE * 3, c.getLength()); assertPointEquals(0, 0, c.pointAt(0)); assertPointEquals(SIDE, SIDE / 2, c.pointAt(0.5)); assertPointEquals(0, SIDE, c.pointAt(1)); c.close(); assertEquals(SIDE * 4, c.getLength()); assertPointEquals(0, 0, c.pointAt(0)); assertPointEquals(SIDE, SIDE, c.pointAt(0.5)); assertPointEquals(0, 0, c.pointAt(1)); } @Test public void testPointAtMultiple() { Contour c1 = new Contour(); c1.addPoint(0, 0); c1.addPoint(50, 0); c1.addPoint(100, 0); assertPointEquals(-50, 0, c1.pointAt(-0.5)); assertPointEquals(0, 0, c1.pointAt(0)); assertPointEquals(25, 0, c1.pointAt(0.25)); assertPointEquals(50, 0, c1.pointAt(0.5)); assertPointEquals(60, 0, c1.pointAt(0.6)); assertPointEquals(100, 0, c1.pointAt(1)); assertPointEquals(150, 0, c1.pointAt(1.5)); } @Test public void testLength() { assertLength(0, 0); assertLength(100, 200); } private void assertLength(double x, double y) { Contour c = new Contour(); c.addPoint(x, y); c.addPoint(x + SIDE, y); c.addPoint(x + SIDE, y + SIDE); c.addPoint(x, y + SIDE); assertEquals(SIDE * 3, c.getLength()); c.close(); assertEquals(SIDE * 4, c.getLength()); } @Test public void testMakePoints() { Point[] points; // A contour that is "open", which means it doesn't describe the last point. Contour c = new Contour(); c.addPoint(0, 0); c.addPoint(SIDE, 0); c.addPoint(SIDE, SIDE); c.addPoint(0, SIDE); assertEquals(SIDE * 3, c.getLength()); points = c.makePoints(7); assertPointEquals(0, 0, points[0]); assertPointEquals(SIDE / 2, 0, points[1]); assertPointEquals(SIDE, 0, points[2]); assertPointEquals(0, SIDE, points[6]); // Closing the contour will encrease the length of the path and thus will also // have an effect on point positions. c.close(); assertEquals(SIDE * 4, c.getLength()); points = c.makePoints(8); assertEquals(new Point(0, 0), points[0]); assertPointEquals(SIDE / 2, 0, points[1]); assertPointEquals(SIDE, 0, points[2]); assertPointEquals(0, SIDE, points[6]); assertPointEquals(0, SIDE / 2, points[7]); // // // A contour that is "closed", which means that the last and first point are equal. // Contour closedContour = new Contour(); // closedContour.addPoint(0, 0); // closedContour.addPoint(50, 0); // closedContour.addPoint(50, 50); // closedContour.addPoint(0, 0); // assertEquals(150.0, closedContour.getLength()); // points = closedContour.makePoints(6); // // The first and last points overlap. // assertEquals(new Point(0, 0), points[0]); // assertEquals(new Point(25, 0), points[1]); // assertEquals(new Point(50, 0), points[2]); // assertEquals(new Point(50, 25), points[3]); // assertEquals(new Point(50, 50), points[4]); // assertEquals(new Point(25, 25), points[5]); // // Because the first and last points overlap, closing the contour has no effect. // // The length does not increase. // closedContour.close(); // assertEquals(150.0, closedContour.getLength()); // // Point positions remain unchanged. // points = closedContour.makePoints(6); // assertEquals(new Point(0, 0), points[0]); // assertEquals(new Point(25, 0), points[1]); // assertEquals(new Point(50, 0), points[2]); // assertEquals(new Point(50, 25), points[3]); // assertEquals(new Point(50, 50), points[4]); // assertEquals(new Point(25, 25), points[5]); } @Test public void testMakePointsEmptyPath() { Contour c = new Contour(); Point[] points = c.makePoints(10); assertEquals(0, points.length); } @Test public void testResample() { Contour r; List<Point> points; Contour c1 = new Contour(); r = c1.resampleByAmount(10); assertEquals(0, r.getPointCount()); assertFalse(r.isClosed()); Contour c2 = new Contour(); addRect(c2, 0, 0, SIDE, SIDE); r = c2.resampleByAmount(4); assertEquals(4, r.getPointCount()); assertFalse(r.isClosed()); points = r.getPoints(); assertPointEquals(0, 0, points.get(0)); assertPointEquals(SIDE, 0, points.get(1)); assertPointEquals(SIDE, SIDE, points.get(2)); assertPointEquals(0, SIDE, points.get(3)); c2.close(); r = c2.resampleByAmount(4); assertEquals(4, r.getPointCount()); assertTrue(r.isClosed()); points = r.getPoints(); assertPointEquals(0, 0, points.get(0)); assertPointEquals(0, SIDE, points.get(3)); } @Test public void testResampleByLength() { Contour r; Contour c1 = new Contour(); r = c1.resampleByLength(1); assertEquals(0, r.getPointCount()); assertFalse(r.isClosed()); Contour c2 = new Contour(); addRect(c2, 0, 0, SIDE, SIDE); r = c2.resampleByLength(SIDE); assertFalse(r.isClosed()); assertRectPoints(r, 0, 0, SIDE, SIDE); c2.close(); r = c2.resampleByLength(SIDE); assertTrue(r.isClosed()); assertRectPoints(r, 0, 0, SIDE, SIDE); } /** * Contour uses a length cache to speed up pointAt, makePoints and resample operations. * Check if the cache is properly invalidated. */ @Test public void testCacheInvalidation() { Contour c = new Contour(); c.addPoint(0, 0); c.addPoint(50, 0); assertEquals(50.0, c.getLength()); // Add a point c.addPoint(100, 0); // Check the length again. assertEquals(100.0, c.getLength()); } /** * Check the bounds for an empty contour. */ @Test public void testEmptyBounds() { Contour c = new Contour(); Rect r = c.getBounds(); assertEquals(new Rect(), r); } private void assertRectPoints(IGeometry g, double x, double y, double width, double height) { assertEquals(4, g.getPointCount()); List<Point> points = g.getPoints(); assertPointEquals(x, y, points.get(0)); assertPointEquals(x + width, y, points.get(1)); assertPointEquals(x + width, y + height, points.get(2)); assertPointEquals(x, y + height, points.get(3)); } }