Skip to content

Commit

Permalink
Add PointLocation.isOnSegment, refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-jts committed Apr 23, 2024
1 parent d2c196b commit f63d5d3
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 48 deletions.
11 changes: 0 additions & 11 deletions include/geos/algorithm/LineIntersector.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <code>p</code>.
///
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,
Expand Down
10 changes: 10 additions & 0 deletions include/geos/algorithm/PointLocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
34 changes: 0 additions & 34 deletions src/algorithm/LineIntersector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
18 changes: 17 additions & 1 deletion src/algorithm/PointLocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,32 @@
#include <vector>

#include <geos/algorithm/LineIntersector.h>
#include <geos/algorithm/Orientation.h>
#include <geos/algorithm/PointLocation.h>
#include <geos/algorithm/RayCrossingCounter.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/Envelope.h>
#include <geos/geom/Location.h>
#include <geos/util/IllegalArgumentException.h>

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)
Expand All @@ -42,7 +58,7 @@ PointLocation::isOnLine(const geom::CoordinateXY& p, const geom::CoordinateSeque
const geom::CoordinateXY* pp = &(pt->getAt<geom::CoordinateXY>(0));
for(std::size_t i = 1; i < ptsize; ++i) {
const geom::CoordinateXY& p1 = pt->getAt<geom::CoordinateXY>(i);
if(LineIntersector::hasIntersection(p, *pp, p1)) {
if(isOnSegment(p, *pp, p1)) {
return true;
}
pp = &p1;
Expand Down
3 changes: 1 addition & 2 deletions src/operation/valid/PolygonTopologyAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CoordinateXY>(i), ringPts->getAt<CoordinateXY>(i+1));
if (li.hasIntersection()) {
if ( algorithm::PointLocation::isOnSegment(*pt, ringPts->getAt<CoordinateXY>(i), ringPts->getAt<CoordinateXY>(i+1)) ) {
//-- check if pt is the start point of the next segment
if (pt->equals2D(ringPts->getAt<CoordinateXY>(i + 1))) {
return i + 1;
Expand Down
129 changes: 129 additions & 0 deletions tests/unit/algorithm/PointLocationTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//
// Test Suite for geos::algorithm::PointLocation
// Ported from JTS junit/algorithm/PointLocationTest.java

#include <tut/tut.hpp>
#include <utility.h>

// geos
#include <geos/geom/Coordinate.h>
#include <geos/algorithm/PointLocation.h>

// std
#include <sstream>
#include <string>
#include <memory>

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<CoordinateSequence> 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<CoordinateSequence> line = readPts(wktLine);

bool isOnSeg = PointLocation::isOnSegment(p, line->getAt(0), line->getAt(1));
ensure(isOnSeg == isExpected);
}

std::unique_ptr<CoordinateSequence>
readPts(const std::string& wkt)
{
std::unique_ptr<Geometry> geom = r_.read(wkt);
const LineString* line = dynamic_cast<LineString*>(geom.get());
if (line)
return line->getCoordinatesRO()->clone();
else
return nullptr;
}

};


typedef test_group<test_PointLocation_data> 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

0 comments on commit f63d5d3

Please sign in to comment.