5#include "testing/testing.h"
19#define DO_REGULAR_TESTS 1
20#define DO_PERF_TESTS 0
23namespace blender::meshintersect::tests {
25constexpr bool DO_OBJ =
false;
34 static constexpr int MAX_FACE_LEN = 1000;
36 static int edge_index(
int face_index,
int facepos)
38 return face_index * MAX_FACE_LEN + facepos;
41 static std::pair<int, int> face_and_pos_for_edge_index(
int e_index)
43 return std::pair<int, int>(e_index / MAX_FACE_LEN, e_index % MAX_FACE_LEN);
54 IMeshBuilder(
const char *spec)
56 std::istringstream ss(spec);
59 std::istringstream hdrss(line);
62 if (nv == 0 || nf == 0) {
65 arena.reserve(nv, nf);
66 Vector<const Vert *>
verts;
70 while (v_index < nv && spec_ok && getline(ss, line)) {
71 std::istringstream iss(line);
75 iss >> p0 >> p1 >> p2;
76 spec_ok = !iss.fail();
78 verts.append(arena.add_or_find_vert(mpq3(p0, p1, p2), v_index));
86 while (f_index < nf && spec_ok && getline(ss, line)) {
87 std::istringstream fss(line);
88 Vector<const Vert *> face_verts;
89 Vector<int> edge_orig;
91 while (spec_ok && fss >> v_index) {
92 if (v_index < 0 || v_index >= nv) {
96 face_verts.append(
verts[v_index]);
97 edge_orig.append(edge_index(f_index, fpos));
104 Face *facep = arena.add_face(face_verts, f_index, edge_orig);
113 std::cout <<
"Bad spec: " << spec;
116 imesh = IMesh(faces);
123static const Face *find_tri_with_verts(
const IMesh &mesh,
128 Face f_arg({v0, v1,
v2}, 0, NO_INDEX);
129 for (
const Face *f : mesh.faces()) {
130 if (f->cyclic_equal(f_arg)) {
138static int count_tris_with_verts(
const IMesh &mesh,
const Vert *v0,
const Vert *v1,
const Vert *
v2)
140 Face f_arg({v0, v1,
v2}, 0, NO_INDEX);
142 for (
const Face *f : mesh.faces()) {
143 if (f->cyclic_equal(f_arg)) {
152static int find_edge_pos_in_tri(
const Vert *v0,
const Vert *v1,
const Face *f)
154 for (
int pos : f->index_range()) {
155 int nextpos = f->next_pos(
pos);
156 if (((*f)[
pos] == v0 && (*f)[nextpos] == v1) || ((*f)[
pos] == v1 && (*f)[nextpos] == v0)) {
166 Vector<const Vert *>
verts;
167 Vector<Face *>
faces;
170 verts.append(arena.add_or_find_vert(mpq3(0, 0, 1), 0));
171 verts.append(arena.add_or_find_vert(mpq3(1, 0, 1), 1));
172 verts.append(arena.add_or_find_vert(mpq3(0.5, 1, 1), 2));
173 faces.append(arena.add_face(
verts, 0, {10, 11, 12}));
176 const Face *f = mesh.face(0);
177 EXPECT_TRUE(f->is_tri());
180TEST(mesh_intersect, TriangulateTri)
182 const char *spec = R
"(3 1
189 IMeshBuilder mb(spec);
190 IMesh im_tri = triangulate_polymesh(mb.imesh, &mb.arena);
194TEST(mesh_intersect, TriangulateQuad)
196 const char *spec = R
"(4 1
204 IMeshBuilder mb(spec);
205 IMesh im_tri = triangulate_polymesh(mb.imesh, &mb.arena);
209TEST(mesh_intersect, TriangulatePentagon)
211 const char *spec = R
"(5 1
220 IMeshBuilder mb(spec);
221 IMesh im_tri = triangulate_polymesh(mb.imesh, &mb.arena);
224 write_obj_mesh(im_tri,
"pentagon");
228TEST(mesh_intersect, TriangulateTwoFaces)
230 const char *spec = R
"(7 2
231 461/250 -343/125 103/1000
232 -3/40 -453/200 -97/500
233 237/100 -321/200 -727/500
234 451/1000 -563/500 -1751/1000
235 12/125 -2297/1000 -181/1000
236 12/125 -411/200 -493/1000
237 1959/1000 -2297/1000 -493/1000
242 IMeshBuilder mb(spec);
243 IMesh im_tri = triangulate_polymesh(mb.imesh, &mb.arena);
246 write_obj_mesh(im_tri,
"twofaces");
250TEST(mesh_intersect, OneTri)
252 const char *spec = R
"(3 1
259 IMeshBuilder mb(spec);
260 IMesh imesh = trimesh_self_intersect(mb.imesh, &mb.arena);
261 imesh.populate_vert();
264 const Face &f_in = *mb.imesh.face(0);
265 const Face &f_out = *imesh.face(0);
267 for (
int i = 0; i < 3; ++i) {
269 EXPECT_EQ(f_in.edge_orig[i], f_out.edge_orig[i]);
273TEST(mesh_intersect, TriTri)
275 const char *spec = R
"(6 2
287 IMeshBuilder mb(spec);
288 IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena);
292 if (out.vert_size() == 6 && out.face_size() == 6) {
293 const Vert *v0 = mb.arena.find_vert(mpq3(0, 0, 0));
294 const Vert *v1 = mb.arena.find_vert(mpq3(4, 0, 0));
295 const Vert *
v2 = mb.arena.find_vert(mpq3(0, 4, 0));
296 const Vert *v3 = mb.arena.find_vert(mpq3(1, 0, 0));
297 const Vert *v4 = mb.arena.find_vert(mpq3(2, 0, 0));
298 const Vert *v5 = mb.arena.find_vert(mpq3(1, 1, 0));
299 EXPECT_TRUE(v0 !=
nullptr && v1 !=
nullptr &&
v2 !=
nullptr);
300 EXPECT_TRUE(v3 !=
nullptr && v4 !=
nullptr && v5 !=
nullptr);
301 if (v0 !=
nullptr && v1 !=
nullptr &&
v2 !=
nullptr && v3 !=
nullptr && v4 !=
nullptr &&
306 const Face *f0 = find_tri_with_verts(out, v4, v1, v5);
307 const Face *f1 = find_tri_with_verts(out, v3, v4, v5);
308 const Face *f2 = find_tri_with_verts(out, v0, v3, v5);
309 const Face *f3 = find_tri_with_verts(out, v0, v5,
v2);
310 const Face *f4 = find_tri_with_verts(out, v5, v1,
v2);
311 EXPECT_TRUE(f0 !=
nullptr && f1 !=
nullptr && f2 !=
nullptr && f3 !=
nullptr &&
315 EXPECT_EQ(count_tris_with_verts(out, v3, v4, v5), 2);
316 if (f0 !=
nullptr && f1 !=
nullptr && f2 !=
nullptr && f3 !=
nullptr && f4 !=
nullptr) {
318 EXPECT_TRUE(f1->orig == 0 || f1->orig == 1);
323 int e03 = find_edge_pos_in_tri(v0, v3, f2);
324 int e34 = find_edge_pos_in_tri(v3, v4, f1);
325 int e45 = find_edge_pos_in_tri(v4, v5, f1);
326 int e05 = find_edge_pos_in_tri(v0, v5, f3);
327 int e15 = find_edge_pos_in_tri(v1, v5, f0);
328 EXPECT_TRUE(e03 != -1 && e34 != -1 && e45 != -1 && e05 != -1 && e15 != -1);
329 if (e03 != -1 && e34 != -1 && e45 != -1 && e05 != -1 && e15 != -1) {
331 EXPECT_TRUE(f1->edge_orig[e34] == 0 ||
332 f1->edge_orig[e34] == 1 * IMeshBuilder::MAX_FACE_LEN);
333 EXPECT_EQ(f1->edge_orig[e45], 1 * IMeshBuilder::MAX_FACE_LEN + 1);
340 write_obj_mesh(out,
"tritri");
344TEST(mesh_intersect, TriTriReversed)
348 const char *spec = R
"(6 2
359 IMeshBuilder mb(spec);
360 IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena);
364 if (out.vert_size() == 6 && out.face_size() == 6) {
365 const Vert *v0 = mb.arena.find_vert(mpq3(0, 0, 0));
366 const Vert *v1 = mb.arena.find_vert(mpq3(4, 0, 0));
367 const Vert *
v2 = mb.arena.find_vert(mpq3(0, 4, 0));
368 const Vert *v3 = mb.arena.find_vert(mpq3(1, 0, 0));
369 const Vert *v4 = mb.arena.find_vert(mpq3(2, 0, 0));
370 const Vert *v5 = mb.arena.find_vert(mpq3(1, 1, 0));
371 EXPECT_TRUE(v0 !=
nullptr && v1 !=
nullptr &&
v2 !=
nullptr);
372 EXPECT_TRUE(v3 !=
nullptr && v4 !=
nullptr && v5 !=
nullptr);
373 if (v0 !=
nullptr && v1 !=
nullptr &&
v2 !=
nullptr && v3 !=
nullptr && v4 !=
nullptr &&
378 const Face *f0 = find_tri_with_verts(out, v4, v5, v1);
379 const Face *f1 = find_tri_with_verts(out, v3, v5, v4);
380 const Face *f2 = find_tri_with_verts(out, v0, v5, v3);
381 const Face *f3 = find_tri_with_verts(out, v0,
v2, v5);
382 const Face *f4 = find_tri_with_verts(out, v5,
v2, v1);
383 EXPECT_TRUE(f0 !=
nullptr && f1 !=
nullptr && f2 !=
nullptr && f3 !=
nullptr &&
387 EXPECT_EQ(count_tris_with_verts(out, v3, v5, v4), 2);
388 if (f0 !=
nullptr && f1 !=
nullptr && f2 !=
nullptr && f3 !=
nullptr && f4 !=
nullptr) {
390 EXPECT_TRUE(f1->orig == 0 || f1->orig == 1);
395 int e03 = find_edge_pos_in_tri(v0, v3, f2);
396 int e34 = find_edge_pos_in_tri(v3, v4, f1);
397 int e45 = find_edge_pos_in_tri(v4, v5, f1);
398 int e05 = find_edge_pos_in_tri(v0, v5, f3);
399 int e15 = find_edge_pos_in_tri(v1, v5, f0);
400 EXPECT_TRUE(e03 != -1 && e34 != -1 && e45 != -1 && e05 != -1 && e15 != -1);
401 if (e03 != -1 && e34 != -1 && e45 != -1 && e05 != -1 && e15 != -1) {
403 EXPECT_TRUE(f1->edge_orig[e34] == 2 ||
404 f1->edge_orig[e34] == 1 * IMeshBuilder::MAX_FACE_LEN + 2);
405 EXPECT_EQ(f1->edge_orig[e45], 1 * IMeshBuilder::MAX_FACE_LEN + 1);
412 write_obj_mesh(out,
"tritrirev");
416TEST(mesh_intersect, TwoTris)
418 Array<mpq3>
verts = {
419 mpq3(1, 1, 1), mpq3(1, 4, 1), mpq3(1, 1, 4),
420 mpq3(2, 2, 2), mpq3(-3, 3, 2), mpq3(-4, 1, 3),
421 mpq3(2, 2, 2), mpq3(-3, 3, 2), mpq3(0, 3, 5),
422 mpq3(2, 2, 2), mpq3(-3, 3, 2), mpq3(0, 3, 3),
423 mpq3(1, 0, 0), mpq3(2, 4, 1), mpq3(-3, 2, 2),
424 mpq3(0, 2, 1), mpq3(-2, 3, 3), mpq3(0, 1, 3),
425 mpq3(1.5, 2, 0.5), mpq3(-2, 3, 3), mpq3(0, 1, 3),
426 mpq3(1, 0, 0), mpq3(-2, 3, 3), mpq3(0, 1, 3),
427 mpq3(1, 0, 0), mpq3(-3, 2, 2), mpq3(0, 1, 3),
428 mpq3(1, 0, 0), mpq3(-1, 1, 1), mpq3(0, 1, 3),
429 mpq3(3, -1, -1), mpq3(-1, 1, 1), mpq3(0, 1, 3),
430 mpq3(0, 0.5, 0.5), mpq3(-1, 1, 1), mpq3(0, 1, 3),
431 mpq3(2, 1, 1), mpq3(3, 5, 2), mpq3(-2, 3, 3),
432 mpq3(2, 1, 1), mpq3(3, 5, 2), mpq3(-2, 3, 4),
433 mpq3(2, 2, 5), mpq3(-3, 3, 5), mpq3(0, 3, 10),
434 mpq3(0, 0, 0), mpq3(4, 4, 0), mpq3(-4, 2, 4),
435 mpq3(0, 1.5, 1), mpq3(1, 2.5, 1), mpq3(-1, 2, 2),
436 mpq3(3, 0, -2), mpq3(7, 4, -2), mpq3(-1, 2, 2),
437 mpq3(3, 0, -2), mpq3(3, 6, 2), mpq3(-1, 2, 2),
438 mpq3(7, 4, -2), mpq3(3, 6, 2), mpq3(-1, 2, 2),
439 mpq3(5, 2, -2), mpq3(1, 4, 2), mpq3(-3, 0, 2),
440 mpq3(2, 2, 0), mpq3(1, 4, 2), mpq3(-3, 0, 2),
441 mpq3(0, 0, 0), mpq3(4, 4, 0), mpq3(-3, 0, 2),
442 mpq3(0, 0, 0), mpq3(4, 4, 0), mpq3(-1, 2, 2),
443 mpq3(2, 2, 0), mpq3(4, 4, 0), mpq3(0, 3, 2),
444 mpq3(0, 0, 0), mpq3(-4, 2, 4), mpq3(4, 4, 0),
446 struct two_tri_test_spec {
452 Array<two_tri_test_spec> test_tris = Span<two_tri_test_spec>{
478 static int perms[6][3] = {{0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0}};
480 const int do_only_test = -1;
481 for (
int test = 0; test < test_tris.size(); ++test) {
482 if (do_only_test >= 0 && test != do_only_test) {
485 int tri1_index = test_tris[test].t0;
486 int tri2_index = test_tris[test].t1;
487 int co1_i = 3 * tri1_index;
488 int co2_i = 3 * tri2_index;
493 std::cout <<
"\nTest " << test <<
": T" << tri1_index <<
" intersect T" << tri2_index
497 const bool do_all_perms =
true;
498 const int perm_limit = do_all_perms ? 3 : 1;
500 for (
int i = 0; i < perm_limit; ++i) {
501 for (
int j = 0; j < perm_limit; ++j) {
503 std::cout <<
"\nperms " << i <<
" " << j <<
"\n";
506 arena.reserve(2 * 3, 2);
507 Array<const Vert *> f0_verts(3);
508 Array<const Vert *> f1_verts(3);
509 for (
int k = 0; k < 3; ++k) {
510 f0_verts[k] = arena.add_or_find_vert(
verts[co1_i + perms[i][k]], k);
512 for (
int k = 0; k < 3; ++k) {
513 f1_verts[k] = arena.add_or_find_vert(
verts[co2_i + perms[i][k]], k + 3);
515 Face *f0 = arena.add_face(f0_verts, 0, {0, 1, 2});
516 Face *f1 = arena.add_face(f1_verts, 1, {3, 4, 5});
517 IMesh in_mesh({f0, f1});
518 IMesh out_mesh = trimesh_self_intersect(in_mesh, &arena);
519 out_mesh.populate_vert();
520 EXPECT_EQ(out_mesh.vert_size(), test_tris[test].nv_out);
521 EXPECT_EQ(out_mesh.face_size(), test_tris[test].nf_out);
522 bool constexpr dump_input =
true;
523 if (DO_OBJ && i == 0 && j == 0) {
525 std::string name =
"test_tt_in" + std::to_string(test);
526 write_obj_mesh(in_mesh, name);
528 std::string name =
"test_tt" + std::to_string(test);
529 write_obj_mesh(out_mesh, name);
536TEST(mesh_intersect, OverlapCluster)
541 const char *spec = R
"(15 5
564 IMeshBuilder mb(spec);
565 IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena);
570 write_obj_mesh(out,
"overlapcluster");
574TEST(mesh_intersect, TriCornerCross1)
577 const char *spec = R
"(12 4
596 IMeshBuilder mb(spec);
597 IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena);
602 write_obj_mesh(out,
"test_tc_1");
606TEST(mesh_intersect, TriCornerCross2)
609 const char *spec = R
"(12 4
628 IMeshBuilder mb(spec);
629 IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena);
634 write_obj_mesh(out,
"test_tc_2");
638TEST(mesh_intersect, TriCornerCross3)
641 const char *spec = R
"(12 4
660 IMeshBuilder mb(spec);
661 IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena);
666 write_obj_mesh(out,
"test_tc_3");
670TEST(mesh_intersect, TetTet)
672 const char *spec = R
"(8 8
691 IMeshBuilder mb(spec);
692 IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena);
698 const Vert *v1 = mb.arena.find_vert(mpq3(2, 0, 0));
699 const Vert *v8 = mb.arena.find_vert(mpq3(0.5, 0.5, 1));
700 const Vert *v9 = mb.arena.find_vert(mpq3(1.5, 0.5, 1));
701 EXPECT_TRUE(v1 && v8 && v9);
702 if (v1 && v8 && v9) {
703 const Face *f = mb.arena.find_face({v1, v8, v9});
704 EXPECT_NE(f,
nullptr);
707 int v1pos = f->vert[0] == v1 ? 0 : (f->vert[1] == v1 ? 1 : 2);
708 EXPECT_EQ(f->edge_orig[v1pos], NO_INDEX);
709 EXPECT_EQ(f->edge_orig[(v1pos + 1) % 3], NO_INDEX);
710 EXPECT_EQ(f->edge_orig[(v1pos + 2) % 3], 1001);
711 EXPECT_EQ(f->is_intersect[v1pos],
false);
712 EXPECT_EQ(f->is_intersect[(v1pos + 1) % 3],
true);
713 EXPECT_EQ(f->is_intersect[(v1pos + 2) % 3],
false);
717 write_obj_mesh(out,
"test_tc_3");
721TEST(mesh_intersect, CubeCubeStep)
723 const char *spec = R
"(16 24
766 IMeshBuilder mb(spec);
767 IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena);
772 write_obj_mesh(out,
"test_cubecubestep");
775 IMeshBuilder mb2(spec);
776 IMesh out2 = trimesh_nary_intersect(
777 mb2.imesh, 2, [](
int t) { return t < 12 ? 0 : 1; },
false, &mb2.arena);
778 out2.populate_vert();
782 write_obj_mesh(out2,
"test_cubecubestep_nary");
786TEST(mesh_intersect, RectCross)
788 const char *spec = R
"(8 4
803 IMeshBuilder mb(spec);
804 IMesh out = trimesh_self_intersect(mb.imesh, &mb.arena);
809 write_obj_mesh(out,
"test_rectcross");
816static void get_sphere_params(
817 int nrings,
int nsegs,
bool triangulate,
int *r_verts_num,
int *r_faces_num)
819 *r_verts_num = nsegs * (nrings - 1) + 2;
821 *r_faces_num = 2 * nsegs + 2 * nsegs * (nrings - 2);
824 *r_faces_num = nsegs * nrings;
828static void fill_sphere_data(
int nrings,
833 MutableSpan<Face *> face,
840 get_sphere_params(nrings, nsegs, triangulate, &verts_num, &faces_num);
842 Array<const Vert *> vert(verts_num);
843 const bool nrings_even = (nrings % 2 == 0);
844 int half_nrings = nrings / 2;
845 const bool nsegs_even = (nsegs % 2) == 0;
846 const bool nsegs_four_divisible = (nsegs % 4 == 0);
847 int half_nsegs = nrings;
848 int quarter_nsegs = half_nsegs / 2;
850 double delta_theta =
M_PI / nrings;
853 auto vert_index_fn = [nrings, verts_num](
int seg,
int ring) {
855 return verts_num - 2;
857 if (ring == nrings) {
858 return verts_num - 1;
860 return seg * (nrings - 1) + (ring - 1);
862 auto face_index_fn = [nrings](
int seg,
int ring) {
return seg * nrings + ring; };
863 auto tri_index_fn = [nrings, nsegs](
int seg,
int ring,
int tri) {
867 if (ring < nrings - 1) {
868 return nsegs + 2 * (ring - 1) * nsegs + 2 * seg + tri;
870 return nsegs + 2 * (nrings - 2) * nsegs + seg;
872 Array<int> eid = {0, 0, 0, 0};
880 for (
int s = 0; s < nsegs; ++s) {
890 else if (nsegs_even && s == half_nsegs) {
895 else if (nsegs_four_divisible && s == quarter_nsegs) {
900 else if (nsegs_four_divisible && s == 3 * quarter_nsegs) {
909 for (
int r = 1; r < nrings; ++r) {
910 double theta = r * delta_theta;
913 if (nrings_even && r == half_nrings) {
915 r_sin_theta = radius;
919 r_sin_theta = radius *
sin(theta);
920 r_cos_theta = radius *
cos(theta);
922 double x = r_sin_theta * cos_phi + center[0];
923 double y = r_sin_theta *
sin_phi + center[1];
924 double z = r_cos_theta + center[2];
925 const Vert *
v = arena->add_or_find_vert(mpq3(x, y,
z), vid++);
926 vert[vert_index_fn(s, r)] =
v;
929 const Vert *vtop = arena->add_or_find_vert(mpq3(center[0], center[1], center[2] + radius),
931 const Vert *vbot = arena->add_or_find_vert(mpq3(center[0], center[1], center[2] - radius),
933 vert[vert_index_fn(0, 0)] = vtop;
934 vert[vert_index_fn(0, nrings)] = vbot;
935 for (
int s = 0; s < nsegs; ++s) {
936 int snext = (s + 1) % nsegs;
937 for (
int r = 0; r < nrings; ++r) {
939 int i0 = vert_index_fn(s, r);
940 int i1 = vert_index_fn(s, rnext);
941 int i2 = vert_index_fn(snext, rnext);
942 int i3 = vert_index_fn(snext, r);
946 f = arena->add_face({vert[i0], vert[i1], vert[i2]}, fid++, eid);
948 else if (r == nrings - 1) {
949 f = arena->add_face({vert[i0], vert[i1], vert[i3]}, fid++, eid);
953 f = arena->add_face({vert[i0], vert[i1], vert[i2]}, fid++, eid);
954 f2 = arena->add_face({vert[i2], vert[i3], vert[i0]}, fid++, eid);
957 f = arena->add_face({vert[i0], vert[i1], vert[i2], vert[i3]}, fid++, eid);
961 int f_index = tri_index_fn(s, r, 0);
963 if (r != 0 && r != nrings - 1) {
964 int f_index2 = tri_index_fn(s, r, 1);
969 int f_index = face_index_fn(s, r);
976static void spheresphere_test(
int nrings,
double y_offset,
bool use_self)
985 int nsegs = 2 * nrings;
986 int sphere_verts_num;
988 get_sphere_params(nrings, nsegs,
true, &sphere_verts_num, &sphere_tris_num);
989 Array<Face *> tris(2 * sphere_tris_num);
990 arena.reserve(6 * sphere_verts_num / 2, 8 * sphere_tris_num);
991 double3 center1(0.0, 0.0, 0.0);
992 fill_sphere_data(nrings,
997 MutableSpan<Face *>(tris.begin(), sphere_tris_num),
1001 double3 center2(0.0, y_offset, 0.0);
1002 fill_sphere_data(nrings,
1007 MutableSpan<Face *>(tris.begin() + sphere_tris_num, sphere_tris_num),
1016 out = trimesh_self_intersect(mesh, &arena);
1019 int nf = sphere_tris_num;
1020 out = trimesh_nary_intersect(
1021 mesh, 2, [nf](
int t) {
return t < nf ? 0 : 1; },
false, &arena);
1024 std::cout <<
"Create time: " << time_create - time_start <<
"\n";
1025 std::cout <<
"Intersect time: " << time_intersect - time_create <<
"\n";
1026 std::cout <<
"Total time: " << time_intersect - time_start <<
"\n";
1028 write_obj_mesh(out,
"spheresphere");
1033static void get_grid_params(
1034 int x_subdiv,
int y_subdiv,
bool triangulate,
int *r_verts_num,
int *r_faces_num)
1036 *r_verts_num = x_subdiv * y_subdiv;
1038 *r_faces_num = 2 * (x_subdiv - 1) * (y_subdiv - 1);
1041 *r_faces_num = (x_subdiv - 1) * (y_subdiv - 1);
1045static void fill_grid_data(
int x_subdiv,
1051 MutableSpan<Face *> face,
1056 if (x_subdiv <= 1 || y_subdiv <= 1) {
1061 get_grid_params(x_subdiv, y_subdiv, triangulate, &verts_num, &faces_num);
1063 Array<const Vert *> vert(verts_num);
1064 auto vert_index_fn = [x_subdiv](
int ix,
int iy) {
return iy * x_subdiv + ix; };
1065 auto face_index_fn = [x_subdiv](
int ix,
int iy) {
return iy * (x_subdiv - 1) + ix; };
1066 auto tri_index_fn = [x_subdiv](
int ix,
int iy,
int tri) {
1067 return 2 * iy * (x_subdiv - 1) + 2 * ix + tri;
1069 Array<int> eid = {0, 0, 0, 0};
1070 double r = size / 2.0;
1071 double delta_x = size / (x_subdiv - 1);
1072 double delta_y = size / (y_subdiv - 1);
1073 int vid = vid_start;
1074 double cos_rot =
cosf(rot_deg *
M_PI / 180.0);
1075 double sin_rot =
sinf(rot_deg *
M_PI / 180.0);
1076 for (
int iy = 0; iy < y_subdiv; ++iy) {
1077 double yy = iy * delta_y - r;
1078 for (
int ix = 0; ix < x_subdiv; ++ix) {
1079 double xx = ix * delta_x - r;
1080 double x = center[0] + xx;
1081 double y = center[1] + yy;
1082 double z = center[2];
1083 if (rot_deg != 0.0) {
1084 x = center[0] + xx * cos_rot - yy * sin_rot;
1085 y = center[1] + xx * sin_rot + yy * cos_rot;
1087 const Vert *
v = arena->add_or_find_vert(mpq3(x, y,
z), vid++);
1088 vert[vert_index_fn(ix, iy)] =
v;
1091 int fid = fid_start;
1092 for (
int iy = 0; iy < y_subdiv - 1; ++iy) {
1093 for (
int ix = 0; ix < x_subdiv - 1; ++ix) {
1094 int i0 = vert_index_fn(ix, iy);
1095 int i1 = vert_index_fn(ix, iy + 1);
1096 int i2 = vert_index_fn(ix + 1, iy + 1);
1097 int i3 = vert_index_fn(ix + 1, iy);
1099 Face *f = arena->add_face({vert[i0], vert[i1], vert[i2]}, fid++, eid);
1100 Face *f2 = arena->add_face({vert[i2], vert[i3], vert[i0]}, fid++, eid);
1101 face[tri_index_fn(ix, iy, 0)] = f;
1102 face[tri_index_fn(ix, iy, 1)] = f2;
1105 Face *f = arena->add_face({vert[i0], vert[i1], vert[i2], vert[i3]}, fid++, eid);
1106 face[face_index_fn(ix, iy)] = f;
1112static void spheregrid_test(
int nrings,
int grid_level,
double z_offset,
bool use_self)
1119 if (nrings < 2 || grid_level < 1) {
1125 int sphere_verts_num;
1126 int sphere_tris_num;
1127 int nsegs = 2 * nrings;
1130 int subdivs = 1 << grid_level;
1131 get_sphere_params(nrings, nsegs,
true, &sphere_verts_num, &sphere_tris_num);
1132 get_grid_params(subdivs, subdivs,
true, &grid_verts_num, &grid_tris_num);
1133 Array<Face *> tris(sphere_tris_num + grid_tris_num);
1134 arena.reserve(3 * (sphere_verts_num + grid_verts_num) / 2,
1135 4 * (sphere_tris_num + grid_tris_num));
1136 double3 center(0.0, 0.0, z_offset);
1137 fill_sphere_data(nrings,
1142 MutableSpan<Face *>(tris.begin(), sphere_tris_num),
1146 fill_grid_data(subdivs,
1152 MutableSpan<Face *>(tris.begin() + sphere_tris_num, grid_tris_num),
1161 out = trimesh_self_intersect(mesh, &arena);
1164 int nf = sphere_tris_num;
1165 out = trimesh_nary_intersect(
1166 mesh, 2, [nf](
int t) {
return t < nf ? 0 : 1; },
false, &arena);
1169 std::cout <<
"Create time: " << time_create - time_start <<
"\n";
1170 std::cout <<
"Intersect time: " << time_intersect - time_create <<
"\n";
1171 std::cout <<
"Total time: " << time_intersect - time_start <<
"\n";
1173 write_obj_mesh(out,
"spheregrid");
1178static void gridgrid_test(
int x_level_1,
1192 int x_subdivs_1 = 1 << x_level_1;
1193 int y_subdivs_1 = 1 << y_level_1;
1194 int x_subdivs_2 = 1 << x_level_2;
1195 int y_subdivs_2 = 1 << y_level_2;
1196 int grid_verts_1_num;
1197 int grid_verts_2_num;
1198 int grid_tris_1_num;
1199 int grid_tris_2_num;
1200 get_grid_params(x_subdivs_1, y_subdivs_1,
true, &grid_verts_1_num, &grid_tris_1_num);
1201 get_grid_params(x_subdivs_2, y_subdivs_2,
true, &grid_verts_2_num, &grid_tris_2_num);
1202 Array<Face *> tris(grid_tris_1_num + grid_tris_2_num);
1203 arena.reserve(3 * (grid_verts_1_num + grid_verts_2_num) / 2,
1204 4 * (grid_tris_1_num + grid_tris_2_num));
1205 fill_grid_data(x_subdivs_1,
1211 MutableSpan<Face *>(tris.begin(), grid_tris_1_num),
1215 fill_grid_data(x_subdivs_2,
1221 MutableSpan<Face *>(tris.begin() + grid_tris_1_num, grid_tris_2_num),
1230 out = trimesh_self_intersect(mesh, &arena);
1233 int nf = grid_tris_1_num;
1234 out = trimesh_nary_intersect(
1235 mesh, 2, [nf](
int t) {
return t < nf ? 0 : 1; },
false, &arena);
1238 std::cout <<
"Create time: " << time_create - time_start <<
"\n";
1239 std::cout <<
"Intersect time: " << time_intersect - time_create <<
"\n";
1240 std::cout <<
"Total time: " << time_intersect - time_start <<
"\n";
1242 write_obj_mesh(out,
"gridgrid");
1247TEST(mesh_intersect_perf, SphereSphere)
1249 spheresphere_test(512, 0.5,
false);
1252TEST(mesh_intersect_perf, SphereSphereSelf)
1254 spheresphere_test(64, 0.5,
true);
1257TEST(mesh_intersect_perf, SphereGrid)
1259 spheregrid_test(512, 4, 0.1,
false);
1262TEST(mesh_intersect_perf, SphereGridSelf)
1264 spheregrid_test(64, 4, 0.1,
true);
1267TEST(mesh_intersect_perf, GridGrid)
1269 gridgrid_test(8, 2, 4, 2, 0.1, 0.1, 0.0,
false);
1272TEST(mesh_intersect_perf, GridGridTilt)
1274 gridgrid_test(8, 2, 4, 2, 0.0, 0.0, 1.0,
false);
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
void BLI_task_scheduler_init(void)
void BLI_task_scheduler_exit(void)
Platform independent time functions.
double BLI_time_now_seconds(void)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
ccl_device_inline float delta_phi(int p, float gamma_o, float gamma_t)
ccl_device float sin_phi(const float3 w)
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
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
TEST(math_rotation, DefaultConstructor)
T cos(const AngleRadianBase< T > &a)
T sin(const AngleRadianBase< T > &a)
VecBase< double, 3 > double3