Blender V5.0
delaunay_2d.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10#include <atomic>
11#include <fstream>
12#include <iostream>
13#include <sstream>
14
15#include "BLI_array.hh"
16#include "BLI_linklist.h"
17#include "BLI_math_boolean.hh"
19#include "BLI_set.hh"
20#include "BLI_task.hh"
21#include "BLI_vector.hh"
22
23#include "BLI_delaunay_2d.hh"
24
25namespace blender::meshintersect {
26
27using namespace blender::math;
28
29/* Throughout this file, template argument T will be an
30 * arithmetic-like type, like float, double, or mpq_class. */
31
32template<typename T> T math_abs(const T v)
33{
34 return (v < 0) ? -v : v;
35}
36
37#ifdef WITH_GMP
38template<> mpq_class math_abs<mpq_class>(const mpq_class v)
39{
40 return abs(v);
41}
42#endif
43
44template<> double math_abs<double>(const double v)
45{
46 return fabs(v);
47}
48
49template<typename T> double math_to_double(const T /*v*/)
50{
51 BLI_assert(false); /* Need implementation for other type. */
52 return 0.0;
53}
54
55#ifdef WITH_GMP
56template<> double math_to_double<mpq_class>(const mpq_class v)
57{
58 return v.get_d();
59}
60#endif
61
62template<> double math_to_double<double>(const double v)
63{
64 return v;
65}
66
78template<typename T> struct CDTVert;
79template<typename T> struct CDTEdge;
80template<typename T> struct CDTFace;
81
82template<typename T> struct SymEdge {
84 SymEdge<T> *next{nullptr};
86 SymEdge<T> *rot{nullptr};
88 CDTVert<T> *vert{nullptr};
90 CDTEdge<T> *edge{nullptr};
92 CDTFace<T> *face{nullptr};
93
94 SymEdge() = default;
95};
96
100template<typename T> inline SymEdge<T> *sym(const SymEdge<T> *se)
101{
102 return se->next->rot;
103}
104
106template<typename T> inline SymEdge<T> *prev(const SymEdge<T> *se)
107{
108 return se->rot->next->rot;
109}
110
112
113template<typename T> struct FatCo {
117
119#ifdef WITH_GMP
120 FatCo(const mpq2 &v);
121#endif
122 FatCo(const double2 &v);
123};
124
125#ifdef WITH_GMP
126template<> struct FatCo<mpq_class> {
127 mpq2 exact;
130
131 FatCo() : exact(mpq2(0, 0)), approx(double2(0, 0)), abs_approx(double2(0, 0)) {}
132
133 FatCo(const mpq2 &v)
134 {
135 exact = v;
136 approx = double2(v.x.get_d(), v.y.get_d());
138 }
139
140 FatCo(const double2 &v)
141 {
142 exact = mpq2(v.x, v.y);
143 approx = v;
145 }
146};
147#endif
148
149template<> struct FatCo<double> {
153
154 FatCo() : exact(double2(0, 0)), approx(double2(0, 0)), abs_approx(double2(0, 0)) {}
155
156#ifdef WITH_GMP
157 FatCo(const mpq2 &v)
158 {
159 exact = double2(v.x.get_d(), v.y.get_d());
160 approx = exact;
162 }
163#endif
164
166 {
167 exact = v;
168 approx = v;
170 }
171};
172
173template<typename T> std::ostream &operator<<(std::ostream &stream, const FatCo<T> &co)
174{
175 stream << "(" << co.approx.x << ", " << co.approx.y << ")";
176 return stream;
177}
178
179template<typename T> struct CDTVert {
187 int index{-1};
192
193 CDTVert() = default;
194 explicit CDTVert(const VecBase<T, 2> &pt);
195};
196
197template<typename T> struct CDTEdge {
204
205 CDTEdge() = default;
206};
207
208template<typename T> struct CDTFace {
218 bool deleted{false};
220 bool hole{false};
221
222 CDTFace() = default;
223};
224
225template<typename T> struct CDTArrangement {
226 /* The arrangement owns the memory pointed to by the pointers in these vectors.
227 * They are pointers instead of actual structures because these vectors may be resized and
228 * other elements refer to the elements by pointer. */
229
238
239 CDTArrangement() = default;
241
244 void reserve(int verts_num, int edges_num, int faces_num);
245
251
259
265
268
276
282
287 CDTEdge<T> *split_edge(SymEdge<T> *se, T lambda);
288
294 void delete_edge(SymEdge<T> *se);
295
301 {
302 CDTVert<T> *v = this->verts[i];
303 if (v->merge_to_index != -1) {
304 v = this->verts[v->merge_to_index];
305 }
306 return v;
307 }
308};
309
310template<typename T> class CDT_state {
311 public:
326
327 explicit CDT_state(
328 int input_verts_num, int input_edges_num, int input_faces_num, T epsilon, bool need_ids);
329};
330
332{
333 for (int i : this->verts.index_range()) {
334 CDTVert<T> *v = this->verts[i];
335 v->input_ids.clear();
336 delete v;
337 this->verts[i] = nullptr;
338 }
339 for (int i : this->edges.index_range()) {
340 CDTEdge<T> *e = this->edges[i];
341 e->input_ids.clear();
342 delete e;
343 this->edges[i] = nullptr;
344 }
345 for (int i : this->faces.index_range()) {
346 CDTFace<T> *f = this->faces[i];
347 f->input_ids.clear();
348 delete f;
349 this->faces[i] = nullptr;
350 }
351}
352
353#define DEBUG_CDT
354#ifdef DEBUG_CDT
355/* Some functions to aid in debugging. */
356template<typename T> std::string vertname(const CDTVert<T> *v)
357{
358 std::stringstream ss;
359 ss << "[" << v->index << "]";
360 return ss.str();
361}
362
363/* Abbreviated pointer value is easier to read in dumps. */
364static std::string trunc_ptr(const void *p)
365{
366 constexpr int TRUNC_PTR_MASK = 0xFFFF;
367 std::stringstream ss;
368 ss << std::hex << (POINTER_AS_INT(p) & TRUNC_PTR_MASK);
369 return ss.str();
370}
371
372template<typename T> std::string sename(const SymEdge<T> *se)
373{
374 std::stringstream ss;
375 ss << "{" << trunc_ptr(se) << "}";
376 return ss.str();
377}
378
379template<typename T> std::ostream &operator<<(std::ostream &os, const SymEdge<T> &se)
380{
381 if (se.next) {
382 os << vertname(se.vert) << "(" << se.vert->co << "->" << se.next->vert->co << ")"
383 << vertname(se.next->vert);
384 }
385 else {
386 os << vertname(se.vert) << "(" << se.vert->co << "->null)";
387 }
388 return os;
389}
390
391template<typename T> std::ostream &operator<<(std::ostream &os, const SymEdge<T> *se)
392{
393 os << *se;
394 return os;
395}
396
397template<typename T> std::string short_se_dump(const SymEdge<T> *se)
398{
399 if (se == nullptr) {
400 return std::string("null");
401 }
402 return vertname(se->vert) +
403 (se->next == nullptr ? std::string("[null]") : vertname(se->next->vert));
404}
405
406template<typename T> std::ostream &operator<<(std::ostream &os, const CDT_state<T> &cdt_state)
407{
408 os << "\nCDT\n\nVERTS\n";
409 for (const CDTVert<T> *v : cdt_state.cdt.verts) {
410 os << vertname(v) << " " << trunc_ptr(v) << ": " << v->co
411 << " symedge=" << trunc_ptr(v->symedge);
412 if (v->merge_to_index == -1) {
413 os << "\n";
414 }
415 else {
416 os << " merge to " << vertname(cdt_state.cdt.verts[v->merge_to_index]) << "\n";
417 }
418 const SymEdge<T> *se = v->symedge;
419 int count = 0;
420 constexpr int print_count_limit = 25;
421 if (se) {
422 os << " edges out:\n";
423 do {
424 if (se->next == nullptr) {
425 os << " [null] next/rot symedge, se=" << trunc_ptr(se) << "\n";
426 break;
427 }
428 if (se->next->next == nullptr) {
429 os << " [null] next-next/rot symedge, se=" << trunc_ptr(se) << "\n";
430 break;
431 }
432 const CDTVert<T> *vother = sym(se)->vert;
433 os << " " << vertname(vother) << "(e=" << trunc_ptr(se->edge)
434 << ", se=" << trunc_ptr(se) << ")\n";
435 se = se->rot;
436 count++;
437 } while (se != v->symedge && count < print_count_limit);
438 os << "\n";
439 }
440 }
441 os << "\nEDGES\n";
442 for (const CDTEdge<T> *e : cdt_state.cdt.edges) {
443 if (e->symedges[0].next == nullptr) {
444 continue;
445 }
446 os << trunc_ptr(&e) << ":\n";
447 for (int i = 0; i < 2; ++i) {
448 const SymEdge<T> *se = &e->symedges[i];
449 os << " se[" << i << "] @" << trunc_ptr(se) << " next=" << trunc_ptr(se->next)
450 << ", rot=" << trunc_ptr(se->rot) << ", vert=" << trunc_ptr(se->vert) << " "
451 << vertname(se->vert) << " " << se->vert->co << ", edge=" << trunc_ptr(se->edge)
452 << ", face=" << trunc_ptr(se->face) << "\n";
453 }
454 }
455 os << "\nFACES\n";
456 os << "outer_face=" << trunc_ptr(cdt_state.cdt.outer_face) << "\n";
457 /* Only after prepare_output do faces have non-null symedges. */
458 if (cdt_state.cdt.outer_face->symedge != nullptr) {
459 for (const CDTFace<T> *f : cdt_state.cdt.faces) {
460 if (!f->deleted) {
461 os << trunc_ptr(f) << " symedge=" << trunc_ptr(f->symedge) << "\n";
462 }
463 }
464 }
465 return os;
466}
467
468template<typename T> void cdt_draw(const std::string &label, const CDTArrangement<T> &cdt)
469{
470 static bool append = false; /* Will be set to true after first call. */
471
472/* Would like to use #BKE_tempdir_base() here, but that brings in dependence on kernel library.
473 * This is just for developer debugging anyway, and should never be called in production Blender.
474 */
475# ifdef _WIN32
476 const char *drawfile = "./cdt_debug_draw.html";
477# else
478 const char *drawfile = "/tmp/cdt_debug_draw.html";
479# endif
480 constexpr int max_draw_width = 1800;
481 constexpr int max_draw_height = 1600;
482 constexpr double margin_expand = 0.05;
483 constexpr int thin_line = 1;
484 constexpr int thick_line = 4;
485 constexpr int vert_radius = 3;
486 constexpr bool draw_vert_labels = true;
487 constexpr bool draw_edge_labels = false;
488 constexpr bool draw_face_labels = false;
489
490 if (cdt.verts.is_empty()) {
491 return;
492 }
493 double2 vmin(std::numeric_limits<double>::max());
494 double2 vmax(std::numeric_limits<double>::lowest());
495 for (const CDTVert<T> *v : cdt.verts) {
496 math::min_max(v->co.approx, vmin, vmax);
497 }
498 double draw_margin = ((vmax.x - vmin.x) + (vmax.y - vmin.y)) * margin_expand;
499 double minx = vmin.x - draw_margin;
500 double maxx = vmax.x + draw_margin;
501 double miny = vmin.y - draw_margin;
502 double maxy = vmax.y + draw_margin;
503
504 double width = maxx - minx;
505 double height = maxy - miny;
506 double aspect = height / width;
507 int view_width = max_draw_width;
508 int view_height = int(view_width * aspect);
509 if (view_height > max_draw_height) {
510 view_height = max_draw_height;
511 view_width = int(view_height / aspect);
512 }
513 double scale = view_width / width;
514
515# define SX(x) (((x) - minx) * scale)
516# define SY(y) ((maxy - (y)) * scale)
517
518 std::ofstream f;
519 if (append) {
520 f.open(drawfile, std::ios_base::app);
521 }
522 else {
523 f.open(drawfile);
524 }
525 if (!f) {
526 std::cout << "Could not open file " << drawfile << "\n";
527 return;
528 }
529
530 f << "<div>" << label << "</div>\n<div>\n"
531 << "<svg version=\"1.1\" "
532 "xmlns=\"http://www.w3.org/2000/svg\" "
533 "xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
534 "xml:space=\"preserve\"\n"
535 << "width=\"" << view_width << "\" height=\"" << view_height << "\">n";
536
537 for (const CDTEdge<T> *e : cdt.edges) {
538 if (e->symedges[0].next == nullptr) {
539 continue;
540 }
541 const CDTVert<T> *u = e->symedges[0].vert;
542 const CDTVert<T> *v = e->symedges[1].vert;
543 const double2 &uco = u->co.approx;
544 const double2 &vco = v->co.approx;
545 int strokew = e->input_ids.size() == 0 ? thin_line : thick_line;
546 f << R"(<line fill="none" stroke="black" stroke-width=")" << strokew << "\" x1=\""
547 << SX(uco[0]) << "\" y1=\"" << SY(uco[1]) << "\" x2=\"" << SX(vco[0]) << "\" y2=\""
548 << SY(vco[1]) << "\">\n";
549 f << " <title>" << vertname(u) << vertname(v) << "</title>\n";
550 f << "</line>\n";
551 if (draw_edge_labels) {
552 f << "<text x=\"" << SX((uco[0] + vco[0]) / 2) << "\" y=\"" << SY((uco[1] + vco[1]) / 2)
553 << R"(" font-size="small">)";
554 f << vertname(u) << vertname(v) << sename(&e->symedges[0]) << sename(&e->symedges[1])
555 << "</text>\n";
556 }
557 }
558
559 int i = 0;
560 for (const CDTVert<T> *v : cdt.verts) {
561 f << R"(<circle fill="black" cx=")" << SX(v->co.approx[0]) << "\" cy=\"" << SY(v->co.approx[1])
562 << "\" r=\"" << vert_radius << "\">\n";
563 f << " <title>[" << i << "]" << v->co.approx << "</title>\n";
564 f << "</circle>\n";
565 if (draw_vert_labels) {
566 f << "<text x=\"" << SX(v->co.approx[0]) + vert_radius << "\" y=\""
567 << SY(v->co.approx[1]) - vert_radius << R"(" font-size="small">[)" << i << "]</text>\n";
568 }
569 ++i;
570 }
571
572 if (draw_face_labels) {
573 for (const CDTFace<T> *face : cdt.faces) {
574 if (!face->deleted) {
575 /* Since may not have prepared output yet, need a slow find of a SymEdge for this face. */
576 const SymEdge<T> *se_face_start = nullptr;
577 for (const CDTEdge<T> *e : cdt.edges) {
578 if (e->symedges[0].face == face) {
579 se_face_start = &e->symedges[0];
580 break;
581 }
582 if (e->symedges[1].face == face) {
583 se_face_start = &e->symedges[1];
584 }
585 }
586 if (se_face_start != nullptr) {
587 /* Find center of face. */
588 int face_nverts = 0;
589 double2 cen(0.0, 0.0);
590 if (face == cdt.outer_face) {
591 cen.x = minx;
592 cen.y = miny;
593 }
594 else {
595 const SymEdge<T> *se = se_face_start;
596 do {
597 if (se->face == face) {
598 cen = cen + se->vert->co.approx;
599 face_nverts++;
600 }
601 } while ((se = se->next) != se_face_start);
602 if (face_nverts > 0) {
603 cen = cen / double(face_nverts);
604 }
605 }
606 f << "<text x=\"" << SX(cen[0]) << "\" y=\"" << SY(cen[1]) << "\""
607 << " font-size=\"small\">[";
608 f << trunc_ptr(face);
609 if (face->input_ids.size() > 0) {
610 for (int id : face->input_ids) {
611 f << " " << id;
612 }
613 }
614 f << "]</text>\n";
615 }
616 }
617 }
618 }
619
620 append = true;
621# undef SX
622# undef SY
623}
624#endif
625
630template<typename T>
631static int filtered_orient2d(const FatCo<T> &a, const FatCo<T> &b, const FatCo<T> &c);
632
633#ifdef WITH_GMP
634template<>
636 const FatCo<mpq_class> &b,
637 const FatCo<mpq_class> &c)
638{
639 double det = (a.approx[0] - c.approx[0]) * (b.approx[1] - c.approx[1]) -
640 (a.approx[1] - c.approx[1]) * (b.approx[0] - c.approx[0]);
641 double supremum = (a.abs_approx[0] + c.abs_approx[0]) * (b.abs_approx[1] + c.abs_approx[1]) +
642 (a.abs_approx[1] + c.abs_approx[1]) * (b.abs_approx[0] + c.abs_approx[0]);
643 constexpr double index_orient2d = 6;
644 double err_bound = supremum * index_orient2d * DBL_EPSILON;
645 if (fabs(det) > err_bound) {
646 return det > 0 ? 1 : -1;
647 }
648 return orient2d(a.exact, b.exact, c.exact);
649}
650#endif
651
652template<>
654 const FatCo<double> &b,
655 const FatCo<double> &c)
656{
657 return orient2d(a.approx, b.approx, c.approx);
658}
659
663template<typename T>
664static int filtered_incircle(const FatCo<T> &a,
665 const FatCo<T> &b,
666 const FatCo<T> &c,
667 const FatCo<T> &d);
668
669#ifdef WITH_GMP
670template<>
672 const FatCo<mpq_class> &b,
673 const FatCo<mpq_class> &c,
674 const FatCo<mpq_class> &d)
675{
676 double adx = a.approx[0] - d.approx[0];
677 double bdx = b.approx[0] - d.approx[0];
678 double cdx = c.approx[0] - d.approx[0];
679 double ady = a.approx[1] - d.approx[1];
680 double bdy = b.approx[1] - d.approx[1];
681 double cdy = c.approx[1] - d.approx[1];
682 double bdxcdy = bdx * cdy;
683 double cdxbdy = cdx * bdy;
684 double alift = adx * adx + ady * ady;
685 double cdxady = cdx * ady;
686 double adxcdy = adx * cdy;
687 double blift = bdx * bdx + bdy * bdy;
688 double adxbdy = adx * bdy;
689 double bdxady = bdx * ady;
690 double clift = cdx * cdx + cdy * cdy;
691 double det = alift * (bdxcdy - cdxbdy) + blift * (cdxady - adxcdy) + clift * (adxbdy - bdxady);
692
693 double sup_adx = a.abs_approx[0] + d.abs_approx[0]; /* index 2. */
694 double sup_bdx = b.abs_approx[0] + d.abs_approx[0];
695 double sup_cdx = c.abs_approx[0] + d.abs_approx[0];
696 double sup_ady = a.abs_approx[1] + d.abs_approx[1];
697 double sup_bdy = b.abs_approx[1] + d.abs_approx[1];
698 double sup_cdy = c.abs_approx[1] + d.abs_approx[1];
699 double sup_bdxcdy = sup_bdx * sup_cdy; /* index 5. */
700 double sup_cdxbdy = sup_cdx * sup_bdy;
701 double sup_alift = sup_adx * sup_adx + sup_ady * sup_ady; /* index 6. */
702 double sup_cdxady = sup_cdx * sup_ady;
703 double sup_adxcdy = sup_adx * sup_cdy;
704 double sup_blift = sup_bdx * sup_bdx + sup_bdy * sup_bdy;
705 double sup_adxbdy = sup_adx * sup_bdy;
706 double sup_bdxady = sup_bdx * sup_ady;
707 double sup_clift = sup_cdx * sup_cdx + sup_cdy * sup_cdy;
708 double sup_det = sup_alift * (sup_bdxcdy + sup_cdxbdy) + sup_blift * (sup_cdxady + sup_adxcdy) +
709 sup_clift * (sup_adxbdy + sup_bdxady);
710 int index = 14;
711 double err_bound = sup_det * index * DBL_EPSILON;
712 if (fabs(det) > err_bound) {
713 return det < 0.0 ? -1 : (det > 0.0 ? 1 : 0);
714 }
715 return incircle(a.exact, b.exact, c.exact, d.exact);
716}
717#endif
718
719template<>
721 const FatCo<double> &b,
722 const FatCo<double> &c,
723 const FatCo<double> &d)
724{
725 return incircle(a.approx, b.approx, c.approx, d.approx);
726}
727
734template<typename T> static bool in_line(const FatCo<T> &a, const FatCo<T> &b, const FatCo<T> &c);
735
736#ifdef WITH_GMP
737template<>
739 const FatCo<mpq_class> &b,
740 const FatCo<mpq_class> &c)
741{
742 double2 ab = b.approx - a.approx;
743 double2 bc = c.approx - b.approx;
744 double2 ac = c.approx - a.approx;
745 double2 supremum_ab = b.abs_approx + a.abs_approx;
746 double2 supremum_bc = c.abs_approx + b.abs_approx;
747 double2 supremum_ac = c.abs_approx + a.abs_approx;
748 double dot_ab_ac = ab.x * ac.x + ab.y * ac.y;
749 double supremum_dot_ab_ac = supremum_ab.x * supremum_ac.x + supremum_ab.y * supremum_ac.y;
750 constexpr double index = 6;
751 double err_bound = supremum_dot_ab_ac * index * DBL_EPSILON;
752 if (dot_ab_ac < -err_bound) {
753 return false;
754 }
755 double dot_bc_ac = bc.x * ac.x + bc.y * ac.y;
756 double supremum_dot_bc_ac = supremum_bc.x * supremum_ac.x + supremum_bc.y * supremum_ac.y;
757 err_bound = supremum_dot_bc_ac * index * DBL_EPSILON;
758 if (dot_bc_ac < -err_bound) {
759 return false;
760 }
761 mpq2 exact_ab = b.exact - a.exact;
762 mpq2 exact_ac = c.exact - a.exact;
763 if (dot(exact_ab, exact_ac) < 0) {
764 return false;
765 }
766 mpq2 exact_bc = c.exact - b.exact;
767 return dot(exact_bc, exact_ac) >= 0;
768}
769#endif
770
771template<>
773{
774 double2 ab = b.approx - a.approx;
775 double2 ac = c.approx - a.approx;
776 if (dot(ab, ac) < 0) {
777 return false;
778 }
779 double2 bc = c.approx - b.approx;
780 return dot(bc, ac) >= 0;
781}
782
784{
785 this->co.exact = pt;
786 this->co.approx = pt;
787 this->co.abs_approx = pt; /* Not used, so doesn't matter. */
788 this->symedge = nullptr;
789 this->index = -1;
790 this->merge_to_index = -1;
791 this->visit_index = 0;
792}
793
794#ifdef WITH_GMP
795template<> CDTVert<mpq_class>::CDTVert(const mpq2 &pt)
796{
797 this->co.exact = pt;
798 this->co.approx = double2(pt.x.get_d(), pt.y.get_d());
799 this->co.abs_approx = double2(fabs(this->co.approx.x), fabs(this->co.approx.y));
800 this->symedge = nullptr;
801 this->index = -1;
802 this->merge_to_index = -1;
803 this->visit_index = 0;
804}
805#endif
806
808{
809 CDTVert<T> *v = new CDTVert<T>(pt);
810 int index = this->verts.append_and_get_index(v);
811 v->index = index;
812 return v;
813}
814
815template<typename T>
817 CDTVert<T> *v2,
818 CDTFace<T> *fleft,
819 CDTFace<T> *fright)
820{
821 CDTEdge<T> *e = new CDTEdge<T>();
822 this->edges.append(e);
823 SymEdge<T> *se = &e->symedges[0];
824 SymEdge<T> *sesym = &e->symedges[1];
825 se->edge = sesym->edge = e;
826 se->face = fleft;
827 sesym->face = fright;
828 se->vert = v1;
829 if (v1->symedge == nullptr) {
830 v1->symedge = se;
831 }
832 sesym->vert = v2;
833 if (v2->symedge == nullptr) {
834 v2->symedge = sesym;
835 }
836 se->next = sesym->next = se->rot = sesym->rot = nullptr;
837 return e;
838}
839
841{
842 CDTFace<T> *f = new CDTFace<T>();
843 this->faces.append(f);
844 return f;
845}
846
847template<typename T> void CDTArrangement<T>::reserve(int verts_num, int edges_num, int faces_num)
848{
849 /* These reserves are just guesses; OK if they aren't exactly right since vectors will resize. */
850 this->verts.reserve(2 * verts_num);
851 this->edges.reserve(3 * verts_num + 2 * edges_num + 3 * 2 * faces_num);
852 this->faces.reserve(2 * verts_num + 2 * edges_num + 2 * faces_num);
853}
854
855template<typename T>
857 int input_verts_num, int input_edges_num, int input_faces_num, T epsilon, bool need_ids)
858{
859 this->input_vert_num = input_verts_num;
860 this->cdt.reserve(input_verts_num, input_edges_num, input_faces_num);
861 this->cdt.outer_face = this->cdt.add_face();
862 this->epsilon = epsilon;
863 this->need_ids = need_ids;
864 this->visit_count = 0;
865}
866
867/* Is any id in (range_start, range_start+1, ... , range_end) in id_list? */
868static bool id_range_in_list(const blender::Set<int> &id_list, int range_start, int range_end)
869{
870 for (int id : id_list) {
871 if (id >= range_start && id <= range_end) {
872 return true;
873 }
874 }
875 return false;
876}
877
878static void add_to_input_ids(blender::Set<int> &dst, int input_id)
879{
880 dst.add(input_id);
881}
882
884{
885 for (int value : src) {
886 dst.add(value);
887 }
888}
889
890template<typename T> inline bool is_border_edge(const CDTEdge<T> *e, const CDT_state<T> *cdt)
891{
892 return e->symedges[0].face == cdt->outer_face || e->symedges[1].face == cdt->outer_face;
893}
894
895template<typename T> inline bool is_constrained_edge(const CDTEdge<T> *e)
896{
897 return e->input_ids.size() > 0;
898}
899
900template<typename T> inline bool is_deleted_edge(const CDTEdge<T> *e)
901{
902 return e->symedges[0].next == nullptr;
903}
904
905template<typename T> inline bool is_original_vert(const CDTVert<T> *v, CDT_state<T> *cdt)
906{
907 return (v->index < cdt->input_vert_num);
908}
909
913template<typename T>
915{
916 SymEdge<T> *t = v1->symedge;
917 SymEdge<T> *tstart = t;
918 do {
919 if (t->next->vert == v2) {
920 return t;
921 }
922 } while ((t = t->rot) != tstart);
923 return nullptr;
924}
925
929template<typename T> SymEdge<T> *find_symedge_with_face(const CDTVert<T> *v, const CDTFace<T> *f)
930{
931 SymEdge<T> *t = v->symedge;
932 SymEdge<T> *tstart = t;
933 do {
934 if (t->face == f) {
935 return t;
936 }
937 } while ((t = t->rot) != tstart);
938 return nullptr;
939}
940
944template<typename T> inline bool exists_edge(const CDTVert<T> *v1, const CDTVert<T> *v2)
945{
946 return find_symedge_between_verts(v1, v2) != nullptr;
947}
948
952template<typename T> bool vert_touches_face(const CDTVert<T> *v, const CDTFace<T> *f)
953{
954 SymEdge<T> *se = v->symedge;
955 do {
956 if (se->face == f) {
957 return true;
958 }
959 } while ((se = se->rot) != v->symedge);
960 return false;
961}
962
972{
973 CDTFace<T> *fold = s1->face;
974 CDTFace<T> *fnew = this->add_face();
975 SymEdge<T> *s1prev = prev(s1);
976 SymEdge<T> *s1prevsym = sym(s1prev);
977 SymEdge<T> *s2prev = prev(s2);
978 SymEdge<T> *s2prevsym = sym(s2prev);
979 CDTEdge<T> *ediag = this->add_edge(s1->vert, s2->vert, fnew, fold);
980 SymEdge<T> *sdiag = &ediag->symedges[0];
981 SymEdge<T> *sdiagsym = &ediag->symedges[1];
982 sdiag->next = s2;
983 sdiagsym->next = s1;
984 s2prev->next = sdiagsym;
985 s1prev->next = sdiag;
986 s1->rot = sdiag;
987 sdiag->rot = s1prevsym;
988 s2->rot = sdiagsym;
989 sdiagsym->rot = s2prevsym;
990 for (SymEdge<T> *se = s2; se != sdiag; se = se->next) {
991 se->face = fnew;
992 }
994 return ediag;
995}
996
997template<typename T>
999{
1000 SymEdge<T> *se_rot = se->rot;
1001 SymEdge<T> *se_rotsym = sym(se_rot);
1002 /* TODO: check: I think last arg in next should be sym(se)->face. */
1003 CDTEdge<T> *e = this->add_edge(v, se->vert, se->face, se->face);
1004 SymEdge<T> *new_se = &e->symedges[0];
1005 SymEdge<T> *new_se_sym = &e->symedges[1];
1006 new_se->next = se;
1007 new_se_sym->next = new_se;
1008 new_se->rot = new_se;
1009 new_se_sym->rot = se_rot;
1010 se->rot = new_se_sym;
1011 se_rotsym->next = new_se_sym;
1012 return e;
1013}
1014
1020template<typename T>
1022{
1023 BLI_assert(se1->face == this->outer_face && se2->face == this->outer_face);
1024 SymEdge<T> *se1_rot = se1->rot;
1025 SymEdge<T> *se1_rotsym = sym(se1_rot);
1026 SymEdge<T> *se2_rot = se2->rot;
1027 SymEdge<T> *se2_rotsym = sym(se2_rot);
1028 CDTEdge<T> *e = this->add_edge(se1->vert, se2->vert, this->outer_face, this->outer_face);
1029 SymEdge<T> *new_se = &e->symedges[0];
1030 SymEdge<T> *new_se_sym = &e->symedges[1];
1031 new_se->next = se2;
1032 new_se_sym->next = se1;
1033 new_se->rot = se1_rot;
1034 new_se_sym->rot = se2_rot;
1035 se1->rot = new_se;
1036 se2->rot = new_se_sym;
1037 se1_rotsym->next = new_se;
1038 se2_rotsym->next = new_se_sym;
1039 return e;
1040}
1041
1047template<typename T> CDTEdge<T> *CDTArrangement<T>::split_edge(SymEdge<T> *se, T lambda)
1048{
1049 /* Split e at lambda. */
1050 const VecBase<T, 2> *a = &se->vert->co.exact;
1051 const VecBase<T, 2> *b = &se->next->vert->co.exact;
1052 SymEdge<T> *sesym = sym(se);
1053 SymEdge<T> *sesymprev = prev(sesym);
1054 SymEdge<T> *sesymprevsym = sym(sesymprev);
1055 SymEdge<T> *senext = se->next;
1056 CDTVert<T> *v = this->add_vert(interpolate(*a, *b, lambda));
1057 CDTEdge<T> *e = this->add_edge(v, se->next->vert, se->face, sesym->face);
1058 sesym->vert = v;
1059 SymEdge<T> *newse = &e->symedges[0];
1060 SymEdge<T> *newsesym = &e->symedges[1];
1061 se->next = newse;
1062 newsesym->next = sesym;
1063 newse->next = senext;
1064 newse->rot = sesym;
1065 sesym->rot = newse;
1066 senext->rot = newsesym;
1067 newsesym->rot = sesymprevsym;
1068 sesymprev->next = newsesym;
1069 if (newsesym->vert->symedge == sesym) {
1070 newsesym->vert->symedge = newsesym;
1071 }
1072 add_list_to_input_ids(e->input_ids, se->edge->input_ids);
1073 return e;
1074}
1075
1097template<typename T> void CDTArrangement<T>::delete_edge(SymEdge<T> *se)
1098{
1099 SymEdge<T> *sesym = sym(se);
1100 CDTVert<T> *v1 = se->vert;
1101 CDTVert<T> *v2 = sesym->vert;
1102 CDTFace<T> *aface = se->face;
1103 CDTFace<T> *bface = sesym->face;
1104 SymEdge<T> *f = se->next;
1105 SymEdge<T> *h = prev(se);
1106 SymEdge<T> *i = sesym->next;
1107 SymEdge<T> *j = prev(sesym);
1108 SymEdge<T> *jsym = sym(j);
1109 SymEdge<T> *hsym = sym(h);
1110 bool v1_isolated = (i == se);
1111 bool v2_isolated = (f == sesym);
1112
1113 if (!v1_isolated) {
1114 h->next = i;
1115 i->rot = hsym;
1116 }
1117 if (!v2_isolated) {
1118 j->next = f;
1119 f->rot = jsym;
1120 }
1121 if (!v1_isolated && !v2_isolated && aface != bface) {
1122 for (SymEdge<T> *k = i; k != f; k = k->next) {
1123 k->face = aface;
1124 }
1125 }
1126
1127 /* If e was representative symedge for v1 or v2, fix that. */
1128 if (v1_isolated) {
1129 v1->symedge = nullptr;
1130 }
1131 else if (v1->symedge == se) {
1132 v1->symedge = i;
1133 }
1134 if (v2_isolated) {
1135 v2->symedge = nullptr;
1136 }
1137 else if (v2->symedge == sesym) {
1138 v2->symedge = f;
1139 }
1140
1141 /* Mark #SymEdge as deleted by setting all its pointers to null. */
1142 se->next = se->rot = nullptr;
1143 sesym->next = sesym->rot = nullptr;
1144 if (!v1_isolated && !v2_isolated && aface != bface) {
1145 bface->deleted = true;
1146 if (this->outer_face == bface) {
1147 this->outer_face = aface;
1148 }
1149 }
1150}
1151
1152template<typename T> class SiteInfo {
1153 public:
1156};
1157
1161template<typename T> bool site_lexicographic_sort(const SiteInfo<T> &a, const SiteInfo<T> &b)
1162{
1163 const VecBase<T, 2> &co_a = a.v->co.exact;
1164 const VecBase<T, 2> &co_b = b.v->co.exact;
1165 if (co_a[0] < co_b[0]) {
1166 return true;
1167 }
1168 if (co_a[0] > co_b[0]) {
1169 return false;
1170 }
1171 if (co_a[1] < co_b[1]) {
1172 return true;
1173 }
1174 if (co_a[1] > co_b[1]) {
1175 return false;
1176 }
1177 return a.orig_index < b.orig_index;
1178}
1179
1185template<typename T> void find_site_merges(Array<SiteInfo<T>> &sites)
1186{
1187 int n = sites.size();
1188 for (int i = 0; i < n - 1; ++i) {
1189 int j = i + 1;
1190 while (j < n && sites[j].v->co.exact == sites[i].v->co.exact) {
1191 sites[j].v->merge_to_index = sites[i].orig_index;
1192 ++j;
1193 }
1194 if (j - i > 1) {
1195 i = j - 1; /* j-1 because loop head will add another 1. */
1196 }
1197 }
1198}
1199
1200template<typename T> inline bool vert_left_of_symedge(CDTVert<T> *v, SymEdge<T> *se)
1201{
1202 return filtered_orient2d(v->co, se->vert->co, se->next->vert->co) > 0;
1203}
1204
1205template<typename T> inline bool vert_right_of_symedge(CDTVert<T> *v, SymEdge<T> *se)
1206{
1207 return filtered_orient2d(v->co, se->next->vert->co, se->vert->co) > 0;
1208}
1209
1210/* Is se above basel? */
1211template<typename T>
1212inline bool dc_tri_valid(SymEdge<T> *se, SymEdge<T> *basel, SymEdge<T> *basel_sym)
1213{
1214 return filtered_orient2d(se->next->vert->co, basel_sym->vert->co, basel->vert->co) > 0;
1215}
1216
1223template<typename T>
1225 Array<SiteInfo<T>> &sites,
1226 int start,
1227 int end,
1228 SymEdge<T> **r_le,
1229 SymEdge<T> **r_re)
1230{
1231 constexpr int dbg_level = 0;
1232 if (dbg_level > 0) {
1233 std::cout << "DC_TRI start=" << start << " end=" << end << "\n";
1234 }
1235 int n = end - start;
1236 if (n <= 1) {
1237 *r_le = nullptr;
1238 *r_re = nullptr;
1239 return;
1240 }
1241
1242 /* Base case: if n <= 3, triangulate directly. */
1243 if (n <= 3) {
1244 CDTVert<T> *v1 = sites[start].v;
1245 CDTVert<T> *v2 = sites[start + 1].v;
1246 CDTEdge<T> *ea = cdt->add_edge(v1, v2, cdt->outer_face, cdt->outer_face);
1247 ea->symedges[0].next = &ea->symedges[1];
1248 ea->symedges[1].next = &ea->symedges[0];
1249 ea->symedges[0].rot = &ea->symedges[0];
1250 ea->symedges[1].rot = &ea->symedges[1];
1251 if (n == 2) {
1252 *r_le = &ea->symedges[0];
1253 *r_re = &ea->symedges[1];
1254 return;
1255 }
1256 CDTVert<T> *v3 = sites[start + 2].v;
1257 CDTEdge<T> *eb = cdt->add_vert_to_symedge_edge(v3, &ea->symedges[1]);
1258 int orient = filtered_orient2d(v1->co, v2->co, v3->co);
1259 if (orient > 0) {
1260 cdt->add_diagonal(&eb->symedges[0], &ea->symedges[0]);
1261 *r_le = &ea->symedges[0];
1262 *r_re = &eb->symedges[0];
1263 }
1264 else if (orient < 0) {
1265 cdt->add_diagonal(&ea->symedges[0], &eb->symedges[0]);
1266 *r_le = ea->symedges[0].rot;
1267 *r_re = eb->symedges[0].rot;
1268 }
1269 else {
1270 /* Collinear points. Just return a line. */
1271 *r_le = &ea->symedges[0];
1272 *r_re = &eb->symedges[0];
1273 }
1274 return;
1275 }
1276 /* Recursive case. Do left (L) and right (R) halves separately, then join. */
1277 int n2 = n / 2;
1278 BLI_assert(n2 >= 2 && end - (start + n2) >= 2);
1279 SymEdge<T> *ldo;
1280 SymEdge<T> *ldi;
1281 SymEdge<T> *rdi;
1282 SymEdge<T> *rdo;
1283 dc_tri(cdt, sites, start, start + n2, &ldo, &ldi);
1284 dc_tri(cdt, sites, start + n2, end, &rdi, &rdo);
1285 if (dbg_level > 0) {
1286 std::cout << "\nDC_TRI merge step for start=" << start << ", end=" << end << "\n";
1287 std::cout << "ldo " << ldo << "\n"
1288 << "ldi " << ldi << "\n"
1289 << "rdi " << rdi << "\n"
1290 << "rdo " << rdo << "\n";
1291 if (dbg_level > 1) {
1292 std::string lab = "dc_tri (" + std::to_string(start) + "," + std::to_string(start + n2) +
1293 ")(" + std::to_string(start + n2) + "," + std::to_string(end) + ")";
1294 cdt_draw(lab, *cdt);
1295 }
1296 }
1297 /* Find lower common tangent of L and R. */
1298 for (;;) {
1299 if (vert_left_of_symedge(rdi->vert, ldi)) {
1300 ldi = ldi->next;
1301 }
1302 else if (vert_right_of_symedge(ldi->vert, rdi)) {
1303 rdi = sym(rdi)->rot; /* Previous edge to rdi with same right face. */
1304 }
1305 else {
1306 break;
1307 }
1308 }
1309 if (dbg_level > 0) {
1310 std::cout << "common lower tangent in between\n"
1311 << "rdi " << rdi << "\n"
1312 << "ldi" << ldi << "\n";
1313 }
1314
1315 CDTEdge<T> *ebasel = cdt->connect_separate_parts(sym(rdi)->next, ldi);
1316 SymEdge<T> *basel = &ebasel->symedges[0];
1317 SymEdge<T> *basel_sym = &ebasel->symedges[1];
1318 if (dbg_level > 1) {
1319 std::cout << "basel " << basel;
1320 cdt_draw("after basel made", *cdt);
1321 }
1322 if (ldi->vert == ldo->vert) {
1323 ldo = basel_sym;
1324 }
1325 if (rdi->vert == rdo->vert) {
1326 rdo = basel;
1327 }
1328
1329 /* Merge loop. */
1330 for (;;) {
1331 /* Locate the first point lcand->next->vert encountered by rising bubble,
1332 * and delete L edges out of basel->next->vert that fail the circle test. */
1333 SymEdge<T> *lcand = basel_sym->rot;
1334 SymEdge<T> *rcand = basel_sym->next;
1335 if (dbg_level > 1) {
1336 std::cout << "\ntop of merge loop\n";
1337 std::cout << "lcand " << lcand << "\n"
1338 << "rcand " << rcand << "\n"
1339 << "basel " << basel << "\n";
1340 }
1341 if (dc_tri_valid(lcand, basel, basel_sym)) {
1342 if (dbg_level > 1) {
1343 std::cout << "found valid lcand\n";
1344 std::cout << " lcand" << lcand << "\n";
1345 }
1346 while (filtered_incircle(basel_sym->vert->co,
1347 basel->vert->co,
1348 lcand->next->vert->co,
1349 lcand->rot->next->vert->co) > 0.0)
1350 {
1351 if (dbg_level > 1) {
1352 std::cout << "incircle says to remove lcand\n";
1353 std::cout << " lcand" << lcand << "\n";
1354 }
1355 SymEdge<T> *t = lcand->rot;
1356 cdt->delete_edge(sym(lcand));
1357 lcand = t;
1358 }
1359 }
1360 /* Symmetrically, locate first R point to be hit and delete R edges. */
1361 if (dc_tri_valid(rcand, basel, basel_sym)) {
1362 if (dbg_level > 1) {
1363 std::cout << "found valid rcand\n";
1364 std::cout << " rcand" << rcand << "\n";
1365 }
1366 while (filtered_incircle(basel_sym->vert->co,
1367 basel->vert->co,
1368 rcand->next->vert->co,
1369 sym(rcand)->next->next->vert->co) > 0.0)
1370 {
1371 if (dbg_level > 0) {
1372 std::cout << "incircle says to remove rcand\n";
1373 std::cout << " rcand" << rcand << "\n";
1374 }
1375 SymEdge<T> *t = sym(rcand)->next;
1376 cdt->delete_edge(rcand);
1377 rcand = t;
1378 }
1379 }
1380 /* If both lcand and rcand are invalid, then basel is the common upper tangent. */
1381 bool valid_lcand = dc_tri_valid(lcand, basel, basel_sym);
1382 bool valid_rcand = dc_tri_valid(rcand, basel, basel_sym);
1383 if (dbg_level > 0) {
1384 std::cout << "after bubbling up, valid_lcand=" << valid_lcand
1385 << ", valid_rand=" << valid_rcand << "\n";
1386 std::cout << "lcand" << lcand << "\n"
1387 << "rcand" << rcand << "\n";
1388 }
1389 if (!valid_lcand && !valid_rcand) {
1390 break;
1391 }
1392 /* The next cross edge to be connected is to either `lcand->next->vert` or `rcand->next->vert`;
1393 * if both are valid, choose the appropriate one using the #incircle test. */
1394 if (!valid_lcand ||
1395 (valid_rcand &&
1397 lcand->next->vert->co, lcand->vert->co, rcand->vert->co, rcand->next->vert->co) > 0))
1398 {
1399 if (dbg_level > 0) {
1400 std::cout << "connecting rcand\n";
1401 std::cout << " se1=basel_sym" << basel_sym << "\n";
1402 std::cout << " se2=rcand->next" << rcand->next << "\n";
1403 }
1404 ebasel = cdt->add_diagonal(rcand->next, basel_sym);
1405 }
1406 else {
1407 if (dbg_level > 0) {
1408 std::cout << "connecting lcand\n";
1409 std::cout << " se1=sym(lcand)" << sym(lcand) << "\n";
1410 std::cout << " se2=basel_sym->next" << basel_sym->next << "\n";
1411 }
1412 ebasel = cdt->add_diagonal(basel_sym->next, sym(lcand));
1413 }
1414 basel = &ebasel->symedges[0];
1415 basel_sym = &ebasel->symedges[1];
1416 BLI_assert(basel_sym->face == cdt->outer_face);
1417 if (dbg_level > 2) {
1418 cdt_draw("after adding new crossedge", *cdt);
1419 }
1420 }
1421 *r_le = ldo;
1422 *r_re = rdo;
1423 BLI_assert(sym(ldo)->face == cdt->outer_face && rdo->face == cdt->outer_face);
1424}
1425
1426/* Guibas-Stolfi Divide-and_Conquer algorithm. */
1427template<typename T> void dc_triangulate(CDTArrangement<T> *cdt, Array<SiteInfo<T>> &sites)
1428{
1429 /* Compress sites in place to eliminated verts that merge to others. */
1430 int i = 0;
1431 int j = 0;
1432 int nsites = sites.size();
1433 while (j < nsites) {
1434 /* Invariant: `sites[0..i-1]` have non-merged verts from `0..(j-1)` in them. */
1435 sites[i] = sites[j++];
1436 if (sites[i].v->merge_to_index < 0) {
1437 i++;
1438 }
1439 }
1440 int n = i;
1441 if (n == 0) {
1442 return;
1443 }
1444 SymEdge<T> *le;
1445 SymEdge<T> *re;
1446 dc_tri(cdt, sites, 0, n, &le, &re);
1447}
1448
1467template<typename T> void initial_triangulation(CDTArrangement<T> *cdt)
1468{
1469 int n = cdt->verts.size();
1470 if (n <= 1) {
1471 return;
1472 }
1473 Array<SiteInfo<T>> sites(n);
1474 for (int i = 0; i < n; ++i) {
1475 sites[i].v = cdt->verts[i];
1476 sites[i].orig_index = i;
1477 }
1478 std::sort(sites.begin(), sites.end(), site_lexicographic_sort<T>);
1479 find_site_merges(sites);
1480 dc_triangulate(cdt, sites);
1481}
1482
1490template<typename T> static void re_delaunay_triangulate(CDTArrangement<T> *cdt, SymEdge<T> *se)
1491{
1492 if (se->face == cdt->outer_face || sym(se)->face == cdt->outer_face) {
1493 return;
1494 }
1495 /* `se` is a diagonal just added, and it is base of area to re-triangulate (face on its left). */
1496 int count = 1;
1497 for (const SymEdge<T> *ss = se->next; ss != se; ss = ss->next) {
1498 count++;
1499 }
1500 if (count <= 3) {
1501 return;
1502 }
1503 /* First and last are the SymEdges whose verts are first and last off of base,
1504 * continuing from 'se'. */
1505 SymEdge<T> *first = se->next->next;
1506 /* We want to make a triangle with 'se' as base and some other c as 3rd vertex. */
1507 CDTVert<T> *a = se->vert;
1508 CDTVert<T> *b = se->next->vert;
1509 CDTVert<T> *c = first->vert;
1510 SymEdge<T> *cse = first;
1511 for (SymEdge<T> *ss = first->next; ss != se; ss = ss->next) {
1512 CDTVert<T> *v = ss->vert;
1513 if (filtered_incircle(a->co, b->co, c->co, v->co) > 0) {
1514 c = v;
1515 cse = ss;
1516 }
1517 }
1518 /* Add diagonals necessary to make `abc` a triangle. */
1519 CDTEdge<T> *ebc = nullptr;
1520 CDTEdge<T> *eca = nullptr;
1521 if (!exists_edge(b, c)) {
1522 ebc = cdt->add_diagonal(se->next, cse);
1523 }
1524 if (!exists_edge(c, a)) {
1525 eca = cdt->add_diagonal(cse, se);
1526 }
1527 /* Now recurse. */
1528 if (ebc) {
1529 re_delaunay_triangulate(cdt, &ebc->symedges[1]);
1530 }
1531 if (eca) {
1532 re_delaunay_triangulate(cdt, &eca->symedges[1]);
1533 }
1534}
1535
1536template<typename T> inline int tri_orient(const SymEdge<T> *t)
1537{
1538 return filtered_orient2d(t->vert->co, t->next->vert->co, t->next->next->vert->co);
1539}
1540
1566template<typename T> class CrossData {
1567 public:
1568 T lambda = T(0);
1572
1575 {
1576 }
1577 CrossData(const CrossData &other)
1578 : lambda(other.lambda), vert(other.vert), in(other.in), out(other.out)
1579 {
1580 }
1581 CrossData(CrossData &&other) noexcept
1582 : lambda(std::move(other.lambda)),
1583 vert(std::move(other.vert)),
1584 in(std::move(other.in)),
1585 out(std::move(other.out))
1586 {
1587 }
1588 ~CrossData() = default;
1590 {
1591 if (this != &other) {
1592 lambda = other.lambda;
1593 vert = other.vert;
1594 in = other.in;
1595 out = other.out;
1596 }
1597 return *this;
1598 }
1599 CrossData &operator=(CrossData &&other) noexcept
1600 {
1601 lambda = std::move(other.lambda);
1602 vert = std::move(other.vert);
1603 in = std::move(other.in);
1604 out = std::move(other.out);
1605 return *this;
1606 }
1607};
1608
1609template<typename T>
1610bool get_next_crossing_from_vert(CDT_state<T> *cdt_state,
1611 CrossData<T> *cd,
1612 CrossData<T> *cd_next,
1613 const CDTVert<T> *v2);
1614
1622template<typename T>
1624 SymEdge<T> *cd_out,
1625 CrossData<T> *cd,
1626 CrossData<T> *cd_next)
1627{
1628 SymEdge<T> *se;
1629
1630 cd_next->lambda = T(0);
1631 cd_next->vert = v;
1632 cd_next->in = nullptr;
1633 cd_next->out = nullptr;
1634 if (cd->lambda == 0) {
1635 cd->out = cd_out;
1636 }
1637 else {
1638 /* One of the edges in the triangle with edge sym(cd->in) contains v. */
1639 se = sym(cd->in);
1640 if (se->vert != v) {
1641 se = se->next;
1642 if (se->vert != v) {
1643 se = se->next;
1644 }
1645 }
1646 BLI_assert(se->vert == v);
1647 cd_next->in = se;
1648 }
1649}
1650
1664template<typename T>
1666 const CDTVert<T> *v2,
1667 SymEdge<T> *t,
1668 CrossData<T> *cd,
1669 CrossData<T> *cd_next,
1670 const T epsilon)
1671{
1672 CDTVert<T> *va = t->vert;
1673 CDTVert<T> *vb = t->next->vert;
1674 CDTVert<T> *vc = t->next->next->vert;
1675 SymEdge<T> *se_vcvb = sym(t->next);
1676 SymEdge<T> *se_vcva = t->next->next;
1677 BLI_assert(se_vcva->vert == vc && se_vcva->next->vert == va);
1678 BLI_assert(se_vcvb->vert == vc && se_vcvb->next->vert == vb);
1680 auto isect = isect_seg_seg(va->co.exact, vb->co.exact, curco.exact, v2->co.exact);
1681 T &lambda = isect.lambda;
1682 switch (isect.kind) {
1683 case isect_result<VecBase<T, 2>>::LINE_LINE_CROSS: {
1684#ifdef WITH_GMP
1685 if (!std::is_same_v<T, mpq_class>)
1686#else
1687 if (true)
1688#endif
1689 {
1690 double len_ab = distance(va->co.approx, vb->co.approx);
1691 if (lambda * len_ab <= epsilon) {
1692 fill_crossdata_for_through_vert(va, se_vcva, cd, cd_next);
1693 }
1694 else if ((1 - lambda) * len_ab <= epsilon) {
1695 fill_crossdata_for_through_vert(vb, se_vcvb, cd, cd_next);
1696 }
1697 else {
1698 *cd_next = CrossData<T>(lambda, nullptr, t, nullptr);
1699 if (cd->lambda == 0) {
1700 cd->out = se_vcva;
1701 }
1702 }
1703 }
1704 else {
1705 *cd_next = CrossData<T>(lambda, nullptr, t, nullptr);
1706 if (cd->lambda == 0) {
1707 cd->out = se_vcva;
1708 }
1709 }
1710 break;
1711 }
1712 case isect_result<VecBase<T, 2>>::LINE_LINE_EXACT: {
1713 if (lambda == 0) {
1714 fill_crossdata_for_through_vert(va, se_vcva, cd, cd_next);
1715 }
1716 else if (lambda == 1) {
1717 fill_crossdata_for_through_vert(vb, se_vcvb, cd, cd_next);
1718 }
1719 else {
1720 *cd_next = CrossData<T>(lambda, nullptr, t, nullptr);
1721 if (cd->lambda == 0) {
1722 cd->out = se_vcva;
1723 }
1724 }
1725 break;
1726 }
1727 case isect_result<VecBase<T, 2>>::LINE_LINE_NONE: {
1728#ifdef WITH_GMP
1729 if (std::is_same_v<T, mpq_class>) {
1730 BLI_assert(false);
1731 }
1732#endif
1733 /* It should be very near one end or other of segment. */
1734 const T middle_lambda = 0.5;
1735 if (lambda <= middle_lambda) {
1736 fill_crossdata_for_through_vert(va, se_vcva, cd, cd_next);
1737 }
1738 else {
1739 fill_crossdata_for_through_vert(vb, se_vcvb, cd, cd_next);
1740 }
1741 break;
1742 }
1743 case isect_result<VecBase<T, 2>>::LINE_LINE_COLINEAR: {
1744 if (distance_squared(va->co.approx, v2->co.approx) <=
1745 distance_squared(vb->co.approx, v2->co.approx))
1746 {
1747 fill_crossdata_for_through_vert(va, se_vcva, cd, cd_next);
1748 }
1749 else {
1750 fill_crossdata_for_through_vert(vb, se_vcvb, cd, cd_next);
1751 }
1752 break;
1753 }
1754 }
1755} // namespace blender::meshintersect
1756
1764template<typename T>
1766 CrossData<T> *cd,
1767 CrossData<T> *cd_next,
1768 const CDTVert<T> *v2)
1769{
1770 SymEdge<T> *tstart = cd->vert->symedge;
1771 SymEdge<T> *t = tstart;
1772 CDTVert<T> *vcur = cd->vert;
1773 bool ok = false;
1774 do {
1775 /* The ray from `vcur` to v2 has to go either between two successive
1776 * edges around `vcur` or exactly along them. This time through the
1777 * loop, check to see if the ray goes along `vcur-va`
1778 * or between `vcur-va` and `vcur-vb`, where va is the end of t
1779 * and vb is the next vertex (on the next rot edge around vcur, but
1780 * should also be the next vert of triangle starting with `vcur-va`. */
1781 if (t->face != cdt_state->cdt.outer_face && tri_orient(t) < 0) {
1782 BLI_assert(false); /* Shouldn't happen. */
1783 }
1784 CDTVert<T> *va = t->next->vert;
1785 CDTVert<T> *vb = t->next->next->vert;
1786 int orient1 = filtered_orient2d(t->vert->co, va->co, v2->co);
1787 if (orient1 == 0 && in_line<T>(vcur->co, va->co, v2->co)) {
1788 fill_crossdata_for_through_vert(va, t, cd, cd_next);
1789 ok = true;
1790 break;
1791 }
1792 if (t->face != cdt_state->cdt.outer_face) {
1793 int orient2 = filtered_orient2d(vcur->co, vb->co, v2->co);
1794 /* Don't handle orient2 == 0 case here: next rotation will get it. */
1795 if (orient1 > 0 && orient2 < 0) {
1796 /* Segment intersection. */
1797 t = t->next;
1798 fill_crossdata_for_intersect(vcur->co, v2, t, cd, cd_next, cdt_state->epsilon);
1799 ok = true;
1800 break;
1801 }
1802 }
1803 } while ((t = t->rot) != tstart);
1804 return ok;
1805}
1806
1815template<typename T>
1817 CrossData<T> *cd_next,
1818 const CDTVert<T> *v2,
1819 const T epsilon)
1820{
1821 CDTVert<T> *va = cd->in->vert;
1822 CDTVert<T> *vb = cd->in->next->vert;
1823 VecBase<T, 2> curco = interpolate(va->co.exact, vb->co.exact, cd->lambda);
1824 FatCo<T> fat_curco(curco);
1825 SymEdge<T> *se_ac = sym(cd->in)->next;
1826 CDTVert<T> *vc = se_ac->next->vert;
1827 int orient = filtered_orient2d(fat_curco, v2->co, vc->co);
1828 if (orient < 0) {
1829 fill_crossdata_for_intersect<T>(fat_curco, v2, se_ac->next, cd, cd_next, epsilon);
1830 }
1831 else if (orient > 0.0) {
1832 fill_crossdata_for_intersect(fat_curco, v2, se_ac, cd, cd_next, epsilon);
1833 }
1834 else {
1835 *cd_next = CrossData<T>{0.0, vc, se_ac->next, nullptr};
1836 }
1837}
1838
1839template<typename T> void dump_crossings(const Span<CrossData<T>> crossings)
1840{
1841 std::cout << "CROSSINGS\n";
1842 for (int i = 0; i < crossings.size(); ++i) {
1843 std::cout << i << ": ";
1844 const CrossData<T> &cd = crossings[i];
1845 if (cd.lambda == 0) {
1846 std::cout << "v" << cd.vert->index;
1847 }
1848 else {
1849 std::cout << "lambda=" << cd.lambda;
1850 }
1851 if (cd.in != nullptr) {
1852 std::cout << " in=" << short_se_dump(cd.in);
1853 std::cout << " out=" << short_se_dump(cd.out);
1854 }
1855 std::cout << "\n";
1856 }
1857}
1858
1870template<typename T>
1872 CDT_state<T> *cdt_state, CDTVert<T> *v1, CDTVert<T> *v2, int input_id, LinkNode **r_edges)
1873{
1874 constexpr int dbg_level = 0;
1875 if (dbg_level > 0) {
1876 std::cout << "\nADD EDGE CONSTRAINT\n" << vertname(v1) << " " << vertname(v2) << "\n";
1877 }
1878 LinkNodePair edge_list = {nullptr, nullptr};
1879
1880 if (r_edges) {
1881 *r_edges = nullptr;
1882 }
1883
1884 /*
1885 * Handle two special cases first:
1886 * 1) The two end vertices are the same (can happen because of merging).
1887 * 2) There is already an edge between v1 and v2.
1888 */
1889 if (v1 == v2) {
1890 return;
1891 }
1893 if (t != nullptr) {
1894 /* Segment already there. */
1895 add_to_input_ids(t->edge->input_ids, input_id);
1896 if (r_edges != nullptr) {
1897 BLI_linklist_append(&edge_list, t->edge);
1898 *r_edges = edge_list.list;
1899 }
1900 return;
1901 }
1902
1903 /*
1904 * Fill crossings array with CrossData points for intersection path from v1 to v2.
1905 *
1906 * At every point, the crossings array has the path so far, except that
1907 * the `.out` field of the last element of it may not be known yet -- if that
1908 * last element is a vertex, then we won't know the output edge until we
1909 * find the next crossing.
1910 *
1911 * To protect against infinite loops, we keep track of which vertices
1912 * we have visited by setting their visit_index to a new visit epoch.
1913 *
1914 * We check a special case first: where the segment is already there in
1915 * one hop. Saves a bunch of orient2d tests in that common case.
1916 */
1917 int visit = ++cdt_state->visit_count;
1918 Vector<CrossData<T>, 128> crossings;
1919 crossings.append(CrossData<T>(T(0), v1, nullptr, nullptr));
1920 int n;
1921 while (!((n = crossings.size()) > 0 && crossings[n - 1].vert == v2)) {
1922 crossings.append(CrossData<T>());
1923 CrossData<T> *cd = &crossings[n - 1];
1924 CrossData<T> *cd_next = &crossings[n];
1925 bool ok;
1926 if (crossings[n - 1].lambda == 0) {
1927 ok = get_next_crossing_from_vert(cdt_state, cd, cd_next, v2);
1928 }
1929 else {
1930 get_next_crossing_from_edge<T>(cd, cd_next, v2, cdt_state->epsilon);
1931 ok = true;
1932 }
1933 constexpr int unreasonably_large_crossings = 100000;
1934 if (!ok || crossings.size() == unreasonably_large_crossings) {
1935 /* Shouldn't happen but if does, just bail out. */
1936 BLI_assert(false);
1937 return;
1938 }
1939 if (crossings[n].lambda == 0) {
1940 if (crossings[n].vert->visit_index == visit) {
1941 /* Shouldn't happen but if it does, just bail out. */
1942 BLI_assert(false);
1943 return;
1944 }
1945 crossings[n].vert->visit_index = visit;
1946 }
1947 }
1948
1949 if (dbg_level > 0) {
1950 dump_crossings<T>(crossings);
1951 }
1952
1953 /*
1954 * Post-process crossings.
1955 * Some crossings may have an intersection crossing followed
1956 * by a vertex crossing that is on the same edge that was just
1957 * intersected. We prefer to go directly from the previous
1958 * crossing directly to the vertex. This may chain backwards.
1959 *
1960 * This loop marks certain crossings as "deleted", by setting
1961 * their lambdas to -1.0.
1962 */
1963 int ncrossings = crossings.size();
1964 for (int i = 2; i < ncrossings; ++i) {
1965 CrossData<T> *cd = &crossings[i];
1966 if (cd->lambda == 0.0) {
1967 CDTVert<T> *v = cd->vert;
1968 int j;
1969 CrossData<T> *cd_prev;
1970 for (j = i - 1; j > 0; --j) {
1971 cd_prev = &crossings[j];
1972 if ((cd_prev->lambda == 0.0 && cd_prev->vert != v) ||
1973 (cd_prev->lambda != 0.0 && cd_prev->in->vert != v && cd_prev->in->next->vert != v))
1974 {
1975 break;
1976 }
1977 cd_prev->lambda = -1.0; /* Mark cd_prev as 'deleted'. */
1978 }
1979 if (j < i - 1) {
1980 /* Some crossings were deleted. Fix the in and out edges across gap. */
1981 cd_prev = &crossings[j];
1982 SymEdge<T> *se;
1983 if (cd_prev->lambda == 0.0) {
1984 se = find_symedge_between_verts(cd_prev->vert, v);
1985 if (se == nullptr) {
1986 return;
1987 }
1988 cd_prev->out = se;
1989 cd->in = nullptr;
1990 }
1991 else {
1992 se = find_symedge_with_face(v, sym(cd_prev->in)->face);
1993 if (se == nullptr) {
1994 return;
1995 }
1996 cd->in = se;
1997 }
1998 }
1999 }
2000 }
2001
2002 /*
2003 * Insert all intersection points on constrained edges.
2004 */
2005 for (int i = 0; i < ncrossings; ++i) {
2006 CrossData<T> *cd = &crossings[i];
2007 if (cd->lambda != 0.0 && cd->lambda != -1.0 && is_constrained_edge(cd->in->edge)) {
2008 CDTEdge<T> *edge = cdt_state->cdt.split_edge(cd->in, cd->lambda);
2009 cd->vert = edge->symedges[0].vert;
2010 }
2011 }
2012
2013 /*
2014 * Remove any crossed, non-intersected edges.
2015 */
2016 for (int i = 0; i < ncrossings; ++i) {
2017 CrossData<T> *cd = &crossings[i];
2018 if (cd->lambda != 0.0 && cd->lambda != -1.0 && !is_constrained_edge(cd->in->edge)) {
2019 cdt_state->cdt.delete_edge(cd->in);
2020 }
2021 }
2022
2023 /*
2024 * Insert segments for v1->v2.
2025 */
2026 SymEdge<T> *tstart = crossings[0].out;
2027 for (int i = 1; i < ncrossings; i++) {
2028 CrossData<T> *cd = &crossings[i];
2029 if (cd->lambda == -1.0) {
2030 continue; /* This crossing was deleted. */
2031 }
2032 t = nullptr;
2033 SymEdge<T> *tnext = t;
2034 CDTEdge<T> *edge;
2035 if (cd->lambda != 0.0) {
2036 if (is_constrained_edge(cd->in->edge)) {
2037 t = cd->vert->symedge;
2038 tnext = sym(t)->next;
2039 }
2040 }
2041 else if (cd->lambda == 0.0) {
2042 t = cd->in;
2043 tnext = cd->out;
2044 if (t == nullptr) {
2045 /* Previous non-deleted crossing must also have been a vert, and segment should exist. */
2046 int j;
2047 CrossData<T> *cd_prev;
2048 for (j = i - 1; j >= 0; j--) {
2049 cd_prev = &crossings[j];
2050 if (cd_prev->lambda != -1.0) {
2051 break;
2052 }
2053 }
2054 BLI_assert(cd_prev->lambda == 0.0);
2055 BLI_assert(cd_prev->out->next->vert == cd->vert);
2056 edge = cd_prev->out->edge;
2057 add_to_input_ids(edge->input_ids, input_id);
2058 if (r_edges != nullptr) {
2059 BLI_linklist_append(&edge_list, edge);
2060 }
2061 }
2062 }
2063 if (t != nullptr) {
2064 if (tstart->next->vert == t->vert) {
2065 edge = tstart->edge;
2066 }
2067 else {
2068 edge = cdt_state->cdt.add_diagonal(tstart, t);
2069 }
2070 add_to_input_ids(edge->input_ids, input_id);
2071 if (r_edges != nullptr) {
2072 BLI_linklist_append(&edge_list, edge);
2073 }
2074 /* Now re-triangulate upper and lower gaps. */
2075 re_delaunay_triangulate(&cdt_state->cdt, &edge->symedges[0]);
2076 re_delaunay_triangulate(&cdt_state->cdt, &edge->symedges[1]);
2077 }
2078 if (i < ncrossings - 1) {
2079 if (tnext != nullptr) {
2080 tstart = tnext;
2081 }
2082 }
2083 }
2084
2085 if (r_edges) {
2086 *r_edges = edge_list.list;
2087 }
2088}
2089
2096template<typename T> void add_edge_constraints(CDT_state<T> *cdt_state, const CDT_input<T> &input)
2097{
2098 int ne = input.edge.size();
2099 int nv = input.vert.size();
2100 for (int i = 0; i < ne; i++) {
2101 int iv1 = input.edge[i].first;
2102 int iv2 = input.edge[i].second;
2103 if (iv1 < 0 || iv1 >= nv || iv2 < 0 || iv2 >= nv) {
2104 /* Ignore invalid indices in edges. */
2105 continue;
2106 }
2107 CDTVert<T> *v1 = cdt_state->cdt.get_vert_resolve_merge(iv1);
2108 CDTVert<T> *v2 = cdt_state->cdt.get_vert_resolve_merge(iv2);
2109 int id = cdt_state->need_ids ? i : 0;
2110 add_edge_constraint(cdt_state, v1, v2, id, nullptr);
2111 }
2112 cdt_state->face_edge_offset = ne;
2113}
2114
2133template<typename T>
2135 CDT_state<T> *cdt_state, SymEdge<T> *face_symedge, int face_id, int fedge_start, int fedge_end)
2136{
2137 /* Can't loop forever since eventually would visit every face. */
2138 cdt_state->visit_count++;
2139 int visit = cdt_state->visit_count;
2140 Vector<SymEdge<T> *> stack;
2141 stack.append(face_symedge);
2142 while (!stack.is_empty()) {
2143 SymEdge<T> *se = stack.pop_last();
2144 CDTFace<T> *face = se->face;
2145 if (face->visit_index == visit) {
2146 continue;
2147 }
2148 face->visit_index = visit;
2149 add_to_input_ids(face->input_ids, face_id);
2150 SymEdge<T> *se_start = se;
2151 for (se = se->next; se != se_start; se = se->next) {
2152 if (!id_range_in_list(se->edge->input_ids, fedge_start, fedge_end)) {
2153 SymEdge<T> *se_sym = sym(se);
2154 CDTFace<T> *face_other = se_sym->face;
2155 if (face_other->visit_index != visit) {
2156 stack.append(se_sym);
2157 }
2158 }
2159 }
2160 }
2161}
2162
2163/* Return a power of 10 that is greater than or equal to x. */
2165{
2166 if (x <= 0) {
2167 return 1;
2168 }
2169 int ans = 1;
2170 BLI_assert(x < std::numeric_limits<int>::max() / 10);
2171 while (ans < x) {
2172 ans *= 10;
2173 }
2174 return ans;
2175}
2176
2187template<typename T>
2189 const CDT_input<T> &input,
2190 CDT_output_type output_type)
2191{
2192 int nv = input.vert.size();
2193 const Span<Vector<int>> input_faces = input.face;
2194 SymEdge<T> *face_symedge0 = nullptr;
2195 CDTArrangement<T> *cdt = &cdt_state->cdt;
2196
2197 int maxflen = 0;
2198 for (const int f : input_faces.index_range()) {
2199 maxflen = std::max<int>(maxflen, input_faces[f].size());
2200 }
2201 /* For convenience in debugging, make face_edge_offset be a power of 10. */
2203 std::max(maxflen, cdt_state->face_edge_offset));
2204 /* The original_edge encoding scheme doesn't work if the following is false.
2205 * If we really have that many faces and that large a max face length that when multiplied
2206 * together the are >= INT_MAX, then the Delaunay calculation will take unreasonably long anyway.
2207 */
2208 BLI_assert(std::numeric_limits<int>::max() / cdt_state->face_edge_offset > input_faces.size());
2209 int faces_added = 0;
2210 for (const int f : input_faces.index_range()) {
2211 const Span<int> face = input_faces[f];
2212 if (face.size() <= 2) {
2213 /* Ignore faces with fewer than 3 vertices. */
2214 continue;
2215 }
2216 int fedge_start = (f + 1) * cdt_state->face_edge_offset;
2217 for (const int i : face.index_range()) {
2218 int face_edge_id = fedge_start + i;
2219 int iv1 = face[i];
2220 int iv2 = face[(i + 1) % face.size()];
2221 if (iv1 < 0 || iv1 >= nv || iv2 < 0 || iv2 >= nv) {
2222 /* Ignore face edges with invalid vertices. */
2223 continue;
2224 }
2225 ++faces_added;
2226 CDTVert<T> *v1 = cdt->get_vert_resolve_merge(iv1);
2228 LinkNode *edge_list;
2229 int id = cdt_state->need_ids ? face_edge_id : 0;
2230 add_edge_constraint(cdt_state, v1, v2, id, &edge_list);
2231 /* Set a new face_symedge0 each time since earlier ones may not
2232 * survive later symedge splits. Really, just want the one when
2233 * `i == face.size() - 1`, but this code guards against that one somehow being null. */
2234 if (edge_list != nullptr) {
2235 CDTEdge<T> *face_edge = static_cast<CDTEdge<T> *>(edge_list->link);
2236 face_symedge0 = &face_edge->symedges[0];
2237 if (face_symedge0->vert != v1) {
2238 face_symedge0 = &face_edge->symedges[1];
2239 BLI_assert(face_symedge0->vert == v1);
2240 }
2241 }
2242 BLI_linklist_free(edge_list, nullptr);
2243 }
2244 int fedge_end = fedge_start + face.size() - 1;
2245 if (face_symedge0 != nullptr) {
2246 /* We need to propagate face ids to all faces that represent #f, if #need_ids.
2247 * Even if `need_ids == false`, we need to propagate at least the fact that
2248 * the face ids set would be non-empty if the output type is one of the ones
2249 * making valid BMesh faces. */
2250 int id = cdt_state->need_ids ? f : 0;
2251 add_face_ids(cdt_state, face_symedge0, id, fedge_start, fedge_end);
2252 if (cdt_state->need_ids ||
2254 {
2255 add_face_ids(cdt_state, face_symedge0, f, fedge_start, fedge_end);
2256 }
2257 }
2258 }
2259 return faces_added;
2260}
2261
2262/* Delete_edge but try not to mess up outer face.
2263 * Also faces have symedges now, so make sure not
2264 * to mess those up either. */
2265template<typename T> void dissolve_symedge(CDT_state<T> *cdt_state, SymEdge<T> *se)
2266{
2267 CDTArrangement<T> *cdt = &cdt_state->cdt;
2268 SymEdge<T> *symse = sym(se);
2269 if (symse->face == cdt->outer_face) {
2270 se = sym(se);
2271 symse = sym(se);
2272 }
2273 if (ELEM(cdt->outer_face->symedge, se, symse)) {
2274 /* Advancing by 2 to get past possible 'sym(se)'. */
2275 if (se->next->next == se) {
2276 cdt->outer_face->symedge = nullptr;
2277 }
2278 else {
2279 cdt->outer_face->symedge = se->next->next;
2280 }
2281 }
2282 else {
2283 if (se->face->symedge == se) {
2284 se->face->symedge = se->next;
2285 }
2286 if (symse->face->symedge == symse) {
2287 symse->face->symedge = symse->next;
2288 }
2289 }
2290 cdt->delete_edge(se);
2291}
2292
2296template<typename T> void remove_non_constraint_edges(CDT_state<T> *cdt_state)
2297{
2298 for (CDTEdge<T> *e : cdt_state->cdt.edges) {
2299 SymEdge<T> *se = &e->symedges[0];
2301 dissolve_symedge(cdt_state, se);
2302 }
2303 }
2304}
2305
2306/*
2307 * Remove the non-constraint edges, but leave enough of them so that all of the
2308 * faces that would be #BMesh faces (that is, the faces that have some input representative)
2309 * are valid: they can't have holes, they can't have repeated vertices, and they can't have
2310 * repeated edges.
2311 *
2312 * Not essential, but to make the result look more aesthetically nice,
2313 * remove the edges in order of decreasing length, so that it is more likely that the
2314 * final remaining support edges are short, and therefore likely to make a fairly
2315 * direct path from an outer face to an inner hole face.
2316 */
2317
2321template<typename T> struct EdgeToSort {
2322 double len_squared = 0.0;
2323 CDTEdge<T> *e{nullptr};
2324
2325 EdgeToSort() = default;
2326 EdgeToSort(const EdgeToSort &other) : len_squared(other.len_squared), e(other.e) {}
2327 EdgeToSort(EdgeToSort &&other) noexcept : len_squared(std::move(other.len_squared)), e(other.e)
2328 {
2329 }
2330 ~EdgeToSort() = default;
2332 {
2333 if (this != &other) {
2334 len_squared = other.len_squared;
2335 e = other.e;
2336 }
2337 return *this;
2338 }
2340 {
2341 len_squared = std::move(other.len_squared);
2342 e = other.e;
2343 return *this;
2344 }
2345};
2346
2348{
2349 CDTArrangement<T> *cdt = &cdt_state->cdt;
2350 size_t nedges = cdt->edges.size();
2351 if (nedges == 0) {
2352 return;
2353 }
2354 Vector<EdgeToSort<T>> dissolvable_edges;
2355 dissolvable_edges.reserve(cdt->edges.size());
2356 int i = 0;
2357 for (CDTEdge<T> *e : cdt->edges) {
2359 dissolvable_edges.append(EdgeToSort<T>());
2360 dissolvable_edges[i].e = e;
2361 const double2 &co1 = e->symedges[0].vert->co.approx;
2362 const double2 &co2 = e->symedges[1].vert->co.approx;
2363 dissolvable_edges[i].len_squared = distance_squared(co1, co2);
2364 i++;
2365 }
2366 }
2367 std::sort(dissolvable_edges.begin(),
2368 dissolvable_edges.end(),
2369 [](const EdgeToSort<T> &a, const EdgeToSort<T> &b) -> bool {
2370 return (a.len_squared < b.len_squared);
2371 });
2372 for (EdgeToSort<T> &ets : dissolvable_edges) {
2373 CDTEdge<T> *e = ets.e;
2374 SymEdge<T> *se = &e->symedges[0];
2375 bool dissolve = true;
2376 CDTFace<T> *fleft = se->face;
2377 CDTFace<T> *fright = sym(se)->face;
2378 if (fleft != cdt->outer_face && fright != cdt->outer_face &&
2379 (fleft->input_ids.size() > 0 || fright->input_ids.size() > 0))
2380 {
2381 /* Is there another #SymEdge with same left and right faces?
2382 * Or is there a vertex not part of e touching the same left and right faces? */
2383 for (SymEdge<T> *se2 = se->next; dissolve && se2 != se; se2 = se2->next) {
2384 if (sym(se2)->face == fright ||
2385 (se2->vert != se->next->vert && vert_touches_face(se2->vert, fright)))
2386 {
2387 dissolve = false;
2388 }
2389 }
2390 }
2391
2392 if (dissolve) {
2393 dissolve_symedge(cdt_state, se);
2394 }
2395 }
2396}
2397
2398template<typename T> void remove_outer_edges_until_constraints(CDT_state<T> *cdt_state)
2399{
2400 int visit = ++cdt_state->visit_count;
2401
2402 cdt_state->cdt.outer_face->visit_index = visit;
2403 /* Walk around outer face, adding faces on other side of dissolvable edges to stack. */
2404 Vector<CDTFace<T> *> fstack;
2405 SymEdge<T> *se_start = cdt_state->cdt.outer_face->symedge;
2406 SymEdge<T> *se = se_start;
2407 do {
2408 if (!is_constrained_edge(se->edge)) {
2409 CDTFace<T> *fsym = sym(se)->face;
2410 if (fsym->visit_index != visit) {
2411 fstack.append(fsym);
2412 }
2413 }
2414 } while ((se = se->next) != se_start);
2415
2416 while (!fstack.is_empty()) {
2417 LinkNode *to_dissolve = nullptr;
2418 bool dissolvable;
2419 CDTFace<T> *f = fstack.pop_last();
2420 if (f->visit_index == visit) {
2421 continue;
2422 }
2423 BLI_assert(f != cdt_state->cdt.outer_face);
2424 f->visit_index = visit;
2425 se_start = se = f->symedge;
2426 do {
2427 dissolvable = !is_constrained_edge(se->edge);
2428 if (dissolvable) {
2429 CDTFace<T> *fsym = sym(se)->face;
2430 if (fsym->visit_index != visit) {
2431 fstack.append(fsym);
2432 }
2433 else {
2434 BLI_linklist_prepend(&to_dissolve, se);
2435 }
2436 }
2437 se = se->next;
2438 } while (se != se_start);
2439 while (to_dissolve != nullptr) {
2440 se = static_cast<SymEdge<T> *>(BLI_linklist_pop(&to_dissolve));
2441 if (se->next != nullptr) {
2442 dissolve_symedge(cdt_state, se);
2443 }
2444 }
2445 }
2446}
2447
2448template<typename T> void remove_faces_in_holes(CDT_state<T> *cdt_state)
2449{
2450 CDTArrangement<T> *cdt = &cdt_state->cdt;
2451 for (int i : cdt->faces.index_range()) {
2452 CDTFace<T> *f = cdt->faces[i];
2453 if (!f->deleted && f->hole) {
2454 f->deleted = true;
2455 SymEdge<T> *se = f->symedge;
2456 SymEdge<T> *se_start = se;
2457 SymEdge<T> *se_next = nullptr;
2458 do {
2459 BLI_assert(se != nullptr);
2460 se_next = se->next; /* In case we delete this edge. */
2461 if (se->edge && !is_constrained_edge(se->edge)) {
2462 /* Invalidate one half of this edge. The other will be, or has already been handled
2463 * with the adjacent triangle is processed: it should be part of the same hole. */
2464 se->next = nullptr;
2465 }
2466 se = se_next;
2467 } while (se != se_start);
2468 }
2469 }
2470}
2471
2482template<typename T> void detect_holes(CDT_state<T> *cdt_state)
2483{
2484 CDTArrangement<T> *cdt = &cdt_state->cdt;
2485
2486 /* Make it so that each face with the same visit_index is connected through a path of
2487 * non-constraint edges. */
2488 Vector<CDTFace<T> *> fstack;
2489 Vector<CDTFace<T> *> region_rep_face;
2490 for (int i : cdt->faces.index_range()) {
2491 cdt->faces[i]->visit_index = -1;
2492 }
2493 int cur_region = -1;
2494 cdt->outer_face->visit_index = -2; /* Don't visit this one. */
2495 for (int i : cdt->faces.index_range()) {
2496 CDTFace<T> *f = cdt->faces[i];
2497 if (!f->deleted && f->symedge && f->visit_index == -1) {
2498 fstack.append(f);
2499 ++cur_region;
2500 region_rep_face.append(f);
2501 while (!fstack.is_empty()) {
2502 CDTFace<T> *f = fstack.pop_last();
2503 if (f->visit_index != -1) {
2504 continue;
2505 }
2506 f->visit_index = cur_region;
2507 SymEdge<T> *se_start = f->symedge;
2508 SymEdge<T> *se = se_start;
2509 do {
2510 if (se->edge && !is_constrained_edge(se->edge)) {
2511 CDTFace<T> *fsym = sym(se)->face;
2512 if (fsym && !fsym->deleted && fsym->visit_index == -1) {
2513 fstack.append(fsym);
2514 }
2515 }
2516 se = se->next;
2517 } while (se != se_start);
2518 }
2519 }
2520 }
2521 cdt_state->visit_count = ++cur_region; /* Good start for next use of visit_count. */
2522
2523 /* Now get hole status for each region_rep_face. */
2524
2525 /* Pick a ray end almost certain to be outside everything and in direction
2526 * that is unlikely to hit a vertex or overlap an edge exactly. */
2527 FatCo<T> ray_end;
2528 ray_end.exact = VecBase<T, 2>(123456, 654321);
2529 for (int i : region_rep_face.index_range()) {
2530 CDTFace<T> *f = region_rep_face[i];
2531 FatCo<T> mid;
2532 mid.exact[0] = (f->symedge->vert->co.exact[0] + f->symedge->next->vert->co.exact[0] +
2533 f->symedge->next->next->vert->co.exact[0]) /
2534 3;
2535 mid.exact[1] = (f->symedge->vert->co.exact[1] + f->symedge->next->vert->co.exact[1] +
2536 f->symedge->next->next->vert->co.exact[1]) /
2537 3;
2538 std::atomic<int> hits = 0;
2539 /* TODO: Use CDT data structure here to greatly reduce search for intersections! */
2540 threading::parallel_for(cdt->edges.index_range(), 256, [&](IndexRange range) {
2541 for (const int i : range) {
2542 const CDTEdge<T> *e = cdt->edges[i];
2543 if (!is_deleted_edge(e) && is_constrained_edge(e)) {
2544 if (e->symedges[0].face->visit_index == e->symedges[1].face->visit_index) {
2545 continue; /* Don't count hits on edges between faces in same region. */
2546 }
2547 auto isect = isect_seg_seg(ray_end.exact,
2548 mid.exact,
2549 e->symedges[0].vert->co.exact,
2550 e->symedges[1].vert->co.exact);
2551 switch (isect.kind) {
2552 case isect_result<VecBase<T, 2>>::LINE_LINE_CROSS: {
2553 hits++;
2554 break;
2555 }
2556 case isect_result<VecBase<T, 2>>::LINE_LINE_EXACT:
2557 case isect_result<VecBase<T, 2>>::LINE_LINE_NONE:
2558 case isect_result<VecBase<T, 2>>::LINE_LINE_COLINEAR:
2559 break;
2560 }
2561 }
2562 }
2563 });
2564 f->hole = (hits.load() % 2) == 0;
2565 }
2566
2567 /* Finally, propagate hole status to all holes of a region. */
2568 for (int i : cdt->faces.index_range()) {
2569 CDTFace<T> *f = cdt->faces[i];
2570 int region = f->visit_index;
2571 if (region < 0) {
2572 continue;
2573 }
2574 CDTFace<T> *f_region_rep = region_rep_face[region];
2575 if (i >= 0) {
2576 f->hole = f_region_rep->hole;
2577 }
2578 }
2579}
2580
2585template<typename T>
2586void prepare_cdt_for_output(CDT_state<T> *cdt_state, const CDT_output_type output_type)
2587{
2588 CDTArrangement<T> *cdt = &cdt_state->cdt;
2589 if (cdt->edges.is_empty()) {
2590 return;
2591 }
2592
2593 /* Make sure all non-deleted faces have a symedge. */
2594 for (CDTEdge<T> *e : cdt->edges) {
2595 if (!is_deleted_edge(e)) {
2596 if (e->symedges[0].face->symedge == nullptr) {
2597 e->symedges[0].face->symedge = &e->symedges[0];
2598 }
2599 if (e->symedges[1].face->symedge == nullptr) {
2600 e->symedges[1].face->symedge = &e->symedges[1];
2601 }
2602 }
2603 }
2604
2605 bool need_holes = output_type == CDT_INSIDE_WITH_HOLES ||
2607
2608 if (need_holes) {
2609 detect_holes(cdt_state);
2610 }
2611
2612 if (output_type == CDT_CONSTRAINTS) {
2613 remove_non_constraint_edges(cdt_state);
2614 }
2615 else if (output_type == CDT_CONSTRAINTS_VALID_BMESH) {
2617 }
2618 else if (output_type == CDT_INSIDE) {
2620 }
2621 else if (output_type == CDT_INSIDE_WITH_HOLES) {
2623 remove_faces_in_holes(cdt_state);
2624 }
2625 else if (output_type == CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES) {
2628 remove_faces_in_holes(cdt_state);
2629 }
2630}
2631
2632template<typename T>
2634 const CDT_input<T> /*input*/,
2635 CDT_output_type output_type)
2636{
2637 CDT_output_type oty = output_type;
2638 prepare_cdt_for_output(cdt_state, oty);
2640 CDTArrangement<T> *cdt = &cdt_state->cdt;
2641 result.face_edge_offset = cdt_state->face_edge_offset;
2642
2643 /* All verts without a merge_to_index will be output.
2644 * vert_to_output_map[i] will hold the output vertex index
2645 * corresponding to the vert in position i in cdt->verts.
2646 * This first loop sets vert_to_output_map for un-merged verts. */
2647 int verts_size = cdt->verts.size();
2648 Array<int> vert_to_output_map(verts_size);
2649 int nv = 0;
2650 for (int i = 0; i < verts_size; ++i) {
2651 CDTVert<T> *v = cdt->verts[i];
2652 if (v->merge_to_index == -1) {
2653 vert_to_output_map[i] = nv;
2654 ++nv;
2655 }
2656 }
2657 if (nv <= 0) {
2658 return result;
2659 }
2660 /* Now we can set vert_to_output_map for merged verts,
2661 * and also add the input indices of merged verts to the input_ids
2662 * list of the merge target if they were an original input id. */
2663 if (nv < verts_size) {
2664 for (int i = 0; i < verts_size; ++i) {
2665 CDTVert<T> *v = cdt->verts[i];
2666 if (v->merge_to_index != -1) {
2667 if (cdt_state->need_ids) {
2668 if (i < cdt_state->input_vert_num) {
2669 add_to_input_ids(cdt->verts[v->merge_to_index]->input_ids, i);
2670 }
2671 }
2672 vert_to_output_map[i] = vert_to_output_map[v->merge_to_index];
2673 }
2674 }
2675 }
2676 result.vert = Array<VecBase<T, 2>>(nv);
2677 if (cdt_state->need_ids) {
2678 result.vert_orig = Array<Vector<int>>(nv);
2679 }
2680 int i_out = 0;
2681 for (int i = 0; i < verts_size; ++i) {
2682 CDTVert<T> *v = cdt->verts[i];
2683 if (v->merge_to_index == -1) {
2684 result.vert[i_out] = v->co.exact;
2685 if (cdt_state->need_ids) {
2686 if (i < cdt_state->input_vert_num) {
2687 result.vert_orig[i_out].append(i);
2688 }
2689 for (int vert : v->input_ids) {
2690 result.vert_orig[i_out].append(vert);
2691 }
2692 }
2693 ++i_out;
2694 }
2695 }
2696
2697 /* All non-deleted edges will be output. */
2698 int ne = std::count_if(cdt->edges.begin(), cdt->edges.end(), [](const CDTEdge<T> *e) -> bool {
2699 return !is_deleted_edge(e);
2700 });
2702 if (cdt_state->need_ids) {
2703 result.edge_orig = Array<Vector<int>>(ne);
2704 }
2705 int e_out = 0;
2706 for (const CDTEdge<T> *e : cdt->edges) {
2707 if (!is_deleted_edge(e)) {
2708 int vo1 = vert_to_output_map[e->symedges[0].vert->index];
2709 int vo2 = vert_to_output_map[e->symedges[1].vert->index];
2710 result.edge[e_out] = std::pair<int, int>(vo1, vo2);
2711 if (cdt_state->need_ids) {
2712 for (int edge : e->input_ids) {
2713 result.edge_orig[e_out].append(edge);
2714 }
2715 }
2716 ++e_out;
2717 }
2718 }
2719
2720 /* All non-deleted, non-outer faces will be output. */
2721 int nf = std::count_if(cdt->faces.begin(), cdt->faces.end(), [=](const CDTFace<T> *f) -> bool {
2722 return !f->deleted && f != cdt->outer_face;
2723 });
2724 result.face = Array<Vector<int>>(nf);
2725 if (cdt_state->need_ids) {
2726 result.face_orig = Array<Vector<int>>(nf);
2727 }
2728 int f_out = 0;
2729 for (const CDTFace<T> *f : cdt->faces) {
2730 if (!f->deleted && f != cdt->outer_face) {
2731 SymEdge<T> *se = f->symedge;
2732 BLI_assert(se != nullptr);
2733 SymEdge<T> *se_start = se;
2734 do {
2735 result.face[f_out].append(vert_to_output_map[se->vert->index]);
2736 se = se->next;
2737 } while (se != se_start);
2738 if (cdt_state->need_ids) {
2739 for (int face : f->input_ids) {
2740 result.face_orig[f_out].append(face);
2741 }
2742 }
2743 ++f_out;
2744 }
2745 }
2746 return result;
2747}
2748
2753template<typename T> void add_input_verts(CDT_state<T> *cdt_state, const CDT_input<T> &input)
2754{
2755 for (int i = 0; i < cdt_state->input_vert_num; ++i) {
2756 cdt_state->cdt.add_vert(input.vert[i]);
2757 }
2758}
2759
2760template<typename T>
2762{
2763 int nv = input.vert.size();
2764 int ne = input.edge.size();
2765 int nf = input.face.size();
2766 CDT_state<T> cdt_state(nv, ne, nf, input.epsilon, input.need_ids);
2767 add_input_verts(&cdt_state, input);
2768 initial_triangulation(&cdt_state.cdt);
2769 add_edge_constraints(&cdt_state, input);
2770 int actual_nf = add_face_constraints(&cdt_state, input, output_type);
2771 if (actual_nf == 0 && !ELEM(output_type, CDT_FULL, CDT_INSIDE, CDT_CONSTRAINTS)) {
2772 /* Can't look for faces or holes if there were no valid input faces. */
2773 output_type = CDT_INSIDE;
2774 }
2775 return get_cdt_output(&cdt_state, input, output_type);
2776}
2777
2783
2784#ifdef WITH_GMP
2785blender::meshintersect::CDT_result<mpq_class> delaunay_2d_calc(const CDT_input<mpq_class> &input,
2786 CDT_output_type output_type)
2787{
2788 return delaunay_calc(input, output_type);
2789}
2790#endif
2791
2792} /* namespace blender::meshintersect */
#define BLI_assert(a)
Definition BLI_assert.h:46
CDT_output_type
@ CDT_CONSTRAINTS_VALID_BMESH
@ CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES
@ CDT_CONSTRAINTS
@ CDT_INSIDE
@ CDT_FULL
@ CDT_INSIDE_WITH_HOLES
Math vector functions needed specifically for mesh intersect and boolean.
#define UNUSED_VARS_NDEBUG(...)
#define POINTER_AS_INT(i)
#define ELEM(...)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
int64_t size() const
Definition BLI_set.hh:587
void clear()
Definition BLI_set.hh:551
const T * end() const
Definition BLI_array.hh:325
const T * begin() const
Definition BLI_array.hh:321
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
int64_t size() const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
void reserve(const int64_t min_capacity)
CDT_state(int input_verts_num, int input_edges_num, int input_faces_num, T epsilon, bool need_ids)
CrossData(T l, CDTVert< T > *v, SymEdge< T > *i, SymEdge< T > *o)
CrossData(const CrossData &other)
CrossData(CrossData &&other) noexcept
CrossData & operator=(CrossData &&other) noexcept
CrossData & operator=(const CrossData &other)
#define SY(y)
#define SX(x)
#define input
#define abs
int count
ccl_device_inline float2 fabs(const float2 a)
static ulong * next
#define T
static char faces[256]
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
isect_result< VecBase< T, Size > > isect_seg_seg(const VecBase< T, Size > &v1, const VecBase< T, Size > &v2, const VecBase< T, Size > &v3, const VecBase< T, Size > &v4)
std::ostream & operator<<(std::ostream &stream, EulerOrder order)
T distance(const T &a, const T &b)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
T interpolate(const T &a, const T &b, const FactorT &t)
void min_max(const T &value, T &min, T &max)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
void detect_holes(CDT_state< T > *cdt_state)
CDT_result< T > delaunay_calc(const CDT_input< T > &input, CDT_output_type output_type)
static void add_list_to_input_ids(blender::Set< int > &dst, const blender::Set< int > &src)
void dissolve_symedge(CDT_state< T > *cdt_state, SymEdge< T > *se)
double math_to_double< double >(const double v)
bool is_original_vert(const CDTVert< T > *v, CDT_state< T > *cdt)
int tri_orient(const SymEdge< T > *t)
SymEdge< T > * find_symedge_with_face(const CDTVert< T > *v, const CDTFace< T > *f)
void add_edge_constraints(CDT_state< T > *cdt_state, const CDT_input< T > &input)
bool is_border_edge(const CDTEdge< T > *e, const CDT_state< T > *cdt)
int add_face_constraints(CDT_state< T > *cdt_state, const CDT_input< T > &input, CDT_output_type output_type)
bool in_line< double >(const FatCo< double > &a, const FatCo< double > &b, const FatCo< double > &c)
bool vert_touches_face(const CDTVert< T > *v, const CDTFace< T > *f)
std::string sename(const SymEdge< T > *se)
void dump_crossings(const Span< CrossData< T > > crossings)
bool vert_left_of_symedge(CDTVert< T > *v, SymEdge< T > *se)
CDT_result< double > delaunay_2d_calc(const CDT_input< double > &input, CDT_output_type output_type)
std::string vertname(const CDTVert< T > *v)
static void add_to_input_ids(blender::Set< int > &dst, int input_id)
void cdt_draw(const std::string &label, const CDTArrangement< T > &cdt)
bool site_lexicographic_sort(const SiteInfo< T > &a, const SiteInfo< T > &b)
bool vert_right_of_symedge(CDTVert< T > *v, SymEdge< T > *se)
std::string short_se_dump(const SymEdge< T > *se)
void find_site_merges(Array< SiteInfo< T > > &sites)
CDT_result< T > get_cdt_output(CDT_state< T > *cdt_state, const CDT_input< T >, CDT_output_type output_type)
void add_edge_constraint(CDT_state< T > *cdt_state, CDTVert< T > *v1, CDTVert< T > *v2, int input_id, LinkNode **r_edges)
bool is_deleted_edge(const CDTEdge< T > *e)
SymEdge< T > * sym(const SymEdge< T > *se)
void dc_triangulate(CDTArrangement< T > *cdt, Array< SiteInfo< T > > &sites)
void fill_crossdata_for_intersect(const FatCo< T > &curco, const CDTVert< T > *v2, SymEdge< T > *t, CrossData< T > *cd, CrossData< T > *cd_next, const T epsilon)
void add_face_ids(CDT_state< T > *cdt_state, SymEdge< T > *face_symedge, int face_id, int fedge_start, int fedge_end)
static bool in_line(const FatCo< T > &a, const FatCo< T > &b, const FatCo< T > &c)
static bool id_range_in_list(const blender::Set< int > &id_list, int range_start, int range_end)
void remove_non_constraint_edges(CDT_state< T > *cdt_state)
bool dc_tri_valid(SymEdge< T > *se, SymEdge< T > *basel, SymEdge< T > *basel_sym)
void prepare_cdt_for_output(CDT_state< T > *cdt_state, const CDT_output_type output_type)
static int filtered_orient2d(const FatCo< T > &a, const FatCo< T > &b, const FatCo< T > &c)
bool is_constrained_edge(const CDTEdge< T > *e)
static std::string trunc_ptr(const void *p)
static void re_delaunay_triangulate(CDTArrangement< T > *cdt, SymEdge< T > *se)
void initial_triangulation(CDTArrangement< T > *cdt)
void remove_outer_edges_until_constraints(CDT_state< T > *cdt_state)
double math_abs< double >(const double v)
double math_to_double(const T)
static int power_of_10_greater_equal_to(int x)
void remove_faces_in_holes(CDT_state< T > *cdt_state)
void get_next_crossing_from_edge(CrossData< T > *cd, CrossData< T > *cd_next, const CDTVert< T > *v2, const T epsilon)
void remove_non_constraint_edges_leave_valid_bmesh(CDT_state< T > *cdt_state)
void dc_tri(CDTArrangement< T > *cdt, Array< SiteInfo< T > > &sites, int start, int end, SymEdge< T > **r_le, SymEdge< T > **r_re)
void fill_crossdata_for_through_vert(CDTVert< T > *v, SymEdge< T > *cd_out, CrossData< T > *cd, CrossData< T > *cd_next)
SymEdge< T > * prev(const SymEdge< T > *se)
int filtered_incircle< double >(const FatCo< double > &a, const FatCo< double > &b, const FatCo< double > &c, const FatCo< double > &d)
int filtered_orient2d< double >(const FatCo< double > &a, const FatCo< double > &b, const FatCo< double > &c)
bool exists_edge(const CDTVert< T > *v1, const CDTVert< T > *v2)
static int filtered_incircle(const FatCo< T > &a, const FatCo< T > &b, const FatCo< T > &c, const FatCo< T > &d)
bool get_next_crossing_from_vert(CDT_state< T > *cdt_state, CrossData< T > *cd, CrossData< T > *cd_next, const CDTVert< T > *v2)
void add_input_verts(CDT_state< T > *cdt_state, const CDT_input< T > &input)
SymEdge< T > * find_symedge_between_verts(const CDTVert< T > *v1, const CDTVert< T > *v2)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
int orient2d(const double2 &a, const double2 &b, const double2 &c)
VecBase< double, 2 > double2
int incircle(const double2 &a, const double2 &b, const double2 &c, const double2 &d)
LinkNode * list
void * link
CDTEdge< T > * add_edge(CDTVert< T > *v1, CDTVert< T > *v2, CDTFace< T > *fleft, CDTFace< T > *fright)
CDTVert< T > * get_vert_resolve_merge(int i)
CDTVert< T > * add_vert(const VecBase< T, 2 > &pt)
CDTEdge< T > * add_vert_to_symedge_edge(CDTVert< T > *v, SymEdge< T > *se)
void reserve(int verts_num, int edges_num, int faces_num)
CDTEdge< T > * add_diagonal(SymEdge< T > *s1, SymEdge< T > *s2)
CDTEdge< T > * connect_separate_parts(SymEdge< T > *se1, SymEdge< T > *se2)
CDTEdge< T > * split_edge(SymEdge< T > *se, T lambda)
blender::Set< int > input_ids
blender::Set< int > input_ids
CDTVert(const VecBase< T, 2 > &pt)
blender::Set< int > input_ids
EdgeToSort(EdgeToSort &&other) noexcept
EdgeToSort(const EdgeToSort &other)
EdgeToSort & operator=(const EdgeToSort &other)
EdgeToSort & operator=(EdgeToSort &&other)
i
Definition text_draw.cc:230