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