diff --git a/include/geos/geom/CircularString.h b/include/geos/geom/CircularString.h index 7d34cd9b2..283cb636c 100644 --- a/include/geos/geom/CircularString.h +++ b/include/geos/geom/CircularString.h @@ -35,25 +35,19 @@ class GEOS_DLL CircularString : public SimpleCurve { GeometryTypeId getGeometryTypeId() const override; - CircularString* cloneImpl() const override + double getLength() const override { - return new CircularString(*this); + throw util::UnsupportedOperationException("Cannot calculate length of CircularString"); } - CircularString* reverseImpl() const override; - - int - getSortIndex() const override + bool hasCurvedComponents() const override { - return SORTINDEX_LINESTRING; - }; - - double getLength() const override { - throw util::UnsupportedOperationException("Cannot calculate length of CircularString"); + return true; } - bool hasCurvedComponents() const override { - return true; + std::unique_ptr reverse() const + { + return std::unique_ptr(reverseImpl()); } protected: @@ -61,14 +55,29 @@ class GEOS_DLL CircularString : public SimpleCurve { /// \brief /// Constructs a CircularString taking ownership the /// given CoordinateSequence. - CircularString(std::unique_ptr && pts, + CircularString(std::unique_ptr&& pts, const GeometryFactory& newFactory); + CircularString* cloneImpl() const override + { + return new CircularString(*this); + } + void geometryChangedAction() override { envelope = computeEnvelopeInternal(false); } + int + getSortIndex() const override + { + return SORTINDEX_LINESTRING; + }; + + CircularString* reverseImpl() const override; + + void validateConstruction(); + }; diff --git a/include/geos/geom/CompoundCurve.h b/include/geos/geom/CompoundCurve.h index 253e7dce2..9e09b7302 100644 --- a/include/geos/geom/CompoundCurve.h +++ b/include/geos/geom/CompoundCurve.h @@ -24,91 +24,93 @@ namespace geom { class GEOS_DLL CompoundCurve : public Curve { friend class GeometryFactory; - public: + using Curve::apply_ro; + using Curve::apply_rw; - CompoundCurve(const CompoundCurve&); - - CompoundCurve& operator=(const CompoundCurve&); - - std::unique_ptr getCoordinates() const override; - - const CoordinateXY* getCoordinate() const override; + void apply_ro(CoordinateFilter* filter) const override; - uint8_t getCoordinateDimension() const override; + void apply_ro(CoordinateSequenceFilter& filter) const override; - bool hasZ() const override; + void apply_rw(CoordinateSequenceFilter& filter) override; - bool hasM() const override; + void apply_rw(const CoordinateFilter* filter) override; - bool isEmpty() const override; + int compareToSameClass(const Geometry* geom) const override; - bool isClosed() const override; + std::unique_ptr clone() const; - std::size_t getNumCurves() const; + CompoundCurve* cloneImpl() const override; - const SimpleCurve* getCurveN(std::size_t) const; + bool equalsExact(const Geometry* other, double tolerance = 0) + const override; - std::size_t getNumPoints() const override; + bool equalsIdentical(const Geometry* other) const override; std::unique_ptr getBoundary() const override; - std::string getGeometryType() const override; + const CoordinateXY* getCoordinate() const override; - GeometryTypeId getGeometryTypeId() const override; + std::unique_ptr getCoordinates() const override; - bool equalsExact(const Geometry* other, double tolerance = 0) - const override; + uint8_t getCoordinateDimension() const override; - bool equalsIdentical(const Geometry* other) const override; + /// Returns the nth section of the CompoundCurve + const SimpleCurve* getCurveN(std::size_t) const; const Envelope* getEnvelopeInternal() const override { return &envelope; } - std::unique_ptr clone() const; + std::string getGeometryType() const override; - CompoundCurve* cloneImpl() const override; + GeometryTypeId getGeometryTypeId() const override; - std::unique_ptr reverse() const; + double getLength() const override; - CompoundCurve* reverseImpl() const override; + /// Returns the number of sections in the CompoundCurve + std::size_t getNumCurves() const; - double getLength() const override; + std::size_t getNumPoints() const override; - using Curve::apply_ro; - using Curve::apply_rw; + bool hasCurvedComponents() const override; - void apply_rw(const CoordinateFilter* filter) override; + bool hasM() const override; - void apply_ro(CoordinateFilter* filter) const override; + bool hasZ() const override; - void apply_rw(CoordinateSequenceFilter& filter) override; + bool isClosed() const override; - void apply_ro(CoordinateSequenceFilter& filter) const override; + bool isEmpty() const override; void normalize() override; - int compareToSameClass(const Geometry* geom) const override; - - bool hasCurvedComponents() const override; + std::unique_ptr reverse() const; protected: + /// Construct a CompoundCurve, taking ownership of the + /// provided CoordinateSequence CompoundCurve(std::vector>&&, const GeometryFactory&); - int getSortIndex() const override - { - return SORTINDEX_COMPOUNDCURVE; - } + CompoundCurve(const CompoundCurve&); + + CompoundCurve& operator=(const CompoundCurve&); + + Envelope computeEnvelopeInternal() const; void geometryChangedAction() override { envelope = computeEnvelopeInternal(); } - Envelope computeEnvelopeInternal() const; + int getSortIndex() const override + { + return SORTINDEX_COMPOUNDCURVE; + } + + CompoundCurve* reverseImpl() const override; private: std::vector> curves; diff --git a/include/geos/geom/Curve.h b/include/geos/geom/Curve.h index a8367c817..b5ee36ace 100644 --- a/include/geos/geom/Curve.h +++ b/include/geos/geom/Curve.h @@ -34,8 +34,10 @@ class GEOS_DLL Curve : public Geometry { return isClosed() ? Dimension::False : 0; } + /// Returns true if the first and last coordinate in the Curve are the same virtual bool isClosed() const = 0; + /// Returns true if the curve is closed and simple bool isRing() const; using Geometry::apply_ro; diff --git a/include/geos/geom/MultiCurve.h b/include/geos/geom/MultiCurve.h index f626bcdf0..5505f5d96 100644 --- a/include/geos/geom/MultiCurve.h +++ b/include/geos/geom/MultiCurve.h @@ -26,18 +26,13 @@ class GEOS_DLL MultiCurve : public GeometryCollection { public: ~MultiCurve() override = default; - /// Returns line dimension (1) - Dimension::DimensionType getDimension() const override; - - bool hasDimension(Dimension::DimensionType d) const override + std::unique_ptr clone() const { - return d == Dimension::L; - } + return std::unique_ptr(cloneImpl()); + }; - bool isDimensionStrict(Dimension::DimensionType d) const override - { - return d == Dimension::L; - } + /// Returns a (possibly empty) [MultiPoint](@ref geom::MultiPoint) + std::unique_ptr getBoundary() const override; /** * \brief @@ -46,8 +41,8 @@ class GEOS_DLL MultiCurve : public GeometryCollection { */ int getBoundaryDimension() const override; - /// Returns a (possibly empty) [MultiPoint](@ref geom::MultiPoint) - std::unique_ptr getBoundary() const override; + /// Returns line dimension (1) + Dimension::DimensionType getDimension() const override; const Curve* getGeometryN(std::size_t n) const override; @@ -55,12 +50,19 @@ class GEOS_DLL MultiCurve : public GeometryCollection { GeometryTypeId getGeometryTypeId() const override; + bool hasDimension(Dimension::DimensionType d) const override + { + return d == Dimension::L; + } + + /// Returns true if the MultiCurve is not empty, and every included + /// Curve is also closed. bool isClosed() const; - std::unique_ptr clone() const + bool isDimensionStrict(Dimension::DimensionType d) const override { - return std::unique_ptr(cloneImpl()); - }; + return d == Dimension::L; + } /** * Creates a MultiCurve in the reverse diff --git a/include/geos/geom/MultiSurface.h b/include/geos/geom/MultiSurface.h index af47a947e..73871e4f0 100644 --- a/include/geos/geom/MultiSurface.h +++ b/include/geos/geom/MultiSurface.h @@ -26,21 +26,10 @@ class GEOS_DLL MultiSurface : public GeometryCollection { ~MultiSurface() override; - /// Returns surface dimension (2) - Dimension::DimensionType getDimension() const override; - - bool hasDimension(Dimension::DimensionType d) const override - { - return d == Dimension::A; - } - - bool isDimensionStrict(Dimension::DimensionType d) const override + std::unique_ptr clone() const { - return d == Dimension::A; - } - - /// Returns 1 (MultiSurface boundary is MultiCurve) - int getBoundaryDimension() const override; + return std::unique_ptr(cloneImpl()); + }; /** \brief * Computes the boundary of this geometry @@ -50,14 +39,25 @@ class GEOS_DLL MultiSurface : public GeometryCollection { */ std::unique_ptr getBoundary() const override; + /// Returns 1 (MultiSurface boundary is MultiCurve) + int getBoundaryDimension() const override; + + /// Returns surface dimension (2) + Dimension::DimensionType getDimension() const override; + std::string getGeometryType() const override; GeometryTypeId getGeometryTypeId() const override; - std::unique_ptr clone() const + bool hasDimension(Dimension::DimensionType d) const override { - return std::unique_ptr(cloneImpl()); - }; + return d == Dimension::A; + } + + bool isDimensionStrict(Dimension::DimensionType d) const override + { + return d == Dimension::A; + } std::unique_ptr reverse() const { @@ -81,14 +81,14 @@ class GEOS_DLL MultiSurface : public GeometryCollection { return new MultiSurface(*this); } - MultiSurface* reverseImpl() const override; - int getSortIndex() const override { return SORTINDEX_MULTISURFACE; }; + MultiSurface* reverseImpl() const override; + }; } } diff --git a/include/geos/geom/SimpleCurve.h b/include/geos/geom/SimpleCurve.h index 187af0c91..7b40d4ca0 100644 --- a/include/geos/geom/SimpleCurve.h +++ b/include/geos/geom/SimpleCurve.h @@ -26,44 +26,58 @@ namespace geom { class GEOS_DLL SimpleCurve : public Curve { public: - std::unique_ptr getCoordinates() const override; + using Curve::apply_ro; + using Curve::apply_rw; - /// Returns a read-only pointer to internal CoordinateSequence - const CoordinateSequence* getCoordinatesRO() const; + void apply_ro(CoordinateFilter* filter) const override; - virtual const Coordinate& getCoordinateN(std::size_t n) const; + void apply_ro(CoordinateSequenceFilter& filter) const override; + + void apply_rw(CoordinateSequenceFilter& filter) override; + + void apply_rw(const CoordinateFilter* filter) override; + + bool equalsExact(const Geometry* other, double tolerance = 0) + const override; + + bool equalsIdentical(const Geometry* other) const override; /** * \brief - * Take ownership of the CoordinateSequence managed by this geometry. - * After releasing the coordinates, the geometry should be considered - * in a moved-from state and should not be accessed. - * @return this Geometry's CoordinateSequence. + * Returns a MultiPoint. + * Empty for closed Curve, a Point for each vertex otherwise. */ - std::unique_ptr releaseCoordinates(); + std::unique_ptr getBoundary() const override; /** * \brief - * Returns Dimension::False for a closed LineString, - * 0 otherwise (LineString boundary is a MultiPoint) + * Returns Dimension::False for a closed Curve, + * 0 otherwise (Curve boundary is a MultiPoint) */ int getBoundaryDimension() const override; + const CoordinateXY* getCoordinate() const override; + /// Returns coordinate dimension. uint8_t getCoordinateDimension() const override; - bool hasM() const override; + virtual const Coordinate& getCoordinateN(std::size_t n) const; - bool hasZ() const override; + std::unique_ptr getCoordinates() const override; - /** - * \brief - * Returns a MultiPoint. - * Empty for closed LineString, a Point for each vertex otherwise. - */ - std::unique_ptr getBoundary() const override; + /// Returns a read-only pointer to internal CoordinateSequence + const CoordinateSequence* getCoordinatesRO() const; - bool isEmpty() const override; + /// \brief + /// Return the end point of the LineString + /// or NULL if this is an EMPTY LineString. + /// + virtual std::unique_ptr getEndPoint() const; + + const Envelope* getEnvelopeInternal() const override + { + return &envelope; + } std::size_t getNumPoints() const override; @@ -75,38 +89,15 @@ class GEOS_DLL SimpleCurve : public Curve { /// virtual std::unique_ptr getStartPoint() const; - /// \brief - /// Return the end point of the LineString - /// or NULL if this is an EMPTY LineString. - /// - virtual std::unique_ptr getEndPoint() const; + bool hasM() const override; + + bool hasZ() const override; bool isClosed() const override; virtual bool isCoordinate(CoordinateXY& pt) const; - bool equalsExact(const Geometry* other, double tolerance = 0) - const override; - - bool equalsIdentical(const Geometry* other) const override; - - const CoordinateXY* getCoordinate() const override; - - const Envelope* getEnvelopeInternal() const override - { - return &envelope; - } - - using Curve::apply_ro; - using Curve::apply_rw; - - void apply_rw(const CoordinateFilter* filter) override; - - void apply_ro(CoordinateFilter* filter) const override; - - void apply_rw(CoordinateSequenceFilter& filter) override; - - void apply_ro(CoordinateSequenceFilter& filter) const override; + bool isEmpty() const override; /** \brief * Normalizes a SimpleCurve. @@ -117,9 +108,14 @@ class GEOS_DLL SimpleCurve : public Curve { */ void normalize() override; - //was protected - int compareToSameClass(const Geometry* ls) const override; - + /** + * \brief + * Take ownership of the CoordinateSequence managed by this geometry. + * After releasing the coordinates, the geometry should be considered + * in a moved-from state and should not be accessed. + * @return this Geometry's CoordinateSequence. + */ + std::unique_ptr releaseCoordinates(); protected: @@ -129,13 +125,15 @@ class GEOS_DLL SimpleCurve : public Curve { bool isLinear, const GeometryFactory& factory); - Envelope computeEnvelopeInternal(bool isLinear) const; + int compareToSameClass(const Geometry* ls) const override; - // TODO: hold value or shared_ptr instead of unique_ptr - std::unique_ptr points; + Envelope computeEnvelopeInternal(bool isLinear) const; mutable Envelope envelope; + // TODO: hold value or shared_ptr instead of unique_ptr? + std::unique_ptr points; + private: void normalizeClosed(); diff --git a/include/geos/geom/Surface.h b/include/geos/geom/Surface.h index 46b491748..861da7831 100644 --- a/include/geos/geom/Surface.h +++ b/include/geos/geom/Surface.h @@ -21,6 +21,9 @@ namespace geom { class Curve; +/// A Surface is an abstract class representing a Geometry of dimension 2. +/// It is extended by Polygon, which represents a Surface with linear edges, +/// and by CurvePolygon, whose edges may include circular arcs. class GEOS_DLL Surface : public Geometry { private: @@ -30,19 +33,23 @@ class GEOS_DLL Surface : public Geometry { public: - uint8_t getCoordinateDimension() const override; + void apply_ro(CoordinateFilter* filter) const override; - /// Returns the exterior ring (shell) - virtual const Curve* getExteriorRing() const = 0; + void apply_ro(CoordinateSequenceFilter& filter) const override; - /// Returns number of interior rings (holes) - virtual size_t getNumInteriorRing() const = 0; + void apply_ro(GeometryComponentFilter* filter) const override; - /// Get nth interior ring (hole) - virtual const Curve* getInteriorRingN(std::size_t n) const = 0; + void apply_ro(GeometryFilter* filter) const override; - size_t getNumPoints() const override; + void apply_rw(CoordinateSequenceFilter& filter) override; + + void apply_rw(GeometryComponentFilter* filter) override; + + void apply_rw(GeometryFilter* filter) override; + void apply_rw(const CoordinateFilter* filter) override; + + std::unique_ptr convexHull() const override; bool equalsExact(const Geometry* other, double tolerance = 0.0) const override; @@ -50,9 +57,6 @@ class GEOS_DLL Surface : public Geometry { bool equalsIdentical(const Geometry* other) const override; - - std::unique_ptr convexHull() const override; - int getBoundaryDimension() const override { @@ -61,6 +65,8 @@ class GEOS_DLL Surface : public Geometry { const CoordinateXY* getCoordinate() const override; + uint8_t getCoordinateDimension() const override; + Dimension::DimensionType getDimension() const override { @@ -69,52 +75,40 @@ class GEOS_DLL Surface : public Geometry { const Envelope* getEnvelopeInternal() const override; - bool hasM() const override; - - bool hasZ() const override; + /// Returns the exterior ring (shell) + virtual const Curve* getExteriorRing() const = 0; - bool isEmpty() const override; + /// Get nth interior ring (hole) + virtual const Curve* getInteriorRingN(std::size_t n) const = 0; /// Returns the perimeter of this Surface double getLength() const override; - void - apply_ro(CoordinateFilter* filter) const override; - - void - apply_rw(const CoordinateFilter* filter) override; - - void - apply_rw(GeometryFilter* filter) override; - - void - apply_ro(GeometryFilter* filter) const override; + /// Returns number of interior rings (holes) + virtual size_t getNumInteriorRing() const = 0; - void - apply_ro(GeometryComponentFilter* filter) const override; + size_t getNumPoints() const override; - void - apply_rw(GeometryComponentFilter* filter) override; + bool hasM() const override; - void - apply_rw(CoordinateSequenceFilter& filter) override; + bool hasZ() const override; - void - apply_ro(CoordinateSequenceFilter& filter) const override; + bool isEmpty() const override; protected: int compareToSameClass(const Geometry* g) const override; - void geometryChangedAction() override {} - + // FIXME explain why this method exists, or remove it static std::unique_ptr createEmptyRing(const GeometryFactory&); virtual Curve* getExteriorRing() = 0; virtual Curve* getInteriorRingN(std::size_t i) = 0; + void geometryChangedAction() override {} + }; } diff --git a/src/geom/CircularString.cpp b/src/geom/CircularString.cpp index 1bdaaf16d..f5bb375c8 100644 --- a/src/geom/CircularString.cpp +++ b/src/geom/CircularString.cpp @@ -21,16 +21,22 @@ namespace geos { namespace geom { /*public*/ -CircularString::CircularString(std::unique_ptr && newCoords, +CircularString::CircularString(std::unique_ptr&& newCoords, const GeometryFactory& factory) : SimpleCurve(std::move(newCoords), false, factory) { - //validateConstruction(); + validateConstruction(); } CircularString::~CircularString() = default; +std::unique_ptr +CircularString::clone() const +{ + return std::unique_ptr(cloneImpl()); +} + std::string CircularString::getGeometryType() const { @@ -43,12 +49,6 @@ CircularString::getGeometryTypeId() const return GEOS_CIRCULARSTRING; } -std::unique_ptr -CircularString::clone() const -{ - return std::unique_ptr(cloneImpl()); -} - CircularString* CircularString::reverseImpl() const { @@ -63,5 +63,18 @@ CircularString::reverseImpl() const return getFactory()->createCircularString(std::move(seq)).release(); } +void +CircularString::validateConstruction() +{ + if (points.get() == nullptr) { + points = std::make_unique(); + return; + } + + if (points->size() == 2) { + throw util::IllegalArgumentException("point array must contain 0 or >2 elements\n"); + } +} + } } diff --git a/src/geom/CompoundCurve.cpp b/src/geom/CompoundCurve.cpp index f44f54876..2175c7ed2 100644 --- a/src/geom/CompoundCurve.cpp +++ b/src/geom/CompoundCurve.cpp @@ -12,8 +12,8 @@ * **********************************************************************/ -#include #include +#include #include #include #include @@ -25,7 +25,7 @@ CompoundCurve::CompoundCurve(std::vector>&& p_curve const GeometryFactory& gf) : Curve(gf), curves(std::move(p_curves)), - envelope(computeEnvelopeInternal()) {} + envelope(computeEnvelopeInternal()) {} CompoundCurve::CompoundCurve(const CompoundCurve& other) : Curve(other), @@ -50,112 +50,69 @@ CompoundCurve::operator=(const CompoundCurve& other) return *this; } -std::unique_ptr -CompoundCurve::getCoordinates() const +void +CompoundCurve::apply_ro(CoordinateFilter* cf) const { - // FIXME: CoordinateSequence would have curved and linear sections? - auto ret = std::make_unique(0, hasZ(), hasM()); for (const auto& curve : curves) { - ret->add(*curve->getCoordinatesRO()); + curve->apply_ro(cf); } - return ret; } -const CoordinateXY* -CompoundCurve::getCoordinate() const +void +CompoundCurve::apply_ro(CoordinateSequenceFilter& csf) const { for (const auto& curve : curves) { - if (!curve->isEmpty()) { - return curve->getCoordinate(); + const auto& seq = *curve->getCoordinatesRO(); + for (std::size_t i = 0; i < seq.size(); i++) { + if (csf.isDone()) { + return; + } + csf.filter_ro(seq, i); } } - - return nullptr; } -uint8_t -CompoundCurve::getCoordinateDimension() const +void +CompoundCurve::apply_rw(const CoordinateFilter* cf) { - return static_cast(2 + hasZ() + hasM()); + for (auto& curve : curves) { + curve->apply_rw(cf); + } } -bool -CompoundCurve::hasZ() const +void +CompoundCurve::apply_rw(CoordinateSequenceFilter&) { - return std::any_of(curves.begin(), curves.end(), [](const auto& curve) { - return curve->hasZ(); - }); + throw util::UnsupportedOperationException(); } -bool -CompoundCurve::hasM() const +std::unique_ptr +CompoundCurve::clone() const { - return std::any_of(curves.begin(), curves.end(), [](const auto& curve) { - return curve->hasM(); - }); + return std::unique_ptr(cloneImpl()); } -bool -CompoundCurve::isEmpty() const +CompoundCurve* +CompoundCurve::cloneImpl() const { - return !std::any_of(curves.begin(), curves.end(), [](const auto& curve) { - return !curve->isEmpty(); - }); + return new CompoundCurve(*this); } -bool -CompoundCurve::isClosed() const +int +CompoundCurve::compareToSameClass(const Geometry* g) const { - if (isEmpty()) { - return false; - } - - const SimpleCurve& first = *curves.front(); - const SimpleCurve& last = *curves.back(); - - return first.getCoordinateN(0) == last.getCoordinateN(last.getNumPoints() - 1); + const CompoundCurve* curve = detail::down_cast(g); + return compare(curves, curve->curves); } -std::size_t -CompoundCurve::getNumPoints() const +Envelope +CompoundCurve::computeEnvelopeInternal() const { - std::size_t n =0; + Envelope e; for (const auto& curve : curves) { - n += curve->getNumPoints(); + e.expandToInclude(curve->getEnvelopeInternal()); } - return n; -} - -std::size_t -CompoundCurve::getNumCurves() const -{ - return curves.size(); -} - -const SimpleCurve* -CompoundCurve::getCurveN(std::size_t i) const -{ - return curves[i].get(); -} - -std::unique_ptr -CompoundCurve::getBoundary() const -{ - operation::BoundaryOp bop(*this); - return bop.getBoundary(); -} - - -std::string -CompoundCurve::getGeometryType() const -{ - return "CompoundCurve"; -} - -GeometryTypeId -CompoundCurve::getGeometryTypeId() const -{ - return GEOS_COMPOUNDCURVE; + return e; } bool @@ -200,36 +157,62 @@ CompoundCurve::equalsIdentical(const Geometry* other) const return true; } -std::unique_ptr -CompoundCurve::clone() const +std::unique_ptr +CompoundCurve::getBoundary() const { - return std::unique_ptr(cloneImpl()); + operation::BoundaryOp bop(*this); + return bop.getBoundary(); } -CompoundCurve* -CompoundCurve::cloneImpl() const +const CoordinateXY* +CompoundCurve::getCoordinate() const { - return new CompoundCurve(*this); + for (const auto& curve : curves) { + if (!curve->isEmpty()) { + return curve->getCoordinate(); + } + } + + return nullptr; } -std::unique_ptr -CompoundCurve::reverse() const +uint8_t +CompoundCurve::getCoordinateDimension() const { - return std::unique_ptr(reverseImpl()); + return static_cast(2 + hasZ() + hasM()); } -CompoundCurve* -CompoundCurve::reverseImpl() const +std::unique_ptr +CompoundCurve::getCoordinates() const { - std::vector> reversed(curves.size()); - std::transform(curves.rbegin(), curves.rend(), reversed.begin(), [](const auto& curve) { - return std::unique_ptr(static_cast(curve->reverse().release())); - }); + auto ret = std::make_unique(0, hasZ(), hasM()); + for (const auto& curve : curves) { + ret->add(*curve->getCoordinatesRO()); + } + return ret; +} - return getFactory()->createCompoundCurve(std::move(reversed)).release(); +const SimpleCurve* +CompoundCurve::getCurveN(std::size_t i) const +{ + return curves[i].get(); +} + +std::string +CompoundCurve::getGeometryType() const +{ + return "CompoundCurve"; } -double CompoundCurve::getLength() const { +GeometryTypeId +CompoundCurve::getGeometryTypeId() const +{ + return GEOS_COMPOUNDCURVE; +} + +double +CompoundCurve::getLength() const +{ double sum = 0; for (const auto& curve : curves) { sum += curve->getLength(); @@ -237,23 +220,41 @@ double CompoundCurve::getLength() const { return sum; } -Envelope -CompoundCurve::computeEnvelopeInternal() const { - Envelope e; +std::size_t +CompoundCurve::getNumCurves() const +{ + return curves.size(); +} + +std::size_t +CompoundCurve::getNumPoints() const +{ + std::size_t n =0; for (const auto& curve : curves) { - e.expandToInclude(curve->getEnvelopeInternal()); + n += curve->getNumPoints(); } - return e; + return n; } -int -CompoundCurve::compareToSameClass(const Geometry* g) const +bool +CompoundCurve::hasZ() const { - const CompoundCurve* curve = detail::down_cast(g); - return compare(curves, curve->curves); + return std::any_of(curves.begin(), curves.end(), [](const auto& curve) { + return curve->hasZ(); + }); } -bool CompoundCurve::hasCurvedComponents() const { +bool +CompoundCurve::hasM() const +{ + return std::any_of(curves.begin(), curves.end(), [](const auto& curve) { + return curve->hasM(); + }); +} + +bool +CompoundCurve::hasCurvedComponents() const +{ for (const auto& curve : curves) { if (curve->hasCurvedComponents()) { return true; @@ -262,48 +263,49 @@ bool CompoundCurve::hasCurvedComponents() const { return false; } -void -CompoundCurve::normalize() +bool +CompoundCurve::isClosed() const { - throw util::UnsupportedOperationException(); + if (isEmpty()) { + return false; + } + + const SimpleCurve& first = *curves.front(); + const SimpleCurve& last = *curves.back(); + + return first.getCoordinateN(0) == last.getCoordinateN(last.getNumPoints() - 1); } -void -CompoundCurve::apply_ro(CoordinateFilter* cf) const +bool +CompoundCurve::isEmpty() const { - for (const auto& curve : curves) { - curve->apply_ro(cf); - } + return !std::any_of(curves.begin(), curves.end(), [](const auto& curve) { + return !curve->isEmpty(); + }); } void -CompoundCurve::apply_ro(CoordinateSequenceFilter& csf) const +CompoundCurve::normalize() { - for (const auto& curve : curves) { - const auto& seq = *curve->getCoordinatesRO(); - for (std::size_t i = 0; i < seq.size(); i++) { - if (csf.isDone()) { - return; - } - csf.filter_ro(seq, i); - } - } + throw util::UnsupportedOperationException(); } -void -CompoundCurve::apply_rw(const CoordinateFilter* cf) +std::unique_ptr +CompoundCurve::reverse() const { - for (auto& curve : curves) { - curve->apply_rw(cf); - } + return std::unique_ptr(reverseImpl()); } -void -CompoundCurve::apply_rw(CoordinateSequenceFilter&) +CompoundCurve* +CompoundCurve::reverseImpl() const { - throw util::UnsupportedOperationException(); -} + std::vector> reversed(curves.size()); + std::transform(curves.rbegin(), curves.rend(), reversed.begin(), [](const auto& curve) { + return std::unique_ptr(static_cast(curve->reverse().release())); + }); + return getFactory()->createCompoundCurve(std::move(reversed)).release(); +} } } diff --git a/src/geom/Curve.cpp b/src/geom/Curve.cpp index 4bd3d0244..91fd60da2 100644 --- a/src/geom/Curve.cpp +++ b/src/geom/Curve.cpp @@ -21,10 +21,10 @@ namespace geos { namespace geom { void -Curve::apply_rw(GeometryFilter* filter) +Curve::apply_ro(GeometryComponentFilter* filter) const { assert(filter); - filter->filter_rw(this); + filter->filter_ro(this); } void @@ -42,10 +42,10 @@ Curve::apply_rw(GeometryComponentFilter* filter) } void -Curve::apply_ro(GeometryComponentFilter* filter) const +Curve::apply_rw(GeometryFilter* filter) { assert(filter); - filter->filter_ro(this); + filter->filter_rw(this); } bool @@ -56,4 +56,4 @@ Curve::isRing() const } -} \ No newline at end of file +} diff --git a/src/geom/MultiCurve.cpp b/src/geom/MultiCurve.cpp index 9b4375094..31e13eb2c 100644 --- a/src/geom/MultiCurve.cpp +++ b/src/geom/MultiCurve.cpp @@ -14,29 +14,35 @@ * **********************************************************************/ +#include #include -#include #include -#include +#include namespace geos { namespace geom { -/*protected*/ -MultiCurve::MultiCurve(std::vector>&& newLines, +MultiCurve::MultiCurve(std::vector>&& newLines, const GeometryFactory& factory) : GeometryCollection(std::move(newLines), factory) -{} +{ + for (const auto& geom : geometries) { + if (!dynamic_cast(geom.get())) { + throw util::IllegalArgumentException("All elements of MultiCurve must be a Curve"); + } + } +} -MultiCurve::MultiCurve(std::vector>&& newLines, +MultiCurve::MultiCurve(std::vector>&& newLines, const GeometryFactory& factory) : GeometryCollection(std::move(newLines), factory) {} -Dimension::DimensionType -MultiCurve::getDimension() const +std::unique_ptr +MultiCurve::getBoundary() const { - return Dimension::L; // line + operation::BoundaryOp bop(*this); + return bop.getBoundary(); } int @@ -48,12 +54,30 @@ MultiCurve::getBoundaryDimension() const return 0; } +Dimension::DimensionType +MultiCurve::getDimension() const +{ + return Dimension::L; // line +} + +const Curve* +MultiCurve::getGeometryN(std::size_t i) const +{ + return static_cast(geometries[i].get()); +} + std::string MultiCurve::getGeometryType() const { return "MultiCurve"; } +GeometryTypeId +MultiCurve::getGeometryTypeId() const +{ + return GEOS_MULTICURVE; +} + bool MultiCurve::isClosed() const { @@ -69,19 +93,6 @@ MultiCurve::isClosed() const return true; } -std::unique_ptr -MultiCurve::getBoundary() const -{ - operation::BoundaryOp bop(*this); - return bop.getBoundary(); -} - -GeometryTypeId -MultiCurve::getGeometryTypeId() const -{ - return GEOS_MULTICURVE; -} - MultiCurve* MultiCurve::reverseImpl() const { @@ -101,12 +112,5 @@ MultiCurve::reverseImpl() const return getFactory()->createMultiCurve(std::move(reversed)).release(); } -const Curve* -MultiCurve::getGeometryN(std::size_t i) const -{ - return static_cast(geometries[i].get()); -} - - } } diff --git a/src/geom/MultiSurface.cpp b/src/geom/MultiSurface.cpp index 82cc4c572..b8e299f6a 100644 --- a/src/geom/MultiSurface.cpp +++ b/src/geom/MultiSurface.cpp @@ -14,18 +14,21 @@ * **********************************************************************/ -#include -#include #include +#include +#include namespace geos { namespace geom { -/*protected*/ MultiSurface::MultiSurface(std::vector>&& newPolys, const GeometryFactory& factory) : GeometryCollection(std::move(newPolys), factory) { - // FIXME check that all elements are in fact surfaces + for (const auto& geom : geometries) { + if (!dynamic_cast(geom.get())) { + throw util::IllegalArgumentException("All elements of MultiSurface must be a Surface"); + } + } } MultiSurface::MultiSurface(std::vector>&& newPolys, const GeometryFactory& factory) @@ -35,33 +38,12 @@ MultiSurface::MultiSurface(std::vector>&& newPolys, con MultiSurface::~MultiSurface() {} -Dimension::DimensionType -MultiSurface::getDimension() const -{ - return Dimension::A; // area -} - -int -MultiSurface::getBoundaryDimension() const -{ - return 1; -} - -std::string -MultiSurface::getGeometryType() const -{ - return "MultiSurface"; -} - std::unique_ptr MultiSurface::getBoundary() const { - // FIXME implement -#if 0 if (isEmpty()) { return std::unique_ptr(getFactory()->createMultiCurve()); } -#endif std::vector> allRings; for (const auto& pg : geometries) { @@ -71,9 +53,8 @@ MultiSurface::getBoundary() const allRings.push_back(std::move(g)); } else { - for (std::size_t i = 0; i < g->getNumGeometries(); ++i) { - // TODO avoid this clone - allRings.push_back(g->getGeometryN(i)->clone()); + for (auto& gi : (static_cast(*g)).releaseGeometries()) { + allRings.push_back(std::move(gi)); } } } @@ -81,6 +62,24 @@ MultiSurface::getBoundary() const return getFactory()->createMultiCurve(std::move(allRings)); } +int +MultiSurface::getBoundaryDimension() const +{ + return 1; +} + +Dimension::DimensionType +MultiSurface::getDimension() const +{ + return Dimension::A; // area +} + +std::string +MultiSurface::getGeometryType() const +{ + return "MultiSurface"; +} + GeometryTypeId MultiSurface::getGeometryTypeId() const { @@ -106,6 +105,5 @@ MultiSurface::reverseImpl() const return getFactory()->createMultiSurface(std::move(reversed)).release(); } - } } diff --git a/src/geom/SimpleCurve.cpp b/src/geom/SimpleCurve.cpp index a0e039760..97b0f1df6 100644 --- a/src/geom/SimpleCurve.cpp +++ b/src/geom/SimpleCurve.cpp @@ -33,30 +33,101 @@ namespace geom { SimpleCurve::SimpleCurve(const SimpleCurve& other) : Curve(other), - points(other.points->clone()), - envelope(other.envelope) + envelope(other.envelope), + points(other.points->clone()) { } SimpleCurve::SimpleCurve(std::unique_ptr&& newCoords, bool isLinear, - const GeometryFactory& factory) + const GeometryFactory& factory) : Curve(factory), - points(newCoords ? std::move(newCoords) : std::make_unique()), - envelope(computeEnvelopeInternal(isLinear)) + envelope(computeEnvelopeInternal(isLinear)), + points(newCoords ? std::move(newCoords) : std::make_unique()) { } +void +SimpleCurve::apply_ro(CoordinateFilter* filter) const +{ + assert(points.get()); + points->apply_ro(filter); +} + +void +SimpleCurve::apply_ro(CoordinateSequenceFilter& filter) const +{ + std::size_t npts = points->size(); + if (!npts) { + return; + } + for (std::size_t i = 0; i < npts; ++i) { + filter.filter_ro(*points, i); + if (filter.isDone()) { + break; + } + } +} + +void +SimpleCurve::apply_rw(const CoordinateFilter* filter) +{ + assert(points.get()); + points->apply_rw(filter); +} + +void +SimpleCurve::apply_rw(CoordinateSequenceFilter& filter) +{ + std::size_t npts = points->size(); + if (!npts) { + return; + } + for (std::size_t i = 0; i < npts; ++i) { + filter.filter_rw(*points, i); + if (filter.isDone()) { + break; + } + } + if (filter.isGeometryChanged()) { + geometryChanged(); + } +} + +int +SimpleCurve::compareToSameClass(const Geometry* ls) const +{ + const SimpleCurve* line = detail::down_cast(ls); + + // MD - optimized implementation + std::size_t mynpts = points->getSize(); + std::size_t othnpts = line->points->getSize(); + if (mynpts > othnpts) { + return 1; + } + if (mynpts < othnpts) { + return -1; + } + for (std::size_t i = 0; i < mynpts; i++) { + int cmp = points->getAt(i).compareTo(line->points->getAt(i)); + if (cmp) { + return cmp; + } + } + return 0; +} + Envelope SimpleCurve::computeEnvelopeInternal(bool isLinear) const { - if(isEmpty()) { + if (isEmpty()) { return Envelope(); } - if(isLinear) { + if (isLinear) { return points->getEnvelope(); - } else { + } + else { Envelope e; for (std::size_t i = 2; i < points->size(); i++) { algorithm::CircularArcs::expandEnvelope(e, @@ -68,36 +139,65 @@ SimpleCurve::computeEnvelopeInternal(bool isLinear) const } } -std::unique_ptr -SimpleCurve::getCoordinates() const +bool +SimpleCurve::equalsExact(const Geometry* other, double tolerance) const { - assert(points.get()); - return points->clone(); + if (!isEquivalentClass(other)) { + return false; + } + + const SimpleCurve* otherCurve = detail::down_cast(other); + std::size_t npts = points->getSize(); + if (npts != otherCurve->points->getSize()) { + return false; + } + for (std::size_t i = 0; i < npts; ++i) { + if (!equal(points->getAt(i), otherCurve->points->getAt(i), tolerance)) { + return false; + } + } + return true; } -const CoordinateSequence* -SimpleCurve::getCoordinatesRO() const +bool +SimpleCurve::equalsIdentical(const Geometry* other_g) const { - assert(nullptr != points.get()); - return points.get(); + if (!isEquivalentClass(other_g)) { + return false; + } + + const auto& other = static_cast(*other_g); + + if (envelope != other.envelope) { + return false; + } + + return getCoordinatesRO()->equalsIdentical(*other.getCoordinatesRO()); } -std::unique_ptr -SimpleCurve::releaseCoordinates() +std::unique_ptr +SimpleCurve::getBoundary() const { - auto newPts = std::make_unique(0u, points->hasZ(), points->hasM()); - auto ret = std::move(points); - points = std::move(newPts); - geometryChanged(); - return ret; + operation::BoundaryOp bop(*this); + return bop.getBoundary(); } +int +SimpleCurve::getBoundaryDimension() const +{ + if (isClosed()) { + return Dimension::False; + } + return 0; +} -const Coordinate& -SimpleCurve::getCoordinateN(std::size_t n) const +const CoordinateXY* +SimpleCurve::getCoordinate() const { - assert(points.get()); - return points->getAt(n); + if (isEmpty()) { + return nullptr; + } + return &(points->getAt(0)); } uint8_t @@ -106,33 +206,34 @@ SimpleCurve::getCoordinateDimension() const return (uint8_t) points->getDimension(); } -bool -SimpleCurve::hasM() const +const Coordinate& +SimpleCurve::getCoordinateN(std::size_t n) const { - return points->hasM(); + assert(points.get()); + return points->getAt(n); } -bool -SimpleCurve::hasZ() const +std::unique_ptr +SimpleCurve::getCoordinates() const { - return points->hasZ(); + assert(points.get()); + return points->clone(); } -int -SimpleCurve::getBoundaryDimension() const +const CoordinateSequence* +SimpleCurve::getCoordinatesRO() const { - if(isClosed()) { - return Dimension::False; - } - return 0; + assert(nullptr != points.get()); + return points.get(); } - -bool -SimpleCurve::isEmpty() const +std::unique_ptr +SimpleCurve::getEndPoint() const { - assert(points.get()); - return points->isEmpty(); + if (isEmpty()) { + return nullptr; + } + return getPointN(getNumPoints() - 1); } std::size_t @@ -153,125 +254,84 @@ SimpleCurve::getPointN(std::size_t n) const std::unique_ptr SimpleCurve::getStartPoint() const { - if(isEmpty()) { + if (isEmpty()) { return nullptr; } return getPointN(0); } -std::unique_ptr -SimpleCurve::getEndPoint() const +bool +SimpleCurve::hasM() const { - if(isEmpty()) { - return nullptr; - } - return getPointN(getNumPoints() - 1); + return points->hasM(); +} + +bool +SimpleCurve::hasZ() const +{ + return points->hasZ(); } bool SimpleCurve::isClosed() const { - if(isEmpty()) { + if (isEmpty()) { return false; } return points->front().equals2D(points->back()); } -std::unique_ptr -SimpleCurve::getBoundary() const -{ - operation::BoundaryOp bop(*this); - return bop.getBoundary(); -} - bool SimpleCurve::isCoordinate(CoordinateXY& pt) const { assert(points.get()); std::size_t npts = points->getSize(); - for(std::size_t i = 0; i < npts; i++) { - if(points->getAt(i) == pt) { + for (std::size_t i = 0; i < npts; i++) { + if (points->getAt(i) == pt) { return true; } } return false; } -const CoordinateXY* -SimpleCurve::getCoordinate() const -{ - if(isEmpty()) { - return nullptr; - } - return &(points->getAt(0)); -} - -bool -SimpleCurve::equalsExact(const Geometry* other, double tolerance) const -{ - if(!isEquivalentClass(other)) { - return false; - } - - const SimpleCurve* otherCurve = detail::down_cast(other); - std::size_t npts = points->getSize(); - if(npts != otherCurve->points->getSize()) { - return false; - } - for(std::size_t i = 0; i < npts; ++i) { - if(!equal(points->getAt(i), otherCurve->points->getAt(i), tolerance)) { - return false; - } - } - return true; -} - bool -SimpleCurve::equalsIdentical(const Geometry* other_g) const +SimpleCurve::isEmpty() const { - if(!isEquivalentClass(other_g)) { - return false; - } - - const auto& other = static_cast(*other_g); - - if (envelope != other.envelope) { - return false; - } - - return getCoordinatesRO()->equalsIdentical(*other.getCoordinatesRO()); + assert(points.get()); + return points->isEmpty(); } -int -SimpleCurve::compareToSameClass(const Geometry* ls) const +/*public*/ +void +SimpleCurve::normalize() { - const SimpleCurve* line = detail::down_cast(ls); + util::ensureNotCurvedType(*this); - // MD - optimized implementation - std::size_t mynpts = points->getSize(); - std::size_t othnpts = line->points->getSize(); - if(mynpts > othnpts) { - return 1; - } - if(mynpts < othnpts) { - return -1; + if (isEmpty()) return; + assert(points.get()); + if (isClosed()) { + normalizeClosed(); + return; } - for(std::size_t i = 0; i < mynpts; i++) { - int cmp = points->getAt(i).compareTo(line->points->getAt(i)); - if(cmp) { - return cmp; + std::size_t npts = points->getSize(); + std::size_t n = npts / 2; + for (std::size_t i = 0; i < n; i++) { + std::size_t j = npts - 1 - i; + if (!(points->getAt(i) == points->getAt(j))) { + if (points->getAt(i).compareTo(points->getAt(j)) > 0) { + points->reverse(); + } + return; } } - return 0; } - /*private*/ void SimpleCurve::normalizeClosed() { - if(isEmpty()) { + if (isEmpty()) { return; } @@ -287,87 +347,21 @@ SimpleCurve::normalizeClosed() CoordinateSequence::scroll(coords.get(), minCoordinate); coords->closeRing(true); - if(coords->size() >= 4 && algorithm::Orientation::isCCW(coords.get())) { + if (coords->size() >= 4 && algorithm::Orientation::isCCW(coords.get())) { coords->reverse(); } points = std::move(coords); } - -/*public*/ -void -SimpleCurve::normalize() -{ - util::ensureNotCurvedType(*this); - - if (isEmpty()) return; - assert(points.get()); - if (isClosed()) { - normalizeClosed(); - return; - } - std::size_t npts = points->getSize(); - std::size_t n = npts / 2; - for(std::size_t i = 0; i < n; i++) { - std::size_t j = npts - 1 - i; - if(!(points->getAt(i) == points->getAt(j))) { - if(points->getAt(i).compareTo(points->getAt(j)) > 0) { - points->reverse(); - } - return; - } - } -} - - -void -SimpleCurve::apply_rw(const CoordinateFilter* filter) -{ - assert(points.get()); - points->apply_rw(filter); -} - -void -SimpleCurve::apply_ro(CoordinateFilter* filter) const -{ - assert(points.get()); - points->apply_ro(filter); -} - - -void -SimpleCurve::apply_rw(CoordinateSequenceFilter& filter) -{ - std::size_t npts = points->size(); - if(!npts) { - return; - } - for(std::size_t i = 0; i < npts; ++i) { - filter.filter_rw(*points, i); - if(filter.isDone()) { - break; - } - } - if(filter.isGeometryChanged()) { - geometryChanged(); - } -} - -void -SimpleCurve::apply_ro(CoordinateSequenceFilter& filter) const +std::unique_ptr +SimpleCurve::releaseCoordinates() { - std::size_t npts = points->size(); - if(!npts) { - return; - } - for(std::size_t i = 0; i < npts; ++i) { - filter.filter_ro(*points, i); - if(filter.isDone()) { - break; - } - } - //if (filter.isGeometryChanged()) geometryChanged(); + auto newPts = std::make_unique(0u, points->hasZ(), points->hasM()); + auto ret = std::move(points); + points = std::move(newPts); + geometryChanged(); + return ret; } } // namespace geos::geom diff --git a/src/geom/Surface.cpp b/src/geom/Surface.cpp index 343dfb1e8..34bb5c601 100644 --- a/src/geom/Surface.cpp +++ b/src/geom/Surface.cpp @@ -37,24 +37,13 @@ Surface::apply_ro(CoordinateFilter* filter) const } void -Surface::apply_rw(const CoordinateFilter* filter) -{ - getExteriorRing()->apply_rw(filter); - for (std::size_t i = 0; i < getNumInteriorRing(); i++) { - getInteriorRingN(i)->apply_rw(filter); - } -} - -void -Surface::apply_rw(GeometryFilter* filter) +Surface::apply_ro(CoordinateSequenceFilter& filter) const { - filter->filter_rw(this); -} + getExteriorRing()->apply_ro(filter); -void -Surface::apply_ro(GeometryFilter* filter) const -{ - filter->filter_ro(this); + for (std::size_t i = 0; !filter.isDone() && i < getNumInteriorRing(); i++) { + getInteriorRingN(i)->apply_ro(filter); + } } void @@ -68,11 +57,16 @@ Surface::apply_ro(GeometryComponentFilter* filter) const } void -Surface::apply_rw(GeometryComponentFilter* filter) +Surface::apply_ro(GeometryFilter* filter) const +{ + filter->filter_ro(this); +} + +void +Surface::apply_rw(const CoordinateFilter* filter) { - filter->filter_rw(this); getExteriorRing()->apply_rw(filter); - for (std::size_t i = 0; !filter->isDone() && i < getNumInteriorRing(); i++) { + for (std::size_t i = 0; i < getNumInteriorRing(); i++) { getInteriorRingN(i)->apply_rw(filter); } } @@ -92,15 +86,21 @@ Surface::apply_rw(CoordinateSequenceFilter& filter) } void -Surface::apply_ro(CoordinateSequenceFilter& filter) const +Surface::apply_rw(GeometryComponentFilter* filter) { - getExteriorRing()->apply_ro(filter); - - for (std::size_t i = 0; !filter.isDone() && i < getNumInteriorRing(); i++) { - getInteriorRingN(i)->apply_ro(filter); + filter->filter_rw(this); + getExteriorRing()->apply_rw(filter); + for (std::size_t i = 0; !filter->isDone() && i < getNumInteriorRing(); i++) { + getInteriorRingN(i)->apply_rw(filter); } } +void +Surface::apply_rw(GeometryFilter* filter) +{ + filter->filter_rw(this); +} + int Surface::compareToSameClass(const Geometry* g) const { @@ -136,6 +136,11 @@ Surface::convexHull() const return getExteriorRing()->convexHull(); } +std::unique_ptr +Surface::createEmptyRing(const GeometryFactory& factory) +{ + return factory.createLinearRing(); +} bool Surface::equalsExact(const Geometry* other, double tolerance) const @@ -222,6 +227,17 @@ Surface::getEnvelopeInternal() const return getExteriorRing()->getEnvelopeInternal(); } +double +Surface::getLength() const +{ + double len = 0.0; + len += getExteriorRing()->getLength(); + for (std::size_t i = 0; i < getNumInteriorRing(); i++) { + len += getInteriorRingN(i)->getLength(); + } + return len; +} + size_t Surface::getNumPoints() const { @@ -266,20 +282,5 @@ Surface::isEmpty() const return getExteriorRing()->isEmpty(); } -double Surface::getLength() const { - double len = 0.0; - len += getExteriorRing()->getLength(); - for(std::size_t i = 0; i < getNumInteriorRing(); i++) { - len += getInteriorRingN(i)->getLength(); - } - return len; -} - -std::unique_ptr -Surface::createEmptyRing(const GeometryFactory& factory) -{ - return factory.createLinearRing(); -} - } }