Blender V4.3
mesh_intersect.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/* The #blender::meshintersect API needs GMP. */
10#ifdef WITH_GMP
11
12# include <algorithm>
13# include <fstream>
14# include <functional>
15# include <iostream>
16# include <memory>
17
18# include "BLI_allocator.hh"
19# include "BLI_array.hh"
20# include "BLI_assert.h"
21# include "BLI_delaunay_2d.hh"
22# include "BLI_hash.hh"
23# include "BLI_kdopbvh.h"
24# include "BLI_map.hh"
25# include "BLI_math_geom.h"
26# include "BLI_math_matrix.h"
27# include "BLI_math_mpq.hh"
28# include "BLI_math_vector.h"
31# include "BLI_polyfill_2d.h"
32# include "BLI_set.hh"
33# include "BLI_sort.hh"
34# include "BLI_span.hh"
35# include "BLI_task.h"
36# include "BLI_task.hh"
37# include "BLI_threads.h"
38# include "BLI_vector.hh"
39# include "BLI_vector_set.hh"
40
41# include "BLI_mesh_intersect.hh"
42
43// # define PERFDEBUG
44
45namespace blender::meshintersect {
46
47# ifdef PERFDEBUG
48static void perfdata_init();
49static void incperfcount(int countnum);
50static void bumpperfcount(int countnum, int amt);
51static void doperfmax(int maxnum, int val);
52static void dump_perfdata();
53# endif
54
56static constexpr bool intersect_use_threading = true;
57
58Vert::Vert(const mpq3 &mco, const double3 &dco, int id, int orig)
59 : co_exact(mco), co(dco), id(id), orig(orig)
60{
61}
62
63bool Vert::operator==(const Vert &other) const
64{
65 return this->co_exact == other.co_exact;
66}
67
68uint64_t Vert::hash() const
69{
70 uint64_t x = *reinterpret_cast<const uint64_t *>(&co.x);
71 uint64_t y = *reinterpret_cast<const uint64_t *>(&co.y);
72 uint64_t z = *reinterpret_cast<const uint64_t *>(&co.z);
73 x = (x >> 56) ^ (x >> 46) ^ x;
74 y = (y >> 55) ^ (y >> 45) ^ y;
75 z = (z >> 54) ^ (z >> 44) ^ z;
76 return x ^ y ^ z;
77}
78
79std::ostream &operator<<(std::ostream &os, const Vert *v)
80{
81 constexpr int dbg_level = 0;
82 os << "v" << v->id;
83 if (v->orig != NO_INDEX) {
84 os << "o" << v->orig;
85 }
86 os << v->co;
87 if (dbg_level > 0) {
88 os << "=" << v->co_exact;
89 }
90 return os;
91}
92
93bool Plane::operator==(const Plane &other) const
94{
95 return norm_exact == other.norm_exact && d_exact == other.d_exact;
96}
97
98void Plane::make_canonical()
99{
100 if (norm_exact[0] != 0) {
101 mpq_class den = norm_exact[0];
102 norm_exact = mpq3(1, norm_exact[1] / den, norm_exact[2] / den);
103 d_exact = d_exact / den;
104 }
105 else if (norm_exact[1] != 0) {
106 mpq_class den = norm_exact[1];
107 norm_exact = mpq3(0, 1, norm_exact[2] / den);
108 d_exact = d_exact / den;
109 }
110 else {
111 if (norm_exact[2] != 0) {
112 mpq_class den = norm_exact[2];
113 norm_exact = mpq3(0, 0, 1);
114 d_exact = d_exact / den;
115 }
116 else {
117 /* A degenerate plane. */
118 d_exact = 0;
119 }
120 }
121 norm = double3(norm_exact[0].get_d(), norm_exact[1].get_d(), norm_exact[2].get_d());
122 d = d_exact.get_d();
123}
124
125Plane::Plane(const mpq3 &norm_exact, const mpq_class &d_exact)
126 : norm_exact(norm_exact), d_exact(d_exact)
127{
128 norm = double3(norm_exact[0].get_d(), norm_exact[1].get_d(), norm_exact[2].get_d());
129 d = d_exact.get_d();
130}
131
132Plane::Plane(const double3 &norm, const double d) : norm(norm), d(d)
133{
134 norm_exact = mpq3(0, 0, 0); /* Marks as "exact not yet populated". */
135}
136
137bool Plane::exact_populated() const
138{
139 return norm_exact[0] != 0 || norm_exact[1] != 0 || norm_exact[2] != 0;
140}
141
142uint64_t Plane::hash() const
143{
144 uint64_t x = *reinterpret_cast<const uint64_t *>(&this->norm.x);
145 uint64_t y = *reinterpret_cast<const uint64_t *>(&this->norm.y);
146 uint64_t z = *reinterpret_cast<const uint64_t *>(&this->norm.z);
147 uint64_t d = *reinterpret_cast<const uint64_t *>(&this->d);
148 x = (x >> 56) ^ (x >> 46) ^ x;
149 y = (y >> 55) ^ (y >> 45) ^ y;
150 z = (z >> 54) ^ (z >> 44) ^ z;
151 d = (d >> 53) ^ (d >> 43) ^ d;
152 return x ^ y ^ z ^ d;
153}
154
155std::ostream &operator<<(std::ostream &os, const Plane *plane)
156{
157 os << "[" << plane->norm << ";" << plane->d << "]";
158 return os;
159}
160
161Face::Face(
162 Span<const Vert *> verts, int id, int orig, Span<int> edge_origs, Span<bool> is_intersect)
163 : vert(verts), edge_orig(edge_origs), is_intersect(is_intersect), id(id), orig(orig)
164{
165}
166
167Face::Face(Span<const Vert *> verts, int id, int orig) : vert(verts), id(id), orig(orig) {}
168
169void Face::populate_plane(bool need_exact)
170{
171 if (plane != nullptr) {
172 if (!need_exact || plane->exact_populated()) {
173 return;
174 }
175 }
176 if (need_exact) {
177 mpq3 normal_exact;
178 if (vert.size() > 3) {
179 Array<mpq3> co(vert.size());
180 for (int i : index_range()) {
181 co[i] = vert[i]->co_exact;
182 }
183 normal_exact = math::cross_poly(co.as_span());
184 }
185 else {
186 mpq3 tr02 = vert[0]->co_exact - vert[2]->co_exact;
187 mpq3 tr12 = vert[1]->co_exact - vert[2]->co_exact;
188 normal_exact = math::cross(tr02, tr12);
189 }
190 mpq_class d_exact = -math::dot(normal_exact, vert[0]->co_exact);
191 plane = new Plane(normal_exact, d_exact);
192 }
193 else {
194 double3 normal;
195 if (vert.size() > 3) {
196 Array<double3> co(vert.size());
197 for (int i : index_range()) {
198 co[i] = vert[i]->co;
199 }
200 normal = math::cross_poly(co.as_span());
201 }
202 else {
203 double3 tr02 = vert[0]->co - vert[2]->co;
204 double3 tr12 = vert[1]->co - vert[2]->co;
205 normal = math::cross(tr02, tr12);
206 }
207 double d = -math::dot(normal, vert[0]->co);
208 plane = new Plane(normal, d);
209 }
210}
211
212Face::~Face()
213{
214 delete plane;
215}
216
217bool Face::operator==(const Face &other) const
218{
219 if (this->size() != other.size()) {
220 return false;
221 }
222 for (FacePos i : index_range()) {
223 /* Can test pointer equality since we will have
224 * unique vert pointers for unique co_equal's. */
225 if (this->vert[i] != other.vert[i]) {
226 return false;
227 }
228 }
229 return true;
230}
231
232bool Face::cyclic_equal(const Face &other) const
233{
234 if (this->size() != other.size()) {
235 return false;
236 }
237 int flen = this->size();
238 for (FacePos start : index_range()) {
239 for (FacePos start_other : index_range()) {
240 bool ok = true;
241 for (int i = 0; ok && i < flen; ++i) {
242 FacePos p = (start + i) % flen;
243 FacePos p_other = (start_other + i) % flen;
244 if (this->vert[p] != other.vert[p_other]) {
245 ok = false;
246 }
247 }
248 if (ok) {
249 return true;
250 }
251 }
252 }
253 return false;
254}
255
256std::ostream &operator<<(std::ostream &os, const Face *f)
257{
258 os << "f" << f->id << "o" << f->orig << "[";
259 for (const Vert *v : *f) {
260 os << v;
261 if (v != f->vert[f->size() - 1]) {
262 os << " ";
263 }
264 }
265 os << "]";
266 if (f->orig != NO_INDEX) {
267 os << "o" << f->orig;
268 }
269 os << " e_orig[";
270 for (int i : f->index_range()) {
271 os << f->edge_orig[i];
272 if (f->is_intersect[i]) {
273 os << "#";
274 }
275 if (i != f->size() - 1) {
276 os << " ";
277 }
278 }
279 os << "]";
280 return os;
281}
282
289// #define USE_SPINLOCK
290
298class IMeshArena::IMeshArenaImpl : NonCopyable, NonMovable {
299
305 struct VSetKey {
306 Vert *vert;
307
308 VSetKey(Vert *p) : vert(p) {}
309
310 uint64_t hash() const
311 {
312 return vert->hash();
313 }
314
315 bool operator==(const VSetKey &other) const
316 {
317 return *this->vert == *other.vert;
318 }
319 };
320
321 Set<VSetKey> vset_;
322
328 Vector<std::unique_ptr<Vert>> allocated_verts_;
329 Vector<std::unique_ptr<Face>> allocated_faces_;
330
331 /* Use these to allocate ids when Verts and Faces are allocated. */
332 int next_vert_id_ = 0;
333 int next_face_id_ = 0;
334
335 /* Need a lock when multi-threading to protect allocation of new elements. */
336# ifdef USE_SPINLOCK
337 SpinLock lock_;
338# else
339 ThreadMutex *mutex_;
340# endif
341
342 public:
343 IMeshArenaImpl()
344 {
345 if (intersect_use_threading) {
346# ifdef USE_SPINLOCK
347 BLI_spin_init(&lock_);
348# else
349 mutex_ = BLI_mutex_alloc();
350# endif
351 }
352 }
353 ~IMeshArenaImpl()
354 {
355 if (intersect_use_threading) {
356# ifdef USE_SPINLOCK
357 BLI_spin_end(&lock_);
358# else
359 BLI_mutex_free(mutex_);
360# endif
361 }
362 }
363
364 void reserve(int vert_num_hint, int face_num_hint)
365 {
366 vset_.reserve(vert_num_hint);
367 allocated_verts_.reserve(vert_num_hint);
368 allocated_faces_.reserve(face_num_hint);
369 }
370
371 int tot_allocated_verts() const
372 {
373 return allocated_verts_.size();
374 }
375
376 int tot_allocated_faces() const
377 {
378 return allocated_faces_.size();
379 }
380
381 const Vert *add_or_find_vert(const mpq3 &co, int orig)
382 {
383 double3 dco(co[0].get_d(), co[1].get_d(), co[2].get_d());
384 return add_or_find_vert(co, dco, orig);
385 }
386
387 const Vert *add_or_find_vert(const double3 &co, int orig)
388 {
389 mpq3 mco(co[0], co[1], co[2]);
390 return add_or_find_vert(mco, co, orig);
391 }
392
393 const Vert *add_or_find_vert(Vert *vert)
394 {
395 return add_or_find_vert_(vert);
396 }
397
398 Face *add_face(Span<const Vert *> verts, int orig, Span<int> edge_origs, Span<bool> is_intersect)
399 {
400 Face *f = new Face(verts, next_face_id_++, orig, edge_origs, is_intersect);
401 if (intersect_use_threading) {
402# ifdef USE_SPINLOCK
403 BLI_spin_lock(&lock_);
404# else
405 BLI_mutex_lock(mutex_);
406# endif
407 }
408 allocated_faces_.append(std::unique_ptr<Face>(f));
409 if (intersect_use_threading) {
410# ifdef USE_SPINLOCK
411 BLI_spin_unlock(&lock_);
412# else
413 BLI_mutex_unlock(mutex_);
414# endif
415 }
416 return f;
417 }
418
419 Face *add_face(Span<const Vert *> verts, int orig, Span<int> edge_origs)
420 {
421 Array<bool> is_intersect(verts.size(), false);
422 return add_face(verts, orig, edge_origs, is_intersect);
423 }
424
425 Face *add_face(Span<const Vert *> verts, int orig)
426 {
427 Array<int> edge_origs(verts.size(), NO_INDEX);
428 Array<bool> is_intersect(verts.size(), false);
429 return add_face(verts, orig, edge_origs, is_intersect);
430 }
431
432 const Vert *find_vert(const mpq3 &co)
433 {
434 Vert vtry(co, double3(co[0].get_d(), co[1].get_d(), co[2].get_d()), NO_INDEX, NO_INDEX);
435 VSetKey vskey(&vtry);
436 if (intersect_use_threading) {
437# ifdef USE_SPINLOCK
438 BLI_spin_lock(&lock_);
439# else
440 BLI_mutex_lock(mutex_);
441# endif
442 }
443 const VSetKey *lookup = vset_.lookup_key_ptr(vskey);
444 if (intersect_use_threading) {
445# ifdef USE_SPINLOCK
446 BLI_spin_unlock(&lock_);
447# else
448 BLI_mutex_unlock(mutex_);
449# endif
450 }
451 if (!lookup) {
452 return nullptr;
453 }
454 return lookup->vert;
455 }
456
462 const Face *find_face(Span<const Vert *> vs)
463 {
464 Array<int> eorig(vs.size(), NO_INDEX);
465 Array<bool> is_intersect(vs.size(), false);
466 Face ftry(vs, NO_INDEX, NO_INDEX, eorig, is_intersect);
467 for (const int i : allocated_faces_.index_range()) {
468 if (ftry.cyclic_equal(*allocated_faces_[i])) {
469 return allocated_faces_[i].get();
470 }
471 }
472 return nullptr;
473 }
474
475 private:
476 const Vert *add_or_find_vert(const mpq3 &mco, const double3 &dco, int orig)
477 {
478 Vert *vtry = new Vert(mco, dco, NO_INDEX, NO_INDEX);
479 const Vert *ans;
480 VSetKey vskey(vtry);
481 if (intersect_use_threading) {
482# ifdef USE_SPINLOCK
483 BLI_spin_lock(&lock_);
484# else
485 BLI_mutex_lock(mutex_);
486# endif
487 }
488 const VSetKey *lookup = vset_.lookup_key_ptr(vskey);
489 if (!lookup) {
490 vtry->id = next_vert_id_++;
491 vtry->orig = orig;
492 vskey.vert = vtry; // new Vert(mco, dco, next_vert_id_++, orig);
493 vset_.add_new(vskey);
494 allocated_verts_.append(std::unique_ptr<Vert>(vskey.vert));
495 ans = vskey.vert;
496 }
497 else {
498 /* It was a duplicate, so return the existing one.
499 * Note that the returned Vert may have a different orig.
500 * This is the intended semantics: if the Vert already
501 * exists then we are merging verts and using the first-seen
502 * one as the canonical one. */
503 delete vtry;
504 ans = lookup->vert;
505 }
506 if (intersect_use_threading) {
507# ifdef USE_SPINLOCK
508 BLI_spin_unlock(&lock_);
509# else
510 BLI_mutex_unlock(mutex_);
511# endif
512 }
513 return ans;
514 };
515
516 const Vert *add_or_find_vert_(Vert *vtry)
517 {
518 const Vert *ans;
519 VSetKey vskey(vtry);
520 if (intersect_use_threading) {
521# ifdef USE_SPINLOCK
522 BLI_spin_lock(&lock_);
523# else
524 BLI_mutex_lock(mutex_);
525# endif
526 }
527 const VSetKey *lookup = vset_.lookup_key_ptr(vskey);
528 if (!lookup) {
529 vtry->id = next_vert_id_++;
530 vskey.vert = vtry; // new Vert(mco, dco, next_vert_id_++, orig);
531 vset_.add_new(vskey);
532 allocated_verts_.append(std::unique_ptr<Vert>(vskey.vert));
533 ans = vskey.vert;
534 }
535 else {
536 /* It was a duplicate, so return the existing one.
537 * Note that the returned Vert may have a different orig.
538 * This is the intended semantics: if the Vert already
539 * exists then we are merging verts and using the first-seen
540 * one as the canonical one. */
541 delete vtry;
542 ans = lookup->vert;
543 }
544 if (intersect_use_threading) {
545# ifdef USE_SPINLOCK
546 BLI_spin_unlock(&lock_);
547# else
548 BLI_mutex_unlock(mutex_);
549# endif
550 }
551 return ans;
552 };
553};
554
555IMeshArena::IMeshArena()
556{
557 pimpl_ = std::make_unique<IMeshArenaImpl>();
558}
559
560IMeshArena::~IMeshArena() = default;
561
562void IMeshArena::reserve(int vert_num_hint, int face_num_hint)
563{
564 pimpl_->reserve(vert_num_hint, face_num_hint);
565}
566
567int IMeshArena::tot_allocated_verts() const
568{
569 return pimpl_->tot_allocated_verts();
570}
571
572int IMeshArena::tot_allocated_faces() const
573{
574 return pimpl_->tot_allocated_faces();
575}
576
577const Vert *IMeshArena::add_or_find_vert(const mpq3 &co, int orig)
578{
579 return pimpl_->add_or_find_vert(co, orig);
580}
581
582const Vert *IMeshArena::add_or_find_vert(Vert *vert)
583{
584 return pimpl_->add_or_find_vert(vert);
585}
586
587Face *IMeshArena::add_face(Span<const Vert *> verts,
588 int orig,
589 Span<int> edge_origs,
590 Span<bool> is_intersect)
591{
592 return pimpl_->add_face(verts, orig, edge_origs, is_intersect);
593}
594
595Face *IMeshArena::add_face(Span<const Vert *> verts, int orig, Span<int> edge_origs)
596{
597 return pimpl_->add_face(verts, orig, edge_origs);
598}
599
600Face *IMeshArena::add_face(Span<const Vert *> verts, int orig)
601{
602 return pimpl_->add_face(verts, orig);
603}
604
605const Vert *IMeshArena::add_or_find_vert(const double3 &co, int orig)
606{
607 return pimpl_->add_or_find_vert(co, orig);
608}
609
610const Vert *IMeshArena::find_vert(const mpq3 &co) const
611{
612 return pimpl_->find_vert(co);
613}
614
615const Face *IMeshArena::find_face(Span<const Vert *> verts) const
616{
617 return pimpl_->find_face(verts);
618}
619
620void IMesh::set_faces(Span<Face *> faces)
621{
622 face_ = faces;
623}
624
625int IMesh::lookup_vert(const Vert *v) const
626{
627 BLI_assert(vert_populated_);
628 return vert_to_index_.lookup_default(v, NO_INDEX);
629}
630
631void IMesh::populate_vert()
632{
633 /* This is likely an overestimate, since verts are shared between
634 * faces. It is ok if estimate is over or even under. */
635 constexpr int ESTIMATE_VERTS_PER_FACE = 4;
636 int estimate_verts_num = ESTIMATE_VERTS_PER_FACE * face_.size();
637 populate_vert(estimate_verts_num);
638}
639
640void IMesh::populate_vert(int max_verts)
641{
642 if (vert_populated_) {
643 return;
644 }
645 vert_to_index_.reserve(max_verts);
646 int next_allocate_index = 0;
647 for (const Face *f : face_) {
648 for (const Vert *v : *f) {
649 if (v->id == 1) {
650 }
651 int index = vert_to_index_.lookup_default(v, NO_INDEX);
652 if (index == NO_INDEX) {
653 BLI_assert(next_allocate_index < UINT_MAX - 2);
654 vert_to_index_.add(v, next_allocate_index++);
655 }
656 }
657 }
658 int tot_v = next_allocate_index;
659 vert_ = Array<const Vert *>(tot_v);
660 for (auto item : vert_to_index_.items()) {
661 int index = item.value;
662 BLI_assert(index < tot_v);
663 vert_[index] = item.key;
664 }
665 /* Easier debugging (at least when there are no merged input verts)
666 * if output vert order is same as input, with new verts at the end.
667 * TODO: when all debugged, set fix_order = false. */
668 const bool fix_order = true;
669 if (fix_order) {
670 blender::parallel_sort(vert_.begin(), vert_.end(), [](const Vert *a, const Vert *b) {
671 if (a->orig != NO_INDEX && b->orig != NO_INDEX) {
672 return a->orig < b->orig;
673 }
674 if (a->orig != NO_INDEX) {
675 return true;
676 }
677 if (b->orig != NO_INDEX) {
678 return false;
679 }
680 return a->id < b->id;
681 });
682 for (int i : vert_.index_range()) {
683 const Vert *v = vert_[i];
684 vert_to_index_.add_overwrite(v, i);
685 }
686 }
687 vert_populated_ = true;
688}
689
690bool IMesh::erase_face_positions(int f_index, Span<bool> face_pos_erase, IMeshArena *arena)
691{
692 const Face *cur_f = this->face(f_index);
693 int cur_len = cur_f->size();
694 int to_erase_num = 0;
695 for (int i : cur_f->index_range()) {
696 if (face_pos_erase[i]) {
697 ++to_erase_num;
698 }
699 }
700 if (to_erase_num == 0) {
701 return false;
702 }
703 int new_len = cur_len - to_erase_num;
704 if (new_len < 3) {
705 /* This erase causes removal of whole face.
706 * Because this may be called from a loop over the face array,
707 * we don't want to compress that array right here; instead will
708 * mark with null pointer and caller should call remove_null_faces().
709 * the loop is done.
710 */
711 this->face_[f_index] = nullptr;
712 return true;
713 }
714 Array<const Vert *> new_vert(new_len);
715 Array<int> new_edge_orig(new_len);
716 Array<bool> new_is_intersect(new_len);
717 int new_index = 0;
718 for (int i : cur_f->index_range()) {
719 if (!face_pos_erase[i]) {
720 new_vert[new_index] = (*cur_f)[i];
721 new_edge_orig[new_index] = cur_f->edge_orig[i];
722 new_is_intersect[new_index] = cur_f->is_intersect[i];
723 ++new_index;
724 }
725 }
726 BLI_assert(new_index == new_len);
727 this->face_[f_index] = arena->add_face(new_vert, cur_f->orig, new_edge_orig, new_is_intersect);
728 return false;
729}
730
731void IMesh::remove_null_faces()
732{
733 int64_t nullcount = 0;
734 for (Face *f : this->face_) {
735 if (f == nullptr) {
736 ++nullcount;
737 }
738 }
739 if (nullcount == 0) {
740 return;
741 }
742 int64_t new_size = this->face_.size() - nullcount;
743 int64_t copy_to_index = 0;
744 int64_t copy_from_index = 0;
745 Array<Face *> new_face(new_size);
746 while (copy_from_index < face_.size()) {
747 Face *f_from = face_[copy_from_index++];
748 if (f_from) {
749 new_face[copy_to_index++] = f_from;
750 }
751 }
752 this->face_ = new_face;
753}
754
755std::ostream &operator<<(std::ostream &os, const IMesh &mesh)
756{
757 if (mesh.has_verts()) {
758 os << "Verts:\n";
759 int i = 0;
760 for (const Vert *v : mesh.vertices()) {
761 os << i << ": " << v << "\n";
762 ++i;
763 }
764 }
765 os << "\nFaces:\n";
766 int i = 0;
767 for (const Face *f : mesh.faces()) {
768 os << i << ": " << f << "\n";
769 if (f->plane != nullptr) {
770 os << " plane=" << f->plane << " eorig=[";
771 for (Face::FacePos p = 0; p < f->size(); ++p) {
772 os << f->edge_orig[p] << " ";
773 }
774 os << "]\n";
775 }
776 ++i;
777 }
778 return os;
779}
780
781bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b)
782{
783 return isect_aabb_aabb_v3(bb_a.min, bb_a.max, bb_b.min, bb_b.max);
784}
785
792struct BBChunkData {
793 double max_abs_val = 0.0;
794};
795
796struct BBCalcData {
797 const IMesh &im;
798 Array<BoundingBox> *face_bounding_box;
799
800 BBCalcData(const IMesh &im, Array<BoundingBox> *fbb) : im(im), face_bounding_box(fbb){};
801};
802
803static void calc_face_bb_range_func(void *__restrict userdata,
804 const int iter,
805 const TaskParallelTLS *__restrict tls)
806{
807 BBCalcData *bbdata = static_cast<BBCalcData *>(userdata);
808 double max_abs = 0.0;
809 const Face &face = *bbdata->im.face(iter);
810 BoundingBox &bb = (*bbdata->face_bounding_box)[iter];
811 for (const Vert *v : face) {
812 bb.combine(v->co);
813 for (int i = 0; i < 3; ++i) {
814 max_abs = max_dd(max_abs, fabs(v->co[i]));
815 }
816 }
817 BBChunkData *chunk = static_cast<BBChunkData *>(tls->userdata_chunk);
818 chunk->max_abs_val = max_dd(max_abs, chunk->max_abs_val);
819}
820
821struct BBPadData {
822 Array<BoundingBox> *face_bounding_box;
823 double pad;
824
825 BBPadData(Array<BoundingBox> *fbb, double pad) : face_bounding_box(fbb), pad(pad){};
826};
827
828static void pad_face_bb_range_func(void *__restrict userdata,
829 const int iter,
830 const TaskParallelTLS *__restrict /*tls*/)
831{
832 BBPadData *pad_data = static_cast<BBPadData *>(userdata);
833 (*pad_data->face_bounding_box)[iter].expand(pad_data->pad);
834}
835
836static void calc_face_bb_reduce(const void *__restrict /*userdata*/,
837 void *__restrict chunk_join,
838 void *__restrict chunk)
839{
840 BBChunkData *bbchunk_join = static_cast<BBChunkData *>(chunk_join);
841 BBChunkData *bbchunk = static_cast<BBChunkData *>(chunk);
842 bbchunk_join->max_abs_val = max_dd(bbchunk_join->max_abs_val, bbchunk->max_abs_val);
843}
844
850static Array<BoundingBox> calc_face_bounding_boxes(const IMesh &m)
851{
852 int n = m.face_size();
853 Array<BoundingBox> ans(n);
854 TaskParallelSettings settings;
855 BBCalcData data(m, &ans);
856 BBChunkData chunk_data;
858 settings.userdata_chunk = &chunk_data;
859 settings.userdata_chunk_size = sizeof(chunk_data);
860 settings.func_reduce = calc_face_bb_reduce;
861 settings.min_iter_per_thread = 1000;
862 settings.use_threading = intersect_use_threading;
863 BLI_task_parallel_range(0, n, &data, calc_face_bb_range_func, &settings);
864 double max_abs_val = chunk_data.max_abs_val;
865 constexpr float pad_factor = 10.0f;
866 float pad = max_abs_val == 0.0f ? FLT_EPSILON : 2 * FLT_EPSILON * max_abs_val;
867 pad *= pad_factor; /* For extra safety. */
868 TaskParallelSettings pad_settings;
870 settings.min_iter_per_thread = 1000;
871 settings.use_threading = intersect_use_threading;
872 BBPadData pad_data(&ans, pad);
873 BLI_task_parallel_range(0, n, &pad_data, pad_face_bb_range_func, &pad_settings);
874 return ans;
875}
876
886class CoplanarCluster {
887 Vector<int> tris_;
888 BoundingBox bb_;
889
890 public:
891 CoplanarCluster() = default;
892 CoplanarCluster(int t, const BoundingBox &bb)
893 {
894 this->add_tri(t, bb);
895 }
896
897 /* Assume that caller knows this will not be a duplicate. */
898 void add_tri(int t, const BoundingBox &bb)
899 {
900 tris_.append(t);
901 bb_.combine(bb);
902 }
903 int tot_tri() const
904 {
905 return tris_.size();
906 }
907 int tri(int index) const
908 {
909 return tris_[index];
910 }
911 const int *begin() const
912 {
913 return tris_.begin();
914 }
915 const int *end() const
916 {
917 return tris_.end();
918 }
919
920 const BoundingBox &bounding_box() const
921 {
922 return bb_;
923 }
924};
925
932class CoplanarClusterInfo {
933 Vector<CoplanarCluster> clusters_;
934 Array<int> tri_cluster_;
935
936 public:
937 CoplanarClusterInfo() = default;
938 explicit CoplanarClusterInfo(int numtri) : tri_cluster_(Array<int>(numtri))
939 {
940 tri_cluster_.fill(-1);
941 }
942
943 int tri_cluster(int t) const
944 {
945 BLI_assert(t < tri_cluster_.size());
946 return tri_cluster_[t];
947 }
948
949 int add_cluster(const CoplanarCluster &cl)
950 {
951 int c_index = clusters_.append_and_get_index(cl);
952 for (int t : cl) {
953 BLI_assert(t < tri_cluster_.size());
954 tri_cluster_[t] = c_index;
955 }
956 return c_index;
957 }
958
959 int tot_cluster() const
960 {
961 return clusters_.size();
962 }
963
964 const CoplanarCluster *begin()
965 {
966 return clusters_.begin();
967 }
968
969 const CoplanarCluster *end()
970 {
971 return clusters_.end();
972 }
973
974 IndexRange index_range() const
975 {
976 return clusters_.index_range();
977 }
978
979 const CoplanarCluster &cluster(int index) const
980 {
981 BLI_assert(index < clusters_.size());
982 return clusters_[index];
983 }
984};
985
986static std::ostream &operator<<(std::ostream &os, const CoplanarCluster &cl);
987
988static std::ostream &operator<<(std::ostream &os, const CoplanarClusterInfo &clinfo);
989
990enum ITT_value_kind { INONE, IPOINT, ISEGMENT, ICOPLANAR };
991
992struct ITT_value {
993 mpq3 p1; /* Only relevant for IPOINT and ISEGMENT kind. */
994 mpq3 p2; /* Only relevant for ISEGMENT kind. */
995 int t_source = -1; /* Index of the source triangle that intersected the target one. */
996 enum ITT_value_kind kind = INONE;
997
998 ITT_value() = default;
999 explicit ITT_value(ITT_value_kind k) : kind(k) {}
1000 ITT_value(ITT_value_kind k, int tsrc) : t_source(tsrc), kind(k) {}
1001 ITT_value(ITT_value_kind k, const mpq3 &p1) : p1(p1), kind(k) {}
1002 ITT_value(ITT_value_kind k, const mpq3 &p1, const mpq3 &p2) : p1(p1), p2(p2), kind(k) {}
1003};
1004
1005static std::ostream &operator<<(std::ostream &os, const ITT_value &itt);
1006
1012static mpq2 project_3d_to_2d(const mpq3 &p3d, int proj_axis)
1013{
1014 mpq2 p2d;
1015 switch (proj_axis) {
1016 case (0): {
1017 p2d[0] = p3d[1];
1018 p2d[1] = p3d[2];
1019 break;
1020 }
1021 case (1): {
1022 p2d[0] = p3d[0];
1023 p2d[1] = p3d[2];
1024 break;
1025 }
1026 case (2): {
1027 p2d[0] = p3d[0];
1028 p2d[1] = p3d[1];
1029 break;
1030 }
1031 default:
1032 BLI_assert(false);
1033 }
1034 return p2d;
1035}
1036
1067static double supremum_dot_cross(const double3 &a, const double3 &b)
1068{
1069 double3 abs_a = math::abs(a);
1070 double3 abs_b = math::abs(b);
1071 double3 c;
1072 /* This is dot(cross(a, b), cross(a,b)) but using absolute values for a and b
1073 * and always using + when operation is + or -. */
1074 c[0] = abs_a[1] * abs_b[2] + abs_a[2] * abs_b[1];
1075 c[1] = abs_a[2] * abs_b[0] + abs_a[0] * abs_b[2];
1076 c[2] = abs_a[0] * abs_b[1] + abs_a[1] * abs_b[0];
1077 return math::dot(c, c);
1078}
1079
1080/* The index of dot when inputs are plane_coords with index 1 is much higher.
1081 * Plane coords have index 6.
1082 */
1083constexpr int index_dot_plane_coords = 15;
1084
1095constexpr int index_dot_cross = 11;
1096
1105constexpr int index_plane_side = 3 + 2 * index_dot_plane_coords;
1106
1107static int filter_plane_side(const double3 &p,
1108 const double3 &plane_p,
1109 const double3 &plane_no,
1110 const double3 &abs_p,
1111 const double3 &abs_plane_p,
1112 const double3 &abs_plane_no)
1113{
1114 double d = math::dot(p - plane_p, plane_no);
1115 if (d == 0.0) {
1116 return 0;
1117 }
1118 double supremum = math::dot(abs_p + abs_plane_p, abs_plane_no);
1119 double err_bound = supremum * index_plane_side * DBL_EPSILON;
1120 if (fabs(d) > err_bound) {
1121 return d > 0 ? 1 : -1;
1122 }
1123 return 0;
1124}
1125
1126/*
1127 * #intersect_tri_tri and helper functions.
1128 * This code uses the algorithm of Guigue and Devillers, as described
1129 * in "Faster Triangle-Triangle Intersection Tests".
1130 * Adapted from code by Eric Haines:
1131 * https://github.com/erich666/jgt-code/tree/master/Volume_08/Number_1/Guigue2003
1132 */
1133
1142static inline mpq3 tti_interp(
1143 const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &n, mpq3 &ab, mpq3 &ac, mpq3 &dotbuf)
1144{
1145 ab = a;
1146 ab -= b;
1147 ac = a;
1148 ac -= c;
1149 mpq_class den = math::dot_with_buffer(ab, n, dotbuf);
1150 BLI_assert(den != 0);
1151 mpq_class alpha = math::dot_with_buffer(ac, n, dotbuf) / den;
1152 return a - alpha * ab;
1153}
1154
1162static inline int tti_above(const mpq3 &a,
1163 const mpq3 &b,
1164 const mpq3 &c,
1165 const mpq3 &ad,
1166 mpq3 &ba,
1167 mpq3 &ca,
1168 mpq3 &n,
1169 mpq3 &dotbuf)
1170{
1171 ba = b;
1172 ba -= a;
1173 ca = c;
1174 ca -= a;
1175
1176 n.x = ba.y * ca.z - ba.z * ca.y;
1177 n.y = ba.z * ca.x - ba.x * ca.z;
1178 n.z = ba.x * ca.y - ba.y * ca.x;
1179
1180 return sgn(math::dot_with_buffer(ad, n, dotbuf));
1181}
1182
1196static ITT_value itt_canon2(const mpq3 &p1,
1197 const mpq3 &q1,
1198 const mpq3 &r1,
1199 const mpq3 &p2,
1200 const mpq3 &q2,
1201 const mpq3 &r2,
1202 const mpq3 &n1,
1203 const mpq3 &n2)
1204{
1205 constexpr int dbg_level = 0;
1206 if (dbg_level > 0) {
1207 std::cout << "\ntri_tri_intersect_canon:\n";
1208 std::cout << "p1=" << p1 << " q1=" << q1 << " r1=" << r1 << "\n";
1209 std::cout << "p2=" << p2 << " q2=" << q2 << " r2=" << r2 << "\n";
1210 std::cout << "n1=" << n1 << " n2=" << n2 << "\n";
1211 std::cout << "approximate values:\n";
1212 std::cout << "p1=(" << p1[0].get_d() << "," << p1[1].get_d() << "," << p1[2].get_d() << ")\n";
1213 std::cout << "q1=(" << q1[0].get_d() << "," << q1[1].get_d() << "," << q1[2].get_d() << ")\n";
1214 std::cout << "r1=(" << r1[0].get_d() << "," << r1[1].get_d() << "," << r1[2].get_d() << ")\n";
1215 std::cout << "p2=(" << p2[0].get_d() << "," << p2[1].get_d() << "," << p2[2].get_d() << ")\n";
1216 std::cout << "q2=(" << q2[0].get_d() << "," << q2[1].get_d() << "," << q2[2].get_d() << ")\n";
1217 std::cout << "r2=(" << r2[0].get_d() << "," << r2[1].get_d() << "," << r2[2].get_d() << ")\n";
1218 std::cout << "n1=(" << n1[0].get_d() << "," << n1[1].get_d() << "," << n1[2].get_d() << ")\n";
1219 std::cout << "n2=(" << n2[0].get_d() << "," << n2[1].get_d() << "," << n2[2].get_d() << ")\n";
1220 }
1221 mpq3 p1p2 = p2 - p1;
1222 mpq3 intersect_1;
1223 mpq3 intersect_2;
1224 mpq3 buf[4];
1225 bool no_overlap = false;
1226 /* Top test in classification tree. */
1227 if (tti_above(p1, q1, r2, p1p2, buf[0], buf[1], buf[2], buf[3]) > 0) {
1228 /* Middle right test in classification tree. */
1229 if (tti_above(p1, r1, r2, p1p2, buf[0], buf[1], buf[2], buf[3]) <= 0) {
1230 /* Bottom right test in classification tree. */
1231 if (tti_above(p1, r1, q2, p1p2, buf[0], buf[1], buf[2], buf[3]) > 0) {
1232 /* Overlap is [k [i l] j]. */
1233 if (dbg_level > 0) {
1234 std::cout << "overlap [k [i l] j]\n";
1235 }
1236 /* i is intersect with p1r1. l is intersect with p2r2. */
1237 intersect_1 = tti_interp(p1, r1, p2, n2, buf[0], buf[1], buf[2]);
1238 intersect_2 = tti_interp(p2, r2, p1, n1, buf[0], buf[1], buf[2]);
1239 }
1240 else {
1241 /* Overlap is [i [k l] j]. */
1242 if (dbg_level > 0) {
1243 std::cout << "overlap [i [k l] j]\n";
1244 }
1245 /* k is intersect with p2q2. l is intersect is p2r2. */
1246 intersect_1 = tti_interp(p2, q2, p1, n1, buf[0], buf[1], buf[2]);
1247 intersect_2 = tti_interp(p2, r2, p1, n1, buf[0], buf[1], buf[2]);
1248 }
1249 }
1250 else {
1251 /* No overlap: [k l] [i j]. */
1252 if (dbg_level > 0) {
1253 std::cout << "no overlap: [k l] [i j]\n";
1254 }
1255 no_overlap = true;
1256 }
1257 }
1258 else {
1259 /* Middle left test in classification tree. */
1260 if (tti_above(p1, q1, q2, p1p2, buf[0], buf[1], buf[2], buf[3]) < 0) {
1261 /* No overlap: [i j] [k l]. */
1262 if (dbg_level > 0) {
1263 std::cout << "no overlap: [i j] [k l]\n";
1264 }
1265 no_overlap = true;
1266 }
1267 else {
1268 /* Bottom left test in classification tree. */
1269 if (tti_above(p1, r1, q2, p1p2, buf[0], buf[1], buf[2], buf[3]) >= 0) {
1270 /* Overlap is [k [i j] l]. */
1271 if (dbg_level > 0) {
1272 std::cout << "overlap [k [i j] l]\n";
1273 }
1274 /* i is intersect with p1r1. j is intersect with p1q1. */
1275 intersect_1 = tti_interp(p1, r1, p2, n2, buf[0], buf[1], buf[2]);
1276 intersect_2 = tti_interp(p1, q1, p2, n2, buf[0], buf[1], buf[2]);
1277 }
1278 else {
1279 /* Overlap is [i [k j] l]. */
1280 if (dbg_level > 0) {
1281 std::cout << "overlap [i [k j] l]\n";
1282 }
1283 /* k is intersect with p2q2. j is intersect with p1q1. */
1284 intersect_1 = tti_interp(p2, q2, p1, n1, buf[0], buf[1], buf[2]);
1285 intersect_2 = tti_interp(p1, q1, p2, n2, buf[0], buf[1], buf[2]);
1286 }
1287 }
1288 }
1289 if (no_overlap) {
1290 return ITT_value(INONE);
1291 }
1292 if (intersect_1 == intersect_2) {
1293 if (dbg_level > 0) {
1294 std::cout << "single intersect: " << intersect_1 << "\n";
1295 }
1296 return ITT_value(IPOINT, intersect_1);
1297 }
1298 if (dbg_level > 0) {
1299 std::cout << "intersect segment: " << intersect_1 << ", " << intersect_2 << "\n";
1300 }
1301 return ITT_value(ISEGMENT, intersect_1, intersect_2);
1302}
1303
1304/* Helper function for intersect_tri_tri. Arguments have been canonicalized for triangle 1. */
1305
1306static ITT_value itt_canon1(const mpq3 &p1,
1307 const mpq3 &q1,
1308 const mpq3 &r1,
1309 const mpq3 &p2,
1310 const mpq3 &q2,
1311 const mpq3 &r2,
1312 const mpq3 &n1,
1313 const mpq3 &n2,
1314 int sp2,
1315 int sq2,
1316 int sr2)
1317{
1318 constexpr int dbg_level = 0;
1319 if (sp2 > 0) {
1320 if (sq2 > 0) {
1321 return itt_canon2(p1, r1, q1, r2, p2, q2, n1, n2);
1322 }
1323 if (sr2 > 0) {
1324 return itt_canon2(p1, r1, q1, q2, r2, p2, n1, n2);
1325 }
1326 return itt_canon2(p1, q1, r1, p2, q2, r2, n1, n2);
1327 }
1328 if (sp2 < 0) {
1329 if (sq2 < 0) {
1330 return itt_canon2(p1, q1, r1, r2, p2, q2, n1, n2);
1331 }
1332 if (sr2 < 0) {
1333 return itt_canon2(p1, q1, r1, q2, r2, p2, n1, n2);
1334 }
1335 return itt_canon2(p1, r1, q1, p2, q2, r2, n1, n2);
1336 }
1337 if (sq2 < 0) {
1338 if (sr2 >= 0) {
1339 return itt_canon2(p1, r1, q1, q2, r2, p2, n1, n2);
1340 }
1341 return itt_canon2(p1, q1, r1, p2, q2, r2, n1, n2);
1342 }
1343 if (sq2 > 0) {
1344 if (sr2 > 0) {
1345 return itt_canon2(p1, r1, q1, p2, q2, r2, n1, n2);
1346 }
1347 return itt_canon2(p1, q1, r1, q2, r2, p2, n1, n2);
1348 }
1349 if (sr2 > 0) {
1350 return itt_canon2(p1, q1, r1, r2, p2, q2, n1, n2);
1351 }
1352 if (sr2 < 0) {
1353 return itt_canon2(p1, r1, q1, r2, p2, q2, n1, n2);
1354 }
1355 if (dbg_level > 0) {
1356 std::cout << "triangles are co-planar\n";
1357 }
1358 return ITT_value(ICOPLANAR);
1359}
1360
1361static ITT_value intersect_tri_tri(const IMesh &tm, int t1, int t2)
1362{
1363 constexpr int dbg_level = 0;
1364# ifdef PERFDEBUG
1365 incperfcount(1); /* Intersect_tri_tri calls. */
1366# endif
1367 const Face &tri1 = *tm.face(t1);
1368 const Face &tri2 = *tm.face(t2);
1369 BLI_assert(tri1.plane_populated() && tri2.plane_populated());
1370 const Vert *vp1 = tri1[0];
1371 const Vert *vq1 = tri1[1];
1372 const Vert *vr1 = tri1[2];
1373 const Vert *vp2 = tri2[0];
1374 const Vert *vq2 = tri2[1];
1375 const Vert *vr2 = tri2[2];
1376 if (dbg_level > 0) {
1377 std::cout << "\nINTERSECT_TRI_TRI t1=" << t1 << ", t2=" << t2 << "\n";
1378 std::cout << " p1 = " << vp1 << "\n";
1379 std::cout << " q1 = " << vq1 << "\n";
1380 std::cout << " r1 = " << vr1 << "\n";
1381 std::cout << " p2 = " << vp2 << "\n";
1382 std::cout << " q2 = " << vq2 << "\n";
1383 std::cout << " r2 = " << vr2 << "\n";
1384 }
1385
1386 /* Get signs of t1's vertices' distances to plane of t2 and vice versa. */
1387
1388 /* Try first getting signs with double arithmetic, with error bounds.
1389 * If the signs calculated in this section are not 0, they are the same
1390 * as what they would be using exact arithmetic. */
1391 const double3 &d_p1 = vp1->co;
1392 const double3 &d_q1 = vq1->co;
1393 const double3 &d_r1 = vr1->co;
1394 const double3 &d_p2 = vp2->co;
1395 const double3 &d_q2 = vq2->co;
1396 const double3 &d_r2 = vr2->co;
1397 const double3 &d_n2 = tri2.plane->norm;
1398
1399 const double3 &abs_d_p1 = math::abs(d_p1);
1400 const double3 &abs_d_q1 = math::abs(d_q1);
1401 const double3 &abs_d_r1 = math::abs(d_r1);
1402 const double3 &abs_d_r2 = math::abs(d_r2);
1403 const double3 &abs_d_n2 = math::abs(d_n2);
1404
1405 int sp1 = filter_plane_side(d_p1, d_r2, d_n2, abs_d_p1, abs_d_r2, abs_d_n2);
1406 int sq1 = filter_plane_side(d_q1, d_r2, d_n2, abs_d_q1, abs_d_r2, abs_d_n2);
1407 int sr1 = filter_plane_side(d_r1, d_r2, d_n2, abs_d_r1, abs_d_r2, abs_d_n2);
1408 if ((sp1 > 0 && sq1 > 0 && sr1 > 0) || (sp1 < 0 && sq1 < 0 && sr1 < 0)) {
1409# ifdef PERFDEBUG
1410 incperfcount(2); /* Triangle-triangle intersects decided by filter plane tests. */
1411# endif
1412 if (dbg_level > 0) {
1413 std::cout << "no intersection, all t1's verts above or below t2\n";
1414 }
1415 return ITT_value(INONE);
1416 }
1417
1418 const double3 &d_n1 = tri1.plane->norm;
1419 const double3 &abs_d_p2 = math::abs(d_p2);
1420 const double3 &abs_d_q2 = math::abs(d_q2);
1421 const double3 &abs_d_n1 = math::abs(d_n1);
1422
1423 int sp2 = filter_plane_side(d_p2, d_r1, d_n1, abs_d_p2, abs_d_r1, abs_d_n1);
1424 int sq2 = filter_plane_side(d_q2, d_r1, d_n1, abs_d_q2, abs_d_r1, abs_d_n1);
1425 int sr2 = filter_plane_side(d_r2, d_r1, d_n1, abs_d_r2, abs_d_r1, abs_d_n1);
1426 if ((sp2 > 0 && sq2 > 0 && sr2 > 0) || (sp2 < 0 && sq2 < 0 && sr2 < 0)) {
1427# ifdef PERFDEBUG
1428 incperfcount(2); /* Triangle-triangle intersects decided by filter plane tests. */
1429# endif
1430 if (dbg_level > 0) {
1431 std::cout << "no intersection, all t2's verts above or below t1\n";
1432 }
1433 return ITT_value(INONE);
1434 }
1435
1436 mpq3 buf[2];
1437 const mpq3 &p1 = vp1->co_exact;
1438 const mpq3 &q1 = vq1->co_exact;
1439 const mpq3 &r1 = vr1->co_exact;
1440 const mpq3 &p2 = vp2->co_exact;
1441 const mpq3 &q2 = vq2->co_exact;
1442 const mpq3 &r2 = vr2->co_exact;
1443
1444 const mpq3 &n2 = tri2.plane->norm_exact;
1445 if (sp1 == 0) {
1446 buf[0] = p1;
1447 buf[0] -= r2;
1448 sp1 = sgn(math::dot_with_buffer(buf[0], n2, buf[1]));
1449 }
1450 if (sq1 == 0) {
1451 buf[0] = q1;
1452 buf[0] -= r2;
1453 sq1 = sgn(math::dot_with_buffer(buf[0], n2, buf[1]));
1454 }
1455 if (sr1 == 0) {
1456 buf[0] = r1;
1457 buf[0] -= r2;
1458 sr1 = sgn(math::dot_with_buffer(buf[0], n2, buf[1]));
1459 }
1460
1461 if (dbg_level > 1) {
1462 std::cout << " sp1=" << sp1 << " sq1=" << sq1 << " sr1=" << sr1 << "\n";
1463 }
1464
1465 if ((sp1 * sq1 > 0) && (sp1 * sr1 > 0)) {
1466 if (dbg_level > 0) {
1467 std::cout << "no intersection, all t1's verts above or below t2 (exact)\n";
1468 }
1469# ifdef PERFDEBUG
1470 incperfcount(3); /* Triangle-triangle intersects decided by exact plane tests. */
1471# endif
1472 return ITT_value(INONE);
1473 }
1474
1475 /* Repeat for signs of t2's vertices with respect to plane of t1. */
1476 const mpq3 &n1 = tri1.plane->norm_exact;
1477 if (sp2 == 0) {
1478 buf[0] = p2;
1479 buf[0] -= r1;
1480 sp2 = sgn(math::dot_with_buffer(buf[0], n1, buf[1]));
1481 }
1482 if (sq2 == 0) {
1483 buf[0] = q2;
1484 buf[0] -= r1;
1485 sq2 = sgn(math::dot_with_buffer(buf[0], n1, buf[1]));
1486 }
1487 if (sr2 == 0) {
1488 buf[0] = r2;
1489 buf[0] -= r1;
1490 sr2 = sgn(math::dot_with_buffer(buf[0], n1, buf[1]));
1491 }
1492
1493 if (dbg_level > 1) {
1494 std::cout << " sp2=" << sp2 << " sq2=" << sq2 << " sr2=" << sr2 << "\n";
1495 }
1496
1497 if ((sp2 * sq2 > 0) && (sp2 * sr2 > 0)) {
1498 if (dbg_level > 0) {
1499 std::cout << "no intersection, all t2's verts above or below t1 (exact)\n";
1500 }
1501# ifdef PERFDEBUG
1502 incperfcount(3); /* Triangle-triangle intersects decided by exact plane tests. */
1503# endif
1504 return ITT_value(INONE);
1505 }
1506
1507 /* Do rest of the work with vertices in a canonical order, where p1 is on
1508 * positive side of plane and q1, r1 are not, or p1 is on the plane and
1509 * q1 and r1 are off the plane on the same side. */
1510 ITT_value ans;
1511 if (sp1 > 0) {
1512 if (sq1 > 0) {
1513 ans = itt_canon1(r1, p1, q1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1514 }
1515 else if (sr1 > 0) {
1516 ans = itt_canon1(q1, r1, p1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1517 }
1518 else {
1519 ans = itt_canon1(p1, q1, r1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1520 }
1521 }
1522 else if (sp1 < 0) {
1523 if (sq1 < 0) {
1524 ans = itt_canon1(r1, p1, q1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1525 }
1526 else if (sr1 < 0) {
1527 ans = itt_canon1(q1, r1, p1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1528 }
1529 else {
1530 ans = itt_canon1(p1, q1, r1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1531 }
1532 }
1533 else {
1534 if (sq1 < 0) {
1535 if (sr1 >= 0) {
1536 ans = itt_canon1(q1, r1, p1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1537 }
1538 else {
1539 ans = itt_canon1(p1, q1, r1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1540 }
1541 }
1542 else if (sq1 > 0) {
1543 if (sr1 > 0) {
1544 ans = itt_canon1(p1, q1, r1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1545 }
1546 else {
1547 ans = itt_canon1(q1, r1, p1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1548 }
1549 }
1550 else {
1551 if (sr1 > 0) {
1552 ans = itt_canon1(r1, p1, q1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1553 }
1554 else if (sr1 < 0) {
1555 ans = itt_canon1(r1, p1, q1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1556 }
1557 else {
1558 if (dbg_level > 0) {
1559 std::cout << "triangles are co-planar\n";
1560 }
1561 ans = ITT_value(ICOPLANAR);
1562 }
1563 }
1564 }
1565 if (ans.kind == ICOPLANAR) {
1566 ans.t_source = t2;
1567 }
1568
1569# ifdef PERFDEBUG
1570 if (ans.kind != INONE) {
1571 incperfcount(4);
1572 }
1573# endif
1574 return ans;
1575}
1576
1577struct CDT_data {
1578 const Plane *t_plane;
1579 Vector<mpq2> vert;
1580 Vector<std::pair<int, int>> edge;
1581 Vector<Vector<int>> face;
1583 Vector<int> input_face;
1585 Vector<bool> is_reversed;
1587 CDT_result<mpq_class> cdt_out;
1591 Map<std::pair<int, int>, int> verts_to_edge;
1592 int proj_axis;
1593};
1594
1598static int prepare_need_vert(CDT_data &cd, const mpq3 &p3d)
1599{
1600 mpq2 p2d = project_3d_to_2d(p3d, cd.proj_axis);
1601 int v = cd.vert.append_and_get_index(p2d);
1602 return v;
1603}
1604
1612static mpq3 unproject_cdt_vert(const CDT_data &cd, const mpq2 &p2d)
1613{
1614 mpq3 p3d;
1615 BLI_assert(cd.t_plane->exact_populated());
1616 BLI_assert(cd.t_plane->norm_exact[cd.proj_axis] != 0);
1617 const mpq3 &n = cd.t_plane->norm_exact;
1618 const mpq_class &d = cd.t_plane->d_exact;
1619 switch (cd.proj_axis) {
1620 case (0): {
1621 mpq_class num = n[1] * p2d[0] + n[2] * p2d[1] + d;
1622 num = -num;
1623 p3d[0] = num / n[0];
1624 p3d[1] = p2d[0];
1625 p3d[2] = p2d[1];
1626 break;
1627 }
1628 case (1): {
1629 p3d[0] = p2d[0];
1630 mpq_class num = n[0] * p2d[0] + n[2] * p2d[1] + d;
1631 num = -num;
1632 p3d[1] = num / n[1];
1633 p3d[2] = p2d[1];
1634 break;
1635 }
1636 case (2): {
1637 p3d[0] = p2d[0];
1638 p3d[1] = p2d[1];
1639 mpq_class num = n[0] * p2d[0] + n[1] * p2d[1] + d;
1640 num = -num;
1641 p3d[2] = num / n[2];
1642 break;
1643 }
1644 default:
1645 BLI_assert(false);
1646 }
1647 return p3d;
1648}
1649
1650static void prepare_need_edge(CDT_data &cd, const mpq3 &p1, const mpq3 &p2)
1651{
1652 int v1 = prepare_need_vert(cd, p1);
1653 int v2 = prepare_need_vert(cd, p2);
1654 cd.edge.append(std::pair<int, int>(v1, v2));
1655}
1656
1657static void prepare_need_tri(CDT_data &cd, const IMesh &tm, int t)
1658{
1659 const Face &tri = *tm.face(t);
1660 int v0 = prepare_need_vert(cd, tri[0]->co_exact);
1661 int v1 = prepare_need_vert(cd, tri[1]->co_exact);
1662 int v2 = prepare_need_vert(cd, tri[2]->co_exact);
1663 bool rev;
1664 /* How to get CCW orientation of projected triangle? Note that when look down y axis
1665 * as opposed to x or z, the orientation of the other two axes is not right-and-up. */
1666 BLI_assert(cd.t_plane->exact_populated());
1667 if (tri.plane->norm_exact[cd.proj_axis] >= 0) {
1668 rev = cd.proj_axis == 1;
1669 }
1670 else {
1671 rev = cd.proj_axis != 1;
1672 }
1673 int cd_t = cd.face.append_and_get_index(Vector<int>());
1674 cd.face[cd_t].append(v0);
1675 if (rev) {
1676 cd.face[cd_t].append(v2);
1677 cd.face[cd_t].append(v1);
1678 }
1679 else {
1680 cd.face[cd_t].append(v1);
1681 cd.face[cd_t].append(v2);
1682 }
1683 cd.input_face.append(t);
1684 cd.is_reversed.append(rev);
1685}
1686
1687static CDT_data prepare_cdt_input(const IMesh &tm, int t, const Span<ITT_value> itts)
1688{
1689 CDT_data ans;
1690 BLI_assert(tm.face(t)->plane_populated());
1691 ans.t_plane = tm.face(t)->plane;
1692 BLI_assert(ans.t_plane->exact_populated());
1693 ans.proj_axis = math::dominant_axis(ans.t_plane->norm_exact);
1694 prepare_need_tri(ans, tm, t);
1695 for (const ITT_value &itt : itts) {
1696 switch (itt.kind) {
1697 case INONE:
1698 break;
1699 case IPOINT: {
1700 prepare_need_vert(ans, itt.p1);
1701 break;
1702 }
1703 case ISEGMENT: {
1704 prepare_need_edge(ans, itt.p1, itt.p2);
1705 break;
1706 }
1707 case ICOPLANAR: {
1708 prepare_need_tri(ans, tm, itt.t_source);
1709 break;
1710 }
1711 }
1712 }
1713 return ans;
1714}
1715
1716static CDT_data prepare_cdt_input_for_cluster(const IMesh &tm,
1717 const CoplanarClusterInfo &clinfo,
1718 int c,
1719 const Span<ITT_value> itts)
1720{
1721 CDT_data ans;
1722 BLI_assert(c < clinfo.tot_cluster());
1723 const CoplanarCluster &cl = clinfo.cluster(c);
1724 BLI_assert(cl.tot_tri() > 0);
1725 int t0 = cl.tri(0);
1726 BLI_assert(tm.face(t0)->plane_populated());
1727 ans.t_plane = tm.face(t0)->plane;
1728 BLI_assert(ans.t_plane->exact_populated());
1729 ans.proj_axis = math::dominant_axis(ans.t_plane->norm_exact);
1730 for (const int t : cl) {
1731 prepare_need_tri(ans, tm, t);
1732 }
1733 for (const ITT_value &itt : itts) {
1734 switch (itt.kind) {
1735 case IPOINT: {
1736 prepare_need_vert(ans, itt.p1);
1737 break;
1738 }
1739 case ISEGMENT: {
1740 prepare_need_edge(ans, itt.p1, itt.p2);
1741 break;
1742 }
1743 default:
1744 break;
1745 }
1746 }
1747 return ans;
1748}
1749
1750/* Return a copy of the argument with the integers ordered in ascending order. */
1751static inline std::pair<int, int> sorted_int_pair(std::pair<int, int> pair)
1752{
1753 if (pair.first <= pair.second) {
1754 return pair;
1755 }
1756 return std::pair<int, int>(pair.second, pair.first);
1757}
1758
1763static void populate_cdt_edge_map(Map<std::pair<int, int>, int> &verts_to_edge,
1764 const CDT_result<mpq_class> &cdt_out)
1765{
1766 verts_to_edge.reserve(cdt_out.edge.size());
1767 for (int e : cdt_out.edge.index_range()) {
1768 std::pair<int, int> vpair = sorted_int_pair(cdt_out.edge[e]);
1769 /* There should be only one edge for each vertex pair. */
1770 verts_to_edge.add(vpair, e);
1771 }
1772}
1773
1777static void do_cdt(CDT_data &cd)
1778{
1779 constexpr int dbg_level = 0;
1780 CDT_input<mpq_class> cdt_in;
1781 cdt_in.vert = Span<mpq2>(cd.vert);
1782 cdt_in.edge = Span<std::pair<int, int>>(cd.edge);
1783 cdt_in.face = Span<Vector<int>>(cd.face);
1784 if (dbg_level > 0) {
1785 std::cout << "CDT input\nVerts:\n";
1786 for (int i : cdt_in.vert.index_range()) {
1787 std::cout << "v" << i << ": " << cdt_in.vert[i] << "=(" << cdt_in.vert[i][0].get_d() << ","
1788 << cdt_in.vert[i][1].get_d() << ")\n";
1789 }
1790 std::cout << "Edges:\n";
1791 for (int i : cdt_in.edge.index_range()) {
1792 std::cout << "e" << i << ": (" << cdt_in.edge[i].first << ", " << cdt_in.edge[i].second
1793 << ")\n";
1794 }
1795 std::cout << "Tris\n";
1796 for (int f : cdt_in.face.index_range()) {
1797 std::cout << "f" << f << ": ";
1798 for (int j : cdt_in.face[f].index_range()) {
1799 std::cout << cdt_in.face[f][j] << " ";
1800 }
1801 std::cout << "\n";
1802 }
1803 }
1804 cdt_in.epsilon = 0; /* TODO: needs attention for non-exact T. */
1806 constexpr int make_edge_map_threshold = 15;
1807 if (cd.cdt_out.edge.size() >= make_edge_map_threshold) {
1808 populate_cdt_edge_map(cd.verts_to_edge, cd.cdt_out);
1809 }
1810 if (dbg_level > 0) {
1811 std::cout << "\nCDT result\nVerts:\n";
1812 for (int i : cd.cdt_out.vert.index_range()) {
1813 std::cout << "v" << i << ": " << cd.cdt_out.vert[i] << "=(" << cd.cdt_out.vert[i][0].get_d()
1814 << "," << cd.cdt_out.vert[i][1].get_d() << "\n";
1815 }
1816 std::cout << "Tris\n";
1817 for (int f : cd.cdt_out.face.index_range()) {
1818 std::cout << "f" << f << ": ";
1819 for (int j : cd.cdt_out.face[f].index_range()) {
1820 std::cout << cd.cdt_out.face[f][j] << " ";
1821 }
1822 std::cout << "orig: ";
1823 for (int j : cd.cdt_out.face_orig[f].index_range()) {
1824 std::cout << cd.cdt_out.face_orig[f][j] << " ";
1825 }
1826 std::cout << "\n";
1827 }
1828 std::cout << "Edges\n";
1829 for (int e : cd.cdt_out.edge.index_range()) {
1830 std::cout << "e" << e << ": (" << cd.cdt_out.edge[e].first << ", "
1831 << cd.cdt_out.edge[e].second << ") ";
1832 std::cout << "orig: ";
1833 for (int j : cd.cdt_out.edge_orig[e].index_range()) {
1834 std::cout << cd.cdt_out.edge_orig[e][j] << " ";
1835 }
1836 std::cout << "\n";
1837 }
1838 }
1839}
1840
1841/* Find an original edge index that goes with the edge that the CDT output edge
1842 * that goes between verts i0 and i1 (in the CDT output vert indexing scheme).
1843 * There may be more than one: if so, prefer one that was originally a face edge.
1844 * The input to CDT for a triangle with some intersecting segments from other triangles
1845 * will have both edges and a face constraint for the main triangle (this is redundant
1846 * but allows us to discover which face edge goes with which output edges).
1847 * If there is any face edge, return one of those as the original.
1848 * If there is no face edge but there is another edge in the input problem, then that
1849 * edge must have come from intersection with another triangle, so set *r_is_intersect
1850 * to true in that case. */
1851static int get_cdt_edge_orig(
1852 int i0, int i1, const CDT_data &cd, const IMesh &in_tm, bool *r_is_intersect)
1853{
1854 int foff = cd.cdt_out.face_edge_offset;
1855 *r_is_intersect = false;
1856 int e = NO_INDEX;
1857 if (cd.verts_to_edge.size() > 0) {
1858 /* Use the populated map to find the edge, if any, between vertices i0 and i1. */
1859 std::pair<int, int> vpair = sorted_int_pair(std::pair<int, int>(i0, i1));
1860 e = cd.verts_to_edge.lookup_default(vpair, NO_INDEX);
1861 }
1862 else {
1863 for (int ee : cd.cdt_out.edge.index_range()) {
1864 std::pair<int, int> edge = cd.cdt_out.edge[ee];
1865 if ((edge.first == i0 && edge.second == i1) || (edge.first == i1 && edge.second == i0)) {
1866 e = ee;
1867 break;
1868 }
1869 }
1870 }
1871 if (e == NO_INDEX) {
1872 return NO_INDEX;
1873 }
1874
1875 /* Pick an arbitrary orig, but not one equal to NO_INDEX, if we can help it. */
1876 /* TODO: if edge has origs from more than one part of the nary input,
1877 * then want to set *r_is_intersect to true. */
1878 int face_eorig = NO_INDEX;
1879 bool have_non_face_eorig = false;
1880 for (int orig_index : cd.cdt_out.edge_orig[e]) {
1881 /* orig_index encodes the triangle and pos within the triangle of the input edge. */
1882 if (orig_index >= foff) {
1883 if (face_eorig == NO_INDEX) {
1884 int in_face_index = (orig_index / foff) - 1;
1885 int pos = orig_index % foff;
1886 /* We need to retrieve the edge orig field from the Face used to populate the
1887 * in_face_index'th face of the CDT, at the pos'th position of the face. */
1888 int in_tm_face_index = cd.input_face[in_face_index];
1889 BLI_assert(in_tm_face_index < in_tm.face_size());
1890 const Face *facep = in_tm.face(in_tm_face_index);
1892 bool is_rev = cd.is_reversed[in_face_index];
1893 int eorig = is_rev ? facep->edge_orig[2 - pos] : facep->edge_orig[pos];
1894 if (eorig != NO_INDEX) {
1895 face_eorig = eorig;
1896 }
1897 }
1898 }
1899 else {
1900 if (!have_non_face_eorig) {
1901 have_non_face_eorig = true;
1902 }
1903 if (face_eorig != NO_INDEX && have_non_face_eorig) {
1904 /* Only need at most one orig for each type. */
1905 break;
1906 }
1907 }
1908 }
1909 if (face_eorig != NO_INDEX) {
1910 return face_eorig;
1911 }
1912 if (have_non_face_eorig) {
1913 /* This must have been an input to the CDT problem that was an intersection edge. */
1914 /* TODO: maybe there is an orig index:
1915 * This happens if an input edge was formed by an input face having
1916 * an edge that is co-planar with the cluster, while the face as a whole is not. */
1917 *r_is_intersect = true;
1918 return NO_INDEX;
1919 }
1920 return NO_INDEX;
1921}
1922
1928static Face *cdt_tri_as_imesh_face(
1929 int cdt_out_t, int cdt_in_t, const CDT_data &cd, const IMesh &tm, IMeshArena *arena)
1930{
1931 const CDT_result<mpq_class> &cdt_out = cd.cdt_out;
1932 int t_orig = tm.face(cd.input_face[cdt_in_t])->orig;
1933 BLI_assert(cdt_out.face[cdt_out_t].size() == 3);
1934 int i0 = cdt_out.face[cdt_out_t][0];
1935 int i1 = cdt_out.face[cdt_out_t][1];
1936 int i2 = cdt_out.face[cdt_out_t][2];
1937 mpq3 v0co = unproject_cdt_vert(cd, cdt_out.vert[i0]);
1938 mpq3 v1co = unproject_cdt_vert(cd, cdt_out.vert[i1]);
1939 mpq3 v2co = unproject_cdt_vert(cd, cdt_out.vert[i2]);
1940 /* No need to provide an original index: if coord matches
1941 * an original one, then it will already be in the arena
1942 * with the correct orig field. */
1943 const Vert *v0 = arena->add_or_find_vert(v0co, NO_INDEX);
1944 const Vert *v1 = arena->add_or_find_vert(v1co, NO_INDEX);
1945 const Vert *v2 = arena->add_or_find_vert(v2co, NO_INDEX);
1946 Face *facep;
1947 bool is_isect0;
1948 bool is_isect1;
1949 bool is_isect2;
1950 if (cd.is_reversed[cdt_in_t]) {
1951 int oe0 = get_cdt_edge_orig(i0, i2, cd, tm, &is_isect0);
1952 int oe1 = get_cdt_edge_orig(i2, i1, cd, tm, &is_isect1);
1953 int oe2 = get_cdt_edge_orig(i1, i0, cd, tm, &is_isect2);
1954 facep = arena->add_face(
1955 {v0, v2, v1}, t_orig, {oe0, oe1, oe2}, {is_isect0, is_isect1, is_isect2});
1956 }
1957 else {
1958 int oe0 = get_cdt_edge_orig(i0, i1, cd, tm, &is_isect0);
1959 int oe1 = get_cdt_edge_orig(i1, i2, cd, tm, &is_isect1);
1960 int oe2 = get_cdt_edge_orig(i2, i0, cd, tm, &is_isect2);
1961 facep = arena->add_face(
1962 {v0, v1, v2}, t_orig, {oe0, oe1, oe2}, {is_isect0, is_isect1, is_isect2});
1963 }
1964 facep->populate_plane(false);
1965 return facep;
1966}
1967
1968/* Like BLI_math's is_quad_flip_v3_first_third_fast, with const double3's. */
1969static bool is_quad_flip_first_third(const double3 &v1,
1970 const double3 &v2,
1971 const double3 &v3,
1972 const double3 &v4)
1973{
1974 const double3 d_12 = v2 - v1;
1975 const double3 d_13 = v3 - v1;
1976 const double3 d_14 = v4 - v1;
1977
1978 const double3 cross_a = math::cross(d_12, d_13);
1979 const double3 cross_b = math::cross(d_14, d_13);
1980 return math::dot(cross_a, cross_b) > 0.0f;
1981}
1982
1995static Array<Face *> polyfill_triangulate_poly(Face *f, IMeshArena *arena)
1996{
1997 /* Similar to loop body in #BM_mesh_calc_tessellation. */
1998 int flen = f->size();
1999 BLI_assert(flen >= 4);
2000 if (!f->plane_populated()) {
2001 f->populate_plane(false);
2002 }
2003 const double3 &poly_normal = f->plane->norm;
2004 float no[3] = {float(poly_normal[0]), float(poly_normal[1]), float(poly_normal[2])};
2005 normalize_v3(no);
2006 if (flen == 4) {
2007 const Vert *v0 = (*f)[0];
2008 const Vert *v1 = (*f)[1];
2009 const Vert *v2 = (*f)[2];
2010 const Vert *v3 = (*f)[3];
2011 int eo_01 = f->edge_orig[0];
2012 int eo_12 = f->edge_orig[1];
2013 int eo_23 = f->edge_orig[2];
2014 int eo_30 = f->edge_orig[3];
2015 Face *f0, *f1;
2016 if (UNLIKELY(is_quad_flip_first_third(v0->co, v1->co, v2->co, v3->co))) {
2017 f0 = arena->add_face({v0, v1, v3}, f->orig, {eo_01, -1, eo_30}, {false, false, false});
2018 f1 = arena->add_face({v1, v2, v3}, f->orig, {eo_12, eo_23, -1}, {false, false, false});
2019 }
2020 else {
2021 f0 = arena->add_face({v0, v1, v2}, f->orig, {eo_01, eo_12, -1}, {false, false, false});
2022 f1 = arena->add_face({v0, v2, v3}, f->orig, {-1, eo_23, eo_30}, {false, false, false});
2023 }
2024 return Array<Face *>{f0, f1};
2025 }
2026 /* Project along negative face normal so (x,y) can be used in 2d. */
2027 float axis_mat[3][3];
2028 float(*projverts)[2];
2029 uint(*tris)[3];
2030 const int totfilltri = flen - 2;
2031 /* Prepare projected vertices and array to receive triangles in tessellation. */
2032 tris = static_cast<uint(*)[3]>(MEM_malloc_arrayN(totfilltri, sizeof(*tris), __func__));
2033 projverts = static_cast<float(*)[2]>(MEM_malloc_arrayN(flen, sizeof(*projverts), __func__));
2034 axis_dominant_v3_to_m3_negate(axis_mat, no);
2035 for (int j = 0; j < flen; ++j) {
2036 const double3 &dco = (*f)[j]->co;
2037 float co[3] = {float(dco[0]), float(dco[1]), float(dco[2])};
2038 mul_v2_m3v3(projverts[j], axis_mat, co);
2039 }
2040 BLI_polyfill_calc(projverts, flen, 1, tris);
2041 /* Put tessellation triangles into Face form. Record original edges where they exist. */
2042 Array<Face *> ans(totfilltri);
2043 for (int t = 0; t < totfilltri; ++t) {
2044 uint *tri = tris[t];
2045 int eo[3];
2046 const Vert *v[3];
2047 for (int k = 0; k < 3; k++) {
2048 BLI_assert(tri[k] < flen);
2049 v[k] = (*f)[tri[k]];
2050 /* If tri edge goes between two successive indices in
2051 * the original face, then it is an original edge. */
2052 if ((tri[k] + 1) % flen == tri[(k + 1) % 3]) {
2053 eo[k] = f->edge_orig[tri[k]];
2054 }
2055 else {
2056 eo[k] = NO_INDEX;
2057 }
2058 ans[t] = arena->add_face(
2059 {v[0], v[1], v[2]}, f->orig, {eo[0], eo[1], eo[2]}, {false, false, false});
2060 }
2061 }
2062
2063 MEM_freeN(tris);
2064 MEM_freeN(projverts);
2065
2066 return ans;
2067}
2068
2084static Array<Face *> exact_triangulate_poly(Face *f, IMeshArena *arena)
2085{
2086 int flen = f->size();
2087 Array<mpq2> in_verts(flen);
2088 Array<Vector<int>> faces(1);
2089 faces.first().resize(flen);
2090 std::iota(faces.first().begin(), faces.first().end(), 0);
2091
2092 /* Project poly along dominant axis of normal to get 2d coords. */
2093 if (!f->plane_populated()) {
2094 f->populate_plane(false);
2095 }
2096 const double3 &poly_normal = f->plane->norm;
2097 int axis = math::dominant_axis(poly_normal);
2098 /* If project down y axis as opposed to x or z, the orientation
2099 * of the face will be reversed.
2100 * Yet another reversal happens if the poly normal in the dominant
2101 * direction is opposite that of the positive dominant axis. */
2102 bool rev1 = (axis == 1);
2103 bool rev2 = poly_normal[axis] < 0;
2104 bool rev = rev1 ^ rev2;
2105 for (int i = 0; i < flen; ++i) {
2106 int ii = rev ? flen - i - 1 : i;
2107 mpq2 &p2d = in_verts[ii];
2108 int k = 0;
2109 for (int j = 0; j < 3; ++j) {
2110 if (j != axis) {
2111 p2d[k++] = (*f)[ii]->co_exact[j];
2112 }
2113 }
2114 }
2115
2116 CDT_input<mpq_class> cdt_in;
2117 cdt_in.vert = std::move(in_verts);
2118 cdt_in.face = std::move(faces);
2119
2120 CDT_result<mpq_class> cdt_out = delaunay_2d_calc(cdt_in, CDT_INSIDE);
2121 int n_tris = cdt_out.face.size();
2122 Array<Face *> ans(n_tris);
2123 for (int t = 0; t < n_tris; ++t) {
2124 int i_v_out[3];
2125 const Vert *v[3];
2126 int eo[3];
2127 bool needs_steiner = false;
2128 for (int i = 0; i < 3; ++i) {
2129 i_v_out[i] = cdt_out.face[t][i];
2130 if (cdt_out.vert_orig[i_v_out[i]].is_empty()) {
2131 needs_steiner = true;
2132 break;
2133 }
2134 v[i] = (*f)[cdt_out.vert_orig[i_v_out[i]][0]];
2135 }
2136 if (needs_steiner) {
2137 /* Fall back on the polyfill triangulator. */
2138 return polyfill_triangulate_poly(f, arena);
2139 }
2140 Map<std::pair<int, int>, int> verts_to_edge;
2141 populate_cdt_edge_map(verts_to_edge, cdt_out);
2142 int foff = cdt_out.face_edge_offset;
2143 for (int i = 0; i < 3; ++i) {
2144 std::pair<int, int> vpair(i_v_out[i], i_v_out[(i + 1) % 3]);
2145 std::pair<int, int> vpair_canon = sorted_int_pair(vpair);
2146 int e_out = verts_to_edge.lookup_default(vpair_canon, NO_INDEX);
2147 BLI_assert(e_out != NO_INDEX);
2148 eo[i] = NO_INDEX;
2149 for (int orig : cdt_out.edge_orig[e_out]) {
2150 if (orig >= foff) {
2151 int pos = orig % foff;
2153 eo[i] = f->edge_orig[pos];
2154 break;
2155 }
2156 }
2157 }
2158 if (rev) {
2159 ans[t] = arena->add_face(
2160 {v[0], v[2], v[1]}, f->orig, {eo[2], eo[1], eo[0]}, {false, false, false});
2161 }
2162 else {
2163 ans[t] = arena->add_face(
2164 {v[0], v[1], v[2]}, f->orig, {eo[0], eo[1], eo[2]}, {false, false, false});
2165 }
2166 }
2167 return ans;
2168}
2169
2170static bool face_is_degenerate(const Face *f)
2171{
2172 const Face &face = *f;
2173 const Vert *v0 = face[0];
2174 const Vert *v1 = face[1];
2175 const Vert *v2 = face[2];
2176 if (v0 == v1 || v0 == v2 || v1 == v2) {
2177 return true;
2178 }
2179 double3 da = v2->co - v0->co;
2180 double3 db = v2->co - v1->co;
2181 double3 dab = math::cross(da, db);
2182 double dab_length_squared = math::length_squared(dab);
2183 double err_bound = supremum_dot_cross(dab, dab) * index_dot_cross * DBL_EPSILON;
2184 if (dab_length_squared > err_bound) {
2185 return false;
2186 }
2187 mpq3 a = v2->co_exact - v0->co_exact;
2188 mpq3 b = v2->co_exact - v1->co_exact;
2189 mpq3 ab = math::cross(a, b);
2190 if (ab.x == 0 && ab.y == 0 && ab.z == 0) {
2191 return true;
2192 }
2193
2194 return false;
2195}
2196
2198static bool any_degenerate_tris_fast(const Array<Face *> triangulation)
2199{
2200 for (const Face *f : triangulation) {
2201 const Vert *v0 = (*f)[0];
2202 const Vert *v1 = (*f)[1];
2203 const Vert *v2 = (*f)[2];
2204 if (v0 == v1 || v0 == v2 || v1 == v2) {
2205 return true;
2206 }
2207 double3 da = v2->co - v0->co;
2208 double3 db = v2->co - v1->co;
2209 double da_length_squared = math::length_squared(da);
2210 double db_length_squared = math::length_squared(db);
2211 if (da_length_squared == 0.0 || db_length_squared == 0.0) {
2212 return true;
2213 }
2214 /* |da x db| = |da| |db| sin t, where t is angle between them.
2215 * The triangle is almost degenerate if sin t is almost 0.
2216 * sin^2 t = |da x db|^2 / (|da|^2 |db|^2)
2217 */
2218 double3 dab = math::cross(da, db);
2219 double dab_length_squared = math::length_squared(dab);
2220 double sin_squared_t = dab_length_squared / (da_length_squared * db_length_squared);
2221 if (sin_squared_t < 1e-8) {
2222 return true;
2223 }
2224 }
2225 return false;
2226}
2227
2236static Array<Face *> triangulate_poly(Face *f, IMeshArena *arena)
2237{
2238 /* Try the much faster method using Blender's BLI_polyfill_calc. */
2239 Array<Face *> ans = polyfill_triangulate_poly(f, arena);
2240
2241 /* This may create degenerate triangles. If so, try the exact CDT-based triangulator. */
2242 if (any_degenerate_tris_fast(ans)) {
2243 return exact_triangulate_poly(f, arena);
2244 }
2245 return ans;
2246}
2247
2248IMesh triangulate_polymesh(IMesh &imesh, IMeshArena *arena)
2249{
2250 Vector<Face *> face_tris;
2251 constexpr int estimated_tris_per_face = 3;
2252 face_tris.reserve(estimated_tris_per_face * imesh.face_size());
2253 threading::parallel_for(imesh.face_index_range(), 2048, [&](IndexRange range) {
2254 for (int i : range) {
2255 Face *f = imesh.face(i);
2256 if (!f->plane_populated() && f->size() >= 4) {
2257 f->populate_plane(false);
2258 }
2259 }
2260 });
2261 for (Face *f : imesh.faces()) {
2262 /* Tessellate face f, following plan similar to #BM_face_calc_tessellation. */
2263 int flen = f->size();
2264 if (flen == 3) {
2265 face_tris.append(f);
2266 }
2267 else {
2268 Array<Face *> tris = triangulate_poly(f, arena);
2269 for (Face *tri : tris) {
2270 face_tris.append(tri);
2271 }
2272 }
2273 }
2274 return IMesh(face_tris);
2275}
2276
2281static IMesh extract_subdivided_tri(const CDT_data &cd,
2282 const IMesh &in_tm,
2283 int t,
2284 IMeshArena *arena)
2285{
2286 const CDT_result<mpq_class> &cdt_out = cd.cdt_out;
2287 int t_in_cdt = -1;
2288 for (int i = 0; i < cd.input_face.size(); ++i) {
2289 if (cd.input_face[i] == t) {
2290 t_in_cdt = i;
2291 }
2292 }
2293 if (t_in_cdt == -1) {
2294 std::cout << "Could not find " << t << " in cdt input tris\n";
2295 BLI_assert(false);
2296 return IMesh();
2297 }
2298 constexpr int inline_buf_size = 20;
2299 Vector<Face *, inline_buf_size> faces;
2300 for (int f : cdt_out.face.index_range()) {
2301 if (cdt_out.face_orig[f].contains(t_in_cdt)) {
2302 Face *facep = cdt_tri_as_imesh_face(f, t_in_cdt, cd, in_tm, arena);
2303 faces.append(facep);
2304 }
2305 }
2306 return IMesh(faces);
2307}
2308
2309static bool bvhtreeverlap_cmp(const BVHTreeOverlap &a, const BVHTreeOverlap &b)
2310{
2311 if (a.indexA < b.indexA) {
2312 return true;
2313 }
2314 if ((a.indexA == b.indexA) && (a.indexB < b.indexB)) {
2315 return true;
2316 }
2317 return false;
2318}
2319class TriOverlaps {
2320 BVHTree *tree_{nullptr};
2321 BVHTree *tree_b_{nullptr};
2322 BVHTreeOverlap *overlap_{nullptr};
2323 Array<int> first_overlap_;
2324 uint overlap_num_{0};
2325
2326 struct CBData {
2327 const IMesh &tm;
2328 std::function<int(int)> shape_fn;
2329 int nshapes;
2330 bool use_self;
2331 };
2332
2333 public:
2334 TriOverlaps(const IMesh &tm,
2335 const Span<BoundingBox> tri_bb,
2336 int nshapes,
2337 std::function<int(int)> shape_fn,
2338 bool use_self)
2339 {
2340 constexpr int dbg_level = 0;
2341 if (dbg_level > 0) {
2342 std::cout << "TriOverlaps construction\n";
2343 }
2344 /* Tree type is 8 => octree; axis = 6 => using XYZ axes only. */
2345 tree_ = BLI_bvhtree_new(tm.face_size(), FLT_EPSILON, 8, 6);
2346 /* In the common case of a binary boolean and no self intersection in
2347 * each shape, we will use two trees and simple bounding box overlap. */
2348 bool two_trees_no_self = nshapes == 2 && !use_self;
2349 if (two_trees_no_self) {
2350 tree_b_ = BLI_bvhtree_new(tm.face_size(), FLT_EPSILON, 8, 6);
2351 }
2352
2353 /* Create a Vector containing face shape. */
2354 Vector<int> shapes;
2355 shapes.resize(tm.face_size());
2356 threading::parallel_for(tm.face_index_range(), 2048, [&](IndexRange range) {
2357 for (int t : range) {
2358 shapes[t] = shape_fn(tm.face(t)->orig);
2359 }
2360 });
2361
2362 float bbpts[6];
2363 for (int t : tm.face_index_range()) {
2364 const BoundingBox &bb = tri_bb[t];
2365 copy_v3_v3(bbpts, bb.min);
2366 copy_v3_v3(bbpts + 3, bb.max);
2367 int shape = shapes[t];
2368 if (two_trees_no_self) {
2369 if (shape == 0) {
2370 BLI_bvhtree_insert(tree_, t, bbpts, 2);
2371 }
2372 else if (shape == 1) {
2373 BLI_bvhtree_insert(tree_b_, t, bbpts, 2);
2374 }
2375 }
2376 else {
2377 if (shape != -1) {
2378 BLI_bvhtree_insert(tree_, t, bbpts, 2);
2379 }
2380 }
2381 }
2382 BLI_bvhtree_balance(tree_);
2383 if (two_trees_no_self) {
2384 BLI_bvhtree_balance(tree_b_);
2385 /* Don't expect a lot of trivial intersects in this case. */
2386 overlap_ = BLI_bvhtree_overlap(tree_, tree_b_, &overlap_num_, nullptr, nullptr);
2387 }
2388 else {
2389 CBData cbdata{tm, shape_fn, nshapes, use_self};
2390 if (nshapes == 1) {
2391 overlap_ = BLI_bvhtree_overlap(tree_, tree_, &overlap_num_, nullptr, nullptr);
2392 }
2393 else {
2394 overlap_ = BLI_bvhtree_overlap(
2395 tree_, tree_, &overlap_num_, only_different_shapes, &cbdata);
2396 }
2397 }
2398 /* The rest of the code is simpler and easier to parallelize if, in the two-trees case,
2399 * we repeat the overlaps with indexA and indexB reversed. It is important that
2400 * in the repeated part, sorting will then bring things with indexB together. */
2401 if (two_trees_no_self) {
2402 overlap_ = static_cast<BVHTreeOverlap *>(
2403 MEM_reallocN(overlap_, 2 * overlap_num_ * sizeof(overlap_[0])));
2404 for (uint i = 0; i < overlap_num_; ++i) {
2405 overlap_[overlap_num_ + i].indexA = overlap_[i].indexB;
2406 overlap_[overlap_num_ + i].indexB = overlap_[i].indexA;
2407 }
2408 overlap_num_ += overlap_num_;
2409 }
2410 /* Sort the overlaps to bring all the intersects with a given indexA together. */
2411 std::sort(overlap_, overlap_ + overlap_num_, bvhtreeverlap_cmp);
2412 if (dbg_level > 0) {
2413 std::cout << overlap_num_ << " overlaps found:\n";
2414 for (BVHTreeOverlap ov : overlap()) {
2415 std::cout << "A: " << ov.indexA << ", B: " << ov.indexB << "\n";
2416 }
2417 }
2418 first_overlap_ = Array<int>(tm.face_size(), -1);
2419 for (int i = 0; i < int(overlap_num_); ++i) {
2420 int t = overlap_[i].indexA;
2421 if (first_overlap_[t] == -1) {
2422 first_overlap_[t] = i;
2423 }
2424 }
2425 }
2426
2427 ~TriOverlaps()
2428 {
2429 if (tree_) {
2430 BLI_bvhtree_free(tree_);
2431 }
2432 if (tree_b_) {
2433 BLI_bvhtree_free(tree_b_);
2434 }
2435 if (overlap_) {
2436 MEM_freeN(overlap_);
2437 }
2438 }
2439
2440 Span<BVHTreeOverlap> overlap() const
2441 {
2442 return Span<BVHTreeOverlap>(overlap_, overlap_num_);
2443 }
2444
2445 int first_overlap_index(int t) const
2446 {
2447 return first_overlap_[t];
2448 }
2449
2450 private:
2451 static bool only_different_shapes(void *userdata, int index_a, int index_b, int /*thread*/)
2452 {
2453 CBData *cbdata = static_cast<CBData *>(userdata);
2454 return cbdata->tm.face(index_a)->orig != cbdata->tm.face(index_b)->orig;
2455 }
2456};
2457
2461struct OverlapIttsData {
2462 Vector<std::pair<int, int>> intersect_pairs;
2463 Map<std::pair<int, int>, ITT_value> &itt_map;
2464 const IMesh &tm;
2465 IMeshArena *arena;
2466
2467 OverlapIttsData(Map<std::pair<int, int>, ITT_value> &itt_map, const IMesh &tm, IMeshArena *arena)
2468 : itt_map(itt_map), tm(tm), arena(arena)
2469 {
2470 }
2471};
2472
2477static std::pair<int, int> canon_int_pair(int a, int b)
2478{
2479 if (a > b) {
2480 std::swap(a, b);
2481 }
2482 return std::pair<int, int>(a, b);
2483}
2484
2485static void calc_overlap_itts_range_func(void *__restrict userdata,
2486 const int iter,
2487 const TaskParallelTLS *__restrict /*tls*/)
2488{
2489 constexpr int dbg_level = 0;
2490 OverlapIttsData *data = static_cast<OverlapIttsData *>(userdata);
2491 std::pair<int, int> tri_pair = data->intersect_pairs[iter];
2492 int a = tri_pair.first;
2493 int b = tri_pair.second;
2494 if (dbg_level > 0) {
2495 std::cout << "calc_overlap_itts_range_func a=" << a << ", b=" << b << "\n";
2496 }
2497 ITT_value itt = intersect_tri_tri(data->tm, a, b);
2498 if (dbg_level > 0) {
2499 std::cout << "result of intersecting " << a << " and " << b << " = " << itt << "\n";
2500 }
2501 BLI_assert(data->itt_map.contains(tri_pair));
2502 data->itt_map.add_overwrite(tri_pair, itt);
2503}
2504
2509static void calc_overlap_itts(Map<std::pair<int, int>, ITT_value> &itt_map,
2510 const IMesh &tm,
2511 const TriOverlaps &ov,
2512 IMeshArena *arena)
2513{
2514 OverlapIttsData data(itt_map, tm, arena);
2515 /* Put dummy values in `itt_map` initially,
2516 * so map entries will exist when doing the range function.
2517 * This means we won't have to protect the `itt_map.add_overwrite` function with a lock. */
2518 for (const BVHTreeOverlap &olap : ov.overlap()) {
2519 std::pair<int, int> key = canon_int_pair(olap.indexA, olap.indexB);
2520 if (!itt_map.contains(key)) {
2521 itt_map.add_new(key, ITT_value());
2522 data.intersect_pairs.append(key);
2523 }
2524 }
2525 int tot_intersect_pairs = data.intersect_pairs.size();
2526 TaskParallelSettings settings;
2528 settings.min_iter_per_thread = 1000;
2529 settings.use_threading = intersect_use_threading;
2530 BLI_task_parallel_range(0, tot_intersect_pairs, &data, calc_overlap_itts_range_func, &settings);
2531}
2532
2539static void calc_subdivided_non_cluster_tris(Array<IMesh> &r_tri_subdivided,
2540 const IMesh &tm,
2541 const Map<std::pair<int, int>, ITT_value> &itt_map,
2542 const CoplanarClusterInfo &clinfo,
2543 const TriOverlaps &ov,
2544 IMeshArena *arena)
2545{
2546 const int dbg_level = 0;
2547 if (dbg_level > 0) {
2548 std::cout << "\nCALC_SUBDIVIDED_TRIS\n\n";
2549 }
2550 Span<BVHTreeOverlap> overlap = ov.overlap();
2551 struct OverlapTriRange {
2552 int tri_index;
2553 int overlap_start;
2554 int len;
2555 };
2556 Vector<OverlapTriRange> overlap_tri_range;
2557 int overlap_num = overlap.size();
2558 overlap_tri_range.reserve(overlap_num);
2559 int overlap_index = 0;
2560 while (overlap_index < overlap_num) {
2561 int t = overlap[overlap_index].indexA;
2562 int i = overlap_index;
2563 while (i + 1 < overlap_num && overlap[i + 1].indexA == t) {
2564 ++i;
2565 }
2566 /* Now overlap[overlap_index] to overlap[i] have indexA == t.
2567 * We only record ranges for triangles that are not in clusters,
2568 * because the ones in clusters are handled separately. */
2569 if (clinfo.tri_cluster(t) == NO_INDEX) {
2570 int len = i - overlap_index + 1;
2571 if (!(len == 1 && overlap[overlap_index].indexB == t)) {
2572 OverlapTriRange range = {t, overlap_index, len};
2573 overlap_tri_range.append(range);
2574# ifdef PERFDEBUG
2575 bumpperfcount(0, len); /* Non-cluster overlaps. */
2576# endif
2577 }
2578 }
2579 overlap_index = i + 1;
2580 }
2581 int overlap_tri_range_num = overlap_tri_range.size();
2582 Array<CDT_data> cd_data(overlap_tri_range_num);
2583 int grain_size = 64;
2584 threading::parallel_for(overlap_tri_range.index_range(), grain_size, [&](IndexRange range) {
2585 for (int otr_index : range) {
2586 OverlapTriRange &otr = overlap_tri_range[otr_index];
2587 int t = otr.tri_index;
2588 if (dbg_level > 0) {
2589 std::cout << "handling overlap range\nt=" << t << " start=" << otr.overlap_start
2590 << " len=" << otr.len << "\n";
2591 }
2592 constexpr int inline_capacity = 100;
2593 Vector<ITT_value, inline_capacity> itts(otr.len);
2594 for (int j = otr.overlap_start; j < otr.overlap_start + otr.len; ++j) {
2595 int t_other = overlap[j].indexB;
2596 std::pair<int, int> key = canon_int_pair(t, t_other);
2597 ITT_value itt;
2598 if (itt_map.contains(key)) {
2599 itt = itt_map.lookup(key);
2600 }
2601 if (itt.kind != INONE) {
2602 itts.append(itt);
2603 }
2604 if (dbg_level > 0) {
2605 std::cout << " tri t" << t_other << "; result = " << itt << "\n";
2606 }
2607 }
2608 if (itts.size() > 0) {
2609 cd_data[otr_index] = prepare_cdt_input(tm, t, itts);
2610 do_cdt(cd_data[otr_index]);
2611 }
2612 }
2613 });
2614 /* Extract the new faces serially, so that Boolean is repeatable regardless of parallelism. */
2615 for (int otr_index : overlap_tri_range.index_range()) {
2616 CDT_data &cdd = cd_data[otr_index];
2617 if (cdd.vert.size() > 0) {
2618 int t = overlap_tri_range[otr_index].tri_index;
2619 r_tri_subdivided[t] = extract_subdivided_tri(cdd, tm, t, arena);
2620 if (dbg_level > 1) {
2621 std::cout << "subdivide output for tri " << t << " = " << r_tri_subdivided[t];
2622 }
2623 }
2624 }
2625 /* Now have to put in the triangles that are the same as the input ones, and not in clusters.
2626 */
2627 threading::parallel_for(tm.face_index_range(), 2048, [&](IndexRange range) {
2628 for (int t : range) {
2629 if (r_tri_subdivided[t].face_size() == 0 && clinfo.tri_cluster(t) == NO_INDEX) {
2630 r_tri_subdivided[t] = IMesh({tm.face(t)});
2631 }
2632 }
2633 });
2634}
2635
2643static void calc_cluster_tris(Array<IMesh> &tri_subdivided,
2644 const IMesh &tm,
2645 const CoplanarClusterInfo &clinfo,
2646 const Span<CDT_data> cluster_subdivided,
2647 IMeshArena *arena)
2648{
2649 for (int c : clinfo.index_range()) {
2650 const CoplanarCluster &cl = clinfo.cluster(c);
2651 const CDT_data &cd = cluster_subdivided[c];
2652 /* Each triangle in cluster c should be an input triangle in cd.input_faces.
2653 * (See prepare_cdt_input_for_cluster.)
2654 * So accumulate a Vector of Face* for each input face by going through the
2655 * output faces and making a Face for each input face that it is part of.
2656 * (The Boolean algorithm wants duplicates if a given output triangle is part
2657 * of more than one input triangle.)
2658 */
2659 int n_cluster_tris = cl.tot_tri();
2660 const CDT_result<mpq_class> &cdt_out = cd.cdt_out;
2661 BLI_assert(cd.input_face.size() == n_cluster_tris);
2662 Array<Vector<Face *>> face_vec(n_cluster_tris);
2663 for (int cdt_out_t : cdt_out.face.index_range()) {
2664 for (int cdt_in_t : cdt_out.face_orig[cdt_out_t]) {
2665 Face *f = cdt_tri_as_imesh_face(cdt_out_t, cdt_in_t, cd, tm, arena);
2666 face_vec[cdt_in_t].append(f);
2667 }
2668 }
2669 for (int cdt_in_t : cd.input_face.index_range()) {
2670 int tm_t = cd.input_face[cdt_in_t];
2671 BLI_assert(tri_subdivided[tm_t].face_size() == 0);
2672 tri_subdivided[tm_t] = IMesh(face_vec[cdt_in_t]);
2673 }
2674 }
2675}
2676
2677static CDT_data calc_cluster_subdivided(const CoplanarClusterInfo &clinfo,
2678 int c,
2679 const IMesh &tm,
2680 const TriOverlaps &ov,
2681 const Map<std::pair<int, int>, ITT_value> &itt_map,
2682 IMeshArena * /*arena*/)
2683{
2684 constexpr int dbg_level = 0;
2685 BLI_assert(c < clinfo.tot_cluster());
2686 const CoplanarCluster &cl = clinfo.cluster(c);
2687 /* Make a CDT input with triangles from C and intersects from other triangles in tm. */
2688 if (dbg_level > 0) {
2689 std::cout << "CALC_CLUSTER_SUBDIVIDED for cluster " << c << " = " << cl << "\n";
2690 }
2691 /* Get vector itts of all intersections of a triangle of cl with any triangle of tm not
2692 * in cl and not co-planar with it (for that latter, if there were an intersection,
2693 * it should already be in cluster cl). */
2694 Vector<ITT_value> itts;
2695 Span<BVHTreeOverlap> ovspan = ov.overlap();
2696 for (int t : cl) {
2697 if (dbg_level > 0) {
2698 std::cout << "find intersects with triangle " << t << " of cluster\n";
2699 }
2700 int first_i = ov.first_overlap_index(t);
2701 if (first_i == -1) {
2702 continue;
2703 }
2704 for (int i = first_i; i < ovspan.size() && ovspan[i].indexA == t; ++i) {
2705 int t_other = ovspan[i].indexB;
2706 if (clinfo.tri_cluster(t_other) != c) {
2707 if (dbg_level > 0) {
2708 std::cout << "use intersect(" << t << "," << t_other << "\n";
2709 }
2710 std::pair<int, int> key = canon_int_pair(t, t_other);
2711 if (itt_map.contains(key)) {
2712 ITT_value itt = itt_map.lookup(key);
2713 if (!ELEM(itt.kind, INONE, ICOPLANAR)) {
2714 itts.append(itt);
2715 if (dbg_level > 0) {
2716 std::cout << " itt = " << itt << "\n";
2717 }
2718 }
2719 }
2720 }
2721 }
2722 }
2723 /* Use CDT to subdivide the cluster triangles and the points and segments in itts. */
2724 CDT_data cd_data = prepare_cdt_input_for_cluster(tm, clinfo, c, itts);
2725 do_cdt(cd_data);
2726 return cd_data;
2727}
2728
2729static IMesh union_tri_subdivides(const blender::Array<IMesh> &tri_subdivided)
2730{
2731 int tot_tri = 0;
2732 for (const IMesh &m : tri_subdivided) {
2733 tot_tri += m.face_size();
2734 }
2735 Array<Face *> faces(tot_tri);
2736 int face_index = 0;
2737 for (const IMesh &m : tri_subdivided) {
2738 for (Face *f : m.faces()) {
2739 faces[face_index++] = f;
2740 }
2741 }
2742 return IMesh(faces);
2743}
2744
2745static CoplanarClusterInfo find_clusters(const IMesh &tm,
2746 const Array<BoundingBox> &tri_bb,
2747 const Map<std::pair<int, int>, ITT_value> &itt_map)
2748{
2749 constexpr int dbg_level = 0;
2750 if (dbg_level > 0) {
2751 std::cout << "FIND_CLUSTERS\n";
2752 }
2753 CoplanarClusterInfo ans(tm.face_size());
2754 /* Use a VectorSet to get stable order from run to run. */
2755 VectorSet<int> maybe_coplanar_tris;
2756 maybe_coplanar_tris.reserve(2 * itt_map.size());
2757 for (auto item : itt_map.items()) {
2758 if (item.value.kind == ICOPLANAR) {
2759 int t1 = item.key.first;
2760 int t2 = item.key.second;
2761 maybe_coplanar_tris.add_multiple({t1, t2});
2762 }
2763 }
2764 if (dbg_level > 0) {
2765 std::cout << "found " << maybe_coplanar_tris.size() << " possible coplanar tris\n";
2766 }
2767 if (maybe_coplanar_tris.is_empty()) {
2768 if (dbg_level > 0) {
2769 std::cout << "No possible coplanar tris, so no clusters\n";
2770 }
2771 return ans;
2772 }
2773 /* There can be more than one #CoplanarCluster per plane. Accumulate them in
2774 * a Vector. We will have to merge some elements of the Vector as we discover
2775 * triangles that form intersection bridges between two or more clusters. */
2776 Map<Plane, Vector<CoplanarCluster>> plane_cls;
2777 plane_cls.reserve(maybe_coplanar_tris.size());
2778 for (int t : maybe_coplanar_tris) {
2779 /* Use a canonical version of the plane for map index.
2780 * We can't just store the canonical version in the face
2781 * since canonicalizing loses the orientation of the normal. */
2782 Plane tplane = *tm.face(t)->plane;
2783 BLI_assert(tplane.exact_populated());
2784 tplane.make_canonical();
2785 if (dbg_level > 0) {
2786 std::cout << "plane for tri " << t << " = " << &tplane << "\n";
2787 }
2788 /* Assume all planes are in canonical from (see canon_plane()). */
2789 if (plane_cls.contains(tplane)) {
2790 Vector<CoplanarCluster> &curcls = plane_cls.lookup(tplane);
2791 if (dbg_level > 0) {
2792 std::cout << "already has " << curcls.size() << " clusters\n";
2793 }
2794 /* Partition `curcls` into those that intersect t non-trivially, and those that don't. */
2795 Vector<CoplanarCluster *> int_cls;
2796 Vector<CoplanarCluster *> no_int_cls;
2797 for (CoplanarCluster &cl : curcls) {
2798 if (dbg_level > 1) {
2799 std::cout << "consider intersecting with cluster " << cl << "\n";
2800 }
2801 if (bbs_might_intersect(tri_bb[t], cl.bounding_box())) {
2802 if (dbg_level > 1) {
2803 std::cout << "append to int_cls\n";
2804 }
2805 int_cls.append(&cl);
2806 }
2807 else {
2808 if (dbg_level > 1) {
2809 std::cout << "append to no_int_cls\n";
2810 }
2811 no_int_cls.append(&cl);
2812 }
2813 }
2814 if (int_cls.is_empty()) {
2815 /* t doesn't intersect any existing cluster in its plane, so make one just for it. */
2816 if (dbg_level > 1) {
2817 std::cout << "no intersecting clusters for t, make a new one\n";
2818 }
2819 curcls.append(CoplanarCluster(t, tri_bb[t]));
2820 }
2821 else if (int_cls.size() == 1) {
2822 /* t intersects exactly one existing cluster, so can add t to that cluster. */
2823 if (dbg_level > 1) {
2824 std::cout << "exactly one existing cluster, " << int_cls[0] << ", adding to it\n";
2825 }
2826 int_cls[0]->add_tri(t, tri_bb[t]);
2827 }
2828 else {
2829 /* t intersections 2 or more existing clusters: need to merge them and replace all the
2830 * originals with the merged one in `curcls`. */
2831 if (dbg_level > 1) {
2832 std::cout << "merging\n";
2833 }
2834 CoplanarCluster mergecl;
2835 mergecl.add_tri(t, tri_bb[t]);
2836 for (CoplanarCluster *cl : int_cls) {
2837 for (int t : *cl) {
2838 mergecl.add_tri(t, tri_bb[t]);
2839 }
2840 }
2841 Vector<CoplanarCluster> newvec;
2842 newvec.append(mergecl);
2843 for (CoplanarCluster *cl_no_int : no_int_cls) {
2844 newvec.append(*cl_no_int);
2845 }
2846 plane_cls.add_overwrite(tplane, newvec);
2847 }
2848 }
2849 else {
2850 if (dbg_level > 0) {
2851 std::cout << "first cluster for its plane\n";
2852 }
2853 plane_cls.add_new(tplane, Vector<CoplanarCluster>{CoplanarCluster(t, tri_bb[t])});
2854 }
2855 }
2856 /* Does this give deterministic order for cluster ids? I think so, since
2857 * hash for planes is on their values, not their addresses. */
2858 for (auto item : plane_cls.items()) {
2859 for (const CoplanarCluster &cl : item.value) {
2860 if (cl.tot_tri() > 1) {
2861 ans.add_cluster(cl);
2862 }
2863 }
2864 }
2865
2866 return ans;
2867}
2868
2869/* Data and functions to test triangle degeneracy in parallel. */
2870struct DegenData {
2871 const IMesh &tm;
2872};
2873
2874struct DegenChunkData {
2875 bool has_degenerate_tri = false;
2876};
2877
2878static void degenerate_range_func(void *__restrict userdata,
2879 const int iter,
2880 const TaskParallelTLS *__restrict tls)
2881{
2882 DegenData *data = static_cast<DegenData *>(userdata);
2883 DegenChunkData *chunk_data = static_cast<DegenChunkData *>(tls->userdata_chunk);
2884 const Face *f = data->tm.face(iter);
2885 bool is_degenerate = face_is_degenerate(f);
2886 chunk_data->has_degenerate_tri |= is_degenerate;
2887}
2888
2889static void degenerate_reduce(const void *__restrict /*userdata*/,
2890 void *__restrict chunk_join,
2891 void *__restrict chunk)
2892{
2893 DegenChunkData *degen_chunk_join = static_cast<DegenChunkData *>(chunk_join);
2894 DegenChunkData *degen_chunk = static_cast<DegenChunkData *>(chunk);
2895 degen_chunk_join->has_degenerate_tri |= degen_chunk->has_degenerate_tri;
2896}
2897
2898/* Does triangle #IMesh tm have any triangles with zero area? */
2899static bool has_degenerate_tris(const IMesh &tm)
2900{
2901 DegenData degen_data = {tm};
2902 DegenChunkData degen_chunk_data;
2903 TaskParallelSettings settings;
2905 settings.userdata_chunk = &degen_chunk_data;
2906 settings.userdata_chunk_size = sizeof(degen_chunk_data);
2907 settings.func_reduce = degenerate_reduce;
2908 settings.min_iter_per_thread = 1000;
2909 settings.use_threading = intersect_use_threading;
2910 BLI_task_parallel_range(0, tm.face_size(), &degen_data, degenerate_range_func, &settings);
2911 return degen_chunk_data.has_degenerate_tri;
2912}
2913
2914static IMesh remove_degenerate_tris(const IMesh &tm_in)
2915{
2916 IMesh ans;
2917 Vector<Face *> new_faces;
2918 new_faces.reserve(tm_in.face_size());
2919 for (Face *f : tm_in.faces()) {
2920 if (!face_is_degenerate(f)) {
2921 new_faces.append(f);
2922 }
2923 }
2924 ans.set_faces(new_faces);
2925 return ans;
2926}
2927
2928IMesh trimesh_self_intersect(const IMesh &tm_in, IMeshArena *arena)
2929{
2930 return trimesh_nary_intersect(
2931 tm_in, 1, [](int /*t*/) { return 0; }, true, arena);
2932}
2933
2934IMesh trimesh_nary_intersect(const IMesh &tm_in,
2935 int nshapes,
2936 const FunctionRef<int(int)> shape_fn,
2937 bool use_self,
2938 IMeshArena *arena)
2939{
2940 constexpr int dbg_level = 0;
2941 if (dbg_level > 0) {
2942 std::cout << "\nTRIMESH_NARY_INTERSECT nshapes=" << nshapes << " use_self=" << use_self
2943 << "\n";
2944 for (const Face *f : tm_in.faces()) {
2945 BLI_assert(f->is_tri());
2947 }
2948 if (dbg_level > 1) {
2949 std::cout << "input mesh:\n" << tm_in;
2950 for (int t : tm_in.face_index_range()) {
2951 std::cout << "shape(" << t << ") = " << shape_fn(tm_in.face(t)->orig) << "\n";
2952 }
2953 write_obj_mesh(const_cast<IMesh &>(tm_in), "trimesh_input");
2954 }
2955 }
2956# ifdef PERFDEBUG
2957 perfdata_init();
2958 double start_time = BLI_time_now_seconds();
2959 std::cout << "trimesh_nary_intersect start\n";
2960# endif
2961 /* Usually can use tm_in but if it has degenerate or illegal triangles,
2962 * then need to work on a copy of it without those triangles. */
2963 const IMesh *tm_clean = &tm_in;
2964 IMesh tm_cleaned;
2965 if (has_degenerate_tris(tm_in)) {
2966 if (dbg_level > 0) {
2967 std::cout << "cleaning degenerate triangles\n";
2968 }
2969 tm_cleaned = remove_degenerate_tris(tm_in);
2970 tm_clean = &tm_cleaned;
2971 if (dbg_level > 1) {
2972 std::cout << "cleaned input mesh:\n" << tm_cleaned;
2973 }
2974 }
2975# ifdef PERFDEBUG
2976 double clean_time = BLI_time_now_seconds();
2977 std::cout << "cleaned, time = " << clean_time - start_time << "\n";
2978# endif
2979 Array<BoundingBox> tri_bb = calc_face_bounding_boxes(*tm_clean);
2980# ifdef PERFDEBUG
2981 double bb_calc_time = BLI_time_now_seconds();
2982 std::cout << "bbs calculated, time = " << bb_calc_time - clean_time << "\n";
2983# endif
2984 TriOverlaps tri_ov(*tm_clean, tri_bb, nshapes, shape_fn, use_self);
2985# ifdef PERFDEBUG
2986 double overlap_time = BLI_time_now_seconds();
2987 std::cout << "intersect overlaps calculated, time = " << overlap_time - bb_calc_time << "\n";
2988# endif
2989 Array<IMesh> tri_subdivided(tm_clean->face_size(), NoInitialization());
2990 threading::parallel_for(tm_clean->face_index_range(), 1024, [&](IndexRange range) {
2991 for (int t : range) {
2992 if (tri_ov.first_overlap_index(t) != -1) {
2993 tm_clean->face(t)->populate_plane(true);
2994 }
2995 new (static_cast<void *>(&tri_subdivided[t])) IMesh;
2996 }
2997 });
2998# ifdef PERFDEBUG
2999 double plane_populate = BLI_time_now_seconds();
3000 std::cout << "planes populated, time = " << plane_populate - overlap_time << "\n";
3001# endif
3002 /* itt_map((a,b)) will hold the intersection value resulting from intersecting
3003 * triangles with indices a and b, where a < b. */
3004 Map<std::pair<int, int>, ITT_value> itt_map;
3005 itt_map.reserve(tri_ov.overlap().size());
3006 calc_overlap_itts(itt_map, *tm_clean, tri_ov, arena);
3007# ifdef PERFDEBUG
3008 double itt_time = BLI_time_now_seconds();
3009 std::cout << "itts found, time = " << itt_time - plane_populate << "\n";
3010# endif
3011 CoplanarClusterInfo clinfo = find_clusters(*tm_clean, tri_bb, itt_map);
3012 if (dbg_level > 1) {
3013 std::cout << clinfo;
3014 }
3015# ifdef PERFDEBUG
3016 double find_cluster_time = BLI_time_now_seconds();
3017 std::cout << "clusters found, time = " << find_cluster_time - itt_time << "\n";
3018 doperfmax(0, tm_in.face_size());
3019 doperfmax(1, clinfo.tot_cluster());
3020 doperfmax(2, tri_ov.overlap().size());
3021# endif
3022 calc_subdivided_non_cluster_tris(tri_subdivided, *tm_clean, itt_map, clinfo, tri_ov, arena);
3023# ifdef PERFDEBUG
3024 double subdivided_tris_time = BLI_time_now_seconds();
3025 std::cout << "subdivided non-cluster tris found, time = " << subdivided_tris_time - itt_time
3026 << "\n";
3027# endif
3028 Array<CDT_data> cluster_subdivided(clinfo.tot_cluster());
3029 for (int c : clinfo.index_range()) {
3030 cluster_subdivided[c] = calc_cluster_subdivided(clinfo, c, *tm_clean, tri_ov, itt_map, arena);
3031 }
3032# ifdef PERFDEBUG
3033 double cluster_subdivide_time = BLI_time_now_seconds();
3034 std::cout << "subdivided clusters found, time = "
3035 << cluster_subdivide_time - subdivided_tris_time << "\n";
3036# endif
3037 calc_cluster_tris(tri_subdivided, *tm_clean, clinfo, cluster_subdivided, arena);
3038# ifdef PERFDEBUG
3039 double extract_time = BLI_time_now_seconds();
3040 std::cout << "subdivided cluster tris found, time = " << extract_time - cluster_subdivide_time
3041 << "\n";
3042# endif
3043 IMesh combined = union_tri_subdivides(tri_subdivided);
3044 if (dbg_level > 1) {
3045 std::cout << "TRIMESH_NARY_INTERSECT answer:\n";
3046 std::cout << combined;
3047 }
3048# ifdef PERFDEBUG
3049 double end_time = BLI_time_now_seconds();
3050 std::cout << "triangles combined, time = " << end_time - extract_time << "\n";
3051 std::cout << "trimesh_nary_intersect done, total time = " << end_time - start_time << "\n";
3052 dump_perfdata();
3053# endif
3054 return combined;
3055}
3056
3057static std::ostream &operator<<(std::ostream &os, const CoplanarCluster &cl)
3058{
3059 os << "cl(";
3060 bool first = true;
3061 for (const int t : cl) {
3062 if (first) {
3063 first = false;
3064 }
3065 else {
3066 os << ",";
3067 }
3068 os << t;
3069 }
3070 os << ")";
3071 return os;
3072}
3073
3074static std::ostream &operator<<(std::ostream &os, const CoplanarClusterInfo &clinfo)
3075{
3076 os << "Coplanar Cluster Info:\n";
3077 for (int c : clinfo.index_range()) {
3078 os << c << ": " << clinfo.cluster(c) << "\n";
3079 }
3080 return os;
3081}
3082
3083static std::ostream &operator<<(std::ostream &os, const ITT_value &itt)
3084{
3085 switch (itt.kind) {
3086 case INONE:
3087 os << "none";
3088 break;
3089 case IPOINT:
3090 os << "point " << itt.p1;
3091 break;
3092 case ISEGMENT:
3093 os << "segment " << itt.p1 << " " << itt.p2;
3094 break;
3095 case ICOPLANAR:
3096 os << "co-planar t" << itt.t_source;
3097 break;
3098 }
3099 return os;
3100}
3101
3102void write_obj_mesh(IMesh &m, const std::string &objname)
3103{
3104 /* Would like to use #BKE_tempdir_base() here, but that brings in dependence on kernel library.
3105 * This is just for developer debugging anyway,
3106 * and should never be called in production Blender. */
3107# ifdef _WIN_32
3108 const char *objdir = BLI_getenv("HOME");
3109# else
3110 const char *objdir = "/tmp/";
3111# endif
3112 if (m.face_size() == 0) {
3113 return;
3114 }
3115
3116 std::string fname = std::string(objdir) + objname + std::string(".obj");
3117 std::ofstream f;
3118 f.open(fname);
3119 if (!f) {
3120 std::cout << "Could not open file " << fname << "\n";
3121 return;
3122 }
3123
3124 if (!m.has_verts()) {
3125 m.populate_vert();
3126 }
3127 for (const Vert *v : m.vertices()) {
3128 const double3 dv = v->co;
3129 f << "v " << dv[0] << " " << dv[1] << " " << dv[2] << "\n";
3130 }
3131 for (const Face *face : m.faces()) {
3132 /* OBJ files use 1-indexing for vertices. */
3133 f << "f ";
3134 for (const Vert *v : *face) {
3135 int i = m.lookup_vert(v);
3136 BLI_assert(i != NO_INDEX);
3137 /* OBJ files use 1-indexing for vertices. */
3138 f << i + 1 << " ";
3139 }
3140 f << "\n";
3141 }
3142 f.close();
3143}
3144
3145# ifdef PERFDEBUG
3146struct PerfCounts {
3147 Vector<int> count;
3148 Vector<const char *> count_name;
3149 Vector<int> max;
3150 Vector<const char *> max_name;
3151};
3152
3153static PerfCounts *perfdata = nullptr;
3154
3155static void perfdata_init()
3156{
3157 perfdata = new PerfCounts;
3158
3159 /* count 0. */
3160 perfdata->count.append(0);
3161 perfdata->count_name.append("Non-cluster overlaps");
3162
3163 /* count 1. */
3164 perfdata->count.append(0);
3165 perfdata->count_name.append("intersect_tri_tri calls");
3166
3167 /* count 2. */
3168 perfdata->count.append(0);
3169 perfdata->count_name.append("tri tri intersects decided by filter plane tests");
3170
3171 /* count 3. */
3172 perfdata->count.append(0);
3173 perfdata->count_name.append("tri tri intersects decided by exact plane tests");
3174
3175 /* count 4. */
3176 perfdata->count.append(0);
3177 perfdata->count_name.append("final non-NONE intersects");
3178
3179 /* max 0. */
3180 perfdata->max.append(0);
3181 perfdata->max_name.append("total faces");
3182
3183 /* max 1. */
3184 perfdata->max.append(0);
3185 perfdata->max_name.append("total clusters");
3186
3187 /* max 2. */
3188 perfdata->max.append(0);
3189 perfdata->max_name.append("total overlaps");
3190}
3191
3192static void incperfcount(int countnum)
3193{
3194 perfdata->count[countnum]++;
3195}
3196
3197static void bumpperfcount(int countnum, int amt)
3198{
3199 perfdata->count[countnum] += amt;
3200}
3201
3202static void doperfmax(int maxnum, int val)
3203{
3204 perfdata->max[maxnum] = max_ii(perfdata->max[maxnum], val);
3205}
3206
3207static void dump_perfdata()
3208{
3209 std::cout << "\nPERFDATA\n";
3210 for (int i : perfdata->count.index_range()) {
3211 std::cout << perfdata->count_name[i] << " = " << perfdata->count[i] << "\n";
3212 }
3213 for (int i : perfdata->max.index_range()) {
3214 std::cout << perfdata->max_name[i] << " = " << perfdata->max[i] << "\n";
3215 }
3216 delete perfdata;
3217}
3218# endif
3219
3220} // namespace blender::meshintersect
3221
3222#endif // WITH_GMP
#define BLI_assert(a)
Definition BLI_assert.h:50
@ CDT_INSIDE
BVHTree * BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
void BLI_bvhtree_balance(BVHTree *tree)
void BLI_bvhtree_free(BVHTree *tree)
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints)
BVHTreeOverlap * BLI_bvhtree_overlap(const BVHTree *tree1, const BVHTree *tree2, unsigned int *r_overlap_num, BVHTree_OverlapCallback callback, void *userdata)
MINLINE int max_ii(int a, int b)
MINLINE double max_dd(double a, double b)
bool isect_aabb_aabb_v3(const float min1[3], const float max1[3], const float min2[3], const float max2[3])
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
const char * BLI_getenv(const char *env) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
void BLI_polyfill_calc(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3])
unsigned int uint
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition task_range.cc:99
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:230
pthread_spinlock_t SpinLock
void BLI_mutex_free(ThreadMutex *mutex)
Definition threads.cc:372
ThreadMutex * BLI_mutex_alloc(void)
Definition threads.cc:365
void BLI_mutex_lock(ThreadMutex *mutex)
Definition threads.cc:345
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition threads.cc:350
void BLI_spin_init(SpinLock *spin)
Definition threads.cc:391
void BLI_spin_unlock(SpinLock *spin)
Definition threads.cc:430
void BLI_spin_lock(SpinLock *spin)
Definition threads.cc:405
pthread_mutex_t ThreadMutex
Definition BLI_threads.h:83
void BLI_spin_end(SpinLock *spin)
Definition threads.cc:445
double BLI_time_now_seconds(void)
Definition time.c:65
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define ELEM(...)
#define MEM_reallocN(vmemh, len)
bool operator==(const AssetWeakReference &a, const AssetWeakReference &b)
int pad[32 - sizeof(int)]
ATTR_WARN_UNUSED_RESULT const BMVert * v2
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
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
Definition btVector3.h:263
local_group_size(16, 16) .push_constant(Type b
blender::meshintersect::CDT_result< double > delaunay_2d_calc(const CDT_input< double > &input, CDT_output_type output_type)
int len
draw_view in_light_buf[] float
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]
#define UINT_MAX
Definition hash_md5.cc:44
int count
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float2 fabs(const float2 a)
static char faces[256]
GAttributeReader lookup(const void *owner, const StringRef attribute_id)
T length_squared(const VecBase< T, Size > &a)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
int dominant_axis(const VecBase< T, 3 > &a)
T abs(const T &a)
VecBase< T, 3 > cross_poly(Span< VecBase< T, 3 > > poly)
CDT_result< double > delaunay_2d_calc(const CDT_input< double > &input, CDT_output_type output_type)
void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end)
Definition BLI_sort.hh:23
VecBase< double, 3 > double3
#define hash
Definition noise.c:154
__int64 int64_t
Definition stdint.h:89
unsigned __int64 uint64_t
Definition stdint.h:90
float co[3]
float max
std::ostream & operator<<(std::ostream &stream, bUUID uuid)
Definition uuid.cc:131