/*
* Copyright (c) 2016 Vivid Solutions.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
*
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.locationtech.jts.operation.buffer;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.MultiPolygon;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.geom.PrecisionModel;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.io.WKTWriter;
import org.locationtech.jts.operation.buffer.validate.BufferResultValidator;
import org.locationtech.jts.util.StringUtil;
import junit.framework.Assert;
/**
* @version 1.7
*/
public class BufferValidator
{
public static void main(String[] args) throws Exception {
Geometry g =
new WKTReader().read(
"MULTILINESTRING (( 635074.5418406526 6184832.4888257105, 635074.5681951842 6184832.571842485, 635074.6472587794 6184832.575795664 ), ( 635074.6657069515 6184832.53889932, 635074.6933792098 6184832.451929366, 635074.5642420045 6184832.474330718 ))");
//System.out.println(g);
//System.out.println(g.buffer(0.01, 100));
//System.out.println("END");
}
private static abstract class Test implements Comparable {
private String name;
public Test(String name) {
this(name, 2);
}
public Test(String name, int priority) {
this.name = name;
this.priority = priority;
}
public String getName() {
return name;
}
public String toString() {
return getName();
}
public abstract void test() throws Exception;
private int priority;
public int compareTo(Object o) {
return priority - ((Test) o).priority;
}
}
private Geometry original;
private double bufferDistance;
private Map nameToTestMap = new HashMap();
private Geometry buffer;
private static final int QUADRANT_SEGMENTS_1 = 100;
private static final int QUADRANT_SEGMENTS_2 = 50;
private String wkt;
private GeometryFactory geomFact = new GeometryFactory();
private WKTWriter wktWriter = new WKTWriter();
private WKTReader wktReader;
public BufferValidator(double bufferDistance, String wkt)
throws ParseException {
this(bufferDistance, wkt, true);
}
public BufferValidator(double bufferDistance, String wkt, boolean addContainsTest)
throws ParseException {
// SRID = 888 is to test that SRID is preserved in computed buffers
setFactory(new PrecisionModel(), 888);
this.bufferDistance = bufferDistance;
this.wkt = wkt;
if (addContainsTest) addContainsTest();
//addBufferResultValidatorTest();
}
public void test() throws Exception {
try {
Collection tests = nameToTestMap.values();
for (Iterator i = tests.iterator();
i.hasNext();
) {
Test test = (Test) i.next();
test.test();
}
} catch (Exception e) {
throw new Exception(
supplement(e.toString()) + StringUtil.getStackTrace(e));
}
}
private String supplement(String message) throws ParseException {
String newMessage = "\n" + message + "\n";
newMessage += "Original: " + wktWriter.writeFormatted(getOriginal()) + "\n";
newMessage += "Buffer Distance: " + bufferDistance + "\n";
newMessage += "Buffer: " + wktWriter.writeFormatted(getBuffer()) + "\n";
return newMessage.substring(0, newMessage.length() - 1);
}
private BufferValidator addTest(Test test) {
nameToTestMap.put(test.getName(), test);
return this;
}
public BufferValidator setExpectedArea(final double expectedArea) {
return addTest(new Test("Area Test") {
public void test() throws Exception {
double tolerance =
Math.abs(
getBuffer().getArea()
- getOriginal()
.buffer(
bufferDistance,
QUADRANT_SEGMENTS_1 - QUADRANT_SEGMENTS_2)
.getArea());
Assert.assertEquals(
getName(),
expectedArea,
getBuffer().getArea(),
tolerance);
}
});
}
public BufferValidator setEmptyBufferExpected(final boolean emptyBufferExpected) {
return addTest(new Test("Empty Buffer Test", 1) {
public void test() throws Exception {
Assert.assertTrue(
supplement(
"Expected buffer "
+ (emptyBufferExpected ? "" : "not ")
+ "to be empty"),
emptyBufferExpected == getBuffer().isEmpty());
}
});
}
public BufferValidator setBufferHolesExpected(final boolean bufferHolesExpected) {
return addTest(new Test("Buffer Holes Test") {
public void test() throws Exception {
Assert.assertTrue(
supplement(
"Expected buffer "
+ (bufferHolesExpected ? "" : "not ")
+ "to have holes"),
hasHoles(getBuffer()) == bufferHolesExpected);
}
private boolean hasHoles(Geometry buffer) {
if (buffer.isEmpty()) {
return false;
}
if (buffer instanceof Polygon) {
return ((Polygon) buffer).getNumInteriorRing() > 0;
}
MultiPolygon multiPolygon = (MultiPolygon) buffer;
for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
if (hasHoles(multiPolygon.getGeometryN(i))) {
return true;
}
}
return false;
}
});
}
private Geometry getOriginal() throws ParseException {
if (original == null) {
original = wktReader.read(wkt);
}
return original;
}
public BufferValidator setPrecisionModel(PrecisionModel precisionModel) {
wktReader = new WKTReader(new GeometryFactory(precisionModel));
return this;
}
public BufferValidator setFactory(PrecisionModel precisionModel, int srid) {
wktReader = new WKTReader(new GeometryFactory(precisionModel, srid));
return this;
}
private Geometry getBuffer() throws ParseException {
if (buffer == null) {
buffer = getOriginal().buffer(bufferDistance, QUADRANT_SEGMENTS_1);
if (getBuffer().getClass() == GeometryCollection.class && getBuffer().isEmpty()) {
try {
//#contains doesn't work with GeometryCollections [Jon Aquino
// 10/29/2003]
buffer = wktReader.read("POINT EMPTY");
} catch (ParseException e) {
org.locationtech.jts.util.Assert.shouldNeverReachHere();
}
}
}
return buffer;
}
private void addContainsTest() {
addTest(new Test("Contains Test") {
public void test() throws Exception {
if (getOriginal().getClass() == GeometryCollection.class) {
return;
}
org.locationtech.jts.util.Assert.isTrue(getOriginal().isValid());
if (bufferDistance > 0) {
Assert.assertTrue(
supplement("Expected buffer to contain original"),
contains(getBuffer(), getOriginal()));
} else {
Assert.assertTrue(
supplement("Expected original to contain buffer"),
contains(getOriginal(), getBuffer()));
}
}
private boolean contains(Geometry a, Geometry b) {
//JTS doesn't currently handle empty geometries correctly [Jon Aquino
// 10/29/2003]
if (b.isEmpty()) {
return true;
}
boolean isContained = a.contains(b);
return isContained;
}
});
}
private void addBufferResultValidatorTest() {
addTest(new Test("BufferResultValidator Test") {
public void test() throws Exception {
if (getOriginal().getClass() == GeometryCollection.class) {
return;
}
Assert.assertTrue(
supplement("BufferResultValidator failure"),
BufferResultValidator.isValid(getOriginal(), bufferDistance, getBuffer()));
}
});
}
}