package org.geotools.process.vector;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.geotools.data.property.PropertyDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.NameImpl;
import org.geotools.test.TestData;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.type.Name;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.io.WKTReader;
public class ClipProcessTest extends Assert {
private SimpleFeatureSource fsMeters;
private SimpleFeatureSource fsDegrees;
private SimpleFeatureSource fsLines;
private SimpleFeatureSource fsCollinear;
private SimpleFeatureSource fsMultilines;
@Before
public void setUp() throws Exception {
PropertyDataStore store = new PropertyDataStore(TestData.file(this, ""));
fsMeters = store.getFeatureSource("squaresMeters");
fsDegrees = store.getFeatureSource("squaresDegrees");
fsLines = store.getFeatureSource("lines");
fsMultilines = store.getFeatureSource("multilines");
fsCollinear = store.getFeatureSource("collinear");
}
@Test
public void testClipPoly3DIncluded() throws Exception {
SimpleFeatureCollection features = fsMeters.getFeatures();
ClipProcess cp = new ClipProcess();
SimpleFeatureCollection result = cp.execute(features, new WKTReader().read("POLYGON((-10 -10, -10 10010, 10010 10010, 10010 -10, -10 -10))"), true);
assertEquals(2, result.size());
assertSquaresMetersIdentical(result);
}
@Test
public void testClipPoly3DOnBorder() throws Exception {
SimpleFeatureCollection features = fsMeters.getFeatures();
ClipProcess cp = new ClipProcess();
SimpleFeatureCollection result = cp.execute(features, new WKTReader().read("POLYGON((0 0, 0 10000, 10000 10000, 10000 0, 0 0))"), true);
assertEquals(2, result.size());
assertSquaresMetersIdentical(result);
}
@Test
public void testClipPoly3DNewVertices() throws Exception {
SimpleFeatureCollection features = fsMeters.getFeatures();
ClipProcess cp = new ClipProcess();
SimpleFeatureCollection result = cp.execute(features, new WKTReader().read("POLYGON((0 5000, 0 10000, 10000 10000, 10000 5000, 0 5000))"), true);
assertEquals(1, result.size());
SimpleFeatureIterator fi = result.features();
// check the first polygon
SimpleFeature f = fi.next();
MultiPolygon mp = (MultiPolygon) f.getDefaultGeometry();
assertEquals(1, mp.getNumGeometries());
Polygon p = (Polygon) mp.getGeometryN(0);
assertEquals(0, p.getNumInteriorRing());
LineString shell = p.getExteriorRing();
CoordinateSequence cs = shell.getCoordinateSequence();
assertEquals(5, cs.size());
assertOrdinates(0, 5000, 1, cs, 0);
assertOrdinates(0, 10000, 2, cs, 1);
assertOrdinates(10000, 10000, 2, cs, 2);
assertOrdinates(10000, 5000, 1, cs, 3);
assertOrdinates(0, 5000, 1, cs, 4);
// ensure no second
assertFalse(fi.hasNext());
fi.close();
}
@Test
public void testClipPoly3DFullyInside() throws Exception {
SimpleFeatureCollection features = fsMeters.getFeatures();
ClipProcess cp = new ClipProcess();
SimpleFeatureCollection result = cp.execute(features, new WKTReader().read("POLYGON((2500 2500, 2500 7500, 7500 7500, 7500 2500, 2500 2500))"), true);
assertEquals(2, result.size());
SimpleFeatureIterator fi = result.features();
// check the first polygon
SimpleFeature f = fi.next();
MultiPolygon mp = (MultiPolygon) f.getDefaultGeometry();
assertEquals(1, mp.getNumGeometries());
Polygon p = (Polygon) mp.getGeometryN(0);
assertEquals(0, p.getNumInteriorRing());
LineString shell = p.getExteriorRing();
CoordinateSequence cs = shell.getCoordinateSequence();
assertEquals(5, cs.size());
assertOrdinates(2500, 2500, 0.411765, cs, 0);
assertOrdinates(2500, 7500, 1.588235, cs, 1);
assertOrdinates(7500, 7500, 1.588235, cs, 2);
assertOrdinates(7500, 2500, 0.411765, cs, 3);
assertOrdinates(2500, 2500, 0.411765, cs, 4);
fi.close();
}
private void assertSquaresMetersIdentical(SimpleFeatureCollection result) {
SimpleFeatureIterator fi = result.features();
// check the first polygon
SimpleFeature f = fi.next();
MultiPolygon mp = (MultiPolygon) f.getDefaultGeometry();
assertEquals(1, mp.getNumGeometries());
Polygon p = (Polygon) mp.getGeometryN(0);
assertEquals(0, p.getNumInteriorRing());
LineString shell = p.getExteriorRing();
CoordinateSequence cs = shell.getCoordinateSequence();
assertEquals(5, cs.size());
assertOrdinates(0, 0, 0, cs, 0);
assertOrdinates(0, 10000, 2, cs, 1);
assertOrdinates(10000, 10000, 2, cs, 2);
assertOrdinates(10000, 0, 0, cs, 3);
assertOrdinates(0, 0, 0, cs, 4);
// check the second
f = fi.next();
mp = (MultiPolygon) f.getDefaultGeometry();
assertEquals(1, mp.getNumGeometries());
p = (Polygon) mp.getGeometryN(0);
assertEquals(0, p.getNumInteriorRing());
shell = p.getExteriorRing();
cs = shell.getCoordinateSequence();
assertEquals(5, cs.size());
assertOrdinates(0, 0, Double.NaN, cs, 0);
assertOrdinates(0, 5000, Double.NaN, cs, 1);
assertOrdinates(5000, 5000, Double.NaN, cs, 2);
assertOrdinates(5000, 0, Double.NaN, cs, 3);
assertOrdinates(0, 0, Double.NaN, cs, 4);
}
@Test
public void testClipLine3DIncluded() throws Exception {
SimpleFeatureCollection features = fsLines.getFeatures();
ClipProcess cp = new ClipProcess();
SimpleFeatureCollection result = cp.execute(features, new WKTReader().read("POLYGON((-10 -10, -10 10010, 10010 10010, 10010 -10, -10 -10))"), true);
assertEquals(1, result.size());
SimpleFeatureIterator fi = result.features();
// check the first polygon
SimpleFeature f = fi.next();
MultiLineString ml = (MultiLineString) f.getDefaultGeometry();
assertEquals(1, ml.getNumGeometries());
LineString ls = (LineString) ml.getGeometryN(0);
CoordinateSequence cs = ls.getCoordinateSequence();
assertEquals(3, cs.size());
assertOrdinates(0, 0, 0, cs, 0);
assertOrdinates(10000, 0, 1, cs, 1);
assertOrdinates(10000, 10000, 2, cs, 2);
fi.close();
}
@Test
public void testClipLine3DMidFirstSegment() throws Exception {
SimpleFeatureCollection features = fsLines.getFeatures();
ClipProcess cp = new ClipProcess();
SimpleFeatureCollection result = cp.execute(features, new WKTReader().read("POLYGON((-10 -10, -10 10, 5000 10, 5000 -10, -10 -10))"), true);
assertEquals(1, result.size());
SimpleFeatureIterator fi = result.features();
// check the first polygon
SimpleFeature f = fi.next();
MultiLineString ml = (MultiLineString) f.getDefaultGeometry();
assertEquals(1, ml.getNumGeometries());
LineString ls = (LineString) ml.getGeometryN(0);
CoordinateSequence cs = ls.getCoordinateSequence();
assertEquals(2, cs.size());
assertOrdinates(0, 0, 0, cs, 0);
assertOrdinates(5000, 0, 0.5, cs, 1);
fi.close();
}
@Test
public void testService() throws Exception{
VectorProcessFactory factory = new VectorProcessFactory();
Set<Name> names = factory.getNames();
assertFalse(names.isEmpty());
assertTrue(names.contains(new NameImpl("vec", "Clip")));
SimpleFeatureCollection features = fsLines.getFeatures();
Map<String, Object> arguments= new HashMap<String, Object>();
arguments.put("features", features);
arguments.put("clip", new WKTReader().read("POLYGON((-10 -10, -10 10, 5000 10, 5000 -10, -10 -10))"));
Map<String, Object> output = factory.create(new NameImpl("vec", "Clip")).execute(arguments, null);
SimpleFeatureCollection result=(SimpleFeatureCollection) output.get("result");
assertEquals(1, result.size());
}
@Test
public void testClipCollinearLine3DMidFirstSegment() throws Exception {
SimpleFeatureCollection features = fsCollinear.getFeatures();
ClipProcess cp = new ClipProcess();
SimpleFeatureCollection result = cp.execute(features, new WKTReader().read("POLYGON((-10 -10, -10 10, 5000 10, 5000 -10, -10 -10))"), true);
assertEquals(1, result.size());
SimpleFeatureIterator fi = result.features();
// check the first polygon
SimpleFeature f = fi.next();
MultiLineString ml = (MultiLineString) f.getDefaultGeometry();
assertEquals(1, ml.getNumGeometries());
LineString ls = (LineString) ml.getGeometryN(0);
CoordinateSequence cs = ls.getCoordinateSequence();
assertEquals(4, cs.size());
assertOrdinates(0, 0, 0, cs, 0);
assertOrdinates(1000, 0, 0.1, cs, 1);
assertOrdinates(4000, 0, 0.4, cs, 2);
assertOrdinates(5000, 0, 0.5, cs, 3);
fi.close();
}
@Test
public void testClipLine3DMidSecondSegment() throws Exception {
SimpleFeatureCollection features = fsLines.getFeatures();
ClipProcess cp = new ClipProcess();
SimpleFeatureCollection result = cp.execute(features, new WKTReader().read("POLYGON((9000 5000, 9000 10000, 11000 10000, 11000 5000, 9000 5000))"), true);
assertEquals(1, result.size());
SimpleFeatureIterator fi = result.features();
// check the first polygon
SimpleFeature f = fi.next();
MultiLineString ml = (MultiLineString) f.getDefaultGeometry();
assertEquals(1, ml.getNumGeometries());
LineString ls = (LineString) ml.getGeometryN(0);
CoordinateSequence cs = ls.getCoordinateSequence();
assertEquals(2, cs.size());
assertOrdinates(10000, 5000, 1.5, cs, 0);
assertOrdinates(10000, 10000, 2, cs, 1);
fi.close();
}
@Test
public void testClipExtractBend() throws Exception {
SimpleFeatureCollection features = fsLines.getFeatures();
ClipProcess cp = new ClipProcess();
SimpleFeatureCollection result = cp.execute(features, new WKTReader().read("POLYGON((5000 -10, 5000 5000, 11000 5000, 11000 -10, 5000 -10))"), true);
assertEquals(1, result.size());
SimpleFeatureIterator fi = result.features();
// check the first polygon
SimpleFeature f = fi.next();
MultiLineString ml = (MultiLineString) f.getDefaultGeometry();
assertEquals(1, ml.getNumGeometries());
LineString ls = (LineString) ml.getGeometryN(0);
CoordinateSequence cs = ls.getCoordinateSequence();
assertEquals(3, cs.size());
assertOrdinates(5000, 0, 0.5, cs, 0);
assertOrdinates(10000, 0, 1, cs, 1);
assertOrdinates(10000, 5000, 1.5, cs, 2);
fi.close();
}
@Test
public void testClipExtractSeparateBitsLowLine() throws Exception {
SimpleFeatureCollection features = fsLines.getFeatures();
ClipProcess cp = new ClipProcess();
// clip with a rotated "C"
SimpleFeatureCollection result = cp.execute(features, new WKTReader().read("POLYGON((1000 -10, 1000 10, 9000 10, 9000 -10, 8000 -10, 8000 5, 2000 5, 2000 -10, 1000 -10))"), true);
assertEquals(1, result.size());
SimpleFeatureIterator fi = result.features();
// check the first polygon
SimpleFeature f = fi.next();
fi.close();
MultiLineString ml = (MultiLineString) f.getDefaultGeometry();
assertEquals(2, ml.getNumGeometries());
LineString ls = (LineString) ml.getGeometryN(0);
CoordinateSequence cs = ls.getCoordinateSequence();
assertEquals(2, cs.size());
assertOrdinates(1000, 0, 0.1, cs, 0);
assertOrdinates(2000, 0, 0.2, cs, 1);
ls = (LineString) ml.getGeometryN(1);
cs = ls.getCoordinateSequence();
assertEquals(2, cs.size());
assertOrdinates(8000, 0, 0.8, cs, 0);
assertOrdinates(9000, 0, 0.9, cs, 1);
}
@Test
public void testClipExtractSeparateBitsBothLines() throws Exception {
SimpleFeatureCollection features = fsLines.getFeatures();
ClipProcess cp = new ClipProcess();
// clip with a rotated "L"
SimpleFeatureCollection result = cp.execute(features, new WKTReader().read("POLYGON((1000 -10, 1000 5000, 11000 5000, 11000 4000, 2000 4000, 2000 -10, 1000 -10))"), true);
assertEquals(1, result.size());
SimpleFeatureIterator fi = result.features();
// check the first polygon
SimpleFeature f = fi.next();
fi.close();
MultiLineString ml = (MultiLineString) f.getDefaultGeometry();
assertEquals(2, ml.getNumGeometries());
LineString ls = (LineString) ml.getGeometryN(0);
CoordinateSequence cs = ls.getCoordinateSequence();
assertEquals(2, cs.size());
assertOrdinates(1000, 0, 0.1, cs, 0);
assertOrdinates(2000, 0, 0.2, cs, 1);
ls = (LineString) ml.getGeometryN(1);
cs = ls.getCoordinateSequence();
assertEquals(2, cs.size());
assertOrdinates(10000, 4000, 1.4, cs, 0);
assertOrdinates(10000, 5000, 1.5, cs, 1);
}
@Test
public void testClipMultiline() throws Exception {
SimpleFeatureCollection features = fsMultilines.getFeatures();
ClipProcess cp = new ClipProcess();
// clip with a rotated "L"
SimpleFeatureCollection result = cp.execute(features, new WKTReader().read("POLYGON((900 900, 900 2100, 2100 2100, 2100 900, 900 900))"), true);
assertEquals(1, result.size());
SimpleFeatureIterator fi = result.features();
// check the first polygon
SimpleFeature f = fi.next();
fi.close();
MultiLineString ml = (MultiLineString) f.getDefaultGeometry();
assertEquals(2, ml.getNumGeometries());
LineString ls = (LineString) ml.getGeometryN(0);
CoordinateSequence cs = ls.getCoordinateSequence();
assertEquals(4, cs.size());
assertOrdinates(1000, 900, 0.9, cs, 0);
assertOrdinates(1000, 1000, 1.0, cs, 1);
assertOrdinates(2000, 1000, 2.0, cs, 2);
assertOrdinates(2000, 900, 2.1, cs, 3);
ls = (LineString) ml.getGeometryN(1);
cs = ls.getCoordinateSequence();
assertEquals(4, cs.size());
assertOrdinates(1000, 2100, 0.9, cs, 0);
assertOrdinates(1000, 2000, 1.0, cs, 1);
assertOrdinates(2000, 2000, 2.0, cs, 2);
assertOrdinates(2000, 2100, 2.1, cs, 3);
}
@Test
public void testEmptyLines() throws Exception {
SimpleFeatureCollection features = fsLines.getFeatures();
ClipProcess cp = new ClipProcess();
// to reproduce the issue we need a non rectangular clip polygon,
// whose bbox will intersect the bbox of the geometry, but whose intersection is actually
// emtpy
SimpleFeatureCollection result = cp.execute(features,
new WKTReader().read("POLYGON((-8 -7, -8 3, 2 3, -8 -7))"), true);
assertEquals(0, result.size());
SimpleFeatureIterator fi = result.features();
assertFalse(fi.hasNext());
fi.close();
}
@Test
public void testEmptyMultiLines() throws Exception {
SimpleFeatureCollection features = fsMultilines.getFeatures();
ClipProcess cp = new ClipProcess();
SimpleFeatureCollection result = cp.execute(features,
new WKTReader().read("POLYGON((-10 -10, -10 -5, -5 -5, -5 -10, -10 -10))"), true);
assertEquals(0, result.size());
SimpleFeatureIterator fi = result.features();
assertFalse(fi.hasNext());
fi.close();
}
private void assertOrdinates(double x, double y, double z, CoordinateSequence cs, int index) {
assertEquals(x, cs.getOrdinate(index, 0), 0d);
assertEquals(y, cs.getOrdinate(index, 1), 0d);
double otherZ = cs.getOrdinate(index, 2);
if(Double.isNaN(z)) {
assertTrue(Double.isNaN(otherZ));
} else {
assertEquals(z, otherZ, 0d);
}
}
}