Skip to content

Commit

Permalink
Port TopologyPreservingSimplifier fixes (libgeosGH-986, libgeosGH-1107,
Browse files Browse the repository at this point in the history
  • Loading branch information
pramsey committed Oct 22, 2024
1 parent d6d727e commit e4a2762
Show file tree
Hide file tree
Showing 12 changed files with 949 additions and 387 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Centroid: Fix crash on polygons with empty holes (GH-1075, Dan Baston)
- MinimumClearance: Fix crash on NaN inputs (GH-1082, Dan Baston)
- GEOSRelatePatternMatch: Fix crash on invalid DE-9IM pattern (GH-1089, Dan Baston)
- Port TopologyPreservingSimplifier fixes (GH-986, GH-1107, GH-857, GH-784, GH-1070, Paul Ramsey)

## Changes in 3.11.4
2024-06-05
Expand Down
4 changes: 3 additions & 1 deletion include/geos/algorithm/RayCrossingCounter.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class GEOS_DLL RayCrossingCounter {
private:
const geom::Coordinate& point;

int crossingCount;
std::size_t crossingCount;

// true if the test point lies on an input segment
bool isPointOnSegment;
Expand Down Expand Up @@ -144,6 +144,8 @@ class GEOS_DLL RayCrossingCounter {
*/
bool isPointInPolygon() const;

std::size_t getCount() const { return crossingCount; };

};

} // geos::algorithm
Expand Down
120 changes: 120 additions & 0 deletions include/geos/simplify/ComponentJumpChecker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/**********************************************************************
*
* GEOS - Geometry Engine Open Source
* http://libgeos.org
*
* Copyright (C) 2006 Refractions Research Inc.
* Copyright (C) 2023 Martin Davis <[email protected]>
* Copyright (C) 2023 Paul Ramsey <[email protected]>
*
* This is free software; you can redistribute and/or modify it under
* the terms of the GNU Lesser General Licence as published
* by the Free Software Foundation.
* See the COPYING file for more information.
*
**********************************************************************/

#pragma once

#include <geos/export.h>
#include <vector>
#include <memory>


// Forward declarations
namespace geos {
namespace geom {
class Coordinate;
class CoordinateSequence;
class Envelope;
class LineSegment;
}
namespace simplify {
class TaggedLineString;
}
}

using geos::geom::Coordinate;
using geos::geom::Envelope;
using geos::geom::LineSegment;

namespace geos {
namespace simplify { // geos::simplify


class GEOS_DLL ComponentJumpChecker {

private:

const std::vector<TaggedLineString*>& components;

static bool hasJumpAtComponent(
const Coordinate& compPt,
const TaggedLineString* line,
std::size_t start, std::size_t end,
const LineSegment& seg);

static bool hasJumpAtComponent(
const Coordinate& compPt,
const LineSegment* seg1, const LineSegment* seg2,
const LineSegment& seg);

static std::size_t crossingCount(
const Coordinate& compPt,
const LineSegment& seg);

static std::size_t crossingCount(
const Coordinate& compPt,
const LineSegment* seg1, const LineSegment* seg2);

std::size_t static crossingCount(
const Coordinate& compPt,
const TaggedLineString* line,
std::size_t start, std::size_t end);

static Envelope computeEnvelope(
const LineSegment* seg1, const LineSegment* seg2);

static Envelope computeEnvelope(
const TaggedLineString* line,
std::size_t start, std::size_t end);


public:

ComponentJumpChecker(const std::vector<TaggedLineString*>& taggedLines)
: components(taggedLines)
{}

bool hasJump(
const TaggedLineString* line,
std::size_t start, std::size_t end,
const LineSegment& seg) const;

/**
* Checks if two consecutive segments jumps a component if flattened.
* The segments are assumed to be consecutive.
* (so the seg1.p1 = seg2.p0).
* The flattening segment must be the segment between seg1.p0 and seg2.p1.
*
* @param line the line containing the section being flattened
* @param seg1 the first replaced segment
* @param seg2 the next replaced segment
* @param seg the flattening segment
* @return true if the flattened segment jumps a component
*/
bool hasJump(
const TaggedLineString* line,
const LineSegment* seg1,
const LineSegment* seg2,
const LineSegment& seg) const;

};

} // namespace geos::simplify
} // namespace geos





28 changes: 23 additions & 5 deletions include/geos/simplify/TaggedLineString.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ class TaggedLineSegment;
}
}

using geos::geom::Coordinate;
using geos::geom::CoordinateSequence;

