Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,25 @@ public static Geometry reflectPoint(Geometry g1, Geometry g2)
return g1.getFactory().createPoint(reflectPt);
}

public static Geometry project(Geometry g1, Geometry g2)
{
LineSegment seg1 = toLineSegment(g1);
Coordinate[] line2 = g2.getCoordinates();
if (line2.length == 1) {
Coordinate pt = line2[0];
Coordinate result = seg1.project(pt);
return g1.getFactory().createPoint(result);
}
LineSegment seg2 = new LineSegment(line2[0], line2[1]);
LineSegment result = seg1.project(seg2);
if (result == null)
return g1.getFactory().createLineString();
return result.toGeometry(g1.getFactory());
}

private static LineSegment toLineSegment(Geometry g) {
Coordinate[] line = g.getCoordinates();
return new LineSegment(line[0], line[1]);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -468,16 +468,30 @@ public LineSegment project(LineSegment seg)
double pf0 = projectionFactor(seg.p0);
double pf1 = projectionFactor(seg.p1);
// check if segment projects at all
if (pf0 >= 1.0 && pf1 >= 1.0) return null;
if (pf0 <= 0.0 && pf1 <= 0.0) return null;
if (pf0 > 1.0 && pf1 > 1.0) return null;
if (pf0 < 0.0 && pf1 < 0.0) return null;

Coordinate newp0 = project(seg.p0, pf0);
if (pf0 < 0.0) newp0 = p0;
if (pf0 > 1.0) newp0 = p1;
Coordinate newp0;
if (pf0 < 0.0) {
newp0 = p0;
}
else if (pf0 > 1.0) {
newp0 = p1;
}
else {
newp0 = project(seg.p0, pf0);
}

Coordinate newp1 = project(seg.p1, pf1);
if (pf1 < 0.0) newp1 = p0;
if (pf1 > 1.0) newp1 = p1;
Coordinate newp1;
if (pf1 < 0.0) {
newp1 = p0;
}
else if (pf1 > 1.0) {
newp1 = p1;
}
else {
newp1 = project(seg.p1, pf1);
}

return new LineSegment(newp0, newp1);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@
*/
package org.locationtech.jts.geom;

import junit.framework.TestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import junit.textui.TestRunner;
import test.jts.GeometryTestCase;


/**
* Test LineSegment methods
*/
public class LineSegmentTest extends TestCase {
public class LineSegmentTest extends GeometryTestCase {

public static void main(String args[]) {
TestRunner.run(LineSegmentTest.class);
Expand Down Expand Up @@ -53,6 +56,60 @@ public void testProjectionFactor()
assertTrue(seg2.projectionFactor(new Coordinate(11, 0)) == 0.1);
}

public void testProjectPoint() {
//-- interior point
checkProjectPoint("LINESTRING (4 0, 8 0)", "POINT (5 2)", 5, 0);
//-- endpoint
checkProjectPoint("LINESTRING (4 0, 8 0)", "POINT (8 2)", 8, 0);
//-- beyond end
checkProjectPoint("LINESTRING (4 0, 8 0)", "POINT (9 2)", 9, 0);
//-- before end
checkProjectPoint("LINESTRING (4 0, 8 0)", "POINT (3 2)", 3, 0);
//-- collinear
checkProjectPoint("LINESTRING (4 0, 8 0)", "POINT (2 0)", 2, 0);
}

private void checkProjectPoint(String wkt1, String wkt2, double x, double y) {
LineSegment seg1 = readLineSegment(wkt1);
Point pt = (Point) read(wkt2);
Coordinate p = pt.getCoordinate();
Coordinate actual = seg1.project(p);

checkEqualXY(new Coordinate(x, y), actual, 0.0001);
}

public void testProjectSegment() {
//-- project onto interior segment
checkProjectSegment("LINESTRING (0 0, 8 0)", "LINESTRING (1 2, 2 3)", "LINESTRING(1 0, 2 0)");
//-- project onto interior point
checkProjectSegment("LINESTRING (0 0, 8 0)", "LINESTRING (1 2, 1 4)", "LINESTRING(1 0, 1 0)");
//-- projection includes endpoint
checkProjectSegment("LINESTRING (0 0, 8 0)", "LINESTRING (0 2, 1 4)", "LINESTRING(0 0, 1 0)");
//- projection onto endpoint
checkProjectSegment("LINESTRING (0 0, 8 0)", "LINESTRING (8 2, 8 4)", "LINESTRING(8 0, 8 0)");
checkProjectSegment("LINESTRING (0 0, 8 0)", "LINESTRING (0 2, 0 4)", "LINESTRING(0 0, 0 0)");
checkProjectSegment("LINESTRING (0 0, 8 0)", "LINESTRING (0 2, -1 4)", "LINESTRING(0 0, 0 0)");
checkProjectSegment("LINESTRING (0 0, 8 0)", "LINESTRING (9 1, 8 0)", "LINESTRING(8 0, 8 0)");
checkProjectSegment("LINESTRING (0 0, 8 0)", "LINESTRING (9 1, 8 1)", "LINESTRING(8 0, 8 0)");
//-- no projection
checkProjectSegment("LINESTRING (0 0, 8 0)", "LINESTRING (9 1, 9 2)", null);
}

private void checkProjectSegment(String wkt1, String wkt2, String wktExpected) {
LineSegment seg1 = readLineSegment(wkt1);
LineSegment seg2 = readLineSegment(wkt2);
LineSegment actual = seg1.project(seg2);

LineSegment expected = wktExpected == null ? null : readLineSegment(wktExpected);
checkEqual(expected, actual, 0.0001);
}

private LineSegment readLineSegment(String wkt) {
Geometry g = read(wkt);
LineString line = (LineString) g;
return new LineSegment(line.getCoordinateN(0), line.getCoordinateN(1));
}

public void testLineIntersection() {
// simple case
checkLineIntersection(
Expand Down
22 changes: 21 additions & 1 deletion modules/core/src/test/java/test/jts/GeometryTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,27 @@ protected void checkEqualXY(String message, Coordinate expected, Coordinate actu
assertEquals(message + " X", expected.getX(), actual.getX(), tolerance);
assertEquals(message + " Y", expected.getY(), actual.getY(), tolerance);
}


protected void checkEqual(LineSegment expected, LineSegment actual, double tolerance) {
boolean equal;
if (actual == null || expected == null) {
equal = actual == null && expected == null;
}
else {
equal = isEqual(actual, expected, tolerance);
}
if (! equal) {
System.out.format(CHECK_EQUAL_FAIL_MSG, expected, actual );
}
assertTrue(equal);
}

private boolean isEqual(LineSegment actual, LineSegment expected, double tolerance) {
return expected.getCoordinate(0).equals2D(actual.getCoordinate(0), tolerance)
&& expected.getCoordinate(1).equals2D(actual.getCoordinate(1), tolerance);

}

protected void checkNoAlias(Geometry geom, Geometry geom2) {
Geometry geom2Copy = geom2.copy();
geom.apply(new CoordinateFilter() {
Expand Down