|
| 1 | +// Python Source: shapely/geometry/collection.py |
| 2 | +// Line Range: L10-L60 (class GeometryCollection) |
| 3 | +// Alignment: strict |
| 4 | +// EXEMPTION: cpp_non_template |
| 5 | +// Reason: GeometryCollection can hold mixed types; non-template for simplicity. |
| 6 | + |
| 7 | +#pragma once |
| 8 | + |
| 9 | +#include <memory> |
| 10 | +#include <vector> |
| 11 | +#include <string> |
| 12 | +#include <cstddef> |
| 13 | +#include <geos/geom/GeometryFactory.h> |
| 14 | +#include <geos/geom/GeometryCollection.h> |
| 15 | +#include <geos/geom/Geometry.h> |
| 16 | + |
| 17 | +namespace shapely { |
| 18 | +namespace geometry { |
| 19 | + |
| 20 | +class GeometryCollection { |
| 21 | +public: |
| 22 | + GeometryCollection(); |
| 23 | + |
| 24 | + /// Add any GEOS geometry (advanced usage) |
| 25 | + void add_geometry(std::unique_ptr<geos::geom::Geometry> geom); |
| 26 | + |
| 27 | + GeometryCollection(GeometryCollection&&) = default; |
| 28 | + GeometryCollection& operator=(GeometryCollection&&) = default; |
| 29 | + |
| 30 | + // -- Access to individual geometries -- |
| 31 | + size_t num_geometries() const; |
| 32 | + const geos::geom::Geometry* geometry_n(size_t i) const; |
| 33 | + |
| 34 | + // -- Predicates with another GeometryCollection -- |
| 35 | + bool contains(const GeometryCollection& other) const; |
| 36 | + bool within(const GeometryCollection& other) const; |
| 37 | + bool disjoint(const GeometryCollection& other) const; |
| 38 | + bool overlaps(const GeometryCollection& other) const; |
| 39 | + bool touches(const GeometryCollection& other) const; |
| 40 | + bool equals(const GeometryCollection& other) const; |
| 41 | + bool equals_exact(const GeometryCollection& other, double tol) const; |
| 42 | + bool intersects(const GeometryCollection& other) const; |
| 43 | + std::string relate(const GeometryCollection& other) const; |
| 44 | + bool relate_pattern(const GeometryCollection& other, const std::string& p) const; |
| 45 | + double hausdorff_distance(const GeometryCollection& other) const; |
| 46 | + |
| 47 | + // -- Constructive operations -- |
| 48 | + GeometryCollection difference(const GeometryCollection& other) const; |
| 49 | + GeometryCollection intersection(const GeometryCollection& other) const; |
| 50 | + GeometryCollection union_op(const GeometryCollection& other) const; |
| 51 | + GeometryCollection sym_difference(const GeometryCollection& other) const; |
| 52 | + GeometryCollection simplify(double tolerance) const; |
| 53 | + |
| 54 | + // -- Accessors -- |
| 55 | + std::string wkt() const; |
| 56 | + std::string wkb_hex() const; |
| 57 | + std::string type() const; |
| 58 | + std::string geom_type() const; |
| 59 | + bool has_z() const; |
| 60 | + |
| 61 | + // -- Properties -- |
| 62 | + bool is_empty() const; |
| 63 | + bool is_simple() const; |
| 64 | + bool is_valid() const; |
| 65 | + double area() const; |
| 66 | + double length() const; |
| 67 | + std::vector<double> bounds() const; |
| 68 | + |
| 69 | + // -- Topology -- |
| 70 | + GeometryCollection convex_hull() const; |
| 71 | + GeometryCollection buffer(double distance) const; |
| 72 | + void normalize(); |
| 73 | + |
| 74 | + // -- Access to internal GEOS geometry (for interop) -- |
| 75 | + const geos::geom::GeometryCollection* geos_collection() const { return geos_coll_.get(); } |
| 76 | + |
| 77 | +private: |
| 78 | + std::unique_ptr<geos::geom::GeometryCollection> geos_coll_; |
| 79 | + geos::geom::GeometryFactory::Ptr factory_; |
| 80 | +}; |
| 81 | + |
| 82 | +} // namespace geometry |
| 83 | +} // namespace shapely |
| 84 | + |
| 85 | +// ============================================================================ |
| 86 | +// Implementation |
| 87 | +// ============================================================================ |
| 88 | + |
| 89 | +#include "shapely/geometry/base.h" |
| 90 | +#include <geos/geom/Coordinate.h> |
| 91 | +#include <geos/operation/distance/DistanceOp.h> |
| 92 | +#include <stdexcept> |
| 93 | + |
| 94 | +namespace shapely { |
| 95 | +namespace geometry { |
| 96 | + |
| 97 | +GeometryCollection::GeometryCollection() { |
| 98 | + factory_ = geos::geom::GeometryFactory::create(); |
| 99 | + geos_coll_ = factory_->createGeometryCollection(); |
| 100 | +} |
| 101 | + |
| 102 | +void GeometryCollection::add_geometry(std::unique_ptr<geos::geom::Geometry> geom) { |
| 103 | + if (!geom) return; |
| 104 | + std::vector<std::unique_ptr<geos::geom::Geometry>> geoms; |
| 105 | + for (size_t i = 0; i < geos_coll_->getNumGeometries(); ++i) |
| 106 | + geoms.push_back(std::unique_ptr<geos::geom::Geometry>(geos_coll_->getGeometryN(i)->clone())); |
| 107 | + geoms.push_back(std::move(geom)); |
| 108 | + geos_coll_ = factory_->createGeometryCollection(std::move(geoms)); |
| 109 | +} |
| 110 | + |
| 111 | +size_t GeometryCollection::num_geometries() const { return geos_coll_->getNumGeometries(); } |
| 112 | + |
| 113 | +const geos::geom::Geometry* GeometryCollection::geometry_n(size_t i) const { |
| 114 | + return geos_coll_->getGeometryN(i); |
| 115 | +} |
| 116 | + |
| 117 | +// -- Predicates (delegate to GEOS) ------------------------------------------- |
| 118 | +#define GC_PRED(METHOD, GEOS_FN) \ |
| 119 | +bool GeometryCollection::METHOD(const GeometryCollection& o) const { return detail::GEOS_FN(geos_coll_.get(), o.geos_coll_.get()); } |
| 120 | +GC_PRED(contains, geos_contains) |
| 121 | +GC_PRED(within, geos_within) |
| 122 | +GC_PRED(disjoint, geos_disjoint) |
| 123 | +GC_PRED(overlaps, geos_overlaps) |
| 124 | +GC_PRED(touches, geos_touches) |
| 125 | +GC_PRED(equals, geos_equals) |
| 126 | +#undef GC_PRED |
| 127 | + |
| 128 | +bool GeometryCollection::equals_exact(const GeometryCollection& o, double tol) const { |
| 129 | + return detail::geos_equals_exact(geos_coll_.get(), o.geos_coll_.get(), tol); |
| 130 | +} |
| 131 | +bool GeometryCollection::intersects(const GeometryCollection& o) const { |
| 132 | + return geos_coll_->intersects(o.geos_coll_.get()); |
| 133 | +} |
| 134 | +std::string GeometryCollection::relate(const GeometryCollection& o) const { |
| 135 | + return detail::geos_relate(geos_coll_.get(), o.geos_coll_.get()); |
| 136 | +} |
| 137 | +bool GeometryCollection::relate_pattern(const GeometryCollection& o, const std::string& p) const { |
| 138 | + return detail::geos_relate_pattern(geos_coll_.get(), o.geos_coll_.get(), p); |
| 139 | +} |
| 140 | +double GeometryCollection::hausdorff_distance(const GeometryCollection& o) const { |
| 141 | + return detail::geos_hausdorff_distance(geos_coll_.get(), o.geos_coll_.get()); |
| 142 | +} |
| 143 | + |
| 144 | +// -- Constructive operations ----------------------------------------------- |
| 145 | +#define GC_CONSTRUCT(OP, GEOS_FN) \ |
| 146 | +GeometryCollection GeometryCollection::OP(const GeometryCollection& o) const { \ |
| 147 | + auto res = detail::GEOS_FN(geos_coll_.get(), o.geos_coll_.get()); \ |
| 148 | + GeometryCollection r; \ |
| 149 | + if (res && !res->isEmpty()) { \ |
| 150 | + for (size_t i = 0; i < res->getNumGeometries(); ++i) \ |
| 151 | + r.add_geometry(std::unique_ptr<geos::geom::Geometry>(res->getGeometryN(i)->clone())); \ |
| 152 | + } \ |
| 153 | + return r; \ |
| 154 | +} |
| 155 | +GC_CONSTRUCT(difference, geos_difference) |
| 156 | +GC_CONSTRUCT(intersection, geos_intersection) |
| 157 | +GC_CONSTRUCT(union_op, geos_union) |
| 158 | +GC_CONSTRUCT(sym_difference, geos_sym_difference) |
| 159 | +#undef GC_CONSTRUCT |
| 160 | + |
| 161 | +GeometryCollection GeometryCollection::simplify(double tol) const { |
| 162 | + auto res = detail::geos_simplify(geos_coll_.get(), tol); |
| 163 | + GeometryCollection r; |
| 164 | + if (res && !res->isEmpty()) { |
| 165 | + for (size_t i = 0; i < res->getNumGeometries(); ++i) |
| 166 | + r.add_geometry(std::unique_ptr<geos::geom::Geometry>(res->getGeometryN(i)->clone())); |
| 167 | + } |
| 168 | + return r; |
| 169 | +} |
| 170 | + |
| 171 | +// -- Accessors --------------------------------------------------------------- |
| 172 | +std::string GeometryCollection::wkt() const { return detail::geos_to_wkt(geos_coll_.get()); } |
| 173 | +std::string GeometryCollection::wkb_hex() const { return detail::geos_to_wkb_hex(geos_coll_.get()); } |
| 174 | +std::string GeometryCollection::type() const { return "GeometryCollection"; } |
| 175 | +std::string GeometryCollection::geom_type() const { return detail::geos_geom_type(geos_coll_.get()); } |
| 176 | +bool GeometryCollection::has_z() const { return detail::geos_has_z(geos_coll_.get()); } |
| 177 | + |
| 178 | +// -- Properties --------------------------------------------------------------- |
| 179 | +bool GeometryCollection::is_empty() const { return detail::geos_is_empty(geos_coll_.get()); } |
| 180 | +bool GeometryCollection::is_simple() const { return detail::geos_is_simple(geos_coll_.get()); } |
| 181 | +bool GeometryCollection::is_valid() const { return detail::geos_is_valid(geos_coll_.get()); } |
| 182 | +double GeometryCollection::area() const { return geos_coll_->getArea(); } |
| 183 | +double GeometryCollection::length() const { return geos_coll_->getLength(); } |
| 184 | +std::vector<double> GeometryCollection::bounds() const { return detail::geos_bounds(geos_coll_.get()); } |
| 185 | + |
| 186 | +// -- Topology ------------------------------------------------------------------ |
| 187 | +GeometryCollection GeometryCollection::convex_hull() const { |
| 188 | + auto res = detail::geos_convex_hull(geos_coll_.get()); |
| 189 | + GeometryCollection r; |
| 190 | + if (res && !res->isEmpty()) { |
| 191 | + for (size_t i = 0; i < res->getNumGeometries(); ++i) |
| 192 | + r.add_geometry(std::unique_ptr<geos::geom::Geometry>(res->getGeometryN(i)->clone())); |
| 193 | + } |
| 194 | + return r; |
| 195 | +} |
| 196 | + |
| 197 | +GeometryCollection GeometryCollection::buffer(double distance) const { |
| 198 | + auto buf = geos_coll_->buffer(distance, 16); |
| 199 | + GeometryCollection r; |
| 200 | + if (buf && !buf->isEmpty()) { |
| 201 | + for (size_t i = 0; i < buf->getNumGeometries(); ++i) |
| 202 | + r.add_geometry(std::unique_ptr<geos::geom::Geometry>(buf->getGeometryN(i)->clone())); |
| 203 | + } |
| 204 | + return r; |
| 205 | +} |
| 206 | + |
| 207 | +void GeometryCollection::normalize() { geos_coll_->normalize(); } |
| 208 | + |
| 209 | +} // namespace geometry |
| 210 | +} // namespace shapely |
0 commit comments