diff --git a/include/geos/algorithm/LineIntersector.h b/include/geos/algorithm/LineIntersector.h
index e4a5c010db..958dbbf128 100644
--- a/include/geos/algorithm/LineIntersector.h
+++ b/include/geos/algorithm/LineIntersector.h
@@ -134,17 +134,6 @@ class GEOS_DLL LineIntersector {
precisionModel = newPM;
}
- /// Compute the intersection of a point p and the line p1-p2.
- ///
- /// This function computes the boolean value of the hasIntersection test.
- /// The actual value of the intersection (if there is one)
- /// is equal to the value of p.
- ///
- void computeIntersection(const geom::CoordinateXY& p, const geom::CoordinateXY& p1, const geom::CoordinateXY& p2);
-
- /// Same as above but doesn't compute intersection point. Faster.
- static bool hasIntersection(const geom::CoordinateXY& p, const geom::CoordinateXY& p1, const geom::CoordinateXY& p2);
-
enum intersection_type : uint8_t {
/// Indicates that line segments do not intersect
NO_INTERSECTION = 0,
diff --git a/include/geos/algorithm/PointLocation.h b/include/geos/algorithm/PointLocation.h
index b68010df65..e7c7f6acf7 100644
--- a/include/geos/algorithm/PointLocation.h
+++ b/include/geos/algorithm/PointLocation.h
@@ -36,6 +36,16 @@ namespace algorithm { // geos::algorithm
class GEOS_DLL PointLocation {
public:
+ /** \brief
+ * Tests whether a point lies on a line segment.
+ *
+ * @param p the point to test
+ * @param p0 a point of the line segment
+ * @param p1 a point of the line segment
+ * @return true if the point lies on the line segment
+ */
+ static bool isOnSegment(const geom::CoordinateXY& p, const geom::CoordinateXY& p0, const geom::CoordinateXY& p1);
+
/** \brief
* Tests whether a point lies on the line defined by a
* [CoordinateSequence](@ref geom::CoordinateSequence).
diff --git a/src/algorithm/LineIntersector.cpp b/src/algorithm/LineIntersector.cpp
index 61ae787d5e..b3901b9b3d 100644
--- a/src/algorithm/LineIntersector.cpp
+++ b/src/algorithm/LineIntersector.cpp
@@ -212,40 +212,6 @@ LineIntersector::computeIntersection(const CoordinateSequence& p, std::size_t p0
CoordinateSequences::binaryDispatch(p, q, dis);
}
-/*public*/
-void
-LineIntersector::computeIntersection(const CoordinateXY& p, const CoordinateXY& p1, const CoordinateXY& p2)
-{
- isProperVar = false;
-
- // do between check first, since it is faster than the orientation test
- if(Envelope::intersects(p1, p2, p)) {
- if((Orientation::index(p1, p2, p) == 0) &&
- (Orientation::index(p2, p1, p) == 0)) {
- isProperVar = true;
- if((p == p1) || (p == p2)) { // 2d only test
- isProperVar = false;
- }
- result = POINT_INTERSECTION;
- return;
- }
- }
- result = NO_INTERSECTION;
-}
-
-/* public static */
-bool
-LineIntersector::hasIntersection(const CoordinateXY& p, const CoordinateXY& p1, const CoordinateXY& p2)
-{
- if(Envelope::intersects(p1, p2, p)) {
- if((Orientation::index(p1, p2, p) == 0) &&
- (Orientation::index(p2, p1, p) == 0)) {
- return true;
- }
- }
- return false;
-}
-
/* private static */
const CoordinateXY&
LineIntersector::nearestEndpoint(const CoordinateXY& p1, const CoordinateXY& p2,
diff --git a/src/algorithm/PointLocation.cpp b/src/algorithm/PointLocation.cpp
index 5ceb6bd53e..5ad430045a 100644
--- a/src/algorithm/PointLocation.cpp
+++ b/src/algorithm/PointLocation.cpp
@@ -20,16 +20,32 @@
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
#include
namespace geos {
namespace algorithm { // geos.algorithm
+/* public static */
+bool
+PointLocation::isOnSegment(const geom::CoordinateXY& p, const geom::CoordinateXY& p0, const geom::CoordinateXY& p1)
+{
+ //-- test envelope first since it's faster
+ if (! geom::Envelope::intersects(p0, p1, p))
+ return false;
+ //-- handle zero-length segments
+ if (p.equals2D(p0))
+ return true;
+ bool isOnLine = Orientation::COLLINEAR == Orientation::index(p0, p1, p);
+ return isOnLine;
+}
+
/* public static */
bool
PointLocation::isOnLine(const geom::CoordinateXY& p, const geom::CoordinateSequence* pt)
@@ -42,7 +58,7 @@ PointLocation::isOnLine(const geom::CoordinateXY& p, const geom::CoordinateSeque
const geom::CoordinateXY* pp = &(pt->getAt(0));
for(std::size_t i = 1; i < ptsize; ++i) {
const geom::CoordinateXY& p1 = pt->getAt(i);
- if(LineIntersector::hasIntersection(p, *pp, p1)) {
+ if(isOnSegment(p, *pp, p1)) {
return true;
}
pp = &p1;
diff --git a/src/operation/valid/PolygonTopologyAnalyzer.cpp b/src/operation/valid/PolygonTopologyAnalyzer.cpp
index 39b672b1d8..c2b9d0a390 100644
--- a/src/operation/valid/PolygonTopologyAnalyzer.cpp
+++ b/src/operation/valid/PolygonTopologyAnalyzer.cpp
@@ -180,8 +180,7 @@ PolygonTopologyAnalyzer::intersectingSegIndex(const CoordinateSequence* ringPts,
{
algorithm::LineIntersector li;
for (std::size_t i = 0; i < ringPts->size() - 1; i++) {
- li.computeIntersection(*pt, ringPts->getAt(i), ringPts->getAt(i+1));
- if (li.hasIntersection()) {
+ if ( algorithm::PointLocation::isOnSegment(*pt, ringPts->getAt(i), ringPts->getAt(i+1)) ) {
//-- check if pt is the start point of the next segment
if (pt->equals2D(ringPts->getAt(i + 1))) {
return i + 1;
diff --git a/tests/unit/algorithm/PointLocationTest.cpp b/tests/unit/algorithm/PointLocationTest.cpp
new file mode 100644
index 0000000000..bed1a1b0bc
--- /dev/null
+++ b/tests/unit/algorithm/PointLocationTest.cpp
@@ -0,0 +1,129 @@
+//
+// Test Suite for geos::algorithm::PointLocation
+// Ported from JTS junit/algorithm/PointLocationTest.java
+
+#include
+#include
+
+// geos
+#include
+#include
+
+// std
+#include
+#include
+#include
+
+using geos::algorithm::PointLocation;
+using geos::geom::CoordinateXY;
+
+namespace tut {
+//
+// Test Group
+//
+
+// dummy data, not used
+struct test_PointLocation_data {
+
+ geos::io::WKTReader r_;
+
+ void
+ checkOnLine(double x, double y, const std::string& wktLine, bool isExpected)
+ {
+ CoordinateXY p(x, y);
+ std::unique_ptr line = readPts(wktLine);
+ bool isOnLine = PointLocation::isOnLine(p, line.get());
+ ensure(isOnLine == isExpected);
+ }
+
+ void
+ checkOnSegment(double x, double y, const std::string& wktLine, bool isExpected)
+ {
+ CoordinateXY p(x, y);
+ std::unique_ptr line = readPts(wktLine);
+
+ bool isOnSeg = PointLocation::isOnSegment(p, line->getAt(0), line->getAt(1));
+ ensure(isOnSeg == isExpected);
+ }
+
+ std::unique_ptr
+ readPts(const std::string& wkt)
+ {
+ std::unique_ptr geom = r_.read(wkt);
+ const LineString* line = dynamic_cast(geom.get());
+ if (line)
+ return line->getCoordinatesRO()->clone();
+ else
+ return nullptr;
+ }
+
+};
+
+
+typedef test_group group;
+typedef group::object object;
+
+group test_PointLocation_data("geos::algorithm::PointLocation");
+
+
+//
+// Test Cases
+//
+
+// testOnLineOnVertex
+template<>
+template<>
+void object::test<1> ()
+{
+ checkOnLine(20, 20, "LINESTRING (0 00, 20 20, 30 30)", true);
+}
+
+// testOnLineInSegment
+template<>
+template<>
+void object::test<2> ()
+{
+ checkOnLine(10, 10, "LINESTRING (0 0, 20 20, 0 40)", true);
+ checkOnLine(10, 30, "LINESTRING (0 0, 20 20, 0 40)", true);
+}
+
+// testNotOnLine
+template<>
+template<>
+void object::test<3> ()
+{
+ checkOnLine(0, 100, "LINESTRING (10 10, 20 10, 30 10)", false);
+}
+
+// testOnSegment
+template<>
+template<>
+void object::test<4> ()
+{
+ checkOnSegment(5, 5, "LINESTRING(0 0, 9 9)", true);
+ checkOnSegment(0, 0, "LINESTRING(0 0, 9 9)", true);
+ checkOnSegment(9, 9, "LINESTRING(0 0, 9 9)", true);
+}
+
+// testNotOnSegment
+template<>
+template<>
+void object::test<5> ()
+{
+ checkOnSegment(5, 6, "LINESTRING(0 0, 9 9)", false);
+ checkOnSegment(10, 10, "LINESTRING(0 0, 9 9)", false);
+ checkOnSegment(9, 9.00001, "LINESTRING(0 0, 9 9)", false);
+}
+
+// testOnZeroLengthSegment
+template<>
+template<>
+void object::test<6> ()
+{
+ checkOnSegment(1, 1, "LINESTRING(1 1, 1 1)", true);
+ checkOnSegment(1, 2, "LINESTRING(1 1, 1 1)", false);
+}
+
+
+} // namespace tut
+