405 lines
10 KiB
C
405 lines
10 KiB
C
|
/**********************************************************************
|
||
|
*
|
||
|
* GEOS - Geometry Engine Open Source
|
||
|
* http://geos.osgeo.org
|
||
|
*
|
||
|
* Copyright (C) 2020 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 <cstdint>
|
||
|
|
||
|
#include <geos/geom/Location.h>
|
||
|
#include <geos/geom/Position.h>
|
||
|
#include <geos/export.h>
|
||
|
|
||
|
using geos::geom::Location;
|
||
|
using geos::geom::Position;
|
||
|
|
||
|
namespace geos { // geos.
|
||
|
namespace operation { // geos.operation
|
||
|
namespace overlayng { // geos.operation.overlayng
|
||
|
|
||
|
/**
|
||
|
* A label for a pair of {@link OverlayEdge}s which records
|
||
|
* the topological information for the edge
|
||
|
* in the {@link OverlayGraph} containing it.
|
||
|
* The label is shared between both OverlayEdges
|
||
|
* of a symmetric pair.
|
||
|
* Accessors for orientation-sensitive information
|
||
|
* require the orientation of the containing OverlayEdge.
|
||
|
*
|
||
|
* A label contains the topological {@link geom::Location}s for
|
||
|
* the two overlay input geometries.
|
||
|
* A labelled input geometry may be either a Line or an Area.
|
||
|
* In both cases, the label locations are populated
|
||
|
* with the locations for the edge {@link geom::Position}s
|
||
|
* once they are computed by topological evaluation.
|
||
|
* The label also records the dimension of each geometry,
|
||
|
* and in the case of area boundary edges, the role
|
||
|
* of the originating ring (which allows
|
||
|
* determination of the edge role in collapse cases).
|
||
|
*
|
||
|
* For each input geometry, the label indicates that an edge
|
||
|
* is in one of the following states (identified by the "dim" field).
|
||
|
* Each state has some additional information about the edge.
|
||
|
*
|
||
|
* * A Boundary edge of an input Area (polygon)
|
||
|
*
|
||
|
* * dim = DIM_BOUNDARY
|
||
|
* * locLeft, locRight : the locations of the edge sides for the input Area
|
||
|
* * isHole : whether the edge was in a shell or a hole
|
||
|
*
|
||
|
* * A Collapsed edge of an input Area
|
||
|
* (which had two or more parent edges)
|
||
|
*
|
||
|
* * dim = DIM_COLLAPSE
|
||
|
* * locLine : the location of the
|
||
|
* edge relative to the input Area
|
||
|
* * isHole : whether some
|
||
|
* contributing edge was in a shell (false),
|
||
|
* or otherwise that all were in holes (true)
|
||
|
*
|
||
|
* * An edge from an input Line
|
||
|
*
|
||
|
* * dim = DIM_LINE
|
||
|
* * locLine : initialized to LOC_UNKNOWN, to simplify logic.
|
||
|
*
|
||
|
* * An edge which is Not Part of an input geometry
|
||
|
* (and thus must be part of the other geometry).
|
||
|
*
|
||
|
* * dim = NOT_PART
|
||
|
*
|
||
|
* Note that:
|
||
|
*
|
||
|
* * an edge cannot be both a Collapse edge and a Line edge in the same input geometry,
|
||
|
* because each input geometry must be homogeneous.
|
||
|
* * an edge may be an Boundary edge in one input geometry
|
||
|
* and a Line or Collapse edge in the other input.
|
||
|
*
|
||
|
* @author Martin Davis
|
||
|
*/
|
||
|
class GEOS_DLL OverlayLabel {
|
||
|
|
||
|
private:
|
||
|
|
||
|
// Members
|
||
|
int aDim = DIM_NOT_PART;
|
||
|
bool aIsHole = false;
|
||
|
Location aLocLeft = LOC_UNKNOWN;
|
||
|
Location aLocRight = LOC_UNKNOWN;
|
||
|
Location aLocLine = LOC_UNKNOWN;
|
||
|
int bDim = DIM_NOT_PART;
|
||
|
bool bIsHole = false;
|
||
|
Location bLocLeft = LOC_UNKNOWN;
|
||
|
Location bLocRight = LOC_UNKNOWN;
|
||
|
Location bLocLine = LOC_UNKNOWN;
|
||
|
|
||
|
std::string dimensionSymbol(int dim) const;
|
||
|
void locationString(uint8_t index, bool isForward, std::ostream& os) const;
|
||
|
|
||
|
|
||
|
public:
|
||
|
|
||
|
static constexpr Location LOC_UNKNOWN = Location::NONE;
|
||
|
|
||
|
enum {
|
||
|
DIM_UNKNOWN = -1,
|
||
|
DIM_NOT_PART = -1,
|
||
|
DIM_LINE = 1,
|
||
|
DIM_BOUNDARY = 2,
|
||
|
DIM_COLLAPSE = 3
|
||
|
};
|
||
|
|
||
|
OverlayLabel()
|
||
|
: aDim(DIM_NOT_PART)
|
||
|
, aIsHole(false)
|
||
|
, aLocLeft(LOC_UNKNOWN)
|
||
|
, aLocRight(LOC_UNKNOWN)
|
||
|
, aLocLine(LOC_UNKNOWN)
|
||
|
, bDim(DIM_NOT_PART)
|
||
|
, bIsHole(false)
|
||
|
, bLocLeft(LOC_UNKNOWN)
|
||
|
, bLocRight(LOC_UNKNOWN)
|
||
|
, bLocLine(LOC_UNKNOWN) {};
|
||
|
|
||
|
explicit OverlayLabel(uint8_t p_index)
|
||
|
: OverlayLabel()
|
||
|
{
|
||
|
initLine(p_index);
|
||
|
};
|
||
|
|
||
|
OverlayLabel(uint8_t p_index, Location p_locLeft, Location p_locRight, bool p_isHole)
|
||
|
: OverlayLabel()
|
||
|
{
|
||
|
initBoundary(p_index, p_locLeft, p_locRight, p_isHole);
|
||
|
};
|
||
|
|
||
|
int dimension(uint8_t index) const { return index == 0 ? aDim : bDim; };
|
||
|
void initBoundary(uint8_t index, Location locLeft, Location locRight, bool p_isHole);
|
||
|
void initCollapse(uint8_t index, bool p_isHole);
|
||
|
void initLine(uint8_t index);
|
||
|
void initNotPart(uint8_t index);
|
||
|
|
||
|
/**
|
||
|
* Sets the line location.
|
||
|
*
|
||
|
* This is used to set the locations for linear edges
|
||
|
* encountered during area label propagation.
|
||
|
*
|
||
|
* @param index source to update
|
||
|
* @param loc location to set
|
||
|
*/
|
||
|
void setLocationLine(uint8_t index, Location loc);
|
||
|
void setLocationAll(uint8_t index, Location loc);
|
||
|
void setLocationCollapse(uint8_t index);
|
||
|
|
||
|
/*
|
||
|
* Tests whether at least one of the sources is a Line.
|
||
|
*
|
||
|
* @return true if at least one source is a line
|
||
|
*/
|
||
|
bool isLine() const
|
||
|
{
|
||
|
return aDim == DIM_LINE || bDim == DIM_LINE;
|
||
|
};
|
||
|
|
||
|
bool isLine(uint8_t index) const
|
||
|
{
|
||
|
return index == 0 ? aDim == DIM_LINE : bDim == DIM_LINE;
|
||
|
};
|
||
|
|
||
|
bool isLinear(uint8_t index) const
|
||
|
{
|
||
|
if (index == 0) {
|
||
|
return aDim == DIM_LINE || aDim == DIM_COLLAPSE;
|
||
|
}
|
||
|
return bDim == DIM_LINE || bDim == DIM_COLLAPSE;
|
||
|
};
|
||
|
|
||
|
bool isKnown(uint8_t index) const
|
||
|
{
|
||
|
if (index == 0) {
|
||
|
return aDim != DIM_UNKNOWN;
|
||
|
}
|
||
|
return bDim != DIM_UNKNOWN;
|
||
|
};
|
||
|
|
||
|
bool isNotPart(uint8_t index) const
|
||
|
{
|
||
|
if (index == 0) {
|
||
|
return aDim == DIM_NOT_PART;
|
||
|
}
|
||
|
return bDim == DIM_NOT_PART;
|
||
|
};
|
||
|
|
||
|
bool isBoundaryEither() const
|
||
|
{
|
||
|
return aDim == DIM_BOUNDARY || bDim == DIM_BOUNDARY;
|
||
|
};
|
||
|
|
||
|
bool isBoundaryBoth() const
|
||
|
{
|
||
|
return aDim == DIM_BOUNDARY && bDim == DIM_BOUNDARY;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Tests if the label is for a collapsed
|
||
|
* edge of an area
|
||
|
* which is coincident with the boundary of the other area.
|
||
|
*
|
||
|
* @return true if the label is for a collapse coincident with a boundary
|
||
|
*/
|
||
|
bool isBoundaryCollapse() const
|
||
|
{
|
||
|
if (isLine()) return false;
|
||
|
return ! isBoundaryBoth();
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Tests if a label is for an edge where two
|
||
|
* area touch along their boundary.
|
||
|
*/
|
||
|
bool isBoundaryTouch() const
|
||
|
{
|
||
|
return isBoundaryBoth() &&
|
||
|
getLocation(0, Position::RIGHT, true) != getLocation(1, Position::RIGHT, true);
|
||
|
};
|
||
|
|
||
|
bool isBoundary(uint8_t index) const
|
||
|
{
|
||
|
if (index == 0) {
|
||
|
return aDim == DIM_BOUNDARY;
|
||
|
}
|
||
|
return bDim == DIM_BOUNDARY;
|
||
|
};
|
||
|
|
||
|
bool isLineLocationUnknown(int index) const
|
||
|
{
|
||
|
if (index == 0) {
|
||
|
return aLocLine == LOC_UNKNOWN;
|
||
|
}
|
||
|
else {
|
||
|
return bLocLine == LOC_UNKNOWN;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Tests whether a label is for an edge which is a boundary of one geometry
|
||
|
* and not part of the other.
|
||
|
*/
|
||
|
bool isBoundarySingleton() const
|
||
|
{
|
||
|
if (aDim == DIM_BOUNDARY && bDim == DIM_NOT_PART) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (bDim == DIM_BOUNDARY && aDim == DIM_NOT_PART) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Tests if a line edge is inside
|
||
|
* @param index
|
||
|
* @return
|
||
|
*/
|
||
|
bool isLineInArea(int8_t index) const
|
||
|
{
|
||
|
if (index == 0) {
|
||
|
return aLocLine == Location::INTERIOR;
|
||
|
}
|
||
|
return bLocLine == Location::INTERIOR;
|
||
|
};
|
||
|
|
||
|
bool isHole(uint8_t index) const
|
||
|
{
|
||
|
if (index == 0) {
|
||
|
return aIsHole;
|
||
|
}
|
||
|
else {
|
||
|
return bIsHole;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
bool isCollapse(uint8_t index) const
|
||
|
{
|
||
|
return dimension(index) == DIM_COLLAPSE;
|
||
|
};
|
||
|
|
||
|
Location getLineLocation(uint8_t index) const
|
||
|
{
|
||
|
if (index == 0) {
|
||
|
return aLocLine;
|
||
|
}
|
||
|
else {
|
||
|
return bLocLine;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Tests if a label is a Collapse has location INTERIOR,
|
||
|
* to at least one source geometry.
|
||
|
*/
|
||
|
bool isInteriorCollapse() const
|
||
|
{
|
||
|
if (aDim == DIM_COLLAPSE && aLocLine == Location::INTERIOR)
|
||
|
return true;
|
||
|
if (bDim == DIM_COLLAPSE && bLocLine == Location::INTERIOR)
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Tests if a label is a Collapse
|
||
|
* and NotPart with location INTERIOR for the other geometry.
|
||
|
*/
|
||
|
bool isCollapseAndNotPartInterior() const;
|
||
|
|
||
|
/**
|
||
|
* Tests if a line is in the interior of a source geometry.
|
||
|
*
|
||
|
* @param index source geometry
|
||
|
* @return true if the label is a line and is interior
|
||
|
*/
|
||
|
bool isLineInterior(uint8_t index) const
|
||
|
{
|
||
|
if (index == 0) {
|
||
|
return aLocLine == Location::INTERIOR;
|
||
|
}
|
||
|
return bLocLine == Location::INTERIOR;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Gets the location for this label for either
|
||
|
* a Boundary or a Line edge.
|
||
|
* This supports a simple determination of
|
||
|
* whether the edge should be included as a result edge.
|
||
|
*
|
||
|
* @param index the source index
|
||
|
* @param position the position for a boundary label
|
||
|
* @param isForward the direction for a boundary label
|
||
|
* @return the location for the specified position
|
||
|
*/
|
||
|
Location getLocationBoundaryOrLine(
|
||
|
uint8_t index,
|
||
|
int position,
|
||
|
bool isForward) const
|
||
|
{
|
||
|
if (isBoundary(index)) {
|
||
|
return getLocation(index, position, isForward);
|
||
|
}
|
||
|
return getLineLocation(index);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Gets the linear location for the given source.
|
||
|
*
|
||
|
* @param index the source index
|
||
|
* @return the linear location for the source
|
||
|
*/
|
||
|
Location getLocation(uint8_t index) const {
|
||
|
if (index == 0) {
|
||
|
return aLocLine;
|
||
|
}
|
||
|
return bLocLine;
|
||
|
};
|
||
|
|
||
|
Location getLocation(uint8_t index, int position, bool isForward) const;
|
||
|
|
||
|
bool hasSides(uint8_t index) const {
|
||
|
if (index == 0) {
|
||
|
return aLocLeft != LOC_UNKNOWN
|
||
|
|| aLocRight != LOC_UNKNOWN;
|
||
|
}
|
||
|
return bLocLeft != LOC_UNKNOWN
|
||
|
|| bLocRight != LOC_UNKNOWN;
|
||
|
};
|
||
|
|
||
|
OverlayLabel copy() const
|
||
|
{
|
||
|
OverlayLabel lbl = *this;
|
||
|
return lbl;
|
||
|
};
|
||
|
|
||
|
friend std::ostream& operator<<(std::ostream& os, const OverlayLabel& ol);
|
||
|
void toString(bool isForward, std::ostream& os) const;
|
||
|
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
} // namespace geos.operation.overlayng
|
||
|
} // namespace geos.operation
|
||
|
} // namespace geos
|