package com.revolsys.geometry.test.model;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import com.revolsys.geometry.algorithm.LineStringLocation;
import com.revolsys.geometry.cs.GeographicCoordinateSystem;
import com.revolsys.geometry.cs.ProjectedCoordinateSystem;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.geometry.model.LineString;
import com.revolsys.geometry.model.Point;
import com.revolsys.geometry.model.Side;
import com.revolsys.geometry.model.impl.PointDouble;
import com.revolsys.geometry.model.metrics.PointLineStringMetrics;
public class LineStringTest {
private static final double START_X = 500000;
private static final double START_Y = 6000000;
public static void assertCoordinatesEquals(final Point point, final double... coordinates) {
Assert.assertEquals("Is Empty", false, point.isEmpty());
Assert.assertEquals("Geometry Count", 1, point.getGeometryCount());
Assert.assertNotNull("Not Null First Vertex", point.getVertex(0));
Assert.assertEquals("Axis Count", coordinates.length, point.getAxisCount());
for (int axisIndex = -1; axisIndex < point.getAxisCount() + 1; axisIndex++) {
final double value = point.getCoordinate(axisIndex);
if (axisIndex < 0 || axisIndex >= coordinates.length) {
if (!Double.isNaN(value)) {
TestUtil.failNotEquals("Value NaN", Double.NaN, value);
}
} else {
Assert.assertEquals("Coordinate Value", coordinates[axisIndex], value, 0);
}
}
}
private static void assertDistanceAlong(final double distanceAlong, final double distance,
final double x, final double y, final Side side, final double... coordinates) {
final GeometryFactory geometryFactory = GeometryFactory.worldMercator().convertAxisCount(2);
final Point point = geometryFactory.point(x, y);
final LineString line = geometryFactory.lineString(2, coordinates);
final double actual = line.distanceAlong(point);
Assert.assertEquals("Distance Along", distanceAlong, actual, 0.0000001);
final PointLineStringMetrics metrics = line.getMetrics(point);
Assert.assertEquals("Metrics Distance Along", distanceAlong, metrics.getDistanceAlong(),
0.0000001);
Assert.assertEquals("Metrics Distance", distance, metrics.getDistance(), 0.0000001);
Assert.assertEquals("Metrics Side", side, metrics.getSide());
Assert.assertEquals("Metrics Length", line.getLength(), metrics.getLineLength(), 0.0000001);
Assert.assertEquals("Distance Along -> Metrics", distanceAlong, metrics.getDistanceAlong(),
0.0000001);
if (side != null) {
final Side reverseSide = Side.opposite(side);
final LineString reverseLine = line.reverse();
final PointLineStringMetrics reverseMetrics = reverseLine.getMetrics(point);
Assert.assertEquals("Reverse Metrics Side", reverseSide, reverseMetrics.getSide());
}
}
public static void assertEmpty(final LineString line) {
Assert.assertEquals("Is Empty", true, line.isEmpty());
Assert.assertEquals("Geometry Count", 0, line.getGeometryCount());
Assert.assertNull("Null First Vertex", line.getVertex(0));
for (int axisIndex = -1; axisIndex < line.getAxisCount() + 1; axisIndex++) {
final double value = line.getCoordinate(0, axisIndex);
if (!Double.isNaN(value)) {
TestUtil.failNotEquals("Value NaN", Double.NaN, value);
}
}
}
public static void assertEquals(final Point point, final double... coordinates) {
final GeometryFactory geometryFactory = point.getGeometryFactory();
final GeometryFactory geometryFactory2;
final int axisCount = geometryFactory.getAxisCount();
if (geometryFactory.getCoordinateSystem() instanceof ProjectedCoordinateSystem) {
final ProjectedCoordinateSystem projectedCs = (ProjectedCoordinateSystem)geometryFactory
.getCoordinateSystem();
final GeographicCoordinateSystem geographicCoordinateSystem = projectedCs
.getGeographicCoordinateSystem();
geometryFactory2 = GeometryFactory
.floating(geographicCoordinateSystem.getCoordinateSystemId(), axisCount);
} else {
geometryFactory2 = GeometryFactory.floating(26910, axisCount);
}
assertCoordinatesEquals(point, coordinates);
final Point clone = point.newPoint();
assertCoordinatesEquals(clone, coordinates);
final Point converted = point.convertGeometry(geometryFactory);
assertCoordinatesEquals(converted, coordinates);
Assert.assertSame(point, converted);
final Point convertedOther = point.convertGeometry(geometryFactory2);
final Point convertedBack = convertedOther.convertGeometry(geometryFactory);
assertCoordinatesEquals(convertedBack, coordinates);
Assert.assertNotSame(point, convertedBack);
final Point copy = point.newGeometry(geometryFactory);
assertCoordinatesEquals(copy, coordinates);
Assert.assertNotSame(point, copy);
final Point copyOther = point.convertGeometry(geometryFactory2);
final Point copyBack = copyOther.convertGeometry(geometryFactory);
assertCoordinatesEquals(copyBack, coordinates);
Assert.assertNotSame(point, copyBack);
final String string = point.toString();
final Point pointString = geometryFactory.geometry(string);
assertCoordinatesEquals(pointString, coordinates);
final String wkt = point.toEwkt();
final Point pointWkt = geometryFactory.geometry(wkt);
assertCoordinatesEquals(pointWkt, coordinates);
}
public static void assertMerge(final boolean loop, final LineString line1, final LineString line2,
final double mergeX, final double mergeY, final double... expectedCoordinates) {
final GeometryFactory geometryFactory = line1.getGeometryFactory();
final int axisCount = geometryFactory.getAxisCount();
final LineString expectedMergedLine = geometryFactory.lineString(axisCount,
expectedCoordinates);
final Point mergePoint = geometryFactory.point(mergeX, mergeY);
final LineString mergedLine = line1.merge(mergePoint, line2);
TestUtil.assertEqualsExact(axisCount, expectedMergedLine, mergedLine);
if (!loop) {
final LineString mergedLine2 = line1.merge(line2);
TestUtil.assertEqualsExact(axisCount, expectedMergedLine, mergedLine2);
}
}
public static void assertSplit(final boolean testLineStringLocation, final LineString line,
final Point splitPoint, final LineString... splitLines) {
final GeometryFactory geometryFactory = line.getGeometryFactory();
final int axisCount = geometryFactory.getAxisCount();
{
final List<LineString> actualSplitLines = line.split(splitPoint);
final int splitCount = splitLines.length;
Assert.assertEquals("Split Count", splitCount, actualSplitLines.size());
for (int i = 0; i < splitLines.length; i++) {
final LineString expectedSplitLine = splitLines[i];
final LineString actualSplitLine = actualSplitLines.get(i);
TestUtil.assertEqualsExact(axisCount, expectedSplitLine, actualSplitLine);
}
}
if (testLineStringLocation) {
final double x = splitPoint.getX();
final double y = splitPoint.getY();
final LineStringLocation location = line.getLineStringLocation(x, y);
final List<LineString> actualSplitLines = line.split(location);
final int splitCount = splitLines.length;
Assert.assertEquals("Split Count", splitCount, actualSplitLines.size());
for (int i = 0; i < splitLines.length; i++) {
final LineString expectedSplitLine = splitLines[i];
final LineString actualSplitLine = actualSplitLines.get(i);
TestUtil.assertEqualsExact(axisCount, expectedSplitLine, actualSplitLine);
}
}
}
private void assertEquals(final double[] coordinates, final double[] coordinatesLessNaN,
final Point pointCoordinatesListAllAxis, final Point pointCoordinatesListExtraAxis,
final Point pointCoordinatesListLessAxis) {
assertEquals(pointCoordinatesListAllAxis, coordinates);
assertEquals(pointCoordinatesListExtraAxis, coordinates);
assertEquals(pointCoordinatesListLessAxis, coordinatesLessNaN);
}
private void assertObjectContsructor(final GeometryFactory geometryFactory,
final double[] coordinates, final double[] coordinatesLessNaN, final Point pointAll,
final Point pointExtra, final Point pointLess) {
final Point pointAllAxis = geometryFactory.point((Object)pointAll);
final Point pointExtraAxis = geometryFactory.point((Object)pointExtra);
final Point pointLessAxis = geometryFactory.point((Object)pointLess);
assertEquals(coordinates, coordinatesLessNaN, pointAllAxis, pointExtraAxis, pointLessAxis);
}
@Test
public void constructEmpty() {
for (int axisCount = 2; axisCount < 4; axisCount++) {
final GeometryFactory geometryFactory = GeometryFactory.fixed(26910, axisCount,
GeometryFactory.newScalesFixed(axisCount, 1000.0));
// Empty Constructor
final LineString pointEmpty = geometryFactory.lineString();
assertEmpty(pointEmpty);
// Point[] Constructor
final LineString pointCoordinatesArrayNull = geometryFactory.lineString((Point[])null);
assertEmpty(pointCoordinatesArrayNull);
final LineString pointCoordinatesArraySize0 = geometryFactory.lineString(new Point[0]);
assertEmpty(pointCoordinatesArraySize0);
final LineString pointCoordinatesNull = geometryFactory.lineString((Point)null);
assertEmpty(pointCoordinatesNull);
// LineString Constructor
final LineString pointCoordinatesListNull = geometryFactory.lineString((LineString)null);
assertEmpty(pointCoordinatesListNull);
final LineString pointCoordinatesListSize0 = geometryFactory
.lineString(geometryFactory.lineString());
assertEmpty(pointCoordinatesListSize0);
// double[] Constructor
final LineString pointDoubleArray0Null = geometryFactory.lineString(0, (double[])null);
assertEmpty(pointDoubleArray0Null);
final LineString pointDoubleArray2Null = geometryFactory.lineString(2, (double[])null);
assertEmpty(pointDoubleArray2Null);
final LineString pointDoubleArray0NoValue = geometryFactory.lineString(0);
assertEmpty(pointDoubleArray0NoValue);
final LineString pointDoubleArray2NoValue = geometryFactory.lineString(2);
assertEmpty(pointDoubleArray2NoValue);
// LineString Constructor
final LineString pointLineStringNull = geometryFactory.lineString((LineString)null);
assertEmpty(pointLineStringNull);
}
}
@Test
public void constructLineString() {
for (int axisCount = 2; axisCount < 4; axisCount++) {
int axisCountLess = axisCount;
if (axisCountLess > 2) {
axisCountLess--;
}
final GeometryFactory geometryFactory = GeometryFactory.fixed(26910, axisCount,
GeometryFactory.newScalesFixed(axisCount, 1000.0));
final GeometryFactory geometryFactoryExtra = GeometryFactory.floating(26910, axisCount + 1);
final GeometryFactory geometryFactoryLess = GeometryFactory.floating(26910, axisCountLess);
final double[] coordinatesExtra = new double[axisCount + 1];
final double[] coordinates = new double[axisCount];
final double[] coordinatesLess = new double[axisCountLess];
final double[] coordinatesLessNaN = new double[axisCount];
for (int i = 0; i < axisCount; i++) {
double value;
switch (i) {
case 0:
value = START_X;
break;
case 1:
value = START_Y;
break;
default:
value = i * 10 + i;
}
coordinates[i] = value;
coordinatesExtra[i] = value;
coordinatesLessNaN[i] = value;
if (i < axisCountLess) {
coordinatesLess[i] = value;
} else {
coordinatesLessNaN[i] = Double.NaN;
}
}
coordinatesExtra[coordinatesExtra.length - 1] = 6;
// double[]
final Point pointDoubleAllAxis = geometryFactory.point(coordinates);
final Point pointDoubleExtraAxis = geometryFactory.point(coordinatesExtra);
final Point pointDoubleLessAxis = geometryFactory.point(coordinatesLess);
assertEquals(coordinates, coordinatesLessNaN, pointDoubleAllAxis, pointDoubleExtraAxis,
pointDoubleLessAxis);
assertObjectContsructor(geometryFactory, coordinates, coordinatesLessNaN, pointDoubleAllAxis,
pointDoubleExtraAxis, pointDoubleLessAxis);
// Coordinates
final Point pointCoordinatesAllAxis = geometryFactory.point(new PointDouble(coordinates));
final Point pointCoordinatesExtraAxis = geometryFactory
.point(new PointDouble(coordinatesExtra));
final Point pointCoordinatesLessAxis = geometryFactory
.point(new PointDouble(coordinatesLess));
assertEquals(coordinates, coordinatesLessNaN, pointCoordinatesAllAxis,
pointCoordinatesExtraAxis, pointCoordinatesLessAxis);
assertObjectContsructor(geometryFactory, coordinates, coordinatesLessNaN,
pointCoordinatesAllAxis, pointCoordinatesExtraAxis, pointCoordinatesLessAxis);
// Object Point
final Point pointAll = pointDoubleAllAxis;
final Point pointExtra = geometryFactoryExtra.point(coordinatesExtra);
final Point pointLess = geometryFactoryLess.point(coordinatesLess);
assertObjectContsructor(geometryFactory, coordinates, coordinatesLessNaN, pointAll,
pointExtra, pointLess);
}
}
@Test
public void testDistanceAlong() {
final double[] horizontal1 = new double[] {
0, 0, //
1, 0
};
// Diagonal
final double[] diagonal = new double[] {
1, 1, //
2, 2
};
assertDistanceAlong(0, 0, 0, 0, null, horizontal1);
assertDistanceAlong(1, 0, 1, 0, null, horizontal1);
assertDistanceAlong(0.5, 0, 0.5, 0, null, horizontal1);
// Before
assertDistanceAlong(-0.5, 0.5, -0.5, 0, Side.ON, horizontal1);
assertDistanceAlong(-0.5, 0.5099019513592785, -0.5, 0.1, Side.LEFT, horizontal1);
assertDistanceAlong(-1.4142135623730951, 1.4142135623730951, 0.0, 0.0, Side.ON, diagonal);
// Above
assertDistanceAlong(0.5, 1, 0.5, 1, Side.LEFT, horizontal1);
// After
assertDistanceAlong(1.5, 0.5, 1.5, 0, Side.ON, horizontal1);
assertDistanceAlong(2.8284271247461903, 1.4142135623730951, 3.0, 3.0, Side.ON, diagonal);
// Right angle
final double[] rightAngle1 = new double[] {
0, 1, //
1, 1, //
1, 0
};
assertDistanceAlong(1, 0.7071067811865476, 1.5, 1.5, Side.LEFT, rightAngle1);
assertDistanceAlong(1, 0.5, 1.0, 1.5, Side.LEFT, rightAngle1);
assertDistanceAlong(1, 0.5, 1.5, 1.0, Side.LEFT, rightAngle1);
}
@Test
public void testFromFile() {
TestUtil.doTestGeometry(getClass(), "LineString.csv");
}
@Test
public void testMerge() {
final GeometryFactory geometryFactory = GeometryFactory.fixed(26910, 3, 1.0, 1.0, 1.0);
// Last point is duplicated
final LineString line1 = geometryFactory.lineString(3, START_X, START_Y, 0, START_X + 100,
START_Y + 100, 1, START_X + 200, START_Y + 200, 2, START_X + 300, START_Y + 300, 3,
START_X + 300, START_Y + 300, 3);
final LineString line1Reverse = line1.reverse();
// Every point is duplicated
final LineString line2 = geometryFactory.lineString(3, START_X + 300, START_Y + 300, 3,
START_X + 300, START_Y + 300, 3, START_X + 400, START_Y + 400, 4, START_X + 400,
START_Y + 400, 4, START_X + 500, START_Y + 500, 5, START_X + 500, START_Y + 500, 5);
final LineString line2Reverse = line2.reverse();
// Line to make a loop
final LineString line3 = geometryFactory.lineString(3, START_X + 300, START_Y + 300, 3, START_X,
START_Y, 0);
final LineString line3Reverse = line3.reverse();
// Forwards, Forwards
assertMerge(false, line1, line2, START_X + 300, START_Y + 300, START_X, START_Y, 0,
START_X + 100, START_Y + 100, 1, START_X + 200, START_Y + 200, 2, START_X + 300,
START_Y + 300, 3, START_X + 400, START_Y + 400, 4, START_X + 500, START_Y + 500, 5);
// Forwards, Reverse
assertMerge(false, line1, line2Reverse, START_X + 300, START_Y + 300, START_X, START_Y, 0,
START_X + 100, START_Y + 100, 1, START_X + 200, START_Y + 200, 2, START_X + 300,
START_Y + 300, 3, START_X + 400, START_Y + 400, 4, START_X + 500, START_Y + 500, 5);
// Reverse, Forwards
assertMerge(false, line1Reverse, line2, START_X + 300, START_Y + 300, START_X + 500,
START_Y + 500, 5, START_X + 400, START_Y + 400, 4, START_X + 300, START_Y + 300, 3,
START_X + 200, START_Y + 200, 2, START_X + 100, START_Y + 100, 1, START_X, START_Y, 0);
// Reverse, Reverse
assertMerge(false, line1Reverse, line2Reverse, START_X + 300, START_Y + 300, START_X + 500,
START_Y + 500, 5, START_X + 400, START_Y + 400, 4, START_X + 300, START_Y + 300, 3,
START_X + 200, START_Y + 200, 2, START_X + 100, START_Y + 100, 1, START_X, START_Y, 0);
// Loop Forwards, Forwards
assertMerge(true, line1, line3, START_X + 300, START_Y + 300, START_X, START_Y, 0,
START_X + 100, START_Y + 100, 1, START_X + 200, START_Y + 200, 2, START_X + 300,
START_Y + 300, 3, START_X, START_Y, 0);
// Loop Forwards, Reverse
assertMerge(true, line1, line3Reverse, START_X + 300, START_Y + 300, START_X, START_Y, 0,
START_X + 100, START_Y + 100, 1, START_X + 200, START_Y + 200, 2, START_X + 300,
START_Y + 300, 3, START_X, START_Y, 0);
// Loop Reverse, Forwards
assertMerge(true, line1Reverse, line3, START_X + 300, START_Y + 300, START_X, START_Y, 0,
START_X + 300, START_Y + 300, 3, START_X + 200, START_Y + 200, 2, START_X + 100,
START_Y + 100, 1, START_X, START_Y, 0);
// Loop Reverse, Reverse
assertMerge(true, line1Reverse, line3Reverse, START_X + 300, START_Y + 300, START_X, START_Y, 0,
START_X + 300, START_Y + 300, 3, START_X + 200, START_Y + 200, 2, START_X + 100,
START_Y + 100, 1, START_X, START_Y, 0);
}
@Test
public void testSplit() {
final GeometryFactory geometryFactory = GeometryFactory.fixed(26910, 3, 1000.0, 1000.0, 1.0);
// Last point is duplicated
final LineString line = geometryFactory.lineString(3, START_X, START_Y, 0, START_X + 100,
START_Y + 100, 1, START_X + 200, START_Y + 100, 2, START_X + 100, START_Y, 3);
// From vertex
assertSplit(true, line, geometryFactory.point(START_X, START_Y), line);
// To vertex
assertSplit(true, line, geometryFactory.point(START_X + 100, START_Y), line);
// Middle vertex
final LineString lineVertexMiddle1 = geometryFactory.lineString(3, START_X, START_Y, 0,
START_X + 100, START_Y + 100, 1);
final LineString lineVertexMiddle2 = geometryFactory.lineString(3, START_X + 100, START_Y + 100,
1, START_X + 200, START_Y + 100, 2, START_X + 100, START_Y, 3);
assertSplit(true, line, geometryFactory.point(START_X + 100, START_Y + 100), lineVertexMiddle1,
lineVertexMiddle2);
// Middle vertex
final LineString lineVertexClose1 = geometryFactory.lineString(3, START_X, START_Y, 0,
START_X + 100, START_Y + 100, 1, START_X + 99.999, START_Y + 100.001, 1);
final LineString lineVertexClose2 = geometryFactory.lineString(3, START_X + 99.999,
START_Y + 100.001, 1, START_X + 100, START_Y + 100, 1, START_X + 200, START_Y + 100, 2,
START_X + 100, START_Y, 3);
assertSplit(false, line, geometryFactory.point(START_X + 99.999, START_Y + 100.001, 1),
lineVertexClose1, lineVertexClose2);
// Middle of first segment
for (final double offset : new double[] {
0.001, 50, 99.999
}) {
final double x = START_X + offset;
final double y = START_Y + offset;
final LineString lineSegmentFirst1 = geometryFactory.lineString(3, START_X, START_Y, 0, x, y,
offset);
final LineString lineSegmentFirst2 = geometryFactory.lineString(3, x, y, offset,
START_X + 100, START_Y + 100, 1, START_X + 200, START_Y + 100, 2, START_X + 100, START_Y,
3);
final Point splitPoint = geometryFactory.point(x, y, offset);
assertSplit(false, line, splitPoint, lineSegmentFirst1, lineSegmentFirst2);
}
}
@Test
public void testSubLine() {
final GeometryFactory geometryFactory = GeometryFactory.wgs84();
final LineString line = geometryFactory.lineString(2, 0.0, 0, 2, 2, 3, 3, 4, 4, 5, 5);
assertEmpty(line.subLine(0));
TestUtil.equalsExact(2, line.subLine(2), geometryFactory.lineString(2, 0.0, 0, 2, 2));
TestUtil.equalsExact(2, line.subLine(2, geometryFactory.point(10, 10)),
geometryFactory.lineString(2, 0.0, 0, 2, 2, 10, 10));
TestUtil.equalsExact(2,
line.subLine(geometryFactory.point(-1, -1), 0, 2, geometryFactory.point(10, 10)),
geometryFactory.lineString(2, -1.0, -1.0, 0.0, 0, 2, 2, 10, 10));
final LineString actualFromToIndexMaxLength = line.subLine(geometryFactory.point(-1, -1), 3, 3,
geometryFactory.point(10, 10));
final LineString expectedFromToIndexMaxLength = geometryFactory.lineString(2, -1.0, -1.0, 4, 4,
5, 5, 10, 10);
TestUtil.equalsExact(2, actualFromToIndexMaxLength, expectedFromToIndexMaxLength);
}
@Test
public void testSubLineLocation() {
final GeometryFactory geometryFactory = GeometryFactory.wgs84();
final LineString line = geometryFactory.lineString(2, 0.0, 0, 2, 2, 3, 3, 4, 4, 5, 5);
TestUtil.equalsExact(//
2, //
line.subLine(null, null), //
line//
);
TestUtil.equalsExact(2, //
line.subLine(null, line.getLineStringLocation(2, 2)), //
geometryFactory.lineString(2, 0.0, 0, 2, 2)//
);
TestUtil.equalsExact(2, //
line.subLine(line.getLineStringLocation(2, 2), null), //
geometryFactory.lineString(2, 2.0, 2, 3, 3, 4, 4, 5, 5)//
);
TestUtil.equalsExact(2, //
line.subLine(//
line.getLineStringLocation(2, 2), //
line.getLineStringLocation(3, 3)//
), //
geometryFactory.lineString(2, 2.0, 2, 3, 3)//
);
TestUtil.equalsExact(2, //
line.subLine(//
line.getLineStringLocation(1, 1), //
line.getLineStringLocation(3, 3)//
), //
geometryFactory.lineString(2, 1.0, 1, 2, 2, 3, 3)//
);
TestUtil.equalsExact(2, //
line.subLine(//
line.getLineStringLocation(1, 1), //
line.getLineStringLocation(3.5, 3.5)//
), //
geometryFactory.lineString(2, 1.0, 1, 2, 2, 3, 3, 3.5, 3.5)//
);
TestUtil.equalsExact(2, //
line.subLine(//
line.getLineStringLocation(2, 2), //
line.getLineStringLocation(2, 2)), //
geometryFactory.lineString()//
);
}
}