Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Adds the package geos::coverage containing classes for operating on Polygonal Coverages.
CoverageValidator determines if a set of polygons forms a valid coverage and identifies locations of invalidity (and optionally narrow gaps)
CoveragePolygonValidator determines if a single polygons forms a valid coverage with adjacent polygons, and identifies locations of invalidity (and optionally narrow gaps)
CoverageGapFinder detects narrow gaps which form holes in a polygonal coverage
CoverageUnion performs an efficient union of a set of polygons which form a coverage
  • Loading branch information
pramsey committed Aug 5, 2022
1 parent ae1b4b7 commit 62c928c
Show file tree
Hide file tree
Showing 34 changed files with 3,267 additions and 135 deletions.
@@ -1,10 +1,10 @@
/**********************************************************************
*
* GEOS - Geometry Engine Open Source
* http://geos.osgeo.org
* http://libgeos.org
*
* Copyright (C) 2021 Paul Ramsey <pramsey@cleverelephant.ca>
* Copyright (C) 2021 Martin Davis
* Copyright (c) 2021 Martin Davis
* Copyright (C) 2022 Paul Ramsey <pramsey@cleverlephant.ca>
*
* This is free software; you can redistribute and/or modify it under
* the terms of the GNU Lesser General Public Licence as published
Expand All @@ -18,21 +18,64 @@
#include <geos/export.h>


#include <memory>

// Forward declarations
namespace geos {
namespace geom {
class Coordinate;
}
}
namespace geos { // geos.
namespace operation { // geos.operation
namespace valid { // geos.operation.valid

using geos::geom::Coordinate;

class GEOS_DLL PolygonNode {

namespace geos {
namespace algorithm { // geos::algorithm

/**
* Functions to compute topological information
* about nodes (ring intersections) in polygonal geometry.
*
* @author mdavis
*
*/
class GEOS_DLL PolygonNodeTopology {

public:

/*
* Check if the segments at a node between two rings (or one ring) cross.
* The node is topologically valid if the rings do not cross.
* This function assumes that the segments are not collinear.
*
* @param nodePt the node location
* @param a0 the previous segment endpoint in a ring
* @param a1 the next segment endpoint in a ring
* @param b0 the previous segment endpoint in the other ring
* @param b1 the next segment endpoint in the other ring
* @return true if the rings cross at the node
*/
static bool
isCrossing(const Coordinate* nodePt,
const Coordinate* a0, const Coordinate* a1,
const Coordinate* b0, const Coordinate* b1);


/**
* Tests whether an segment node-b lies in the interior or exterior
* of a corner of a ring formed by the two segments a0-node-a1.
* The ring interior is assumed to be on the right of the corner
* (i.e. a CW shell or CCW hole).
* The test segment must not be collinear with the corner segments.
*
* @param nodePt the node location
* @param a0 the first vertex of the corner
* @param a1 the second vertex of the corner
* @param b the other vertex of the test segment
* @return true if the segment is interior to the ring corner
*/
static bool isInteriorSegment(const Coordinate* nodePt,
const Coordinate* a0, const Coordinate* a1, const Coordinate* b);


private:

Expand All @@ -48,8 +91,8 @@ class GEOS_DLL PolygonNode {
* @param e1 the destination point of edge e1
* @return true if p is between e0 and e1
*/
static bool
isBetween(const Coordinate* origin, const Coordinate* p,
static bool isBetween(const Coordinate* origin,
const Coordinate* p,
const Coordinate* e0, const Coordinate* e1);

/**
Expand All @@ -61,53 +104,14 @@ class GEOS_DLL PolygonNode {
* @param q the endpoint of the vector Q
* @return true if vector P has angle greater than Q
*/
static bool
isAngleGreater(const Coordinate* origin,
const Coordinate* p, const Coordinate* q);

static int
quadrant(const Coordinate* origin, const Coordinate* p);
static bool isAngleGreater(const Coordinate* origin, const Coordinate* p, const Coordinate* q);

static int quadrant(const Coordinate* origin, const Coordinate* p);

public:

/**
* Check if the edges at a node between two rings (or one ring) cross.
* The node is topologically valid if the ring edges do not cross.
* This function assumes that the edges are not collinear.
*
* @param nodePt the node location
* @param a0 the previous edge endpoint in a ring
* @param a1 the next edge endpoint in a ring
* @param b0 the previous edge endpoint in the other ring
* @param b1 the next edge endpoint in the other ring
* @return true if the edges cross at the node
*/
static bool isCrossing(const Coordinate* nodePt,
const Coordinate* a0, const Coordinate* a1,
const Coordinate* b0, const Coordinate* b1);

/**
* Tests whether an edge node-b lies in the interior or exterior
* of a corner of a ring given by a0-node-a1.
* The ring interior is assumed to be on the right of the corner (a CW ring).
* The edge must not be collinear with the corner segments.
*
* @param nodePt the node location
* @param a0 the first vertex of the corner
* @param a1 the second vertex of the corner
* @param b the destination vertex of the edge
* @return true if the edge is interior to the ring corner
*/
static bool isInteriorSegment(const Coordinate* nodePt,
const Coordinate* a0, const Coordinate* a1,
const Coordinate* b);

};



} // namespace geos.operation.valid
} // namespace geos.operation
} // namespace geos::algorithm
} // namespace geos

106 changes: 106 additions & 0 deletions include/geos/coverage/CoverageGapFinder.h
@@ -0,0 +1,106 @@
/**********************************************************************
*
* GEOS - Geometry Engine Open Source
* http://geos.osgeo.org
*
* Copyright (C) 2022 Paul Ramsey <pramsey@cleverelephant.ca>
*
* This is free software; you can redistribute and/or modify it under
* the terms of the GNU Lesser General Public 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 Geometry;
class LinearRing;
}
}

using geos::geom::Geometry;
using geos::geom::LinearRing;


namespace geos { // geos
namespace coverage { // geos::coverage

/**
* Finds gaps in a polygonal coverage.
* Gaps are holes in the coverage which are narrower than a given width.
*
* The coverage should be valid according to CoverageValidator.
* If this is not the case, some gaps may not be reported, or the invocation may fail.
*
* This is a more accurate way of identifying gaps
* than using CoverageValidator::setGapWidth(double).
* Gaps which separate the coverage into two disjoint regions are not detected.
* Gores are not identified as gaps.
*
* @author mdavis
*
*/
class GEOS_DLL CoverageGapFinder {

private:

std::vector<const Geometry*>& m_coverage;

bool isGap(const LinearRing* hole, double gapWidth);


public:

/**
* Creates a new polygonal coverage gap finder.
*
* @param coverage a set of polygons forming a polygonal coverage
*/
CoverageGapFinder(std::vector<const Geometry*>& coverage)
: m_coverage(coverage)
{};

/**
* Finds gaps in a polygonal coverage.
* Returns lines indicating the locations of the gaps.
*
* @param coverage a set of polygons forming a polygonal coverage
* @param gapWidth the maximum width of gap to detect
* @return a geometry indicating the locations of gaps (which is empty if no gaps were found), or null if the coverage was empty
*/
static std::unique_ptr<Geometry> findGaps(
std::vector<const Geometry*>& coverage,
double gapWidth);

/**
* Finds gaps in the coverage.
* Returns lines indicating the locations of the gaps.
*
* @param gapWidth the maximum width of gap to detect
* @return a geometry indicating the locations of gaps (which is empty if no gaps were found), or null if the coverage was empty
*/
std::unique_ptr<Geometry> findGaps(double gapWidth);


};

} // namespace geos::coverage
} // namespace geos









0 comments on commit 62c928c

Please sign in to comment.