Fishnet 2.0.1
Framework for Graph-Based Analysis of GIS Vector Data
Loading...
Searching...
No Matches
MultiPolygon.hpp
Go to the documentation of this file.
1#pragma once
2#include <algorithm>
3#include <ranges>
8#include "Vec2D.hpp"
9#include "Ring.hpp"
10#include "Rectangle.hpp"
11
12namespace fishnet::geometry{
13
19template<IPolygon P>
21private:
22 std::vector<P> polygons;
23
24 constexpr inline bool anyOf(util::Predicate<P> auto && predicate) const noexcept{
25 return std::ranges::any_of(polygons,predicate);
26 }
27
34 constexpr std::optional<std::string> tryAddGetCauseOnError(const P & polygon) noexcept {
35 for(const auto & p : polygons){
36 if(p == polygon)
37 return "Duplicate polygon: "+p.toString();
38 if(p.crosses(polygon))
39 return "Polygon: "+polygon.toString()+"\nintersects another polygon:\n"+p.toString();
40 if(p.contains(polygon) || polygon.contains(p))
41 return "Polygons are contained within each other:\n"+polygon.toString()+"\n and \n"+p.toString();
42 }
43 polygons.push_back(polygon);
44 return {};
45 }
46
47 constexpr void addOrThrow(const P & polygon) {
48 auto error = tryAddGetCauseOnError(polygon);
49 if(error)
50 throw InvalidGeometryException(error.value());
51 }
52
53
54public:
55 using numeric_type = typename P::numeric_type;
56 using polygon_type = P;
57 constexpr static GeometryType type = GeometryType::MULTIPOLYGON;
58
65 MultiPolygon(util::input_range_of<P> auto && polygonsRange,bool checked =false){
66 if (checked){
67 this->polygons = std::vector<P>(std::ranges::begin(polygonsRange),std::ranges::end(polygonsRange));
68 }else{
69 if(util::size(polygonsRange) < 10) // use brute force for small multi-polygons (< 10 polygons)
70 std::ranges::for_each(polygonsRange,[this](const P & p){addOrThrow(p);});
71 else {
72 // use sweep-line for large multi-polygons, filter out invalid entries
73 this->polygons = filter(polygonsRange,[](const P & lhs, const P & rhs){
74 return not( lhs == rhs || lhs.crosses(rhs) || lhs.contains(rhs) || rhs.contains(lhs));
75 });
76 }
77 }
78 }
79
80 MultiPolygon(const P & polygon):polygons({polygon}) {}
81
82 MultiPolygon(const P & polygon, const P & otherPolygon){
83 addOrThrow(polygon);
84 addOrThrow(otherPolygon);
85 }
86
95 template<typename... Args>
96 MultiPolygon(const P & current, const P & next, Args... remaining):MultiPolygon(next,remaining...){
97 addOrThrow(current);
98 }
99
100 constexpr util::view_of<P> auto getPolygons() const noexcept{
101 return std::views::all(polygons);
102 }
103
112 template<bool checked=false>
113 constexpr bool addPolygon(const P & polygon) noexcept {
114 if constexpr(checked){
115 this->polygons.push_back(polygon);
116 return true;
117 }else {
118 return not tryAddGetCauseOnError(polygon).has_value();
119 }
120 }
121
122 constexpr bool removePolygon(const P & polygon) noexcept {
123 auto [position,end] = std::ranges::remove(polygons,polygon);
124 if(position==end)
125 return false;
126 polygons.erase(position,end);
127 return true;
128 }
129
130
131 constexpr fishnet::math::DEFAULT_FLOATING_POINT area() const noexcept {
132 auto viewOnPolygonArea = std::views::all(polygons) | std::views::transform([](const P & p){return p.area();});
133 return std::accumulate(std::ranges::begin(viewOnPolygonArea),std::ranges::end(viewOnPolygonArea),0.0);
134 }
135
141 constexpr Vec2DReal centroid() const noexcept {
142 Vec2DReal accumulatedWeightedCentroid {0.0,0.0};
144 for(const auto & polygon: polygons) {
145 accumulatedWeightedCentroid = accumulatedWeightedCentroid + polygon.centroid() * (polygon.area() / totalArea);
146 }
147 return accumulatedWeightedCentroid;
148 }
149
150 constexpr bool contains(IPoint auto const & point) const noexcept {
151 return anyOf([&point](const P & p){return p.contains(point);});
152 }
153
154 constexpr bool contains(ISegment auto const & segment) const noexcept{
155 return anyOf([&segment](const P & p){return p.contains(segment);});
156 }
157
158 constexpr bool isInside(IPoint auto const & point ) const noexcept {
159 return anyOf([&point](const P & p){return p.isInside(point);});
160 }
161
162 constexpr bool isOnBoundary(IPoint auto const & point) const noexcept {
163 return anyOf([&point](const P & p){return p.isOnBoundary(point);});
164 }
165
166 constexpr bool isOutside(IPoint auto const & point) const noexcept {
167 return std::ranges::all_of(polygons,[&point](const P & p){return p.isOutside(point);});
168 }
169
170 constexpr bool intersects(LinearGeometry auto const & linearFeature) const noexcept {
171 return anyOf([&linearFeature](const P & p){return p.intersects(linearFeature);});
172 }
173
174 constexpr std::unordered_set<Vec2DReal> intersections(LinearGeometry auto const & linearGeometry) const noexcept {
175 std::unordered_set<Vec2DReal> intersectionSet;
176 std::ranges::for_each(polygons,[&intersectionSet,&linearGeometry](const P & p){
177 std::ranges::for_each(p.intersections(linearGeometry),[&intersectionSet](const auto & point){
178 intersectionSet.insert(point);
179 });
180 });
181 return intersectionSet;
182 }
183
184 constexpr bool contains(IPolygon auto const & query) const noexcept {
185 return anyOf([&query](const P & p){return p.contains(query);});
186 }
187
188 constexpr bool crosses(IPolygon auto const & query) const noexcept {
189 return anyOf([&query](const P & p){return p.crosses(query);});
190 }
191
192 constexpr bool touches(IPolygon auto const & query) const noexcept {
193 return not contains(query) && not crosses(query) && anyOf([&query](const P & p){return p.touches(query);});
194 }
195
196 constexpr bool containsInHole(IPolygon auto const & query) const noexcept {
197 return anyOf([&query](const P & p){return p.containsInHole(query);});
198 }
199
200 constexpr fishnet::math::DEFAULT_FLOATING_POINT distance(IPolygon auto const & query) const noexcept {
201 return std::ranges::min(this->getPolygons() | std::views::transform([&query](const P & p){return p.distance(query);}));
202 }
203
204 constexpr fishnet::math::DEFAULT_FLOATING_POINT distance(IMultiPolygon auto const & other) const noexcept {
205 return std::ranges::min( other.getPolygons() | std::views::transform([this](const auto & otherPolygon){return this->distance(otherPolygon);}));
206 }
207
208 constexpr Rectangle<numeric_type> aaBB() const noexcept {
209 auto initialPoint = std::ranges::begin(this->polygons.at(0).getBoundary().getSegments())->p();
210 numeric_type high = initialPoint.y;
211 numeric_type low = high;
212 numeric_type right = initialPoint.x;
213 numeric_type left = right;
214 auto viewOnAllSegments = this->getPolygons()
215 | std::views::transform([](const P & p){return p.getBoundary().getSegments();})
216 | std::views::join;
217 for(const auto s: viewOnAllSegments){
218 auto p = s.p();
219 if(p.y > high)
220 high = p.y;
221 if(p.y < low)
222 low = p.y;
223 if(p.x > right)
224 right = p.x;
225 if(p.x < left)
226 left = p.x;
227 }
228 return Rectangle<numeric_type>(left,high,right,low);
229 }
230
231 template<IPolygon Q>
232 constexpr bool operator==(const MultiPolygon<Q> & other) const noexcept {
233 if(util::size(this->polygons) != util::size(other.getPolygons()))
234 return false;
235 for(const auto & p: other.getPolygons()){
236 auto foundIt = std::ranges::find(this->polygons,p);
237 if(foundIt == std::ranges::end(this->getPolygons()))
238 return false;
239 }
240 return true;
241 }
242
243 constexpr size_t hash() const noexcept {
244 auto polygonHashes = this->getPolygons() | std::views::transform([](const auto & p){return p.hash();});
245 return std::accumulate(std::ranges::begin(polygonHashes),std::ranges::end(polygonHashes),size_t(0));
246 }
247
248 constexpr std::string toString() const noexcept {
249 std::ostringstream oss;
250 oss << "{";
251 bool first = true;
252 for(const auto & p : this->polygons){
253 if(!first) oss << "|";
254 oss << p.toString();
255 first = false;
256 }
257 oss << "}";
258 return oss.str();
259 }
260};
261} // namespace fishnet::geometry
Exception class for geometry-related errors.
Definition InvalidGeometryException.hpp:10
Implementation of a Multi-Polygon.
Definition MultiPolygon.hpp:20
constexpr Rectangle< numeric_type > aaBB() const noexcept
Definition MultiPolygon.hpp:208
P polygon_type
Definition MultiPolygon.hpp:56
constexpr fishnet::math::DEFAULT_FLOATING_POINT distance(IMultiPolygon auto const &other) const noexcept
Definition MultiPolygon.hpp:204
constexpr util::view_of< P > auto getPolygons() const noexcept
Definition MultiPolygon.hpp:100
constexpr bool contains(IPolygon auto const &query) const noexcept
Definition MultiPolygon.hpp:184
static constexpr GeometryType type
Definition MultiPolygon.hpp:57
MultiPolygon(util::input_range_of< P > auto &&polygonsRange, bool checked=false)
Construct a new Multi Polygon object.
Definition MultiPolygon.hpp:65
constexpr bool removePolygon(const P &polygon) noexcept
Definition MultiPolygon.hpp:122
constexpr bool isInside(IPoint auto const &point) const noexcept
Definition MultiPolygon.hpp:158
constexpr fishnet::math::DEFAULT_FLOATING_POINT distance(IPolygon auto const &query) const noexcept
Definition MultiPolygon.hpp:200
constexpr bool operator==(const MultiPolygon< Q > &other) const noexcept
Definition MultiPolygon.hpp:232
MultiPolygon(const P &current, const P &next, Args... remaining)
VarArg constructor of a new Multi Polygon object.
Definition MultiPolygon.hpp:96
constexpr bool isOnBoundary(IPoint auto const &point) const noexcept
Definition MultiPolygon.hpp:162
constexpr std::string toString() const noexcept
Definition MultiPolygon.hpp:248
constexpr Vec2DReal centroid() const noexcept
Computes centroid point of multi-polygon, by weighting the centroid point of each polygon with its ar...
Definition MultiPolygon.hpp:141
constexpr fishnet::math::DEFAULT_FLOATING_POINT area() const noexcept
Definition MultiPolygon.hpp:131
constexpr bool containsInHole(IPolygon auto const &query) const noexcept
Definition MultiPolygon.hpp:196
constexpr bool crosses(IPolygon auto const &query) const noexcept
Definition MultiPolygon.hpp:188
constexpr size_t hash() const noexcept
Definition MultiPolygon.hpp:243
constexpr bool touches(IPolygon auto const &query) const noexcept
Definition MultiPolygon.hpp:192
constexpr std::unordered_set< Vec2DReal > intersections(LinearGeometry auto const &linearGeometry) const noexcept
Definition MultiPolygon.hpp:174
constexpr bool contains(ISegment auto const &segment) const noexcept
Definition MultiPolygon.hpp:154
constexpr bool contains(IPoint auto const &point) const noexcept
Definition MultiPolygon.hpp:150
typename P::numeric_type numeric_type
Definition MultiPolygon.hpp:55
MultiPolygon(const P &polygon, const P &otherPolygon)
Definition MultiPolygon.hpp:82
constexpr bool addPolygon(const P &polygon) noexcept
Add Polygon to the multi-polygon.
Definition MultiPolygon.hpp:113
constexpr bool intersects(LinearGeometry auto const &linearFeature) const noexcept
Definition MultiPolygon.hpp:170
MultiPolygon(const P &polygon)
Definition MultiPolygon.hpp:80
constexpr bool isOutside(IPoint auto const &point) const noexcept
Definition MultiPolygon.hpp:166
Implementation of a rectangle Stores top,right,bottom and left point of the rectangle.
Definition Rectangle.hpp:15
Implementation of a two-dimensional vector.
Definition Vec2D.hpp:16
Interface for a multi-polygon A multi-polygon is a collection of polygons.
Definition IMultiPolygon.hpp:93
Interface for a point.
Definition IPoint.hpp:92
Interface for a polygon A polygon is a two-dimensional shape defined by a boundary and zero or more h...
Definition IPolygon.hpp:98
Interface for a segment A segment is formed between two points p and q, containing only the points on...
Definition ISegment.hpp:105
Definition IGeometry.hpp:13
Definition FunctionalConcepts.hpp:36
Definition CollectionConcepts.hpp:33
Definition CollectionConcepts.hpp:45
Definition BoundingBoxWrapper.hpp:5
GeometryType
Definition GeometryBase.hpp:6
static std::vector< std::ranges::range_value_t< R > > filter(const R &polygons, BinaryFilter binaryCondition, Filter condition=Filter()) noexcept
Filters a range of polygons and returns a list of all polygons that pass the filter(s)
Definition PolygonFilter.hpp:98
double DEFAULT_FLOATING_POINT
Definition NumericConcepts.hpp:12
constexpr size_t size(std::ranges::range auto &&range) noexcept
Definition CollectionConcepts.hpp:50