/src/geos/include/geos/dissolve/LineDissolver.h
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * GEOS - Geometry Engine Open Source |
4 | | * http://geos.osgeo.org |
5 | | * |
6 | | * Copyright (c) 2025 Martin Davis |
7 | | * Copyright (C) 2025 Paul Ramsey <pramsey@cleverelephant.ca> |
8 | | * |
9 | | * This is free software; you can redistribute and/or modify it under |
10 | | * the terms of the GNU Lesser General Public Licence as published |
11 | | * by the Free Software Foundation. |
12 | | * See the COPYING file for more information. |
13 | | * |
14 | | **********************************************************************/ |
15 | | |
16 | | #pragma once |
17 | | |
18 | | #include <geos/dissolve/DissolveEdgeGraph.h> |
19 | | // #include <memory> |
20 | | // #include <vector> |
21 | | // #include <stack> |
22 | | #include <geos/geom/LineString.h> |
23 | | #include <geos/export.h> |
24 | | |
25 | | |
26 | | // Forward declarations |
27 | | namespace geos { |
28 | | namespace dissolve { |
29 | | class DissolveHalfEdge; |
30 | | } |
31 | | namespace edgegraph { |
32 | | class HalfEdge; |
33 | | } |
34 | | namespace geom { |
35 | | class CoordinateSequence; |
36 | | class Geometry; |
37 | | class GeometryFactory; |
38 | | // class LineString; |
39 | | } |
40 | | } |
41 | | |
42 | | |
43 | | namespace geos { // geos. |
44 | | namespace dissolve { // geos.dissolve |
45 | | |
46 | | |
47 | | /** |
48 | | * Dissolves the linear components |
49 | | * from a collection of Geometry |
50 | | * into a set of maximal-length LineString |
51 | | * in which every unique segment appears once only. |
52 | | * The output linestrings run between node vertices |
53 | | * of the input, which are vertices which have |
54 | | * either degree 1, or degree 3 or greater. |
55 | | * |
56 | | * Use cases for dissolving linear components |
57 | | * include generalization |
58 | | * (in particular, simplifying polygonal coverages), |
59 | | * and visualization |
60 | | * (in particular, avoiding symbology conflicts when |
61 | | * depicting shared polygon boundaries). |
62 | | * |
63 | | * This class does **not** node the input lines. |
64 | | * If there are line segments crossing in the input, |
65 | | * they will still cross in the output. |
66 | | * |
67 | | * @author Martin Davis |
68 | | * |
69 | | */ |
70 | | class GEOS_DLL LineDissolver { |
71 | | |
72 | | using CoordinateSequence = geos::geom::CoordinateSequence; |
73 | | using Geometry = geos::geom::Geometry; |
74 | | using GeometryFactory = geos::geom::GeometryFactory; |
75 | | using LineString = geos::geom::LineString; |
76 | | using HalfEdge = geos::edgegraph::HalfEdge; |
77 | | |
78 | | private: |
79 | | |
80 | | std::unique_ptr<Geometry> result; |
81 | | const GeometryFactory* factory = nullptr; |
82 | | DissolveEdgeGraph graph; |
83 | | std::vector<std::unique_ptr<LineString>> lines; |
84 | | std::stack<HalfEdge*> nodeEdgeStack; |
85 | | DissolveHalfEdge* ringStartEdge = nullptr; |
86 | | |
87 | | |
88 | | void computeResult(); |
89 | | |
90 | | void process(HalfEdge* e); |
91 | | |
92 | | /** |
93 | | * Adds edges around this node to the stack. |
94 | | * |
95 | | * @param node |
96 | | */ |
97 | | void stackEdges(HalfEdge* node); |
98 | | |
99 | | /** |
100 | | * For each edge in stack |
101 | | * (which must originate at a node) |
102 | | * extracts the line it initiates. |
103 | | */ |
104 | | void buildLines(); |
105 | | |
106 | | /** |
107 | | * Updates the tracked ringStartEdge |
108 | | * if the given edge has a lower origin |
109 | | * (using the standard Coordinate ordering). |
110 | | * |
111 | | * Identifying the lowest starting node meets two goals: |
112 | | * |
113 | | * * It ensures that isolated input rings are created using the original node and orientation |
114 | | * * For isolated rings formed from multiple input linestrings, |
115 | | * it provides a canonical node and orientation for the output |
116 | | * (rather than essentially random, and thus hard to test). |
117 | | * |
118 | | * @param e |
119 | | */ |
120 | | void updateRingStartEdge(DissolveHalfEdge* e); |
121 | | |
122 | | /** |
123 | | * Builds a line starting from the given edge. |
124 | | * The start edge origin is a node (valence = 1 or >= 3), |
125 | | * unless it is part of a pure ring. |
126 | | * A pure ring has no other incident lines. |
127 | | * In this case the start edge may occur anywhere on the ring. |
128 | | * |
129 | | * The line is built up to the next node encountered, |
130 | | * or until the start edge is re-encountered |
131 | | * (which happens if the edges form a ring). |
132 | | * |
133 | | * @param eStart |
134 | | */ |
135 | | void buildLine(HalfEdge* eStart); |
136 | | |
137 | | void buildRing(HalfEdge* eStartRing); |
138 | | |
139 | | void addLine(std::unique_ptr<CoordinateSequence>& cs); |
140 | | |
141 | | |
142 | | public: |
143 | | |
144 | 0 | LineDissolver() : result(nullptr) {}; |
145 | | |
146 | | /** |
147 | | * Dissolves the linear components in a geometry. |
148 | | * |
149 | | * @param g the geometry to dissolve |
150 | | * @return the dissolved lines |
151 | | */ |
152 | | static std::unique_ptr<Geometry> dissolve(const Geometry* g); |
153 | | |
154 | | /** |
155 | | * Adds a Geometry to be dissolved. |
156 | | * Any number of geometries may be added by calling this method multiple times. |
157 | | * Any type of Geometry may be added. The constituent linework will be |
158 | | * extracted to be dissolved. |
159 | | * |
160 | | * @param geometry geometry to be line-merged |
161 | | */ |
162 | | void add(const Geometry* geometry); |
163 | | |
164 | | /** |
165 | | * Adds a collection of Geometries to be processed. May be called multiple times. |
166 | | * Any dimension of Geometry may be added; the constituent linework will be |
167 | | * extracted. |
168 | | * |
169 | | * @param geometries the geometries to be line-merged |
170 | | */ |
171 | | void add(std::vector<const Geometry*> geometries); |
172 | | |
173 | | void add(const LineString* lineString); |
174 | | |
175 | | /** |
176 | | * Gets the dissolved result as a MultiLineString. |
177 | | * |
178 | | * @return the dissolved lines |
179 | | */ |
180 | | std::unique_ptr<Geometry> getResult(); |
181 | | |
182 | | /** |
183 | | * Disable copy construction and assignment. Needed to make this |
184 | | * class compile under MSVC, because it has a vector<unique_ptr> |
185 | | * as a member. (See https://stackoverflow.com/q/29565299) |
186 | | */ |
187 | | LineDissolver(const LineDissolver&) = delete; |
188 | | LineDissolver& operator=(const LineDissolver&) = delete; |
189 | | |
190 | | |
191 | | }; |
192 | | |
193 | | } // namespace geos.dissolve |
194 | | } // namespace geos |
195 | | |