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 <<
"]";
163 : vert(
verts), edge_orig(edge_origs), is_intersect(is_intersect), 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) {
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) {
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)
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) {
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) {
490 vtry->id = next_vert_id_++;
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) {
529 vtry->id = next_vert_id_++;
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);
592 return pimpl_->add_face(
verts, orig, edge_origs, is_intersect);
597 return pimpl_->add_face(
verts, orig, edge_origs);
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);
617 return pimpl_->find_face(
verts);
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;
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;
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;
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);
852 int n = m.face_size();
855 BBCalcData
data(m, &ans);
856 BBChunkData chunk_data;
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;
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)
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
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;
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,
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;
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});
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;
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();
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();
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);
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);
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)
2242 if (any_degenerate_tris_fast(ans)) {
2243 return exact_triangulate_poly(f, arena);
2248IMesh triangulate_polymesh(IMesh &imesh, IMeshArena *arena)
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();
2269 for (Face *tri : tris) {
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;
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);
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;
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;
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";
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();
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";
2551 struct OverlapTriRange {
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();
2583 int grain_size = 64;
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,
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);
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";
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();
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,
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());
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;
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";
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";
2791 if (dbg_level > 0) {
2792 std::cout <<
"already has " << curcls.
size() <<
" clusters\n";
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";
2808 if (dbg_level > 1) {
2809 std::cout <<
"append to no_int_cls\n";
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]);
2843 for (CoplanarCluster *cl_no_int : no_int_cls) {
2844 newvec.
append(*cl_no_int);
2850 if (dbg_level > 0) {
2851 std::cout <<
"first cluster for its plane\n";
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;
2911 return degen_chunk_data.has_degenerate_tri;
2914static IMesh remove_degenerate_tris(
const IMesh &tm_in)
2918 new_faces.
reserve(tm_in.face_size());
2919 for (Face *f : tm_in.faces()) {
2920 if (!face_is_degenerate(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,
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";
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";
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
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)
struct BVHTreeOverlap BVHTreeOverlap
void BLI_bvhtree_balance(BVHTree *tree)
void BLI_bvhtree_free(BVHTree *tree)
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints)
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)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Map
bool operator==(const AssetWeakReference &a, const AssetWeakReference &b)
int pad[32 - sizeof(int)]
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
void fill(const T &value) const
bool add_overwrite(const Key &key, const Value &value)
const Value & lookup(const Key &key) const
Value lookup_default(const Key &key, const Value &default_value) const
void add_new(const Key &key, const Value &value)
ItemIterator items() const
bool contains(const Key &key) const
void reserve(const int64_t n)
void add_new(const Key &key)
const Key * lookup_key_ptr(const Key &key) const
constexpr int64_t size() const
void reserve(const int64_t n)
void add_multiple(Span< Key > keys)
int64_t append_and_get_index(const T &value)
void append(const T &value)
IndexRange index_range() const
void resize(const int64_t new_size)
void reserve(const int64_t min_capacity)
local_group_size(16, 16) .push_constant(Type b
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
struct BoundingBox { packed_float3 min; packed_float3 max;} BoundingBox
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
TaskParallelReduceFunc func_reduce
size_t userdata_chunk_size
std::ostream & operator<<(std::ostream &stream, bUUID uuid)