216 lines
5.1 KiB
C++
216 lines
5.1 KiB
C++
/**********************************************************************
|
|
*
|
|
* GEOS - Geometry Engine Open Source
|
|
* http://geos.osgeo.org
|
|
*
|
|
* Copyright (C) 2011 Sandro Santilli <strk@kbt.io>
|
|
* Copyright (C) 2007 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/OffsetSegmentString.java r378 (JTS-1.12)
|
|
*
|
|
**********************************************************************/
|
|
|
|
#pragma once
|
|
|
|
#include <geos/geom/Coordinate.h> // for inlines
|
|
#include <geos/geom/CoordinateSequence.h> // for inlines
|
|
#include <geos/geom/PrecisionModel.h> // for inlines
|
|
|
|
#include <vector>
|
|
#include <memory>
|
|
#include <cassert>
|
|
|
|
namespace geos {
|
|
namespace operation { // geos.operation
|
|
namespace buffer { // geos.operation.buffer
|
|
|
|
/// A dynamic list of the vertices in a constructed offset curve.
|
|
///
|
|
/// Automatically removes close vertices
|
|
/// which are closer than a given tolerance.
|
|
///
|
|
/// @author Martin Davis
|
|
///
|
|
class OffsetSegmentString {
|
|
|
|
private:
|
|
|
|
geom::CoordinateSequence* ptList;
|
|
|
|
const geom::PrecisionModel* precisionModel;
|
|
|
|
/** \brief
|
|
* The distance below which two adjacent points on the curve
|
|
* are considered to be coincident.
|
|
*
|
|
* This is chosen to be a small fraction of the offset distance.
|
|
*/
|
|
double minimumVertexDistance;
|
|
|
|
/** \brief
|
|
* Tests whether the given point is redundant relative to the previous
|
|
* point in the list (up to tolerance)
|
|
*
|
|
* @param pt
|
|
* @return true if the point is redundant
|
|
*/
|
|
bool
|
|
isRedundant(const geom::Coordinate& pt) const
|
|
{
|
|
if(ptList->size() < 1) {
|
|
return false;
|
|
}
|
|
const geom::Coordinate& lastPt = ptList->back();
|
|
double ptDist = pt.distance(lastPt);
|
|
if(ptDist < minimumVertexDistance) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
OffsetSegmentString(const OffsetSegmentString&) = delete;
|
|
OffsetSegmentString& operator=(const OffsetSegmentString&) = delete;
|
|
|
|
public:
|
|
|
|
friend std::ostream& operator<< (std::ostream& os, const OffsetSegmentString& node);
|
|
|
|
OffsetSegmentString()
|
|
:
|
|
ptList(new geom::CoordinateSequence()),
|
|
precisionModel(nullptr),
|
|
minimumVertexDistance(0.0)
|
|
{
|
|
}
|
|
|
|
~OffsetSegmentString()
|
|
{
|
|
delete ptList;
|
|
}
|
|
|
|
void
|
|
reset()
|
|
{
|
|
if(ptList) {
|
|
ptList->clear();
|
|
}
|
|
else {
|
|
ptList = new geom::CoordinateSequence();
|
|
}
|
|
|
|
precisionModel = nullptr;
|
|
minimumVertexDistance = 0.0;
|
|
}
|
|
|
|
void
|
|
setPrecisionModel(const geom::PrecisionModel* nPrecisionModel)
|
|
{
|
|
precisionModel = nPrecisionModel;
|
|
}
|
|
|
|
void
|
|
setMinimumVertexDistance(double nMinVertexDistance)
|
|
{
|
|
minimumVertexDistance = nMinVertexDistance;
|
|
}
|
|
|
|
void
|
|
addPt(const geom::Coordinate& pt)
|
|
{
|
|
assert(precisionModel);
|
|
|
|
geom::Coordinate bufPt = pt;
|
|
precisionModel->makePrecise(bufPt);
|
|
// don't add duplicate (or near-duplicate) points
|
|
if(isRedundant(bufPt)) {
|
|
return;
|
|
}
|
|
// we ask to allow repeated as we checked this ourself
|
|
// (JTS uses a vector for ptList, not a CoordinateSequence,
|
|
// we should do the same)
|
|
ptList->add(bufPt, true);
|
|
}
|
|
|
|
void
|
|
addPts(const geom::CoordinateSequence& pts, bool isForward)
|
|
{
|
|
if(isForward) {
|
|
for(std::size_t i = 0, n = pts.size(); i < n; ++i) {
|
|
addPt(pts[i]);
|
|
}
|
|
}
|
|
else {
|
|
for(std::size_t i = pts.size(); i > 0; --i) {
|
|
addPt(pts[i - 1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Check that points are a ring
|
|
///
|
|
/// add the startpoint again if they are not
|
|
void
|
|
closeRing()
|
|
{
|
|
if(ptList->size() < 1) {
|
|
return;
|
|
}
|
|
const geom::Coordinate& startPt = ptList->front();
|
|
const geom::Coordinate& lastPt = ptList->back();
|
|
if(startPt.equals(lastPt)) {
|
|
return;
|
|
}
|
|
// we ask to allow repeated as we checked this ourself
|
|
ptList->add(startPt, true);
|
|
}
|
|
|
|
/// Get coordinates by taking ownership of them
|
|
///
|
|
/// After this call, the coordinates reference in
|
|
/// this object are dropped. Calling twice will
|
|
/// segfault...
|
|
///
|
|
/// FIXME: refactor memory management of this
|
|
///
|
|
geom::CoordinateSequence*
|
|
getCoordinates()
|
|
{
|
|
closeRing();
|
|
geom::CoordinateSequence* ret = ptList;
|
|
ptList = nullptr;
|
|
return ret;
|
|
}
|
|
|
|
inline size_t
|
|
size() const
|
|
{
|
|
return ptList ? ptList->size() : 0 ;
|
|
}
|
|
|
|
};
|
|
|
|
inline std::ostream&
|
|
operator<< (std::ostream& os,
|
|
const OffsetSegmentString& lst)
|
|
{
|
|
if(lst.ptList) {
|
|
os << *(lst.ptList);
|
|
}
|
|
else {
|
|
os << "empty (consumed?)";
|
|
}
|
|
return os;
|
|
}
|
|
|
|
} // namespace geos.operation.buffer
|
|
} // namespace geos.operation
|
|
} // namespace geos
|
|
|