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