1010#include " MTUtils.hpp"
1111#include " TriangleMeshSlicer.hpp"
1212#include " TriangleSelector.hpp"
13+ #include " AABBTreeIndirect.hpp"
14+ #include < queue>
1315
1416#include " Format/AMF.hpp"
1517#include " Format/svg.hpp"
@@ -2786,9 +2788,21 @@ ModelObjectPtrs ModelObject::merge_volumes(std::vector<int>& vol_indeces)
27862788
27872789#if 1
27882790 TriangleMesh mesh;
2791+ // BBS: preserve painting across the merge. its_merge() appends faces in
2792+ // order (only vertex indices are offset), so face f of the merged mesh maps
2793+ // exactly to the captured per-part triangles below. Capture before
2794+ // reset_mesh() empties the source volumes.
2795+ std::vector<std::string> merged_supported, merged_seam, merged_mmu, merged_fuzzy;
27892796 for (int i : vol_indeces) {
27902797 auto volume = volumes[i];
27912798 if (!volume->mesh ().empty ()) {
2799+ const size_t nf = volume->mesh ().its .indices .size ();
2800+ for (size_t f = 0 ; f < nf; ++f) {
2801+ merged_supported.emplace_back (volume->supported_facets .get_triangle_as_string ((int )f));
2802+ merged_seam.emplace_back (volume->seam_facets .get_triangle_as_string ((int )f));
2803+ merged_mmu.emplace_back (volume->mmu_segmentation_facets .get_triangle_as_string ((int )f));
2804+ merged_fuzzy.emplace_back (volume->fuzzy_skin_facets .get_triangle_as_string ((int )f));
2805+ }
27922806 const auto volume_matrix = volume->get_matrix ();
27932807 TriangleMesh mesh_ (volume->mesh ());
27942808 mesh_.transform (volume_matrix, true );
@@ -2808,6 +2822,13 @@ ModelObjectPtrs ModelObject::merge_volumes(std::vector<int>& vol_indeces)
28082822 #endif
28092823
28102824 ModelVolume* vol = upper->add_volume (mesh);
2825+ // BBS: re-apply the painting captured above onto the merged volume.
2826+ for (size_t f = 0 ; f < merged_mmu.size () && f < mesh.its .indices .size (); ++f) {
2827+ if (!merged_supported[f].empty ()) vol->supported_facets .set_triangle_from_string ((int )f, merged_supported[f]);
2828+ if (!merged_seam[f].empty ()) vol->seam_facets .set_triangle_from_string ((int )f, merged_seam[f]);
2829+ if (!merged_mmu[f].empty ()) vol->mmu_segmentation_facets .set_triangle_from_string ((int )f, merged_mmu[f]);
2830+ if (!merged_fuzzy[f].empty ()) vol->fuzzy_skin_facets .set_triangle_from_string ((int )f, merged_fuzzy[f]);
2831+ }
28112832 for (int i = 0 ; i < volumes.size ();i++) {
28122833 if (std::find (vol_indeces.begin (), vol_indeces.end (), i) != vol_indeces.end ()) {
28132834 vol->name = " Merged Parts" ;
@@ -3148,6 +3169,106 @@ void ModelVolume::reset_extra_facets() {
31483169 this ->mmu_segmentation_facets .reset ();
31493170}
31503171
3172+ // ---- BBS: best-effort paint re-projection across mesh-rebuilding ops ----------
3173+ // Walk a TriangleSelector's split tree for source face s; return the first
3174+ // non-NONE leaf state (collapses sub-triangle painting to the dominant intent).
3175+ static EnforcerBlockerType reproj_first_leaf (TriangleSelector &sel, int root_idx)
3176+ {
3177+ const auto &tris = sel.get_triangles ();
3178+ if (root_idx < 0 || root_idx >= (int )tris.size ()) return EnforcerBlockerType::NONE ;
3179+ std::queue<int > q;
3180+ q.push (root_idx);
3181+ while (!q.empty ()) {
3182+ int i = q.front (); q.pop ();
3183+ const auto &t = tris[i];
3184+ if (!t.valid ()) continue ;
3185+ if (!t.is_split ()) {
3186+ if (t.get_state () != EnforcerBlockerType::NONE )
3187+ return t.get_state ();
3188+ } else {
3189+ for (int c : t.children ) if (c >= 0 ) q.push (c);
3190+ }
3191+ }
3192+ return EnforcerBlockerType::NONE ;
3193+ }
3194+
3195+ // Per-face dominant state of one annotation layer over `mesh`.
3196+ static void reproj_per_face_states (const TriangleMesh &mesh, const FacetsAnnotation &ann,
3197+ std::vector<EnforcerBlockerType> &out)
3198+ {
3199+ out.assign (mesh.its .indices .size (), EnforcerBlockerType::NONE );
3200+ if (ann.empty () || mesh.its .indices .empty ()) return ;
3201+ TriangleSelector sel (mesh);
3202+ sel.deserialize (ann.get_data (), true );
3203+ for (int f = 0 ; f < (int )mesh.its .indices .size (); ++f)
3204+ out[f] = reproj_first_leaf (sel, f);
3205+ }
3206+
3207+ // Write per-face states onto `mesh`'s annotation layer (NONE entries skipped).
3208+ static void reproj_apply_states (const TriangleMesh &mesh,
3209+ const std::vector<EnforcerBlockerType> &states,
3210+ FacetsAnnotation &out)
3211+ {
3212+ out.reset ();
3213+ bool any = false ;
3214+ TriangleSelector sel (mesh);
3215+ const int n = std::min<int >((int )states.size (), (int )mesh.its .indices .size ());
3216+ for (int f = 0 ; f < n; ++f) {
3217+ if (states[f] != EnforcerBlockerType::NONE ) { sel.set_facet (f, states[f]); any = true ; }
3218+ }
3219+ if (any) out.set (sel);
3220+ }
3221+
3222+ // Map each face of new_mesh to the nearest face of old_mesh (by centroid), then
3223+ // transfer the four precomputed old per-face state vectors onto new annotations.
3224+ static void reproj_transfer (const TriangleMesh &old_mesh, const TriangleMesh &new_mesh,
3225+ const std::vector<EnforcerBlockerType> &o_sup,
3226+ const std::vector<EnforcerBlockerType> &o_seam,
3227+ const std::vector<EnforcerBlockerType> &o_mmu,
3228+ const std::vector<EnforcerBlockerType> &o_fuzzy,
3229+ FacetsAnnotation &d_sup, FacetsAnnotation &d_seam,
3230+ FacetsAnnotation &d_mmu, FacetsAnnotation &d_fuzzy)
3231+ {
3232+ d_sup.reset (); d_seam.reset (); d_mmu.reset (); d_fuzzy.reset ();
3233+ if (old_mesh.its .indices .empty () || new_mesh.its .indices .empty ()) return ;
3234+ auto tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set (
3235+ old_mesh.its .vertices , old_mesh.its .indices );
3236+ const int nf = (int )new_mesh.its .indices .size ();
3237+ std::vector<EnforcerBlockerType> n_sup (nf, EnforcerBlockerType::NONE ), n_seam = n_sup, n_mmu = n_sup, n_fuzzy = n_sup;
3238+ for (int f = 0 ; f < nf; ++f) {
3239+ const Vec3i &idx = new_mesh.its .indices [f];
3240+ Vec3f c = (new_mesh.its .vertices [idx[0 ]] + new_mesh.its .vertices [idx[1 ]] + new_mesh.its .vertices [idx[2 ]]) / 3 .f ;
3241+ size_t hit = size_t (-1 );
3242+ Vec3f hp;
3243+ double d2 = AABBTreeIndirect::squared_distance_to_indexed_triangle_set (
3244+ old_mesh.its .vertices , old_mesh.its .indices , tree, c, hit, hp);
3245+ if (d2 < 0 . || hit == size_t (-1 ) || hit >= o_sup.size ()) continue ;
3246+ n_sup[f] = o_sup[hit];
3247+ n_seam[f] = o_seam[hit];
3248+ n_mmu[f] = o_mmu[hit];
3249+ n_fuzzy[f] = o_fuzzy[hit];
3250+ }
3251+ reproj_apply_states (new_mesh, n_sup, d_sup);
3252+ reproj_apply_states (new_mesh, n_seam, d_seam);
3253+ reproj_apply_states (new_mesh, n_mmu, d_mmu);
3254+ reproj_apply_states (new_mesh, n_fuzzy, d_fuzzy);
3255+ }
3256+
3257+ void ModelVolume::set_mesh_keep_paint (TriangleMesh &&mesh_in)
3258+ {
3259+ const TriangleMesh old_mesh = this ->mesh (); // copy before replacing
3260+ std::vector<EnforcerBlockerType> o_sup, o_seam, o_mmu, o_fuzzy;
3261+ reproj_per_face_states (old_mesh, this ->supported_facets , o_sup);
3262+ reproj_per_face_states (old_mesh, this ->seam_facets , o_seam);
3263+ reproj_per_face_states (old_mesh, this ->mmu_segmentation_facets , o_mmu);
3264+ reproj_per_face_states (old_mesh, this ->fuzzy_skin_facets , o_fuzzy);
3265+ this ->set_mesh (std::move (mesh_in));
3266+ reproj_transfer (old_mesh, this ->mesh (), o_sup, o_seam, o_mmu, o_fuzzy,
3267+ this ->supported_facets , this ->seam_facets ,
3268+ this ->mmu_segmentation_facets , this ->fuzzy_skin_facets );
3269+ }
3270+ // ------------------------------------------------------------------------------
3271+
31513272ModelMaterial* ModelVolume::material () const
31523273{
31533274 return this ->object ->get_model ()->get_material (m_material_id);
@@ -3523,10 +3644,19 @@ size_t ModelVolume::split(unsigned int max_extruders, float scale_det)
35233644 const bool src_assemble_initialized = this ->is_assemble_initialized ();
35243645 const Transform3d src_assemble_matrix = this ->get_assemble_transformation ().get_matrix ();
35253646 std::vector<std::string> tris_split_strs;
3647+ // BBS: also carry support/seam/fuzzy-skin painting across the split (the
3648+ // ships[] relationship maps each split face back to its source face).
3649+ std::vector<std::string> tris_sup_strs, tris_seam_strs, tris_fuzzy_strs;
35263650 auto face_count = m_mesh->its .indices .size ();
35273651 tris_split_strs.reserve (face_count);
3652+ tris_sup_strs.reserve (face_count);
3653+ tris_seam_strs.reserve (face_count);
3654+ tris_fuzzy_strs.reserve (face_count);
35283655 for (size_t i = 0 ; i < face_count; i++) {
35293656 tris_split_strs.emplace_back (mmu_segmentation_facets.get_triangle_as_string (i));
3657+ tris_sup_strs.emplace_back (supported_facets.get_triangle_as_string (i));
3658+ tris_seam_strs.emplace_back (seam_facets.get_triangle_as_string (i));
3659+ tris_fuzzy_strs.emplace_back (fuzzy_skin_facets.get_triangle_as_string (i));
35303660 }
35313661 int last_all_mesh_face_count = 0 ;
35323662 for (TriangleMesh &mesh : meshes) {
@@ -3552,9 +3682,14 @@ size_t ModelVolume::split(unsigned int max_extruders, float scale_det)
35523682 for (size_t i = 0 ; i < cur_face_count; i++) {
35533683 if (ships[idx].find (i) != ships[idx].end ()) {
35543684 auto index = ships[idx][i];
3555- if (tris_split_strs[index].size () > 0 ) {
3685+ if (tris_split_strs[index].size () > 0 )
35563686 mmu_segmentation_facets.set_triangle_from_string (i, tris_split_strs[index]);
3557- }
3687+ if (tris_sup_strs[index].size () > 0 )
3688+ supported_facets.set_triangle_from_string (i, tris_sup_strs[index]);
3689+ if (tris_seam_strs[index].size () > 0 )
3690+ seam_facets.set_triangle_from_string (i, tris_seam_strs[index]);
3691+ if (tris_fuzzy_strs[index].size () > 0 )
3692+ fuzzy_skin_facets.set_triangle_from_string (i, tris_fuzzy_strs[index]);
35583693 }
35593694 }
35603695 } else {
@@ -3563,9 +3698,14 @@ size_t ModelVolume::split(unsigned int max_extruders, float scale_det)
35633698 for (size_t i = 0 ; i < new_mv->mesh_ptr ()->its .indices .size (); i++) {
35643699 if (ships[idx].find (i) != ships[idx].end ()) {
35653700 auto index = ships[idx][i];
3566- if (tris_split_strs[index].size () > 0 ) {
3701+ if (tris_split_strs[index].size () > 0 )
35673702 new_mv->mmu_segmentation_facets .set_triangle_from_string (i, tris_split_strs[index]);
3568- }
3703+ if (tris_sup_strs[index].size () > 0 )
3704+ new_mv->supported_facets .set_triangle_from_string (i, tris_sup_strs[index]);
3705+ if (tris_seam_strs[index].size () > 0 )
3706+ new_mv->seam_facets .set_triangle_from_string (i, tris_seam_strs[index]);
3707+ if (tris_fuzzy_strs[index].size () > 0 )
3708+ new_mv->fuzzy_skin_facets .set_triangle_from_string (i, tris_fuzzy_strs[index]);
35693709 }
35703710 }
35713711 }
0 commit comments