59 static void perfdata_init(
void);
60 static void incperfcount(
int countnum);
61 static void bumpperfcount(
int countnum,
int amt);
62 static void doperfmax(
int maxnum,
int val);
63 static void dump_perfdata(
void);
67 static constexpr
bool intersect_use_threading =
true;
69 Vert::Vert(
const mpq3 &mco,
const double3 &dco,
int id,
int orig)
70 : co_exact(mco), co(dco),
id(
id), orig(orig)
76 return this->co_exact == other.co_exact;
84 x = (
x >> 56) ^ (
x >> 46) ^
x;
85 y = (
y >> 55) ^ (
y >> 45) ^
y;
86 z = (
z >> 54) ^ (
z >> 44) ^
z;
92 constexpr
int dbg_level = 0;
94 if (
v->orig != NO_INDEX) {
99 os <<
"=" <<
v->co_exact;
106 return norm_exact == other.norm_exact && d_exact == other.d_exact;
109 void Plane::make_canonical()
111 if (norm_exact[0] != 0) {
112 mpq_class den = norm_exact[0];
113 norm_exact = mpq3(1, norm_exact[1] / den, norm_exact[2] / den);
114 d_exact = d_exact / den;
116 else if (norm_exact[1] != 0) {
117 mpq_class den = norm_exact[1];
118 norm_exact = mpq3(0, 1, norm_exact[2] / den);
119 d_exact = d_exact / den;
122 if (norm_exact[2] != 0) {
123 mpq_class den = norm_exact[2];
124 norm_exact = mpq3(0, 0, 1);
125 d_exact = d_exact / den;
132 norm = double3(norm_exact[0].get_d(), norm_exact[1].get_d(), norm_exact[2].get_d());
136 Plane::Plane(
const mpq3 &norm_exact,
const mpq_class &d_exact)
137 : norm_exact(norm_exact), d_exact(d_exact)
139 norm = double3(norm_exact[0].get_d(), norm_exact[1].get_d(), norm_exact[2].get_d());
143 Plane::Plane(
const double3 &
norm,
const double d) :
norm(
norm), d(d)
145 norm_exact = mpq3(0, 0, 0);
149 bool Plane::exact_populated()
const
151 return norm_exact[0] != 0 || norm_exact[1] != 0 || norm_exact[2] != 0;
160 x = (
x >> 56) ^ (
x >> 46) ^
x;
161 y = (
y >> 55) ^ (
y >> 45) ^
y;
162 z = (
z >> 54) ^ (
z >> 44) ^
z;
163 d = (d >> 53) ^ (d >> 43) ^ d;
164 return x ^
y ^
z ^ d;
167 std::ostream &
operator<<(std::ostream &os,
const Plane *plane)
169 os <<
"[" << plane->norm <<
";" << plane->d <<
"]";
174 Span<const Vert *>
verts,
int id,
int orig, Span<int> edge_origs, Span<bool> is_intersect)
175 : vert(
verts), edge_orig(edge_origs), is_intersect(is_intersect),
id(
id), orig(orig)
183 void Face::populate_plane(
bool need_exact)
185 if (plane !=
nullptr) {
186 if (!need_exact || plane->exact_populated()) {
192 if (vert.size() > 3) {
193 Array<mpq3> co(vert.size());
194 for (
int i : index_range()) {
195 co[i] = vert[i]->co_exact;
197 normal_exact = mpq3::cross_poly(co);
200 mpq3 tr02 = vert[0]->co_exact - vert[2]->co_exact;
201 mpq3 tr12 = vert[1]->co_exact - vert[2]->co_exact;
204 mpq_class d_exact = -
mpq3::dot(normal_exact, vert[0]->co_exact);
205 plane =
new Plane(normal_exact, d_exact);
209 if (vert.size() > 3) {
210 Array<double3> co(vert.size());
211 for (
int i : index_range()) {
214 normal = double3::cross_poly(co);
217 double3 tr02 = vert[0]->co - vert[2]->co;
218 double3 tr12 = vert[1]->co - vert[2]->co;
219 normal = double3::cross_high_precision(tr02, tr12);
222 plane =
new Plane(
normal, d);
233 if (this->
size() != other.size()) {
236 for (FacePos i : index_range()) {
239 if (this->vert[i] != other.vert[i]) {
246 bool Face::cyclic_equal(
const Face &other)
const
248 if (this->
size() != other.size()) {
251 int flen = this->
size();
252 for (FacePos start : index_range()) {
253 for (FacePos start_other : index_range()) {
255 for (
int i = 0; ok && i < flen; ++i) {
256 FacePos p = (start + i) % flen;
257 FacePos p_other = (start_other + i) % flen;
258 if (this->vert[p] != other.vert[p_other]) {
272 os <<
"f" << f->id <<
"o" << f->orig <<
"[";
273 for (
const Vert *
v : *f) {
275 if (
v != f->vert[f->size() - 1]) {
280 if (f->orig != NO_INDEX) {
281 os <<
"o" << f->orig;
284 for (
int i : f->index_range()) {
285 os << f->edge_orig[i];
286 if (f->is_intersect[i]) {
289 if (i != f->size() - 1) {
312 class IMeshArena::IMeshArenaImpl : NonCopyable, NonMovable {
322 VSetKey(
Vert *p) : vert(p)
333 return *this->vert == *other.vert;
344 Vector<std::unique_ptr<Vert>> allocated_verts_;
345 Vector<std::unique_ptr<Face>> allocated_faces_;
348 int next_vert_id_ = 0;
349 int next_face_id_ = 0;
361 if (intersect_use_threading) {
371 if (intersect_use_threading) {
380 void reserve(
int vert_num_hint,
int face_num_hint)
382 vset_.reserve(vert_num_hint);
383 allocated_verts_.reserve(vert_num_hint);
384 allocated_faces_.reserve(face_num_hint);
387 int tot_allocated_verts()
const
389 return allocated_verts_.size();
392 int tot_allocated_faces()
const
394 return allocated_faces_.size();
397 const Vert *add_or_find_vert(
const mpq3 &co,
int orig)
399 double3 dco(co[0].get_d(), co[1].get_d(), co[2].get_d());
400 return add_or_find_vert(co, dco, orig);
403 const Vert *add_or_find_vert(
const double3 &co,
int orig)
405 mpq3 mco(co[0], co[1], co[2]);
406 return add_or_find_vert(mco, co, orig);
409 Face *add_face(Span<const Vert *>
verts,
int orig, Span<int> edge_origs, Span<bool> is_intersect)
411 Face *f =
new Face(
verts, next_face_id_++, orig, edge_origs, is_intersect);
412 if (intersect_use_threading) {
419 allocated_faces_.append(std::unique_ptr<Face>(f));
420 if (intersect_use_threading) {
430 Face *add_face(Span<const Vert *>
verts,
int orig, Span<int> edge_origs)
432 Array<bool> is_intersect(
verts.size(),
false);
433 return add_face(
verts, orig, edge_origs, is_intersect);
436 Face *add_face(Span<const Vert *>
verts,
int orig)
438 Array<int> edge_origs(
verts.size(), NO_INDEX);
439 Array<bool> is_intersect(
verts.size(),
false);
440 return add_face(
verts, orig, edge_origs, is_intersect);
443 const Vert *find_vert(
const mpq3 &co)
445 Vert vtry(co, double3(co[0].get_d(), co[1].get_d(), co[2].get_d()), NO_INDEX, NO_INDEX);
446 VSetKey vskey(&vtry);
447 if (intersect_use_threading) {
454 const VSetKey *lookup = vset_.lookup_key_ptr(vskey);
455 if (intersect_use_threading) {
473 const Face *find_face(Span<const Vert *> vs)
475 Array<int> eorig(vs.size(), NO_INDEX);
476 Array<bool> is_intersect(vs.size(),
false);
477 Face ftry(vs, NO_INDEX, NO_INDEX, eorig, is_intersect);
478 for (
const int i : allocated_faces_.index_range()) {
479 if (ftry.cyclic_equal(*allocated_faces_[i])) {
480 return allocated_faces_[i].get();
487 const Vert *add_or_find_vert(
const mpq3 &mco,
const double3 &dco,
int orig)
490 Vert vtry(mco, dco, NO_INDEX, NO_INDEX);
492 VSetKey vskey(&vtry);
493 if (intersect_use_threading) {
500 const VSetKey *lookup = vset_.lookup_key_ptr(vskey);
502 vskey.vert =
new Vert(mco, dco, next_vert_id_++, orig);
503 vset_.add_new(vskey);
504 allocated_verts_.append(std::unique_ptr<Vert>(vskey.vert));
515 if (intersect_use_threading) {
526 IMeshArena::IMeshArena()
528 pimpl_ = std::make_unique<IMeshArenaImpl>();
531 IMeshArena::~IMeshArena() =
default;
533 void IMeshArena::reserve(
int vert_num_hint,
int face_num_hint)
535 pimpl_->reserve(vert_num_hint, face_num_hint);
538 int IMeshArena::tot_allocated_verts()
const
540 return pimpl_->tot_allocated_verts();
543 int IMeshArena::tot_allocated_faces()
const
545 return pimpl_->tot_allocated_faces();
548 const Vert *IMeshArena::add_or_find_vert(
const mpq3 &co,
int orig)
550 return pimpl_->add_or_find_vert(co, orig);
553 Face *IMeshArena::add_face(Span<const Vert *>
verts,
555 Span<int> edge_origs,
556 Span<bool> is_intersect)
558 return pimpl_->add_face(
verts, orig, edge_origs, is_intersect);
561 Face *IMeshArena::add_face(Span<const Vert *>
verts,
int orig, Span<int> edge_origs)
563 return pimpl_->add_face(
verts, orig, edge_origs);
566 Face *IMeshArena::add_face(Span<const Vert *>
verts,
int orig)
568 return pimpl_->add_face(
verts, orig);
571 const Vert *IMeshArena::add_or_find_vert(
const double3 &co,
int orig)
573 return pimpl_->add_or_find_vert(co, orig);
576 const Vert *IMeshArena::find_vert(
const mpq3 &co)
const
578 return pimpl_->find_vert(co);
581 const Face *IMeshArena::find_face(Span<const Vert *>
verts)
const
583 return pimpl_->find_face(
verts);
586 void IMesh::set_faces(Span<Face *>
faces)
591 int IMesh::lookup_vert(
const Vert *
v)
const
594 return vert_to_index_.lookup_default(
v, NO_INDEX);
597 void IMesh::populate_vert()
601 constexpr
int ESTIMATE_VERTS_PER_FACE = 4;
602 int estimate_num_verts = ESTIMATE_VERTS_PER_FACE * face_.size();
603 populate_vert(estimate_num_verts);
606 void IMesh::populate_vert(
int max_verts)
608 if (vert_populated_) {
611 vert_to_index_.reserve(max_verts);
612 int next_allocate_index = 0;
613 for (
const Face *f : face_) {
614 for (
const Vert *
v : *f) {
617 int index = vert_to_index_.lookup_default(
v, NO_INDEX);
618 if (index == NO_INDEX) {
620 vert_to_index_.add(
v, next_allocate_index++);
624 int tot_v = next_allocate_index;
625 vert_ = Array<const Vert *>(tot_v);
626 for (
auto item : vert_to_index_.items()) {
627 int index = item.value;
629 vert_[index] = item.key;
634 const bool fix_order =
true;
637 if (a->orig != NO_INDEX && b->orig != NO_INDEX) {
638 return a->orig < b->orig;
640 if (
a->orig != NO_INDEX) {
643 if (b->orig != NO_INDEX) {
646 return a->id < b->id;
648 for (
int i : vert_.index_range()) {
649 const Vert *
v = vert_[i];
650 vert_to_index_.add_overwrite(
v, i);
653 vert_populated_ =
true;
656 bool IMesh::erase_face_positions(
int f_index, Span<bool> face_pos_erase, IMeshArena *arena)
658 const Face *cur_f = this->face(f_index);
659 int cur_len = cur_f->size();
660 int num_to_erase = 0;
661 for (
int i : cur_f->index_range()) {
662 if (face_pos_erase[i]) {
666 if (num_to_erase == 0) {
669 int new_len = cur_len - num_to_erase;
677 this->face_[f_index] =
NULL;
680 Array<const Vert *> new_vert(new_len);
681 Array<int> new_edge_orig(new_len);
682 Array<bool> new_is_intersect(new_len);
684 for (
int i : cur_f->index_range()) {
685 if (!face_pos_erase[i]) {
686 new_vert[new_index] = (*cur_f)[i];
687 new_edge_orig[new_index] = cur_f->edge_orig[i];
688 new_is_intersect[new_index] = cur_f->is_intersect[i];
693 this->face_[f_index] = arena->add_face(new_vert, cur_f->orig, new_edge_orig, new_is_intersect);
697 void IMesh::remove_null_faces()
700 for (
Face *f : this->face_) {
705 if (nullcount == 0) {
708 int64_t new_size = this->face_.size() - nullcount;
711 Array<Face *> new_face(new_size);
712 while (copy_from_index < face_.size()) {
713 Face *f_from = face_[copy_from_index++];
715 new_face[copy_to_index++] = f_from;
718 this->face_ = new_face;
723 if (
mesh.has_verts()) {
727 os << i <<
": " <<
v <<
"\n";
733 for (
const Face *f :
mesh.faces()) {
734 os << i <<
": " << f <<
"\n";
735 if (f->plane !=
nullptr) {
736 os <<
" plane=" << f->plane <<
" eorig=[";
737 for (Face::FacePos p = 0; p < f->size(); ++p) {
738 os << f->edge_orig[p] <<
" ";
749 float3 max{-FLT_MAX, -FLT_MAX, -FLT_MAX};
756 void combine(
const float3 &p)
766 void combine(
const double3 &p)
786 void expand(
float pad)
814 double max_abs_val = 0.0;
819 Array<BoundingBox> *face_bounding_box;
821 BBCalcData(
const IMesh &im, Array<BoundingBox> *fbb) : im(im), face_bounding_box(fbb){};
824 static void calc_face_bb_range_func(
void *__restrict userdata,
828 BBCalcData *bbdata =
static_cast<BBCalcData *
>(userdata);
829 double max_abs = 0.0;
830 const Face &face = *bbdata->im.face(iter);
831 BoundingBox &bb = (*bbdata->face_bounding_box)[iter];
832 for (
const Vert *
v : face) {
834 for (
int i = 0; i < 3; ++i) {
838 BBChunkData *chunk =
static_cast<BBChunkData *
>(tls->userdata_chunk);
839 chunk->max_abs_val =
max_dd(max_abs, chunk->max_abs_val);
843 Array<BoundingBox> *face_bounding_box;
846 BBPadData(Array<BoundingBox> *fbb,
double pad) : face_bounding_box(fbb), pad(pad){};
849 static void pad_face_bb_range_func(
void *__restrict userdata,
853 BBPadData *pad_data =
static_cast<BBPadData *
>(userdata);
854 (*pad_data->face_bounding_box)[iter].expand(pad_data->pad);
857 static void calc_face_bb_reduce(
const void *__restrict
UNUSED(userdata),
858 void *__restrict chunk_join,
859 void *__restrict chunk)
861 BBChunkData *bbchunk_join =
static_cast<BBChunkData *
>(chunk_join);
862 BBChunkData *bbchunk =
static_cast<BBChunkData *
>(chunk);
863 bbchunk_join->max_abs_val =
max_dd(bbchunk_join->max_abs_val, bbchunk->max_abs_val);
871 static Array<BoundingBox> calc_face_bounding_boxes(
const IMesh &m)
873 int n = m.face_size();
874 Array<BoundingBox> ans(n);
876 BBCalcData
data(m, &ans);
877 BBChunkData chunk_data;
885 double max_abs_val = chunk_data.max_abs_val;
886 constexpr
float pad_factor = 10.0f;
887 float pad = max_abs_val == 0.0f ? FLT_EPSILON : 2 * FLT_EPSILON * max_abs_val;
893 BBPadData pad_data(&ans, pad);
907 class CoplanarCluster {
912 CoplanarCluster() =
default;
915 this->add_tri(
t, bb);
928 int tri(
int index)
const
932 const int *begin()
const
934 return tris_.
begin();
936 const int *end()
const
953 class CoplanarClusterInfo {
954 Vector<CoplanarCluster> clusters_;
955 Array<int> tri_cluster_;
958 CoplanarClusterInfo() =
default;
959 explicit CoplanarClusterInfo(
int numtri) : tri_cluster_(Array<int>(numtri))
961 tri_cluster_.fill(-1);
964 int tri_cluster(
int t)
const
967 return tri_cluster_[
t];
970 int add_cluster(CoplanarCluster cl)
972 int c_index = clusters_.append_and_get_index(cl);
975 tri_cluster_[
t] = c_index;
980 int tot_cluster()
const
982 return clusters_.size();
985 const CoplanarCluster *begin()
987 return clusters_.begin();
990 const CoplanarCluster *end()
992 return clusters_.end();
995 IndexRange index_range()
const
997 return clusters_.index_range();
1000 const CoplanarCluster &cluster(
int index)
const
1003 return clusters_[index];
1007 static std::ostream &
operator<<(std::ostream &os,
const CoplanarCluster &cl);
1009 static std::ostream &
operator<<(std::ostream &os,
const CoplanarClusterInfo &clinfo);
1011 enum ITT_value_kind { INONE, IPOINT, ISEGMENT, ICOPLANAR };
1017 enum ITT_value_kind kind = INONE;
1019 ITT_value() =
default;
1020 explicit ITT_value(ITT_value_kind k) : kind(k)
1023 ITT_value(ITT_value_kind k,
int tsrc) : t_source(tsrc), kind(k)
1026 ITT_value(ITT_value_kind k,
const mpq3 &p1) : p1(p1), kind(k)
1029 ITT_value(ITT_value_kind k,
const mpq3 &p1,
const mpq3 &p2) : p1(p1), p2(p2), kind(k)
1034 static std::ostream &
operator<<(std::ostream &os,
const ITT_value &itt);
1041 static mpq2 project_3d_to_2d(
const mpq3 &p3d,
int proj_axis)
1044 switch (proj_axis) {
1096 static double supremum_dot_cross(
const double3 &
a,
const double3 &b)
1103 c[0] = abs_a[1] * abs_b[2] + abs_a[2] * abs_b[1];
1104 c[1] = abs_a[2] * abs_b[0] + abs_a[0] * abs_b[2];
1105 c[2] = abs_a[0] * abs_b[1] + abs_a[1] * abs_b[0];
1112 constexpr
int index_dot_plane_coords = 15;
1124 constexpr
int index_dot_cross = 11;
1134 constexpr
int index_plane_side = 3 + 2 * index_dot_plane_coords;
1136 static int filter_plane_side(
const double3 &p,
1137 const double3 &plane_p,
1138 const double3 &plane_no,
1139 const double3 &abs_p,
1140 const double3 &abs_plane_p,
1141 const double3 &abs_plane_no)
1147 double supremum =
double3::dot(abs_p + abs_plane_p, abs_plane_no);
1148 double err_bound = supremum * index_plane_side * DBL_EPSILON;
1149 if (
fabs(d) > err_bound) {
1150 return d > 0 ? 1 : -1;
1169 static inline mpq3 tti_interp(
const mpq3 &
a,
const mpq3 &b,
const mpq3 &
c,
const mpq3 &n)
1183 static inline int tti_above(
const mpq3 &
a,
const mpq3 &b,
const mpq3 &
c,
const mpq3 &ad)
1202 static ITT_value itt_canon2(
const mpq3 &p1,
1211 constexpr
int dbg_level = 0;
1212 if (dbg_level > 0) {
1213 std::cout <<
"\ntri_tri_intersect_canon:\n";
1214 std::cout <<
"p1=" << p1 <<
" q1=" <<
q1 <<
" r1=" << r1 <<
"\n";
1215 std::cout <<
"p2=" << p2 <<
" q2=" << q2 <<
" r2=" << r2 <<
"\n";
1216 std::cout <<
"n1=" << n1 <<
" n2=" << n2 <<
"\n";
1217 std::cout <<
"approximate values:\n";
1218 std::cout <<
"p1=(" << p1[0].get_d() <<
"," << p1[1].get_d() <<
"," << p1[2].get_d() <<
")\n";
1219 std::cout <<
"q1=(" <<
q1[0].get_d() <<
"," <<
q1[1].get_d() <<
"," <<
q1[2].get_d() <<
")\n";
1220 std::cout <<
"r1=(" << r1[0].get_d() <<
"," << r1[1].get_d() <<
"," << r1[2].get_d() <<
")\n";
1221 std::cout <<
"p2=(" << p2[0].get_d() <<
"," << p2[1].get_d() <<
"," << p2[2].get_d() <<
")\n";
1222 std::cout <<
"q2=(" << q2[0].get_d() <<
"," << q2[1].get_d() <<
"," << q2[2].get_d() <<
")\n";
1223 std::cout <<
"r2=(" << r2[0].get_d() <<
"," << r2[1].get_d() <<
"," << r2[2].get_d() <<
")\n";
1224 std::cout <<
"n1=(" << n1[0].get_d() <<
"," << n1[1].get_d() <<
"," << n1[2].get_d() <<
")\n";
1225 std::cout <<
"n2=(" << n2[0].get_d() <<
"," << n2[1].get_d() <<
"," << n2[2].get_d() <<
")\n";
1227 mpq3 p1p2 = p2 - p1;
1230 bool no_overlap =
false;
1232 if (tti_above(p1,
q1, r2, p1p2) > 0) {
1234 if (tti_above(p1, r1, r2, p1p2) <= 0) {
1236 if (tti_above(p1, r1, q2, p1p2) > 0) {
1238 if (dbg_level > 0) {
1239 std::cout <<
"overlap [k [i l] j]\n";
1242 intersect_1 = tti_interp(p1, r1, p2, n2);
1243 intersect_2 = tti_interp(p2, r2, p1, n1);
1247 if (dbg_level > 0) {
1248 std::cout <<
"overlap [i [k l] j]\n";
1251 intersect_1 = tti_interp(p2, q2, p1, n1);
1252 intersect_2 = tti_interp(p2, r2, p1, n1);
1257 if (dbg_level > 0) {
1258 std::cout <<
"no overlap: [k l] [i j]\n";
1265 if (tti_above(p1,
q1, q2, p1p2) < 0) {
1267 if (dbg_level > 0) {
1268 std::cout <<
"no overlap: [i j] [k l]\n";
1274 if (tti_above(p1, r1, q2, p1p2) >= 0) {
1276 if (dbg_level > 0) {
1277 std::cout <<
"overlap [k [i j] l]\n";
1280 intersect_1 = tti_interp(p1, r1, p2, n2);
1281 intersect_2 = tti_interp(p1,
q1, p2, n2);
1285 if (dbg_level > 0) {
1286 std::cout <<
"overlap [i [k j] l]\n";
1289 intersect_1 = tti_interp(p2, q2, p1, n1);
1290 intersect_2 = tti_interp(p1,
q1, p2, n2);
1295 return ITT_value(INONE);
1297 if (intersect_1 == intersect_2) {
1298 if (dbg_level > 0) {
1299 std::cout <<
"single intersect: " << intersect_1 <<
"\n";
1301 return ITT_value(IPOINT, intersect_1);
1303 if (dbg_level > 0) {
1304 std::cout <<
"intersect segment: " << intersect_1 <<
", " << intersect_2 <<
"\n";
1306 return ITT_value(ISEGMENT, intersect_1, intersect_2);
1311 static ITT_value itt_canon1(
const mpq3 &p1,
1323 constexpr
int dbg_level = 0;
1326 return itt_canon2(p1, r1,
q1, r2, p2, q2, n1, n2);
1329 return itt_canon2(p1, r1,
q1, q2, r2, p2, n1, n2);
1331 return itt_canon2(p1,
q1, r1, p2, q2, r2, n1, n2);
1335 return itt_canon2(p1,
q1, r1, r2, p2, q2, n1, n2);
1338 return itt_canon2(p1,
q1, r1, q2, r2, p2, n1, n2);
1340 return itt_canon2(p1, r1,
q1, p2, q2, r2, n1, n2);
1344 return itt_canon2(p1, r1,
q1, q2, r2, p2, n1, n2);
1346 return itt_canon2(p1,
q1, r1, p2, q2, r2, n1, n2);
1350 return itt_canon2(p1, r1,
q1, p2, q2, r2, n1, n2);
1352 return itt_canon2(p1,
q1, r1, q2, r2, p2, n1, n2);
1355 return itt_canon2(p1,
q1, r1, r2, p2, q2, n1, n2);
1358 return itt_canon2(p1, r1,
q1, r2, p2, q2, n1, n2);
1360 if (dbg_level > 0) {
1361 std::cout <<
"triangles are co-planar\n";
1363 return ITT_value(ICOPLANAR);
1366 static ITT_value intersect_tri_tri(
const IMesh &tm,
int t1,
int t2)
1368 constexpr
int dbg_level = 0;
1372 const Face &tri1 = *tm.face(t1);
1373 const Face &tri2 = *tm.face(t2);
1374 BLI_assert(tri1.plane_populated() && tri2.plane_populated());
1375 const Vert *vp1 = tri1[0];
1376 const Vert *vq1 = tri1[1];
1377 const Vert *vr1 = tri1[2];
1378 const Vert *vp2 = tri2[0];
1379 const Vert *vq2 = tri2[1];
1380 const Vert *vr2 = tri2[2];
1381 if (dbg_level > 0) {
1382 std::cout <<
"\nINTERSECT_TRI_TRI t1=" << t1 <<
", t2=" << t2 <<
"\n";
1383 std::cout <<
" p1 = " << vp1 <<
"\n";
1384 std::cout <<
" q1 = " << vq1 <<
"\n";
1385 std::cout <<
" r1 = " << vr1 <<
"\n";
1386 std::cout <<
" p2 = " << vp2 <<
"\n";
1387 std::cout <<
" q2 = " << vq2 <<
"\n";
1388 std::cout <<
" r2 = " << vr2 <<
"\n";
1396 const double3 &d_p1 = vp1->co;
1397 const double3 &d_q1 = vq1->co;
1398 const double3 &d_r1 = vr1->co;
1399 const double3 &d_p2 = vp2->co;
1400 const double3 &d_q2 = vq2->co;
1401 const double3 &d_r2 = vr2->co;
1402 const double3 &d_n2 = tri2.plane->norm;
1410 int sp1 = filter_plane_side(d_p1, d_r2, d_n2, abs_d_p1, abs_d_r2, abs_d_n2);
1411 int sq1 = filter_plane_side(d_q1, d_r2, d_n2, abs_d_q1, abs_d_r2, abs_d_n2);
1412 int sr1 = filter_plane_side(d_r1, d_r2, d_n2, abs_d_r1, abs_d_r2, abs_d_n2);
1413 if ((sp1 > 0 && sq1 > 0 && sr1 > 0) || (sp1 < 0 && sq1 < 0 && sr1 < 0)) {
1417 if (dbg_level > 0) {
1418 std::cout <<
"no intersection, all t1's verts above or below t2\n";
1420 return ITT_value(INONE);
1423 const double3 &d_n1 = tri1.plane->norm;
1428 int sp2 = filter_plane_side(d_p2, d_r1, d_n1, abs_d_p2, abs_d_r1, abs_d_n1);
1429 int sq2 = filter_plane_side(d_q2, d_r1, d_n1, abs_d_q2, abs_d_r1, abs_d_n1);
1430 int sr2 = filter_plane_side(d_r2, d_r1, d_n1, abs_d_r2, abs_d_r1, abs_d_n1);
1431 if ((sp2 > 0 && sq2 > 0 && sr2 > 0) || (sp2 < 0 && sq2 < 0 && sr2 < 0)) {
1435 if (dbg_level > 0) {
1436 std::cout <<
"no intersection, all t2's verts above or below t1\n";
1438 return ITT_value(INONE);
1441 const mpq3 &p1 = vp1->co_exact;
1442 const mpq3 &
q1 = vq1->co_exact;
1443 const mpq3 &r1 = vr1->co_exact;
1444 const mpq3 &p2 = vp2->co_exact;
1445 const mpq3 &q2 = vq2->co_exact;
1446 const mpq3 &r2 = vr2->co_exact;
1448 const mpq3 &n2 = tri2.plane->norm_exact;
1459 if (dbg_level > 1) {
1460 std::cout <<
" sp1=" << sp1 <<
" sq1=" << sq1 <<
" sr1=" << sr1 <<
"\n";
1463 if ((sp1 * sq1 > 0) && (sp1 * sr1 > 0)) {
1464 if (dbg_level > 0) {
1465 std::cout <<
"no intersection, all t1's verts above or below t2 (exact)\n";
1470 return ITT_value(INONE);
1474 const mpq3 &n1 = tri1.plane->norm_exact;
1485 if (dbg_level > 1) {
1486 std::cout <<
" sp2=" << sp2 <<
" sq2=" << sq2 <<
" sr2=" << sr2 <<
"\n";
1489 if ((sp2 * sq2 > 0) && (sp2 * sr2 > 0)) {
1490 if (dbg_level > 0) {
1491 std::cout <<
"no intersection, all t2's verts above or below t1 (exact)\n";
1496 return ITT_value(INONE);
1505 ans = itt_canon1(r1, p1,
q1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1508 ans = itt_canon1(
q1, r1, p1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1511 ans = itt_canon1(p1,
q1, r1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1516 ans = itt_canon1(r1, p1,
q1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1519 ans = itt_canon1(
q1, r1, p1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1522 ans = itt_canon1(p1,
q1, r1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1528 ans = itt_canon1(
q1, r1, p1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1531 ans = itt_canon1(p1,
q1, r1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1536 ans = itt_canon1(p1,
q1, r1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1539 ans = itt_canon1(
q1, r1, p1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1544 ans = itt_canon1(r1, p1,
q1, p2, q2, r2, n1, n2, sp2, sq2, sr2);
1547 ans = itt_canon1(r1, p1,
q1, p2, r2, q2, n1, n2, sp2, sr2, sq2);
1550 if (dbg_level > 0) {
1551 std::cout <<
"triangles are co-planar\n";
1553 ans = ITT_value(ICOPLANAR);
1557 if (ans.kind == ICOPLANAR) {
1562 if (ans.kind != INONE) {
1570 const Plane *t_plane;
1572 Vector<std::pair<int, int>> edge;
1573 Vector<Vector<int>> face;
1575 Vector<int> input_face;
1577 Vector<bool> is_reversed;
1582 Map<std::pair<int, int>,
int> verts_to_edge;
1589 static int prepare_need_vert(CDT_data &cd,
const mpq3 &p3d)
1591 mpq2 p2d = project_3d_to_2d(p3d, cd.proj_axis);
1592 int v = cd.vert.append_and_get_index(p2d);
1603 static mpq3 unproject_cdt_vert(
const CDT_data &cd,
const mpq2 &p2d)
1607 BLI_assert(cd.t_plane->norm_exact[cd.proj_axis] != 0);
1608 const mpq3 &n = cd.t_plane->norm_exact;
1609 const mpq_class &d = cd.t_plane->d_exact;
1610 switch (cd.proj_axis) {
1612 mpq_class num = n[1] * p2d[0] + n[2] * p2d[1] + d;
1614 p3d[0] = num / n[0];
1621 mpq_class num = n[0] * p2d[0] + n[2] * p2d[1] + d;
1623 p3d[1] = num / n[1];
1630 mpq_class num = n[0] * p2d[0] + n[1] * p2d[1] + d;
1632 p3d[2] = num / n[2];
1641 static void prepare_need_edge(CDT_data &cd,
const mpq3 &p1,
const mpq3 &p2)
1643 int v1 = prepare_need_vert(cd, p1);
1644 int v2 = prepare_need_vert(cd, p2);
1645 cd.edge.append(std::pair<int, int>(
v1,
v2));
1648 static void prepare_need_tri(CDT_data &cd,
const IMesh &tm,
int t)
1650 const Face &tri = *tm.face(
t);
1651 int v0 = prepare_need_vert(cd, tri[0]->co_exact);
1652 int v1 = prepare_need_vert(cd, tri[1]->co_exact);
1653 int v2 = prepare_need_vert(cd, tri[2]->co_exact);
1658 if (tri.plane->norm_exact[cd.proj_axis] >= 0) {
1659 rev = cd.proj_axis == 1;
1662 rev = cd.proj_axis != 1;
1664 int cd_t = cd.face.append_and_get_index(Vector<int>());
1665 cd.face[cd_t].append(v0);
1667 cd.face[cd_t].append(
v2);
1668 cd.face[cd_t].append(
v1);
1671 cd.face[cd_t].append(
v1);
1672 cd.face[cd_t].append(
v2);
1674 cd.input_face.append(
t);
1675 cd.is_reversed.append(rev);
1678 static CDT_data prepare_cdt_input(
const IMesh &tm,
int t,
const Vector<ITT_value> itts)
1682 ans.t_plane = tm.face(
t)->plane;
1684 ans.proj_axis = mpq3::dominant_axis(ans.t_plane->norm_exact);
1685 prepare_need_tri(ans, tm,
t);
1686 for (
const ITT_value &itt : itts) {
1691 prepare_need_vert(ans, itt.p1);
1695 prepare_need_edge(ans, itt.p1, itt.p2);
1699 prepare_need_tri(ans, tm, itt.t_source);
1707 static CDT_data prepare_cdt_input_for_cluster(
const IMesh &tm,
1708 const CoplanarClusterInfo &clinfo,
1710 const Vector<ITT_value> itts)
1714 const CoplanarCluster &cl = clinfo.cluster(
c);
1718 ans.t_plane = tm.face(t0)->plane;
1720 ans.proj_axis = mpq3::dominant_axis(ans.t_plane->norm_exact);
1721 for (
const int t : cl) {
1722 prepare_need_tri(ans, tm,
t);
1724 for (
const ITT_value &itt : itts) {
1727 prepare_need_vert(ans, itt.p1);
1731 prepare_need_edge(ans, itt.p1, itt.p2);
1742 static inline std::pair<int, int> sorted_int_pair(std::pair<int, int> pair)
1744 if (pair.first <= pair.second) {
1748 return std::pair<int, int>(pair.second, pair.first);
1756 static void populate_cdt_edge_map(Map<std::pair<int, int>,
int> &verts_to_edge,
1759 verts_to_edge.reserve(cdt_out.edge.size());
1760 for (
int e : cdt_out.edge.index_range()) {
1761 std::pair<int, int> vpair = sorted_int_pair(cdt_out.edge[
e]);
1763 verts_to_edge.add(vpair,
e);
1770 static void do_cdt(CDT_data &cd)
1772 constexpr
int dbg_level = 0;
1774 cdt_in.vert = Span<mpq2>(cd.vert);
1775 cdt_in.edge = Span<std::pair<int, int>>(cd.edge);
1776 cdt_in.face = Span<Vector<int>>(cd.face);
1777 if (dbg_level > 0) {
1778 std::cout <<
"CDT input\nVerts:\n";
1779 for (
int i : cdt_in.vert.index_range()) {
1780 std::cout <<
"v" << i <<
": " << cdt_in.vert[i] <<
"=(" << cdt_in.vert[i][0].get_d() <<
","
1781 << cdt_in.vert[i][1].get_d() <<
")\n";
1783 std::cout <<
"Edges:\n";
1784 for (
int i : cdt_in.edge.index_range()) {
1785 std::cout <<
"e" << i <<
": (" << cdt_in.edge[i].first <<
", " << cdt_in.edge[i].second
1788 std::cout <<
"Tris\n";
1789 for (
int f : cdt_in.face.index_range()) {
1790 std::cout <<
"f" << f <<
": ";
1791 for (
int j : cdt_in.face[f].index_range()) {
1792 std::cout << cdt_in.face[f][j] <<
" ";
1798 cd.cdt_out = blender::meshintersect::delaunay_2d_calc(cdt_in,
CDT_INSIDE);
1799 constexpr
int make_edge_map_threshold = 15;
1800 if (cd.cdt_out.edge.size() >= make_edge_map_threshold) {
1801 populate_cdt_edge_map(cd.verts_to_edge, cd.cdt_out);
1803 if (dbg_level > 0) {
1804 std::cout <<
"\nCDT result\nVerts:\n";
1805 for (
int i : cd.cdt_out.vert.index_range()) {
1806 std::cout <<
"v" << i <<
": " << cd.cdt_out.vert[i] <<
"=(" << cd.cdt_out.vert[i][0].get_d()
1807 <<
"," << cd.cdt_out.vert[i][1].get_d() <<
"\n";
1809 std::cout <<
"Tris\n";
1810 for (
int f : cd.cdt_out.face.index_range()) {
1811 std::cout <<
"f" << f <<
": ";
1812 for (
int j : cd.cdt_out.face[f].index_range()) {
1813 std::cout << cd.cdt_out.face[f][j] <<
" ";
1815 std::cout <<
"orig: ";
1816 for (
int j : cd.cdt_out.face_orig[f].index_range()) {
1817 std::cout << cd.cdt_out.face_orig[f][j] <<
" ";
1821 std::cout <<
"Edges\n";
1822 for (
int e : cd.cdt_out.edge.index_range()) {
1823 std::cout <<
"e" <<
e <<
": (" << cd.cdt_out.edge[
e].first <<
", "
1824 << cd.cdt_out.edge[
e].second <<
") ";
1825 std::cout <<
"orig: ";
1826 for (
int j : cd.cdt_out.edge_orig[
e].index_range()) {
1827 std::cout << cd.cdt_out.edge_orig[
e][j] <<
" ";
1834 static int get_cdt_edge_orig(
1835 int i0,
int i1,
const CDT_data &cd,
const IMesh &in_tm,
bool *r_is_intersect)
1837 int foff = cd.cdt_out.face_edge_offset;
1838 *r_is_intersect =
false;
1840 if (cd.verts_to_edge.size() > 0) {
1842 std::pair<int, int> vpair = sorted_int_pair(std::pair<int, int>(i0,
i1));
1843 e = cd.verts_to_edge.lookup_default(vpair, NO_INDEX);
1846 for (
int ee : cd.cdt_out.edge.index_range()) {
1847 std::pair<int, int> edge = cd.cdt_out.edge[ee];
1848 if ((edge.first == i0 && edge.second ==
i1) || (edge.first ==
i1 && edge.second == i0)) {
1854 if (
e == NO_INDEX) {
1861 for (
int orig_index : cd.cdt_out.edge_orig[
e]) {
1863 if (orig_index >= foff) {
1864 int in_face_index = (orig_index / foff) - 1;
1865 int pos = orig_index % foff;
1868 int in_tm_face_index = cd.input_face[in_face_index];
1869 BLI_assert(in_tm_face_index < in_tm.face_size());
1870 const Face *facep = in_tm.face(in_tm_face_index);
1872 bool is_rev = cd.is_reversed[in_face_index];
1873 int eorig = is_rev ? facep->edge_orig[2 -
pos] : facep->edge_orig[
pos];
1874 if (eorig != NO_INDEX) {
1881 *r_is_intersect =
true;
1896 static Face *cdt_tri_as_imesh_face(
1897 int cdt_out_t,
int cdt_in_t,
const CDT_data &cd,
const IMesh &tm, IMeshArena *arena)
1900 int t_orig = tm.face(cd.input_face[cdt_in_t])->orig;
1901 BLI_assert(cdt_out.face[cdt_out_t].size() == 3);
1902 int i0 = cdt_out.face[cdt_out_t][0];
1903 int i1 = cdt_out.face[cdt_out_t][1];
1904 int i2 = cdt_out.face[cdt_out_t][2];
1905 mpq3 v0co = unproject_cdt_vert(cd, cdt_out.vert[i0]);
1906 mpq3 v1co = unproject_cdt_vert(cd, cdt_out.vert[
i1]);
1907 mpq3 v2co = unproject_cdt_vert(cd, cdt_out.vert[i2]);
1911 const Vert *v0 = arena->add_or_find_vert(v0co, NO_INDEX);
1912 const Vert *
v1 = arena->add_or_find_vert(v1co, NO_INDEX);
1913 const Vert *
v2 = arena->add_or_find_vert(v2co, NO_INDEX);
1918 if (cd.is_reversed[cdt_in_t]) {
1919 int oe0 = get_cdt_edge_orig(i0, i2, cd, tm, &is_isect0);
1920 int oe1 = get_cdt_edge_orig(i2,
i1, cd, tm, &is_isect1);
1921 int oe2 = get_cdt_edge_orig(
i1, i0, cd, tm, &is_isect2);
1922 facep = arena->add_face(
1923 {v0,
v2,
v1}, t_orig, {oe0, oe1, oe2}, {is_isect0, is_isect1, is_isect2});
1926 int oe0 = get_cdt_edge_orig(i0,
i1, cd, tm, &is_isect0);
1927 int oe1 = get_cdt_edge_orig(
i1, i2, cd, tm, &is_isect1);
1928 int oe2 = get_cdt_edge_orig(i2, i0, cd, tm, &is_isect2);
1929 facep = arena->add_face(
1930 {v0,
v1,
v2}, t_orig, {oe0, oe1, oe2}, {is_isect0, is_isect1, is_isect2});
1932 facep->populate_plane(
false);
1948 static Array<Face *> polyfill_triangulate_poly(
Face *f, IMeshArena *arena)
1951 int flen = f->size();
1953 if (!f->plane_populated()) {
1954 f->populate_plane(
false);
1957 const double3 &poly_normal = f->plane->norm;
1958 float no[3] = {
float(poly_normal[0]),
float(poly_normal[1]),
float(poly_normal[2])};
1960 float axis_mat[3][3];
1961 float(*projverts)[2];
1962 unsigned int(*tris)[3];
1963 const int totfilltri = flen - 2;
1965 tris =
static_cast<unsigned int(*)[3]
>(
MEM_malloc_arrayN(totfilltri,
sizeof(*tris), __func__));
1966 projverts =
static_cast<float(*)[2]
>(
MEM_malloc_arrayN(flen,
sizeof(*projverts), __func__));
1968 for (
int j = 0; j < flen; ++j) {
1969 const double3 &dco = (*f)[j]->co;
1975 Array<Face *> ans(totfilltri);
1976 for (
int t = 0;
t < totfilltri; ++
t) {
1977 unsigned int *tri = tris[
t];
1980 for (
int k = 0; k < 3; k++) {
1982 v[k] = (*f)[tri[k]];
1985 if ((tri[k] + 1) % flen == tri[(k + 1) % 3]) {
1986 eo[k] = f->edge_orig[tri[k]];
1991 ans[
t] = arena->add_face(
1992 {
v[0],
v[1],
v[2]}, f->orig, {eo[0], eo[1], eo[2]}, {
false,
false,
false});
2017 static Array<Face *> triangulate_poly(
Face *f, IMeshArena *arena)
2019 int flen = f->size();
2021 cdt_in.vert = Array<mpq2>(flen);
2022 cdt_in.face = Array<Vector<int>>(1);
2023 cdt_in.face[0].reserve(flen);
2024 for (
int i : f->index_range()) {
2025 cdt_in.face[0].append(i);
2028 if (!f->plane_populated()) {
2029 f->populate_plane(
false);
2031 const double3 &poly_normal = f->plane->norm;
2032 int axis = double3::dominant_axis(poly_normal);
2037 bool rev1 = (axis == 1);
2038 bool rev2 = poly_normal[axis] < 0;
2039 bool rev = rev1 ^ rev2;
2040 for (
int i = 0; i < flen; ++i) {
2041 int ii = rev ? flen - i - 1 : i;
2042 mpq2 &p2d = cdt_in.vert[ii];
2044 for (
int j = 0; j < 3; ++j) {
2046 p2d[k++] = (*f)[ii]->co_exact[j];
2051 int n_tris = cdt_out.face.size();
2052 Array<Face *> ans(n_tris);
2053 for (
int t = 0;
t < n_tris; ++
t) {
2057 bool needs_steiner =
false;
2058 for (
int i = 0; i < 3; ++i) {
2059 i_v_out[i] = cdt_out.face[
t][i];
2060 if (cdt_out.vert_orig[i_v_out[i]].size() == 0) {
2061 needs_steiner =
true;
2064 v[i] = (*f)[cdt_out.vert_orig[i_v_out[i]][0]];
2066 if (needs_steiner) {
2068 return polyfill_triangulate_poly(f, arena);
2070 Map<std::pair<int, int>,
int> verts_to_edge;
2071 populate_cdt_edge_map(verts_to_edge, cdt_out);
2073 for (
int i = 0; i < 3; ++i) {
2074 std::pair<int, int> vpair(i_v_out[i], i_v_out[(i + 1) % 3]);
2075 std::pair<int, int> vpair_canon = sorted_int_pair(vpair);
2076 int e_out = verts_to_edge.lookup_default(vpair_canon, NO_INDEX);
2079 for (
int orig : cdt_out.edge_orig[e_out]) {
2081 int pos = orig % foff;
2083 eo[i] = f->edge_orig[
pos];
2089 ans[
t] = arena->add_face(
2090 {
v[0],
v[2],
v[1]}, f->orig, {eo[2], eo[1], eo[0]}, {
false,
false,
false});
2093 ans[
t] = arena->add_face(
2094 {
v[0],
v[1],
v[2]}, f->orig, {eo[0], eo[1], eo[2]}, {
false,
false,
false});
2106 IMesh triangulate_polymesh(IMesh &imesh, IMeshArena *arena)
2108 Vector<Face *> face_tris;
2109 constexpr
int estimated_tris_per_face = 3;
2110 face_tris.reserve(estimated_tris_per_face * imesh.face_size());
2111 for (
Face *f : imesh.faces()) {
2113 int flen = f->size();
2115 face_tris.append(f);
2117 else if (flen == 4) {
2118 const Vert *v0 = (*f)[0];
2119 const Vert *
v1 = (*f)[1];
2120 const Vert *
v2 = (*f)[2];
2121 const Vert *v3 = (*f)[3];
2122 int eo_01 = f->edge_orig[0];
2123 int eo_12 = f->edge_orig[1];
2124 int eo_23 = f->edge_orig[2];
2125 int eo_30 = f->edge_orig[3];
2126 Face *f0 = arena->add_face({v0,
v1,
v2}, f->orig, {eo_01, eo_12, -1}, {
false,
false,
false});
2127 Face *f1 = arena->add_face({v0,
v2, v3}, f->orig, {-1, eo_23, eo_30}, {
false,
false,
false});
2128 face_tris.append(f0);
2129 face_tris.append(f1);
2132 Array<Face *> tris = triangulate_poly(f, arena);
2133 for (
Face *tri : tris) {
2134 face_tris.append(tri);
2138 return IMesh(face_tris);
2145 static IMesh extract_subdivided_tri(
const CDT_data &cd,
2152 for (
int i = 0; i < cd.input_face.size(); ++i) {
2153 if (cd.input_face[i] ==
t) {
2157 if (t_in_cdt == -1) {
2158 std::cout <<
"Could not find " <<
t <<
" in cdt input tris\n";
2162 constexpr
int inline_buf_size = 20;
2163 Vector<Face *, inline_buf_size>
faces;
2164 for (
int f : cdt_out.face.index_range()) {
2165 if (cdt_out.face_orig[f].contains(t_in_cdt)) {
2166 Face *facep = cdt_tri_as_imesh_face(f, t_in_cdt, cd, in_tm, arena);
2167 faces.append(facep);
2170 return IMesh(
faces);
2187 Array<int> first_overlap_;
2188 uint overlap_tot_{0};
2192 std::function<int(
int)> shape_fn;
2198 TriOverlaps(
const IMesh &tm,
2199 const Array<BoundingBox> &tri_bb,
2201 std::function<
int(
int)> shape_fn,
2204 constexpr
int dbg_level = 0;
2205 if (dbg_level > 0) {
2206 std::cout <<
"TriOverlaps construction\n";
2212 bool two_trees_no_self = nshapes == 2 && !use_self;
2213 if (two_trees_no_self) {
2217 for (
int t : tm.face_index_range()) {
2221 int shape = shape_fn(tm.face(
t)->orig);
2222 if (two_trees_no_self) {
2226 else if (shape == 1) {
2237 if (two_trees_no_self) {
2243 CBData cbdata{tm, shape_fn, nshapes, use_self};
2249 tree_, tree_, &overlap_tot_, only_different_shapes, &cbdata);
2255 if (two_trees_no_self) {
2257 MEM_reallocN(overlap_, 2 * overlap_tot_ *
sizeof(overlap_[0])));
2258 for (
uint i = 0; i < overlap_tot_; ++i) {
2259 overlap_[overlap_tot_ + i].
indexA = overlap_[i].indexB;
2260 overlap_[overlap_tot_ + i].indexB = overlap_[i].indexA;
2262 overlap_tot_ += overlap_tot_;
2265 std::sort(overlap_, overlap_ + overlap_tot_, bvhtreeverlap_cmp);
2266 if (dbg_level > 0) {
2267 std::cout << overlap_tot_ <<
" overlaps found:\n";
2269 std::cout <<
"A: " << ov.indexA <<
", B: " << ov.indexB <<
"\n";
2272 first_overlap_ = Array<int>(tm.face_size(), -1);
2273 for (
int i = 0; i < static_cast<int>(overlap_tot_); ++i) {
2274 int t = overlap_[i].indexA;
2275 if (first_overlap_[
t] == -1) {
2276 first_overlap_[
t] = i;
2294 Span<BVHTreeOverlap> overlap()
const
2296 return Span<BVHTreeOverlap>(overlap_, overlap_tot_);
2299 int first_overlap_index(
int t)
const
2301 return first_overlap_[
t];
2305 static bool only_different_shapes(
void *userdata,
int index_a,
int index_b,
int UNUSED(
thread))
2308 return cbdata->tm.face(index_a)->orig != cbdata->tm.face(index_b)->orig;
2315 struct OverlapIttsData {
2316 Vector<std::pair<int, int>> intersect_pairs;
2317 Map<std::pair<int, int>, ITT_value> &itt_map;
2321 OverlapIttsData(Map<std::pair<int, int>, ITT_value> &itt_map,
const IMesh &tm, IMeshArena *arena)
2322 : itt_map(itt_map), tm(tm), arena(arena)
2331 static std::pair<int, int> canon_int_pair(
int a,
int b)
2336 return std::pair<int, int>(
a, b);
2339 static void calc_overlap_itts_range_func(
void *__restrict userdata,
2343 constexpr
int dbg_level = 0;
2344 OverlapIttsData *
data =
static_cast<OverlapIttsData *
>(userdata);
2345 std::pair<int, int> tri_pair =
data->intersect_pairs[iter];
2346 int a = tri_pair.first;
2347 int b = tri_pair.second;
2348 if (dbg_level > 0) {
2349 std::cout <<
"calc_overlap_itts_range_func a=" <<
a <<
", b=" << b <<
"\n";
2351 ITT_value itt = intersect_tri_tri(
data->tm,
a, b);
2352 if (dbg_level > 0) {
2353 std::cout <<
"result of intersecting " <<
a <<
" and " << b <<
" = " << itt <<
"\n";
2356 data->itt_map.add_overwrite(tri_pair, itt);
2363 static void calc_overlap_itts(Map<std::pair<int, int>, ITT_value> &itt_map,
2365 const TriOverlaps &ov,
2368 OverlapIttsData
data(itt_map, tm, arena);
2373 std::pair<int, int> key = canon_int_pair(olap.indexA, olap.indexB);
2374 if (!itt_map.contains(key)) {
2375 itt_map.add_new(key, ITT_value());
2376 data.intersect_pairs.append(key);
2379 int tot_intersect_pairs =
data.intersect_pairs.size();
2390 struct OverlapTriRange {
2395 struct SubdivideTrisData {
2396 Array<IMesh> &r_tri_subdivided;
2398 const Map<std::pair<int, int>, ITT_value> &itt_map;
2399 Span<BVHTreeOverlap> overlap;
2406 Vector<OverlapTriRange> overlap_tri_range;
2408 SubdivideTrisData(Array<IMesh> &r_tri_subdivided,
2410 const Map<std::pair<int, int>, ITT_value> &itt_map,
2411 Span<BVHTreeOverlap> overlap,
2413 : r_tri_subdivided(r_tri_subdivided),
2422 static void calc_subdivided_tri_range_func(
void *__restrict userdata,
2426 constexpr
int dbg_level = 0;
2427 SubdivideTrisData *
data =
static_cast<SubdivideTrisData *
>(userdata);
2428 OverlapTriRange &otr =
data->overlap_tri_range[iter];
2429 int t = otr.tri_index;
2430 if (dbg_level > 0) {
2431 std::cout <<
"calc_subdivided_tri_range_func\nt=" <<
t <<
" start=" << otr.overlap_start
2432 <<
" len=" << otr.len <<
"\n";
2434 constexpr
int inline_capacity = 100;
2435 Vector<ITT_value, inline_capacity> itts(otr.len);
2436 for (
int j = otr.overlap_start; j < otr.overlap_start + otr.len; ++j) {
2437 int t_other =
data->overlap[j].indexB;
2438 std::pair<int, int> key = canon_int_pair(
t, t_other);
2440 if (
data->itt_map.contains(key)) {
2441 itt =
data->itt_map.lookup(key);
2443 if (itt.kind != INONE) {
2446 if (dbg_level > 0) {
2447 std::cout <<
" tri t" << t_other <<
"; result = " << itt <<
"\n";
2450 if (itts.size() > 0) {
2451 CDT_data cd_data = prepare_cdt_input(
data->tm,
t, itts);
2453 data->r_tri_subdivided[
t] = extract_subdivided_tri(cd_data,
data->tm,
t,
data->arena);
2454 if (dbg_level > 0) {
2455 std::cout <<
"subdivide output\n" <<
data->r_tri_subdivided[
t];
2466 static void calc_subdivided_non_cluster_tris(Array<IMesh> &r_tri_subdivided,
2468 const Map<std::pair<int, int>, ITT_value> &itt_map,
2469 const CoplanarClusterInfo &clinfo,
2470 const TriOverlaps &ov,
2473 const int dbg_level = 0;
2474 if (dbg_level > 0) {
2475 std::cout <<
"\nCALC_SUBDIVIDED_TRIS\n\n";
2477 Span<BVHTreeOverlap> overlap = ov.overlap();
2478 SubdivideTrisData
data(r_tri_subdivided, tm, itt_map, overlap, arena);
2479 int overlap_tot = overlap.size();
2480 data.overlap_tri_range = Vector<OverlapTriRange>();
2481 data.overlap_tri_range.reserve(overlap_tot);
2482 int overlap_index = 0;
2483 while (overlap_index < overlap_tot) {
2484 int t = overlap[overlap_index].indexA;
2485 int i = overlap_index;
2486 while (i + 1 < overlap_tot && overlap[i + 1].indexA ==
t) {
2492 if (clinfo.tri_cluster(
t) == NO_INDEX) {
2493 int len = i - overlap_index + 1;
2494 if (!(
len == 1 && overlap[overlap_index].indexB ==
t)) {
2495 OverlapTriRange range = {
t, overlap_index,
len};
2496 data.overlap_tri_range.append(range);
2498 bumpperfcount(0,
len);
2502 overlap_index = i + 1;
2504 int overlap_tri_range_tot =
data.overlap_tri_range.size();
2510 0, overlap_tri_range_tot, &
data, calc_subdivided_tri_range_func, &settings);
2513 for (
int t : tm.face_index_range()) {
2514 if (r_tri_subdivided[
t].face_size() == 0 && clinfo.tri_cluster(
t) == NO_INDEX) {
2515 r_tri_subdivided[
t] = IMesh({tm.face(
t)});
2527 static void calc_cluster_tris(Array<IMesh> &tri_subdivided,
2529 const CoplanarClusterInfo &clinfo,
2530 const Array<CDT_data> &cluster_subdivided,
2533 for (
int c : clinfo.index_range()) {
2534 const CoplanarCluster &cl = clinfo.cluster(
c);
2535 const CDT_data &cd = cluster_subdivided[
c];
2543 int n_cluster_tris = cl.tot_tri();
2545 BLI_assert(cd.input_face.size() == n_cluster_tris);
2546 Array<Vector<Face *>> face_vec(n_cluster_tris);
2547 for (
int cdt_out_t : cdt_out.face.index_range()) {
2548 for (
int cdt_in_t : cdt_out.face_orig[cdt_out_t]) {
2549 Face *f = cdt_tri_as_imesh_face(cdt_out_t, cdt_in_t, cd, tm, arena);
2550 face_vec[cdt_in_t].append(f);
2553 for (
int cdt_in_t : cd.input_face.index_range()) {
2554 int tm_t = cd.input_face[cdt_in_t];
2555 BLI_assert(tri_subdivided[tm_t].face_size() == 0);
2556 tri_subdivided[tm_t] = IMesh(face_vec[cdt_in_t]);
2561 static CDT_data calc_cluster_subdivided(
const CoplanarClusterInfo &clinfo,
2564 const TriOverlaps &ov,
2565 const Map<std::pair<int, int>, ITT_value> &itt_map,
2566 IMeshArena *
UNUSED(arena))
2568 constexpr
int dbg_level = 0;
2570 const CoplanarCluster &cl = clinfo.cluster(
c);
2572 if (dbg_level > 0) {
2573 std::cout <<
"CALC_CLUSTER_SUBDIVIDED for cluster " <<
c <<
" = " << cl <<
"\n";
2578 Vector<ITT_value> itts;
2579 Span<BVHTreeOverlap> ovspan = ov.overlap();
2581 if (dbg_level > 0) {
2582 std::cout <<
"find intersects with triangle " <<
t <<
" of cluster\n";
2584 int first_i = ov.first_overlap_index(
t);
2585 if (first_i == -1) {
2588 for (
int i = first_i; i < ovspan.size() && ovspan[i].indexA ==
t; ++i) {
2589 int t_other = ovspan[i].indexB;
2590 if (clinfo.tri_cluster(t_other) !=
c) {
2591 if (dbg_level > 0) {
2592 std::cout <<
"use intersect(" <<
t <<
"," << t_other <<
"\n";
2594 std::pair<int, int> key = canon_int_pair(
t, t_other);
2595 if (itt_map.contains(key)) {
2596 ITT_value itt = itt_map.lookup(key);
2597 if (!
ELEM(itt.kind, INONE, ICOPLANAR)) {
2599 if (dbg_level > 0) {
2600 std::cout <<
" itt = " << itt <<
"\n";
2608 CDT_data cd_data = prepare_cdt_input_for_cluster(tm, clinfo,
c, itts);
2616 for (
const IMesh &m : tri_subdivided) {
2617 tot_tri += m.face_size();
2619 Array<Face *>
faces(tot_tri);
2621 for (
const IMesh &m : tri_subdivided) {
2622 for (
Face *f : m.faces()) {
2623 faces[face_index++] = f;
2626 return IMesh(
faces);
2629 static CoplanarClusterInfo find_clusters(
const IMesh &tm,
2630 const Array<BoundingBox> &tri_bb,
2631 const Map<std::pair<int, int>, ITT_value> &itt_map)
2633 constexpr
int dbg_level = 0;
2634 if (dbg_level > 0) {
2635 std::cout <<
"FIND_CLUSTERS\n";
2637 CoplanarClusterInfo ans(tm.face_size());
2639 VectorSet<int> maybe_coplanar_tris;
2640 maybe_coplanar_tris.reserve(2 * itt_map.size());
2641 for (
auto item : itt_map.items()) {
2642 if (item.value.kind == ICOPLANAR) {
2643 int t1 = item.key.first;
2644 int t2 = item.key.second;
2645 maybe_coplanar_tris.add_multiple({t1, t2});
2648 if (dbg_level > 0) {
2649 std::cout <<
"found " << maybe_coplanar_tris.size() <<
" possible coplanar tris\n";
2651 if (maybe_coplanar_tris.size() == 0) {
2652 if (dbg_level > 0) {
2653 std::cout <<
"No possible coplanar tris, so no clusters\n";
2660 Map<Plane, Vector<CoplanarCluster>> plane_cls;
2661 plane_cls.reserve(maybe_coplanar_tris.size());
2662 for (
int t : maybe_coplanar_tris) {
2666 Plane tplane = *tm.face(
t)->plane;
2668 tplane.make_canonical();
2669 if (dbg_level > 0) {
2670 std::cout <<
"plane for tri " <<
t <<
" = " << &tplane <<
"\n";
2673 if (plane_cls.contains(tplane)) {
2674 Vector<CoplanarCluster> &curcls = plane_cls.lookup(tplane);
2675 if (dbg_level > 0) {
2676 std::cout <<
"already has " << curcls.size() <<
" clusters\n";
2679 Vector<CoplanarCluster *> int_cls;
2680 Vector<CoplanarCluster *> no_int_cls;
2681 for (CoplanarCluster &cl : curcls) {
2682 if (dbg_level > 1) {
2683 std::cout <<
"consider intersecting with cluster " << cl <<
"\n";
2685 if (bbs_might_intersect(tri_bb[
t], cl.bounding_box())) {
2686 if (dbg_level > 1) {
2687 std::cout <<
"append to int_cls\n";
2689 int_cls.append(&cl);
2692 if (dbg_level > 1) {
2693 std::cout <<
"append to no_int_cls\n";
2695 no_int_cls.append(&cl);
2698 if (int_cls.size() == 0) {
2700 if (dbg_level > 1) {
2701 std::cout <<
"no intersecting clusters for t, make a new one\n";
2703 curcls.append(CoplanarCluster(
t, tri_bb[
t]));
2705 else if (int_cls.size() == 1) {
2707 if (dbg_level > 1) {
2708 std::cout <<
"exactly one existing cluster, " << int_cls[0] <<
", adding to it\n";
2710 int_cls[0]->add_tri(
t, tri_bb[
t]);
2715 if (dbg_level > 1) {
2716 std::cout <<
"merging\n";
2718 CoplanarCluster mergecl;
2719 mergecl.add_tri(
t, tri_bb[
t]);
2720 for (CoplanarCluster *cl : int_cls) {
2722 mergecl.add_tri(
t, tri_bb[
t]);
2725 Vector<CoplanarCluster> newvec;
2726 newvec.append(mergecl);
2727 for (CoplanarCluster *cl_no_int : no_int_cls) {
2728 newvec.append(*cl_no_int);
2730 plane_cls.add_overwrite(tplane, newvec);
2734 if (dbg_level > 0) {
2735 std::cout <<
"first cluster for its plane\n";
2737 plane_cls.add_new(tplane, Vector<CoplanarCluster>{CoplanarCluster(
t, tri_bb[
t])});
2742 for (
auto item : plane_cls.items()) {
2743 for (
const CoplanarCluster &cl : item.value) {
2744 if (cl.tot_tri() > 1) {
2745 ans.add_cluster(cl);
2753 static bool face_is_degenerate(
const Face *f)
2755 const Face &face = *f;
2756 const Vert *v0 = face[0];
2757 const Vert *
v1 = face[1];
2758 const Vert *
v2 = face[2];
2759 if (v0 ==
v1 || v0 ==
v2 ||
v1 ==
v2) {
2762 double3 da =
v2->
co - v0->co;
2763 double3 db =
v2->
co -
v1->co;
2764 double3 dab = double3::cross_high_precision(da, db);
2765 double dab_length_squared = dab.length_squared();
2766 double err_bound = supremum_dot_cross(dab, dab) * index_dot_cross * DBL_EPSILON;
2767 if (dab_length_squared > err_bound) {
2770 mpq3
a =
v2->co_exact - v0->co_exact;
2771 mpq3 b =
v2->co_exact -
v1->co_exact;
2773 if (ab.x == 0 && ab.y == 0 && ab.z == 0) {
2785 struct DegenChunkData {
2786 bool has_degenerate_tri =
false;
2789 static void degenerate_range_func(
void *__restrict userdata,
2793 DegenData *
data =
static_cast<DegenData *
>(userdata);
2794 DegenChunkData *chunk_data =
static_cast<DegenChunkData *
>(tls->userdata_chunk);
2795 const Face *f =
data->tm.face(iter);
2796 bool is_degenerate = face_is_degenerate(f);
2797 chunk_data->has_degenerate_tri |= is_degenerate;
2800 static void degenerate_reduce(
const void *__restrict
UNUSED(userdata),
2801 void *__restrict chunk_join,
2802 void *__restrict chunk)
2804 DegenChunkData *degen_chunk_join =
static_cast<DegenChunkData *
>(chunk_join);
2805 DegenChunkData *degen_chunk =
static_cast<DegenChunkData *
>(chunk);
2806 degen_chunk_join->has_degenerate_tri |= degen_chunk->has_degenerate_tri;
2810 static bool has_degenerate_tris(
const IMesh &tm)
2812 DegenData degen_data = {tm};
2813 DegenChunkData degen_chunk_data;
2822 return degen_chunk_data.has_degenerate_tri;
2825 static IMesh remove_degenerate_tris(
const IMesh &tm_in)
2828 Vector<Face *> new_faces;
2829 new_faces.reserve(tm_in.face_size());
2830 for (
Face *f : tm_in.faces()) {
2831 if (!face_is_degenerate(f)) {
2832 new_faces.append(f);
2835 ans.set_faces(new_faces);
2840 IMesh trimesh_self_intersect(
const IMesh &tm_in, IMeshArena *arena)
2842 return trimesh_nary_intersect(
2843 tm_in, 1, [](
int UNUSED(
t)) {
return 0; },
true, arena);
2846 IMesh trimesh_nary_intersect(
const IMesh &tm_in,
2848 std::function<
int(
int)> shape_fn,
2852 constexpr
int dbg_level = 0;
2853 if (dbg_level > 0) {
2854 std::cout <<
"\nTRIMESH_NARY_INTERSECT nshapes=" << nshapes <<
" use_self=" << use_self
2856 for (
const Face *f : tm_in.faces()) {
2860 if (dbg_level > 1) {
2861 std::cout <<
"input mesh:\n" << tm_in;
2862 for (
int t : tm_in.face_index_range()) {
2863 std::cout <<
"shape(" <<
t <<
") = " << shape_fn(tm_in.face(
t)->orig) <<
"\n";
2865 write_obj_mesh(
const_cast<IMesh &
>(tm_in),
"trimesh_input");
2871 std::cout <<
"trimesh_nary_intersect start\n";
2875 const IMesh *tm_clean = &tm_in;
2877 if (has_degenerate_tris(tm_in)) {
2878 if (dbg_level > 0) {
2879 std::cout <<
"cleaning degenerate triangles\n";
2881 tm_cleaned = remove_degenerate_tris(tm_in);
2882 tm_clean = &tm_cleaned;
2883 if (dbg_level > 1) {
2884 std::cout <<
"cleaned input mesh:\n" << tm_cleaned;
2889 std::cout <<
"cleaned, time = " << clean_time - start_time <<
"\n";
2891 Array<BoundingBox> tri_bb = calc_face_bounding_boxes(*tm_clean);
2894 std::cout <<
"bbs calculated, time = " << bb_calc_time - clean_time <<
"\n";
2896 TriOverlaps tri_ov(*tm_clean, tri_bb, nshapes, shape_fn, use_self);
2899 std::cout <<
"intersect overlaps calculated, time = " << overlap_time - bb_calc_time <<
"\n";
2901 for (
int t : tm_clean->face_index_range()) {
2902 if (tri_ov.first_overlap_index(
t) != -1) {
2903 tm_clean->face(
t)->populate_plane(
true);
2908 std::cout <<
"planes populated, time = " << plane_populate - overlap_time <<
"\n";
2912 Map<std::pair<int, int>, ITT_value> itt_map;
2913 itt_map.reserve(tri_ov.overlap().size());
2914 calc_overlap_itts(itt_map, *tm_clean, tri_ov, arena);
2917 std::cout <<
"itts found, time = " << itt_time - plane_populate <<
"\n";
2919 CoplanarClusterInfo clinfo = find_clusters(*tm_clean, tri_bb, itt_map);
2920 if (dbg_level > 1) {
2921 std::cout << clinfo;
2925 std::cout <<
"clusters found, time = " << find_cluster_time - itt_time <<
"\n";
2926 doperfmax(0, tm_in.face_size());
2927 doperfmax(1, clinfo.tot_cluster());
2928 doperfmax(2, tri_ov.overlap().size());
2930 Array<IMesh> tri_subdivided(tm_clean->face_size());
2931 calc_subdivided_non_cluster_tris(tri_subdivided, *tm_clean, itt_map, clinfo, tri_ov, arena);
2934 std::cout <<
"subdivided non-cluster tris found, time = " << subdivided_tris_time - itt_time
2937 Array<CDT_data> cluster_subdivided(clinfo.tot_cluster());
2938 for (
int c : clinfo.index_range()) {
2939 cluster_subdivided[
c] = calc_cluster_subdivided(clinfo,
c, *tm_clean, tri_ov, itt_map, arena);
2943 std::cout <<
"subdivided clusters found, time = "
2944 << cluster_subdivide_time - subdivided_tris_time <<
"\n";
2946 calc_cluster_tris(tri_subdivided, *tm_clean, clinfo, cluster_subdivided, arena);
2949 std::cout <<
"subdivided cluster tris found, time = " << extract_time - cluster_subdivide_time
2952 IMesh combined = union_tri_subdivides(tri_subdivided);
2953 if (dbg_level > 1) {
2954 std::cout <<
"TRIMESH_NARY_INTERSECT answer:\n";
2955 std::cout << combined;
2959 std::cout <<
"triangles combined, time = " << end_time - extract_time <<
"\n";
2960 std::cout <<
"trimesh_nary_intersect done, total time = " << end_time - start_time <<
"\n";
2966 static std::ostream &
operator<<(std::ostream &os,
const CoplanarCluster &cl)
2970 for (
const int t : cl) {
2983 static std::ostream &
operator<<(std::ostream &os,
const CoplanarClusterInfo &clinfo)
2985 os <<
"Coplanar Cluster Info:\n";
2986 for (
int c : clinfo.index_range()) {
2987 os <<
c <<
": " << clinfo.cluster(
c) <<
"\n";
2992 static std::ostream &
operator<<(std::ostream &os,
const ITT_value &itt)
2999 os <<
"point " << itt.p1;
3002 os <<
"segment " << itt.p1 <<
" " << itt.p2;
3005 os <<
"co-planar t" << itt.t_source;
3014 void write_obj_mesh(IMesh &m,
const std::string &objname)
3022 const char *objdir =
"/tmp/";
3024 if (m.face_size() == 0) {
3028 std::string fname = std::string(objdir) + objname + std::string(
".obj");
3032 std::cout <<
"Could not open file " << fname <<
"\n";
3036 if (!m.has_verts()) {
3039 for (
const Vert *
v : m.vertices()) {
3040 const double3 dv =
v->
co;
3041 f <<
"v " << dv[0] <<
" " << dv[1] <<
" " << dv[2] <<
"\n";
3044 for (
const Face *face : m.faces()) {
3047 for (
const Vert *
v : *face) {
3048 int i = m.lookup_vert(
v);
3062 Vector<const char *> count_name;
3064 Vector<const char *> max_name;
3067 static PerfCounts *perfdata =
nullptr;
3069 static void perfdata_init(
void)
3071 perfdata =
new PerfCounts;
3074 perfdata->count.append(0);
3075 perfdata->count_name.append(
"Non-cluster overlaps");
3078 perfdata->count.append(0);
3079 perfdata->count_name.append(
"intersect_tri_tri calls");
3082 perfdata->count.append(0);
3083 perfdata->count_name.append(
"tri tri intersects decided by filter plane tests");
3086 perfdata->count.append(0);
3087 perfdata->count_name.append(
"tri tri intersects decided by exact plane tests");
3090 perfdata->count.append(0);
3091 perfdata->count_name.append(
"final non-NONE intersects");
3094 perfdata->max.append(0);
3095 perfdata->max_name.append(
"total faces");
3098 perfdata->max.append(0);
3099 perfdata->max_name.append(
"total clusters");
3102 perfdata->max.append(0);
3103 perfdata->max_name.append(
"total overlaps");
3106 static void incperfcount(
int countnum)
3108 perfdata->count[countnum]++;
3111 static void bumpperfcount(
int countnum,
int amt)
3113 perfdata->count[countnum] += amt;
3116 static void doperfmax(
int maxnum,
int val)
3118 perfdata->max[maxnum] =
max_ii(perfdata->max[maxnum], val);
3121 static void dump_perfdata(
void)
3123 std::cout <<
"\nPERFDATA\n";
3124 for (
int i : perfdata->count.index_range()) {
3125 std::cout << perfdata->count_name[i] <<
" = " << perfdata->count[i] <<
"\n";
3127 for (
int i : perfdata->max.index_range()) {
3128 std::cout << perfdata->max_name[i] <<
" = " << perfdata->max[i] <<
"\n";
typedef float(TangentPoint)[2]
BVHTreeOverlap * BLI_bvhtree_overlap(const BVHTree *tree1, const BVHTree *tree2, unsigned int *r_overlap_tot, BVHTree_OverlapCallback callback, void *userdata)
void BLI_bvhtree_balance(BVHTree *tree)
BVHTree * BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
void BLI_bvhtree_free(BVHTree *tree)
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
MINLINE double max_dd(double a, double b)
Math vector functions needed specifically for mesh intersect and boolean.
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 float normalize_v3(float r[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
const char * BLI_getenv(const char *env) ATTR_NONNULL(1)
void BLI_polyfill_calc(const float(*coords)[2], const unsigned int coords_tot, const int coords_sign, unsigned int(*r_tris)[3])
void BLI_task_parallel_range(const int start, const 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)
#define UNUSED_VARS_NDEBUG(...)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble z
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint i1
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
#define MEM_reallocN(vmemh, len)
Platform independent time functions.
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)
void sort(btMatrix3x3 &U, btVector3 &sigma, btMatrix3x3 &V, int t)
Helper function of 3X3 SVD for sorting singular values.
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
static CCL_NAMESPACE_BEGIN const double alpha
std::ostream & operator<<(std::ostream &stream, const GeometrySet &geometry_set)
bool operator==(const GeometrySet &UNUSED(a), const GeometrySet &UNUSED(b))
IconTextureDrawCall normal
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
void(* MEM_freeN)(void *vmemh)
unsigned __int64 uint64_t
TaskParallelReduceFunc func_reduce
size_t userdata_chunk_size
double PIL_check_seconds_timer(void)
__forceinline avxf cross(const avxf &a, const avxf &b)
__forceinline const avxi abs(const avxi &a)
ccl_device_inline float dot(const float2 &a, const float2 &b)
ccl_device_inline float2 fabs(const float2 &a)