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
8
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 {
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);
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;
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. */
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. */
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 }
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)
struct BVHTreeOverlap BVHTreeOverlap
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)
struct BVHTree BVHTree
Definition BLI_kdopbvh.h:20
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(...)
struct CBData CBData
#define MEM_reallocN(vmemh, len)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Map
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
int64_t size() const
Definition BLI_array.hh:245
void fill(const T &value) const
Definition BLI_array.hh:261
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:301
const Value & lookup(const Key &key) const
Definition BLI_map.hh:506
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:531
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:241
ItemIterator items() const
Definition BLI_map.hh:864
void reserve(int64_t n)
Definition BLI_map.hh:979
bool contains(const Key &key) const
Definition BLI_map.hh:329
void reserve(const int64_t n)
Definition BLI_set.hh:614
void add_new(const Key &key)
Definition BLI_set.hh:233
const Key * lookup_key_ptr(const Key &key) const
Definition BLI_set.hh:335
constexpr int64_t size() const
Definition BLI_span.hh:253
void reserve(const int64_t n)
int64_t size() const
bool is_empty() const
void add_multiple(Span< Key > keys)
int64_t size() const
int64_t append_and_get_index(const T &value)
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
void resize(const int64_t new_size)
void reserve(const int64_t min_capacity)
T * end()
T * begin()
local_group_size(16, 16) .push_constant(Type b
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
struct BoundingBox { packed_float3 min; packed_float3 max;} BoundingBox
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 index(const bNode &, void *r_value)
void normal(const bNode &, void *r_value)
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
TaskParallelReduceFunc func_reduce
Definition BLI_task.h:185
size_t userdata_chunk_size
Definition BLI_task.h:173
float max
std::ostream & operator<<(std::ostream &stream, bUUID uuid)
Definition uuid.cc:131