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;
395 Vector<int, inline_outface_size>
verts;
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;
417 Vector<OutFace> new_faces;
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_;
455 const MeshOffsets *mesh_offsets_;
458 OutToInMaps(
const MeshAssembly *mesh_assembly,
459 const Mesh *joined_mesh,
460 const Mesh *output_mesh,
461 const MeshOffsets *mesh_offsets)
462 : mesh_assembly_(mesh_assembly),
463 joined_mesh_(joined_mesh),
464 output_mesh_(output_mesh),
465 mesh_offsets_(mesh_offsets)
469 Span<int> ensure_vertex_map();
470 Span<int> ensure_face_map();
471 Span<int> ensure_edge_map();
472 Span<int> ensure_corner_map();
477 if (!face_map_.is_empty()) {
482 timeit::ScopedTimer
timer(
"filling face map");
484 face_map_.reinitialize(output_mesh_->faces_num);
485 BLI_assert(mesh_assembly_->new_faces.size() == face_map_.size());
486 constexpr int grain_size = 50000;
487 threading::parallel_for(
488 mesh_assembly_->new_faces.index_range(), grain_size, [&](
const IndexRange range) {
489 for (const int i : range) {
490 face_map_[i] = mesh_assembly_->new_faces[i].face_id;
496Span<int> OutToInMaps::ensure_vertex_map()
498 if (!vertex_map_.is_empty()) {
505 const Span<int> face_map = this->ensure_face_map();
507 timeit::ScopedTimer
timer(
"filling vertex map");
509 vertex_map_ =
Array<int>(output_mesh_->verts_num, -1);
514 const OffsetIndices<int> in_faces = joined_mesh_->faces();
515 const OffsetIndices<int> out_faces = output_mesh_->faces();
516 const Span<int> in_corner_verts = joined_mesh_->corner_verts();
517 const Span<int> out_corner_verts = output_mesh_->corner_verts();
518 const Span<float3> out_vert_positions = output_mesh_->vert_positions();
519 const Span<float3> in_vert_positions = joined_mesh_->vert_positions();
520 for (
const int out_face_index :
IndexRange(output_mesh_->faces_num)) {
521 const int in_face_index = face_map[out_face_index];
522 const IndexRange in_face = in_faces[in_face_index];
523 const IndexRange out_face = out_faces[out_face_index];
525 for (
const int out_v : out_corner_verts.
slice(out_face)) {
526 if (vertex_map_[out_v] != -1) {
529 float3 out_pos = out_vert_positions[out_v];
530 const auto *it = std::find_if(in_face_verts.
begin(), in_face_verts.
end(), [&](
int in_v) {
531 return out_pos == in_vert_positions[in_v];
533 if (it != in_face_verts.
end()) {
534 int in_v = in_face_verts[std::distance(in_face_verts.
begin(), it)];
535 vertex_map_[out_v] = in_v;
542Span<int> OutToInMaps::ensure_corner_map()
544 if (!corner_map_.is_empty()) {
552 const Span<int> face_map = this->ensure_face_map();
553 const Span<int> vert_map = this->ensure_vertex_map();
555 timeit::ScopedTimer
timer(
"filling corner map");
557 corner_map_ =
Array<int>(output_mesh_->corners_num, -1);
558 const OffsetIndices<int> in_faces = joined_mesh_->faces();
559 const OffsetIndices<int> out_faces = output_mesh_->faces();
560 const Span<int> in_corner_verts = joined_mesh_->corner_verts();
561 const Span<int> out_corner_verts = output_mesh_->corner_verts();
562 constexpr int grain_size = 10000;
563 threading::parallel_for(
565 for (const int out_face_index : range) {
566 const int in_face_index = face_map[out_face_index];
567 const IndexRange in_face = in_faces[in_face_index];
568 for (const int out_c : out_faces[out_face_index]) {
569 BLI_assert(corner_map_[out_c] == -1);
570 const int out_v = out_corner_verts[out_c];
571 const int in_v = vert_map[out_v];
575 const int in_face_i = in_corner_verts.slice(in_face).first_index_try(in_v);
576 if (in_face_i != -1) {
577 const int in_c = in_face[in_face_i];
578 corner_map_[out_c] = in_c;
595 return (
math::abs(abs_cos_pq - 1.0f) <= 1e-5f);
602static inline int mesh_id_for_face(
const int face_id,
const MeshOffsets &mesh_offsets)
604 for (
const int mesh_id : mesh_offsets.face_offsets.index_range()) {
605 if (mesh_offsets.face_offsets[mesh_id].contains(face_id)) {
616static IndexRange vertex_range_for_face(
const int face_id,
const MeshOffsets &mesh_offsets)
618 const int mesh_id = mesh_id_for_face(face_id, mesh_offsets);
623 mesh_offsets.vert_start[mesh_id + 1]);
628 constexpr int dbg_level = 0;
629 if (!edge_map_.is_empty()) {
633 std::cout <<
"\nensure_edge_map\n";
635 dump_mesh(joined_mesh_,
"joined_mesh");
636 dump_mesh(output_mesh_,
"output_mesh");
650 const Span<int> face_map = this->ensure_face_map();
651 const Span<int> vert_map = this->ensure_vertex_map();
652 const Span<int> corner_map = this->ensure_corner_map();
658 timeit::ScopedTimer
timer(
"filling edge map");
660 edge_map_ =
Array<int>(output_mesh_->edges_num, -1);
661 const Span<int> out_corner_edges = output_mesh_->corner_edges();
662 const Span<int> out_corner_verts = output_mesh_->corner_verts();
663 const Span<int2> out_edges = output_mesh_->edges();
664 const Span<float3> out_positions = output_mesh_->vert_positions();
665 const Span<int> in_corner_edges = joined_mesh_->corner_edges();
666 const Span<int> in_corner_verts = joined_mesh_->corner_verts();
667 const Span<int2> in_edges = joined_mesh_->edges();
668 const Span<float3> in_positions = joined_mesh_->vert_positions();
669 const OffsetIndices<int> in_faces = joined_mesh_->faces();
670 const OffsetIndices<int> out_faces = output_mesh_->faces();
671 Array<bool> done_edge(output_mesh_->edges_num,
false);
672 for (
const int out_face_index :
IndexRange(output_mesh_->faces_num)) {
673 const int in_face_index = face_map[out_face_index];
674 const IndexRange in_face = in_faces[in_face_index];
675 const IndexRange in_face_vert_range = vertex_range_for_face(in_face_index, *mesh_offsets_);
677 std::cout <<
"process out_face = " << out_face_index <<
", in_face = " << in_face_index
680 for (
const int out_c : out_faces[out_face_index]) {
681 const int in_c = corner_map[out_c];
683 std::cout <<
" out_c = " << out_c <<
", in_c = " << in_c <<
"\n";
689 const int out_e = out_corner_edges[out_c];
691 std::cout <<
" out_e = " << out_e <<
", done = " << done_edge[out_e] <<
"\n";
693 if (done_edge[out_e]) {
696 const int out_v = out_corner_verts[out_c];
697 const int in_e = in_corner_edges[in_c];
698 const int in_v = in_corner_verts[in_c];
701 int2 out_e_v = out_edges[out_e];
702 if (out_e_v[0] != out_v) {
703 out_e_v = {out_e_v[1], out_e_v[0]};
705 int2 in_e_v = in_edges[in_e];
706 if (in_e_v[0] != in_v) {
707 in_e_v = {in_e_v[1], in_e_v[0]};
710 std::cout <<
" out_v = " << out_v <<
", in_e = " << in_e <<
", in_v = " << in_v <<
"\n";
711 std::cout <<
" out_e_v = " << out_e_v <<
", in_e_v = " << in_e_v <<
"\n";
712 std::cout <<
" vertex_map(out_e_v) = " <<
int2(vert_map[out_e_v[0]], vert_map[out_e_v[1]])
719 BLI_assert(vert_map[out_e_v[0]] == in_e_v[0]);
721 if (vert_map[out_e_v[1]] == in_e_v[1]) {
724 std::cout <<
" case 1, edge_rep = in_e = " << in_e <<
"\n";
728 else if (!in_face_vert_range.
contains(vert_map[out_e_v[1]])) {
732 if (same_dir(out_positions[out_e_v[0]],
733 out_positions[out_e_v[1]],
734 in_positions[in_e_v[0]],
735 in_positions[in_e_v[1]]))
738 std::cout <<
" case 2, edge_rep = in_e = " << in_e <<
"\n";
748 if (edge_rep == -1) {
749 const int in_c_prev = bke::mesh::face_corner_prev(in_face, in_c);
750 const int in_e_prev = in_corner_edges[in_c_prev];
751 const int in_v_prev = in_corner_verts[in_c_prev];
752 int2 in_e_v_prev = in_edges[in_e_prev];
753 if (in_e_v_prev[0] != in_v_prev) {
754 in_e_v_prev = {in_e_v_prev[1], in_e_v_prev[0]};
757 std::cout <<
" in_c_prev = " << in_c_prev <<
", in_e_prev = " << in_e_prev
758 <<
", in_v_prev = " << in_v_prev <<
"\n";
759 std::cout <<
" in_e_v_prev = " << in_e_v_prev <<
"\n";
761 if (vert_map[out_e_v[0]] == in_e_v_prev[1]) {
762 if (vert_map[out_e_v[1]] == in_e_v_prev[0]) {
764 std::cout <<
" case 3, edge_rep = in_e_prev = " << in_e_prev <<
"\n";
766 edge_rep = in_e_prev;
768 else if (vert_map[out_e_v[1]] == -1) {
769 if (same_dir(out_positions[out_e_v[0]],
770 out_positions[out_e_v[1]],
771 in_positions[in_e_v_prev[0]],
772 in_positions[in_e_v_prev[1]]))
775 std::cout <<
" case 4, edge_rep = in_e_prev = " << in_e_prev <<
"\n";
777 edge_rep = in_e_prev;
782 if (edge_rep != -1) {
784 std::cout <<
" found: set edge_map[" << out_e <<
"] = " << edge_rep <<
"\n";
786 edge_map_[out_e] = edge_rep;
787 done_edge[out_e] =
true;
795constexpr int face_group_inline = 4;
806 timeit::ScopedTimer
timer(
"get_face_groups");
808 constexpr int dbg_level = 0;
810 const int tris_num = mgl.NumTri();
813 const int faceid = mgl.faceID[t];
814 fg[faceid].append(t);
817 std::cout <<
"face_groups\n";
818 for (
const int i : fg.index_range()) {
819 std::cout <<
"orig face " <<
i;
820 dump_span(fg[
i].as_span(),
"");
839 BLI_assert(0 <= face_index && face_index < mesh->faces_num);
840 const IndexRange orig_face = mesh->faces()[face_index];
843 int orig_face_size = orig_face.
size();
844 if (orig_face_size != group.
size() + 2) {
847 Span<int> orig_face_verts = mesh->corner_verts().slice(mesh->faces()[face_index]);
851 int stride = mgl.numProp;
852 for (
const int t : group) {
858 int v = mgl.triVerts[3 * t +
i];
859 int prop_offset =
v * stride;
860 float3 pos(mgl.vertProperties[prop_offset],
861 mgl.vertProperties[prop_offset + 1],
862 mgl.vertProperties[prop_offset + 2]);
863 auto it = std::find_if(orig_face_verts.
begin(), orig_face_verts.
end(), [&](
int orig_v) {
864 return pos == mesh->vert_positions()[orig_v];
866 face_vert_index[
i] = it == orig_face_verts.
end() ?
868 std::distance(orig_face_verts.
begin(), it);
872 const int a = face_vert_index[
i];
873 const int b = face_vert_index[(
i + 1) % 3];
874 if (a != -1 &&
b != -1) {
875 if ((a + 1) % orig_face_size ==
b) {
878 else if ((
b + 1) % orig_face_size == a) {
884 if (std::all_of(edge_value.begin(), edge_value.end(), [](
int x) { return x == 1; })) {
887 else if (std::all_of(edge_value.begin(), edge_value.end(), [](
int x) { return x == -1; })) {
894static OutFace make_out_face(
const MeshGL &mgl,
int tri_index,
int orig_face)
898 const int k = 3 * tri_index;
899 ans.verts[0] = mgl.triVerts[k];
900 ans.verts[1] = mgl.triVerts[k + 1];
901 ans.verts[2] = mgl.triVerts[k + 2];
902 ans.face_id = orig_face;
923 SharedEdge(
int e1,
int e2,
int v1,
int v2) : e1(e1), e2(e2), v1(v1),
v2(
v2) {}
927 int2 outface_group_face_indices()
const
929 return int2(e1 / 3, e2 / 3);
934static inline SharedEdge canon_shared_edge(
int e1,
int e2,
int v1,
int v2)
937 return SharedEdge(e1, e2, v1,
v2);
939 return SharedEdge(e2, e1,
v2, v1);
947static SharedEdge get_shared_edge_from_pair(
const OutFace &tri1,
const OutFace &tri2)
950 SharedEdge shared_edge(-1, -1, -1, -1);
953 const int v1 = tri1.verts[i1];
954 const int v2 = tri2.verts[i2];
956 const int v1_next = tri1.verts[(i1 + 1) % 3];
957 const int v2_prev = tri2.verts[(i2 + 2) % 3];
958 if (v1_next == v2_prev) {
959 shared_edge = SharedEdge(i1, 3 + ((i2 + 2) % 3), v1, v1_next);
962 const int v1_prev = tri1.verts[(i1 + 2) % 3];
963 const int v2_next = tri2.verts[(i2 + 1) % 3];
964 if (v1_prev == v2_next) {
965 shared_edge = SharedEdge((i1 + 2) % 3, 3 + i2, v1_prev, v1);
970 if (shared_edge.e1 != -1) {
988 for (
const int face_index :
faces.index_range()) {
989 const OutFace &f =
faces[face_index];
992 int v2 = f.verts[(
i + 1) % 3];
993 int this_e = face_index * 3 +
i;
997 ans.
append(canon_shared_edge(this_e, other_e, v1,
v2));
1009static bool is_legal_merge(
const OutFace &f1,
const OutFace &f2,
int v1,
int v2)
1015 for (
const int v : f1.verts) {
1017 if (f2.find_vert_index(
v) != -1) {
1022 for (
const int v : f2.verts) {
1024 if (f1.find_vert_index(
v) != -1) {
1040static bool try_merge_out_face_pair(OutFace &f1,
const OutFace &f2,
const SharedEdge &se)
1043 constexpr int dbg_level = 0;
1044 if (dbg_level > 0) {
1045 std::cout <<
"try_merge_out_face_pair\n";
1046 dump_span(f1.verts.as_span(),
"f1");
1047 dump_span(f2.verts.as_span(),
"f2");
1048 std::cout <<
"shared edge: "
1049 <<
"(e" << se.e1 <<
",e" << se.e2 <<
";v" << se.v1 <<
",v" << se.v2 <<
")\n";
1051 const int f1_len = f1.verts.size();
1052 const int f2_len = f2.verts.size();
1053 const int v1 = se.v1;
1054 const int v2 = se.v2;
1057 const int i1 = f1.find_vert_index(v1);
1059 const int i1_next = (i1 + 1) % f1_len;
1060 const int i2 = f2.find_vert_index(
v2);
1062 const int i2_next = (i2 + 1) % f2_len;
1063 BLI_assert(f1.verts[i1] == v1 && f1.verts[i1_next] ==
v2);
1064 BLI_assert(f2.verts[i2] ==
v2 && f2.verts[i2_next] == v1);
1065 const bool can_merge = is_legal_merge(f1, f2, v1,
v2);
1066 if (dbg_level > 0) {
1067 std::cout <<
"i1 = " << i1 <<
", i2 = " << i2 <<
", can_merge = " << can_merge <<
"\n";
1078 const int i2_prev = (i2 + f2_len - 1) % f2_len;
1079 const int i2_next_next = (i2_next + 1) % f2_len;
1080 const auto *f2_start_it = f2.verts.begin() + i2_next_next;
1081 const auto *f2_end_it = f2.verts.begin() + i2_prev + 1;
1082 if (f2_end_it > f2_start_it) {
1083 f1.verts.insert(i1_next, f2_start_it, f2_end_it);
1086 const int n1 = std::distance(f2_start_it, f2.verts.end());
1088 f1.verts.insert(i1_next, f2_start_it, f2.verts.end());
1090 if (n1 < f2_len - 2) {
1091 f1.verts.insert(i1_next + n1, f2.verts.begin(), f2_end_it);
1094 if (dbg_level > 0) {
1095 dump_span(f1.verts.as_span(),
"merge result");
1103 constexpr int dbg_level = 0;
1105 OutFace &tri1 =
faces[0];
1106 OutFace &tri2 =
faces[1];
1107 if (dbg_level > 0) {
1108 std::cout <<
"\nmerge_out_face_pair for faceid " <<
faces[0].face_id <<
"\n";
1109 dump_span(tri1.verts.as_span(),
"tri1");
1110 dump_span(tri2.verts.as_span(),
"tri2");
1112 const SharedEdge shared_edge = get_shared_edge_from_pair(tri1, tri2);
1113 if (shared_edge.e1 == -1) {
1117 const int va = shared_edge.v1;
1118 const int vb = shared_edge.v2;
1119 const int e1 = shared_edge.e1;
1120 const int e2 = shared_edge.e2;
1121 if (dbg_level > 0) {
1122 std::cout <<
"shared_edge = e" << e1 <<
", e" << e2 <<
"; " << va <<
", " << vb <<
"\n";
1129 const int vc = tri1.verts[(e1 + 2) % 3];
1130 const int vd = tri2.verts[(e2 - 3 + 2) % 3];
1131 BLI_assert(tri1.verts[e1] == va && tri1.verts[(e1 + 1) % 3] == vb && tri2.verts[e2 - 3] == vb &&
1132 tri2.verts[(e2 - 3 + 1) % 3] == va);
1137 tri1.verts.resize(4);
1142 if (dbg_level > 0) {
1143 dump_span(tri1.verts.as_span(),
"merged quad");
1155 constexpr int dbg_level = 0;
1156 if (
faces.size() <= 1) {
1159 if (
faces.size() == 2) {
1160 merge_out_face_pair(
faces);
1163 if (dbg_level > 0) {
1164 std::cout <<
"\nmerge_out_faces for faceid " <<
faces[0].face_id <<
"\n";
1165 for (
const int i :
faces.index_range()) {
1166 const OutFace &f =
faces[
i];
1167 dump_span(f.verts.as_span(), std::to_string(
i));
1171 if (dbg_level > 0) {
1172 std::cout <<
"shared edges:\n";
1173 for (
const SharedEdge &se : shared_edges) {
1174 std::cout <<
"(e" << se.e1 <<
",e" << se.e2 <<
";v" << se.v1 <<
",v" << se.v2 <<
")";
1188 auto final_merged_to = [&](
int f_orig) {
1190 int f_mapped = f_orig;
1192 if (merged_to[f_mapped] != -1) {
1193 f_mapped = merged_to[f_mapped];
1195 }
while (merged_to[f_mapped] != -1);
1200 if (!shared_edge_valid[
i]) {
1203 const SharedEdge se = shared_edges[
i];
1204 const int2 orig_faces = se.outface_group_face_indices();
1205 const int2 cur_faces =
int2(final_merged_to(orig_faces[0]), final_merged_to(orig_faces[1]));
1206 const int f1 = cur_faces[0];
1207 const int f2 = cur_faces[1];
1208 if (f1 == -1 || f2 == -2) {
1211 if (dbg_level > 0) {
1212 std::cout <<
"try merge of faces " << f1 <<
" and " << f2 <<
"\n";
1214 if (try_merge_out_face_pair(
faces[f1],
faces[f2], se)) {
1215 if (dbg_level > 0) {
1216 std::cout <<
"successful merge\n";
1217 dump_span(
faces[f1].
verts.as_span(),
"new f1");
1225 const int orig_faces_num =
faces.size();
1226 while (move_from < orig_faces_num) {
1228 while (move_from < orig_faces_num && merged_to[move_from] != -1) {
1231 if (move_from >= orig_faces_num) {
1234 if (move_to < move_from) {
1240 if (move_to < orig_faces_num) {
1241 faces.resize(move_to);
1243 if (dbg_level > 0) {
1244 std::cout <<
"final faces:\n";
1245 for (
const int i :
faces.index_range()) {
1246 dump_span(
faces[
i].
verts.as_span(), std::to_string(
i));
1252static inline bool approx_in_line(
const float3 &p0,
const float3 &p1,
const float3 &p2)
1269static void dissolve_valence2_verts(MeshAssembly &ma)
1271 const int vnum = ma.output_verts_num;
1276 for (
const int f : ma.new_faces.index_range()) {
1277 const OutFace &face = ma.new_faces[f];
1278 const int fsize = face.verts.size();
1280 const int vprev = face.verts[(
i - 1 + fsize) % fsize];
1281 const int v = face.verts[
i];
1282 const int vnext = face.verts[(
i + 1) % fsize];
1283 std::pair<int, int> &v_nbrs = neighbors[
v];
1284 if (v_nbrs.first == -1) {
1286 v_nbrs.first = vprev;
1287 v_nbrs.second = vnext;
1289 dissolve[
v] = fsize <= 3 ?
false :
true;
1295 if (fsize == 3 || !(vprev == v_nbrs.second && vnext == v_nbrs.first)) {
1296 dissolve[
v] =
false;
1305 for (
const int f : ma.new_faces.index_range()) {
1306 const OutFace &face = ma.new_faces[f];
1307 const int fsize = face.verts.size();
1308 int num_dissolved = 0;
1310 if (dissolve[face.verts[
i]]) {
1314 if (fsize - num_dissolved < 3) {
1316 dissolve[face.verts[
i]] =
false;
1321 const int grain_size = 15000;
1322 bool any_dissolve =
false;
1324 bool range_any_dissolve =
false;
1325 for (
const int v : range) {
1327 std::pair<int, int> &v_nbrs = neighbors[
v];
1328 BLI_assert(v_nbrs.first != -1 && v_nbrs.second != -1);
1329 const float3 p0 = ma.vert_position(v_nbrs.first);
1330 const float3 p1 = ma.vert_position(
v);
1331 const float3 p2 = ma.vert_position(v_nbrs.second);
1332 if (!approx_in_line(p0, p1, p2)) {
1333 dissolve[
v] =
false;
1336 range_any_dissolve =
true;
1340 if (range_any_dissolve) {
1342 any_dissolve =
true;
1345 if (!any_dissolve) {
1355 dissolve.index_range(), dissolve.as_span(), memory);
1356 const int new_vnum = keep.
size();
1357 ma.old_to_new_vert_map.reinitialize(vnum);
1358 ma.old_to_new_vert_map.fill(-1);
1359 index_mask::build_reverse_map<int>(keep, ma.old_to_new_vert_map);
1362 float *vpos_data = ma.vertpos.data();
1365 const int new_v = ma.old_to_new_vert_map[old_v];
1368 std::copy_n(vpos_data + 3 * old_v, 3, vpos_data + 3 * new_v);
1371 ma.vertpos = ma.vertpos.take_front(new_vnum * ma.vertpos_stride);
1372 ma.output_verts_num = new_vnum;
1375 threading::parallel_for(ma.new_faces.index_range(), 10000, [&](
IndexRange range) {
1376 for (const int f : range) {
1377 OutFace &face = ma.new_faces[f];
1379 for (const int i_from : face.verts.index_range()) {
1380 const int mapped_v_from = ma.mapped_vert(face.verts[i_from]);
1381 if (mapped_v_from >= 0) {
1382 face.verts[i_to++] = mapped_v_from;
1385 if (i_to < face.verts.size()) {
1386 BLI_assert(i_to >= 3);
1387 face.verts.resize(i_to);
1402static MeshAssembly assemble_mesh_from_meshgl(MeshGL &mgl,
const MeshOffsets &mesh_offsets)
1405 timeit::ScopedTimer
timer(
"calculating assemble_mesh_from_meshgl");
1407 constexpr int dbg_level = 0;
1408 if (dbg_level > 0) {
1409 std::cout <<
"assemble_mesh_from_meshgl\n";
1412 ma.vertpos =
MutableSpan<float>(&*mgl.vertProperties.begin(), mgl.vertProperties.size());
1413 ma.vertpos_stride = mgl.numProp;
1414 ma.input_verts_num = mesh_offsets.vert_start.last();
1415 ma.output_verts_num = ma.vertpos.size() / ma.vertpos_stride;
1416 const int input_faces_num = mesh_offsets.face_start.last();
1420 if (dbg_level > 1) {
1421 std::cout <<
"groups:\n";
1423 std::cout <<
"orig (offset) face " <<
i <<
": ";
1424 dump_span(face_groups[
i].as_span(),
"");
1429 timeit::ScopedTimer
timer(
"face merging");
1432 const int grain_size = 15000;
1434 for (const int gid : range) {
1435 const Span<int> group = face_groups[gid].as_span();
1436 Vector<OutFace> &group_faces = new_groups[gid] = Vector<OutFace, 4>(group.size());
1437 for (const int i : group_faces.index_range()) {
1438 int tri_index = group[i];
1439 group_faces[i] = make_out_face(mgl, tri_index, gid);
1441 merge_out_faces(group_faces);
1445 timeit::ScopedTimer xtimer(
"copying groups at end");
1447 for (
const int i : new_groups.index_range()) {
1448 ma.new_faces.extend(new_groups[
i].as_span());
1453 timeit::ScopedTimer
timer(
"valence-2-vertex dissolving");
1455 dissolve_valence2_verts(ma);
1456 if (ma.old_to_new_vert_map.size() > 0) {
1459 mgl.vertProperties.resize(ma.vertpos.size());
1462 if (dbg_level > 0) {
1463 std::cout <<
"mesh_assembly result:\n";
1464 std::cout <<
"input_verts_num = " << ma.input_verts_num
1465 <<
", output_verts_num = " << ma.output_verts_num <<
"\n";
1466 dump_span_with_stride(ma.vertpos.as_span(), ma.vertpos_stride,
"vertpos");
1467 std::cout <<
"new_faces:\n";
1468 for (
const int i : ma.new_faces.index_range()) {
1469 std::cout <<
i <<
": face_id = " << ma.new_faces[
i].face_id <<
"\nverts ";
1470 dump_span(ma.new_faces[
i].verts.as_span(),
"");
1476static void copy_attribute_using_map(
const GSpan src,
1481 const int grain_size = 20000;
1483 for (const int out_elem : range) {
1484 const int in_elem = out_to_in_map[out_elem];
1485 if (in_elem != -1) {
1486 type.copy_assign(src[in_elem], dst[out_elem]);
1492static void interpolate_corner_attributes(bke::MutableAttributeAccessor &output_attrs,
1493 bke::AttributeAccessor &input_attrs,
1495 const Mesh *input_mesh,
1500 timeit::ScopedTimer
timer(
"interpolate corner attributes");
1510 input_attrs.foreach_attribute([&](
const bke::AttributeIter &iter) {
1511 if (iter.domain != bke::AttrDomain::Corner ||
ELEM(iter.name,
".corner_vert",
".corner_edge"))
1515 const bke::GAttributeReader reader = input_attrs.lookup_or_default(
1516 iter.name, iter.domain, iter.data_type);
1521 output_attrs.lookup_or_add_for_write_span(iter.name, iter.domain, iter.data_type));
1522 readers.
append(input_attrs.lookup_or_default(iter.name, iter.domain, iter.data_type));
1525 is_normal_attribute.
append(iter.name ==
"custom_normal");
1529 const OffsetIndices<int> output_faces = output_mesh->faces();
1530 const OffsetIndices<int> input_faces = input_mesh->faces();
1531 const Span<int> input_corner_verts = input_mesh->corner_verts();
1532 const Span<float3> input_vert_positions = input_mesh->vert_positions();
1533 const Span<int> output_corner_verts = output_mesh->corner_verts();
1534 const Span<float3> output_vert_positions = output_mesh->vert_positions();
1535 const int grain_size = 256;
1536 threading::parallel_for(
1538 Vector<float, 20> weights;
1539 Vector<float2, 20> cos_2d;
1541 for (const int out_face_index : range) {
1545 IndexRange out_face = output_faces[out_face_index];
1546 if (!std::any_of(out_face.begin(), out_face.end(), [&](int c) {
1547 return out_to_in_corner_map[c] == -1;
1557 const int in_face_index = out_to_in_face_map[out_face_index];
1558 const IndexRange in_face = input_faces[in_face_index];
1559 const Span<int> in_face_verts = input_corner_verts.slice(in_face);
1560 const int in_face_size = in_face.size();
1561 const Span<int> out_face_verts = output_corner_verts.slice(out_face);
1562 weights.resize(in_face_size);
1563 cos_2d.resize(in_face_size);
1564 float (*cos_2d_p)[2] = reinterpret_cast<float (*)[2]>(cos_2d.data());
1565 const float3 axis_dominant = bke::mesh::face_normal_calc(input_vert_positions,
1567 axis_dominant_v3_to_m3(axis_mat.ptr(), axis_dominant);
1571 const float3 out_face_normal = bke::mesh::face_normal_calc(output_vert_positions,
1573 const bool face_is_flipped = math::dot(axis_dominant, out_face_normal) < 0.0;
1574 for (const int i : in_face_verts.index_range()) {
1575 const float3 &co = input_vert_positions[in_face_verts[i]];
1576 cos_2d[i] = (axis_mat * co).xy();
1580 for (const int out_c : out_face) {
1581 const int in_c = out_to_in_corner_map[out_c];
1585 const int out_v = output_corner_verts[out_c];
1587 mul_v2_m3v3(co, axis_mat.ptr(), output_vert_positions[out_v]);
1588 interp_weights_poly_v2(weights.data(), cos_2d_p, in_face_size, co);
1590 for (const int attr_index : dsts.index_range()) {
1591 const GSpan src = srcs[attr_index];
1592 GMutableSpan dst = dsts[attr_index];
1593 const bool need_flip = face_is_flipped && is_normal_attribute[attr_index];
1594 const CPPType &type = dst.type();
1595 bke::attribute_math::convert_to_static_type(type, [&](auto dummy) {
1596 using T = decltype(dummy);
1597 const Span<T> src_typed = src.typed<T>();
1598 MutableSpan<T> dst_typed = dst.typed<T>();
1599 bke::attribute_math::DefaultMixer<T> mixer{MutableSpan(&dst_typed[out_c], 1)};
1600 for (const int i : in_face.index_range()) {
1601 mixer.mix_in(0, src_typed[in_face[i]], weights[i]);
1606 if (type.is<float3>()) {
1607 dst.typed<float3>()[out_c] = -dst.typed<float3>()[out_c];
1615 for (bke::GSpanAttributeWriter &writer : writers) {
1625static void set_material_from_map(
const Span<int> out_to_in_map,
1628 const MeshOffsets &mesh_offsets,
1634 bke::AttributeAccessor input_attrs = meshes[
i]->attributes();
1636 *input_attrs.lookup_or_default<
int>(
"material_index", bke::AttrDomain::Face, 0));
1639 for (const int out_f : range) {
1640 const int in_f = out_to_in_map[out_f];
1641 const int mesh_id = mesh_id_for_face(in_f, mesh_offsets);
1642 const int in_f_local = in_f - mesh_offsets.face_start[mesh_id];
1643 const int orig = material_varrays[mesh_id][in_f_local];
1644 const Array<short> &map = material_remaps[mesh_id];
1645 dst[out_f] = (orig >= 0 && orig < map.size()) ? map[orig] : orig;
1655static void get_intersecting_edges(
Vector<int> *r_intersecting_edges,
1657 OutToInMaps &out_to_in,
1658 const MeshOffsets &mesh_offsets)
1664 timeit::ScopedTimer
timer(
"get_intersecting_edges");
1666 const OffsetIndices<int>
faces = mesh->faces();
1667 const Span<int> corner_edges = mesh->corner_edges();
1668 const Span<int> face_map = out_to_in.ensure_face_map();
1670 for (
int face_i :
faces.index_range()) {
1671 for (
const int edge_i : corner_edges.
slice(
faces[face_i])) {
1672 int face2_i = edge_first_face[edge_i];
1673 if (face2_i == -1) {
1674 edge_first_face[edge_i] = face_i;
1677 int in_face_i = face_map[face_i];
1678 int in_face2_i = face_map[face2_i];
1679 int m1 = mesh_id_for_face(in_face_i, mesh_offsets);
1680 int m2 = mesh_id_for_face(in_face2_i, mesh_offsets);
1683 r_intersecting_edges->
append(edge_i);
1695static bool is_plane(
const Mesh *mesh,
1698 float *r_origin_offset)
1705 const Span<int> f_corners = mesh->corner_verts().slice(mesh->faces()[0]);
1706 for (
int i = 0;
i < 4;
i++) {
1713 *r_origin_offset =
math::dot(norm1, vpos[0]);
1725static MeshGL mesh_trim_manifold(Manifold &manifold0,
1727 float origin_offset,
1728 const MeshOffsets &mesh_offsets,
1729 BooleanError *r_error)
1731 Manifold man_result = manifold0.TrimByPlane(manifold::vec3(normal[0], normal[1], normal[2]),
1732 double(origin_offset));
1733 MeshGL meshgl = man_result.GetMeshGL();
1734 if (man_result.Status() != Manifold::Error::NoError) {
1735 if (man_result.Status() == Manifold::Error::ResultTooLarge) {
1736 *r_error = BooleanError::ResultTooBig;
1738 else if (man_result.Status() == Manifold::Error::NotManifold) {
1739 *r_error = BooleanError::NonManifold;
1742 *r_error = BooleanError::UnknownError;
1749 if (meshgl.vertProperties.size() > 0) {
1750 BLI_assert(meshgl.runOriginalID.size() == 2 && meshgl.runOriginalID[1] > 0);
1751 meshgl.runOriginalID[1] = 1;
1753 int plane_face_start = meshgl.runIndex[1] / 3;
1754 int plane_face_end = meshgl.runIndex[2] / 3;
1755 for (
int i = plane_face_start;
i < plane_face_end;
i++) {
1756 meshgl.faceID[
i] = mesh_offsets.face_offsets[1][0];
1768static Mesh *meshgl_to_mesh(MeshGL &mgl,
1769 const Mesh *joined_mesh,
1772 const MeshOffsets &mesh_offsets,
1775 constexpr int dbg_level = 0;
1776 if (dbg_level > 0) {
1777 std::cout <<
"MESHGL_TO_MESH\n";
1780 timeit::ScopedTimer
timer(
"meshgl to mesh from joined_mesh");
1784 if (mgl.vertProperties.empty() || mgl.triVerts.empty()) {
1790 MeshAssembly ma = assemble_mesh_from_meshgl(mgl, mesh_offsets);
1791 const int verts_num = ma.output_verts_num;
1792 const int faces_num = ma.new_faces.size();
1797 Mesh *mesh = bke::mesh_new_no_attributes(verts_num, 0, faces_num, 0);
1804 for (
const int face : range) {
1805 face_offsets[face] = ma.new_faces[face].verts.size();
1808 const OffsetIndices<int>
faces = offset_indices::accumulate_counts_to_offsets(face_offsets);
1811 bke::MutableAttributeAccessor output_attrs = mesh->attributes_for_write();
1816 timeit::ScopedTimer timer_c(
"calculate faces");
1818 output_attrs.add<
int>(
".corner_vert", bke::AttrDomain::Corner, bke::AttributeInitConstruct());
1821 for (
const int face : range) {
1822 corner_verts.slice(
faces[face]).copy_from(ma.new_faces[face].verts);
1830 timeit::ScopedTimer timer_c(
"set positions");
1832 BLI_assert(!output_attrs.contains(
"position"));
1834 auto *sharing_info =
new ImplicitSharedValue<std::vector<float>>(
1835 std::move(mgl.vertProperties));
1836 const bke::AttributeInitShared
init(sharing_info->data.data(), *sharing_info);
1837 output_attrs.add<
float3>(
"position", bke::AttrDomain::Point,
init);
1838 sharing_info->remove_user_and_delete_if_last();
1843 timeit::ScopedTimer timer_e(
"calculating edges");
1845 bke::mesh_calc_edges(*mesh,
false,
false);
1850 OutToInMaps out_to_in(&ma, joined_mesh, mesh, &mesh_offsets);
1854 timeit::ScopedTimer timer_a(
"copying and interpolating attributes");
1865 bke::AttributeAccessor join_attrs = joined_mesh->
attributes();
1867 bool need_corner_interpolation =
false;
1869 join_attrs.foreach_attribute([&](
const bke::AttributeIter &iter) {
1870 if (
ELEM(iter.name,
"position",
".edge_verts",
".corner_vert",
".corner_edge")) {
1874 bool do_copy =
true;
1875 bool do_material_remap =
false;
1876 switch (iter.domain) {
1877 case bke::AttrDomain::Point: {
1878 out_to_in_map = out_to_in.ensure_vertex_map();
1881 case bke::AttrDomain::Face: {
1882 out_to_in_map = out_to_in.ensure_face_map();
1888 do_material_remap = material_remaps.size() > 0 && iter.name ==
"material_index";
1891 case bke::AttrDomain::Edge: {
1892 out_to_in_map = out_to_in.ensure_edge_map();
1895 case bke::AttrDomain::Corner: {
1896 out_to_in_map = out_to_in.ensure_corner_map();
1897 need_corner_interpolation =
true;
1907 if (dbg_level > 0) {
1908 std::cout <<
"copy_attribute_using_map, name = " << iter.name <<
"\n";
1910 bke::GSpanAttributeWriter dst = output_attrs.lookup_or_add_for_write_span(
1911 iter.name, iter.domain, iter.data_type);
1912 if (do_material_remap) {
1913 set_material_from_map(
1914 out_to_in_map, material_remaps, meshes, mesh_offsets, dst.span.typed<
int>());
1917 copy_attribute_using_map(GVArraySpan(*iter.get()), out_to_in_map, dst.span);
1922 if (need_corner_interpolation) {
1923 interpolate_corner_attributes(output_attrs,
1927 out_to_in.ensure_corner_map(),
1928 out_to_in.ensure_face_map());
1930 if (r_intersecting_edges !=
nullptr) {
1931 get_intersecting_edges(r_intersecting_edges, mesh, out_to_in, mesh_offsets);
1935 mesh->tag_loose_verts_none();
1936 mesh->tag_overlapping_none();
1947 timeit::ScopedTimer jtimer(__func__);
1949 bke::Instances instances;
1950 instances.resize(meshes.
size());
1951 instances.transforms_for_write().copy_from(transforms);
1957 bke::GeometrySet geometry = bke::GeometrySet::from_mesh(
1958 const_cast<Mesh *
>(meshes[
i]), bke::GeometryOwnershipType::ReadOnly);
1959 return instances.add_new_reference(std::move(geometry));
1962 return geometry::realize_instances(
1963 bke::GeometrySet::from_instances(&instances, bke::GeometryOwnershipType::Editable),
1964 geometry::RealizeInstancesOptions())
1971 const BooleanOpParameters op_params,
1973 BooleanError *r_error)
1975 constexpr int dbg_level = 0;
1976 if (dbg_level > 0) {
1977 std::cout <<
"\nMESH_BOOLEAN_MANIFOLD with " << meshes.
size() <<
" args\n";
1979 *r_error = BooleanError::NoError;
1982 timeit::ScopedTimer
timer(
"MANIFOLD BOOLEAN");
1985 const int meshes_num = meshes.
size();
1987 bke::GeometrySet joined_meshes_set = join_meshes_with_transforms(meshes, transforms);
1988 const Mesh *joined_mesh = joined_meshes_set.get_mesh();
1989 if (joined_mesh ==
nullptr) {
1993 const MeshOffsets mesh_offsets(meshes);
1994 std::vector<Manifold> manifolds(meshes_num);
1995 get_manifolds(manifolds, meshes, transforms, mesh_offsets);
1997 MeshGL meshgl_result;
1999 if (std::any_of(manifolds.
begin(), manifolds.
end(), [](
const Manifold &m) {
2000 return m.Status() != Manifold::Error::NoError;
2005 float origin_offset;
2006 if (meshes_num == 2 && op == Operation::Difference &&
2007 manifolds[0].Status() == Manifold::Error::NoError &&
2008 is_plane(meshes[1], transforms[1], &normal, &origin_offset))
2011 timeit::ScopedTimer timer_trim(
"DOING BOOLEAN SLICE, GETTING MESH_GL RESULT");
2013 meshgl_result = mesh_trim_manifold(
2014 manifolds[0], normal, origin_offset, mesh_offsets, r_error);
2015 if (*r_error != BooleanError::NoError) {
2020 if (std::any_of(manifolds.
begin(), manifolds.
end(), [](
const Manifold &m) {
2021 return m.Status() == Manifold::Error::NotManifold;
2024 *r_error = BooleanError::NonManifold;
2027 *r_error = BooleanError::UnknownError;
2033 manifold::OpType mop = op == Operation::Intersect ?
2034 manifold::OpType::Intersect :
2035 (op == Operation::Union ? manifold::OpType::Add :
2036 manifold::OpType::Subtract);
2038 timeit::ScopedTimer timer_bool(
"DOING BOOLEAN, GETTING MESH_GL RESULT");
2040 Manifold man_result = Manifold::BatchBoolean(manifolds, mop);
2041 meshgl_result = man_result.GetMeshGL();
2043 if (man_result.Status() != Manifold::Error::NoError) {
2044 if (man_result.Status() == Manifold::Error::ResultTooLarge) {
2045 *r_error = BooleanError::ResultTooBig;
2048 *r_error = BooleanError::UnknownError;
2050 if (dbg_level > 0) {
2051 std::cout <<
"manifold boolean returned with error status\n";
2056 if (dbg_level > 0) {
2057 std::cout <<
"boolean result has " << meshgl_result.NumTri() <<
" tris\n";
2058 dump_meshgl(meshgl_result,
"boolean result meshgl");
2063 timeit::ScopedTimer timer_out(
"MESHGL RESULT TO MESH");
2065 mesh_result = meshgl_to_mesh(
2066 meshgl_result, joined_mesh, meshes, material_remaps, mesh_offsets, r_intersecting_edges);
2070 catch (
const std::exception &
e) {
2071 std::cout <<
"mesh_boolean_manifold: exception: " <<
e.what() <<
"\n";
2074 std::cout <<
"mesh_boolean_manifold: unknown exception\n";
2076 *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
static constexpr IndexRange from_begin_end(const int64_t begin, const int64_t end)
constexpr bool contains(int64_t value) 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)