package org.geotools.geometry.jts;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import org.geotools.test.TestData;
import org.junit.Before;
import org.junit.Test;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.io.WKTReader;
/**
*
*
* @source $URL$
*/
public class GeometryClipperTest {
static final double EPS = 1e-3;
static final double EPS_CORNERS = 1e-1;
GeometryClipper clipper;
Geometry boundsPoly;
WKTReader wkt;
@Before
public void setUp() throws Exception {
// System.setProperty("org.geotools.test.interactive", "true");
clipper = new GeometryClipper(new Envelope(0, 10, 0, 10));
wkt = new WKTReader();
boundsPoly = wkt.read("POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))");
}
@Test
public void testFullyInside() throws Exception {
LineString ls = (LineString) wkt.read("LINESTRING(1 1, 2 5, 9 1)");
LineString clipped = (LineString) clipper.clip(ls, false);
assertTrue(ls.equalsExact(clipped));
showResult("Fully inside", ls, clipped);
}
@Test
public void testInsideBorders() throws Exception {
LineString ls = (LineString) wkt.read("LINESTRING(0 0, 2 5, 10 0)");
LineString clipped = (LineString) clipper.clip(ls, false);
assertTrue(ls.equalsExact(clipped));
showResult("Inside touching borders", ls, clipped);
}
@Test
public void testFullyOutside() throws Exception {
LineString ls = (LineString) wkt.read("LINESTRING(-5 0, -5 15, 15 15)");
LineString clipped = (LineString) clipper.clip(ls, false);
assertNull(clipped);
showResult("Inside touching borders", ls, clipped);
}
@Test
public void testCross() throws Exception {
LineString ls = (LineString) wkt.read("LINESTRING(-5 -5, 15 15)");
LineString clipped = (LineString) clipper.clip(ls, false);
assertTrue(clipped.equalsExact(wkt.read("LINESTRING(0 0, 10 10)")));
showResult("Cross", ls, clipped);
}
@Test
public void testTouchLine() throws Exception {
LineString ls = (LineString) wkt.read("LINESTRING(0 0, 0 10)");
LineString clipped = (LineString) clipper.clip(ls, false);
assertTrue(clipped.equalsExact(ls));
showResult("Touch border", ls, clipped);
}
@Test
public void testTouchPoint() throws Exception {
LineString ls = (LineString) wkt.read("LINESTRING(-5 5, 0 5)");
Geometry clipped = clipper.clip(ls, false);
assertNull(clipped);
showResult("Touch point", ls, clipped);
}
@Test
public void testMultiTouch() throws Exception {
LineString ls = (LineString) wkt.read("LINESTRING(-5 0, 0 1, -5 2, 0 3, -5 4, 0 5)");
Geometry clipped = clipper.clip(ls, false);
assertNull(clipped);
showResult("Multitouch", ls, clipped);
}
@Test
public void testTouchAndCross() throws Exception {
LineString ls = (LineString) wkt.read("LINESTRING(-5 0, 0 1, -5 2, 5 2, 5 3, -5 3, 0 4)");
Geometry clipped = clipper.clip(ls, false);
assertTrue(clipped.equalsExact(wkt.read("LINESTRING(0 2, 5 2, 5 3, 0 3)")));
showResult("Touch and cross", ls, clipped);
}
@Test
public void testTouchAndParallel() throws Exception {
LineString ls = (LineString) wkt.read("LINESTRING(-5 0, 0 1, -5 2, 0 2, 0 3, -5 3, 0 4)");
Geometry clipped = clipper.clip(ls, false);
assertTrue(clipped.equalsExact(wkt.read("LINESTRING(0 2, 0 3)")));
showResult("Touch and parallel", ls, clipped);
}
@Test
public void testInsideOut() throws Exception {
LineString ls = (LineString) wkt.read("LINESTRING(-2 8, 12 8, 12 2, -2 2)");
MultiLineString clipped = (MultiLineString) clipper.clip(ls, false);
assertTrue(clipped.equalsExact(wkt.read("MULTILINESTRING((0 8, 10 8), (10 2, 0 2))")));
showResult("Touch border", ls, clipped);
}
@Test
public void testFullyOutsideCircle() throws Exception {
Point p = (Point) wkt.read("POINT(5 5)");
LineString ls = ((Polygon) p.buffer(10)).getExteriorRing();
Geometry clipped = clipper.clip(ls, false);
assertNull(clipped);
showResult("Circle around", ls, clipped);
}
@Test
public void testCrossingCircle() throws Exception {
Point p = (Point) wkt.read("POINT(5 5)");
LineString ls = ((Polygon) p.buffer(6)).getExteriorRing();
MultiLineString clipped = (MultiLineString) clipper.clip(ls, false);
assertEquals(4, clipped.getNumGeometries());
showResult("Circle around", ls, clipped);
}
@Test
public void testInsidePolygon() throws Exception {
Geometry g = wkt.read("POINT(5 5)").buffer(2);
Geometry clipped = clipper.clip(g, false);
assertTrue(g.equalsExact(clipped));
showResult("Polygon inside", g, clipped);
}
@Test
public void testOutsidePolygon() throws Exception {
Geometry g = wkt.read("POINT(5 5)").buffer(10);
Geometry clipped = clipper.clip(g, false);
assertTrue(boundsPoly.equalsTopo(clipped));
showResult("Polygon outside", g, clipped);
}
@Test
public void testPolygonCrossingSide() throws Exception {
Geometry g = wkt.read("POLYGON((-2 2, 2 2, 2 4, -2 4, -2 2))");
Geometry clipped = clipper.clip(g, false);
//assertTrue(clipped.equalsExact(wkt.read("POLYGON((0 2, 2 2, 2 4, 0 4, 0 2))")));
showResult("Crossing side", g, clipped);
}
@Test
public void testCrossingOtherSide() throws Exception {
Geometry g = wkt.read("POLYGON((6 2, 12 2, 12 6, 6 6, 6 2))");
Geometry clipped = clipper.clip(g, false);
//assertTrue(clipped.equalsExact(wkt.read("POLYGON((0 2, 10 2, 10 10, 0 10, 0 2))")));
showResult("Donut crossing", g, clipped);
}
@Test
public void testPolygonCrossingTwoSides() throws Exception {
Geometry g = wkt.read("POLYGON((-2 2, 2 2, 2 12, -2 12, -2 2))");
Geometry clipped = clipper.clip(g, false);
assertTrue(clipped.equalsExact(wkt.read("POLYGON((0 2, 2 2, 2 10, 0 10, 0 2))")));
showResult("Crossing two sides", g, clipped);
}
@Test
public void testPolygonCrossingThreeSides() throws Exception {
Geometry g = wkt.read("POLYGON((-2 2, 12 2, 12 12, -2 12, -2 2))");
Geometry clipped = clipper.clip(g, false);
assertTrue(clipped.equalsExact(wkt.read("POLYGON((0 2, 10 2, 10 10, 0 10, 0 2))")));
showResult("Crossing three sides", g, clipped);
}
@Test
public void testDonutCrossingInvalid() throws Exception {
Geometry g = wkt.read("POLYGON((6 2, 14 2, 14 8, 6 8, 6 2), (8 4, 12 4, 12 6, 8 6, 8 4))");
Geometry clipped = clipper.clip(g, false);
// System.out.println(clipped);
assertTrue(clipped.equalsExact(wkt.read("POLYGON ((10 2, 10 8, 6 8, 6 2, 10 2), (10 4, 10 6, 8 6, 8 4, 10 4))")));
showResult("Donut crossing, invalid geom", g, clipped);
}
@Test
public void testDonutHoleOutside() throws Exception {
Geometry g = wkt.read("POLYGON((6 2, 14 2, 14 8, 6 8, 6 2), (11 4, 12 4, 12 6, 11 6, 11 4))");
Geometry clipped = clipper.clip(g, false);
// System.out.println(clipped);
assertTrue(clipped.equalsExact(wkt.read("POLYGON ((10 2, 10 8, 6 8, 6 2, 10 2))")));
showResult("Donut crossing, invalid geom", g, clipped);
}
@Test
public void testDonutCrossingValid() throws Exception {
Geometry g = wkt.read("POLYGON((6 2, 14 2, 14 8, 6 8, 6 2), (8 4, 12 4, 12 6, 8 6, 8 4))");
Geometry clipped = clipper.clip(g, true);
assertTrue(clipped.equalsExact(wkt.read("POLYGON ((10 2, 6 2, 6 8, 10 8, 10 6, 8 6, 8 4, 10 4, 10 2))")));
showResult("Donut crossing, valid geom", g, clipped);
}
@Test
public void testGeotXYWZ() throws Exception {
clipper = new GeometryClipper(new Envelope(-11, 761, -11, 611));
Geometry g = wkt.read("POLYGON((367 -13, 459 105, 653 -42, 611 -96, 562 -60, 514 -124, 367 -13))");
System.out.println(g.getNumPoints());
Geometry clipped = clipper.clip(g, false);
assertNotNull(clipped);
assertTrue(!clipped.isEmpty());
// System.out.println(clipped);
}
public void showResult(String title, Geometry original, Geometry clipped) throws Exception {
final String headless = System.getProperty("java.awt.headless", "false");
if (headless.equalsIgnoreCase("true") || !TestData.isInteractiveTest()) {
return;
}
BufferedImage image = new BufferedImage(600, 600, BufferedImage.TYPE_3BYTE_BGR);
Graphics2D gr = image.createGraphics();
gr.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
gr.setColor(Color.WHITE);
gr.fillRect(0, 0, image.getWidth(), image.getHeight());
gr.setColor(Color.LIGHT_GRAY);
gr.setStroke(new BasicStroke(1, 0, 0, 1, new float[] { 5, 5 }, 0));
gr.draw(new Line2D.Double(0, 300, 600, 300));
gr.draw(new Line2D.Double(300, 0, 300, 600));
AffineTransform at = new AffineTransform();
at.translate(300, 300);
at.scale(10, -10);
gr.setStroke(new BasicStroke(1));
gr.setColor(Color.LIGHT_GRAY);
gr.draw(new LiteShape(boundsPoly, at, false));
gr.setStroke(new BasicStroke(0.5f));
gr.setColor(Color.BLUE);
gr.draw(new LiteShape(original, at, false));
if(clipped != null) {
gr.setStroke(new BasicStroke(2));
if(clipped instanceof Polygon || clipped instanceof MultiPolygon) {
gr.setColor(Color.LIGHT_GRAY);
gr.fill(new LiteShape(clipped, at, false));
gr.setColor(Color.BLUE);
}
gr.draw(new LiteShape(clipped, at, false));
}
gr.dispose();
JFrame frame = new JFrame(title);
frame.setContentPane(new JLabel(new ImageIcon(image)));
frame.pack();
frame.setVisible(true);
Thread.sleep(3000);
frame.setVisible(false);
}
// public static void main(String[] args) throws Exception {
// GeometryClipper clipper = new GeometryClipper(new Envelope(0, 10, 0, 10));
// Geometry boundsPoly = new WKTReader().read("POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))");
//
// Point p = (Point) new WKTReader().read("POINT(5 5)");
// LineString ls = ((Polygon) p.buffer(6, 128)).getExteriorRing();
//
// long start = System.nanoTime();
// for (int i = 0; i < 1000000; i++) {
// clipper.clip(ls);
// }
// long end = System.nanoTime();
// System.out.println("GeometryClipper: " + (end - start) / 1000000000.0);
// start = System.nanoTime();
// for (int i = 0; i < 10000; i++) {
// ls.intersection(boundsPoly);
// }
// end = System.nanoTime();
// System.out.println("JTS: " + (end - start) / 1000000000.0);
//
// MultiLineString clipped = (MultiLineString) clipper.clip(ls);
// System.out.println(clipped);
// System.out.println(ls.intersection(boundsPoly));
// }
}