Blender  V2.93
BLI_mesh_boolean_test.cc
Go to the documentation of this file.
1 /* Apache License, Version 2.0 */
2 
3 #include "testing/testing.h"
4 
5 #include <fstream>
6 #include <iostream>
7 #include <sstream>
8 
9 #include "MEM_guardedalloc.h"
10 
11 #include "BLI_array.hh"
12 #include "BLI_map.hh"
13 #include "BLI_math_mpq.hh"
14 #include "BLI_mesh_boolean.hh"
15 #include "BLI_mpq3.hh"
16 #include "BLI_vector.hh"
17 
18 #ifdef WITH_GMP
19 namespace blender::meshintersect::tests {
20 
21 constexpr bool DO_OBJ = false;
22 
23 /* Build and hold an IMesh from a string spec. Also hold and own resources used by IMesh. */
24 class IMeshBuilder {
25  public:
26  IMesh imesh;
27  IMeshArena arena;
28 
29  /* "Edge orig" indices are an encoding of <input face#, position in face of start of edge>. */
30  static constexpr int MAX_FACE_LEN = 1000; /* Used for forming "orig edge" indices only. */
31 
32  static int edge_index(int face_index, int facepos)
33  {
34  return face_index * MAX_FACE_LEN + facepos;
35  }
36 
37  static std::pair<int, int> face_and_pos_for_edge_index(int e_index)
38  {
39  return std::pair<int, int>(e_index / MAX_FACE_LEN, e_index % MAX_FACE_LEN);
40  }
41 
42  /*
43  * Spec should have form:
44  * #verts #faces
45  * mpq_class mpq_class mpq_clas [#verts lines]
46  * int int int ... [#faces lines; indices into verts for given face]
47  */
48  IMeshBuilder(const char *spec)
49  {
50  std::istringstream ss(spec);
51  std::string line;
52  getline(ss, line);
53  std::istringstream hdrss(line);
54  int nv, nf;
55  hdrss >> nv >> nf;
56  if (nv == 0 || nf == 0) {
57  return;
58  }
59  arena.reserve(nv, nf);
60  Vector<const Vert *> verts;
61  Vector<Face *> faces;
62  bool spec_ok = true;
63  int v_index = 0;
64  while (v_index < nv && spec_ok && getline(ss, line)) {
65  std::istringstream iss(line);
66  mpq_class p0;
67  mpq_class p1;
68  mpq_class p2;
69  iss >> p0 >> p1 >> p2;
70  spec_ok = !iss.fail();
71  verts.append(arena.add_or_find_vert(mpq3(p0, p1, p2), v_index));
72  ++v_index;
73  }
74  if (v_index != nv) {
75  spec_ok = false;
76  }
77  int f_index = 0;
78  while (f_index < nf && spec_ok && getline(ss, line)) {
79  std::istringstream fss(line);
80  Vector<const Vert *> face_verts;
81  Vector<int> edge_orig;
82  int fpos = 0;
83  while (spec_ok && fss >> v_index) {
84  if (v_index < 0 || v_index >= nv) {
85  spec_ok = false;
86  continue;
87  }
88  face_verts.append(verts[v_index]);
89  edge_orig.append(edge_index(f_index, fpos));
90  ++fpos;
91  }
92  Face *facep = arena.add_face(face_verts, f_index, edge_orig);
93  faces.append(facep);
94  ++f_index;
95  }
96  if (f_index != nf) {
97  spec_ok = false;
98  }
99  if (!spec_ok) {
100  std::cout << "Bad spec: " << spec;
101  return;
102  }
103  imesh = IMesh(faces);
104  }
105 };
106 
107 static int all_shape_zero(int UNUSED(t))
108 {
109  return 0;
110 }
111 
112 TEST(boolean_trimesh, Empty)
113 {
114  IMeshArena arena;
115  IMesh in;
116  IMesh out = boolean_trimesh(in, BoolOpType::None, 1, all_shape_zero, true, false, &arena);
117  out.populate_vert();
118  EXPECT_EQ(out.vert_size(), 0);
119  EXPECT_EQ(out.face_size(), 0);
120 }
121 
122 TEST(boolean_trimesh, TetTetTrimesh)
123 {
124  const char *spec = R"(8 8
125  0 0 0
126  2 0 0
127  1 2 0
128  1 1 2
129  0 0 1
130  2 0 1
131  1 2 1
132  1 1 3
133  0 2 1
134  0 1 3
135  1 2 3
136  2 0 3
137  4 6 5
138  4 5 7
139  5 6 7
140  6 4 7
141  )";
142 
143  IMeshBuilder mb(spec);
144  IMesh out = boolean_trimesh(
145  mb.imesh, BoolOpType::None, 1, all_shape_zero, true, false, &mb.arena);
146  out.populate_vert();
147  EXPECT_EQ(out.vert_size(), 11);
148  EXPECT_EQ(out.face_size(), 20);
149  if (DO_OBJ) {
150  write_obj_mesh(out, "tettet_tm");
151  }
152 
153  IMeshBuilder mb2(spec);
154  IMesh out2 = boolean_trimesh(
155  mb2.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb2.arena);
156  out2.populate_vert();
157  EXPECT_EQ(out2.vert_size(), 10);
158  EXPECT_EQ(out2.face_size(), 16);
159  if (DO_OBJ) {
160  write_obj_mesh(out2, "tettet_union_tm");
161  }
162 
163  IMeshBuilder mb3(spec);
164  IMesh out3 = boolean_trimesh(
165  mb3.imesh,
166  BoolOpType::Union,
167  2,
168  [](int t) { return t < 4 ? 0 : 1; },
169  false,
170  false,
171  &mb3.arena);
172  out3.populate_vert();
173  EXPECT_EQ(out3.vert_size(), 10);
174  EXPECT_EQ(out3.face_size(), 16);
175  if (DO_OBJ) {
176  write_obj_mesh(out3, "tettet_union_binary_tm");
177  }
178 
179  IMeshBuilder mb4(spec);
180  IMesh out4 = boolean_trimesh(
181  mb4.imesh,
182  BoolOpType::Union,
183  2,
184  [](int t) { return t < 4 ? 0 : 1; },
185  true,
186  false,
187  &mb4.arena);
188  out4.populate_vert();
189  EXPECT_EQ(out4.vert_size(), 10);
190  EXPECT_EQ(out4.face_size(), 16);
191  if (DO_OBJ) {
192  write_obj_mesh(out4, "tettet_union_binary_self_tm");
193  }
194 
195  IMeshBuilder mb5(spec);
196  IMesh out5 = boolean_trimesh(
197  mb5.imesh,
199  2,
200  [](int t) { return t < 4 ? 0 : 1; },
201  false,
202  false,
203  &mb5.arena);
204  out5.populate_vert();
205  EXPECT_EQ(out5.vert_size(), 4);
206  EXPECT_EQ(out5.face_size(), 4);
207  if (DO_OBJ) {
208  write_obj_mesh(out5, "tettet_intersect_binary_tm");
209  }
210 
211  IMeshBuilder mb6(spec);
212  IMesh out6 = boolean_trimesh(
213  mb6.imesh,
214  BoolOpType::Difference,
215  2,
216  [](int t) { return t < 4 ? 0 : 1; },
217  false,
218  false,
219  &mb6.arena);
220  out6.populate_vert();
221  EXPECT_EQ(out6.vert_size(), 6);
222  EXPECT_EQ(out6.face_size(), 8);
223  if (DO_OBJ) {
224  write_obj_mesh(out6, "tettet_difference_binary_tm");
225  }
226 
227  IMeshBuilder mb7(spec);
228  IMesh out7 = boolean_trimesh(
229  mb7.imesh,
230  BoolOpType::Difference,
231  2,
232  [](int t) { return t < 4 ? 1 : 0; },
233  false,
234  false,
235  &mb7.arena);
236  out7.populate_vert();
237  EXPECT_EQ(out7.vert_size(), 8);
238  EXPECT_EQ(out7.face_size(), 12);
239  if (DO_OBJ) {
240  write_obj_mesh(out7, "tettet_difference_rev_binary_tm");
241  }
242 }
243 
244 TEST(boolean_trimesh, TetTet2Trimesh)
245 {
246  const char *spec = R"(8 8
247  0 1 -1
248  7/8 -1/2 -1
249  -7/8 -1/2 -1
250  0 0 1
251  0 1 0
252  7/8 -1/2 0
253  -7/8 -1/2 0
254  0 0 2
255  0 3 1
256  0 1 2
257  1 3 2
258  2 3 0
259  4 7 5
260  4 5 6
261  5 7 6
262  6 7 4
263  )";
264 
265  IMeshBuilder mb(spec);
266  IMesh out = boolean_trimesh(
267  mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
268  out.populate_vert();
269  EXPECT_EQ(out.vert_size(), 10);
270  EXPECT_EQ(out.face_size(), 16);
271  if (DO_OBJ) {
272  write_obj_mesh(out, "tettet2_union_tm");
273  }
274 }
275 
276 TEST(boolean_trimesh, CubeTetTrimesh)
277 {
278  const char *spec = R"(12 16
279  -1 -1 -1
280  -1 -1 1
281  -1 1 -1
282  -1 1 1
283  1 -1 -1
284  1 -1 1
285  1 1 -1
286  1 1 1
287  0 1/2 1/2
288  1/2 -1/4 1/2
289  -1/2 -1/4 1/2
290  0 0 3/2
291  0 1 3
292  0 3 2
293  2 3 7
294  2 7 6
295  6 7 5
296  6 5 4
297  4 5 1
298  4 1 0
299  2 6 4
300  2 4 0
301  7 3 1
302  7 1 5
303  8 11 9
304  8 9 10
305  9 11 10
306  10 11 8
307  )";
308 
309  IMeshBuilder mb(spec);
310  IMesh out = boolean_trimesh(
311  mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
312  out.populate_vert();
313  EXPECT_EQ(out.vert_size(), 14);
314  EXPECT_EQ(out.face_size(), 24);
315  if (DO_OBJ) {
316  write_obj_mesh(out, "cubetet_union_tm");
317  }
318 }
319 
320 TEST(boolean_trimesh, BinaryTetTetTrimesh)
321 {
322  const char *spec = R"(8 8
323  0 0 0
324  2 0 0
325  1 2 0
326  1 1 2
327  0 0 1
328  2 0 1
329  1 2 1
330  1 1 3
331  0 2 1
332  0 1 3
333  1 2 3
334  2 0 3
335  4 6 5
336  4 5 7
337  5 6 7
338  6 4 7
339  )";
340 
341  IMeshBuilder mb(spec);
342  IMesh out = boolean_trimesh(
343  mb.imesh,
345  2,
346  [](int t) { return t < 4 ? 0 : 1; },
347  false,
348  false,
349  &mb.arena);
350  out.populate_vert();
351  EXPECT_EQ(out.vert_size(), 4);
352  EXPECT_EQ(out.face_size(), 4);
353  if (DO_OBJ) {
354  write_obj_mesh(out, "binary_tettet_isect_tm");
355  }
356 }
357 
358 TEST(boolean_trimesh, TetTetCoplanarTrimesh)
359 {
360  const char *spec = R"(8 8
361  0 1 0
362  7/8 -1/2 0
363  -7/8 -1/2 0
364  0 0 1
365  0 1 0
366  7/8 -1/2 0
367  -7/8 -1/2 0
368  0 0 -1
369  0 3 1
370  0 1 2
371  1 3 2
372  2 3 0
373  4 5 7
374  4 6 5
375  5 6 7
376  6 4 7
377  )";
378 
379  IMeshBuilder mb(spec);
380  IMesh out = boolean_trimesh(
381  mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
382  out.populate_vert();
383  EXPECT_EQ(out.vert_size(), 5);
384  EXPECT_EQ(out.face_size(), 6);
385  if (DO_OBJ) {
386  write_obj_mesh(out, "tettet_coplanar_tm");
387  }
388 }
389 
390 TEST(boolean_trimesh, TetInsideTetTrimesh)
391 {
392  const char *spec = R"(8 8
393  0 0 0
394  2 0 0
395  1 2 0
396  1 1 2
397  -1 -3/4 -1/2
398  3 -3/4 -1/2
399  1 13/4 -1/2
400  1 5/4 7/2
401  0 2 1
402  0 1 3
403  1 2 3
404  2 0 3
405  4 6 5
406  4 5 7
407  5 6 7
408  6 4 7
409  )";
410 
411  IMeshBuilder mb(spec);
412  IMesh out = boolean_trimesh(
413  mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
414  out.populate_vert();
415  EXPECT_EQ(out.vert_size(), 4);
416  EXPECT_EQ(out.face_size(), 4);
417  if (DO_OBJ) {
418  write_obj_mesh(out, "tetinsidetet_tm");
419  }
420 }
421 
422 TEST(boolean_trimesh, TetBesideTetTrimesh)
423 {
424  const char *spec = R"(8 8
425  0 0 0
426  2 0 0
427  1 2 0
428  1 1 2
429  3 0 0
430  5 0 0
431  4 2 0
432  4 1 2
433  0 2 1
434  0 1 3
435  1 2 3
436  2 0 3
437  4 6 5
438  4 5 7
439  5 6 7
440  6 4 7
441  )";
442 
443  IMeshBuilder mb(spec);
444  IMesh out = boolean_trimesh(
445  mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
446  out.populate_vert();
447  EXPECT_EQ(out.vert_size(), 8);
448  EXPECT_EQ(out.face_size(), 8);
449  if (DO_OBJ) {
450  write_obj_mesh(out, "tetbesidetet_tm");
451  }
452 }
453 
454 TEST(boolean_trimesh, DegenerateTris)
455 {
456  const char *spec = R"(10 10
457  0 0 0
458  2 0 0
459  1 2 0
460  1 1 2
461  0 0 1
462  2 0 1
463  1 2 1
464  1 1 3
465  0 0 0
466  1 0 0
467  0 2 1
468  0 8 1
469  0 1 3
470  1 2 3
471  2 0 3
472  4 6 5
473  4 5 7
474  5 6 7
475  6 4 7
476  0 1 9
477  )";
478 
479  IMeshBuilder mb(spec);
480  IMesh out = boolean_trimesh(
481  mb.imesh,
483  2,
484  [](int t) { return t < 5 ? 0 : 1; },
485  false,
486  false,
487  &mb.arena);
488  out.populate_vert();
489  EXPECT_EQ(out.vert_size(), 4);
490  EXPECT_EQ(out.face_size(), 4);
491  if (DO_OBJ) {
492  write_obj_mesh(out, "degenerate_tris_tm");
493  }
494 }
495 
496 TEST(boolean_polymesh, TetTet)
497 {
498  const char *spec = R"(8 8
499  0 0 0
500  2 0 0
501  1 2 0
502  1 1 2
503  0 0 1
504  2 0 1
505  1 2 1
506  1 1 3
507  0 2 1
508  0 1 3
509  1 2 3
510  2 0 3
511  4 6 5
512  4 5 7
513  5 6 7
514  6 4 7
515  )";
516 
517  IMeshBuilder mb(spec);
518  IMesh out = boolean_mesh(
519  mb.imesh, BoolOpType::None, 1, all_shape_zero, true, false, nullptr, &mb.arena);
520  out.populate_vert();
521  EXPECT_EQ(out.vert_size(), 11);
522  EXPECT_EQ(out.face_size(), 13);
523  if (DO_OBJ) {
524  write_obj_mesh(out, "tettet");
525  }
526 
527  IMeshBuilder mb2(spec);
528  IMesh out2 = boolean_mesh(
529  mb2.imesh,
530  BoolOpType::None,
531  2,
532  [](int t) { return t < 4 ? 0 : 1; },
533  false,
534  false,
535  nullptr,
536  &mb2.arena);
537  out2.populate_vert();
538  EXPECT_EQ(out2.vert_size(), 11);
539  EXPECT_EQ(out2.face_size(), 13);
540  if (DO_OBJ) {
541  write_obj_mesh(out, "tettet2");
542  }
543 }
544 
545 TEST(boolean_polymesh, CubeCube)
546 {
547  const char *spec = R"(16 12
548  -1 -1 -1
549  -1 -1 1
550  -1 1 -1
551  -1 1 1
552  1 -1 -1
553  1 -1 1
554  1 1 -1
555  1 1 1
556  1/2 1/2 1/2
557  1/2 1/2 5/2
558  1/2 5/2 1/2
559  1/2 5/2 5/2
560  5/2 1/2 1/2
561  5/2 1/2 5/2
562  5/2 5/2 1/2
563  5/2 5/2 5/2
564  0 1 3 2
565  6 2 3 7
566  4 6 7 5
567  0 4 5 1
568  0 2 6 4
569  3 1 5 7
570  8 9 11 10
571  14 10 11 15
572  12 14 15 13
573  8 12 13 9
574  8 10 14 12
575  11 9 13 15
576  )";
577 
578  IMeshBuilder mb(spec);
579  if (DO_OBJ) {
580  write_obj_mesh(mb.imesh, "cube_cube_in");
581  }
582  IMesh out = boolean_mesh(
583  mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, nullptr, &mb.arena);
584  out.populate_vert();
585  EXPECT_EQ(out.vert_size(), 20);
586  EXPECT_EQ(out.face_size(), 12);
587  if (DO_OBJ) {
588  write_obj_mesh(out, "cubecube_union");
589  }
590 
591  IMeshBuilder mb2(spec);
592  IMesh out2 = boolean_mesh(
593  mb2.imesh,
594  BoolOpType::None,
595  2,
596  [](int t) { return t < 6 ? 0 : 1; },
597  false,
598  false,
599  nullptr,
600  &mb2.arena);
601  out2.populate_vert();
602  EXPECT_EQ(out2.vert_size(), 22);
603  EXPECT_EQ(out2.face_size(), 18);
604  if (DO_OBJ) {
605  write_obj_mesh(out2, "cubecube_none");
606  }
607 }
608 
609 TEST(boolean_polymesh, CubeCone)
610 {
611  const char *spec = R"(14 12
612  -1 -1 -1
613  -1 -1 1
614  -1 1 -1
615  -1 1 1
616  1 -1 -1
617  1 -1 1
618  1 1 -1
619  1 1 1
620  0 1/2 3/4
621  119/250 31/200 3/4
622  147/500 -81/200 3/4
623  0 0 7/4
624  -147/500 -81/200 3/4
625  -119/250 31/200 3/4
626  0 1 3 2
627  2 3 7 6
628  6 7 5 4
629  4 5 1 0
630  2 6 4 0
631  7 3 1 5
632  8 11 9
633  9 11 10
634  10 11 12
635  12 11 13
636  13 11 8
637  8 9 10 12 13)";
638 
639  IMeshBuilder mb(spec);
640  IMesh out = boolean_mesh(
641  mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, nullptr, &mb.arena);
642  out.populate_vert();
643  EXPECT_EQ(out.vert_size(), 14);
644  EXPECT_EQ(out.face_size(), 12);
645  if (DO_OBJ) {
646  write_obj_mesh(out, "cubeccone");
647  }
648 }
649 
650 TEST(boolean_polymesh, CubeCubeCoplanar)
651 {
652  const char *spec = R"(16 12
653  -1 -1 -1
654  -1 -1 1
655  -1 1 -1
656  -1 1 1
657  1 -1 -1
658  1 -1 1
659  1 1 -1
660  1 1 1
661  -1/2 -1/2 1
662  -1/2 -1/2 2
663  -1/2 1/2 1
664  -1/2 1/2 2
665  1/2 -1/2 1
666  1/2 -1/2 2
667  1/2 1/2 1
668  1/2 1/2 2
669  0 1 3 2
670  2 3 7 6
671  6 7 5 4
672  4 5 1 0
673  2 6 4 0
674  7 3 1 5
675  8 9 11 10
676  10 11 15 14
677  14 15 13 12
678  12 13 9 8
679  10 14 12 8
680  15 11 9 13
681  )";
682 
683  IMeshBuilder mb(spec);
684  IMesh out = boolean_mesh(
685  mb.imesh,
686  BoolOpType::Union,
687  2,
688  [](int t) { return t < 6 ? 0 : 1; },
689  false,
690  false,
691  nullptr,
692  &mb.arena);
693  out.populate_vert();
694  EXPECT_EQ(out.vert_size(), 16);
695  EXPECT_EQ(out.face_size(), 12);
696  if (DO_OBJ) {
697  write_obj_mesh(out, "cubecube_coplanar");
698  }
699 }
700 
701 TEST(boolean_polymesh, TetTeTCoplanarDiff)
702 {
703  const char *spec = R"(8 8
704  0 1 0
705  7/8 -1/2 0
706  -7/8 -1/2 0
707  0 0 1
708  0 1 0
709  7/8 -1/2 0
710  -7/8 -1/2 0
711  0 0 -1
712  0 3 1
713  0 1 2
714  1 3 2
715  2 3 0
716  4 5 7
717  4 6 5
718  5 6 7
719  6 4 7
720  )";
721 
722  IMeshBuilder mb(spec);
723  IMesh out = boolean_mesh(
724  mb.imesh,
725  BoolOpType::Difference,
726  2,
727  [](int t) { return t < 4 ? 0 : 1; },
728  false,
729  false,
730  nullptr,
731  &mb.arena);
732  out.populate_vert();
733  EXPECT_EQ(out.vert_size(), 4);
734  EXPECT_EQ(out.face_size(), 4);
735  if (DO_OBJ) {
736  write_obj_mesh(out, "tettet_coplanar_diff");
737  }
738 }
739 
740 TEST(boolean_polymesh, CubeCubeStep)
741 {
742  const char *spec = R"(16 12
743  0 -1 0
744  0 -1 2
745  0 1 0
746  0 1 2
747  2 -1 0
748  2 -1 2
749  2 1 0
750  2 1 2
751  -1 -1 -1
752  -1 -1 1
753  -1 1 -1
754  -1 1 1
755  1 -1 -1
756  1 -1 1
757  1 1 -1
758  1 1 1
759  0 1 3 2
760  2 3 7 6
761  6 7 5 4
762  4 5 1 0
763  2 6 4 0
764  7 3 1 5
765  8 9 11 10
766  10 11 15 14
767  14 15 13 12
768  12 13 9 8
769  10 14 12 8
770  15 11 9 13
771  )";
772 
773  IMeshBuilder mb(spec);
774  IMesh out = boolean_mesh(
775  mb.imesh,
776  BoolOpType::Difference,
777  2,
778  [](int t) { return t < 6 ? 0 : 1; },
779  false,
780  false,
781  nullptr,
782  &mb.arena);
783  out.populate_vert();
784  EXPECT_EQ(out.vert_size(), 12);
785  EXPECT_EQ(out.face_size(), 8);
786  if (DO_OBJ) {
787  write_obj_mesh(out, "cubecubestep");
788  }
789 }
790 
791 TEST(boolean_polymesh, CubeCyl4)
792 {
793  const char *spec = R"(16 12
794  0 1 -1
795  0 1 1
796  1 0 -1
797  1 0 1
798  0 -1 -1
799  0 -1 1
800  -1 0 -1
801  -1 0 1
802  -1 -1 -1
803  -1 -1 1
804  -1 1 -1
805  -1 1 1
806  1 -1 -1
807  1 -1 1
808  1 1 -1
809  1 1 1
810  0 1 3 2
811  2 3 5 4
812  3 1 7 5
813  4 5 7 6
814  6 7 1 0
815  0 2 4 6
816  8 9 11 10
817  10 11 15 14
818  14 15 13 12
819  12 13 9 8
820  10 14 12 8
821  15 11 9 13
822  )";
823 
824  IMeshBuilder mb(spec);
825  IMesh out = boolean_mesh(
826  mb.imesh,
827  BoolOpType::Difference,
828  2,
829  [](int t) { return t < 6 ? 1 : 0; },
830  false,
831  false,
832  nullptr,
833  &mb.arena);
834  out.populate_vert();
835  EXPECT_EQ(out.vert_size(), 16);
836  EXPECT_EQ(out.face_size(), 20);
837  if (DO_OBJ) {
838  write_obj_mesh(out, "cubecyl4");
839  }
840 }
841 
842 TEST(boolean_polymesh, CubeCubesubdivDiff)
843 {
844  /* A cube intersected by a subdivided cube that intersects first cubes edges exactly. */
845  const char *spec = R"(26 22
846  2 1/3 2
847  2 -1/3 2
848  2 -1/3 0
849  2 1/3 0
850  0 -1/3 2
851  0 1/3 2
852  0 1/3 0
853  0 -1/3 0
854  1 1/3 2
855  1 -1/3 2
856  1 1/3 0
857  1 -1/3 0
858  0 -1/3 1
859  0 1/3 1
860  2 1/3 1
861  2 -1/3 1
862  1 1/3 1
863  1 -1/3 1
864  -1 -1 -1
865  -1 -1 1
866  -1 1 -1
867  -1 1 1
868  1 -1 -1
869  1 -1 1
870  1 1 -1
871  1 1 1
872  17 9 4 12
873  13 6 7 12
874  15 2 3 14
875  11 7 6 10
876  16 13 5 8
877  9 1 0 8
878  4 9 8 5
879  14 16 8 0
880  2 11 10 3
881  15 1 9 17
882  2 15 17 11
883  3 10 16 14
884  10 6 13 16
885  1 15 14 0
886  5 13 12 4
887  11 17 12 7
888  19 21 20 18
889  21 25 24 20
890  25 23 22 24
891  23 19 18 22
892  18 20 24 22
893  23 25 21 19
894  )";
895 
896  IMeshBuilder mb(spec);
897  IMesh out = boolean_mesh(
898  mb.imesh,
899  BoolOpType::Difference,
900  2,
901  [](int t) { return t < 16 ? 1 : 0; },
902  false,
903  false,
904  nullptr,
905  &mb.arena);
906  out.populate_vert();
907  EXPECT_EQ(out.vert_size(), 16);
908  EXPECT_EQ(out.face_size(), 10);
909  if (DO_OBJ) {
910  write_obj_mesh(out, "cubecubesubdivdiff");
911  }
912 }
913 
914 TEST(boolean_polymesh, CubePlane)
915 {
916  const char *spec = R"(12 7
917  -2 -2 0
918  2 -2 0
919  -2 2 0
920  2 2 0
921  -1 -1 -1
922  -1 -1 1
923  -1 1 -1
924  -1 1 1
925  1 -1 -1
926  1 -1 1
927  1 1 -1
928  1 1 1
929  0 1 3 2
930  4 5 7 6
931  6 7 11 10
932  10 11 9 8
933  8 9 5 4
934  6 10 8 4
935  11 7 5 9
936 )";
937 
938  IMeshBuilder mb(spec);
939  IMesh out = boolean_mesh(
940  mb.imesh,
941  BoolOpType::Difference,
942  2,
943  [](int t) { return t >= 1 ? 0 : 1; },
944  false,
945  false,
946  nullptr,
947  &mb.arena);
948  out.populate_vert();
949  EXPECT_EQ(out.vert_size(), 8);
950  EXPECT_EQ(out.face_size(), 6);
951  if (DO_OBJ) {
952  write_obj_mesh(out, "cubeplane");
953  }
954 }
955 
956 } // namespace blender::meshintersect::tests
957 #endif
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
#define UNUSED(x)
_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
Read Guarded memory(de)allocation.
DBVT_INLINE bool Intersect(const btDbvtAabbMm &a, const btDbvtAabbMm &b)
Definition: btDbvt.h:621
static float verts[][3]
static char faces[256]