/src/geos/src/triangulate/quadedge/QuadEdgeSubdivision.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * GEOS - Geometry Engine Open Source |
4 | | * http://geos.osgeo.org |
5 | | * |
6 | | * Copyright (C) 2012 Excensus LLC. |
7 | | * Copyright (C) 2019 Daniel Baston |
8 | | * |
9 | | * This is free software; you can redistribute and/or modify it under |
10 | | * the terms of the GNU Lesser General Licence as published |
11 | | * by the Free Software Foundation. |
12 | | * See the COPYING file for more information. |
13 | | * |
14 | | ********************************************************************** |
15 | | * |
16 | | * Last port: triangulate/quadedge/QuadEdgeSubdivision.java r524 |
17 | | * |
18 | | **********************************************************************/ |
19 | | #include <geos/triangulate/quadedge/QuadEdgeSubdivision.h> |
20 | | |
21 | | #include <algorithm> |
22 | | #include <vector> |
23 | | #include <set> |
24 | | #include <iostream> |
25 | | |
26 | | #include <geos/geom/Polygon.h> |
27 | | #include <geos/geom/LineSegment.h> |
28 | | #include <geos/geom/LineString.h> |
29 | | #include <geos/geom/CoordinateSequence.h> |
30 | | #include <geos/geom/CoordinateList.h> |
31 | | #include <geos/geom/GeometryCollection.h> |
32 | | #include <geos/geom/GeometryFactory.h> |
33 | | #include <geos/util.h> |
34 | | #include <geos/triangulate/quadedge/QuadEdge.h> |
35 | | #include <geos/triangulate/quadedge/QuadEdgeLocator.h> |
36 | | #include <geos/triangulate/quadedge/LastFoundQuadEdgeLocator.h> |
37 | | #include <geos/triangulate/quadedge/LocateFailureException.h> |
38 | | #include <geos/triangulate/quadedge/TriangleVisitor.h> |
39 | | #include <geos/geom/Triangle.h> |
40 | | #include <geos/util.h> |
41 | | |
42 | | |
43 | | using namespace geos::geom; |
44 | | |
45 | | |
46 | | namespace geos { |
47 | | namespace triangulate { //geos.triangulate |
48 | | namespace quadedge { //geos.triangulate.quadedge |
49 | | |
50 | | const double EDGE_COINCIDENCE_TOL_FACTOR = 1000; |
51 | | |
52 | | //-- Frame size factor for initializing subdivision frame. Larger is more robust |
53 | | const double FRAME_SIZE_FACTOR = 10; |
54 | | |
55 | | void |
56 | | QuadEdgeSubdivision::getTriangleEdges(const QuadEdge& startQE, |
57 | | const QuadEdge* triEdge[3]) |
58 | 0 | { |
59 | 0 | triEdge[0] = &startQE; |
60 | 0 | triEdge[1] = &triEdge[0]->lNext(); |
61 | 0 | triEdge[2] = &triEdge[1]->lNext(); |
62 | 0 | if(&triEdge[2]->lNext() != triEdge[0]) { |
63 | 0 | throw util::IllegalArgumentException("Edges do not form a triangle"); |
64 | 0 | } |
65 | 0 | } |
66 | | |
67 | | QuadEdgeSubdivision::QuadEdgeSubdivision(const geom::Envelope& env, double p_tolerance) : |
68 | 0 | tolerance(p_tolerance), |
69 | 0 | locator(new LastFoundQuadEdgeLocator(this)), |
70 | 0 | visit_state_clean(true) |
71 | 0 | { |
72 | 0 | edgeCoincidenceTolerance = tolerance / EDGE_COINCIDENCE_TOL_FACTOR; |
73 | 0 | createFrame(env); |
74 | 0 | initSubdiv(); |
75 | 0 | } |
76 | | |
77 | | void |
78 | | QuadEdgeSubdivision::createFrame(const geom::Envelope& env) |
79 | 0 | { |
80 | 0 | if (env.isNull()) { |
81 | 0 | throw util::IllegalArgumentException("Cannot create frame from empty Envelope."); |
82 | 0 | } |
83 | | |
84 | 0 | double deltaX = env.getWidth(); |
85 | 0 | double deltaY = env.getHeight(); |
86 | 0 | double offset = std::max(deltaX, deltaY) * FRAME_SIZE_FACTOR; |
87 | |
|
88 | 0 | frameVertex[0] = Vertex((env.getMaxX() + env.getMinX()) / 2.0, |
89 | 0 | env.getMaxY() + offset); |
90 | 0 | frameVertex[1] = Vertex(env.getMinX() - offset, env.getMinY() - offset); |
91 | 0 | frameVertex[2] = Vertex(env.getMaxX() + offset, env.getMinY() - offset); |
92 | |
|
93 | 0 | frameEnv = Envelope(frameVertex[0].getCoordinate(), |
94 | 0 | frameVertex[1].getCoordinate()); |
95 | 0 | frameEnv.expandToInclude(frameVertex[2].getCoordinate()); |
96 | 0 | } |
97 | | void |
98 | | QuadEdgeSubdivision::initSubdiv() |
99 | 0 | { |
100 | 0 | assert(quadEdges.empty()); |
101 | | |
102 | | // build initial subdivision from frame |
103 | 0 | startingEdges[0] = QuadEdge::makeEdge(frameVertex[0], frameVertex[1], quadEdges); |
104 | 0 | startingEdges[1] = QuadEdge::makeEdge(frameVertex[1], frameVertex[2], quadEdges); |
105 | 0 | QuadEdge::splice(startingEdges[0]->sym(), *startingEdges[1]); |
106 | |
|
107 | 0 | startingEdges[2] = QuadEdge::makeEdge(frameVertex[2], frameVertex[0], quadEdges); |
108 | 0 | QuadEdge::splice(startingEdges[1]->sym(), *startingEdges[2]); |
109 | 0 | QuadEdge::splice(startingEdges[2]->sym(), *startingEdges[0]); |
110 | 0 | } |
111 | | |
112 | | QuadEdge& |
113 | | QuadEdgeSubdivision::makeEdge(const Vertex& o, const Vertex& d) |
114 | 0 | { |
115 | 0 | QuadEdge* e = QuadEdge::makeEdge(o, d, quadEdges); |
116 | 0 | return *e; |
117 | 0 | } |
118 | | |
119 | | QuadEdge& |
120 | | QuadEdgeSubdivision::connect(QuadEdge& a, QuadEdge& b) |
121 | 0 | { |
122 | 0 | QuadEdge* e = QuadEdge::connect(a, b, quadEdges); |
123 | 0 | return *e; |
124 | 0 | } |
125 | | |
126 | | void |
127 | | QuadEdgeSubdivision::remove(QuadEdge& e) |
128 | 0 | { |
129 | 0 | QuadEdge::splice(e, e.oPrev()); |
130 | 0 | QuadEdge::splice(e.sym(), e.sym().oPrev()); |
131 | | |
132 | | // because QuadEdge pointers must be stable, do not remove edge from quadedges container |
133 | | // This is fine since they are detached from the subdivision |
134 | |
|
135 | 0 | e.remove(); |
136 | 0 | } |
137 | | |
138 | | QuadEdge* |
139 | | QuadEdgeSubdivision::locateFromEdge(const Vertex& v, |
140 | | const QuadEdge& startEdge) const |
141 | 0 | { |
142 | 0 | ::geos::ignore_unused_variable_warning(startEdge); |
143 | |
|
144 | 0 | std::size_t iter = 0; |
145 | 0 | auto maxIter = quadEdges.size(); |
146 | |
|
147 | 0 | QuadEdge* e = startingEdges[0]; |
148 | |
|
149 | 0 | for(;;) { |
150 | 0 | ++iter; |
151 | | /* |
152 | | * So far it has always been the case that failure to locate indicates an |
153 | | * invalid subdivision. So just fail completely. (An alternative would be |
154 | | * to perform an exhaustive search for the containing triangle, but this |
155 | | * would mask errors in the subdivision topology) |
156 | | * |
157 | | * This can also happen if two vertices are located very close together, |
158 | | * since the orientation predicates may experience precision failures. |
159 | | */ |
160 | 0 | if(iter > maxIter) { |
161 | 0 | throw LocateFailureException("Could not locate vertex."); |
162 | 0 | } |
163 | | |
164 | 0 | if((v.equals(e->orig())) || (v.equals(e->dest()))) { |
165 | 0 | break; |
166 | 0 | } |
167 | 0 | else if(v.rightOf(*e)) { |
168 | 0 | e = &e->sym(); |
169 | 0 | } |
170 | 0 | else if(!v.rightOf(e->oNext())) { |
171 | 0 | e = &e->oNext(); |
172 | 0 | } |
173 | 0 | else if(!v.rightOf(e->dPrev())) { |
174 | 0 | e = &e->dPrev(); |
175 | 0 | } |
176 | 0 | else { |
177 | | // on edge or in triangle containing edge |
178 | 0 | break; |
179 | 0 | } |
180 | 0 | } |
181 | 0 | return e; |
182 | 0 | } |
183 | | |
184 | | QuadEdge* |
185 | | QuadEdgeSubdivision::locate(const Coordinate& p0, const Coordinate& p1) |
186 | 0 | { |
187 | | // find an edge containing one of the points |
188 | 0 | QuadEdge* e = locator->locate(Vertex(p0)); |
189 | 0 | if(e == nullptr) { |
190 | 0 | return nullptr; |
191 | 0 | } |
192 | | |
193 | | // normalize so that p0 is origin of base edge |
194 | 0 | QuadEdge* base = e; |
195 | 0 | if(e->dest().getCoordinate().equals2D(p0)) { |
196 | 0 | base = &e->sym(); |
197 | 0 | } |
198 | | // check all edges around origin of base edge |
199 | 0 | QuadEdge* locEdge = base; |
200 | 0 | do { |
201 | 0 | if(locEdge->dest().getCoordinate().equals2D(p1)) { |
202 | 0 | return locEdge; |
203 | 0 | } |
204 | 0 | locEdge = &locEdge->oNext(); |
205 | 0 | } |
206 | 0 | while(locEdge != base); |
207 | 0 | return nullptr; |
208 | 0 | } |
209 | | |
210 | | QuadEdge& |
211 | | QuadEdgeSubdivision::insertSite(const Vertex& v) |
212 | 0 | { |
213 | 0 | QuadEdge* e = locate(v); |
214 | |
|
215 | 0 | if((v.equals(e->orig(), tolerance)) || (v.equals(e->dest(), tolerance))) { |
216 | 0 | return *e; // point already in subdivision. |
217 | 0 | } |
218 | | |
219 | | // Connect the new point to the vertices of the containing |
220 | | // triangle (or quadrilateral, if the new point fell on an |
221 | | // existing edge.) |
222 | 0 | QuadEdge* base = &makeEdge(e->orig(), v); |
223 | 0 | QuadEdge::splice(*base, *e); |
224 | 0 | QuadEdge* startEdge = base; |
225 | 0 | do { |
226 | 0 | base = &connect(*e, base->sym()); |
227 | 0 | e = &base->oPrev(); |
228 | 0 | } |
229 | 0 | while(&e->lNext() != startEdge); |
230 | |
|
231 | 0 | return *startEdge; |
232 | 0 | } |
233 | | |
234 | | bool |
235 | | QuadEdgeSubdivision::isFrameEdge(const QuadEdge& e) const |
236 | 0 | { |
237 | 0 | if(isFrameVertex(e.orig()) || isFrameVertex(e.dest())) { |
238 | 0 | return true; |
239 | 0 | } |
240 | 0 | return false; |
241 | 0 | } |
242 | | |
243 | | bool |
244 | | QuadEdgeSubdivision::isFrameBorderEdge(const QuadEdge& e) const |
245 | 0 | { |
246 | | // check other vertex of triangle to left of edge |
247 | 0 | Vertex vLeftTriOther = e.lNext().dest(); |
248 | 0 | if(isFrameVertex(vLeftTriOther)) { |
249 | 0 | return true; |
250 | 0 | } |
251 | | // check other vertex of triangle to right of edge |
252 | 0 | Vertex vRightTriOther = e.sym().lNext().dest(); |
253 | 0 | if(isFrameVertex(vRightTriOther)) { |
254 | 0 | return true; |
255 | 0 | } |
256 | | |
257 | 0 | return false; |
258 | 0 | } |
259 | | |
260 | | bool |
261 | | QuadEdgeSubdivision::isFrameVertex(const Vertex& v) const |
262 | 0 | { |
263 | 0 | if(v.equals(frameVertex[0])) { |
264 | 0 | return true; |
265 | 0 | } |
266 | 0 | if(v.equals(frameVertex[1])) { |
267 | 0 | return true; |
268 | 0 | } |
269 | 0 | if(v.equals(frameVertex[2])) { |
270 | 0 | return true; |
271 | 0 | } |
272 | 0 | return false; |
273 | 0 | } |
274 | | |
275 | | bool |
276 | | QuadEdgeSubdivision::isOnEdge(const QuadEdge& e, const Coordinate& p) const |
277 | 0 | { |
278 | 0 | geom::LineSegment seg; |
279 | 0 | seg.setCoordinates(e.orig().getCoordinate(), e.dest().getCoordinate()); |
280 | 0 | double dist = seg.distance(p); |
281 | | // heuristic (hack?) |
282 | 0 | return dist < edgeCoincidenceTolerance; |
283 | 0 | } |
284 | | |
285 | | bool |
286 | | QuadEdgeSubdivision::isVertexOfEdge(const QuadEdge& e, const Vertex& v) const |
287 | 0 | { |
288 | 0 | if((v.equals(e.orig(), tolerance)) || (v.equals(e.dest(), tolerance))) { |
289 | 0 | return true; |
290 | 0 | } |
291 | 0 | return false; |
292 | 0 | } |
293 | | |
294 | | std::unique_ptr<QuadEdgeSubdivision::QuadEdgeList> |
295 | | QuadEdgeSubdivision::getPrimaryEdges(bool includeFrame) |
296 | 0 | { |
297 | 0 | QuadEdgeList* edges = new QuadEdgeList(); |
298 | 0 | QuadEdgeStack edgeStack; |
299 | |
|
300 | 0 | edgeStack.push(startingEdges[0]); |
301 | |
|
302 | 0 | prepareVisit(); |
303 | |
|
304 | 0 | while(!edgeStack.empty()) { |
305 | 0 | QuadEdge* edge = edgeStack.top(); |
306 | 0 | edgeStack.pop(); |
307 | 0 | if(!edge->isVisited()) { |
308 | 0 | QuadEdge* priQE = (QuadEdge*)&edge->getPrimary(); |
309 | |
|
310 | 0 | if(includeFrame || ! isFrameEdge(*priQE)) { |
311 | 0 | edges->push_back(priQE); |
312 | 0 | } |
313 | |
|
314 | 0 | edgeStack.push(&edge->oNext()); |
315 | 0 | edgeStack.push(&edge->sym().oNext()); |
316 | |
|
317 | 0 | edge->setVisited(true); |
318 | 0 | edge->sym().setVisited(true); |
319 | 0 | } |
320 | 0 | } |
321 | 0 | return std::unique_ptr<QuadEdgeList>(edges); |
322 | 0 | } |
323 | | |
324 | | std::array<QuadEdge*, 3>* |
325 | | QuadEdgeSubdivision::fetchTriangleToVisit(QuadEdge* edge, |
326 | | QuadEdgeStack& edgeStack, bool includeFrame) |
327 | 0 | { |
328 | 0 | QuadEdge* curr = edge; |
329 | 0 | std::size_t edgeCount = 0; |
330 | 0 | bool isFrame = false; |
331 | 0 | do { |
332 | 0 | m_triEdges[edgeCount] = curr; |
333 | |
|
334 | 0 | if(!includeFrame && isFrameEdge(*curr)) { |
335 | 0 | isFrame = true; |
336 | 0 | } |
337 | | |
338 | | // push sym edges to visit next |
339 | 0 | QuadEdge* sym = &curr->sym(); |
340 | 0 | if (!sym->isVisited()) { |
341 | 0 | edgeStack.push(sym); |
342 | 0 | } |
343 | | |
344 | | // mark this edge as visited |
345 | 0 | curr->setVisited(true); |
346 | |
|
347 | 0 | edgeCount++; |
348 | 0 | curr = &curr->lNext(); |
349 | 0 | } |
350 | 0 | while(curr != edge); |
351 | |
|
352 | 0 | if(!includeFrame && isFrame) { |
353 | 0 | return nullptr; |
354 | 0 | } |
355 | 0 | return &m_triEdges; |
356 | 0 | } |
357 | | |
358 | | class |
359 | | QuadEdgeSubdivision::TriangleCoordinatesVisitor : public TriangleVisitor { |
360 | | private: |
361 | | QuadEdgeSubdivision::TriList* triCoords; |
362 | | |
363 | | public: |
364 | 0 | TriangleCoordinatesVisitor(QuadEdgeSubdivision::TriList* p_triCoords): triCoords(p_triCoords) |
365 | 0 | { |
366 | 0 | } |
367 | | |
368 | | void |
369 | | visit(std::array<QuadEdge*, 3>& triEdges) override |
370 | 0 | { |
371 | 0 | auto coordSeq = detail::make_unique<geom::CoordinateSequence>(4u, 0u); |
372 | 0 | for(std::size_t i = 0; i < 3; i++) { |
373 | 0 | Vertex v = triEdges[i]->orig(); |
374 | 0 | coordSeq->setAt(v.getCoordinate(), i); |
375 | 0 | } |
376 | 0 | coordSeq->setAt(triEdges[0]->orig().getCoordinate(), 3); |
377 | 0 | triCoords->push_back(std::move(coordSeq)); |
378 | 0 | } |
379 | | }; |
380 | | |
381 | | |
382 | | class |
383 | | QuadEdgeSubdivision::TriangleCircumcentreVisitor : public TriangleVisitor { |
384 | | public: |
385 | | void |
386 | | visit(std::array<QuadEdge*, 3>& triEdges) override |
387 | 0 | { |
388 | 0 | Triangle triangle(triEdges[0]->orig().getCoordinate(), |
389 | 0 | triEdges[1]->orig().getCoordinate(), triEdges[2]->orig().getCoordinate()); |
390 | 0 | Coordinate cc; |
391 | | |
392 | | //TODO: identify heuristic to allow calling faster circumcentre() when possible |
393 | 0 | triangle.circumcentreDD(cc); |
394 | |
|
395 | 0 | Vertex ccVertex(cc); |
396 | |
|
397 | 0 | for(uint8_t i = 0 ; i < 3 ; i++) { |
398 | 0 | triEdges[i]->rot().setOrig(ccVertex); |
399 | 0 | } |
400 | 0 | } |
401 | | }; |
402 | | |
403 | | |
404 | | void |
405 | | QuadEdgeSubdivision::getTriangleCoordinates(QuadEdgeSubdivision::TriList* triList, bool includeFrame) |
406 | 0 | { |
407 | 0 | TriangleCoordinatesVisitor visitor(triList); |
408 | 0 | visitTriangles(&visitor, includeFrame); |
409 | 0 | } |
410 | | |
411 | | void |
412 | 0 | QuadEdgeSubdivision::prepareVisit() { |
413 | 0 | if (!visit_state_clean) { |
414 | 0 | for (auto& qe : quadEdges) { |
415 | 0 | qe.setVisited(false); |
416 | 0 | } |
417 | 0 | } |
418 | |
|
419 | 0 | visit_state_clean = false; |
420 | 0 | } |
421 | | |
422 | | void |
423 | | QuadEdgeSubdivision::visitTriangles(TriangleVisitor* triVisitor, bool includeFrame) |
424 | 0 | { |
425 | 0 | QuadEdgeStack edgeStack; |
426 | 0 | edgeStack.push(startingEdges[0]); |
427 | |
|
428 | 0 | prepareVisit(); |
429 | |
|
430 | 0 | while(!edgeStack.empty()) { |
431 | 0 | QuadEdge* edge = edgeStack.top(); |
432 | 0 | edgeStack.pop(); |
433 | 0 | if(!edge->isVisited()) { |
434 | 0 | auto triEdges = fetchTriangleToVisit(edge, edgeStack, includeFrame); |
435 | 0 | if(triEdges != nullptr) { |
436 | 0 | triVisitor->visit(*triEdges); |
437 | 0 | } |
438 | 0 | } |
439 | 0 | } |
440 | 0 | } |
441 | | |
442 | | std::unique_ptr<geom::MultiLineString> |
443 | | QuadEdgeSubdivision::getEdges(const geom::GeometryFactory& geomFact) |
444 | 0 | { |
445 | 0 | std::unique_ptr<QuadEdgeList> p_quadEdges(getPrimaryEdges(false)); |
446 | 0 | std::vector<std::unique_ptr<Geometry>> edges; |
447 | |
|
448 | 0 | edges.reserve(p_quadEdges->size()); |
449 | 0 | for(const QuadEdge* qe : *p_quadEdges) { |
450 | 0 | auto coordSeq = detail::make_unique<geom::CoordinateSequence>(2u); |
451 | |
|
452 | 0 | coordSeq->setAt(qe->orig().getCoordinate(), 0); |
453 | 0 | coordSeq->setAt(qe->dest().getCoordinate(), 1); |
454 | |
|
455 | 0 | edges.emplace_back(geomFact.createLineString(std::move(coordSeq))); |
456 | 0 | } |
457 | |
|
458 | 0 | return geomFact.createMultiLineString(std::move(edges)); |
459 | 0 | } |
460 | | |
461 | | std::unique_ptr<GeometryCollection> |
462 | | QuadEdgeSubdivision::getTriangles(const GeometryFactory& geomFact) |
463 | 0 | { |
464 | 0 | TriList triPtsList; |
465 | 0 | getTriangleCoordinates(&triPtsList, false); |
466 | 0 | std::vector<std::unique_ptr<Geometry>> tris; |
467 | 0 | tris.reserve(triPtsList.size()); |
468 | |
|
469 | 0 | for(auto& coordSeq : triPtsList) { |
470 | 0 | tris.push_back( |
471 | 0 | geomFact.createPolygon(geomFact.createLinearRing(std::move(coordSeq)))); |
472 | 0 | } |
473 | |
|
474 | 0 | return geomFact.createGeometryCollection(std::move(tris)); |
475 | 0 | } |
476 | | |
477 | | |
478 | | //Methods for VoronoiDiagram |
479 | | std::unique_ptr<geom::GeometryCollection> |
480 | | QuadEdgeSubdivision::getVoronoiDiagram(const geom::GeometryFactory& geomFact) |
481 | 0 | { |
482 | 0 | return geomFact.createGeometryCollection(getVoronoiCellPolygons(geomFact)); |
483 | 0 | } |
484 | | |
485 | | std::unique_ptr<geom::MultiLineString> |
486 | | QuadEdgeSubdivision::getVoronoiDiagramEdges(const geom::GeometryFactory& geomFact) |
487 | 0 | { |
488 | 0 | return geomFact.createMultiLineString(getVoronoiCellEdges(geomFact)); |
489 | 0 | } |
490 | | |
491 | | std::vector<std::unique_ptr<geom::Geometry>> |
492 | | QuadEdgeSubdivision::getVoronoiCellPolygons(const geom::GeometryFactory& geomFact) |
493 | 0 | { |
494 | 0 | std::vector<std::unique_ptr<geom::Geometry>> cells; |
495 | 0 | TriangleCircumcentreVisitor tricircumVisitor; |
496 | |
|
497 | 0 | visitTriangles(&tricircumVisitor, true); |
498 | |
|
499 | 0 | std::unique_ptr<QuadEdgeSubdivision::QuadEdgeList> edges = getVertexUniqueEdges(false); |
500 | |
|
501 | 0 | cells.reserve(edges->size()); |
502 | 0 | for(const QuadEdge* qe : *edges) { |
503 | 0 | cells.push_back(getVoronoiCellPolygon(qe, geomFact)); |
504 | 0 | } |
505 | |
|
506 | 0 | return cells; |
507 | 0 | } |
508 | | |
509 | | std::vector<std::unique_ptr<geom::Geometry>> |
510 | | QuadEdgeSubdivision::getVoronoiCellEdges(const geom::GeometryFactory& geomFact) |
511 | 0 | { |
512 | 0 | std::vector<std::unique_ptr<geom::Geometry>> cells; |
513 | 0 | TriangleCircumcentreVisitor tricircumVisitor; |
514 | |
|
515 | 0 | visitTriangles((TriangleVisitor*) &tricircumVisitor, true); |
516 | |
|
517 | 0 | std::unique_ptr<QuadEdgeSubdivision::QuadEdgeList> edges = getVertexUniqueEdges(false); |
518 | 0 | cells.reserve(edges->size()); |
519 | |
|
520 | 0 | for(const QuadEdge* qe : *edges) { |
521 | 0 | cells.push_back(getVoronoiCellEdge(qe, geomFact)); |
522 | 0 | } |
523 | |
|
524 | 0 | return cells; |
525 | 0 | } |
526 | | |
527 | | std::unique_ptr<geom::Geometry> |
528 | | QuadEdgeSubdivision::getVoronoiCellPolygon(const QuadEdge* qe, const geom::GeometryFactory& geomFact) |
529 | 0 | { |
530 | 0 | auto cellPts = detail::make_unique<CoordinateSequence>(); |
531 | |
|
532 | 0 | const QuadEdge* startQE = qe; |
533 | 0 | do { |
534 | 0 | const Coordinate& cc = qe->rot().orig().getCoordinate(); |
535 | 0 | if(cellPts->isEmpty() || cellPts->back() != cc) { // no duplicates |
536 | 0 | cellPts->add(cc); |
537 | 0 | } |
538 | 0 | qe = &qe->oPrev(); |
539 | |
|
540 | 0 | } |
541 | 0 | while(qe != startQE); |
542 | | |
543 | | // Close the ring |
544 | 0 | if (cellPts->front() != cellPts->back()) { |
545 | 0 | cellPts->closeRing(); |
546 | 0 | } |
547 | 0 | if (cellPts->size() < 4) { |
548 | 0 | cellPts->add(cellPts->back()); |
549 | 0 | } |
550 | |
|
551 | 0 | std::unique_ptr<Geometry> cellPoly = geomFact.createPolygon(geomFact.createLinearRing(std::move(cellPts))); |
552 | |
|
553 | 0 | const Vertex& v = startQE->orig(); |
554 | 0 | const Coordinate& c = v.getCoordinate(); |
555 | 0 | cellPoly->setUserData(const_cast<Coordinate*>(&c)); |
556 | |
|
557 | 0 | return cellPoly; |
558 | 0 | } |
559 | | |
560 | | std::unique_ptr<geom::Geometry> |
561 | | QuadEdgeSubdivision::getVoronoiCellEdge(const QuadEdge* qe, const geom::GeometryFactory& geomFact) |
562 | 0 | { |
563 | 0 | auto cellPts = detail::make_unique<CoordinateSequence>(); |
564 | |
|
565 | 0 | const QuadEdge* startQE = qe; |
566 | 0 | do { |
567 | 0 | const Coordinate& cc = qe->rot().orig().getCoordinate(); |
568 | 0 | if(cellPts->isEmpty() || cellPts->back() != cc) { // no duplicates |
569 | 0 | cellPts->add(cc); |
570 | 0 | } |
571 | 0 | qe = &qe->oPrev(); |
572 | |
|
573 | 0 | } |
574 | 0 | while(qe != startQE); |
575 | | |
576 | | // Close the ring |
577 | 0 | if (cellPts->front() != cellPts->back()) { |
578 | 0 | cellPts->closeRing(); |
579 | 0 | } |
580 | |
|
581 | 0 | std::unique_ptr<geom::Geometry> cellEdge( |
582 | 0 | geomFact.createLineString(std::move(cellPts))); |
583 | |
|
584 | 0 | return cellEdge; |
585 | 0 | } |
586 | | |
587 | | std::unique_ptr<QuadEdgeSubdivision::QuadEdgeList> |
588 | | QuadEdgeSubdivision::getVertexUniqueEdges(bool includeFrame) |
589 | 0 | { |
590 | 0 | auto edges = detail::make_unique<QuadEdgeList>(); |
591 | 0 | std::set<Vertex> visitedVertices; // TODO unordered_set of Vertex* ? |
592 | |
|
593 | 0 | for(auto& quartet : quadEdges) { |
594 | 0 | QuadEdge* qe = &quartet.base(); |
595 | 0 | const Vertex& v = qe->orig(); |
596 | |
|
597 | 0 | if(visitedVertices.insert(v).second) { |
598 | | // v was not found and was newly inserted |
599 | 0 | if(includeFrame || ! QuadEdgeSubdivision::isFrameVertex(v)) { |
600 | 0 | edges->push_back(qe); |
601 | 0 | } |
602 | 0 | } |
603 | 0 | QuadEdge* qd = &(qe->sym()); |
604 | 0 | const Vertex& vd = qd->orig(); |
605 | |
|
606 | 0 | if (visitedVertices.insert(vd).second) { |
607 | | // vd was not found and was newly inserted |
608 | 0 | if(includeFrame || ! QuadEdgeSubdivision::isFrameVertex(vd)) { |
609 | 0 | edges->push_back(qd); |
610 | 0 | } |
611 | 0 | } |
612 | 0 | } |
613 | 0 | return edges; |
614 | 0 | } |
615 | | |
616 | | } //namespace geos.triangulate.quadedge |
617 | | } //namespace geos.triangulate |
618 | | |
619 | | } //namespace goes |