/********************************************************************** * * GEOS - Geometry Engine Open Source * http://geos.osgeo.org * * Copyright (C) 2011 Sandro Santilli * 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 // for inlines #include // for inlines #include // for inlines #include #include #include 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