/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2014 - 2015, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.geometry.jts; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Arrays; import org.junit.Test; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.CoordinateSequence; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.geom.impl.CoordinateArraySequence; public class CurvedGeometryTest { private static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory(); @Test public void testCircularStringEmpty() { CircularString cs = new CircularString(new double[0], GEOMETRY_FACTORY, Double.MAX_VALUE); assertTrue(cs.isEmpty()); assertEquals("CIRCULARSTRING EMPTY", cs.toCurvedText()); assertEquals(0, cs.getNumArcs()); assertEquals(0, cs.getNumPoints()); } @Test public void testCircularStringSingleCurve() { double[] controlPoints = new Circle(10).samplePoints(Math.PI / 2, Math.PI / 4, 0); CircularString cs = new CircularString(controlPoints, GEOMETRY_FACTORY, Double.MAX_VALUE); // check envelope Envelope env = cs.getEnvelopeInternal(); assertEnvelopeEquals(new Envelope(0, 10, 0, 10), env); // check linearization assertEquals(CircularArc.BASE_SEGMENTS_QUADRANT + 1, cs.getNumPoints()); // check cloning CircularString cloned = (CircularString) cs.clone(); assertEquals(cs, cloned); // check perimeter, not enough control points to have a accurate estimate assertEquals(10 * Math.PI / 2, cs.getLength(), 1e-1); // use a tighter tolerance assertEquals(10 * Math.PI / 2, cs.linearize(1e-6).getLength(), 1e-6); // topological operation check assertTrue(cs.intersects(JTS.toGeometry(new Envelope(4, 8, 4, 8)))); // verify a close-by, mis-aligned (angle wise) arc with the minimum segmentation // (cannot do 9.999 or the control points will cause the intersection) double[] controlPoints2 = new Circle(9.9).samplePoints(Math.PI * 3 / 5, Math.PI / 4, Math.PI / 10); CircularString cs2 = new CircularString(controlPoints2, GEOMETRY_FACTORY, Double.MAX_VALUE); // they should not intersect assertFalse(cs.intersects(cs2)); // check curved WKT generation String wkt = cs.toCurvedText(); assertEquals( "CIRCULARSTRING (6.123233995736766E-16 10.0, 7.0710678118654755 7.071067811865475, 10.0 0.0)", wkt); // check reversing CircularString reversed = (CircularString) cs.reverse(); assertEquals(reversed.controlPoints[0], cs.controlPoints[4], 0d); assertEquals(reversed.controlPoints[1], cs.controlPoints[5], 0d); assertEquals(reversed.controlPoints[2], cs.controlPoints[2], 0d); assertEquals(reversed.controlPoints[3], cs.controlPoints[3], 0d); assertEquals(reversed.controlPoints[4], cs.controlPoints[0], 0d); assertEquals(reversed.controlPoints[5], cs.controlPoints[1], 0d); } @Test public void testCircularStringWings() { double[] sp1 = new Circle(10).samplePoints(Math.PI / 2, Math.PI / 4, 0); double[] sp2 = new Circle(10, 20, 0).samplePoints(Math.PI, Math.PI * 3 / 4, Math.PI / 2); GrowableOrdinateArray data = new GrowableOrdinateArray(); data.addAll(sp1); data.add(sp2[2], sp2[3]); data.add(sp2[4], sp2[5]); CircularString cs = new CircularString(data.getData(), GEOMETRY_FACTORY, Double.MAX_VALUE); // System.out.println(cs.toText()); Envelope env = cs.getEnvelopeInternal(); assertEnvelopeEquals(new Envelope(0, 20, 0, 10), env); // check linearization assertEquals(CircularArc.BASE_SEGMENTS_QUADRANT * 2 + 1, cs.getNumPoints()); // check cloning CircularString cloned = (CircularString) cs.clone(); assertEquals(cs, cloned); // check perimeter, not enough control points to have a accurate estimate assertEquals(10 * Math.PI, cs.getLength(), 1e-1); // use a tighter tolerance assertEquals(10 * Math.PI, cs.linearize(1e-6).getLength(), 1e-6); // topological operation check assertTrue(cs.intersects(JTS.toGeometry(new Envelope(4, 8, 4, 8)))); // verify a close-by, mis-aligned (angle wise) arc with the minimum segmentation // (cannot do 9.999 or the control points will cause the intersection) double[] controlPoints2 = new Circle(9.9).samplePoints(Math.PI * 3 / 5, Math.PI / 4, Math.PI / 10); CircularString cs2 = new CircularString(controlPoints2, GEOMETRY_FACTORY, Double.MAX_VALUE); // they should not intersect assertFalse(cs.intersects(cs2)); // check curved WKT generation String wkt = cs.toCurvedText(); assertEquals( "CIRCULARSTRING (6.123233995736766E-16 10.0, 7.0710678118654755 7.071067811865475, 10.0 0.0, 12.928932188134524 7.0710678118654755, 20.0 10.0)", wkt); // check reversing CircularString reversed = (CircularString) cs.reverse(); double[] controlPoints = cs.controlPoints; double[] controlPointsReverse = reversed.controlPoints; assertEquals(controlPointsReverse[0], controlPoints[8], 0d); assertEquals(controlPointsReverse[1], controlPoints[9], 0d); assertEquals(controlPointsReverse[2], controlPoints[6], 0d); assertEquals(controlPointsReverse[3], controlPoints[7], 0d); assertEquals(controlPointsReverse[4], controlPoints[4], 0d); assertEquals(controlPointsReverse[5], controlPoints[5], 0d); assertEquals(controlPointsReverse[6], controlPoints[2], 0d); assertEquals(controlPointsReverse[7], controlPoints[3], 0d); assertEquals(controlPointsReverse[8], controlPoints[0], 0d); assertEquals(controlPointsReverse[9], controlPoints[1], 0d); } @Test public void testSimpleCircle() { Circle circle = new Circle(10); double[] circleControlPoints = circle.samplePoints(0, Math.PI / 2, Math.PI, Math.PI * 3 / 2, 0); CircularRing cr = new CircularRing(circleControlPoints, GEOMETRY_FACTORY, Double.MAX_VALUE); Envelope env = cr.getEnvelopeInternal(); assertEnvelopeEquals(new Envelope(-10, 10, -10, 10), env); // check linearization assertEquals(CircularArc.BASE_SEGMENTS_QUADRANT * 4 + 1, cr.getNumPoints()); CoordinateSequence coordinates = cr.linearize() .getCoordinateSequence(); circle.assertTolerance(coordinates, 0.1); // check cloning CircularRing cloned = (CircularRing) cr.clone(); assertEquals(cr, cloned); // check perimeter, not enough control points to have a accurate estimate assertEquals(10 * Math.PI * 2, cr.getLength(), 1e-1); // topological operation check assertTrue(cr.intersects(JTS.toGeometry(new Envelope(4, 8, 4, 8)))); // verify a close-by, mis-aligned (angle wise) arc with the minimum segmentation // (cannot do 9.999 or the control points will cause the intersection) double[] controlPoints2 = new Circle(9.9).samplePoints(Math.PI * 3 / 5, Math.PI / 4, Math.PI / 10); CircularString cs2 = new CircularString(controlPoints2, GEOMETRY_FACTORY, Double.MAX_VALUE); // they should not intersect assertFalse(cr.intersects(cs2)); // check curved WKT generation String wkt = cr.toCurvedText(); assertEquals( "CIRCULARSTRING (10.0 0.0, 6.123233995736766E-16 10.0, -10.0 1.2246467991473533E-15, -1.8369701987210296E-15 -10.0, 10.0 0.0)", wkt); // check reversing CircularRing reversed = (CircularRing) cr.reverse(); // System.out.println(cr.toCurvedText()); // System.out.println(reversed.toCurvedText()); double[] controlPoints = cr.delegate.controlPoints; double[] controlPointsReverse = reversed.delegate.controlPoints; assertEquals(controlPointsReverse[0], controlPoints[8], 0d); assertEquals(controlPointsReverse[1], controlPoints[9], 0d); assertEquals(controlPointsReverse[2], controlPoints[6], 0d); assertEquals(controlPointsReverse[3], controlPoints[7], 0d); assertEquals(controlPointsReverse[4], controlPoints[4], 0d); assertEquals(controlPointsReverse[5], controlPoints[5], 0d); assertEquals(controlPointsReverse[6], controlPoints[2], 0d); assertEquals(controlPointsReverse[7], controlPoints[3], 0d); assertEquals(controlPointsReverse[8], controlPoints[0], 0d); assertEquals(controlPointsReverse[9], controlPoints[1], 0d); } @Test public void testCompoundCurve() { double[] halfCircle = new double[] { 10, 10, 0, 20, -10, 10 }; CircularString cs = new CircularString(halfCircle, GEOMETRY_FACTORY, Double.MAX_VALUE); LineString ls = new LineString(new CoordinateArraySequence(new Coordinate[] { new Coordinate(-10, 10), new Coordinate(-10, 0), new Coordinate(10, 0), new Coordinate(10, 10) }), GEOMETRY_FACTORY); CompoundCurve curve = new CompoundCurve(Arrays.asList(cs, ls), GEOMETRY_FACTORY, Double.MAX_VALUE); assertFalse("Check that this should not be a rectangle.", curve.isRectangle()); // envelope check Envelope env = curve.getEnvelopeInternal(); assertEnvelopeEquals(new Envelope(-10, 10, 0, 20), env); // check linearization assertEquals(CircularArc.BASE_SEGMENTS_QUADRANT * 2 + 4, curve.getNumPoints()); // check cloning CompoundCurve cloned = (CompoundCurve) curve.clone(); assertEquals(curve, cloned); // check perimeter, not enough control points to have a accurate estimate assertEquals(10 * Math.PI + 40, curve.getLength(), 1e-1); // topological operation check assertTrue(curve.intersects(JTS.toGeometry(new Envelope(0, 10, 12, 15)))); assertTrue(curve.intersects(JTS.toGeometry(new Envelope(8, 12, -2, 2)))); // check curved WKT generation String wkt = curve.toCurvedText(); assertEquals( "COMPOUNDCURVE (CIRCULARSTRING (10.0 10.0, 0.0 20.0, -10.0 10.0), (-10.0 10.0, -10.0 0.0, 10.0 0.0, 10.0 10.0))", wkt); } @Test public void testCompoundRing() { double[] halfCircle = new double[] { 10, 10, 0, 20, -10, 10 }; CircularString cs = new CircularString(halfCircle, GEOMETRY_FACTORY, Double.MAX_VALUE); LineString ls = new LineString(new CoordinateArraySequence(new Coordinate[] { new Coordinate(-10, 10), new Coordinate(-10, 0), new Coordinate(10, 0), new Coordinate(10, 10) }), GEOMETRY_FACTORY); CompoundRing ring = new CompoundRing(Arrays.asList(cs, ls), GEOMETRY_FACTORY, Double.MAX_VALUE); // envelope check Envelope env = ring.getEnvelopeInternal(); assertEnvelopeEquals(new Envelope(-10, 10, 0, 20), env); // check linearization assertEquals(CircularArc.BASE_SEGMENTS_QUADRANT * 2 + 4, ring.getNumPoints()); // check cloning CompoundRing cloned = (CompoundRing) ring.clone(); assertEquals(ring, cloned); // check perimeter, not enough control points to have a accurate estimate assertEquals(10 * Math.PI + 40, ring.getLength(), 1e-1); // topological operation check assertTrue(ring.intersects(JTS.toGeometry(new Envelope(0, 10, 12, 15)))); assertTrue(ring.intersects(JTS.toGeometry(new Envelope(8, 12, -2, 2)))); // check curved WKT generation String wkt = ring.toCurvedText(); assertEquals( "COMPOUNDCURVE (CIRCULARSTRING (10.0 10.0, 0.0 20.0, -10.0 10.0), (-10.0 10.0, -10.0 0.0, 10.0 0.0, 10.0 10.0))", wkt); } @Test public void testCurvePolygons() { CurvePolygon curved = buildCurvePolygon(); // envelope check Envelope env = curved.getEnvelopeInternal(); assertEnvelopeEquals(new Envelope(-10, 10, -10, 10), env); // check linearization assertEquals(CircularArc.BASE_SEGMENTS_QUADRANT * 4 + 1 + 5, curved.getNumPoints()); // check cloning CurvePolygon cloned = (CurvePolygon) curved.clone(); assertEquals(curved, cloned); // check perimeter, not enough control points to have a accurate estimate assertEquals(2 * 10 * Math.PI + 8, curved.getLength(), 1e-1); // topological operation check assertTrue(curved.intersects(JTS.toGeometry(new Envelope(0, 10, 5, 15)))); assertTrue(curved.intersects(JTS.toGeometry(new Envelope(8, 12, -2, 2)))); // check curved WKT generation String wkt = curved.toCurvedText(); assertEquals( "CURVEPOLYGON (CIRCULARSTRING (-10.0 0.0, 0.0 10.0, 10.0 0.0, 0.0 -10.0, -10.0 0.0), (-1.0 -1.0, -1.0 1.0, 1.0 1.0, 1.0 -1.0, -1.0 -1.0))", wkt); } @Test public void testMultiSurface() { CurvePolygon p1 = buildCurvePolygon(); LinearRing shell = new LinearRing(new CoordinateArraySequence(new Coordinate[] { new Coordinate(20, 20), new Coordinate(24, 20), new Coordinate(24, 24), new Coordinate(20, 24), new Coordinate(20, 20) }), GEOMETRY_FACTORY); LinearRing hole = new LinearRing(new CoordinateArraySequence(new Coordinate[] { new Coordinate(22, 22), new Coordinate(23, 22), new Coordinate(23, 23), new Coordinate(23, 22), new Coordinate(22, 22) }), GEOMETRY_FACTORY); Polygon p2 = new Polygon(shell, new LinearRing[] { hole }, GEOMETRY_FACTORY); MultiSurface ms = new MultiSurface(new Polygon[] {p1, p2}, GEOMETRY_FACTORY, Double.MAX_VALUE); // envelope check Envelope env = ms.getEnvelopeInternal(); assertEnvelopeEquals(new Envelope(-10, 24, -10, 24), env); // check linearization assertEquals((CircularArc.BASE_SEGMENTS_QUADRANT * 4 + 1 + 5) + (5 + 5), ms.getNumPoints()); // check cloning MultiSurface cloned = (MultiSurface) ms.clone(); assertEquals(ms, cloned); // check perimeter, not enough control points to have a accurate estimate assertEquals((2 * 10 * Math.PI + 8) + (16 + 4), ms.getLength(), 1e-1); // topological operation check assertTrue(ms.intersects(JTS.toGeometry(new Envelope(0, 10, 5, 15)))); assertTrue(ms.intersects(JTS.toGeometry(new Envelope(8, 12, -2, 2)))); // check curved WKT generation String wkt = ms.toCurvedText(); assertEquals( "MULTISURFACE (CURVEPOLYGON (CIRCULARSTRING (-10.0 0.0, 0.0 10.0, 10.0 0.0, 0.0 -10.0, -10.0 0.0), " + "(-1.0 -1.0, -1.0 1.0, 1.0 1.0, 1.0 -1.0, -1.0 -1.0)), ((20.0 20.0, 24.0 20.0, 24.0 24.0, 20.0 24.0, 20.0 20.0), " + "(22.0 22.0, 23.0 22.0, 23.0 23.0, 23.0 22.0, 22.0 22.0)))", wkt); } @Test public void testNormalize() { double[] circleControlPoints = new double[] { 0, 0, 0, 10, 0, 0 }; CircularRing circle = new CircularRing(circleControlPoints, GEOMETRY_FACTORY, 1e-6); CircularRing normalized = circle.normalizeRing(); assertEquals(2, normalized.getNumArcs()); CircularArc a1 = normalized.getArcN(0); assertArrayEquals(new double[] { 0, 0, 5, 5, 0, 10 }, a1.getControlPoints(), 1e-6); CircularArc a2 = normalized.getArcN(1); assertArrayEquals(new double[] { 0, 10, -5, 5, 0, 0 }, a2.getControlPoints(), 1e-6); } private CurvePolygon buildCurvePolygon() { double[] circleControlPoints = new double[] { -10, 0, 0, 10, 10, 0, 0, -10, -10, 0 }; CircularRing shell = new CircularRing(circleControlPoints, GEOMETRY_FACTORY, Double.MAX_VALUE); LinearRing hole = new LinearRing(new CoordinateArraySequence(new Coordinate[] { new Coordinate(-1, -1), new Coordinate(-1, 1), new Coordinate(1, 1), new Coordinate(1, -1), new Coordinate(-1, -1) }), GEOMETRY_FACTORY); CurvePolygon curved = new CurvePolygon(shell, new LinearRing[] { hole }, GEOMETRY_FACTORY, Double.MAX_VALUE); return curved; } private void assertEnvelopeEquals(Envelope envelope, Envelope env) { assertEquals(envelope.getMinX(), env.getMinX(), Circle.EPS); assertEquals(envelope.getMinY(), env.getMinY(), Circle.EPS); assertEquals(envelope.getMinX(), env.getMinX(), Circle.EPS); assertEquals(envelope.getMaxY(), env.getMaxY(), Circle.EPS); } }