48static void perfdata_init();
49static void incperfcount(
int countnum);
50static void bumpperfcount(
int countnum,
int amt);
51static void doperfmax(
int maxnum,
int val);
52static void dump_perfdata();
56static constexpr bool intersect_use_threading =
true;
58Vert::Vert(
const mpq3 &mco,
const double3 &dco,
int id,
int orig)
59 : co_exact(mco), co(dco), id(id), orig(orig)
63bool Vert::operator==(
const Vert &other)
const
65 return this->co_exact == other.co_exact;
73 x = (x >> 56) ^ (x >> 46) ^
x;
74 y = (y >> 55) ^ (y >> 45) ^
y;
75 z = (
z >> 54) ^ (
z >> 44) ^
z;
81 constexpr int dbg_level = 0;
83 if (
v->orig != NO_INDEX) {
88 os <<
"=" <<
v->co_exact;
93bool Plane::operator==(
const Plane &other)
const
95 return norm_exact == other.norm_exact && d_exact == other.d_exact;
98void Plane::make_canonical()
100 if (norm_exact[0] != 0) {
101 mpq_class den = norm_exact[0];
102 norm_exact = mpq3(1, norm_exact[1] / den, norm_exact[2] / den);
103 d_exact = d_exact / den;
105 else if (norm_exact[1] != 0) {
106 mpq_class den = norm_exact[1];
107 norm_exact = mpq3(0, 1, norm_exact[2] / den);
108 d_exact = d_exact / den;
111 if (norm_exact[2] != 0) {
112 mpq_class den = norm_exact[2];
113 norm_exact = mpq3(0, 0, 1);
114 d_exact = d_exact / den;
121 norm =
double3(norm_exact[0].get_d(), norm_exact[1].get_d(), norm_exact[2].get_d());
125Plane::Plane(
const mpq3 &norm_exact,
const mpq_class &d_exact)
126 : norm_exact(norm_exact), d_exact(d_exact)
128 norm =
double3(norm_exact[0].get_d(), norm_exact[1].get_d(), norm_exact[2].get_d());
132Plane::Plane(
const double3 &
norm,
const double d) :
norm(
norm), d(d)
134 norm_exact = mpq3(0, 0, 0);
137bool Plane::exact_populated()
const
139 return norm_exact[0] != 0 || norm_exact[1] != 0 || norm_exact[2] != 0;
148 x = (x >> 56) ^ (x >> 46) ^
x;
149 y = (y >> 55) ^ (y >> 45) ^
y;
150 z = (
z >> 54) ^ (
z >> 44) ^
z;
151 d = (d >> 53) ^ (d >> 43) ^ d;
152 return x ^ y ^
z ^ d;
155std::ostream &
operator<<(std::ostream &os,
const Plane *plane)
157 os <<
"[" << plane->norm <<
";" << plane->d <<
"]";
162 Span<const Vert *>
verts,
int id,
int orig, Span<int> edge_origs, Span<bool> is_intersect)
163 : vert(
verts), edge_orig(edge_origs), is_intersect(is_intersect), id(id), orig(orig)
167Face::Face(Span<const Vert *>
verts,
int id,
int orig) : vert(
verts), id(id), orig(orig) {}
169void Face::populate_plane(
bool need_exact)
171 if (plane !=
nullptr) {
172 if (!need_exact || plane->exact_populated()) {
178 if (vert.size() > 3) {
179 Array<mpq3> co(vert.size());
180 for (
int i : index_range()) {
181 co[i] = vert[i]->co_exact;
186 mpq3 tr02 = vert[0]->co_exact - vert[2]->co_exact;
187 mpq3 tr12 = vert[1]->co_exact - vert[2]->co_exact;
190 mpq_class d_exact = -
math::dot(normal_exact, vert[0]->co_exact);
191 plane =
new Plane(normal_exact, d_exact);
195 if (vert.size() > 3) {
196 Array<double3> co(vert.size());
197 for (
int i : index_range()) {
203 double3 tr02 = vert[0]->co - vert[2]->co;
204 double3 tr12 = vert[1]->co - vert[2]->co;
207 double d = -
math::dot(normal, vert[0]->co);
208 plane =
new Plane(normal, d);
217bool Face::operator==(
const Face &other)
const
219 if (this->
size() != other.size()) {
222 for (FacePos i : index_range()) {
225 if (this->vert[i] != other.vert[i]) {
232bool Face::cyclic_equal(
const Face &other)
const
234 if (this->
size() != other.size()) {
237 int flen = this->
size();
238 for (FacePos start : index_range()) {
239 for (FacePos start_other : index_range()) {
241 for (
int i = 0; ok && i < flen; ++i) {
242 FacePos p = (start + i) % flen;
243 FacePos p_other = (start_other + i) % flen;
244 if (this->vert[p] != other.vert[p_other]) {
256std::ostream &
operator<<(std::ostream &os,
const Face *f)
258 os <<
"f" << f->id <<
"o" << f->orig <<
"[";
259 for (
const Vert *
v : *f) {
261 if (
v != f->vert[f->size() - 1]) {
266 if (f->orig != NO_INDEX) {
267 os <<
"o" << f->orig;
270 for (
int i : f->index_range()) {
271 os << f->edge_orig[i];
272 if (f->is_intersect[i]) {
275 if (i != f->size() - 1) {
298class IMeshArena::IMeshArenaImpl : NonCopyable, NonMovable {
308 VSetKey(
Vert *p) : vert(p) {}
317 return *this->vert == *other.vert;
328 Vector<std::unique_ptr<Vert>> allocated_verts_;
329 Vector<std::unique_ptr<Face>> allocated_faces_;
332 int next_vert_id_ = 0;
333 int next_face_id_ = 0;
345 if (intersect_use_threading) {
355 if (intersect_use_threading) {
364 void reserve(
int vert_num_hint,
int face_num_hint)
366 vset_.reserve(vert_num_hint);
367 allocated_verts_.reserve(vert_num_hint);
368 allocated_faces_.reserve(face_num_hint);
371 int tot_allocated_verts()
const
373 return allocated_verts_.size();
376 int tot_allocated_faces()
const
378 return allocated_faces_.size();
381 const Vert *add_or_find_vert(
const mpq3 &co,
int orig)
383 double3 dco(co[0].get_d(), co[1].get_d(), co[2].get_d());
384 return add_or_find_vert(co, dco, orig);
387 const Vert *add_or_find_vert(
const double3 &co,
int orig)
389 mpq3 mco(co[0], co[1], co[2]);
390 return add_or_find_vert(mco, co, orig);
393 const Vert *add_or_find_vert(
Vert *vert)
395 return add_or_find_vert_(vert);
398 Face *add_face(Span<const Vert *>
verts,
int orig, Span<int> edge_origs, Span<bool> is_intersect)
400 Face *f =
new Face(
verts, next_face_id_++, orig, edge_origs, is_intersect);
401 if (intersect_use_threading) {
408 allocated_faces_.append(std::unique_ptr<Face>(f));
409 if (intersect_use_threading) {
419 Face *add_face(Span<const Vert *>
verts,
int orig, Span<int> edge_origs)
421 Array<bool> is_intersect(
verts.size(),
false);
422 return add_face(
verts, orig, edge_origs, is_intersect);
425 Face *add_face(Span<const Vert *>
verts,
int orig)
427 Array<int> edge_origs(
verts.size(), NO_INDEX);
428 Array<bool> is_intersect(
verts.size(),
false);
429 return add_face(
verts, orig, edge_origs, is_intersect);
432 const Vert *find_vert(
const mpq3 &co)
434 Vert vtry(co,
double3(co[0].get_d(), co[1].get_d(), co[2].get_d()), NO_INDEX, NO_INDEX);
435 VSetKey vskey(&vtry);
436 if (intersect_use_threading) {
443 const VSetKey *
lookup = vset_.lookup_key_ptr(vskey);
444 if (intersect_use_threading) {
462 const Face *find_face(Span<const Vert *> vs)
464 Array<int> eorig(vs.size(), NO_INDEX);
465 Array<bool> is_intersect(vs.size(),
false);
466 Face ftry(vs, NO_INDEX, NO_INDEX, eorig, is_intersect);
467 for (
const int i : allocated_faces_.index_range()) {
468 if (ftry.cyclic_equal(*allocated_faces_[i])) {
469 return allocated_faces_[i].get();
476 const Vert *add_or_find_vert(
const mpq3 &mco,
const double3 &dco,
int orig)
478 Vert *vtry =
new Vert(mco, dco, NO_INDEX, NO_INDEX);
481 if (intersect_use_threading) {
488 const VSetKey *
lookup = vset_.lookup_key_ptr(vskey);
490 vtry->id = next_vert_id_++;
493 vset_.add_new(vskey);
494 allocated_verts_.append(std::unique_ptr<Vert>(vskey.vert));
506 if (intersect_use_threading) {
516 const Vert *add_or_find_vert_(
Vert *vtry)
520 if (intersect_use_threading) {
527 const VSetKey *
lookup = vset_.lookup_key_ptr(vskey);
529 vtry->id = next_vert_id_++;
531 vset_.add_new(vskey);
532 allocated_verts_.append(std::unique_ptr<Vert>(vskey.vert));
544 if (intersect_use_threading) {
555IMeshArena::IMeshArena()
557 pimpl_ = std::make_unique<IMeshArenaImpl>();
560IMeshArena::~IMeshArena() =
default;
562void IMeshArena::reserve(
int vert_num_hint,
int face_num_hint)
564 pimpl_->reserve(vert_num_hint, face_num_hint);
567int IMeshArena::tot_allocated_verts()
const
569 return pimpl_->tot_allocated_verts();
572int IMeshArena::tot_allocated_faces()
const
574 return pimpl_->tot_allocated_faces();
577const Vert *IMeshArena::add_or_find_vert(
const mpq3 &co,
int orig)
579 return pimpl_->add_or_find_vert(co, orig);
582const Vert *IMeshArena::add_or_find_vert(
Vert *vert)
584 return pimpl_->add_or_find_vert(vert);
587Face *IMeshArena::add_face(Span<const Vert *>
verts,
589 Span<int> edge_origs,
590 Span<bool> is_intersect)
592 return pimpl_->add_face(
verts, orig, edge_origs, is_intersect);
595Face *IMeshArena::add_face(Span<const Vert *>
verts,
int orig, Span<int> edge_origs)
597 return pimpl_->add_face(
verts, orig, edge_origs);
600Face *IMeshArena::add_face(Span<const Vert *>
verts,
int orig)
602 return pimpl_->add_face(
verts, orig);
605const Vert *IMeshArena::add_or_find_vert(
const double3 &co,
int orig)
607 return pimpl_->add_or_find_vert(co, orig);
610const Vert *IMeshArena::find_vert(
const mpq3 &co)
const
612 return pimpl_->find_vert(co);
615const Face *IMeshArena::find_face(Span<const Vert *>
verts)
const
617 return pimpl_->find_face(
verts);
620void IMesh::set_faces(Span<Face *> faces)
625int IMesh::lookup_vert(
const Vert *
v)
const
628 return vert_to_index_.lookup_default(
v, NO_INDEX);
631void IMesh::populate_vert()
635 constexpr int ESTIMATE_VERTS_PER_FACE = 4;
636 int estimate_verts_num = ESTIMATE_VERTS_PER_FACE * face_.size();
637 populate_vert(estimate_verts_num);
640void IMesh::populate_vert(
int max_verts)
642 if (vert_populated_) {
645 vert_to_index_.reserve(max_verts);
646 int next_allocate_index = 0;
647 for (
const Face *f : face_) {
648 for (
const Vert *
v : *f) {
651 int index = vert_to_index_.lookup_default(
v, NO_INDEX);
652 if (index == NO_INDEX) {
654 vert_to_index_.add(
v, next_allocate_index++);
658 int tot_v = next_allocate_index;
659 vert_ = Array<const Vert *>(tot_v);
660 for (
auto item : vert_to_index_.items()) {
661 int index = item.value;
663 vert_[index] = item.key;
668 const bool fix_order =
true;
671 if (a->orig != NO_INDEX && b->orig != NO_INDEX) {
672 return a->orig < b->orig;
674 if (a->orig != NO_INDEX) {
677 if (
b->orig != NO_INDEX) {
680 return a->id <
b->id;
682 for (
int i : vert_.index_range()) {
683 const Vert *
v = vert_[i];
684 vert_to_index_.add_overwrite(
v, i);
687 vert_populated_ =
true;
690bool IMesh::erase_face_positions(
int f_index, Span<bool> face_pos_erase, IMeshArena *arena)
692 const Face *cur_f = this->face(f_index);
693 int cur_len = cur_f->size();
694 int to_erase_num = 0;
695 for (
int i : cur_f->index_range()) {
696 if (face_pos_erase[i]) {
700 if (to_erase_num == 0) {
703 int new_len = cur_len - to_erase_num;
711 this->face_[f_index] =
nullptr;
714 Array<const Vert *> new_vert(new_len);
715 Array<int> new_edge_orig(new_len);
716 Array<bool> new_is_intersect(new_len);
718 for (
int i : cur_f->index_range()) {
719 if (!face_pos_erase[i]) {
720 new_vert[new_index] = (*cur_f)[i];
721 new_edge_orig[new_index] = cur_f->edge_orig[i];
722 new_is_intersect[new_index] = cur_f->is_intersect[i];
727 this->face_[f_index] = arena->add_face(new_vert, cur_f->orig, new_edge_orig, new_is_intersect);
731void IMesh::remove_null_faces()
734 for (Face *f : this->face_) {
739 if (nullcount == 0) {
742 int64_t new_size = this->face_.size() - nullcount;
745 Array<Face *> new_face(new_size);
746 while (copy_from_index < face_.size()) {
747 Face *f_from = face_[copy_from_index++];
749 new_face[copy_to_index++] = f_from;
752 this->face_ = new_face;
755std::ostream &
operator<<(std::ostream &os,
const IMesh &mesh)
757 if (mesh.has_verts()) {
760 for (
const Vert *
v : mesh.vertices()) {
761 os << i <<
": " <<
v <<
"\n";
767 for (
const Face *f : mesh.faces()) {
768 os << i <<
": " << f <<
"\n";
769 if (f->plane !=
nullptr) {
770 os <<
" plane=" << f->plane <<
" eorig=[";
771 for (Face::FacePos p = 0; p < f->size(); ++p) {
772 os << f->edge_orig[p] <<
" ";
793 double max_abs_val = 0.0;
798 Array<BoundingBox> *face_bounding_box;
800 BBCalcData(
const IMesh &im, Array<BoundingBox> *fbb) : im(im), face_bounding_box(fbb){};
803static void calc_face_bb_range_func(
void *__restrict userdata,
807 BBCalcData *bbdata =
static_cast<BBCalcData *
>(userdata);
808 double max_abs = 0.0;
809 const Face &face = *bbdata->im.face(iter);
810 BoundingBox &bb = (*bbdata->face_bounding_box)[iter];
811 for (
const Vert *
v : face) {
813 for (
int i = 0; i < 3; ++i) {
817 BBChunkData *chunk =
static_cast<BBChunkData *
>(tls->userdata_chunk);
818 chunk->max_abs_val =
max_dd(max_abs, chunk->max_abs_val);
822 Array<BoundingBox> *face_bounding_box;
825 BBPadData(Array<BoundingBox> *fbb,
double pad) : face_bounding_box(fbb),
pad(
pad){};
828static void pad_face_bb_range_func(
void *__restrict userdata,
832 BBPadData *pad_data =
static_cast<BBPadData *
>(userdata);
833 (*pad_data->face_bounding_box)[iter].expand(pad_data->pad);
836static void calc_face_bb_reduce(
const void *__restrict ,
837 void *__restrict chunk_join,
838 void *__restrict chunk)
840 BBChunkData *bbchunk_join =
static_cast<BBChunkData *
>(chunk_join);
841 BBChunkData *bbchunk =
static_cast<BBChunkData *
>(chunk);
842 bbchunk_join->max_abs_val =
max_dd(bbchunk_join->max_abs_val, bbchunk->max_abs_val);
850static Array<BoundingBox> calc_face_bounding_boxes(
const IMesh &m)
852 int n = m.face_size();
853 Array<BoundingBox> ans(n);
855 BBCalcData
data(m, &ans);
856 BBChunkData chunk_data;
858 settings.userdata_chunk = &chunk_data;
859 settings.userdata_chunk_size =
sizeof(chunk_data);
860 settings.func_reduce = calc_face_bb_reduce;
861 settings.min_iter_per_thread = 1000;
862 settings.use_threading = intersect_use_threading;
864 double max_abs_val = chunk_data.max_abs_val;
865 constexpr float pad_factor = 10.0f;
866 float pad = max_abs_val == 0.0f ? FLT_EPSILON : 2 * FLT_EPSILON * max_abs_val;
870 settings.min_iter_per_thread = 1000;
871 settings.use_threading = intersect_use_threading;
872 BBPadData pad_data(&ans,
pad);
886class CoplanarCluster {
891 CoplanarCluster() =
default;
894 this->add_tri(t, bb);
907 int tri(
int index)
const
911 const int *begin()
const
913 return tris_.begin();
915 const int *end()
const
932class CoplanarClusterInfo {
933 Vector<CoplanarCluster> clusters_;
934 Array<int> tri_cluster_;
937 CoplanarClusterInfo() =
default;
938 explicit CoplanarClusterInfo(
int numtri) : tri_cluster_(
Array<
int>(numtri))
940 tri_cluster_.fill(-1);
943 int tri_cluster(
int t)
const
946 return tri_cluster_[t];
949 int add_cluster(
const CoplanarCluster &cl)
951 int c_index = clusters_.append_and_get_index(cl);
954 tri_cluster_[t] = c_index;
959 int tot_cluster()
const
961 return clusters_.size();
964 const CoplanarCluster *begin()
966 return clusters_.begin();
969 const CoplanarCluster *end()
971 return clusters_.end();
974 IndexRange index_range()
const
976 return clusters_.index_range();
979 const CoplanarCluster &cluster(
int index)
const
982 return clusters_[index];
986static std::ostream &
operator<<(std::ostream &os,
const CoplanarCluster &cl);
988static std::ostream &
operator<<(std::ostream &os,
const CoplanarClusterInfo &clinfo);
990enum ITT_value_kind { INONE, IPOINT, ISEGMENT, ICOPLANAR };
996 enum ITT_value_kind kind = INONE;
998 ITT_value() =
default;
999 explicit ITT_value(ITT_value_kind k) : kind(k) {}
1000 ITT_value(ITT_value_kind k,
int tsrc) : t_source(tsrc), kind(k) {}
1001 ITT_value(ITT_value_kind k,
const mpq3 &p1) : p1(p1), kind(k) {}
1002 ITT_value(ITT_value_kind k,
const mpq3 &p1,
const mpq3 &p2) : p1(p1), p2(p2), kind(k) {}
1005static std::ostream &
operator<<(std::ostream &os,
const ITT_value &itt);
1012static mpq2 project_3d_to_2d(
const mpq3 &p3d,
int proj_axis)
1015 switch (proj_axis) {
1067static double supremum_dot_cross(
const double3 &a,
const double3 &
b)
1074 c[0] = abs_a[1] * abs_b[2] + abs_a[2] * abs_b[1];
1075 c[1] = abs_a[2] * abs_b[0] + abs_a[0] * abs_b[2];
1076 c[2] = abs_a[0] * abs_b[1] + abs_a[1] * abs_b[0];
1083constexpr int index_dot_plane_coords = 15;
1095constexpr int index_dot_cross = 11;
1105constexpr int index_plane_side = 3 + 2 * index_dot_plane_coords;
1107static int filter_plane_side(
const double3 &p,
1108 const double3 &plane_p,
1109 const double3 &plane_no,
1110 const double3 &abs_p,
1111 const double3 &abs_plane_p,
1112 const double3 &abs_plane_no)
1114 double d =
math::dot(p - plane_p, plane_no);
1118 double supremum =
math::dot(abs_p + abs_plane_p, abs_plane_no);
1119 double err_bound = supremum * index_plane_side * DBL_EPSILON;
1120 if (
fabs(d) > err_bound) {
1121 return d > 0 ? 1 : -1;
1142static inline mpq3 tti_interp(
1143 const mpq3 &a,
const mpq3 &
b,
const mpq3 &c,
const mpq3 &n, mpq3 &ab, mpq3 &ac, mpq3 &dotbuf)
1149 mpq_class den = math::dot_with_buffer(ab, n, dotbuf);
1151 mpq_class alpha = math::dot_with_buffer(ac, n, dotbuf) / den;
1152 return a - alpha * ab;
1162static inline int tti_above(
const mpq3 &a,
1176 n.x = ba.y * ca.z - ba.z * ca.y;
1177 n.y = ba.z * ca.x - ba.x * ca.z;
1178 n.z = ba.x * ca.y - ba.y * ca.x;
1180 return sgn(math::dot_with_buffer(ad, n, dotbuf));
1196static ITT_value itt_canon2(
const mpq3 &p1,
1205 constexpr int dbg_level = 0;
1206 if (dbg_level > 0) {
1207 std::cout <<
"\ntri_tri_intersect_canon:\n";
1208 std::cout <<
"p1=" << p1 <<
" q1=" <<
q1 <<
" r1=" << r1 <<
"\n";
1209 std::cout <<
"p2=" << p2 <<
" q2=" << q2 <<
" r2=" << r2 <<
"\n";
1210 std::cout <<
"n1=" << n1 <<
" n2=" << n2 <<
"\n";
1211 std::cout <<
"approximate values:\n";
1212 std::cout <<
"p1=(" << p1[0].get_d() <<
"," << p1[1].get_d() <<
"," << p1[2].get_d() <<
")\n";
1213 std::cout <<
"q1=(" <<
q1[0].get_d() <<
"," <<
q1[1].get_d() <<
"," <<
q1[2].get_d() <<
")\n";
1214 std::cout <<
"r1=(" << r1[0].get_d() <<
"," << r1[1].get_d() <<
"," << r1[2].get_d() <<
")\n";
1215 std::cout <<
"p2=(" << p2[0].get_d() <<
"," << p2[1].get_d() <<
"," << p2[2].get_d() <<
")\n";
1216 std::cout <<
"q2=(" << q2[0].get_d() <<
"," << q2[1].get_d() <<
"," << q2[2].get_d() <<
")\n";
1217 std::cout <<
"r2=(" << r2[0].get_d() <<
"," << r2[1].get_d() <<
"," << r2[2].get_d() <<
")\n";
1218 std::cout <<
"n1=(" << n1[0].get_d() <<
"," << n1[1].get_d() <<
"," << n1[2].get_d() <<
")\n";
1219 std::cout <<
"n2=(" << n2[0].get_d() <<
"," << n2[1].get_d() <<
"," << n2[2].get_d() <<
")\n";
1221 mpq3 p1p2 = p2 - p1;
1225 bool no_overlap =
false;
1227 if (tti_above(p1,
q1, r2, p1p2, buf[0], buf[1], buf[2], buf[3]) > 0) {
1229 if (tti_above(p1, r1, r2, p1p2, buf[0], buf[1], buf[2], buf[3]) <= 0) {
1231 if (tti_above(p1, r1, q2, p1p2, buf[0], buf[1], buf[2], buf[3]) > 0) {
1233 if (dbg_level > 0) {
1234 std::cout <<
"overlap [k [i l] j]\n";
1237 intersect_1 = tti_interp(p1, r1, p2, n2, buf[0], buf[1], buf[2]);
1238 intersect_2 = tti_interp(p2, r2, p1, n1, buf[0], buf[1], buf[2]);
1242 if (dbg_level > 0) {
1243 std::cout <<
"overlap [i [k l] j]\n";
1246 intersect_1 = tti_interp(p2, q2, p1, n1, buf[0], buf[1], buf[2]);
1247 intersect_2 = tti_interp(p2, r2, p1, n1, buf[0], buf[1], buf[2]);
1252 if (dbg_level > 0) {
1253 std::cout <<
"no overlap: [k l] [i j]\n";
1260 if (tti_above(p1,
q1, q2, p1p2, buf[0], buf[1], buf[2], buf[3]) < 0) {
1262 if (dbg_level > 0) {
1263 std::cout <<
"no overlap: [i j] [k l]\n";
1269 if (tti_above(p1, r1, q2, p1p2, buf[0], buf[1], buf[2], buf[3]) >= 0) {
1271 if (dbg_level > 0) {
1272 std::cout <<
"overlap [k [i j] l]\n";
1275 intersect_1 = tti_interp(p1, r1, p2, n2, buf[0], buf[1], buf[2]);
1276 intersect_2 = tti_interp(p1,
q1, p2, n2, buf[0], buf[1], buf[2]);
1280 if (dbg_level > 0) {
1281 std::cout <<
"overlap [i [k j] l]\n";
1284 intersect_1 = tti_interp(p2, q2, p1, n1, buf[0], buf[1], buf[2]);
1285 intersect_2 = tti_interp(p1,
q1, p2, n2, buf[0], buf[1], buf[2]);
1290 return ITT_value(INONE);
1292 if (intersect_1 == intersect_2) {
1293 if (dbg_level > 0) {
1294 std::cout <<
"single intersect: " << intersect_1 <<
"\n";
1296 return ITT_value(IPOINT, intersect_1);
1298 if (dbg_level > 0) {
1299 std::cout <<
"intersect segment: " << intersect_1 <<
", " << intersect_2 <<
"\n";
1301 return ITT_value(ISEGMENT, intersect_1, intersect_2);
1306static ITT_value itt_canon1(
const mpq3 &p1,
1318 constexpr int dbg_level = 0;
1321 return itt_canon2(p1, r1,
q1, r2, p2, q2, n1, n2);
1324 return itt_canon2(p1, r1,
q1, q2, r2, p2, n1, n2);
1326 return itt_canon2(p1,
q1, r1, p2, q2, r2, n1, n2);
1330 return itt_canon2(p1,
q1, r1, r2, p2, q2, n1, n2);
1333 return itt_canon2(p1,
q1, r1, q2, r2, p2, n1, n2);
1335 return itt_canon2(p1, r1,
q1, p2, q2, r2, n1, n2);
1339 return itt_canon2(p1, r1,
q1, q2, r2, p2, n1, n2);
1341 return itt_canon2(p1,
q1, r1, p2, q2, r2, n1, n2);
1345 return itt_canon2(p1, r1,
q1, p2, q2, r2, n1, n2);
1347 return itt_canon2(p1,
q1, r1, q2, r2, p2, n1, n2);
1350 return itt_canon2(p1,
q1, r1, r2, p2, q2, n1, n2);
1353 return itt_canon2(p1, r1,
q1, r2, p2, q2, n1, n2);
1355 if (dbg_level > 0) {
1356 std::cout <<
"triangles are co-planar\n";
1358 return ITT_value(ICOPLANAR);
1361static ITT_value intersect_tri_tri(
const IMesh &tm,
int t1,
int t2)
1363 constexpr int dbg_level = 0;
1367 const Face &tri1 = *tm.face(t1);
1368 const Face &tri2 = *tm.face(t2);
1369 BLI_assert(tri1.plane_populated() && tri2.plane_populated());
1370 const Vert *vp1 = tri1[0];
1371 const Vert *vq1 = tri1[1];
1372 const Vert *vr1 = tri1[2];
1373 const Vert *vp2 = tri2[0];
1374 const Vert *vq2 = tri2[1];
1375 const Vert *vr2 = tri2[2];
1376 if (dbg_level > 0) {
1377 std::cout <<
"\nINTERSECT_TRI_TRI t1=" << t1 <<
", t2=" << t2 <<
"\n";
1378 std::cout <<
" p1 = " << vp1 <<
"\n";
1379 std::cout <<
" q1 = " << vq1 <<
"\n";
1380 std::cout <<
" r1 = " << vr1 <<
"\n";
1381 std::cout <<
" p2 = " << vp2 <<
"\n";
1382 std::cout <<
" q2 = " << vq2 <<
"\n";
1383 std::cout <<
" r2 = " << vr2 <<
"\n";
1391 const double3 &d_p1 = vp1->co;
1392 const double3 &d_q1 = vq1->co;
1393 const double3 &d_r1 = vr1->co;
1394 const double3 &d_p2 = vp2->co;
1395 const double3 &d_q2 = vq2->co;
1396 const double3 &d_r2 = vr2->co;
1397 const double3 &d_n2 = tri2.plane->norm;
1405 int sp1 = filter_plane_side(d_p1, d_r2, d_n2, abs_d_p1, abs_d_r2, abs_d_n2);
1406 int sq1 = filter_plane_side(d_q1, d_r2, d_n2, abs_d_q1, abs_d_r2, abs_d_n2);
1407 int sr1 = filter_plane_side(d_r1, d_r2, d_n2, abs_d_r1, abs_d_r2, abs_d_n2);
1408 if ((sp1 > 0 && sq1 > 0 && sr1 > 0) || (sp1 < 0 && sq1 < 0 && sr1 < 0)) {
1412 if (dbg_level > 0) {
1413 std::cout <<
"no intersection, all t1's verts above or below t2\n";
1415 return ITT_value(INONE);
1418 const double3 &d_n1 = tri1.plane->norm;
1423 int sp2 = filter_plane_side(d_p2, d_r1, d_n1, abs_d_p2, abs_d_r1, abs_d_n1);
1424 int sq2 = filter_plane_side(d_q2, d_r1, d_n1, abs_d_q2, abs_d_r1, abs_d_n1);
1425 int sr2 = filter_plane_side(d_r2, d_r1, d_n1, abs_d_r2, abs_d_r1, abs_d_n1);
1426 if ((sp2 > 0 && sq2 > 0 && sr2 > 0) || (sp2 < 0 && sq2 < 0 && sr2 < 0)) {
1430 if (dbg_level > 0) {
1431 std::cout <<
"no intersection, all t2's verts above or below t1\n";
1433 return ITT_value(INONE);
1437 const mpq3 &p1 = vp1->co_exact;
1438 const mpq3 &
q1 = vq1->co_exact;
1439 const mpq3 &r1 = vr1->co_exact;
1440 const mpq3 &p2 = vp2->co_exact;
1441 const mpq3 &q2 = vq2->co_exact;
1442 const mpq3 &r2 = vr2->co_exact;
1444 const mpq3 &n2 = tri2.plane->norm_exact;
1448 sp1 = sgn(math::dot_with_buffer(buf[0], n2, buf[1]));
1453 sq1 = sgn(math::dot_with_buffer(buf[0], n2, buf[1]));
1458 sr1 = sgn(math::dot_with_buffer(buf[0], n2, buf[1]));
1461 if (dbg_level > 1) {
1462 std::cout <<
" sp1=" << sp1 <<
" sq1=" << sq1 <<
" sr1=" << sr1 <<
"\n";
1465 if ((sp1 * sq1 > 0) && (sp1 * sr1 > 0)) {
1466 if (dbg_level > 0) {
1467 std::cout <<
"no intersection, all t1's verts above or below t2 (exact)\n";
1472 return ITT_value(INONE);
1476 const mpq3 &n1 = tri1.plane->norm_exact;
1480 sp2 = sgn(math::dot_with_buffer(buf[0], n1, buf[1]));
1485 sq2 = sgn(math::dot_with_buffer(buf[0], n1, buf[1]));
1490 sr2 = sgn(math::dot_with_buffer(buf[0], n1, buf[1]));
1493 if (dbg_level > 1) {
1494 std::cout <<
" sp2=" << sp2 <<
" sq2=" << sq2 <<
" sr2=" << sr2 <<
"\n";
1497 if ((sp2 * sq2 > 0) && (sp2 * sr2 > 0)) {
1498 if (dbg_level > 0) {
1499 std::cout <<
"no intersection, all t2's verts above or below t1 (exact)\n";
1504 return ITT_value(INONE);
1513 ans = itt_canon1(r1, p1,
q1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1516 ans = itt_canon1(
q1, r1, p1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1519 ans = itt_canon1(p1,
q1, r1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1524 ans = itt_canon1(r1, p1,
q1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1527 ans = itt_canon1(
q1, r1, p1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1530 ans = itt_canon1(p1,
q1, r1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1536 ans = itt_canon1(
q1, r1, p1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1539 ans = itt_canon1(p1,
q1, r1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1544 ans = itt_canon1(p1,
q1, r1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1547 ans = itt_canon1(
q1, r1, p1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1552 ans = itt_canon1(r1, p1,
q1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1555 ans = itt_canon1(r1, p1,
q1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1558 if (dbg_level > 0) {
1559 std::cout <<
"triangles are co-planar\n";
1561 ans = ITT_value(ICOPLANAR);
1565 if (ans.kind == ICOPLANAR) {
1570 if (ans.kind != INONE) {
1578 const Plane *t_plane;
1580 Vector<std::pair<int, int>> edge;
1581 Vector<Vector<int>> face;
1583 Vector<int> input_face;
1585 Vector<bool> is_reversed;
1587 CDT_result<mpq_class> cdt_out;
1591 Map<std::pair<int, int>,
int> verts_to_edge;
1598static int prepare_need_vert(CDT_data &cd,
const mpq3 &p3d)
1600 mpq2 p2d = project_3d_to_2d(p3d, cd.proj_axis);
1601 int v = cd.vert.append_and_get_index(p2d);
1612static mpq3 unproject_cdt_vert(
const CDT_data &cd,
const mpq2 &p2d)
1616 BLI_assert(cd.t_plane->norm_exact[cd.proj_axis] != 0);
1617 const mpq3 &n = cd.t_plane->norm_exact;
1618 const mpq_class &d = cd.t_plane->d_exact;
1619 switch (cd.proj_axis) {
1621 mpq_class num = n[1] * p2d[0] + n[2] * p2d[1] + d;
1623 p3d[0] = num / n[0];
1630 mpq_class num = n[0] * p2d[0] + n[2] * p2d[1] + d;
1632 p3d[1] = num / n[1];
1639 mpq_class num = n[0] * p2d[0] + n[1] * p2d[1] + d;
1641 p3d[2] = num / n[2];
1650static void prepare_need_edge(CDT_data &cd,
const mpq3 &p1,
const mpq3 &p2)
1652 int v1 = prepare_need_vert(cd, p1);
1653 int v2 = prepare_need_vert(cd, p2);
1654 cd.edge.append(std::pair<int, int>(v1,
v2));
1657static void prepare_need_tri(CDT_data &cd,
const IMesh &tm,
int t)
1659 const Face &tri = *tm.face(t);
1660 int v0 = prepare_need_vert(cd, tri[0]->co_exact);
1661 int v1 = prepare_need_vert(cd, tri[1]->co_exact);
1662 int v2 = prepare_need_vert(cd, tri[2]->co_exact);
1667 if (tri.plane->norm_exact[cd.proj_axis] >= 0) {
1668 rev = cd.proj_axis == 1;
1671 rev = cd.proj_axis != 1;
1673 int cd_t = cd.face.append_and_get_index(Vector<int>());
1674 cd.face[cd_t].append(v0);
1676 cd.face[cd_t].append(
v2);
1677 cd.face[cd_t].append(v1);
1680 cd.face[cd_t].append(v1);
1681 cd.face[cd_t].append(
v2);
1683 cd.input_face.append(t);
1684 cd.is_reversed.append(rev);
1687static CDT_data prepare_cdt_input(
const IMesh &tm,
int t,
const Span<ITT_value> itts)
1691 ans.t_plane = tm.face(t)->plane;
1694 prepare_need_tri(ans, tm, t);
1695 for (
const ITT_value &itt : itts) {
1700 prepare_need_vert(ans, itt.p1);
1704 prepare_need_edge(ans, itt.p1, itt.p2);
1708 prepare_need_tri(ans, tm, itt.t_source);
1716static CDT_data prepare_cdt_input_for_cluster(
const IMesh &tm,
1717 const CoplanarClusterInfo &clinfo,
1719 const Span<ITT_value> itts)
1723 const CoplanarCluster &cl = clinfo.cluster(c);
1727 ans.t_plane = tm.face(t0)->plane;
1730 for (
const int t : cl) {
1731 prepare_need_tri(ans, tm, t);
1733 for (
const ITT_value &itt : itts) {
1736 prepare_need_vert(ans, itt.p1);
1740 prepare_need_edge(ans, itt.p1, itt.p2);
1751static inline std::pair<int, int> sorted_int_pair(std::pair<int, int> pair)
1753 if (pair.first <= pair.second) {
1756 return std::pair<int, int>(pair.second, pair.first);
1763static void populate_cdt_edge_map(Map<std::pair<int, int>,
int> &verts_to_edge,
1764 const CDT_result<mpq_class> &cdt_out)
1766 verts_to_edge.reserve(cdt_out.edge.size());
1767 for (
int e : cdt_out.edge.index_range()) {
1768 std::pair<int, int> vpair = sorted_int_pair(cdt_out.edge[
e]);
1770 verts_to_edge.add(vpair,
e);
1777static void do_cdt(CDT_data &cd)
1779 constexpr int dbg_level = 0;
1780 CDT_input<mpq_class> cdt_in;
1781 cdt_in.vert = Span<mpq2>(cd.vert);
1782 cdt_in.edge = Span<std::pair<int, int>>(cd.edge);
1783 cdt_in.face = Span<Vector<int>>(cd.face);
1784 if (dbg_level > 0) {
1785 std::cout <<
"CDT input\nVerts:\n";
1786 for (
int i : cdt_in.vert.index_range()) {
1787 std::cout <<
"v" << i <<
": " << cdt_in.vert[i] <<
"=(" << cdt_in.vert[i][0].get_d() <<
","
1788 << cdt_in.vert[i][1].get_d() <<
")\n";
1790 std::cout <<
"Edges:\n";
1791 for (
int i : cdt_in.edge.index_range()) {
1792 std::cout <<
"e" << i <<
": (" << cdt_in.edge[i].first <<
", " << cdt_in.edge[i].second
1795 std::cout <<
"Tris\n";
1796 for (
int f : cdt_in.face.index_range()) {
1797 std::cout <<
"f" << f <<
": ";
1798 for (
int j : cdt_in.face[f].index_range()) {
1799 std::cout << cdt_in.face[f][j] <<
" ";
1806 constexpr int make_edge_map_threshold = 15;
1807 if (cd.cdt_out.edge.size() >= make_edge_map_threshold) {
1808 populate_cdt_edge_map(cd.verts_to_edge, cd.cdt_out);
1810 if (dbg_level > 0) {
1811 std::cout <<
"\nCDT result\nVerts:\n";
1812 for (
int i : cd.cdt_out.vert.index_range()) {
1813 std::cout <<
"v" << i <<
": " << cd.cdt_out.vert[i] <<
"=(" << cd.cdt_out.vert[i][0].get_d()
1814 <<
"," << cd.cdt_out.vert[i][1].get_d() <<
"\n";
1816 std::cout <<
"Tris\n";
1817 for (
int f : cd.cdt_out.face.index_range()) {
1818 std::cout <<
"f" << f <<
": ";
1819 for (
int j : cd.cdt_out.face[f].index_range()) {
1820 std::cout << cd.cdt_out.face[f][j] <<
" ";
1822 std::cout <<
"orig: ";
1823 for (
int j : cd.cdt_out.face_orig[f].index_range()) {
1824 std::cout << cd.cdt_out.face_orig[f][j] <<
" ";
1828 std::cout <<
"Edges\n";
1829 for (
int e : cd.cdt_out.edge.index_range()) {
1830 std::cout <<
"e" <<
e <<
": (" << cd.cdt_out.edge[
e].first <<
", "
1831 << cd.cdt_out.edge[
e].second <<
") ";
1832 std::cout <<
"orig: ";
1833 for (
int j : cd.cdt_out.edge_orig[
e].index_range()) {
1834 std::cout << cd.cdt_out.edge_orig[
e][j] <<
" ";
1851static int get_cdt_edge_orig(
1852 int i0,
int i1,
const CDT_data &cd,
const IMesh &in_tm,
bool *r_is_intersect)
1854 int foff = cd.cdt_out.face_edge_offset;
1855 *r_is_intersect =
false;
1857 if (cd.verts_to_edge.size() > 0) {
1859 std::pair<int, int> vpair = sorted_int_pair(std::pair<int, int>(i0, i1));
1860 e = cd.verts_to_edge.lookup_default(vpair, NO_INDEX);
1863 for (
int ee : cd.cdt_out.edge.index_range()) {
1864 std::pair<int, int> edge = cd.cdt_out.edge[ee];
1865 if ((edge.first == i0 && edge.second == i1) || (edge.first == i1 && edge.second == i0)) {
1871 if (
e == NO_INDEX) {
1878 int face_eorig = NO_INDEX;
1879 bool have_non_face_eorig =
false;
1880 for (
int orig_index : cd.cdt_out.edge_orig[
e]) {
1882 if (orig_index >= foff) {
1883 if (face_eorig == NO_INDEX) {
1884 int in_face_index = (orig_index / foff) - 1;
1885 int pos = orig_index % foff;
1888 int in_tm_face_index = cd.input_face[in_face_index];
1889 BLI_assert(in_tm_face_index < in_tm.face_size());
1890 const Face *facep = in_tm.face(in_tm_face_index);
1892 bool is_rev = cd.is_reversed[in_face_index];
1893 int eorig = is_rev ? facep->edge_orig[2 -
pos] : facep->edge_orig[
pos];
1894 if (eorig != NO_INDEX) {
1900 if (!have_non_face_eorig) {
1901 have_non_face_eorig =
true;
1903 if (face_eorig != NO_INDEX && have_non_face_eorig) {
1909 if (face_eorig != NO_INDEX) {
1912 if (have_non_face_eorig) {
1917 *r_is_intersect =
true;
1928static Face *cdt_tri_as_imesh_face(
1929 int cdt_out_t,
int cdt_in_t,
const CDT_data &cd,
const IMesh &tm, IMeshArena *arena)
1931 const CDT_result<mpq_class> &cdt_out = cd.cdt_out;
1932 int t_orig = tm.face(cd.input_face[cdt_in_t])->orig;
1933 BLI_assert(cdt_out.face[cdt_out_t].size() == 3);
1934 int i0 = cdt_out.face[cdt_out_t][0];
1935 int i1 = cdt_out.face[cdt_out_t][1];
1936 int i2 = cdt_out.face[cdt_out_t][2];
1937 mpq3 v0co = unproject_cdt_vert(cd, cdt_out.vert[i0]);
1938 mpq3 v1co = unproject_cdt_vert(cd, cdt_out.vert[i1]);
1939 mpq3 v2co = unproject_cdt_vert(cd, cdt_out.vert[i2]);
1943 const Vert *v0 = arena->add_or_find_vert(v0co, NO_INDEX);
1944 const Vert *v1 = arena->add_or_find_vert(v1co, NO_INDEX);
1945 const Vert *
v2 = arena->add_or_find_vert(v2co, NO_INDEX);
1950 if (cd.is_reversed[cdt_in_t]) {
1951 int oe0 = get_cdt_edge_orig(i0, i2, cd, tm, &is_isect0);
1952 int oe1 = get_cdt_edge_orig(i2, i1, cd, tm, &is_isect1);
1953 int oe2 = get_cdt_edge_orig(i1, i0, cd, tm, &is_isect2);
1954 facep = arena->add_face(
1955 {v0,
v2, v1}, t_orig, {oe0, oe1, oe2}, {is_isect0, is_isect1, is_isect2});
1958 int oe0 = get_cdt_edge_orig(i0, i1, cd, tm, &is_isect0);
1959 int oe1 = get_cdt_edge_orig(i1, i2, cd, tm, &is_isect1);
1960 int oe2 = get_cdt_edge_orig(i2, i0, cd, tm, &is_isect2);
1961 facep = arena->add_face(
1962 {v0, v1,
v2}, t_orig, {oe0, oe1, oe2}, {is_isect0, is_isect1, is_isect2});
1964 facep->populate_plane(
false);
1969static bool is_quad_flip_first_third(
const double3 &v1,
1980 return math::dot(cross_a, cross_b) > 0.0f;
1995static Array<Face *> polyfill_triangulate_poly(Face *f, IMeshArena *arena)
1998 int flen = f->size();
2000 if (!f->plane_populated()) {
2001 f->populate_plane(
false);
2003 const double3 &poly_normal = f->plane->norm;
2004 float no[3] = {
float(poly_normal[0]),
float(poly_normal[1]),
float(poly_normal[2])};
2007 const Vert *v0 = (*f)[0];
2008 const Vert *v1 = (*f)[1];
2009 const Vert *
v2 = (*f)[2];
2010 const Vert *v3 = (*f)[3];
2011 int eo_01 = f->edge_orig[0];
2012 int eo_12 = f->edge_orig[1];
2013 int eo_23 = f->edge_orig[2];
2014 int eo_30 = f->edge_orig[3];
2016 if (
UNLIKELY(is_quad_flip_first_third(v0->co, v1->co,
v2->
co, v3->co))) {
2017 f0 = arena->add_face({v0, v1, v3}, f->orig, {eo_01, -1, eo_30}, {
false,
false,
false});
2018 f1 = arena->add_face({v1,
v2, v3}, f->orig, {eo_12, eo_23, -1}, {
false,
false,
false});
2021 f0 = arena->add_face({v0, v1,
v2}, f->orig, {eo_01, eo_12, -1}, {
false,
false,
false});
2022 f1 = arena->add_face({v0,
v2, v3}, f->orig, {-1, eo_23, eo_30}, {
false,
false,
false});
2024 return Array<Face *>{f0, f1};
2027 float axis_mat[3][3];
2028 float(*projverts)[2];
2030 const int totfilltri = flen - 2;
2033 projverts =
static_cast<float(*)[2]
>(
MEM_malloc_arrayN(flen,
sizeof(*projverts), __func__));
2035 for (
int j = 0; j < flen; ++j) {
2036 const double3 &dco = (*f)[j]->co;
2042 Array<Face *> ans(totfilltri);
2043 for (
int t = 0; t < totfilltri; ++t) {
2044 uint *tri = tris[t];
2047 for (
int k = 0; k < 3; k++) {
2049 v[k] = (*f)[tri[k]];
2052 if ((tri[k] + 1) % flen == tri[(k + 1) % 3]) {
2053 eo[k] = f->edge_orig[tri[k]];
2058 ans[t] = arena->add_face(
2059 {
v[0],
v[1],
v[2]}, f->orig, {eo[0], eo[1], eo[2]}, {
false,
false,
false});
2084static Array<Face *> exact_triangulate_poly(Face *f, IMeshArena *arena)
2086 int flen = f->size();
2087 Array<mpq2> in_verts(flen);
2088 Array<Vector<int>>
faces(1);
2089 faces.first().resize(flen);
2090 std::iota(faces.first().begin(), faces.first().end(), 0);
2093 if (!f->plane_populated()) {
2094 f->populate_plane(
false);
2096 const double3 &poly_normal = f->plane->norm;
2102 bool rev1 = (axis == 1);
2103 bool rev2 = poly_normal[axis] < 0;
2104 bool rev = rev1 ^ rev2;
2105 for (
int i = 0; i < flen; ++i) {
2106 int ii = rev ? flen - i - 1 : i;
2107 mpq2 &p2d = in_verts[ii];
2109 for (
int j = 0; j < 3; ++j) {
2111 p2d[k++] = (*f)[ii]->co_exact[j];
2116 CDT_input<mpq_class> cdt_in;
2117 cdt_in.vert = std::move(in_verts);
2118 cdt_in.face = std::move(faces);
2121 int n_tris = cdt_out.face.size();
2122 Array<Face *> ans(n_tris);
2123 for (
int t = 0; t < n_tris; ++t) {
2127 bool needs_steiner =
false;
2128 for (
int i = 0; i < 3; ++i) {
2129 i_v_out[i] = cdt_out.face[t][i];
2130 if (cdt_out.vert_orig[i_v_out[i]].is_empty()) {
2131 needs_steiner =
true;
2134 v[i] = (*f)[cdt_out.vert_orig[i_v_out[i]][0]];
2136 if (needs_steiner) {
2138 return polyfill_triangulate_poly(f, arena);
2140 Map<std::pair<int, int>,
int> verts_to_edge;
2141 populate_cdt_edge_map(verts_to_edge, cdt_out);
2142 int foff = cdt_out.face_edge_offset;
2143 for (
int i = 0; i < 3; ++i) {
2144 std::pair<int, int> vpair(i_v_out[i], i_v_out[(i + 1) % 3]);
2145 std::pair<int, int> vpair_canon = sorted_int_pair(vpair);
2146 int e_out = verts_to_edge.lookup_default(vpair_canon, NO_INDEX);
2149 for (
int orig : cdt_out.edge_orig[e_out]) {
2151 int pos = orig % foff;
2153 eo[i] = f->edge_orig[
pos];
2159 ans[t] = arena->add_face(
2160 {
v[0],
v[2],
v[1]}, f->orig, {eo[2], eo[1], eo[0]}, {
false,
false,
false});
2163 ans[t] = arena->add_face(
2164 {
v[0],
v[1],
v[2]}, f->orig, {eo[0], eo[1], eo[2]}, {
false,
false,
false});
2170static bool face_is_degenerate(
const Face *f)
2172 const Face &face = *f;
2173 const Vert *v0 = face[0];
2174 const Vert *v1 = face[1];
2175 const Vert *
v2 = face[2];
2176 if (v0 == v1 || v0 ==
v2 || v1 ==
v2) {
2183 double err_bound = supremum_dot_cross(dab, dab) * index_dot_cross * DBL_EPSILON;
2184 if (dab_length_squared > err_bound) {
2187 mpq3 a =
v2->co_exact - v0->co_exact;
2188 mpq3
b =
v2->co_exact - v1->co_exact;
2190 if (ab.x == 0 && ab.y == 0 && ab.z == 0) {
2198static bool any_degenerate_tris_fast(
const Array<Face *> triangulation)
2200 for (
const Face *f : triangulation) {
2201 const Vert *v0 = (*f)[0];
2202 const Vert *v1 = (*f)[1];
2203 const Vert *
v2 = (*f)[2];
2204 if (v0 == v1 || v0 ==
v2 || v1 ==
v2) {
2211 if (da_length_squared == 0.0 || db_length_squared == 0.0) {
2220 double sin_squared_t = dab_length_squared / (da_length_squared * db_length_squared);
2221 if (sin_squared_t < 1
e-8) {
2236static Array<Face *> triangulate_poly(Face *f, IMeshArena *arena)
2239 Array<Face *> ans = polyfill_triangulate_poly(f, arena);
2242 if (any_degenerate_tris_fast(ans)) {
2243 return exact_triangulate_poly(f, arena);
2248IMesh triangulate_polymesh(IMesh &imesh, IMeshArena *arena)
2250 Vector<Face *> face_tris;
2251 constexpr int estimated_tris_per_face = 3;
2252 face_tris.reserve(estimated_tris_per_face * imesh.face_size());
2253 threading::parallel_for(imesh.face_index_range(), 2048, [&](IndexRange range) {
2254 for (int i : range) {
2255 Face *f = imesh.face(i);
2256 if (!f->plane_populated() && f->size() >= 4) {
2257 f->populate_plane(false);
2261 for (Face *f : imesh.faces()) {
2263 int flen = f->size();
2265 face_tris.append(f);
2268 Array<Face *> tris = triangulate_poly(f, arena);
2269 for (Face *tri : tris) {
2270 face_tris.append(tri);
2274 return IMesh(face_tris);
2281static IMesh extract_subdivided_tri(
const CDT_data &cd,
2286 const CDT_result<mpq_class> &cdt_out = cd.cdt_out;
2288 for (
int i = 0; i < cd.input_face.size(); ++i) {
2289 if (cd.input_face[i] == t) {
2293 if (t_in_cdt == -1) {
2294 std::cout <<
"Could not find " << t <<
" in cdt input tris\n";
2298 constexpr int inline_buf_size = 20;
2299 Vector<Face *, inline_buf_size>
faces;
2300 for (
int f : cdt_out.face.index_range()) {
2301 if (cdt_out.face_orig[f].contains(t_in_cdt)) {
2302 Face *facep = cdt_tri_as_imesh_face(f, t_in_cdt, cd, in_tm, arena);
2303 faces.append(facep);
2306 return IMesh(faces);
2311 if (a.indexA <
b.indexA) {
2314 if ((a.indexA ==
b.indexA) && (a.indexB <
b.indexB)) {
2323 Array<int> first_overlap_;
2324 uint overlap_num_{0};
2328 std::function<
int(
int)> shape_fn;
2334 TriOverlaps(
const IMesh &tm,
2335 const Span<BoundingBox> tri_bb,
2337 std::function<
int(
int)> shape_fn,
2340 constexpr int dbg_level = 0;
2341 if (dbg_level > 0) {
2342 std::cout <<
"TriOverlaps construction\n";
2348 bool two_trees_no_self = nshapes == 2 && !use_self;
2349 if (two_trees_no_self) {
2355 shapes.resize(tm.face_size());
2356 threading::parallel_for(tm.face_index_range(), 2048, [&](IndexRange range) {
2357 for (int t : range) {
2358 shapes[t] = shape_fn(tm.face(t)->orig);
2363 for (
int t : tm.face_index_range()) {
2367 int shape = shapes[t];
2368 if (two_trees_no_self) {
2372 else if (shape == 1) {
2383 if (two_trees_no_self) {
2389 CBData cbdata{tm, shape_fn, nshapes, use_self};
2395 tree_, tree_, &overlap_num_, only_different_shapes, &cbdata);
2401 if (two_trees_no_self) {
2403 MEM_reallocN(overlap_, 2 * overlap_num_ *
sizeof(overlap_[0])));
2404 for (
uint i = 0; i < overlap_num_; ++i) {
2405 overlap_[overlap_num_ + i].
indexA = overlap_[i].indexB;
2406 overlap_[overlap_num_ + i].indexB = overlap_[i].indexA;
2408 overlap_num_ += overlap_num_;
2411 std::sort(overlap_, overlap_ + overlap_num_, bvhtreeverlap_cmp);
2412 if (dbg_level > 0) {
2413 std::cout << overlap_num_ <<
" overlaps found:\n";
2415 std::cout <<
"A: " << ov.indexA <<
", B: " << ov.indexB <<
"\n";
2418 first_overlap_ = Array<int>(tm.face_size(), -1);
2419 for (
int i = 0; i <
int(overlap_num_); ++i) {
2420 int t = overlap_[i].indexA;
2421 if (first_overlap_[t] == -1) {
2422 first_overlap_[t] = i;
2440 Span<BVHTreeOverlap> overlap()
const
2442 return Span<BVHTreeOverlap>(overlap_, overlap_num_);
2445 int first_overlap_index(
int t)
const
2447 return first_overlap_[t];
2451 static bool only_different_shapes(
void *userdata,
int index_a,
int index_b,
int )
2454 return cbdata->tm.face(index_a)->orig != cbdata->tm.face(index_b)->orig;
2461struct OverlapIttsData {
2462 Vector<std::pair<int, int>> intersect_pairs;
2463 Map<std::pair<int, int>, ITT_value> &itt_map;
2467 OverlapIttsData(Map<std::pair<int, int>, ITT_value> &itt_map,
const IMesh &tm, IMeshArena *arena)
2468 : itt_map(itt_map), tm(tm), arena(arena)
2477static std::pair<int, int> canon_int_pair(
int a,
int b)
2482 return std::pair<int, int>(a,
b);
2485static void calc_overlap_itts_range_func(
void *__restrict userdata,
2489 constexpr int dbg_level = 0;
2490 OverlapIttsData *data =
static_cast<OverlapIttsData *
>(userdata);
2491 std::pair<int, int> tri_pair = data->intersect_pairs[iter];
2492 int a = tri_pair.first;
2493 int b = tri_pair.second;
2494 if (dbg_level > 0) {
2495 std::cout <<
"calc_overlap_itts_range_func a=" << a <<
", b=" <<
b <<
"\n";
2497 ITT_value itt = intersect_tri_tri(data->tm, a,
b);
2498 if (dbg_level > 0) {
2499 std::cout <<
"result of intersecting " << a <<
" and " <<
b <<
" = " << itt <<
"\n";
2501 BLI_assert(data->itt_map.contains(tri_pair));
2502 data->itt_map.add_overwrite(tri_pair, itt);
2509static void calc_overlap_itts(Map<std::pair<int, int>, ITT_value> &itt_map,
2511 const TriOverlaps &ov,
2514 OverlapIttsData
data(itt_map, tm, arena);
2519 std::pair<int, int> key = canon_int_pair(olap.indexA, olap.indexB);
2520 if (!itt_map.contains(key)) {
2521 itt_map.add_new(key, ITT_value());
2522 data.intersect_pairs.append(key);
2525 int tot_intersect_pairs = data.intersect_pairs.size();
2528 settings.min_iter_per_thread = 1000;
2529 settings.use_threading = intersect_use_threading;
2539static void calc_subdivided_non_cluster_tris(Array<IMesh> &r_tri_subdivided,
2541 const Map<std::pair<int, int>, ITT_value> &itt_map,
2542 const CoplanarClusterInfo &clinfo,
2543 const TriOverlaps &ov,
2546 const int dbg_level = 0;
2547 if (dbg_level > 0) {
2548 std::cout <<
"\nCALC_SUBDIVIDED_TRIS\n\n";
2550 Span<BVHTreeOverlap> overlap = ov.overlap();
2551 struct OverlapTriRange {
2556 Vector<OverlapTriRange> overlap_tri_range;
2557 int overlap_num = overlap.size();
2558 overlap_tri_range.reserve(overlap_num);
2559 int overlap_index = 0;
2560 while (overlap_index < overlap_num) {
2561 int t = overlap[overlap_index].indexA;
2562 int i = overlap_index;
2563 while (i + 1 < overlap_num && overlap[i + 1].indexA == t) {
2569 if (clinfo.tri_cluster(t) == NO_INDEX) {
2570 int len = i - overlap_index + 1;
2571 if (!(
len == 1 && overlap[overlap_index].indexB == t)) {
2572 OverlapTriRange range = {t, overlap_index,
len};
2573 overlap_tri_range.append(range);
2575 bumpperfcount(0,
len);
2579 overlap_index = i + 1;
2581 int overlap_tri_range_num = overlap_tri_range.size();
2582 Array<CDT_data> cd_data(overlap_tri_range_num);
2583 int grain_size = 64;
2584 threading::parallel_for(overlap_tri_range.index_range(), grain_size, [&](IndexRange range) {
2585 for (int otr_index : range) {
2586 OverlapTriRange &otr = overlap_tri_range[otr_index];
2587 int t = otr.tri_index;
2588 if (dbg_level > 0) {
2589 std::cout <<
"handling overlap range\nt=" << t <<
" start=" << otr.overlap_start
2590 <<
" len=" << otr.len <<
"\n";
2592 constexpr int inline_capacity = 100;
2593 Vector<ITT_value, inline_capacity> itts(otr.len);
2594 for (int j = otr.overlap_start; j < otr.overlap_start + otr.len; ++j) {
2595 int t_other = overlap[j].indexB;
2596 std::pair<int, int> key = canon_int_pair(t, t_other);
2598 if (itt_map.contains(key)) {
2599 itt = itt_map.lookup(key);
2601 if (itt.kind != INONE) {
2604 if (dbg_level > 0) {
2605 std::cout <<
" tri t" << t_other <<
"; result = " << itt <<
"\n";
2608 if (itts.size() > 0) {
2609 cd_data[otr_index] = prepare_cdt_input(tm, t, itts);
2610 do_cdt(cd_data[otr_index]);
2615 for (
int otr_index : overlap_tri_range.index_range()) {
2616 CDT_data &cdd = cd_data[otr_index];
2617 if (cdd.vert.size() > 0) {
2618 int t = overlap_tri_range[otr_index].tri_index;
2619 r_tri_subdivided[t] = extract_subdivided_tri(cdd, tm, t, arena);
2620 if (dbg_level > 1) {
2621 std::cout <<
"subdivide output for tri " << t <<
" = " << r_tri_subdivided[t];
2627 threading::parallel_for(tm.face_index_range(), 2048, [&](IndexRange range) {
2628 for (int t : range) {
2629 if (r_tri_subdivided[t].face_size() == 0 && clinfo.tri_cluster(t) == NO_INDEX) {
2630 r_tri_subdivided[t] = IMesh({tm.face(t)});
2643static void calc_cluster_tris(Array<IMesh> &tri_subdivided,
2645 const CoplanarClusterInfo &clinfo,
2646 const Span<CDT_data> cluster_subdivided,
2649 for (
int c : clinfo.index_range()) {
2650 const CoplanarCluster &cl = clinfo.cluster(c);
2651 const CDT_data &cd = cluster_subdivided[c];
2659 int n_cluster_tris = cl.tot_tri();
2660 const CDT_result<mpq_class> &cdt_out = cd.cdt_out;
2661 BLI_assert(cd.input_face.size() == n_cluster_tris);
2662 Array<Vector<Face *>> face_vec(n_cluster_tris);
2663 for (
int cdt_out_t : cdt_out.face.index_range()) {
2664 for (
int cdt_in_t : cdt_out.face_orig[cdt_out_t]) {
2665 Face *f = cdt_tri_as_imesh_face(cdt_out_t, cdt_in_t, cd, tm, arena);
2666 face_vec[cdt_in_t].append(f);
2669 for (
int cdt_in_t : cd.input_face.index_range()) {
2670 int tm_t = cd.input_face[cdt_in_t];
2671 BLI_assert(tri_subdivided[tm_t].face_size() == 0);
2672 tri_subdivided[tm_t] = IMesh(face_vec[cdt_in_t]);
2677static CDT_data calc_cluster_subdivided(
const CoplanarClusterInfo &clinfo,
2680 const TriOverlaps &ov,
2681 const Map<std::pair<int, int>, ITT_value> &itt_map,
2684 constexpr int dbg_level = 0;
2686 const CoplanarCluster &cl = clinfo.cluster(c);
2688 if (dbg_level > 0) {
2689 std::cout <<
"CALC_CLUSTER_SUBDIVIDED for cluster " << c <<
" = " << cl <<
"\n";
2694 Vector<ITT_value> itts;
2695 Span<BVHTreeOverlap> ovspan = ov.overlap();
2697 if (dbg_level > 0) {
2698 std::cout <<
"find intersects with triangle " << t <<
" of cluster\n";
2700 int first_i = ov.first_overlap_index(t);
2701 if (first_i == -1) {
2704 for (
int i = first_i; i < ovspan.size() && ovspan[i].indexA == t; ++i) {
2705 int t_other = ovspan[i].indexB;
2706 if (clinfo.tri_cluster(t_other) != c) {
2707 if (dbg_level > 0) {
2708 std::cout <<
"use intersect(" << t <<
"," << t_other <<
"\n";
2710 std::pair<int, int> key = canon_int_pair(t, t_other);
2711 if (itt_map.contains(key)) {
2712 ITT_value itt = itt_map.lookup(key);
2713 if (!
ELEM(itt.kind, INONE, ICOPLANAR)) {
2715 if (dbg_level > 0) {
2716 std::cout <<
" itt = " << itt <<
"\n";
2724 CDT_data cd_data = prepare_cdt_input_for_cluster(tm, clinfo, c, itts);
2732 for (
const IMesh &m : tri_subdivided) {
2733 tot_tri += m.face_size();
2735 Array<Face *>
faces(tot_tri);
2737 for (
const IMesh &m : tri_subdivided) {
2738 for (Face *f : m.faces()) {
2739 faces[face_index++] = f;
2742 return IMesh(faces);
2745static CoplanarClusterInfo find_clusters(
const IMesh &tm,
2746 const Array<BoundingBox> &tri_bb,
2747 const Map<std::pair<int, int>, ITT_value> &itt_map)
2749 constexpr int dbg_level = 0;
2750 if (dbg_level > 0) {
2751 std::cout <<
"FIND_CLUSTERS\n";
2753 CoplanarClusterInfo ans(tm.face_size());
2755 VectorSet<int> maybe_coplanar_tris;
2756 maybe_coplanar_tris.reserve(2 * itt_map.size());
2757 for (
auto item : itt_map.items()) {
2758 if (item.value.kind == ICOPLANAR) {
2759 int t1 = item.key.first;
2760 int t2 = item.key.second;
2761 maybe_coplanar_tris.add_multiple({t1, t2});
2764 if (dbg_level > 0) {
2765 std::cout <<
"found " << maybe_coplanar_tris.size() <<
" possible coplanar tris\n";
2767 if (maybe_coplanar_tris.is_empty()) {
2768 if (dbg_level > 0) {
2769 std::cout <<
"No possible coplanar tris, so no clusters\n";
2776 Map<Plane, Vector<CoplanarCluster>> plane_cls;
2777 plane_cls.reserve(maybe_coplanar_tris.size());
2778 for (
int t : maybe_coplanar_tris) {
2782 Plane tplane = *tm.face(t)->plane;
2784 tplane.make_canonical();
2785 if (dbg_level > 0) {
2786 std::cout <<
"plane for tri " << t <<
" = " << &tplane <<
"\n";
2789 if (plane_cls.contains(tplane)) {
2790 Vector<CoplanarCluster> &curcls = plane_cls.lookup(tplane);
2791 if (dbg_level > 0) {
2792 std::cout <<
"already has " << curcls.size() <<
" clusters\n";
2795 Vector<CoplanarCluster *> int_cls;
2796 Vector<CoplanarCluster *> no_int_cls;
2797 for (CoplanarCluster &cl : curcls) {
2798 if (dbg_level > 1) {
2799 std::cout <<
"consider intersecting with cluster " << cl <<
"\n";
2801 if (bbs_might_intersect(tri_bb[t], cl.bounding_box())) {
2802 if (dbg_level > 1) {
2803 std::cout <<
"append to int_cls\n";
2805 int_cls.append(&cl);
2808 if (dbg_level > 1) {
2809 std::cout <<
"append to no_int_cls\n";
2811 no_int_cls.append(&cl);
2814 if (int_cls.is_empty()) {
2816 if (dbg_level > 1) {
2817 std::cout <<
"no intersecting clusters for t, make a new one\n";
2819 curcls.append(CoplanarCluster(t, tri_bb[t]));
2821 else if (int_cls.size() == 1) {
2823 if (dbg_level > 1) {
2824 std::cout <<
"exactly one existing cluster, " << int_cls[0] <<
", adding to it\n";
2826 int_cls[0]->add_tri(t, tri_bb[t]);
2831 if (dbg_level > 1) {
2832 std::cout <<
"merging\n";
2834 CoplanarCluster mergecl;
2835 mergecl.add_tri(t, tri_bb[t]);
2836 for (CoplanarCluster *cl : int_cls) {
2838 mergecl.add_tri(t, tri_bb[t]);
2841 Vector<CoplanarCluster> newvec;
2842 newvec.append(mergecl);
2843 for (CoplanarCluster *cl_no_int : no_int_cls) {
2844 newvec.append(*cl_no_int);
2846 plane_cls.add_overwrite(tplane, newvec);
2850 if (dbg_level > 0) {
2851 std::cout <<
"first cluster for its plane\n";
2853 plane_cls.add_new(tplane, Vector<CoplanarCluster>{CoplanarCluster(t, tri_bb[t])});
2858 for (
auto item : plane_cls.items()) {
2859 for (
const CoplanarCluster &cl : item.value) {
2860 if (cl.tot_tri() > 1) {
2861 ans.add_cluster(cl);
2874struct DegenChunkData {
2875 bool has_degenerate_tri =
false;
2878static void degenerate_range_func(
void *__restrict userdata,
2882 DegenData *data =
static_cast<DegenData *
>(userdata);
2883 DegenChunkData *chunk_data =
static_cast<DegenChunkData *
>(tls->userdata_chunk);
2884 const Face *f = data->tm.face(iter);
2885 bool is_degenerate = face_is_degenerate(f);
2886 chunk_data->has_degenerate_tri |= is_degenerate;
2889static void degenerate_reduce(
const void *__restrict ,
2890 void *__restrict chunk_join,
2891 void *__restrict chunk)
2893 DegenChunkData *degen_chunk_join =
static_cast<DegenChunkData *
>(chunk_join);
2894 DegenChunkData *degen_chunk =
static_cast<DegenChunkData *
>(chunk);
2895 degen_chunk_join->has_degenerate_tri |= degen_chunk->has_degenerate_tri;
2899static bool has_degenerate_tris(
const IMesh &tm)
2901 DegenData degen_data = {tm};
2902 DegenChunkData degen_chunk_data;
2905 settings.userdata_chunk = °en_chunk_data;
2906 settings.userdata_chunk_size =
sizeof(degen_chunk_data);
2907 settings.func_reduce = degenerate_reduce;
2908 settings.min_iter_per_thread = 1000;
2909 settings.use_threading = intersect_use_threading;
2911 return degen_chunk_data.has_degenerate_tri;
2914static IMesh remove_degenerate_tris(
const IMesh &tm_in)
2917 Vector<Face *> new_faces;
2918 new_faces.reserve(tm_in.face_size());
2919 for (Face *f : tm_in.faces()) {
2920 if (!face_is_degenerate(f)) {
2921 new_faces.append(f);
2924 ans.set_faces(new_faces);
2928IMesh trimesh_self_intersect(
const IMesh &tm_in, IMeshArena *arena)
2930 return trimesh_nary_intersect(
2931 tm_in, 1, [](
int ) {
return 0; },
true, arena);
2934IMesh trimesh_nary_intersect(
const IMesh &tm_in,
2936 const FunctionRef<
int(
int)> shape_fn,
2940 constexpr int dbg_level = 0;
2941 if (dbg_level > 0) {
2942 std::cout <<
"\nTRIMESH_NARY_INTERSECT nshapes=" << nshapes <<
" use_self=" << use_self
2944 for (
const Face *f : tm_in.faces()) {
2948 if (dbg_level > 1) {
2949 std::cout <<
"input mesh:\n" << tm_in;
2950 for (
int t : tm_in.face_index_range()) {
2951 std::cout <<
"shape(" << t <<
") = " << shape_fn(tm_in.face(t)->orig) <<
"\n";
2953 write_obj_mesh(
const_cast<IMesh &
>(tm_in),
"trimesh_input");
2959 std::cout <<
"trimesh_nary_intersect start\n";
2963 const IMesh *tm_clean = &tm_in;
2965 if (has_degenerate_tris(tm_in)) {
2966 if (dbg_level > 0) {
2967 std::cout <<
"cleaning degenerate triangles\n";
2969 tm_cleaned = remove_degenerate_tris(tm_in);
2970 tm_clean = &tm_cleaned;
2971 if (dbg_level > 1) {
2972 std::cout <<
"cleaned input mesh:\n" << tm_cleaned;
2977 std::cout <<
"cleaned, time = " << clean_time - start_time <<
"\n";
2979 Array<BoundingBox> tri_bb = calc_face_bounding_boxes(*tm_clean);
2982 std::cout <<
"bbs calculated, time = " << bb_calc_time - clean_time <<
"\n";
2984 TriOverlaps tri_ov(*tm_clean, tri_bb, nshapes, shape_fn, use_self);
2987 std::cout <<
"intersect overlaps calculated, time = " << overlap_time - bb_calc_time <<
"\n";
2989 Array<IMesh> tri_subdivided(tm_clean->face_size(), NoInitialization());
2990 threading::parallel_for(tm_clean->face_index_range(), 1024, [&](IndexRange range) {
2991 for (int t : range) {
2992 if (tri_ov.first_overlap_index(t) != -1) {
2993 tm_clean->face(t)->populate_plane(true);
2995 new (static_cast<void *>(&tri_subdivided[t])) IMesh;
3000 std::cout <<
"planes populated, time = " << plane_populate - overlap_time <<
"\n";
3004 Map<std::pair<int, int>, ITT_value> itt_map;
3005 itt_map.reserve(tri_ov.overlap().size());
3006 calc_overlap_itts(itt_map, *tm_clean, tri_ov, arena);
3009 std::cout <<
"itts found, time = " << itt_time - plane_populate <<
"\n";
3011 CoplanarClusterInfo clinfo = find_clusters(*tm_clean, tri_bb, itt_map);
3012 if (dbg_level > 1) {
3013 std::cout << clinfo;
3017 std::cout <<
"clusters found, time = " << find_cluster_time - itt_time <<
"\n";
3018 doperfmax(0, tm_in.face_size());
3019 doperfmax(1, clinfo.tot_cluster());
3020 doperfmax(2, tri_ov.overlap().size());
3022 calc_subdivided_non_cluster_tris(tri_subdivided, *tm_clean, itt_map, clinfo, tri_ov, arena);
3025 std::cout <<
"subdivided non-cluster tris found, time = " << subdivided_tris_time - itt_time
3028 Array<CDT_data> cluster_subdivided(clinfo.tot_cluster());
3029 for (
int c : clinfo.index_range()) {
3030 cluster_subdivided[c] = calc_cluster_subdivided(clinfo, c, *tm_clean, tri_ov, itt_map, arena);
3034 std::cout <<
"subdivided clusters found, time = "
3035 << cluster_subdivide_time - subdivided_tris_time <<
"\n";
3037 calc_cluster_tris(tri_subdivided, *tm_clean, clinfo, cluster_subdivided, arena);
3040 std::cout <<
"subdivided cluster tris found, time = " << extract_time - cluster_subdivide_time
3043 IMesh combined = union_tri_subdivides(tri_subdivided);
3044 if (dbg_level > 1) {
3045 std::cout <<
"TRIMESH_NARY_INTERSECT answer:\n";
3046 std::cout << combined;
3050 std::cout <<
"triangles combined, time = " << end_time - extract_time <<
"\n";
3051 std::cout <<
"trimesh_nary_intersect done, total time = " << end_time - start_time <<
"\n";
3057static std::ostream &
operator<<(std::ostream &os,
const CoplanarCluster &cl)
3061 for (
const int t : cl) {
3074static std::ostream &
operator<<(std::ostream &os,
const CoplanarClusterInfo &clinfo)
3076 os <<
"Coplanar Cluster Info:\n";
3077 for (
int c : clinfo.index_range()) {
3078 os << c <<
": " << clinfo.cluster(c) <<
"\n";
3083static std::ostream &
operator<<(std::ostream &os,
const ITT_value &itt)
3090 os <<
"point " << itt.p1;
3093 os <<
"segment " << itt.p1 <<
" " << itt.p2;
3096 os <<
"co-planar t" << itt.t_source;
3102void write_obj_mesh(IMesh &m,
const std::string &objname)
3110 const char *objdir =
"/tmp/";
3112 if (m.face_size() == 0) {
3116 std::string fname = std::string(objdir) + objname + std::string(
".obj");
3120 std::cout <<
"Could not open file " << fname <<
"\n";
3124 if (!m.has_verts()) {
3127 for (
const Vert *
v : m.vertices()) {
3129 f <<
"v " << dv[0] <<
" " << dv[1] <<
" " << dv[2] <<
"\n";
3131 for (
const Face *face : m.faces()) {
3134 for (
const Vert *
v : *face) {
3135 int i = m.lookup_vert(
v);
3148 Vector<const char *> count_name;
3150 Vector<const char *> max_name;
3153static PerfCounts *perfdata =
nullptr;
3155static void perfdata_init()
3157 perfdata =
new PerfCounts;
3160 perfdata->count.append(0);
3161 perfdata->count_name.append(
"Non-cluster overlaps");
3164 perfdata->count.append(0);
3165 perfdata->count_name.append(
"intersect_tri_tri calls");
3168 perfdata->count.append(0);
3169 perfdata->count_name.append(
"tri tri intersects decided by filter plane tests");
3172 perfdata->count.append(0);
3173 perfdata->count_name.append(
"tri tri intersects decided by exact plane tests");
3176 perfdata->count.append(0);
3177 perfdata->count_name.append(
"final non-NONE intersects");
3180 perfdata->max.append(0);
3181 perfdata->max_name.append(
"total faces");
3184 perfdata->max.append(0);
3185 perfdata->max_name.append(
"total clusters");
3188 perfdata->max.append(0);
3189 perfdata->max_name.append(
"total overlaps");
3192static void incperfcount(
int countnum)
3194 perfdata->count[countnum]++;
3197static void bumpperfcount(
int countnum,
int amt)
3199 perfdata->count[countnum] += amt;
3202static void doperfmax(
int maxnum,
int val)
3204 perfdata->max[maxnum] =
max_ii(perfdata->max[maxnum], val);
3207static void dump_perfdata()
3209 std::cout <<
"\nPERFDATA\n";
3210 for (
int i : perfdata->
count.index_range()) {
3211 std::cout << perfdata->count_name[i] <<
" = " << perfdata->count[i] <<
"\n";
3213 for (
int i : perfdata->max.index_range()) {
3214 std::cout << perfdata->max_name[i] <<
" = " << perfdata->max[i] <<
"\n";
BVHTree * BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
void BLI_bvhtree_balance(BVHTree *tree)
void BLI_bvhtree_free(BVHTree *tree)
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints)
BVHTreeOverlap * BLI_bvhtree_overlap(const BVHTree *tree1, const BVHTree *tree2, unsigned int *r_overlap_num, BVHTree_OverlapCallback callback, void *userdata)
MINLINE int max_ii(int a, int b)
MINLINE double max_dd(double a, double b)
bool isect_aabb_aabb_v3(const float min1[3], const float max1[3], const float min2[3], const float max2[3])
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
const char * BLI_getenv(const char *env) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
void BLI_polyfill_calc(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3])
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
pthread_spinlock_t SpinLock
void BLI_mutex_free(ThreadMutex *mutex)
ThreadMutex * BLI_mutex_alloc(void)
void BLI_mutex_lock(ThreadMutex *mutex)
void BLI_mutex_unlock(ThreadMutex *mutex)
void BLI_spin_init(SpinLock *spin)
void BLI_spin_unlock(SpinLock *spin)
void BLI_spin_lock(SpinLock *spin)
pthread_mutex_t ThreadMutex
void BLI_spin_end(SpinLock *spin)
double BLI_time_now_seconds(void)
#define UNUSED_VARS_NDEBUG(...)
#define MEM_reallocN(vmemh, len)
bool operator==(const AssetWeakReference &a, const AssetWeakReference &b)
int pad[32 - sizeof(int)]
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
local_group_size(16, 16) .push_constant(Type b
blender::meshintersect::CDT_result< double > delaunay_2d_calc(const CDT_input< double > &input, CDT_output_type output_type)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
ccl_device_inline float2 fabs(const float2 a)
GAttributeReader lookup(const void *owner, const StringRef attribute_id)
T length_squared(const VecBase< T, Size > &a)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
int dominant_axis(const VecBase< T, 3 > &a)
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)
VecBase< double, 3 > double3
unsigned __int64 uint64_t
std::ostream & operator<<(std::ostream &stream, bUUID uuid)