/src/geos/src/triangulate/tri/Tri.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * GEOS - Geometry Engine Open Source |
4 | | * http://geos.osgeo.org |
5 | | * |
6 | | * Copyright (C) 2020 Paul Ramsey <pramsey@cleverelephant.ca> |
7 | | * |
8 | | * This is free software; you can redistribute and/or modify it under |
9 | | * the terms of the GNU Lesser General Public Licence as published |
10 | | * by the Free Software Foundation. |
11 | | * See the COPYING file for more information. |
12 | | * |
13 | | **********************************************************************/ |
14 | | |
15 | | #include <geos/algorithm/Orientation.h> |
16 | | #include <geos/algorithm/LineIntersector.h> |
17 | | #include <geos/geom/CoordinateSequence.h> |
18 | | #include <geos/geom/Geometry.h> |
19 | | #include <geos/geom/GeometryFactory.h> |
20 | | #include <geos/geom/LinearRing.h> |
21 | | #include <geos/geom/Polygon.h> |
22 | | #include <geos/geom/Triangle.h> |
23 | | #include <geos/triangulate/tri/Tri.h> |
24 | | #include <geos/util/IllegalArgumentException.h> |
25 | | #include <geos/util/IllegalStateException.h> |
26 | | #include <geos/util.h> |
27 | | |
28 | | using namespace geos::geom; |
29 | | using geos::util::IllegalArgumentException; |
30 | | using geos::algorithm::Orientation; |
31 | | using geos::geom::Triangle; |
32 | | |
33 | | namespace geos { // geos |
34 | | namespace triangulate { // geos.triangulate |
35 | | namespace tri { // geos.triangulate.tri |
36 | | |
37 | | |
38 | | /* public */ |
39 | | void |
40 | | Tri::setAdjacent(Tri* p_tri0, Tri* p_tri1, Tri* p_tri2) |
41 | 0 | { |
42 | 0 | tri0 = p_tri0; |
43 | 0 | tri1 = p_tri1; |
44 | 0 | tri2 = p_tri2; |
45 | 0 | } |
46 | | |
47 | | /* public */ |
48 | | void |
49 | | Tri::setAdjacent(const Coordinate& pt, Tri* tri) |
50 | 0 | { |
51 | 0 | TriIndex index = getIndex(pt); |
52 | 0 | setTri(index, tri); |
53 | | // TODO: validate that tri is adjacent at the edge specified |
54 | 0 | } |
55 | | |
56 | | /* public */ |
57 | | void |
58 | | Tri::setTri(TriIndex edgeIndex, Tri* tri) |
59 | 0 | { |
60 | 0 | switch (edgeIndex) { |
61 | 0 | case 0: tri0 = tri; return; |
62 | 0 | case 1: tri1 = tri; return; |
63 | 0 | case 2: tri2 = tri; return; |
64 | 0 | } |
65 | 0 | throw util::IllegalArgumentException("Tri::setTri - invalid index"); |
66 | 0 | } |
67 | | |
68 | | /* private */ |
69 | | void |
70 | | Tri::setCoordinates(const Coordinate& np0, const Coordinate& np1, const Coordinate& np2) |
71 | 0 | { |
72 | 0 | p0 = np0; |
73 | 0 | p1 = np1; |
74 | 0 | p2 = np2; |
75 | 0 | } |
76 | | |
77 | | /* public */ |
78 | | void |
79 | | Tri::flip(TriIndex index) |
80 | 0 | { |
81 | 0 | Tri* tri = getAdjacent(index); |
82 | 0 | TriIndex index1 = tri->getIndex(this); |
83 | |
|
84 | 0 | Coordinate adj0 = getCoordinate(index); |
85 | 0 | Coordinate adj1 = getCoordinate(next(index)); |
86 | 0 | Coordinate opp0 = getCoordinate(oppVertex(index)); |
87 | 0 | Coordinate opp1 = tri->getCoordinate(oppVertex(index1)); |
88 | |
|
89 | 0 | flip(tri, index, index1, adj0, adj1, opp0, opp1); |
90 | 0 | } |
91 | | |
92 | | /* private */ |
93 | | void |
94 | | Tri::flip(Tri* tri, TriIndex index0, TriIndex index1, |
95 | | const Coordinate& adj0, const Coordinate& adj1, |
96 | | const Coordinate& opp0, const Coordinate& opp1) |
97 | 0 | { |
98 | | //System.out.println("Flipping: " + this + " -> " + tri); |
99 | | //validate(); |
100 | | //tri.validate(); |
101 | |
|
102 | 0 | setCoordinates(opp1, opp0, adj0); |
103 | 0 | tri->setCoordinates(opp0, opp1, adj1); |
104 | | |
105 | | /** |
106 | | * Order: 0: opp0-adj0 edge, 1: opp0-adj1 edge, |
107 | | * 2: opp1-adj0 edge, 3: opp1-adj1 edge |
108 | | */ |
109 | 0 | std::vector<Tri*> adjacent = getAdjacentTris(tri, index0, index1); |
110 | 0 | setAdjacent(tri, adjacent[0], adjacent[2]); |
111 | | //--- update the adjacent triangles with new adjacency |
112 | 0 | if ( adjacent[2] != nullptr ) { |
113 | 0 | adjacent[2]->replace(tri, this); |
114 | 0 | } |
115 | 0 | tri->setAdjacent(this, adjacent[3], adjacent[1]); |
116 | 0 | if ( adjacent[1] != nullptr ) { |
117 | 0 | adjacent[1]->replace(this, tri); |
118 | 0 | } |
119 | | //validate(); |
120 | | //tri.validate(); |
121 | 0 | } |
122 | | |
123 | | /** |
124 | | * Replace triOld with triNew |
125 | | * |
126 | | * @param triOld |
127 | | * @param triNew |
128 | | */ |
129 | | /* private */ |
130 | | void |
131 | | Tri::replace(Tri* triOld, Tri* triNew) |
132 | 0 | { |
133 | 0 | if ( tri0 != nullptr && tri0 == triOld ) { |
134 | 0 | tri0 = triNew; |
135 | 0 | } |
136 | 0 | else if ( tri1 != nullptr && tri1 == triOld ) { |
137 | 0 | tri1 = triNew; |
138 | 0 | } |
139 | 0 | else if ( tri2 != nullptr && tri2 == triOld ) { |
140 | 0 | tri2 = triNew; |
141 | 0 | } |
142 | 0 | } |
143 | | |
144 | | |
145 | | /* public */ |
146 | | void |
147 | | Tri::remove(TriList<Tri>& triList) |
148 | 0 | { |
149 | 0 | remove(); |
150 | 0 | triList.remove(this); |
151 | 0 | } |
152 | | |
153 | | /* public */ |
154 | | void |
155 | | Tri::remove() |
156 | 0 | { |
157 | 0 | remove(0); |
158 | 0 | remove(1); |
159 | 0 | remove(2); |
160 | 0 | } |
161 | | |
162 | | /* private */ |
163 | | void |
164 | | Tri::remove(TriIndex index) |
165 | 0 | { |
166 | 0 | Tri* adj = getAdjacent(index); |
167 | 0 | if (adj == nullptr) return; |
168 | 0 | adj->setTri(adj->getIndex(this), nullptr); |
169 | 0 | setTri(index, nullptr); |
170 | 0 | } |
171 | | |
172 | | |
173 | | /** |
174 | | * |
175 | | * Order: 0: opp0-adj0 edge, 1: opp0-adj1 edge, |
176 | | * 2: opp1-adj0 edge, 3: opp1-adj1 edge |
177 | | * |
178 | | * @param tri |
179 | | * @param index0 |
180 | | * @param index1 |
181 | | * @return |
182 | | */ |
183 | | /* private */ |
184 | | std::vector<Tri*> |
185 | | Tri::getAdjacentTris(Tri* triAdj, TriIndex index, TriIndex indexAdj) |
186 | 0 | { |
187 | 0 | std::vector<Tri*> adj(4); |
188 | 0 | adj[0] = getAdjacent(prev(index)); |
189 | 0 | adj[1] = getAdjacent(next(index)); |
190 | 0 | adj[2] = triAdj->getAdjacent(next(indexAdj)); |
191 | 0 | adj[3] = triAdj->getAdjacent(prev(indexAdj)); |
192 | 0 | return adj; |
193 | 0 | } |
194 | | |
195 | | /* public */ |
196 | | void |
197 | | Tri::validate() |
198 | 0 | { |
199 | 0 | if ( Orientation::CLOCKWISE != Orientation::index(p0, p1, p2) ) { |
200 | 0 | throw IllegalArgumentException("Tri is not oriented correctly"); |
201 | 0 | } |
202 | | |
203 | 0 | validateAdjacent(0); |
204 | 0 | validateAdjacent(1); |
205 | 0 | validateAdjacent(2); |
206 | 0 | } |
207 | | |
208 | | /* public */ |
209 | | void |
210 | | Tri::validateAdjacent(TriIndex index) |
211 | 0 | { |
212 | 0 | Tri* tri = getAdjacent(index); |
213 | 0 | if (tri == nullptr) return; |
214 | | |
215 | 0 | assert(isAdjacent(tri)); |
216 | 0 | assert(tri->isAdjacent(this)); |
217 | | |
218 | | // const Coordinate& e0 = getCoordinate(index); |
219 | | // const Coordinate& e1 = getCoordinate(next(index)); |
220 | | // TriIndex indexNeighbor = tri->getIndex(this); |
221 | | // const Coordinate& n0 = tri->getCoordinate(indexNeighbor); |
222 | | // const Coordinate& n1 = tri->getCoordinate(next(indexNeighbor)); |
223 | | // assert(e0.equals2D(n1)); // Edge coord not equal |
224 | | // assert(e1.equals2D(n0)); // Edge coord not equal |
225 | | |
226 | | //--- check that no edges cross |
227 | 0 | algorithm::LineIntersector li; |
228 | 0 | for (TriIndex i = 0; i < 3; i++) { |
229 | 0 | for (TriIndex j = 0; j < 3; j++) { |
230 | 0 | const Coordinate& p00 = getCoordinate(i); |
231 | 0 | const Coordinate& p01 = getCoordinate(next(i)); |
232 | 0 | const Coordinate& p10 = tri->getCoordinate(j); |
233 | 0 | const Coordinate& p11 = tri->getCoordinate(next(j)); |
234 | 0 | li.computeIntersection(p00, p01, p10, p11); |
235 | 0 | assert(!li.isProper()); |
236 | 0 | } |
237 | 0 | } |
238 | 0 | } |
239 | | |
240 | | /* public */ |
241 | | std::pair<const Coordinate&, const Coordinate&> |
242 | | Tri::getEdge(Tri* neighbor) const |
243 | 0 | { |
244 | 0 | TriIndex index = getIndex(neighbor); |
245 | 0 | TriIndex nextTri = next(index); |
246 | | |
247 | | // const Coordinate& e0 = getCoordinate(index); |
248 | | // const Coordinate& e1 = getCoordinate(nextTri); |
249 | | // assert (neighbor->hasCoordinate(e0)); |
250 | | // assert (neighbor->hasCoordinate(e1)); |
251 | | // TriIndex iN = neighbor->getIndex(e0); |
252 | | // TriIndex iNPrev = prev(iN); |
253 | | // assert (neighbor->getIndex(e1) == iNPrev); |
254 | |
|
255 | 0 | std::pair<const Coordinate&, const Coordinate&> edge(getCoordinate(index), getCoordinate(nextTri)); |
256 | 0 | return edge; |
257 | 0 | } |
258 | | |
259 | | /* public */ |
260 | | const Coordinate& |
261 | | Tri::getEdgeStart(TriIndex i) const |
262 | 0 | { |
263 | 0 | return getCoordinate(i); |
264 | 0 | } |
265 | | |
266 | | /* public */ |
267 | | const Coordinate& |
268 | | Tri::getEdgeEnd(TriIndex i) const |
269 | 0 | { |
270 | 0 | return getCoordinate(next(i)); |
271 | 0 | } |
272 | | |
273 | | /* public */ |
274 | | bool |
275 | | Tri::hasCoordinate(const Coordinate& v) const |
276 | 0 | { |
277 | 0 | if ( p0.equals(v) || p1.equals(v) || p2.equals(v) ) { |
278 | 0 | return true; |
279 | 0 | } |
280 | 0 | return false; |
281 | 0 | } |
282 | | |
283 | | /* public */ |
284 | | const Coordinate& |
285 | | Tri::getCoordinate(TriIndex i) const |
286 | 0 | { |
287 | 0 | switch(i) { |
288 | 0 | case 0: return p0; |
289 | 0 | case 1: return p1; |
290 | 0 | case 2: return p2; |
291 | 0 | } |
292 | 0 | throw util::IllegalArgumentException("Tri::getCoordinate - invalid index"); |
293 | 0 | } |
294 | | |
295 | | /* public */ |
296 | | TriIndex |
297 | | Tri::getIndex(const Coordinate& p) const |
298 | 0 | { |
299 | 0 | if ( p0.equals2D(p) ) |
300 | 0 | return 0; |
301 | 0 | if ( p1.equals2D(p) ) |
302 | 0 | return 1; |
303 | 0 | if ( p2.equals2D(p) ) |
304 | 0 | return 2; |
305 | 0 | return -1; |
306 | 0 | } |
307 | | |
308 | | /* public */ |
309 | | TriIndex |
310 | | Tri::getIndex(const Tri* tri) const |
311 | 0 | { |
312 | 0 | if ( tri0 == tri ) |
313 | 0 | return 0; |
314 | 0 | if ( tri1 == tri ) |
315 | 0 | return 1; |
316 | 0 | if ( tri2 == tri ) |
317 | 0 | return 2; |
318 | 0 | return -1; |
319 | 0 | } |
320 | | |
321 | | /* public */ |
322 | | Tri* |
323 | | Tri::getAdjacent(TriIndex i) const |
324 | 0 | { |
325 | 0 | switch(i) { |
326 | 0 | case 0: return tri0; |
327 | 0 | case 1: return tri1; |
328 | 0 | case 2: return tri2; |
329 | 0 | } |
330 | 0 | throw util::IllegalArgumentException("Tri::getAdjacent - invalid index"); |
331 | 0 | } |
332 | | |
333 | | /* public */ |
334 | | bool |
335 | | Tri::hasAdjacent() const |
336 | 0 | { |
337 | 0 | return hasAdjacent(0) || hasAdjacent(1) || hasAdjacent(2); |
338 | 0 | } |
339 | | |
340 | | /* public */ |
341 | | bool |
342 | | Tri::hasAdjacent(TriIndex i) const |
343 | 0 | { |
344 | 0 | return nullptr != getAdjacent(i); |
345 | 0 | } |
346 | | |
347 | | |
348 | | /* public */ |
349 | | bool |
350 | | Tri::isAdjacent(Tri* tri) const |
351 | 0 | { |
352 | 0 | return getIndex(tri) >= 0; |
353 | 0 | } |
354 | | |
355 | | /* public */ |
356 | | int |
357 | | Tri::numAdjacent() const |
358 | 0 | { |
359 | 0 | int num = 0; |
360 | 0 | if ( tri0 != nullptr ) |
361 | 0 | num++; |
362 | 0 | if ( tri1 != nullptr ) |
363 | 0 | num++; |
364 | 0 | if ( tri2 != nullptr ) |
365 | 0 | num++; |
366 | 0 | return num; |
367 | 0 | } |
368 | | |
369 | | /* public */ |
370 | | bool |
371 | | Tri::isInteriorVertex(TriIndex index) const |
372 | 0 | { |
373 | 0 | const Tri* curr = this; |
374 | 0 | TriIndex currIndex = index; |
375 | 0 | do { |
376 | 0 | const Tri* adj = curr->getAdjacent(currIndex); |
377 | 0 | if (adj == nullptr) return false; |
378 | 0 | TriIndex adjIndex = adj->getIndex(curr); |
379 | 0 | if (adjIndex < 0) { |
380 | 0 | throw util::IllegalStateException("Inconsistent adjacency - invalid triangulation"); |
381 | 0 | } |
382 | 0 | curr = adj; |
383 | 0 | currIndex = Tri::next(adjIndex); |
384 | 0 | } |
385 | 0 | while (curr != this); |
386 | 0 | return true; |
387 | 0 | } |
388 | | |
389 | | /* public */ |
390 | | bool |
391 | | Tri::isBorder() const |
392 | 0 | { |
393 | 0 | return isBoundary(0) || isBoundary(1) || isBoundary(2); |
394 | 0 | } |
395 | | |
396 | | /* public */ |
397 | | bool |
398 | | Tri::isBoundary(TriIndex index) const |
399 | 0 | { |
400 | 0 | return ! hasAdjacent(index); |
401 | 0 | } |
402 | | |
403 | | /* public static */ |
404 | | TriIndex |
405 | | Tri::next(TriIndex i) |
406 | 0 | { |
407 | 0 | switch (i) { |
408 | 0 | case 0: return 1; |
409 | 0 | case 1: return 2; |
410 | 0 | case 2: return 0; |
411 | 0 | } |
412 | 0 | return -1; |
413 | 0 | } |
414 | | |
415 | | /* public static */ |
416 | | TriIndex |
417 | | Tri::prev(TriIndex i) |
418 | 0 | { |
419 | 0 | switch (i) { |
420 | 0 | case 0: return 2; |
421 | 0 | case 1: return 0; |
422 | 0 | case 2: return 1; |
423 | 0 | } |
424 | 0 | return -1; |
425 | 0 | } |
426 | | |
427 | | /* public static */ |
428 | | TriIndex |
429 | | Tri::oppVertex(TriIndex edgeIndex) |
430 | 0 | { |
431 | 0 | return prev(edgeIndex); |
432 | 0 | } |
433 | | |
434 | | /* public static */ |
435 | | TriIndex |
436 | | Tri::oppEdge(TriIndex vertexIndex) |
437 | 0 | { |
438 | 0 | return next(vertexIndex); |
439 | 0 | } |
440 | | |
441 | | |
442 | | /* public */ |
443 | | Coordinate |
444 | | Tri::midpoint(TriIndex edgeIndex) const |
445 | 0 | { |
446 | 0 | const Coordinate& np0 = getCoordinate(edgeIndex); |
447 | 0 | const Coordinate& np1 = getCoordinate(next(edgeIndex)); |
448 | 0 | double midX = (np0.x + np1.x) / 2; |
449 | 0 | double midY = (np0.y + np1.y) / 2; |
450 | 0 | return Coordinate(midX, midY); |
451 | 0 | } |
452 | | |
453 | | /* public */ |
454 | | double |
455 | | Tri::getArea() const |
456 | 0 | { |
457 | 0 | return Triangle::area(p0, p1, p2); |
458 | 0 | } |
459 | | |
460 | | /* public */ |
461 | | double |
462 | | Tri::getLength() const |
463 | 0 | { |
464 | 0 | return Triangle::length(p0, p1, p2); |
465 | 0 | } |
466 | | |
467 | | /* public */ |
468 | | double |
469 | | Tri::getLength(TriIndex i) const |
470 | 0 | { |
471 | 0 | return getCoordinate(i).distance(getCoordinate(next(i))); |
472 | 0 | } |
473 | | |
474 | | /* public */ |
475 | | std::unique_ptr<geom::Polygon> |
476 | | Tri::toPolygon(const geom::GeometryFactory* gf) const |
477 | 0 | { |
478 | 0 | auto coords = detail::make_unique<geom::CoordinateSequence>(4u); |
479 | 0 | (*coords)[0] = p0; |
480 | 0 | (*coords)[1] = p1; |
481 | 0 | (*coords)[2] = p2; |
482 | 0 | (*coords)[3] = p0; |
483 | |
|
484 | 0 | return gf->createPolygon(gf->createLinearRing(std::move(coords))); |
485 | 0 | } |
486 | | |
487 | | /* public static */ |
488 | | std::unique_ptr<geom::Geometry> |
489 | | Tri::toGeometry(std::set<Tri*>& tris, const geom::GeometryFactory* gf) |
490 | 0 | { |
491 | 0 | std::vector<std::unique_ptr<geom::Polygon>> polys; |
492 | 0 | for (Tri* tri: tris) { |
493 | 0 | std::unique_ptr<geom::Polygon> poly = tri->toPolygon(gf); |
494 | 0 | polys.emplace_back(poly.release()); |
495 | 0 | } |
496 | 0 | return gf->createGeometryCollection(std::move(polys)); |
497 | 0 | } |
498 | | |
499 | | |
500 | | std::ostream& |
501 | | operator<<(std::ostream& os, const Tri& tri) |
502 | 0 | { |
503 | 0 | os << "POLYGON (("; |
504 | 0 | os << tri.p0 << ", "; |
505 | 0 | os << tri.p1 << ", "; |
506 | 0 | os << tri.p2 << ", "; |
507 | 0 | os << tri.p0 << "))"; |
508 | 0 | return os; |
509 | 0 | } |
510 | | |
511 | | |
512 | | } // namespace geos.triangulate.tri |
513 | | } // namespace geos.triangulate |
514 | | } // namespace geos |