/* * 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.linearref; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.io.ParseException; import org.locationtech.jts.io.WKTReader; import junit.framework.TestCase; /** * Base class for linear referencing class unit tests. */ public abstract class AbstractIndexedLineTest extends TestCase { private WKTReader reader = new WKTReader(); public AbstractIndexedLineTest(String name) { super(name); } public void testFirst() { runOffsetTest("LINESTRING (0 0, 20 20)", "POINT(20 20)", 0.0, "POINT (20 20)"); } public void testML() { runIndicesOfThenExtract("MULTILINESTRING ((0 0, 10 10), (20 20, 30 30))", "MULTILINESTRING ((1 1, 10 10), (20 20, 25 25))"); } public void testPartOfSegmentNoVertex() { runIndicesOfThenExtract("LINESTRING (0 0, 10 10, 20 20)", "LINESTRING (1 1, 9 9)"); } public void testPartOfSegmentContainingVertex() { runIndicesOfThenExtract("LINESTRING (0 0, 10 10, 20 20)", "LINESTRING (5 5, 10 10, 15 15)"); } /** * Tests that duplicate coordinates are handled correctly. */ public void testPartOfSegmentContainingDuplicateCoords() { runIndicesOfThenExtract("LINESTRING (0 0, 10 10, 10 10, 20 20)", "LINESTRING (5 5, 10 10, 10 10, 15 15)"); } /** * Following tests check that correct portion of loop is identified. * This requires that the correct vertex for (0,0) is selected. */ public void testLoopWithStartSubLine() { runIndicesOfThenExtract("LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)", "LINESTRING (0 0, 0 10, 10 10)"); } public void testLoopWithEndingSubLine() { runIndicesOfThenExtract("LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)", "LINESTRING (10 10, 10 0, 0 0)"); } // test a subline equal to the parent loop public void testLoopWithIdenticalSubLine() { runIndicesOfThenExtract("LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)", "LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)"); } // test a zero-length subline equal to the start point public void testZeroLenSubLineAtStart() { runIndicesOfThenExtract("LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)", "LINESTRING (0 0, 0 0)"); } // test a zero-length subline equal to a mid point public void testZeroLenSubLineAtMidVertex() { runIndicesOfThenExtract("LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)", "LINESTRING (10 10, 10 10)"); } public void testIndexOfAfterSquare() { runIndexOfAfterTest("LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)", "POINT (0 0)"); } public void testIndexOfAfterRibbon() { runIndexOfAfterTest("LINESTRING (0 0, 0 60, 50 60, 50 20, -20 20)", "POINT (0 20)"); runIndexOfAfterTest("LINESTRING (0 0, 0 60, 50 60, 50 20, -20 20)", "POINT (0 20)", "POINT (30 60)"); } public void testIndexOfAfterBeyondEndRibbon() { runIndexOfAfterTest("LINESTRING (0 0, 0 60, 50 60, 50 20, -20 20)", "POINT (-30 20)", "POINT (-20 20)"); } public void testOffsetStartPoint() { runOffsetTest("LINESTRING (0 0, 10 10, 20 20)", "POINT(0 0)", 1.0, "POINT (-0.7071067811865475 0.7071067811865475)"); runOffsetTest("LINESTRING (0 0, 10 10, 20 20)", "POINT(0 0)", -1.0, "POINT (0.7071067811865475 -0.7071067811865475)"); runOffsetTest("LINESTRING (0 0, 10 10, 20 20)", "POINT(10 10)", 5.0, "POINT (6.464466094067262 13.535533905932738)"); runOffsetTest("LINESTRING (0 0, 10 10, 20 20)", "POINT(10 10)", -5.0, "POINT (13.535533905932738 6.464466094067262)"); } public void testOffsetStartPointRepeatedPoint() { runOffsetTest("LINESTRING (0 0, 10 10, 10 10, 20 20)", "POINT(0 0)", 1.0, "POINT (-0.7071067811865475 0.7071067811865475)"); runOffsetTest("LINESTRING (0 0, 10 10, 10 10, 20 20)", "POINT(0 0)", -1.0, "POINT (0.7071067811865475 -0.7071067811865475)"); // These tests work for LengthIndexedLine, but not LocationIndexedLine //runOffsetTest("LINESTRING (0 0, 10 10, 10 10, 20 20)", "POINT(10 10)", 5.0, "POINT (6.464466094067262 13.535533905932738)"); //runOffsetTest("LINESTRING (0 0, 10 10, 10 10, 20 20)", "POINT(10 10)", -5.0, "POINT (13.535533905932738 6.464466094067262)"); } public void testOffsetEndPoint() { runOffsetTest("LINESTRING (0 0, 20 20)", "POINT(20 20)", 0.0, "POINT (20 20)"); runOffsetTest("LINESTRING (0 0, 13 13, 20 20)", "POINT(20 20)", 0.0, "POINT (20 20)"); runOffsetTest("LINESTRING (0 0, 10 0, 20 0)", "POINT(20 0)", 1.0, "POINT (20 1)"); runOffsetTest("LINESTRING (0 0, 20 0)", "POINT(10 0)", 1.0, "POINT (10 1)"); // point on last segment runOffsetTest("MULTILINESTRING ((0 0, 10 0), (10 0, 20 0))", "POINT(10 0)", -1.0, "POINT (10 -1)"); runOffsetTest("MULTILINESTRING ((0 0, 10 0), (10 0, 20 0))", "POINT(20 0)", 1.0, "POINT (20 1)"); } protected Geometry read(String wkt) { try { return reader.read(wkt); } catch (ParseException ex) { throw new RuntimeException(ex); } } protected void runIndicesOfThenExtract(String inputStr, String subLineStr) // throws Exception { Geometry input = read(inputStr); Geometry subLine = read(subLineStr); Geometry result = indicesOfThenExtract(input, subLine); checkExpected(result, subLineStr); } protected void checkExpected(Geometry result, String expected) { Geometry subLine = read(expected); boolean isEqual = result.equalsExact(subLine, 1.0e-5); if (! isEqual) { System.out.println("Computed result is: " + result); } assertTrue(isEqual); } protected abstract Geometry indicesOfThenExtract(Geometry input, Geometry subLine); /* // example of indicesOfThenLocate method private Geometry indicesOfThenLocate(LineString input, LineString subLine) { LocationIndexedLine indexedLine = new LocationIndexedLine(input); LineStringLocation[] loc = indexedLine.indicesOf(subLine); Geometry result = indexedLine.locate(loc[0], loc[1]); return result; } */ protected void runIndexOfAfterTest(String inputStr, String testPtWKT) // throws Exception { Geometry input = read(inputStr); Geometry testPoint = read(testPtWKT); Coordinate testPt = testPoint.getCoordinate(); boolean resultOK = indexOfAfterCheck(input, testPt); assertTrue(resultOK); } protected void runIndexOfAfterTest(String inputStr, String testPtWKT, String afterPtWKT) // throws Exception { Geometry input = read(inputStr); Geometry testPoint = read(testPtWKT); Coordinate testPt = testPoint.getCoordinate(); Geometry afterPoint = read(afterPtWKT); Coordinate afterPt = afterPoint.getCoordinate(); boolean resultOK = indexOfAfterCheck(input, testPt, afterPt); assertTrue(resultOK); } /** * Checks that the point computed by <tt>indexOfAfter</tt> * is the same as the input point. * (This should be the case for all except pathological cases, * such as the input test point being beyond the end of the line). * * @param input * @param testPt * @return true if the result of indexOfAfter is the same as the input point */ protected abstract boolean indexOfAfterCheck(Geometry input, Coordinate testPt); protected abstract boolean indexOfAfterCheck(Geometry input, Coordinate testPt, Coordinate afterPt); static final double TOLERANCE_DIST = 0.001; protected void runOffsetTest(String inputWKT, String testPtWKT, double offsetDistance, String expectedPtWKT) // throws Exception { Geometry input = read(inputWKT); Geometry testPoint = read(testPtWKT); Geometry expectedPoint = read(expectedPtWKT); Coordinate testPt = testPoint.getCoordinate(); Coordinate expectedPt = expectedPoint.getCoordinate(); Coordinate offsetPt = extractOffsetAt(input, testPt, offsetDistance); boolean isOk = offsetPt.distance(expectedPt) < TOLERANCE_DIST; if (! isOk) System.out.println("Expected = " + expectedPoint + " Actual = " + offsetPt); assertTrue(isOk); } protected abstract Coordinate extractOffsetAt(Geometry input, Coordinate testPt, double offsetDistance); }