Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/manifold/src/polygon.cpp
9903 views
1
// Copyright 2021 The Manifold Authors.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include "manifold/polygon.h"
16
17
#include <functional>
18
#include <map>
19
#include <set>
20
21
#include "manifold/manifold.h"
22
#include "manifold/optional_assert.h"
23
#include "parallel.h"
24
#include "tree2d.h"
25
#include "utils.h"
26
27
#ifdef MANIFOLD_DEBUG
28
#include <iomanip>
29
#endif
30
31
namespace {
32
using namespace manifold;
33
34
constexpr int TRIANGULATOR_VERBOSE_LEVEL = 2;
35
36
constexpr double kBest = -std::numeric_limits<double>::infinity();
37
38
// it seems that MSVC cannot optimize la::determinant(mat2(a, b))
39
constexpr double determinant2x2(vec2 a, vec2 b) {
40
return a.x * b.y - a.y * b.x;
41
}
42
43
#ifdef MANIFOLD_DEBUG
44
struct PolyEdge {
45
int startVert, endVert;
46
};
47
48
std::vector<PolyEdge> Polygons2Edges(const PolygonsIdx& polys) {
49
std::vector<PolyEdge> halfedges;
50
for (const auto& poly : polys) {
51
for (size_t i = 1; i < poly.size(); ++i) {
52
halfedges.push_back({poly[i - 1].idx, poly[i].idx});
53
}
54
halfedges.push_back({poly.back().idx, poly[0].idx});
55
}
56
return halfedges;
57
}
58
59
std::vector<PolyEdge> Triangles2Edges(const std::vector<ivec3>& triangles) {
60
std::vector<PolyEdge> halfedges;
61
halfedges.reserve(triangles.size() * 3);
62
for (const ivec3& tri : triangles) {
63
halfedges.push_back({tri[0], tri[1]});
64
halfedges.push_back({tri[1], tri[2]});
65
halfedges.push_back({tri[2], tri[0]});
66
}
67
return halfedges;
68
}
69
70
void CheckTopology(const std::vector<PolyEdge>& halfedges) {
71
DEBUG_ASSERT(halfedges.size() % 2 == 0, topologyErr,
72
"Odd number of halfedges.");
73
size_t n_edges = halfedges.size() / 2;
74
std::vector<PolyEdge> forward(halfedges.size()), backward(halfedges.size());
75
76
auto end = std::copy_if(halfedges.begin(), halfedges.end(), forward.begin(),
77
[](PolyEdge e) { return e.endVert > e.startVert; });
78
DEBUG_ASSERT(
79
static_cast<size_t>(std::distance(forward.begin(), end)) == n_edges,
80
topologyErr, "Half of halfedges should be forward.");
81
forward.resize(n_edges);
82
83
end = std::copy_if(halfedges.begin(), halfedges.end(), backward.begin(),
84
[](PolyEdge e) { return e.endVert < e.startVert; });
85
DEBUG_ASSERT(
86
static_cast<size_t>(std::distance(backward.begin(), end)) == n_edges,
87
topologyErr, "Half of halfedges should be backward.");
88
backward.resize(n_edges);
89
90
std::for_each(backward.begin(), backward.end(),
91
[](PolyEdge& e) { std::swap(e.startVert, e.endVert); });
92
auto cmp = [](const PolyEdge& a, const PolyEdge& b) {
93
return a.startVert < b.startVert ||
94
(a.startVert == b.startVert && a.endVert < b.endVert);
95
};
96
std::stable_sort(forward.begin(), forward.end(), cmp);
97
std::stable_sort(backward.begin(), backward.end(), cmp);
98
for (size_t i = 0; i < n_edges; ++i) {
99
DEBUG_ASSERT(forward[i].startVert == backward[i].startVert &&
100
forward[i].endVert == backward[i].endVert,
101
topologyErr, "Not manifold.");
102
}
103
}
104
105
void CheckTopology(const std::vector<ivec3>& triangles,
106
const PolygonsIdx& polys) {
107
std::vector<PolyEdge> halfedges = Triangles2Edges(triangles);
108
std::vector<PolyEdge> openEdges = Polygons2Edges(polys);
109
for (PolyEdge e : openEdges) {
110
halfedges.push_back({e.endVert, e.startVert});
111
}
112
CheckTopology(halfedges);
113
}
114
115
void CheckGeometry(const std::vector<ivec3>& triangles,
116
const PolygonsIdx& polys, double epsilon) {
117
std::unordered_map<int, vec2> vertPos;
118
for (const auto& poly : polys) {
119
for (size_t i = 0; i < poly.size(); ++i) {
120
vertPos[poly[i].idx] = poly[i].pos;
121
}
122
}
123
DEBUG_ASSERT(std::all_of(triangles.begin(), triangles.end(),
124
[&vertPos, epsilon](const ivec3& tri) {
125
return CCW(vertPos[tri[0]], vertPos[tri[1]],
126
vertPos[tri[2]], epsilon) >= 0;
127
}),
128
geometryErr, "triangulation is not entirely CCW!");
129
}
130
131
void Dump(const PolygonsIdx& polys, double epsilon) {
132
std::cout << std::setprecision(19);
133
std::cout << "Polygon 0 " << epsilon << " " << polys.size() << std::endl;
134
for (auto poly : polys) {
135
std::cout << poly.size() << std::endl;
136
for (auto v : poly) {
137
std::cout << v.pos.x << " " << v.pos.y << std::endl;
138
}
139
}
140
std::cout << "# ... " << std::endl;
141
for (auto poly : polys) {
142
std::cout << "show(array([" << std::endl;
143
for (auto v : poly) {
144
std::cout << " [" << v.pos.x << ", " << v.pos.y << "]," << std::endl;
145
}
146
std::cout << "]))" << std::endl;
147
}
148
}
149
150
std::atomic<int> numFailures(0);
151
152
void PrintFailure(const std::exception& e, const PolygonsIdx& polys,
153
std::vector<ivec3>& triangles, double epsilon) {
154
// only print the first triangulation failure
155
if (numFailures.fetch_add(1) != 0) return;
156
std::cout << std::setprecision(19);
157
std::cout << "-----------------------------------" << std::endl;
158
std::cout << "Triangulation failed! Precision = " << epsilon << std::endl;
159
std::cout << e.what() << std::endl;
160
if (triangles.size() > 1000 &&
161
ManifoldParams().verbose < TRIANGULATOR_VERBOSE_LEVEL) {
162
std::cout << "Output truncated due to producing " << triangles.size()
163
<< " triangles." << std::endl;
164
return;
165
}
166
Dump(polys, epsilon);
167
std::cout << "produced this triangulation:" << std::endl;
168
for (size_t j = 0; j < triangles.size(); ++j) {
169
std::cout << triangles[j][0] << ", " << triangles[j][1] << ", "
170
<< triangles[j][2] << std::endl;
171
}
172
}
173
174
#define PRINT(msg) \
175
if (ManifoldParams().verbose >= TRIANGULATOR_VERBOSE_LEVEL) \
176
std::cout << msg << std::endl;
177
#else
178
#define PRINT(msg)
179
#endif
180
181
/**
182
* Tests if the input polygons are convex by searching for any reflex vertices.
183
* Exactly colinear edges and zero-length edges are treated conservatively as
184
* reflex. Does not check for overlaps.
185
*/
186
bool IsConvex(const PolygonsIdx& polys, double epsilon) {
187
for (const SimplePolygonIdx& poly : polys) {
188
const vec2 firstEdge = poly[0].pos - poly[poly.size() - 1].pos;
189
// Zero-length edges comes out NaN, which won't trip the early return, but
190
// it's okay because that zero-length edge will also get tested
191
// non-normalized and will trip det == 0.
192
vec2 lastEdge = la::normalize(firstEdge);
193
for (size_t v = 0; v < poly.size(); ++v) {
194
const vec2 edge =
195
v + 1 < poly.size() ? poly[v + 1].pos - poly[v].pos : firstEdge;
196
const double det = determinant2x2(lastEdge, edge);
197
if (det <= 0 || (std::abs(det) < epsilon && la::dot(lastEdge, edge) < 0))
198
return false;
199
lastEdge = la::normalize(edge);
200
}
201
}
202
return true;
203
}
204
205
/**
206
* Triangulates a set of convex polygons by alternating instead of a fan, to
207
* avoid creating high-degree vertices.
208
*/
209
std::vector<ivec3> TriangulateConvex(const PolygonsIdx& polys) {
210
const size_t numTri = manifold::transform_reduce(
211
polys.begin(), polys.end(), 0_uz,
212
[](size_t a, size_t b) { return a + b; },
213
[](const SimplePolygonIdx& poly) { return poly.size() - 2; });
214
std::vector<ivec3> triangles;
215
triangles.reserve(numTri);
216
for (const SimplePolygonIdx& poly : polys) {
217
size_t i = 0;
218
size_t k = poly.size() - 1;
219
bool right = true;
220
while (i + 1 < k) {
221
const size_t j = right ? i + 1 : k - 1;
222
triangles.push_back({poly[i].idx, poly[j].idx, poly[k].idx});
223
if (right) {
224
i = j;
225
} else {
226
k = j;
227
}
228
right = !right;
229
}
230
}
231
return triangles;
232
}
233
234
/**
235
* Ear-clipping triangulator based on David Eberly's approach from Geometric
236
* Tools, but adjusted to handle epsilon-valid polygons, and including a
237
* fallback that ensures a manifold triangulation even for overlapping polygons.
238
* This is reduced from an O(n^2) algorithm by means of our BVH Collider.
239
*
240
* The main adjustments for robustness involve clipping the sharpest ears first
241
* (a known technique to get higher triangle quality), and doing an exhaustive
242
* search to determine ear convexity exactly if the first geometric result is
243
* within epsilon.
244
*/
245
246
class EarClip {
247
public:
248
EarClip(const PolygonsIdx& polys, double epsilon) : epsilon_(epsilon) {
249
ZoneScoped;
250
251
size_t numVert = 0;
252
for (const SimplePolygonIdx& poly : polys) {
253
numVert += poly.size();
254
}
255
polygon_.reserve(numVert + 2 * polys.size());
256
257
std::vector<VertItr> starts = Initialize(polys);
258
259
for (VertItr v = polygon_.begin(); v != polygon_.end(); ++v) {
260
ClipIfDegenerate(v);
261
}
262
263
for (const VertItr first : starts) {
264
FindStart(first);
265
}
266
}
267
268
std::vector<ivec3> Triangulate() {
269
ZoneScoped;
270
271
for (const VertItr start : holes_) {
272
CutKeyhole(start);
273
}
274
275
for (const VertItr start : simples_) {
276
TriangulatePoly(start);
277
}
278
279
return triangles_;
280
}
281
282
double GetPrecision() const { return epsilon_; }
283
284
private:
285
struct Vert;
286
using VertItr = std::vector<Vert>::iterator;
287
using VertItrC = std::vector<Vert>::const_iterator;
288
struct MaxX {
289
bool operator()(const VertItr& a, const VertItr& b) const {
290
return a->pos.x > b->pos.x;
291
}
292
};
293
struct MinCost {
294
bool operator()(const VertItr& a, const VertItr& b) const {
295
return a->cost < b->cost;
296
}
297
};
298
using qItr = std::set<VertItr, MinCost>::iterator;
299
300
// The flat list where all the Verts are stored. Not used much for traversal.
301
std::vector<Vert> polygon_;
302
// The set of right-most starting points, one for each negative-area contour.
303
std::multiset<VertItr, MaxX> holes_;
304
// The set of starting points, one for each positive-area contour.
305
std::vector<VertItr> outers_;
306
// The set of starting points, one for each simple polygon.
307
std::vector<VertItr> simples_;
308
// Maps each hole (by way of starting point) to its bounding box.
309
std::map<VertItr, Rect> hole2BBox_;
310
// A priority queue of valid ears - the multiset allows them to be updated.
311
std::multiset<VertItr, MinCost> earsQueue_;
312
// The output triangulation.
313
std::vector<ivec3> triangles_;
314
// Bounding box of the entire set of polygons
315
Rect bBox_;
316
// Working epsilon: max of float error and input value.
317
double epsilon_;
318
319
struct IdxCollider {
320
Vec<PolyVert> points;
321
std::vector<VertItr> itr;
322
};
323
324
// A circularly-linked list representing the polygon(s) that still need to be
325
// triangulated. This gets smaller as ears are clipped until it degenerates to
326
// two points and terminates.
327
struct Vert {
328
int mesh_idx;
329
double cost;
330
qItr ear;
331
vec2 pos, rightDir;
332
VertItr left, right;
333
334
// Shorter than half of epsilon, to be conservative so that it doesn't
335
// cause CW triangles that exceed epsilon due to rounding error.
336
bool IsShort(double epsilon) const {
337
const vec2 edge = right->pos - pos;
338
return la::dot(edge, edge) * 4 < epsilon * epsilon;
339
}
340
341
// Like CCW, returns 1 if v is on the inside of the angle formed at this
342
// vert, -1 on the outside, and 0 if it's within epsilon of the boundary.
343
// Ensure v is more than epsilon from pos, as case this will not return 0.
344
int Interior(vec2 v, double epsilon) const {
345
const vec2 diff = v - pos;
346
if (la::dot(diff, diff) < epsilon * epsilon) {
347
return 0;
348
}
349
return CCW(pos, left->pos, right->pos, epsilon) +
350
CCW(pos, right->pos, v, epsilon) + CCW(pos, v, left->pos, epsilon);
351
}
352
353
// Returns true if Vert is on the inside of the edge that goes from tail to
354
// tail->right. This will walk the edges if necessary until a clear answer
355
// is found (beyond epsilon). If toLeft is true, this Vert will walk its
356
// edges to the left. This should be chosen so that the edges walk in the
357
// same general direction - tail always walks to the right.
358
bool InsideEdge(VertItr tail, double epsilon, bool toLeft) const {
359
const double p2 = epsilon * epsilon;
360
VertItr nextL = left->right;
361
VertItr nextR = tail->right;
362
VertItr center = tail;
363
VertItr last = center;
364
365
while (nextL != nextR && tail != nextR &&
366
nextL != (toLeft ? right : left)) {
367
const vec2 edgeL = nextL->pos - center->pos;
368
const double l2 = la::dot(edgeL, edgeL);
369
if (l2 <= p2) {
370
nextL = toLeft ? nextL->left : nextL->right;
371
continue;
372
}
373
374
const vec2 edgeR = nextR->pos - center->pos;
375
const double r2 = la::dot(edgeR, edgeR);
376
if (r2 <= p2) {
377
nextR = nextR->right;
378
continue;
379
}
380
381
const vec2 vecLR = nextR->pos - nextL->pos;
382
const double lr2 = la::dot(vecLR, vecLR);
383
if (lr2 <= p2) {
384
last = center;
385
center = nextL;
386
nextL = toLeft ? nextL->left : nextL->right;
387
if (nextL == nextR) break;
388
nextR = nextR->right;
389
continue;
390
}
391
392
int convexity = CCW(nextL->pos, center->pos, nextR->pos, epsilon);
393
if (center != last) {
394
convexity += CCW(last->pos, center->pos, nextL->pos, epsilon) +
395
CCW(nextR->pos, center->pos, last->pos, epsilon);
396
}
397
if (convexity != 0) return convexity > 0;
398
399
if (l2 < r2) {
400
center = nextL;
401
nextL = toLeft ? nextL->left : nextL->right;
402
} else {
403
center = nextR;
404
nextR = nextR->right;
405
}
406
last = center;
407
}
408
// The whole polygon is degenerate - consider this to be convex.
409
return true;
410
}
411
412
// Returns true for convex or colinear ears.
413
bool IsConvex(double epsilon) const {
414
return CCW(left->pos, pos, right->pos, epsilon) >= 0;
415
}
416
417
// Subtly different from !IsConvex because IsConvex will return true for
418
// colinear non-folded verts, while IsReflex will always check until actual
419
// certainty is determined.
420
bool IsReflex(double epsilon) const {
421
return !left->InsideEdge(left->right, epsilon, true);
422
}
423
424
// Returns the x-value on this edge corresponding to the start.y value,
425
// returning NAN if the edge does not cross the value from below to above,
426
// right of start - all within a epsilon tolerance. If onTop != 0, this
427
// restricts which end is allowed to terminate within the epsilon band.
428
double InterpY2X(vec2 start, int onTop, double epsilon) const {
429
if (la::abs(pos.y - start.y) <= epsilon) {
430
if (right->pos.y <= start.y + epsilon || onTop == 1) {
431
return NAN;
432
} else {
433
return pos.x;
434
}
435
} else if (pos.y < start.y - epsilon) {
436
if (right->pos.y > start.y + epsilon) {
437
return pos.x + (start.y - pos.y) * (right->pos.x - pos.x) /
438
(right->pos.y - pos.y);
439
} else if (right->pos.y < start.y - epsilon || onTop == -1) {
440
return NAN;
441
} else {
442
return right->pos.x;
443
}
444
} else {
445
return NAN;
446
}
447
}
448
449
// This finds the cost of this vert relative to one of the two closed sides
450
// of the ear. Points are valid even when they touch, so long as their edge
451
// goes to the outside. No need to check the other side, since all verts are
452
// processed in the EarCost loop.
453
double SignedDist(VertItr v, vec2 unit, double epsilon) const {
454
double d = determinant2x2(unit, v->pos - pos);
455
if (std::abs(d) < epsilon) {
456
double dR = determinant2x2(unit, v->right->pos - pos);
457
if (std::abs(dR) > epsilon) return dR;
458
double dL = determinant2x2(unit, v->left->pos - pos);
459
if (std::abs(dL) > epsilon) return dL;
460
}
461
return d;
462
}
463
464
// Find the cost of Vert v within this ear, where openSide is the unit
465
// vector from Verts right to left - passed in for reuse.
466
double Cost(VertItr v, vec2 openSide, double epsilon) const {
467
double cost = std::min(SignedDist(v, rightDir, epsilon),
468
SignedDist(v, left->rightDir, epsilon));
469
470
const double openCost = determinant2x2(openSide, v->pos - right->pos);
471
return std::min(cost, openCost);
472
}
473
474
// For verts outside the ear, apply a cost based on the Delaunay condition
475
// to aid in prioritization and produce cleaner triangulations. This doesn't
476
// affect robustness, but may be adjusted to improve output.
477
static double DelaunayCost(vec2 diff, double scale, double epsilon) {
478
return -epsilon - scale * la::dot(diff, diff);
479
}
480
481
// This is the expensive part of the algorithm, checking this ear against
482
// every Vert to ensure none are inside. The Collider brings the total
483
// triangulator cost down from O(n^2) to O(nlogn) for most large polygons.
484
//
485
// Think of a cost as vaguely a distance metric - 0 is right on the edge of
486
// being invalid. cost > epsilon is definitely invalid. Cost < -epsilon
487
// is definitely valid, so all improvement costs are designed to always give
488
// values < -epsilon so they will never affect validity. The first
489
// totalCost is designed to give priority to sharper angles. Any cost < (-1
490
// - epsilon) has satisfied the Delaunay condition.
491
double EarCost(double epsilon, IdxCollider& collider) const {
492
vec2 openSide = left->pos - right->pos;
493
const vec2 center = 0.5 * (left->pos + right->pos);
494
const double scale = 4 / la::dot(openSide, openSide);
495
const double radius = la::length(openSide) / 2;
496
openSide = la::normalize(openSide);
497
498
double totalCost = la::dot(left->rightDir, rightDir) - 1 - epsilon;
499
if (CCW(pos, left->pos, right->pos, epsilon) == 0) {
500
// Clip folded ears first
501
return totalCost;
502
}
503
504
Rect earBox = Rect(vec2(center.x - radius, center.y - radius),
505
vec2(center.x + radius, center.y + radius));
506
earBox.Union(pos);
507
earBox.min -= epsilon;
508
earBox.max += epsilon;
509
510
const int lid = left->mesh_idx;
511
const int rid = right->mesh_idx;
512
QueryTwoDTree(collider.points, earBox, [&](PolyVert point) {
513
const VertItr test = collider.itr[point.idx];
514
if (!Clipped(test) && test->mesh_idx != mesh_idx &&
515
test->mesh_idx != lid &&
516
test->mesh_idx != rid) { // Skip duplicated verts
517
double cost = Cost(test, openSide, epsilon);
518
if (cost < -epsilon) {
519
cost = DelaunayCost(test->pos - center, scale, epsilon);
520
}
521
if (cost > totalCost) totalCost = cost;
522
}
523
});
524
return totalCost;
525
}
526
527
void PrintVert() const {
528
#ifdef MANIFOLD_DEBUG
529
if (ManifoldParams().verbose < TRIANGULATOR_VERBOSE_LEVEL) return;
530
std::cout << "vert: " << mesh_idx << ", left: " << left->mesh_idx
531
<< ", right: " << right->mesh_idx << ", cost: " << cost
532
<< std::endl;
533
#endif
534
}
535
};
536
537
static vec2 SafeNormalize(vec2 v) {
538
vec2 n = la::normalize(v);
539
return std::isfinite(n.x) ? n : vec2(0, 0);
540
}
541
542
// This function and JoinPolygons are the only functions that affect the
543
// circular list data structure. This helps ensure it remains circular.
544
static void Link(VertItr left, VertItr right) {
545
left->right = right;
546
right->left = left;
547
left->rightDir = SafeNormalize(right->pos - left->pos);
548
}
549
550
// When an ear vert is clipped, its neighbors get linked, so they get unlinked
551
// from it, but it is still linked to them.
552
static bool Clipped(VertItr v) { return v->right->left != v; }
553
554
// Apply func to each un-clipped vert in a polygon and return an un-clipped
555
// vert.
556
template <typename F>
557
VertItrC Loop(VertItr first, F func) const {
558
VertItr v = first;
559
do {
560
if (Clipped(v)) {
561
// Update first to an un-clipped vert so we will return to it instead
562
// of infinite-looping.
563
first = v->right->left;
564
if (!Clipped(first)) {
565
v = first;
566
if (v->right == v->left) {
567
return polygon_.end();
568
}
569
func(v);
570
}
571
} else {
572
if (v->right == v->left) {
573
return polygon_.end();
574
}
575
func(v);
576
}
577
v = v->right;
578
} while (v != first);
579
return v;
580
}
581
582
// Remove this vert from the circular list and output a corresponding
583
// triangle.
584
void ClipEar(VertItrC ear) {
585
Link(ear->left, ear->right);
586
if (ear->left->mesh_idx != ear->mesh_idx &&
587
ear->mesh_idx != ear->right->mesh_idx &&
588
ear->right->mesh_idx != ear->left->mesh_idx) {
589
// Filter out topological degenerates, which can form in bad
590
// triangulations of polygons with holes, due to vert duplication.
591
triangles_.push_back(
592
{ear->left->mesh_idx, ear->mesh_idx, ear->right->mesh_idx});
593
} else {
594
PRINT("Topological degenerate!");
595
}
596
}
597
598
// If an ear will make a degenerate triangle, clip it early to avoid
599
// difficulty in key-holing. This function is recursive, as the process of
600
// clipping may cause the neighbors to degenerate.
601
void ClipIfDegenerate(VertItr ear) {
602
if (Clipped(ear)) {
603
return;
604
}
605
if (ear->left == ear->right) {
606
return;
607
}
608
if (ear->IsShort(epsilon_) ||
609
(CCW(ear->left->pos, ear->pos, ear->right->pos, epsilon_) == 0 &&
610
la::dot(ear->left->pos - ear->pos, ear->right->pos - ear->pos) > 0)) {
611
ClipEar(ear);
612
ClipIfDegenerate(ear->left);
613
ClipIfDegenerate(ear->right);
614
}
615
}
616
617
// Build the circular list polygon structures.
618
std::vector<VertItr> Initialize(const PolygonsIdx& polys) {
619
std::vector<VertItr> starts;
620
const auto invalidItr = polygon_.begin();
621
for (const SimplePolygonIdx& poly : polys) {
622
auto vert = poly.begin();
623
polygon_.push_back({vert->idx,
624
0.0,
625
earsQueue_.end(),
626
vert->pos,
627
{0, 0},
628
invalidItr,
629
invalidItr});
630
const VertItr first = std::prev(polygon_.end());
631
632
bBox_.Union(first->pos);
633
VertItr last = first;
634
// This is not the real rightmost start, but just an arbitrary vert for
635
// now to identify each polygon.
636
starts.push_back(first);
637
638
for (++vert; vert != poly.end(); ++vert) {
639
bBox_.Union(vert->pos);
640
641
polygon_.push_back({vert->idx,
642
0.0,
643
earsQueue_.end(),
644
vert->pos,
645
{0, 0},
646
invalidItr,
647
invalidItr});
648
VertItr next = std::prev(polygon_.end());
649
650
Link(last, next);
651
last = next;
652
}
653
Link(last, first);
654
}
655
656
if (epsilon_ < 0) epsilon_ = bBox_.Scale() * kPrecision;
657
658
// Slightly more than enough, since each hole can cause two extra triangles.
659
triangles_.reserve(polygon_.size() + 2 * starts.size());
660
return starts;
661
}
662
663
// Find the actual rightmost starts after degenerate removal. Also calculate
664
// the polygon bounding boxes.
665
void FindStart(VertItr first) {
666
const vec2 origin = first->pos;
667
668
VertItr start = first;
669
double maxX = -std::numeric_limits<double>::infinity();
670
Rect bBox;
671
// Kahan summation
672
double area = 0;
673
double areaCompensation = 0;
674
675
auto AddPoint = [&](VertItr v) {
676
bBox.Union(v->pos);
677
const double area1 =
678
determinant2x2(v->pos - origin, v->right->pos - origin);
679
const double t1 = area + area1;
680
areaCompensation += (area - t1) + area1;
681
area = t1;
682
683
if (v->pos.x > maxX) {
684
maxX = v->pos.x;
685
start = v;
686
}
687
};
688
689
if (Loop(first, AddPoint) == polygon_.end()) {
690
// No polygon left if all ears were degenerate and already clipped.
691
return;
692
}
693
694
area += areaCompensation;
695
const vec2 size = bBox.Size();
696
const double minArea = epsilon_ * std::max(size.x, size.y);
697
698
if (std::isfinite(maxX) && area < -minArea) {
699
holes_.insert(start);
700
hole2BBox_.insert({start, bBox});
701
} else {
702
simples_.push_back(start);
703
if (area > minArea) {
704
outers_.push_back(start);
705
}
706
}
707
}
708
709
// All holes must be key-holed (attached to an outer polygon) before ear
710
// clipping can commence. Instead of relying on sorting, which may be
711
// incorrect due to epsilon, we check for polygon edges both ahead and
712
// behind to ensure all valid options are found.
713
void CutKeyhole(const VertItr start) {
714
const Rect bBox = hole2BBox_[start];
715
const int onTop = start->pos.y >= bBox.max.y - epsilon_ ? 1
716
: start->pos.y <= bBox.min.y + epsilon_ ? -1
717
: 0;
718
VertItr connector = polygon_.end();
719
720
auto CheckEdge = [&](VertItr edge) {
721
const double x = edge->InterpY2X(start->pos, onTop, epsilon_);
722
if (std::isfinite(x) && start->InsideEdge(edge, epsilon_, true) &&
723
(connector == polygon_.end() ||
724
CCW({x, start->pos.y}, connector->pos, connector->right->pos,
725
epsilon_) == 1 ||
726
(connector->pos.y < edge->pos.y
727
? edge->InsideEdge(connector, epsilon_, false)
728
: !connector->InsideEdge(edge, epsilon_, false)))) {
729
connector = edge;
730
}
731
};
732
733
for (const VertItr first : outers_) {
734
Loop(first, CheckEdge);
735
}
736
737
if (connector == polygon_.end()) {
738
PRINT("hole did not find an outer contour!");
739
simples_.push_back(start);
740
return;
741
}
742
743
connector = FindCloserBridge(start, connector);
744
745
JoinPolygons(start, connector);
746
747
#ifdef MANIFOLD_DEBUG
748
if (ManifoldParams().verbose >= TRIANGULATOR_VERBOSE_LEVEL) {
749
std::cout << "connected " << start->mesh_idx << " to "
750
<< connector->mesh_idx << std::endl;
751
}
752
#endif
753
}
754
755
// This converts the initial guess for the keyhole location into the final one
756
// and returns it. It does so by finding any reflex verts inside the triangle
757
// containing the best connection and the initial horizontal line.
758
VertItr FindCloserBridge(VertItr start, VertItr edge) {
759
VertItr connector =
760
edge->pos.x < start->pos.x ? edge->right
761
: edge->right->pos.x < start->pos.x ? edge
762
: edge->right->pos.y - start->pos.y > start->pos.y - edge->pos.y
763
? edge
764
: edge->right;
765
if (la::abs(connector->pos.y - start->pos.y) <= epsilon_) {
766
return connector;
767
}
768
const double above = connector->pos.y > start->pos.y ? 1 : -1;
769
770
auto CheckVert = [&](VertItr vert) {
771
const double inside =
772
above * CCW(start->pos, vert->pos, connector->pos, epsilon_);
773
if (vert->pos.x > start->pos.x - epsilon_ &&
774
vert->pos.y * above > start->pos.y * above - epsilon_ &&
775
(inside > 0 || (inside == 0 && vert->pos.x < connector->pos.x &&
776
vert->pos.y * above < connector->pos.y * above)) &&
777
vert->InsideEdge(edge, epsilon_, true) && vert->IsReflex(epsilon_)) {
778
connector = vert;
779
}
780
};
781
782
for (const VertItr first : outers_) {
783
Loop(first, CheckVert);
784
}
785
786
return connector;
787
}
788
789
// Creates a keyhole between the start vert of a hole and the connector vert
790
// of an outer polygon. To do this, both verts are duplicated and reattached.
791
// This process may create degenerate ears, so these are clipped if necessary
792
// to keep from confusing subsequent key-holing operations.
793
void JoinPolygons(VertItr start, VertItr connector) {
794
polygon_.push_back(*start);
795
const VertItr newStart = std::prev(polygon_.end());
796
polygon_.push_back(*connector);
797
const VertItr newConnector = std::prev(polygon_.end());
798
799
start->right->left = newStart;
800
connector->left->right = newConnector;
801
Link(start, connector);
802
Link(newConnector, newStart);
803
804
ClipIfDegenerate(start);
805
ClipIfDegenerate(newStart);
806
ClipIfDegenerate(connector);
807
ClipIfDegenerate(newConnector);
808
}
809
810
// Recalculate the cost of the Vert v ear, updating it in the queue by
811
// removing and reinserting it.
812
void ProcessEar(VertItr v, IdxCollider& collider) {
813
if (v->ear != earsQueue_.end()) {
814
earsQueue_.erase(v->ear);
815
v->ear = earsQueue_.end();
816
}
817
if (v->IsShort(epsilon_)) {
818
v->cost = kBest;
819
v->ear = earsQueue_.insert(v);
820
} else if (v->IsConvex(2 * epsilon_)) {
821
v->cost = v->EarCost(epsilon_, collider);
822
v->ear = earsQueue_.insert(v);
823
} else {
824
v->cost = 1; // not used, but marks reflex verts for debug
825
}
826
}
827
828
// Create a collider of all vertices in this polygon, each expanded by
829
// epsilon_. Each ear uses this BVH to quickly find a subset of vertices to
830
// check for cost.
831
IdxCollider VertCollider(VertItr start) const {
832
ZoneScoped;
833
std::vector<VertItr> itr;
834
Vec<PolyVert> points;
835
Loop(start, [&itr, &points](VertItr v) {
836
points.push_back({v->pos, static_cast<int>(itr.size())});
837
itr.push_back(v);
838
});
839
840
BuildTwoDTree(points);
841
return {std::move(points), std::move(itr)};
842
}
843
844
// The main ear-clipping loop. This is called once for each simple polygon -
845
// all holes have already been key-holed and joined to an outer polygon.
846
void TriangulatePoly(VertItr start) {
847
ZoneScoped;
848
849
IdxCollider vertCollider = VertCollider(start);
850
851
if (vertCollider.itr.empty()) {
852
PRINT("Empty poly");
853
return;
854
}
855
856
// A simple polygon always creates two fewer triangles than it has verts.
857
int numTri = -2;
858
earsQueue_.clear();
859
860
auto QueueVert = [&](VertItr v) {
861
ProcessEar(v, vertCollider);
862
++numTri;
863
v->PrintVert();
864
};
865
866
VertItrC v = Loop(start, QueueVert);
867
if (v == polygon_.end()) return;
868
Dump(v);
869
870
while (numTri > 0) {
871
const qItr ear = earsQueue_.begin();
872
if (ear != earsQueue_.end()) {
873
v = *ear;
874
// Cost should always be negative, generally < -epsilon.
875
v->PrintVert();
876
earsQueue_.erase(ear);
877
} else {
878
PRINT("No ear found!");
879
}
880
881
ClipEar(v);
882
--numTri;
883
884
ProcessEar(v->left, vertCollider);
885
ProcessEar(v->right, vertCollider);
886
// This is a backup vert that is used if the queue is empty (geometrically
887
// invalid polygon), to ensure manifoldness.
888
v = v->right;
889
}
890
891
DEBUG_ASSERT(v->right == v->left, logicErr, "Triangulator error!");
892
PRINT("Finished poly");
893
}
894
895
void Dump(VertItrC start) const {
896
#ifdef MANIFOLD_DEBUG
897
if (ManifoldParams().verbose < TRIANGULATOR_VERBOSE_LEVEL) return;
898
VertItrC v = start;
899
std::cout << "show(array([" << std::setprecision(15) << std::endl;
900
do {
901
std::cout << " [" << v->pos.x << ", " << v->pos.y << "],# "
902
<< v->mesh_idx << ", cost: " << v->cost << std::endl;
903
v = v->right;
904
} while (v != start);
905
std::cout << " [" << v->pos.x << ", " << v->pos.y << "],# " << v->mesh_idx
906
<< std::endl;
907
std::cout << "]))" << std::endl;
908
909
v = start;
910
std::cout << "polys.push_back({" << std::setprecision(15) << std::endl;
911
do {
912
std::cout << " {" << v->pos.x << ", " << v->pos.y << "}, //"
913
<< std::endl;
914
v = v->right;
915
} while (v != start);
916
std::cout << "});" << std::endl;
917
#endif
918
}
919
};
920
} // namespace
921
922
namespace manifold {
923
924
/**
925
* @brief Triangulates a set of &epsilon;-valid polygons. If the input is not
926
* &epsilon;-valid, the triangulation may overlap, but will always return a
927
* manifold result that matches the input edge directions.
928
*
929
* @param polys The set of polygons, wound CCW and representing multiple
930
* polygons and/or holes. These have 2D-projected positions as well as
931
* references back to the original vertices.
932
* @param epsilon The value of &epsilon;, bounding the uncertainty of the
933
* input.
934
* @param allowConvex If true (default), the triangulator will use a fast
935
* triangulation if the input is convex, falling back to ear-clipping if not.
936
* The triangle quality may be lower, so set to false to disable this
937
* optimization.
938
* @return std::vector<ivec3> The triangles, referencing the original
939
* vertex indicies.
940
*/
941
std::vector<ivec3> TriangulateIdx(const PolygonsIdx& polys, double epsilon,
942
bool allowConvex) {
943
std::vector<ivec3> triangles;
944
double updatedEpsilon = epsilon;
945
#ifdef MANIFOLD_DEBUG
946
try {
947
#endif
948
if (allowConvex && IsConvex(polys, epsilon)) { // fast path
949
triangles = TriangulateConvex(polys);
950
} else {
951
EarClip triangulator(polys, epsilon);
952
triangles = triangulator.Triangulate();
953
updatedEpsilon = triangulator.GetPrecision();
954
}
955
#ifdef MANIFOLD_DEBUG
956
if (ManifoldParams().intermediateChecks) {
957
CheckTopology(triangles, polys);
958
if (!ManifoldParams().processOverlaps) {
959
CheckGeometry(triangles, polys, 2 * updatedEpsilon);
960
}
961
}
962
} catch (const geometryErr& e) {
963
if (!ManifoldParams().suppressErrors) {
964
PrintFailure(e, polys, triangles, updatedEpsilon);
965
}
966
throw;
967
} catch (const std::exception& e) {
968
PrintFailure(e, polys, triangles, updatedEpsilon);
969
throw;
970
}
971
#endif
972
return triangles;
973
}
974
975
/**
976
* @brief Triangulates a set of &epsilon;-valid polygons. If the input is not
977
* &epsilon;-valid, the triangulation may overlap, but will always return a
978
* manifold result that matches the input edge directions.
979
*
980
* @param polygons The set of polygons, wound CCW and representing multiple
981
* polygons and/or holes.
982
* @param epsilon The value of &epsilon;, bounding the uncertainty of the
983
* input.
984
* @param allowConvex If true (default), the triangulator will use a fast
985
* triangulation if the input is convex, falling back to ear-clipping if not.
986
* The triangle quality may be lower, so set to false to disable this
987
* optimization.
988
* @return std::vector<ivec3> The triangles, referencing the original
989
* polygon points in order.
990
*/
991
std::vector<ivec3> Triangulate(const Polygons& polygons, double epsilon,
992
bool allowConvex) {
993
int idx = 0;
994
PolygonsIdx polygonsIndexed;
995
for (const auto& poly : polygons) {
996
SimplePolygonIdx simpleIndexed;
997
for (const vec2& polyVert : poly) {
998
simpleIndexed.push_back({polyVert, idx++});
999
}
1000
polygonsIndexed.push_back(simpleIndexed);
1001
}
1002
return TriangulateIdx(polygonsIndexed, epsilon, allowConvex);
1003
}
1004
1005
} // namespace manifold
1006
1007