From 1ff08f86146450141cf18af14af884ebcaa68092 Mon Sep 17 00:00:00 2001 From: sentientstardust Date: Wed, 24 Jun 2026 01:21:11 +0100 Subject: [PATCH] Allow top-surface min and max line width to be equal --- src/libslic3r/Fill/Fill.cpp | 11 ++-- src/libslic3r/TextureMapping.cpp | 30 ++++----- src/libslic3r/TextureMapping.hpp | 2 +- src/libslic3r/TextureMappingOffset.cpp | 6 +- src/libslic3r/TextureMappingOffset.hpp | 3 +- src/slic3r/GUI/Plater.cpp | 87 +++++++++++++++++++------- 6 files changed, 92 insertions(+), 47 deletions(-) diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 9c7ed178343..66e35c70bf3 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -6127,7 +6127,8 @@ static std::optional top_surface_image_co top_surface_image_contoning_texture_sample_pitch_mm(plan), raw_top_surface_depth_override, TextureMappingZone::DefaultFilamentOverhangContrastPct, - TextureMappingRawSurfaceUsage::Flat); + TextureMappingRawSurfaceUsage::Flat, + true); if (!offset_context) return std::nullopt; @@ -9301,12 +9302,12 @@ static std::vector top_surface_image_region_plans( top_surface_image_components_bottom_to_top(*zone, print_config, components)); if (plan.components_bottom_to_top.empty()) continue; - plan.max_width_mm = std::clamp(zone->top_surface_image_max_line_width_mm, - TextureMappingZone::MinTopSurfaceImageLineWidthMm, - TextureMappingZone::MaxTopSurfaceImageLineWidthMm); plan.min_width_mm = std::clamp(zone->top_surface_image_min_line_width_mm, TextureMappingZone::MinTopSurfaceImageLineWidthMm, - plan.max_width_mm); + TextureMappingZone::MaxTopSurfaceImageLineWidthMm); + plan.max_width_mm = std::clamp(zone->top_surface_image_max_line_width_mm, + plan.min_width_mm, + TextureMappingZone::MaxTopSurfaceImageLineWidthMm); plan.fixed_coloring = zone->top_surface_image_fixed_coloring_filaments_active(); plan.color_upper_surfaces = zone->top_surface_contoning_colors_upper_surfaces(); plan.color_lower_surfaces = zone->top_surface_contoning_colors_lower_surfaces(); diff --git a/src/libslic3r/TextureMapping.cpp b/src/libslic3r/TextureMapping.cpp index dab3709e6f6..64a1ca609fc 100644 --- a/src/libslic3r/TextureMapping.cpp +++ b/src/libslic3r/TextureMapping.cpp @@ -2835,16 +2835,18 @@ std::string TextureMappingManager::serialize_entries() texture["top_surface_image_printing_enabled"] = zone.top_surface_image_printing_enabled; texture["top_surface_image_printing_method"] = top_surface_image_printing_method_name(zone.top_surface_image_printing_method); - const float top_surface_max_width = - std::clamp(finite_or(zone.top_surface_image_max_line_width_mm, - TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm), - TextureMappingZone::MinTopSurfaceImageLineWidthMm, - TextureMappingZone::MaxTopSurfaceImageLineWidthMm); - texture["top_surface_image_min_line_width_mm"] = + const float top_surface_min_width = std::clamp(finite_or(zone.top_surface_image_min_line_width_mm, TextureMappingZone::DefaultTopSurfaceImageMinLineWidthMm), TextureMappingZone::MinTopSurfaceImageLineWidthMm, - top_surface_max_width); + TextureMappingZone::MaxTopSurfaceImageLineWidthMm); + const float top_surface_max_width = + std::clamp(finite_or(zone.top_surface_image_max_line_width_mm, + TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm), + top_surface_min_width, + TextureMappingZone::MaxTopSurfaceImageLineWidthMm); + texture["top_surface_image_min_line_width_mm"] = + top_surface_min_width; texture["top_surface_image_max_line_width_mm"] = top_surface_max_width; texture["top_surface_image_colored_top_layers"] = clamp_int(zone.top_surface_image_colored_top_layers, @@ -3150,18 +3152,18 @@ void TextureMappingManager::load_entries(const std::string &serialized, top_surface_image_printing_method_from_name( texture.value("top_surface_image_printing_method", top_surface_image_printing_method_name(TextureMappingZone::DefaultTopSurfaceImagePrintingMethod))); - zone.top_surface_image_max_line_width_mm = - std::clamp(finite_or(texture.value("top_surface_image_max_line_width_mm", - TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm), - TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm), - TextureMappingZone::MinTopSurfaceImageLineWidthMm, - TextureMappingZone::MaxTopSurfaceImageLineWidthMm); zone.top_surface_image_min_line_width_mm = std::clamp(finite_or(texture.value("top_surface_image_min_line_width_mm", TextureMappingZone::DefaultTopSurfaceImageMinLineWidthMm), TextureMappingZone::DefaultTopSurfaceImageMinLineWidthMm), TextureMappingZone::MinTopSurfaceImageLineWidthMm, - zone.top_surface_image_max_line_width_mm); + TextureMappingZone::MaxTopSurfaceImageLineWidthMm); + zone.top_surface_image_max_line_width_mm = + std::clamp(finite_or(texture.value("top_surface_image_max_line_width_mm", + TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm), + TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm), + zone.top_surface_image_min_line_width_mm, + TextureMappingZone::MaxTopSurfaceImageLineWidthMm); zone.top_surface_image_colored_top_layers = clamp_int(texture.value("top_surface_image_colored_top_layers", TextureMappingZone::DefaultTopSurfaceImageColoredTopLayers), diff --git a/src/libslic3r/TextureMapping.hpp b/src/libslic3r/TextureMapping.hpp index d2273067206..10e35aca1f9 100644 --- a/src/libslic3r/TextureMapping.hpp +++ b/src/libslic3r/TextureMapping.hpp @@ -202,7 +202,7 @@ struct TextureMappingZone static constexpr bool DefaultTopVisiblePerimeterRecolorPointSampling = true; static constexpr bool DefaultTopSurfaceImagePrintingEnabled = false; static constexpr int DefaultTopSurfaceImagePrintingMethod = int(TopSurfaceImageContoning); - static constexpr float MinTopSurfaceImageLineWidthMm = 0.32f; + static constexpr float MinTopSurfaceImageLineWidthMm = 0.05f; static constexpr float MaxTopSurfaceImageLineWidthMm = 0.80f; static constexpr float DefaultTopSurfaceImageMinLineWidthMm = 0.32f; static constexpr float DefaultTopSurfaceImageMaxLineWidthMm = 0.64f; diff --git a/src/libslic3r/TextureMappingOffset.cpp b/src/libslic3r/TextureMappingOffset.cpp index 1db528435ba..9a284117ced 100644 --- a/src/libslic3r/TextureMappingOffset.cpp +++ b/src/libslic3r/TextureMappingOffset.cpp @@ -3476,7 +3476,8 @@ std::optional build_texture_mapping_offset_context_ std::optional texture_sample_pitch_mm_override, std::optional raw_top_surface_depth_override, std::optional filament_overhang_contrast_pct_override, - TextureMappingRawSurfaceUsage raw_surface_usage) + TextureMappingRawSurfaceUsage raw_surface_usage, + bool allow_zero_width_delta_for_sampling) { const Print *print = print_object.print(); if (print == nullptr) @@ -3637,7 +3638,8 @@ std::optional build_texture_mapping_offset_context_ const float max_width_delta_mm = std::max(0.f, base_outer_width_mm - safe_min_gradient_width_mm); const float effective_max_width_delta_mm = max_width_delta_mm * global_strength_factor; const float max_width_delta_limit_mm = std::min(effective_max_width_delta_mm, 2.f * max_allowed_distance_mm); - if (!std::isfinite(max_width_delta_limit_mm) || max_width_delta_limit_mm <= EPSILON) + if (!std::isfinite(max_width_delta_limit_mm) || + (max_width_delta_limit_mm <= EPSILON && !allow_zero_width_delta_for_sampling)) return std::nullopt; const bool dithering_enabled = zone.dithering_enabled && !raw_texture_mapping_mode; diff --git a/src/libslic3r/TextureMappingOffset.hpp b/src/libslic3r/TextureMappingOffset.hpp index 86997613df8..b234c8fd817 100644 --- a/src/libslic3r/TextureMappingOffset.hpp +++ b/src/libslic3r/TextureMappingOffset.hpp @@ -128,7 +128,8 @@ std::optional build_texture_mapping_offset_context_ std::optional texture_sample_pitch_mm_override = std::nullopt, std::optional raw_top_surface_depth_override = std::nullopt, std::optional filament_overhang_contrast_pct_override = std::nullopt, - TextureMappingRawSurfaceUsage raw_surface_usage = TextureMappingRawSurfaceUsage::Side); + TextureMappingRawSurfaceUsage raw_surface_usage = TextureMappingRawSurfaceUsage::Side, + bool allow_zero_width_delta_for_sampling = false); std::vector sample_weight_field_components(const TextureMappingOffsetWeightField &weight_field, float x_mm, diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index cb2c9a7cbb2..9279ba108e5 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3140,6 +3140,14 @@ public: 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap); + const double initial_top_surface_min_line_width_mm = + std::clamp(double(top_surface_image_min_line_width_mm), + double(TextureMappingZone::MinTopSurfaceImageLineWidthMm), + double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm)); + const double initial_top_surface_max_line_width_mm = + std::clamp(double(top_surface_image_max_line_width_mm), + initial_top_surface_min_line_width_mm, + double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm)); m_top_surface_image_min_line_width_spin = new wxSpinCtrlDouble(top_surface_page, wxID_ANY, @@ -3148,10 +3156,8 @@ public: wxSize(FromDIP(84), -1), wxSP_ARROW_KEYS | wxALIGN_RIGHT | wxTE_PROCESS_ENTER, double(TextureMappingZone::MinTopSurfaceImageLineWidthMm), - double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm), - std::clamp(double(top_surface_image_min_line_width_mm), - double(TextureMappingZone::MinTopSurfaceImageLineWidthMm), - double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm)), + initial_top_surface_max_line_width_mm, + initial_top_surface_min_line_width_mm, 0.01); m_top_surface_image_min_line_width_spin->SetDigits(2); top_surface_width_row->Add(m_top_surface_image_min_line_width_spin, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap / 2); @@ -3166,11 +3172,9 @@ public: wxDefaultPosition, wxSize(FromDIP(84), -1), wxSP_ARROW_KEYS | wxALIGN_RIGHT | wxTE_PROCESS_ENTER, - double(TextureMappingZone::MinTopSurfaceImageLineWidthMm), + initial_top_surface_min_line_width_mm, double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm), - std::clamp(double(top_surface_image_max_line_width_mm), - double(TextureMappingZone::MinTopSurfaceImageLineWidthMm), - double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm)), + initial_top_surface_max_line_width_mm, 0.01); m_top_surface_image_max_line_width_spin->SetDigits(2); top_surface_width_row->Add(m_top_surface_image_max_line_width_spin, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap / 2); @@ -3715,6 +3719,22 @@ public: update_top_surface_image_options_visibility(true); }); } + if (m_top_surface_image_min_line_width_spin != nullptr) { + m_top_surface_image_min_line_width_spin->Bind(wxEVT_SPINCTRLDOUBLE, [this](wxSpinDoubleEvent &) { + enforce_top_surface_image_line_width_order(m_top_surface_image_min_line_width_spin); + }); + m_top_surface_image_min_line_width_spin->Bind(wxEVT_TEXT, [this](wxCommandEvent &) { + enforce_top_surface_image_line_width_order(m_top_surface_image_min_line_width_spin); + }); + } + if (m_top_surface_image_max_line_width_spin != nullptr) { + m_top_surface_image_max_line_width_spin->Bind(wxEVT_SPINCTRLDOUBLE, [this](wxSpinDoubleEvent &) { + enforce_top_surface_image_line_width_order(m_top_surface_image_max_line_width_spin); + }); + m_top_surface_image_max_line_width_spin->Bind(wxEVT_TEXT, [this](wxCommandEvent &) { + enforce_top_surface_image_line_width_order(m_top_surface_image_max_line_width_spin); + }); + } m_top_surface_image_printing_enabled_checkbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &) { update_top_surface_image_options_visibility(true); }); @@ -4013,25 +4033,25 @@ public: } float top_surface_image_min_line_width_mm() const { - const double max_width = m_top_surface_image_max_line_width_spin != nullptr ? - m_top_surface_image_max_line_width_spin->GetValue() : - double(TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm); const double value = m_top_surface_image_min_line_width_spin != nullptr ? m_top_surface_image_min_line_width_spin->GetValue() : double(TextureMappingZone::DefaultTopSurfaceImageMinLineWidthMm); return float(std::clamp(value, double(TextureMappingZone::MinTopSurfaceImageLineWidthMm), - std::clamp(max_width, - double(TextureMappingZone::MinTopSurfaceImageLineWidthMm), - double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm)))); + double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm))); } float top_surface_image_max_line_width_mm() const { + const double min_width = m_top_surface_image_min_line_width_spin != nullptr ? + m_top_surface_image_min_line_width_spin->GetValue() : + double(TextureMappingZone::DefaultTopSurfaceImageMinLineWidthMm); const double value = m_top_surface_image_max_line_width_spin != nullptr ? m_top_surface_image_max_line_width_spin->GetValue() : double(TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm); return float(std::clamp(value, - double(TextureMappingZone::MinTopSurfaceImageLineWidthMm), + std::clamp(min_width, + double(TextureMappingZone::MinTopSurfaceImageLineWidthMm), + double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm)), double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm))); } int top_surface_image_colored_top_layers() const @@ -5557,16 +5577,12 @@ private: if (m_top_surface_contoning_polygonize_resolution_choice == nullptr) return; + const int effective_flat_mode = TextureMappingZone::effective_top_surface_contoning_flat_surface_infill_mode( + top_surface_contoning_flat_surface_infill_mode()); const bool allow_x8 = TextureMappingZone::ShowExperimentalTopSurfaceContoningOptions || - TextureMappingZone::effective_top_surface_contoning_flat_surface_infill_mode( - top_surface_contoning_flat_surface_infill_mode()) == - int(TextureMappingZone::ContoningFlatSurfaceInfillBoundarySkinVariable) || - TextureMappingZone::effective_top_surface_contoning_flat_surface_infill_mode( - top_surface_contoning_flat_surface_infill_mode()) == - int(TextureMappingZone::ContoningFlatSurfaceInfillBoundarySkinVariableOverlap) || - TextureMappingZone::effective_top_surface_contoning_flat_surface_infill_mode( - top_surface_contoning_flat_surface_infill_mode()) == - int(TextureMappingZone::ContoningFlatSurfaceInfillAdaptiveLines); + (effective_flat_mode != int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinear) && + effective_flat_mode != int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinearWithBoundary) && + effective_flat_mode != int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinearWithRepair)); int resolution = TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution(preferred_resolution); if (!allow_x8 && resolution == 8) resolution = 4; @@ -5596,6 +5612,29 @@ private: m_top_surface_contoning_polygonize_resolution_choice->SetSelection(selection); } + void enforce_top_surface_image_line_width_order(wxSpinCtrlDouble *changed_spin) + { + if (m_top_surface_image_min_line_width_spin == nullptr || + m_top_surface_image_max_line_width_spin == nullptr) + return; + + const double lower = double(TextureMappingZone::MinTopSurfaceImageLineWidthMm); + const double upper = double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm); + double min_width = std::clamp(m_top_surface_image_min_line_width_spin->GetValue(), lower, upper); + double max_width = std::clamp(m_top_surface_image_max_line_width_spin->GetValue(), lower, upper); + if (changed_spin == m_top_surface_image_max_line_width_spin) + max_width = std::max(max_width, min_width); + else + min_width = std::min(min_width, max_width); + + m_top_surface_image_min_line_width_spin->SetRange(lower, max_width); + m_top_surface_image_max_line_width_spin->SetRange(min_width, upper); + if (m_top_surface_image_min_line_width_spin->GetValue() != min_width) + m_top_surface_image_min_line_width_spin->SetValue(min_width); + if (m_top_surface_image_max_line_width_spin->GetValue() != max_width) + m_top_surface_image_max_line_width_spin->SetValue(max_width); + } + void update_top_surface_image_options_visibility(bool fit_dialog) { const bool enabled =