namespace geos {
namespace simplify { // geos::simplify

Expand All @@ -58,27 +61,36 @@ class GEOS_DLL TaggedLineString {

public:

typedef std::vector<geom::Coordinate> CoordVect;
typedef std::vector<Coordinate> CoordVect;

typedef std::unique_ptr<CoordVect> CoordVectPtr;

typedef geom::CoordinateSequence CoordSeq;
typedef CoordinateSequence CoordSeq;

typedef std::unique_ptr<geom::CoordinateSequence> CoordSeqPtr;
typedef std::unique_ptr<CoordinateSequence> CoordSeqPtr;

TaggedLineString(const geom::LineString* nParentLine,
std::size_t minimumSize = 2);
std::size_t minimumSize,
bool bIsRing);

~TaggedLineString();

std::size_t getMinimumSize() const;

bool isRing() const;

const geom::LineString* getParent() const;

const CoordSeq* getParentCoordinates() const;

CoordSeqPtr getResultCoordinates() const;

const Coordinate& getCoordinate(std::size_t i) const;

std::size_t size() const;

const Coordinate& getComponentPoint() const;

std::size_t getResultSize() const;

TaggedLineSegment* getSegment(std::size_t i);
Expand All @@ -89,8 +101,12 @@ class GEOS_DLL TaggedLineString {

const std::vector<TaggedLineSegment*>& getSegments() const;

const std::vector<TaggedLineSegment*>& getResultSegments() const;

void addToResult(std::unique_ptr<TaggedLineSegment> seg);

const TaggedLineSegment* removeRingEndpoint();

std::unique_ptr<geom::Geometry> asLineString() const;

std::unique_ptr<geom::Geometry> asLinearRing() const;
Expand All @@ -107,9 +123,11 @@ class GEOS_DLL TaggedLineString {

std::size_t minimumSize;

bool m_isRing;

void init();

static CoordVectPtr extractCoordinates(
static std::unique_ptr<CoordinateSequence> extractCoordinates(
const std::vector<TaggedLineSegment*>& segs);

// Copying is turned off
Expand Down
79 changes: 43 additions & 36 deletions include/geos/simplify/TaggedLineStringSimplifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,22 @@ class LineIntersector;
}
namespace geom {
class CoordinateSequence;
class Coordinate;
class LineSegment;
}
namespace simplify {
class TaggedLineSegment;
class TaggedLineString;
class LineSegmentIndex;
class ComponentJumpChecker;
}
}

using geos::geom::CoordinateSequence;
using geos::geom::Coordinate;
using geos::geom::LineSegment;


namespace geos {
namespace simplify { // geos::simplify

Expand All @@ -64,25 +71,17 @@ class GEOS_DLL TaggedLineStringSimplifier {
public:

TaggedLineStringSimplifier(LineSegmentIndex* inputIndex,
LineSegmentIndex* outputIndex);

/** \brief
* Sets the distance tolerance for the simplification.
*
* All vertices in the simplified geometry will be within this
* distance of the original geometry.
*
* @param d the approximation tolerance to use
*/
void setDistanceTolerance(double d);
LineSegmentIndex* outputIndex,
const ComponentJumpChecker* jumpChecker);

/**
* Simplifies the given {@link TaggedLineString}
* using the distance tolerance specified.
*
* @param line the linestring to simplify
* @param distanceTolerance simplification tolerance
*/
void simplify(TaggedLineString* line);
void simplify(TaggedLineString* line, double distanceTolerance);


private:
Expand All @@ -93,50 +92,63 @@ class GEOS_DLL TaggedLineStringSimplifier {
// externally owned
LineSegmentIndex* outputIndex;

const ComponentJumpChecker* jumpChecker;

std::unique_ptr<algorithm::LineIntersector> li;

/// non-const as segments are possibly added to it
TaggedLineString* line;

const geom::CoordinateSequence* linePts;
const CoordinateSequence* linePts;

double distanceTolerance;
void simplifySection(std::size_t i, std::size_t j, std::size_t depth, double distanceTolerance);

void simplifySection(std::size_t i, std::size_t j,
std::size_t depth);
void simplifyRingEndpoint(double distanceTolerance);

static std::size_t findFurthestPoint(
const geom::CoordinateSequence* pts,
const CoordinateSequence* pts,
std::size_t i, std::size_t j,
double& maxDistance);

bool hasBadIntersection(const TaggedLineString* parentLine,
const std::pair<std::size_t, std::size_t>& sectionIndex,
const geom::LineSegment& candidateSeg);
bool isTopologyValid(
const TaggedLineString* lineIn,
std::size_t sectionStart, std::size_t sectionEnd,
const LineSegment& flatSeg);

bool isTopologyValid(
const TaggedLineString* lineIn,
const LineSegment* seg1, const LineSegment* seg2,
const LineSegment& flatSeg);

bool hasBadInputIntersection(const TaggedLineString* parentLine,
const std::pair<std::size_t, std::size_t>& sectionIndex,
const geom::LineSegment& candidateSeg);
bool hasInputIntersection(const LineSegment& flatSeg);

bool hasBadOutputIntersection(const geom::LineSegment& candidateSeg);
bool hasInputIntersection(
const TaggedLineString* lineIn,
std::size_t excludeStart, std::size_t excludeEnd,
const LineSegment& flatSeg);

bool hasInteriorIntersection(const geom::LineSegment& seg0,
const geom::LineSegment& seg1) const;
bool isCollinear(const Coordinate& pt, const LineSegment& seg) const;

bool hasOutputIntersection(const LineSegment& flatSeg);

bool hasInvalidIntersection(
const LineSegment& seg0,
const LineSegment& seg1) const;

std::unique_ptr<TaggedLineSegment> flatten(
std::size_t start, std::size_t end);

/** \brief
* Tests whether a segment is in a section of a TaggedLineString
*
* @param parentLine
* @param sectionIndex
* @param seg
* @param line line to be checked for the presence of `seg`
* @param sectionIndex start and end indices of the section to check
* @param seg segment to look for in `line`
* @return
*/
static bool isInLineSection(
const TaggedLineString* parentLine,
const std::pair<std::size_t, std::size_t>& sectionIndex,
const TaggedLineString* line,
const std::size_t excludeStart, const std::size_t excludeEnd,
const TaggedLineSegment* seg);

/** \brief
Expand All @@ -152,11 +164,6 @@ class GEOS_DLL TaggedLineStringSimplifier {

};

inline void
TaggedLineStringSimplifier::setDistanceTolerance(double d)
{
distanceTolerance = d;
}

} // namespace geos::simplify
} // namespace geos
Expand Down
Loading

0 comments on commit e4a2762

Please sign in to comment.