Don't remap paint unless it's the final cut

This commit is contained in:
Noisyfox
2026-05-05 17:08:53 +08:00
parent 4b489339c6
commit 01e0013b16
4 changed files with 27 additions and 26 deletions

View File

@@ -14,9 +14,9 @@ namespace Slic3r {
using namespace Geometry;
// Saved painting data for remapping after mesh cutting.
// Saved painting data for remapping after mesh change.
struct SavedPainting {
indexed_triangle_set its; // Original mesh transformed to cut space
indexed_triangle_set its; // Original mesh
TriangleSelector::TriangleSplittingData supported;
TriangleSelector::TriangleSplittingData seam;
TriangleSelector::TriangleSplittingData mmu;
@@ -24,21 +24,24 @@ struct SavedPainting {
};
// Remap painting data from saved source to a cut result mesh, and set on a volume.
static void remap_and_set_painting(ModelVolume* vol, const indexed_triangle_set& cut_its,
const SavedPainting& saved)
static void remap_and_set_painting(ModelVolume* vol, const SavedPainting* saved)
{
if (!saved) {
return;
}
auto remap_one = [&](const TriangleSelector::TriangleSplittingData& src_data,
FacetsAnnotation& target_facets) {
if (src_data.bitstream.empty())
return;
auto result = TriangleSelector::remap_painting(saved.its, src_data, cut_its);
auto result = TriangleSelector::remap_painting(saved->its, src_data, vol->mesh().its);
if (!result.bitstream.empty())
target_facets.set_data(result);
};
remap_one(saved.supported, vol->supported_facets);
remap_one(saved.seam, vol->seam_facets);
remap_one(saved.mmu, vol->mmu_segmentation_facets);
remap_one(saved.fuzzy, vol->fuzzy_skin_facets);
remap_one(saved->supported, vol->supported_facets);
remap_one(saved->seam, vol->seam_facets);
remap_one(saved->mmu, vol->mmu_segmentation_facets);
remap_one(saved->fuzzy, vol->fuzzy_skin_facets);
}
static void apply_tolerance(ModelVolume* vol)
@@ -217,28 +220,26 @@ static void process_solid_part_cut(ModelVolume* volume, const Transform3d& insta
// Add required cut parts to the objects
if (attributes.has(ModelObjectCutAttribute::KeepAsParts)) {
add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A");
if (saved_painting && !upper_mesh.empty())
remap_and_set_painting(upper->volumes.back(), upper_mesh.its, *saved_painting);
if (!upper_mesh.empty()) {
add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A");
remap_and_set_painting(upper->volumes.back(), saved_painting);
}
if (!lower_mesh.empty()) {
add_cut_volume(lower_mesh, upper, volume, cut_matrix, "_B");
if (saved_painting)
remap_and_set_painting(upper->volumes.back(), lower_mesh.its, *saved_painting);
upper->volumes.back()->cut_info.is_from_upper = false;
remap_and_set_painting(upper->volumes.back(), saved_painting);
}
return;
}
if (attributes.has(ModelObjectCutAttribute::KeepUpper)) {
if (attributes.has(ModelObjectCutAttribute::KeepUpper) && !upper_mesh.empty()) {
add_cut_volume(upper_mesh, upper, volume, cut_matrix);
if (saved_painting && !upper_mesh.empty())
remap_and_set_painting(upper->volumes.back(), upper_mesh.its, *saved_painting);
remap_and_set_painting(upper->volumes.back(), saved_painting);
}
if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty()) {
add_cut_volume(lower_mesh, lower, volume, cut_matrix);
if (saved_painting)
remap_and_set_painting(lower->volumes.back(), lower_mesh.its, *saved_painting);
remap_and_set_painting(lower->volumes.back(), saved_painting);
}
}
@@ -363,21 +364,19 @@ const ModelObjectPtrs& Cut::perform_with_plane()
// Save painting data before reset_extra_facets() discards it.
// Only for model parts that will be cut (not modifiers/connectors).
std::optional<SavedPainting> saved_painting;
if (volume->is_model_part() && !volume->mesh().empty()) {
SavedPainting sp;
if (m_attributes.has(ModelObjectCutAttribute::KeepPaint) && volume->is_any_painted() && volume->is_model_part() && !volume->mesh().empty()) {
// Get mesh in cut space (same transform as process_volume_cut applies)
TriangleMesh mesh(volume->mesh());
const auto volume_matrix = volume->get_matrix();
mesh.transform(inverse_cut_matrix * instance_matrix * volume_matrix, true);
mesh.transform(m_cut_matrix);
SavedPainting sp;
sp.its = std::move(mesh.its);
sp.supported = volume->supported_facets.get_data();
sp.seam = volume->seam_facets.get_data();
sp.mmu = volume->mmu_segmentation_facets.get_data();
sp.fuzzy = volume->fuzzy_skin_facets.get_data();
if (!sp.supported.bitstream.empty() || !sp.seam.bitstream.empty() ||
!sp.mmu.bitstream.empty() || !sp.fuzzy.bitstream.empty())
saved_painting = std::move(sp);
saved_painting = std::move(sp);
}
volume->reset_extra_facets();

View File

@@ -11,7 +11,7 @@ namespace Slic3r {
using ModelObjectPtrs = std::vector<ModelObject*>;
enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, KeepAsParts, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels, InvalidateCutInfo };
enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, KeepAsParts, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels, InvalidateCutInfo, KeepPaint };
using ModelObjectCutAttributes = enum_bitmask<ModelObjectCutAttribute>;
ENABLE_ENUM_BITMASK_OPERATORS(ModelObjectCutAttribute);

View File

@@ -1005,6 +1005,7 @@ public:
bool is_seam_painted() const { return !this->seam_facets.empty(); }
bool is_mm_painted() const { return !this->mmu_segmentation_facets.empty(); }
bool is_fuzzy_skin_painted() const { return !this->fuzzy_skin_facets.empty(); }
bool is_any_painted() const { return is_fdm_support_painted() || is_seam_painted() || is_mm_painted() || is_fuzzy_skin_painted(); }
// Orca: Implement prusa's filament shrink compensation approach
// Returns 0-based indices of extruders painted by multi-material painting gizmo.

View File

@@ -3329,7 +3329,8 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
only_if(m_rotate_upper, ModelObjectCutAttribute::FlipUpper) |
only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower) |
only_if(dowels_count > 0, ModelObjectCutAttribute::CreateDowels) |
only_if(!has_connectors && !cut_with_groove && cut_mo->cut_id.id().invalid(), ModelObjectCutAttribute::InvalidateCutInfo);
only_if(!has_connectors && !cut_with_groove && cut_mo->cut_id.id().invalid(), ModelObjectCutAttribute::InvalidateCutInfo) |
ModelObjectCutAttribute::KeepPaint;
// update cut_id for the cut object in respect to the attributes
update_object_cut_id(cut_mo->cut_id, attributes, dowels_count);