You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

255 lines
8.2 KiB
C

1 month ago
/**********************************************************************
*
* GEOS - Geometry Engine Open Source
* http://geos.osgeo.org
*
* Copyright (C) 2011 Sandro Santilli <strk@kbt.io>
* Copyright (C) 2006 Refractions Research Inc.
*
* 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.
*
**********************************************************************
*
* Last port: operation/buffer/OffsetCurveSetBuilder.java r378 (JTS-1.12)
*
**********************************************************************/
#ifndef GEOS_OP_BUFFER_OFFSETCURVESETBUILDER_H
#define GEOS_OP_BUFFER_OFFSETCURVESETBUILDER_H
#include <geos/export.h>
#include <geos/geom/Location.h>
#include <vector>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4251) // warning C4251: needs to have dll-interface to be used by clients of class
#endif
// Forward declarations
namespace geos {
namespace geom {
class Geometry;
class CoordinateSequence;
class GeometryCollection;
class Point;
class LineString;
class LinearRing;
class Polygon;
}
namespace geomgraph {
class Label;
}
namespace noding {
class SegmentString;
}
namespace operation {
namespace buffer {
class OffsetCurveBuilder;
}
}
}
namespace geos {
namespace operation { // geos.operation
namespace buffer { // geos.operation.buffer
/**
* \class OffsetCurveSetBuilder
*
* \brief
* Creates all the raw offset curves for a buffer of a Geometry.
*
* Raw curves need to be noded together and polygonized to form the
* final buffer area.
*
*/
class GEOS_DLL OffsetCurveSetBuilder {
private:
// To keep track of newly-created Labels.
// Labels will be relesed by object dtor
std::vector<geomgraph::Label*> newLabels;
const geom::Geometry& inputGeom;
double distance;
OffsetCurveBuilder& curveBuilder;
/// The raw offset curves computed.
/// This class holds ownership of std::vector elements.
///
std::vector<noding::SegmentString*> curveList;
/**
* Creates a noding::SegmentString for a coordinate list which is a raw
* offset curve, and adds it to the list of buffer curves.
* The noding::SegmentString is tagged with a geomgraph::Label
* giving the topology of the curve.
* The curve may be oriented in either direction.
* If the curve is oriented CW, the locations will be:
* - Left: Location.EXTERIOR
* - Right: Location.INTERIOR
*
* @param coord is raw offset curve, ownership transferred here
*/
void addCurve(geom::CoordinateSequence* coord, geom::Location leftLoc,
geom::Location rightLoc);
void add(const geom::Geometry& g);
void addCollection(const geom::GeometryCollection* gc);
/**
* Add a Point to the graph.
*/
void addPoint(const geom::Point* p);
void addLineString(const geom::LineString* line);
void addPolygon(const geom::Polygon* p);
void addRingBothSides(const geom::CoordinateSequence* coord, double p_distance);
/**
* Add an offset curve for a polygon ring.
* The side and left and right topological location arguments
* assume that the ring is oriented CW.
* If the ring is in the opposite orientation,
* the left and right locations must be interchanged and the side
* flipped.
*
* @param coord the coordinates of the ring (must not contain
* repeated points)
* @param offsetDistance the distance at which to create the buffer
* @param side the side of the ring on which to construct the buffer
* line
* @param cwLeftLoc the location on the L side of the ring
* (if it is CW)
* @param cwRightLoc the location on the R side of the ring
* (if it is CW)
*/
void addRingSide(const geom::CoordinateSequence* coord,
double offsetDistance, int side, geom::Location cwLeftLoc,
geom::Location cwRightLoc);
/**
* Tests whether the offset curve for a ring is fully inverted.
* An inverted ("inside-out") curve occurs in some specific situations
* involving a buffer distance which should result in a fully-eroded (empty) buffer.
* It can happen that the sides of a small, convex polygon
* produce offset segments which all cross one another to form
* a curve with inverted orientation.
* This happens at buffer distances slightly greater than the distance at
* which the buffer should disappear.
* The inverted curve will produce an incorrect non-empty buffer (for a shell)
* or an incorrect hole (for a hole).
* It must be discarded from the set of offset curves used in the buffer.
* Heuristics are used to reduce the number of cases which area checked,
* for efficiency and correctness.
* <p>
* See https://github.com/locationtech/jts/issues/472
*
* @param inputPts the input ring
* @param distance the buffer distance
* @param curvePts the generated offset curve
* @return true if the offset curve is inverted
*/
static bool isRingCurveInverted(
const geom::CoordinateSequence* inputPts, double dist,
const geom::CoordinateSequence* curvePts);
/**
* Computes the maximum distance out of a set of points to a linestring.
*
* @param pts the points
* @param line the linestring vertices
* @return the maximum distance
*/
static double maxDistance(
const geom::CoordinateSequence* pts, const geom::CoordinateSequence* line);
/**
* The ringCoord is assumed to contain no repeated points.
* It may be degenerate (i.e. contain only 1, 2, or 3 points).
* In this case it has no area, and hence has a minimum diameter of 0.
*
* @param ringCoord
* @param bufferDistance
* @return
*/
bool isErodedCompletely(const geom::LinearRing* ringCoord,
double bufferDistance);
/**
* Tests whether a triangular ring would be eroded completely by
* the given buffer distance.
* This is a precise test. It uses the fact that the inner buffer
* of a triangle converges on the inCentre of the triangle (the
* point equidistant from all sides). If the buffer distance is
* greater than the distance of the inCentre from a side, the
* triangle will be eroded completely.
*
* This test is important, since it removes a problematic case where
* the buffer distance is slightly larger than the inCentre distance.
* In this case the triangle buffer curve "inverts" with incorrect
* topology, producing an incorrect hole in the buffer.
*
* @param triCoord
* @param bufferDistance
* @return
*/
bool isTriangleErodedCompletely(const geom::CoordinateSequence* triCoords,
double bufferDistance);
// Declare type as noncopyable
OffsetCurveSetBuilder(const OffsetCurveSetBuilder& other) = delete;
OffsetCurveSetBuilder& operator=(const OffsetCurveSetBuilder& rhs) = delete;
public:
/// Constructor
OffsetCurveSetBuilder(const geom::Geometry& newInputGeom,
double newDistance, OffsetCurveBuilder& newCurveBuilder);
/// Destructor
~OffsetCurveSetBuilder();
/** \brief
* Computes the set of raw offset curves for the buffer.
*
* Each offset curve has an attached {@link geomgraph::Label} indicating
* its left and right location.
*
* @return a Collection of SegmentStrings representing the raw buffer curves
*/
std::vector<noding::SegmentString*>& getCurves();
/// \brief Add raw curves for a set of CoordinateSequences.
///
/// @param lineList is a list of CoordinateSequence, ownership
/// of which is transferred here
/// @param leftLoc left location
/// @param rightLoc right location
///
void addCurves(const std::vector<geom::CoordinateSequence*>& lineList,
geom::Location leftLoc, geom::Location rightLoc);
};
} // namespace geos::operation::buffer
} // namespace geos::operation
} // namespace geos
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // ndef GEOS_OP_BUFFER_OFFSETCURVESETBUILDER_H