40# include "manifold/manifold.h"
42using manifold::Manifold;
43using manifold::MeshGL;
52template<
typename T>
static void dump_span(Span<T> span,
const std::string &name)
54 std::cout << name <<
":";
57 std::cout <<
"\n[" <<
i <<
"] ";
59 std::cout << span[
i] <<
" ";
65static void dump_span_with_stride(Span<T> span,
int stride,
const std::string &name)
67 std::cout << name <<
":";
70 std::cout <<
"\n[" <<
i <<
"] ";
72 std::cout << span[
i] <<
" ";
73 if (stride > 1 && (
i % stride) == stride - 1) {
81static void dump_vector(
const std::vector<T> &vec,
int stride,
const std::string &name)
83 std::cout << name <<
":";
84 for (
int i = 0;
i < vec.size();
i++) {
86 std::cout <<
"\n[" <<
i <<
"] ";
88 std::cout << vec[
i] <<
" ";
89 if (stride > 1 && (
i % stride) == stride - 1) {
97static void dump_vector_values(
const std::string indent,
98 const std::string &assign_to,
99 const std::vector<T> &vec)
101 std::cout << indent << assign_to <<
" = { ";
102 for (
int i = 0;
i < vec.size();
i++) {
103 if (
i > 0 && (
i % 10) == 0) {
104 std::cout <<
"\n" << indent << indent;
107 if (
i == vec.size() - 1) {
108 std::cout <<
" };\n";
116static void dump_meshgl(
const MeshGL &mgl,
const std::string &name)
118 std::cout <<
"\nMeshGL " << name <<
":\n"
119 <<
"num verts = " << mgl.NumVert() <<
"\nnum triangles = " << mgl.NumTri() <<
"\n"
121 dump_vector(mgl.vertProperties, mgl.numProp,
"vertProperties");
122 dump_vector(mgl.triVerts, 3,
"triVerts");
123 dump_vector(mgl.faceID, 1,
"faceID");
124 if (!mgl.mergeFromVert.empty()) {
125 dump_vector(mgl.mergeFromVert, 1,
"mergeFromVert");
126 dump_vector(mgl.mergeToVert, 1,
"mergeToVert");
128 dump_vector(mgl.runIndex, 1,
"runIndex");
129 dump_vector(mgl.runOriginalID, 1,
"runOrigiinalID");
132[[maybe_unused]]
static void dump_meshgl_for_debug(
const MeshGL &mgl)
134 std::string indent =
" ";
135 std::cout << indent <<
"MeshGL m;\n";
136 std::cout << indent <<
"m.numProp = " << mgl.numProp <<
";\n";
137 dump_vector_values(indent,
"m.vertProperties", mgl.vertProperties);
138 dump_vector_values(indent,
"m.triVerts", mgl.triVerts);
139 if (!mgl.mergeFromVert.empty()) {
140 dump_vector_values(indent,
"m.mergeFromVert", mgl.mergeFromVert);
141 dump_vector_values(indent,
"m.mergeToVert", mgl.mergeToVert);
143 dump_vector_values(indent,
"m.runIndex", mgl.runIndex);
144 dump_vector_values(indent,
"m.runOriginalID", mgl.runOriginalID);
145 dump_vector_values(indent,
"m.faceID", mgl.faceID);
148 if (mgl.tolerance != 0) {
149 std::cout << indent <<
"m.tolerance = " << mgl.tolerance <<
";\n";
153static const char *domain_names[] = {
154 "point",
"edge",
"face",
"corner",
"curve",
"instance",
"layer"};
156static void dump_mesh(
const Mesh *mesh,
const std::string &name)
158 std::cout <<
"\nMesh " << name <<
":\n"
162 dump_span(mesh->vert_positions(),
"verts");
163 dump_span(mesh->edges(),
"edges");
164 dump_span(mesh->corner_verts(),
"corner_verts");
165 dump_span(mesh->corner_edges(),
"corner_edges");
166 dump_span(mesh->face_offsets(),
"face_offsets");
167 std::cout <<
"triangulation:\n";
168 dump_span(mesh->corner_tris(),
"corner_tris");
169 dump_span(mesh->corner_tri_faces(),
"corner_tri_faces");
170 std::cout <<
"attributes:\n";
171 bke::AttributeAccessor attrs = mesh->
attributes();
172 attrs.foreach_attribute([&](
const bke::AttributeIter &iter) {
173 if (
ELEM(iter.name,
"position",
".edge_verts",
".corner_vert",
".corner_edge")) {
176 const int di =
int8_t(iter.domain);
177 const char *domain = (di >= 0 && di <
ATTR_DOMAIN_NUM) ? domain_names[di] :
"?";
178 std::string label = std::string(domain) +
": " + iter.name;
179 switch (iter.data_type) {
181 VArraySpan<float> floatspan(*attrs.lookup<
float>(iter.name));
182 dump_span(floatspan, label);
186 const VArraySpan<int> intspan(*attrs.lookup<
int>(iter.name));
187 dump_span(intspan, label);
190 const VArraySpan<float3> float3span(*attrs.lookup<
float3>(iter.name));
191 dump_span(float3span, label);
194 const VArraySpan<float2> float2span(*attrs.lookup<
float2>(iter.name));
195 dump_span(float2span, label);
198 std::cout << label <<
" attribute not dumped\n";
202 std::cout <<
"materials:\n";
204 std::cout <<
"[" <<
i <<
"]: " << (mesh->
mat[
i] ? mesh->
mat[
i]->
id.
name + 2 :
"none") <<
"\n";
215 Array<int> vert_start;
216 Array<int> face_start;
217 Array<int> edge_start;
218 Array<int> corner_start;
219 OffsetIndices<int> vert_offsets;
220 OffsetIndices<int> face_offsets;
221 OffsetIndices<int> edge_offsets;
222 OffsetIndices<int> corner_offsets;
224 MeshOffsets(Span<const Mesh *> meshes);
227MeshOffsets::MeshOffsets(Span<const Mesh *> meshes)
229 const int meshes_num = meshes.
size();
230 this->vert_start.reinitialize(meshes_num + 1);
231 this->face_start.reinitialize(meshes_num + 1);
232 this->edge_start.reinitialize(meshes_num + 1);
233 this->corner_start.reinitialize(meshes_num + 1);
234 for (
int i = 0;
i <= meshes_num;
i++) {
235 this->vert_start[
i] = (
i == 0) ? 0 :
this->vert_start[
i - 1] + meshes[
i - 1]->verts_num;
236 this->face_start[
i] = (
i == 0) ? 0 :
this->face_start[
i - 1] + meshes[
i - 1]->faces_num;
237 this->edge_start[
i] = (
i == 0) ? 0 :
this->edge_start[
i - 1] + meshes[
i - 1]->edges_num;
238 this->corner_start[
i] = (
i == 0) ? 0 :
this->corner_start[
i - 1] + meshes[
i - 1]->corners_num;
240 this->vert_offsets = OffsetIndices<int>(this->vert_start);
241 this->face_offsets = OffsetIndices<int>(this->face_start);
242 this->edge_offsets = OffsetIndices<int>(this->edge_start);
243 this->corner_offsets = OffsetIndices<int>(this->corner_start);
262static void get_manifold(
Manifold &manifold,
263 const Span<const Mesh *> meshes,
265 const MeshOffsets &mesh_offsets)
267 constexpr int dbg_level = 0;
269 std::cout <<
"get_manifold for mesh " << mesh_index <<
"\n";
274 const Mesh &mesh = *meshes[mesh_index];
275 const OffsetIndices<int>
faces = mesh.faces();
276 const Span<int> corner_verts = mesh.corner_verts();
277 const Span<int3> corner_tris = mesh.corner_tris();
281 constexpr int props_num = 3;
282 meshgl.numProp = props_num;
283 meshgl.vertProperties.resize(
size_t(mesh.
verts_num) * props_num);
289 constexpr bool use_runids =
false;
292 meshgl.runOriginalID.resize(mesh.
faces_num);
295 const int face_start = mesh_offsets.face_start[mesh_index];
297 meshgl.faceID.resize(corner_tris.
size());
299 MutableSpan face_ids = MutableSpan(meshgl.faceID);
301 for (const int i : range) {
302 const IndexRange face = faces[i];
303 const int start = poly_to_tri_count(int(i), int(face.start()));
304 const int num = bke::mesh::face_triangles_num(int(face.size()));
305 face_ids.slice(start, num).fill(uint32_t(i + face_start));
307 meshgl.runOriginalID[i] = face_start + i;
308 meshgl.runIndex[i] = start * 3;
313 meshgl.triVerts.resize(corner_tris.
size() * 3);
314 MutableSpan vert_tris = MutableSpan(meshgl.triVerts).cast<
int3>();
318 meshgl.runIndex.resize(2);
319 meshgl.runOriginalID.resize(1);
320 meshgl.runIndex[0] = 0;
321 meshgl.runIndex[1] = corner_tris.
size() * 3;
322 meshgl.runOriginalID[0] = mesh_index;
325 dump_meshgl(meshgl,
"converted result for mesh " + std::to_string(mesh_index));
327 dump_meshgl_for_debug(meshgl);
332 timeit::ScopedTimer mtimer(
"manifold constructor from meshgl");
345 const MeshOffsets &mesh_offsets)
347 constexpr int dbg_level = 0;
349 std::cout <<
"GET_MANIFOLDS\n";
350 std::cout <<
"\nMesh Offset (starts):\n";
351 dump_span(mesh_offsets.vert_start.as_span(),
"vert");
352 dump_span(mesh_offsets.face_start.as_span(),
"face");
353 dump_span(mesh_offsets.edge_start.as_span(),
"edge");
354 dump_span(mesh_offsets.corner_start.as_span(),
"corner");
356 const int meshes_num = manifolds.
size();
364 transformed_meshes[
i] = meshes[
i];
368 bke::mesh_transform(*transformed_mesh, transforms[
i],
false);
369 transformed_meshes[
i] = transformed_mesh;
374 for (
const int mesh_index :
IndexRange(meshes_num)) {
375 get_manifold(manifolds[mesh_index], transformed_meshes, mesh_index, mesh_offsets);
379 threading::parallel_for_each(
IndexRange(meshes_num), [&](
int mesh_index) {
380 get_manifold(manifolds[mesh_index], transformed_meshes, mesh_index, mesh_offsets);
384 for (
const int i : transformed_meshes.index_range()) {
385 if (transformed_meshes[
i] != meshes[
i]) {
391constexpr int inline_outface_size = 8;
401 int find_vert_index(
int v)
const
403 return verts.first_index_of_try(
v);
410 MutableSpan<float> vertpos;
411 int vertpos_stride = 3;
415 int output_verts_num;
423 Vector<int> old_to_new_vert_map;
425 float3 vert_position(
const int v)
const
427 const int start = vertpos_stride *
v;
428 return float3(vertpos[start], vertpos[start + 1], vertpos[start + 2]);
431 int mapped_vert(
const int v)
const
434 return old_to_new_vert_map[
v];
447 Array<int> vertex_map_;
448 Array<int> face_map_;
449 Array<int> edge_map_;
450 Array<int> corner_map_;
452 const MeshAssembly *mesh_assembly_;
453 const Mesh *joined_mesh_;
454 const Mesh *output_mesh_;
457 OutToInMaps(
const MeshAssembly *mesh_assembly,
const Mesh *joined_mesh,
const Mesh *output_mesh)
458 : mesh_assembly_(mesh_assembly), joined_mesh_(joined_mesh), output_mesh_(output_mesh)
462 Span<int> ensure_vertex_map();
463 Span<int> ensure_face_map();
464 Span<int> ensure_edge_map();
465 Span<int> ensure_corner_map();
470 if (!face_map_.is_empty()) {
475 timeit::ScopedTimer
timer(
"filling face map");
477 face_map_.reinitialize(output_mesh_->faces_num);
478 BLI_assert(mesh_assembly_->new_faces.size() == face_map_.size());
479 constexpr int grain_size = 50000;
480 threading::parallel_for(
481 mesh_assembly_->new_faces.index_range(), grain_size, [&](
const IndexRange range) {
482 for (const int i : range) {
483 face_map_[i] = mesh_assembly_->new_faces[i].face_id;
489Span<int> OutToInMaps::ensure_vertex_map()
491 if (!vertex_map_.is_empty()) {
498 const Span<int> face_map = this->ensure_face_map();
500 timeit::ScopedTimer
timer(
"filling vertex map");
502 vertex_map_ =
Array<int>(output_mesh_->verts_num, -1);
507 const OffsetIndices<int> in_faces = joined_mesh_->faces();
508 const OffsetIndices<int> out_faces = output_mesh_->faces();
509 const Span<int> in_corner_verts = joined_mesh_->corner_verts();
510 const Span<int> out_corner_verts = output_mesh_->corner_verts();
511 const Span<float3> out_vert_positions = output_mesh_->vert_positions();
512 const Span<float3> in_vert_positions = joined_mesh_->vert_positions();
513 for (
const int out_face_index :
IndexRange(output_mesh_->faces_num)) {
514 const int in_face_index = face_map[out_face_index];
515 const IndexRange in_face = in_faces[in_face_index];
516 const IndexRange out_face = out_faces[out_face_index];
518 for (
const int out_v : out_corner_verts.
slice(out_face)) {
519 if (vertex_map_[out_v] != -1) {
522 float3 out_pos = out_vert_positions[out_v];
523 const auto *it = std::find_if(in_face_verts.
begin(), in_face_verts.
end(), [&](
int in_v) {
524 return out_pos == in_vert_positions[in_v];
526 if (it != in_face_verts.
end()) {
527 int in_v = in_face_verts[std::distance(in_face_verts.
begin(), it)];
528 vertex_map_[out_v] = in_v;
535Span<int> OutToInMaps::ensure_corner_map()
537 if (!corner_map_.is_empty()) {
545 const Span<int> face_map = this->ensure_face_map();
546 const Span<int> vert_map = this->ensure_vertex_map();
548 timeit::ScopedTimer
timer(
"filling corner map");
550 corner_map_ =
Array<int>(output_mesh_->corners_num, -1);
551 const OffsetIndices<int> in_faces = joined_mesh_->faces();
552 const OffsetIndices<int> out_faces = output_mesh_->faces();
553 const Span<int> in_corner_verts = joined_mesh_->corner_verts();
554 const Span<int> out_corner_verts = output_mesh_->corner_verts();
555 constexpr int grain_size = 10000;
556 threading::parallel_for(
558 for (const int out_face_index : range) {
559 const int in_face_index = face_map[out_face_index];
560 const IndexRange in_face = in_faces[in_face_index];
561 for (const int out_c : out_faces[out_face_index]) {
562 BLI_assert(corner_map_[out_c] == -1);
563 const int out_v = out_corner_verts[out_c];
564 const int in_v = vert_map[out_v];
568 const int in_face_i = in_corner_verts.slice(in_face).first_index_try(in_v);
569 if (in_face_i != -1) {
570 const int in_c = in_face[in_face_i];
571 corner_map_[out_c] = in_c;
588 return (
math::abs(abs_cos_pq - 1.0f) <= 1e-5f);
593 constexpr int dbg_level = 0;
594 if (!edge_map_.is_empty()) {
598 std::cout <<
"\nensure_edge_map\n";
600 dump_mesh(joined_mesh_,
"joined_mesh");
601 dump_mesh(output_mesh_,
"output_mesh");
615 const Span<int> face_map = this->ensure_face_map();
616 const Span<int> vert_map = this->ensure_vertex_map();
617 const Span<int> corner_map = this->ensure_corner_map();
623 timeit::ScopedTimer
timer(
"filling edge map");
625 edge_map_ =
Array<int>(output_mesh_->edges_num, -1);
626 const Span<int> out_corner_edges = output_mesh_->corner_edges();
627 const Span<int> out_corner_verts = output_mesh_->corner_verts();
628 const Span<int2> out_edges = output_mesh_->edges();
629 const Span<float3> out_positions = output_mesh_->vert_positions();
630 const Span<int> in_corner_edges = joined_mesh_->corner_edges();
631 const Span<int> in_corner_verts = joined_mesh_->corner_verts();
632 const Span<int2> in_edges = joined_mesh_->edges();
633 const Span<float3> in_positions = joined_mesh_->vert_positions();
634 const OffsetIndices<int> in_faces = joined_mesh_->faces();
635 const OffsetIndices<int> out_faces = output_mesh_->faces();
636 Array<bool> done_edge(output_mesh_->edges_num,
false);
637 for (
const int out_face_index :
IndexRange(output_mesh_->faces_num)) {
638 const int in_face_index = face_map[out_face_index];
639 const IndexRange in_face = in_faces[in_face_index];
641 std::cout <<
"process out_face = " << out_face_index <<
", in_face = " << in_face_index
644 for (
const int out_c : out_faces[out_face_index]) {
645 const int in_c = corner_map[out_c];
647 std::cout <<
" out_c = " << out_c <<
", in_c = " << in_c <<
"\n";
653 const int out_e = out_corner_edges[out_c];
655 std::cout <<
" out_e = " << out_e <<
", done = " << done_edge[out_e] <<
"\n";
657 if (done_edge[out_e]) {
660 const int out_v = out_corner_verts[out_c];
661 const int in_e = in_corner_edges[in_c];
662 const int in_v = in_corner_verts[in_c];
665 int2 out_e_v = out_edges[out_e];
666 if (out_e_v[0] != out_v) {
667 out_e_v = {out_e_v[1], out_e_v[0]};
669 int2 in_e_v = in_edges[in_e];
670 if (in_e_v[0] != in_v) {
671 in_e_v = {in_e_v[1], in_e_v[0]};
674 std::cout <<
" out_v = " << out_v <<
", in_e = " << in_e <<
", in_v = " << in_v <<
"\n";
675 std::cout <<
" out_e_v = " << out_e_v <<
", in_e_v = " << in_e_v <<
"\n";
676 std::cout <<
" vertex_map(out_e_v) = " <<
int2(vert_map[out_e_v[0]], vert_map[out_e_v[1]])
683 BLI_assert(vert_map[out_e_v[0]] == in_e_v[0]);
685 if (vert_map[out_e_v[1]] == in_e_v[1]) {
688 std::cout <<
" case 1, edge_rep = in_e = " << in_e <<
"\n";
692 else if (vert_map[out_e_v[1]] == -1) {
696 if (same_dir(out_positions[out_e_v[0]],
697 out_positions[out_e_v[1]],
698 in_positions[in_e_v[0]],
699 in_positions[in_e_v[1]]))
702 std::cout <<
" case 2, edge_rep = in_e = " << in_e <<
"\n";
712 if (edge_rep == -1) {
713 const int in_c_prev = bke::mesh::face_corner_prev(in_face, in_c);
714 const int in_e_prev = in_corner_edges[in_c_prev];
715 const int in_v_prev = in_corner_verts[in_c_prev];
716 int2 in_e_v_prev = in_edges[in_e_prev];
717 if (in_e_v_prev[0] != in_v_prev) {
718 in_e_v_prev = {in_e_v_prev[1], in_e_v_prev[0]};
721 std::cout <<
" in_c_prev = " << in_c_prev <<
", in_e_prev = " << in_e_prev
722 <<
", in_v_prev = " << in_v_prev <<
"\n";
723 std::cout <<
" in_e_v_prev = " << in_e_v_prev <<
"\n";
725 if (vert_map[out_e_v[0]] == in_e_v_prev[1]) {
726 if (vert_map[out_e_v[1]] == in_e_v_prev[0]) {
728 std::cout <<
" case 3, edge_rep = in_e_prev = " << in_e_prev <<
"\n";
730 edge_rep = in_e_prev;
732 else if (vert_map[out_e_v[1]] == -1) {
733 if (same_dir(out_positions[out_e_v[0]],
734 out_positions[out_e_v[1]],
735 in_positions[in_e_v_prev[0]],
736 in_positions[in_e_v_prev[1]]))
739 std::cout <<
" case 4, edge_rep = in_e_prev = " << in_e_prev <<
"\n";
741 edge_rep = in_e_prev;
746 if (edge_rep != -1) {
748 std::cout <<
" found: set edge_map[" << out_e <<
"] = " << edge_rep <<
"\n";
750 edge_map_[out_e] = edge_rep;
751 done_edge[out_e] =
true;
759constexpr int face_group_inline = 4;
770 timeit::ScopedTimer
timer(
"get_face_groups");
772 constexpr int dbg_level = 0;
774 const int tris_num = mgl.NumTri();
777 const int faceid = mgl.faceID[t];
778 fg[faceid].append(t);
781 std::cout <<
"face_groups\n";
782 for (
const int i : fg.index_range()) {
783 std::cout <<
"orig face " <<
i;
784 dump_span(fg[
i].as_span(),
"");
803 BLI_assert(0 <= face_index && face_index < mesh->faces_num);
804 const IndexRange orig_face = mesh->faces()[face_index];
807 int orig_face_size = orig_face.
size();
808 if (orig_face_size != group.
size() + 2) {
811 Span<int> orig_face_verts = mesh->corner_verts().slice(mesh->faces()[face_index]);
815 int stride = mgl.numProp;
816 for (
const int t : group) {
822 int v = mgl.triVerts[3 * t +
i];
823 int prop_offset =
v * stride;
824 float3 pos(mgl.vertProperties[prop_offset],
825 mgl.vertProperties[prop_offset + 1],
826 mgl.vertProperties[prop_offset + 2]);
827 auto it = std::find_if(orig_face_verts.
begin(), orig_face_verts.
end(), [&](
int orig_v) {
828 return pos == mesh->vert_positions()[orig_v];
830 face_vert_index[
i] = it == orig_face_verts.
end() ?
832 std::distance(orig_face_verts.
begin(), it);
836 const int a = face_vert_index[
i];
837 const int b = face_vert_index[(
i + 1) % 3];
838 if (a != -1 &&
b != -1) {
839 if ((a + 1) % orig_face_size ==
b) {
842 else if ((
b + 1) % orig_face_size == a) {
848 if (std::all_of(edge_value.begin(), edge_value.end(), [](
int x) { return x == 1; })) {
851 else if (std::all_of(edge_value.begin(), edge_value.end(), [](
int x) { return x == -1; })) {
858static OutFace make_out_face(
const MeshGL &mgl,
int tri_index,
int orig_face)
862 const int k = 3 * tri_index;
863 ans.verts[0] = mgl.triVerts[k];
864 ans.verts[1] = mgl.triVerts[k + 1];
865 ans.verts[2] = mgl.triVerts[k + 2];
866 ans.face_id = orig_face;
887 SharedEdge(
int e1,
int e2,
int v1,
int v2) : e1(e1), e2(e2), v1(v1),
v2(
v2) {}
891 int2 outface_group_face_indices()
const
893 return int2(e1 / 3, e2 / 3);
898static inline SharedEdge canon_shared_edge(
int e1,
int e2,
int v1,
int v2)
901 return SharedEdge(e1, e2, v1,
v2);
903 return SharedEdge(e2, e1,
v2, v1);
911static SharedEdge get_shared_edge_from_pair(
const OutFace &tri1,
const OutFace &tri2)
914 SharedEdge shared_edge(-1, -1, -1, -1);
917 const int v1 = tri1.verts[i1];
918 const int v2 = tri2.verts[i2];
920 const int v1_next = tri1.verts[(i1 + 1) % 3];
921 const int v2_prev = tri2.verts[(i2 + 2) % 3];
922 if (v1_next == v2_prev) {
923 shared_edge = SharedEdge(i1, 3 + ((i2 + 2) % 3), v1, v1_next);
926 const int v1_prev = tri1.verts[(i1 + 2) % 3];
927 const int v2_next = tri2.verts[(i2 + 1) % 3];
928 if (v1_prev == v2_next) {
929 shared_edge = SharedEdge((i1 + 2) % 3, 3 + i2, v1_prev, v1);
934 if (shared_edge.e1 != -1) {
952 for (
const int face_index :
faces.index_range()) {
953 const OutFace &f =
faces[face_index];
956 int v2 = f.verts[(
i + 1) % 3];
957 int this_e = face_index * 3 +
i;
961 ans.
append(canon_shared_edge(this_e, other_e, v1,
v2));
973static bool is_legal_merge(
const OutFace &f1,
const OutFace &f2,
int v1,
int v2)
979 for (
const int v : f1.verts) {
981 if (f2.find_vert_index(
v) != -1) {
986 for (
const int v : f2.verts) {
988 if (f1.find_vert_index(
v) != -1) {
1004static bool try_merge_out_face_pair(OutFace &f1,
const OutFace &f2,
const SharedEdge &se)
1007 constexpr int dbg_level = 0;
1008 if (dbg_level > 0) {
1009 std::cout <<
"try_merge_out_face_pair\n";
1010 dump_span(f1.verts.as_span(),
"f1");
1011 dump_span(f2.verts.as_span(),
"f2");
1012 std::cout <<
"shared edge: "
1013 <<
"(e" << se.e1 <<
",e" << se.e2 <<
";v" << se.v1 <<
",v" << se.v2 <<
")\n";
1015 const int f1_len = f1.verts.size();
1016 const int f2_len = f2.verts.size();
1017 const int v1 = se.v1;
1018 const int v2 = se.v2;
1021 const int i1 = f1.find_vert_index(v1);
1023 const int i1_next = (i1 + 1) % f1_len;
1024 const int i2 = f2.find_vert_index(
v2);
1026 const int i2_next = (i2 + 1) % f2_len;
1027 BLI_assert(f1.verts[i1] == v1 && f1.verts[i1_next] ==
v2);
1028 BLI_assert(f2.verts[i2] ==
v2 && f2.verts[i2_next] == v1);
1029 const bool can_merge = is_legal_merge(f1, f2, v1,
v2);
1030 if (dbg_level > 0) {
1031 std::cout <<
"i1 = " << i1 <<
", i2 = " << i2 <<
", can_merge = " << can_merge <<
"\n";
1042 const int i2_prev = (i2 + f2_len - 1) % f2_len;
1043 const int i2_next_next = (i2_next + 1) % f2_len;
1044 const auto *f2_start_it = f2.verts.begin() + i2_next_next;
1045 const auto *f2_end_it = f2.verts.begin() + i2_prev + 1;
1046 if (f2_end_it > f2_start_it) {
1047 f1.verts.insert(i1_next, f2_start_it, f2_end_it);
1050 const int n1 = std::distance(f2_start_it, f2.verts.end());
1052 f1.verts.insert(i1_next, f2_start_it, f2.verts.end());
1054 if (n1 < f2_len - 2) {
1055 f1.verts.insert(i1_next + n1, f2.verts.begin(), f2_end_it);
1058 if (dbg_level > 0) {
1059 dump_span(f1.verts.as_span(),
"merge result");
1067 constexpr int dbg_level = 0;
1069 OutFace &tri1 =
faces[0];
1070 OutFace &tri2 =
faces[1];
1071 if (dbg_level > 0) {
1072 std::cout <<
"\nmerge_out_face_pair for faceid " <<
faces[0].face_id <<
"\n";
1073 dump_span(tri1.verts.as_span(),
"tri1");
1074 dump_span(tri2.verts.as_span(),
"tri2");
1076 const SharedEdge shared_edge = get_shared_edge_from_pair(tri1, tri2);
1077 if (shared_edge.e1 == -1) {
1081 const int va = shared_edge.v1;
1082 const int vb = shared_edge.v2;
1083 const int e1 = shared_edge.e1;
1084 const int e2 = shared_edge.e2;
1085 if (dbg_level > 0) {
1086 std::cout <<
"shared_edge = e" << e1 <<
", e" << e2 <<
"; " << va <<
", " << vb <<
"\n";
1093 const int vc = tri1.verts[(e1 + 2) % 3];
1094 const int vd = tri2.verts[(e2 - 3 + 2) % 3];
1095 BLI_assert(tri1.verts[e1] == va && tri1.verts[(e1 + 1) % 3] == vb && tri2.verts[e2 - 3] == vb &&
1096 tri2.verts[(e2 - 3 + 1) % 3] == va);
1101 tri1.verts.resize(4);
1106 if (dbg_level > 0) {
1107 dump_span(tri1.verts.as_span(),
"merged quad");
1119 constexpr int dbg_level = 0;
1120 if (
faces.size() <= 1) {
1123 if (
faces.size() == 2) {
1124 merge_out_face_pair(
faces);
1127 if (dbg_level > 0) {
1128 std::cout <<
"\nmerge_out_faces for faceid " <<
faces[0].face_id <<
"\n";
1129 for (
const int i :
faces.index_range()) {
1130 const OutFace &f =
faces[
i];
1131 dump_span(f.verts.as_span(), std::to_string(
i));
1135 if (dbg_level > 0) {
1136 std::cout <<
"shared edges:\n";
1137 for (
const SharedEdge &se : shared_edges) {
1138 std::cout <<
"(e" << se.e1 <<
",e" << se.e2 <<
";v" << se.v1 <<
",v" << se.v2 <<
")";
1152 auto final_merged_to = [&](
int f_orig) {
1154 int f_mapped = f_orig;
1156 if (merged_to[f_mapped] != -1) {
1157 f_mapped = merged_to[f_mapped];
1159 }
while (merged_to[f_mapped] != -1);
1164 if (!shared_edge_valid[
i]) {
1167 const SharedEdge se = shared_edges[
i];
1168 const int2 orig_faces = se.outface_group_face_indices();
1169 const int2 cur_faces =
int2(final_merged_to(orig_faces[0]), final_merged_to(orig_faces[1]));
1170 const int f1 = cur_faces[0];
1171 const int f2 = cur_faces[1];
1172 if (f1 == -1 || f2 == -2) {
1175 if (dbg_level > 0) {
1176 std::cout <<
"try merge of faces " << f1 <<
" and " << f2 <<
"\n";
1178 if (try_merge_out_face_pair(
faces[f1],
faces[f2], se)) {
1179 if (dbg_level > 0) {
1180 std::cout <<
"successful merge\n";
1181 dump_span(
faces[f1].
verts.as_span(),
"new f1");
1189 const int orig_faces_num =
faces.size();
1190 while (move_from < orig_faces_num) {
1192 while (move_from < orig_faces_num && merged_to[move_from] != -1) {
1195 if (move_from >= orig_faces_num) {
1198 if (move_to < move_from) {
1204 if (move_to < orig_faces_num) {
1205 faces.resize(move_to);
1207 if (dbg_level > 0) {
1208 std::cout <<
"final faces:\n";
1209 for (
const int i :
faces.index_range()) {
1210 dump_span(
faces[
i].
verts.as_span(), std::to_string(
i));
1216static inline const bool approx_in_line(
const float3 &p0,
const float3 &p1,
const float3 &p2)
1233static void dissolve_valence2_verts(MeshAssembly &ma)
1235 const int vnum = ma.output_verts_num;
1240 for (
const int f : ma.new_faces.index_range()) {
1241 const OutFace &face = ma.new_faces[f];
1242 const int fsize = face.verts.size();
1244 const int vprev = face.verts[(
i - 1 + fsize) % fsize];
1245 const int v = face.verts[
i];
1246 const int vnext = face.verts[(
i + 1) % fsize];
1247 std::pair<int, int> &v_nbrs = neighbors[
v];
1248 if (v_nbrs.first == -1) {
1250 v_nbrs.first = vprev;
1251 v_nbrs.second = vnext;
1253 dissolve[
v] = fsize <= 3 ?
false :
true;
1259 if (fsize == 3 || !(vprev == v_nbrs.second && vnext == v_nbrs.first)) {
1260 dissolve[
v] =
false;
1270 for (
const int f : ma.new_faces.index_range()) {
1271 const OutFace &face = ma.new_faces[f];
1272 const int fsize = face.verts.size();
1273 int num_dissolved = 0;
1275 if (dissolve[face.verts[
i]]) {
1279 if (fsize - num_dissolved < 3) {
1281 dissolve[face.verts[
i]] =
false;
1286 const int grain_size = 15000;
1287 bool any_dissolve =
false;
1289 bool range_any_dissolve =
false;
1290 for (
const int v : range) {
1292 std::pair<int, int> &v_nbrs = neighbors[
v];
1293 BLI_assert(v_nbrs.first != -1 && v_nbrs.second != -1);
1294 const float3 p0 = ma.vert_position(v_nbrs.first);
1295 const float3 p1 = ma.vert_position(
v);
1296 const float3 p2 = ma.vert_position(v_nbrs.second);
1297 if (!approx_in_line(p0, p1, p2)) {
1298 dissolve[
v] =
false;
1301 range_any_dissolve =
true;
1305 if (range_any_dissolve) {
1307 any_dissolve =
true;
1310 if (!any_dissolve) {
1321 dissolve.index_range(), dissolve.as_span(), memory);
1322 const int new_vnum = keep.
size();
1323 ma.old_to_new_vert_map.reinitialize(vnum);
1324 ma.old_to_new_vert_map.fill(-1);
1325 index_mask::build_reverse_map<int>(keep, ma.old_to_new_vert_map);
1328 float *vpos_data = ma.vertpos.data();
1331 const int new_v = ma.old_to_new_vert_map[old_v];
1334 std::copy_n(vpos_data + 3 * old_v, 3, vpos_data + 3 * new_v);
1337 ma.vertpos = ma.vertpos.take_front(new_vnum * ma.vertpos_stride);
1338 ma.output_verts_num = new_vnum;
1341 threading::parallel_for(ma.new_faces.index_range(), 10000, [&](
IndexRange range) {
1342 for (const int f : range) {
1343 OutFace &face = ma.new_faces[f];
1345 for (const int i_from : face.verts.index_range()) {
1346 const int mapped_v_from = ma.mapped_vert(face.verts[i_from]);
1347 if (mapped_v_from >= 0) {
1348 face.verts[i_to++] = mapped_v_from;
1351 if (i_to < face.verts.size()) {
1352 BLI_assert(i_to >= 3);
1353 face.verts.resize(i_to);
1368static MeshAssembly assemble_mesh_from_meshgl(MeshGL &mgl,
const MeshOffsets &mesh_offsets)
1371 timeit::ScopedTimer
timer(
"calculating assemble_mesh_from_meshgl");
1373 constexpr int dbg_level = 0;
1374 if (dbg_level > 0) {
1375 std::cout <<
"assemble_mesh_from_meshgl\n";
1378 ma.vertpos =
MutableSpan<float>(&*mgl.vertProperties.begin(), mgl.vertProperties.size());
1379 ma.vertpos_stride = mgl.numProp;
1380 ma.input_verts_num = mesh_offsets.vert_start.last();
1381 ma.output_verts_num = ma.vertpos.size() / ma.vertpos_stride;
1382 const int input_faces_num = mesh_offsets.face_start.last();
1386 if (dbg_level > 1) {
1387 std::cout <<
"groups:\n";
1389 std::cout <<
"orig (offset) face " <<
i <<
": ";
1390 dump_span(face_groups[
i].as_span(),
"");
1395 timeit::ScopedTimer
timer(
"face merging");
1398 const int grain_size = 15000;
1400 for (const int gid : range) {
1401 const Span<int> group = face_groups[gid].as_span();
1402 Vector<OutFace> &group_faces = new_groups[gid] = Vector<OutFace, 4>(group.size());
1403 for (const int i : group_faces.index_range()) {
1404 int tri_index = group[i];
1405 group_faces[i] = make_out_face(mgl, tri_index, gid);
1407 merge_out_faces(group_faces);
1411 timeit::ScopedTimer xtimer(
"copying groups at end");
1413 for (
const int i : new_groups.index_range()) {
1414 ma.new_faces.extend(new_groups[
i].as_span());
1419 timeit::ScopedTimer
timer(
"valence-2-vertex dissolving");
1421 dissolve_valence2_verts(ma);
1422 if (ma.old_to_new_vert_map.size() > 0) {
1425 mgl.vertProperties.resize(ma.vertpos.size());
1428 if (dbg_level > 0) {
1429 std::cout <<
"mesh_assembly result:\n";
1430 std::cout <<
"input_verts_num = " << ma.input_verts_num
1431 <<
", output_verts_num = " << ma.output_verts_num <<
"\n";
1432 dump_span_with_stride(ma.vertpos.as_span(), ma.vertpos_stride,
"vertpos");
1433 std::cout <<
"new_faces:\n";
1434 for (
const int i : ma.new_faces.index_range()) {
1435 std::cout <<
i <<
": face_id = " << ma.new_faces[
i].face_id <<
"\nverts ";
1436 dump_span(ma.new_faces[
i].verts.as_span(),
"");
1442static void copy_attribute_using_map(
const GSpan src,
1447 const int grain_size = 20000;
1449 for (const int out_elem : range) {
1450 const int in_elem = out_to_in_map[out_elem];
1451 if (in_elem != -1) {
1452 type.copy_assign(src[in_elem], dst[out_elem]);
1458static void interpolate_corner_attributes(bke::MutableAttributeAccessor &output_attrs,
1459 bke::AttributeAccessor &input_attrs,
1461 const Mesh *input_mesh,
1466 timeit::ScopedTimer
timer(
"interpolate corner attributes");
1476 input_attrs.foreach_attribute([&](
const bke::AttributeIter &iter) {
1477 if (iter.domain != bke::AttrDomain::Corner ||
ELEM(iter.name,
".corner_vert",
".corner_edge"))
1481 const bke::GAttributeReader reader = input_attrs.lookup_or_default(
1482 iter.name, iter.domain, iter.data_type);
1487 output_attrs.lookup_or_add_for_write_span(iter.name, iter.domain, iter.data_type));
1488 readers.
append(input_attrs.lookup_or_default(iter.name, iter.domain, iter.data_type));
1491 is_normal_attribute.
append(iter.name ==
"custom_normal");
1495 const OffsetIndices<int> output_faces = output_mesh->faces();
1496 const OffsetIndices<int> input_faces = input_mesh->faces();
1497 const Span<int> input_corner_verts = input_mesh->corner_verts();
1498 const Span<float3> input_vert_positions = input_mesh->vert_positions();
1499 const Span<int> output_corner_verts = output_mesh->corner_verts();
1500 const Span<float3> output_vert_positions = output_mesh->vert_positions();
1501 const int grain_size = 256;
1502 threading::parallel_for(
1504 Vector<float, 20> weights;
1505 Vector<float2, 20> cos_2d;
1507 for (const int out_face_index : range) {
1511 IndexRange out_face = output_faces[out_face_index];
1512 if (!std::any_of(out_face.begin(), out_face.end(), [&](int c) {
1513 return out_to_in_corner_map[c] == -1;
1523 const int in_face_index = out_to_in_face_map[out_face_index];
1524 const IndexRange in_face = input_faces[in_face_index];
1525 const Span<int> in_face_verts = input_corner_verts.slice(in_face);
1526 const int in_face_size = in_face.size();
1527 const Span<int> out_face_verts = output_corner_verts.slice(out_face);
1528 weights.resize(in_face_size);
1529 cos_2d.resize(in_face_size);
1530 float(*cos_2d_p)[2] = reinterpret_cast<float(*)[2]>(cos_2d.data());
1531 const float3 axis_dominant = bke::mesh::face_normal_calc(input_vert_positions,
1533 axis_dominant_v3_to_m3(axis_mat.ptr(), axis_dominant);
1537 const float3 out_face_normal = bke::mesh::face_normal_calc(output_vert_positions,
1539 const bool face_is_flipped = math::dot(axis_dominant, out_face_normal) < 0.0;
1540 for (const int i : in_face_verts.index_range()) {
1541 const float3 &co = input_vert_positions[in_face_verts[i]];
1542 cos_2d[i] = (axis_mat * co).xy();
1546 for (const int out_c : out_face) {
1547 const int in_c = out_to_in_corner_map[out_c];
1551 const int out_v = output_corner_verts[out_c];
1553 mul_v2_m3v3(co, axis_mat.ptr(), output_vert_positions[out_v]);
1554 interp_weights_poly_v2(weights.data(), cos_2d_p, in_face_size, co);
1556 for (const int attr_index : dsts.index_range()) {
1557 const GSpan src = srcs[attr_index];
1558 GMutableSpan dst = dsts[attr_index];
1559 const bool need_flip = face_is_flipped && is_normal_attribute[attr_index];
1560 const CPPType &type = dst.type();
1561 bke::attribute_math::convert_to_static_type(type, [&](auto dummy) {
1562 using T = decltype(dummy);
1563 const Span<T> src_typed = src.typed<T>();
1564 MutableSpan<T> dst_typed = dst.typed<T>();
1565 bke::attribute_math::DefaultMixer<T> mixer{MutableSpan(&dst_typed[out_c], 1)};
1566 for (const int i : in_face.index_range()) {
1567 mixer.mix_in(0, src_typed[in_face[i]], weights[i]);
1572 if (type.is<float3>()) {
1573 dst.typed<float3>()[out_c] = -dst.typed<float3>()[out_c];
1581 for (bke::GSpanAttributeWriter &writer : writers) {
1590static inline int mesh_id_for_face(
int face_id,
const MeshOffsets &mesh_offsets)
1592 for (
const int mesh_id : mesh_offsets.face_offsets.index_range()) {
1593 if (mesh_offsets.face_offsets[mesh_id].contains(face_id)) {
1605static void set_material_from_map(
const Span<int> out_to_in_map,
1608 const MeshOffsets &mesh_offsets,
1614 bke::AttributeAccessor input_attrs = meshes[
i]->attributes();
1616 *input_attrs.lookup_or_default<
int>(
"material_index", bke::AttrDomain::Face, 0));
1619 for (const int out_f : range) {
1620 const int in_f = out_to_in_map[out_f];
1621 const int mesh_id = mesh_id_for_face(in_f, mesh_offsets);
1622 const int in_f_local = in_f - mesh_offsets.face_start[mesh_id];
1623 const int orig = material_varrays[mesh_id][in_f_local];
1624 const Array<short> &map = material_remaps[mesh_id];
1625 dst[out_f] = (orig >= 0 && orig < map.size()) ? map[orig] : orig;
1635static void get_intersecting_edges(
Vector<int> *r_intersecting_edges,
1637 OutToInMaps &out_to_in,
1638 const MeshOffsets &mesh_offsets)
1644 timeit::ScopedTimer
timer(
"get_intersecting_edges");
1646 const OffsetIndices<int>
faces = mesh->faces();
1647 const Span<int> corner_edges = mesh->corner_edges();
1648 const Span<int> face_map = out_to_in.ensure_face_map();
1650 for (
int face_i :
faces.index_range()) {
1651 for (
const int edge_i : corner_edges.
slice(
faces[face_i])) {
1652 int face2_i = edge_first_face[edge_i];
1653 if (face2_i == -1) {
1654 edge_first_face[edge_i] = face_i;
1657 int in_face_i = face_map[face_i];
1658 int in_face2_i = face_map[face2_i];
1659 int m1 = mesh_id_for_face(in_face_i, mesh_offsets);
1660 int m2 = mesh_id_for_face(in_face2_i, mesh_offsets);
1663 r_intersecting_edges->
append(edge_i);
1675static bool is_plane(
const Mesh *mesh,
1678 float *r_origin_offset)
1685 const Span<int> f_corners = mesh->corner_verts().slice(mesh->faces()[0]);
1686 for (
int i = 0;
i < 4;
i++) {
1693 *r_origin_offset =
math::dot(norm1, vpos[0]);
1705static MeshGL mesh_trim_manifold(Manifold &manifold0,
1707 float origin_offset,
1708 const MeshOffsets &mesh_offsets,
1709 BooleanError *r_error)
1711 Manifold man_result = manifold0.TrimByPlane(manifold::vec3(normal[0], normal[1], normal[2]),
1712 double(origin_offset));
1713 MeshGL meshgl = man_result.GetMeshGL();
1714 if (man_result.Status() != Manifold::Error::NoError) {
1715 if (man_result.Status() == Manifold::Error::ResultTooLarge) {
1716 *r_error = BooleanError::ResultTooBig;
1718 else if (man_result.Status() == Manifold::Error::NotManifold) {
1719 *r_error = BooleanError::NonManifold;
1722 *r_error = BooleanError::UnknownError;
1729 if (meshgl.vertProperties.size() > 0) {
1730 BLI_assert(meshgl.runOriginalID.size() == 2 && meshgl.runOriginalID[1] > 0);
1731 meshgl.runOriginalID[1] = 1;
1733 int plane_face_start = meshgl.runIndex[1] / 3;
1734 int plane_face_end = meshgl.runIndex[2] / 3;
1735 for (
int i = plane_face_start;
i < plane_face_end;
i++) {
1736 meshgl.faceID[
i] = mesh_offsets.face_offsets[1][0];
1748static Mesh *meshgl_to_mesh(MeshGL &mgl,
1749 const Mesh *joined_mesh,
1752 const MeshOffsets &mesh_offsets,
1755 constexpr int dbg_level = 0;
1756 if (dbg_level > 0) {
1757 std::cout <<
"MESHGL_TO_MESH\n";
1760 timeit::ScopedTimer
timer(
"meshgl to mesh from joined_mesh");
1764 if (mgl.vertProperties.empty() || mgl.triVerts.empty()) {
1770 MeshAssembly ma = assemble_mesh_from_meshgl(mgl, mesh_offsets);
1771 const int verts_num = ma.output_verts_num;
1772 const int faces_num = ma.new_faces.size();
1777 Mesh *mesh = bke::mesh_new_no_attributes(verts_num, 0, faces_num, 0);
1784 for (
const int face : range) {
1785 face_offsets[face] = ma.new_faces[face].verts.size();
1788 const OffsetIndices<int>
faces = offset_indices::accumulate_counts_to_offsets(face_offsets);
1791 bke::MutableAttributeAccessor output_attrs = mesh->attributes_for_write();
1796 timeit::ScopedTimer timer_c(
"calculate faces");
1798 output_attrs.add<
int>(
".corner_vert", bke::AttrDomain::Corner, bke::AttributeInitConstruct());
1801 for (
const int face : range) {
1802 corner_verts.slice(
faces[face]).copy_from(ma.new_faces[face].verts);
1809 timeit::ScopedTimer timer_e(
"calculating edges");
1811 bke::mesh_calc_edges(*mesh,
false,
false);
1817 timeit::ScopedTimer timer_c(
"set positions");
1819 BLI_assert(!output_attrs.contains(
"position"));
1821 auto *sharing_info =
new ImplicitSharedValue<std::vector<float>>(
1822 std::move(mgl.vertProperties));
1823 const bke::AttributeInitShared
init(sharing_info->data.data(), *sharing_info);
1824 output_attrs.add<
float3>(
"position", bke::AttrDomain::Point,
init);
1825 sharing_info->remove_user_and_delete_if_last();
1828 OutToInMaps out_to_in(&ma, joined_mesh, mesh);
1832 timeit::ScopedTimer timer_a(
"copying and interpolating attributes");
1843 bke::AttributeAccessor join_attrs = joined_mesh->
attributes();
1845 bool need_corner_interpolation =
false;
1847 join_attrs.foreach_attribute([&](
const bke::AttributeIter &iter) {
1848 if (
ELEM(iter.name,
"position",
".edge_verts",
".corner_vert",
".corner_edge")) {
1852 bool do_copy =
true;
1853 bool do_material_remap =
false;
1854 switch (iter.domain) {
1855 case bke::AttrDomain::Point: {
1856 out_to_in_map = out_to_in.ensure_vertex_map();
1859 case bke::AttrDomain::Face: {
1860 out_to_in_map = out_to_in.ensure_face_map();
1866 do_material_remap = material_remaps.size() > 0 && iter.name ==
"material_index";
1869 case bke::AttrDomain::Edge: {
1870 out_to_in_map = out_to_in.ensure_edge_map();
1873 case bke::AttrDomain::Corner: {
1874 out_to_in_map = out_to_in.ensure_corner_map();
1875 need_corner_interpolation =
true;
1885 if (dbg_level > 0) {
1886 std::cout <<
"copy_attribute_using_map, name = " << iter.name <<
"\n";
1888 bke::GSpanAttributeWriter dst = output_attrs.lookup_or_add_for_write_span(
1889 iter.name, iter.domain, iter.data_type);
1890 if (do_material_remap) {
1891 set_material_from_map(
1892 out_to_in_map, material_remaps, meshes, mesh_offsets, dst.span.typed<
int>());
1895 copy_attribute_using_map(GVArraySpan(*iter.get()), out_to_in_map, dst.span);
1900 if (need_corner_interpolation) {
1901 interpolate_corner_attributes(output_attrs,
1905 out_to_in.ensure_corner_map(),
1906 out_to_in.ensure_face_map());
1908 if (r_intersecting_edges !=
nullptr) {
1909 get_intersecting_edges(r_intersecting_edges, mesh, out_to_in, mesh_offsets);
1913 mesh->tag_loose_verts_none();
1914 mesh->tag_overlapping_none();
1925 timeit::ScopedTimer jtimer(__func__);
1927 bke::Instances instances;
1928 instances.resize(meshes.
size());
1929 instances.transforms_for_write().copy_from(transforms);
1935 bke::GeometrySet geometry = bke::GeometrySet::from_mesh(
1936 const_cast<Mesh *
>(meshes[
i]), bke::GeometryOwnershipType::ReadOnly);
1937 return instances.add_new_reference(std::move(geometry));
1940 return geometry::realize_instances(
1941 bke::GeometrySet::from_instances(&instances, bke::GeometryOwnershipType::Editable),
1942 geometry::RealizeInstancesOptions());
1948 const BooleanOpParameters op_params,
1950 BooleanError *r_error)
1952 constexpr int dbg_level = 0;
1953 if (dbg_level > 0) {
1954 std::cout <<
"\nMESH_BOOLEAN_MANIFOLD with " << meshes.
size() <<
" args\n";
1956 *r_error = BooleanError::NoError;
1959 timeit::ScopedTimer
timer(
"MANIFOLD BOOLEAN");
1962 const int meshes_num = meshes.
size();
1964 bke::GeometrySet joined_meshes_set = join_meshes_with_transforms(meshes, transforms);
1965 const Mesh *joined_mesh = joined_meshes_set.get_mesh();
1966 if (joined_mesh ==
nullptr) {
1970 const MeshOffsets mesh_offsets(meshes);
1971 std::vector<Manifold> manifolds(meshes_num);
1972 get_manifolds(manifolds, meshes, transforms, mesh_offsets);
1974 MeshGL meshgl_result;
1976 if (std::any_of(manifolds.
begin(), manifolds.
end(), [](
const Manifold &m) {
1977 return m.Status() != Manifold::Error::NoError;
1982 float origin_offset;
1983 if (meshes_num == 2 && op == Operation::Difference &&
1984 manifolds[0].Status() == Manifold::Error::NoError &&
1985 is_plane(meshes[1], transforms[1], &normal, &origin_offset))
1988 timeit::ScopedTimer timer_trim(
"DOING BOOLEAN SLICE, GETTING MESH_GL RESULT");
1990 meshgl_result = mesh_trim_manifold(
1991 manifolds[0], normal, origin_offset, mesh_offsets, r_error);
1992 if (*r_error != BooleanError::NoError) {
1997 if (std::any_of(manifolds.
begin(), manifolds.
end(), [](
const Manifold &m) {
1998 return m.Status() == Manifold::Error::NotManifold;
2001 *r_error = BooleanError::NonManifold;
2004 *r_error = BooleanError::UnknownError;
2010 manifold::OpType mop = op == Operation::Intersect ?
2011 manifold::OpType::Intersect :
2012 (op == Operation::Union ? manifold::OpType::Add :
2013 manifold::OpType::Subtract);
2015 timeit::ScopedTimer timer_bool(
"DOING BOOLEAN, GETTING MESH_GL RESULT");
2017 Manifold man_result = Manifold::BatchBoolean(manifolds, mop);
2018 meshgl_result = man_result.GetMeshGL();
2020 if (man_result.Status() != Manifold::Error::NoError) {
2021 if (man_result.Status() == Manifold::Error::ResultTooLarge) {
2022 *r_error = BooleanError::ResultTooBig;
2025 *r_error = BooleanError::UnknownError;
2027 if (dbg_level > 0) {
2028 std::cout <<
"manifold boolean returned with error status\n";
2033 if (dbg_level > 0) {
2034 std::cout <<
"boolean result has " << meshgl_result.NumTri() <<
" tris\n";
2035 dump_meshgl(meshgl_result,
"boolean result meshgl");
2040 timeit::ScopedTimer timer_out(
"MESHGL RESULT TO MESH");
2042 mesh_result = meshgl_to_mesh(
2043 meshgl_result, joined_mesh, meshes, material_remaps, mesh_offsets, r_intersecting_edges);
2047 catch (
const std::exception &
e) {
2048 std::cout <<
"mesh_boolean_manifold: exception: " <<
e.what() <<
"\n";
2051 std::cout <<
"mesh_boolean_manifold: unknown exception\n";
2053 *r_error = BooleanError::UnknownError;
void BKE_id_free(Main *bmain, void *idv)
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
Mesh * BKE_mesh_copy_for_eval(const Mesh &source)
bool BKE_mesh_is_valid(Mesh *mesh)
#define BLI_assert_unreachable()
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
IndexRange index_range() const
const CPPType & type() const
static IndexMask from_bools_inverse(const VArray< bool > &bools, IndexMaskMemory &memory)
constexpr int64_t size() const
Value lookup_default(const Key &key, const Value &default_value) const
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
void add_new(const Key &key, const Value &value)
constexpr int64_t size() const
constexpr T * end() const
constexpr T * begin() const
constexpr Span slice(int64_t start, int64_t size) const
constexpr int64_t size() const
constexpr const T * end() const
constexpr IndexRange index_range() const
constexpr const T * begin() const
void append(const T &value)
const T & last(const int64_t n=0) const
IndexRange index_range() const
VecBase< float, 3 > float3
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
void vert_tris_from_corner_tris(Span< int > corner_verts, Span< int3 > corner_tris, MutableSpan< int3 > vert_tris)
Mesh * mesh_boolean_manifold(Span< const Mesh * > meshes, Span< float4x4 > transforms, Span< Array< short > > material_remaps, BooleanOpParameters op_params, Vector< int > *r_intersecting_edges, BooleanError *r_error)
VecBase< T, 3 > normal_tri(const VecBase< T, 3 > &v1, const VecBase< T, 3 > &v2, const VecBase< T, 3 > &v3)
T length(const VecBase< T, Size > &a)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
bool almost_equal_relative(const VecBase< T, Size > &a, const VecBase< T, Size > &b, const T &epsilon_factor)
bool is_identity(const MatBase< T, NumCol, NumRow > &mat)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
static void init(bNodeTree *, bNode *node)