Coverage Report

Created: 2025-11-12 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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