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