Working on top layer line recoloring for v2 perimeter path modulation

This commit is contained in:
sentientstardust
2026-05-23 08:11:46 +01:00
parent 06f3511b2d
commit 054ae4f903
5 changed files with 928 additions and 177 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -400,13 +400,45 @@ static std::vector<const MMU_Graph::Arc *> get_next_arc(
return sorted_arcs.front().first;
}
static bool is_profile_self_interaction(Polygon poly)
static bool is_profile_self_interaction(const Polygon &poly)
{
auto lines = poly.lines();
struct LineBounds {
coord_t min_x;
coord_t max_x;
coord_t min_y;
coord_t max_y;
};
std::vector<LineBounds> bounds;
bounds.reserve(lines.size());
for (const Line &line : lines) {
bounds.push_back({std::min(line.a.x(), line.b.x()),
std::max(line.a.x(), line.b.x()),
std::min(line.a.y(), line.b.y()),
std::max(line.a.y(), line.b.y())});
}
auto bounds_overlap = [](const LineBounds &lhs, const LineBounds &rhs) {
return lhs.min_x <= rhs.max_x && rhs.min_x <= lhs.max_x &&
lhs.min_y <= rhs.max_y && rhs.min_y <= lhs.max_y;
};
std::vector<size_t> order(lines.size());
for (size_t idx = 0; idx < order.size(); ++idx)
order[idx] = idx;
std::sort(order.begin(), order.end(), [&bounds](size_t lhs, size_t rhs) {
return bounds[lhs].min_x < bounds[rhs].min_x;
});
auto are_adjacent = [&lines](size_t lhs, size_t rhs) {
const size_t diff = lhs > rhs ? lhs - rhs : rhs - lhs;
return diff <= 1 || diff + 1 == lines.size();
};
Point intersection;
for (int i = 0; i < lines.size(); ++i) {
for (int j = i + 2; j < std::min(lines.size(), lines.size() + i - 1); ++j) {
if (lines[i].intersection(lines[j], &intersection)) return true;
for (size_t order_i = 0; order_i < order.size(); ++order_i) {
const size_t i = order[order_i];
for (size_t order_j = order_i + 1; order_j < order.size(); ++order_j) {
const size_t j = order[order_j];
if (bounds[j].min_x > bounds[i].max_x)
break;
if (!are_adjacent(i, j) && bounds_overlap(bounds[i], bounds[j]) && lines[i].intersection(lines[j], &intersection)) return true;
}
}
return false;

View File

@@ -869,6 +869,8 @@ bool TextureMappingZone::operator==(const TextureMappingZone &rhs) const
recolor_small_perimeter_loops == rhs.recolor_small_perimeter_loops &&
recolor_top_visible_perimeter_sections == rhs.recolor_top_visible_perimeter_sections &&
top_visible_perimeter_recolor_aggressiveness == rhs.top_visible_perimeter_recolor_aggressiveness &&
top_visible_perimeter_recolor_above_layers == rhs.top_visible_perimeter_recolor_above_layers &&
top_visible_perimeter_recolor_point_sampling == rhs.top_visible_perimeter_recolor_point_sampling &&
compact_offset_mode == rhs.compact_offset_mode &&
use_legacy_fixed_color_mode == rhs.use_legacy_fixed_color_mode &&
high_speed_image_texture_sampling == rhs.high_speed_image_texture_sampling &&
@@ -1128,6 +1130,11 @@ std::string TextureMappingManager::serialize_entries()
texture["recolor_top_visible_perimeter_sections"] = zone.recolor_top_visible_perimeter_sections;
texture["top_visible_perimeter_recolor_aggressiveness"] =
top_visible_recolor_aggressiveness_name(zone.top_visible_perimeter_recolor_aggressiveness);
texture["top_visible_perimeter_recolor_above_layers"] =
clamp_int(zone.top_visible_perimeter_recolor_above_layers,
TextureMappingZone::MinTopVisiblePerimeterRecolorAboveLayers,
TextureMappingZone::MaxTopVisiblePerimeterRecolorAboveLayers);
texture["top_visible_perimeter_recolor_point_sampling"] = zone.top_visible_perimeter_recolor_point_sampling;
texture["compact_offset_mode"] = zone.compact_offset_mode;
texture["use_legacy_fixed_color_mode"] = zone.use_legacy_fixed_color_mode;
texture["high_speed_image_texture_sampling"] = true;
@@ -1285,6 +1292,14 @@ void TextureMappingManager::load_entries(const std::string &serialized,
top_visible_recolor_aggressiveness_from_name(
texture.value("top_visible_perimeter_recolor_aggressiveness",
top_visible_recolor_aggressiveness_name(TextureMappingZone::DefaultTopVisiblePerimeterRecolorAggressiveness)));
zone.top_visible_perimeter_recolor_above_layers =
clamp_int(texture.value("top_visible_perimeter_recolor_above_layers",
TextureMappingZone::DefaultTopVisiblePerimeterRecolorAboveLayers),
TextureMappingZone::MinTopVisiblePerimeterRecolorAboveLayers,
TextureMappingZone::MaxTopVisiblePerimeterRecolorAboveLayers);
zone.top_visible_perimeter_recolor_point_sampling =
texture.value("top_visible_perimeter_recolor_point_sampling",
TextureMappingZone::DefaultTopVisiblePerimeterRecolorPointSampling);
zone.compact_offset_mode = texture.value("compact_offset_mode", TextureMappingZone::DefaultCompactOffsetMode);
zone.use_legacy_fixed_color_mode =
texture.value("use_legacy_fixed_color_mode", TextureMappingZone::DefaultUseLegacyFixedColorMode);

View File

@@ -119,6 +119,10 @@ struct TextureMappingZone
static constexpr bool DefaultRecolorSmallPerimeterLoops = false;
static constexpr bool DefaultRecolorTopVisiblePerimeterSections = false;
static constexpr int DefaultTopVisiblePerimeterRecolorAggressiveness = int(TopVisibleRecolorAggressive);
static constexpr int MinTopVisiblePerimeterRecolorAboveLayers = 1;
static constexpr int MaxTopVisiblePerimeterRecolorAboveLayers = 5;
static constexpr int DefaultTopVisiblePerimeterRecolorAboveLayers = 2;
static constexpr bool DefaultTopVisiblePerimeterRecolorPointSampling = true;
static constexpr bool DefaultCompactOffsetMode = true;
static constexpr bool DefaultUseLegacyFixedColorMode = false;
static constexpr bool DefaultHighSpeedImageTextureSampling = true;
@@ -176,6 +180,8 @@ struct TextureMappingZone
bool recolor_small_perimeter_loops = DefaultRecolorSmallPerimeterLoops;
bool recolor_top_visible_perimeter_sections = DefaultRecolorTopVisiblePerimeterSections;
int top_visible_perimeter_recolor_aggressiveness = DefaultTopVisiblePerimeterRecolorAggressiveness;
int top_visible_perimeter_recolor_above_layers = DefaultTopVisiblePerimeterRecolorAboveLayers;
bool top_visible_perimeter_recolor_point_sampling = DefaultTopVisiblePerimeterRecolorPointSampling;
bool compact_offset_mode = DefaultCompactOffsetMode;
bool use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode;
bool high_speed_image_texture_sampling = DefaultHighSpeedImageTextureSampling;
@@ -237,6 +243,8 @@ struct TextureMappingZone
recolor_small_perimeter_loops = DefaultRecolorSmallPerimeterLoops;
recolor_top_visible_perimeter_sections = DefaultRecolorTopVisiblePerimeterSections;
top_visible_perimeter_recolor_aggressiveness = DefaultTopVisiblePerimeterRecolorAggressiveness;
top_visible_perimeter_recolor_above_layers = DefaultTopVisiblePerimeterRecolorAboveLayers;
top_visible_perimeter_recolor_point_sampling = DefaultTopVisiblePerimeterRecolorPointSampling;
compact_offset_mode = DefaultCompactOffsetMode;
use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode;
high_speed_image_texture_sampling = DefaultHighSpeedImageTextureSampling;

View File

@@ -1430,6 +1430,8 @@ public:
bool recolor_small_perimeter_loops,
bool recolor_top_visible_perimeter_sections,
int top_visible_perimeter_recolor_aggressiveness,
int top_visible_perimeter_recolor_above_layers,
bool top_visible_perimeter_recolor_point_sampling,
bool compact_offset_mode,
bool use_legacy_fixed_color_mode,
bool minimum_visibility_offset_enabled,
@@ -1737,7 +1739,29 @@ public:
int(TextureMappingZone::TopVisibleRecolorConservative),
int(TextureMappingZone::TopVisibleRecolorAggressive)));
top_visible_recolor_row->Add(m_top_visible_perimeter_recolor_aggressiveness_choice, 1, wxALIGN_CENTER_VERTICAL);
print_settings_box->Add(top_visible_recolor_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP | wxBOTTOM, gap);
print_settings_box->Add(top_visible_recolor_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
auto *top_visible_recolor_layers_row = new wxBoxSizer(wxHORIZONTAL);
m_top_visible_perimeter_recolor_above_layers_label =
new wxStaticText(print_settings_page, wxID_ANY, _L("Visible layer lookahead:"));
top_visible_recolor_layers_row->Add(m_top_visible_perimeter_recolor_above_layers_label,
0,
wxALIGN_CENTER_VERTICAL | wxRIGHT,
gap);
m_top_visible_perimeter_recolor_above_layers_spin =
new wxSpinCtrl(print_settings_page,
wxID_ANY,
wxEmptyString,
wxDefaultPosition,
wxSize(FromDIP(70), -1),
wxSP_ARROW_KEYS | wxALIGN_RIGHT,
TextureMappingZone::MinTopVisiblePerimeterRecolorAboveLayers,
TextureMappingZone::MaxTopVisiblePerimeterRecolorAboveLayers,
std::clamp(top_visible_perimeter_recolor_above_layers,
TextureMappingZone::MinTopVisiblePerimeterRecolorAboveLayers,
TextureMappingZone::MaxTopVisiblePerimeterRecolorAboveLayers));
top_visible_recolor_layers_row->Add(m_top_visible_perimeter_recolor_above_layers_spin, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap / 2);
top_visible_recolor_layers_row->Add(new wxStaticText(print_settings_page, wxID_ANY, _L("layers")), 0, wxALIGN_CENTER_VERTICAL);
print_settings_box->Add(top_visible_recolor_layers_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP | wxBOTTOM, gap);
print_settings_root->Add(print_settings_box, 0, wxEXPAND | wxALL, gap);
auto *experimental_box = new wxStaticBoxSizer(wxVERTICAL, experimental_page, _L("Surface Texture"));
@@ -1763,6 +1787,12 @@ public:
new wxCheckBox(experimental_page, wxID_ANY, _L("Use modulated overhang geometry in support generation"));
m_use_modulated_overhang_geometry_for_support_checkbox->SetValue(use_modulated_overhang_geometry_for_support);
experimental_box->Add(m_use_modulated_overhang_geometry_for_support_checkbox, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, gap);
m_top_visible_perimeter_recolor_point_sampling_checkbox =
new wxCheckBox(experimental_page, wxID_ANY, _L("Point-sample visible layer-line recolor"));
m_top_visible_perimeter_recolor_point_sampling_checkbox->SetValue(top_visible_perimeter_recolor_point_sampling);
m_top_visible_perimeter_recolor_point_sampling_checkbox->SetToolTip(
_L("Uses dense point samples instead of clipped vector areas to decide which top-visible perimeter sections should be recolored."));
experimental_box->Add(m_top_visible_perimeter_recolor_point_sampling_checkbox, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, gap);
m_dithering_resolution_panel = new wxPanel(experimental_page, wxID_ANY);
auto *dithering_resolution_row = new wxBoxSizer(wxHORIZONTAL);
m_dithering_resolution_panel->SetSizer(dithering_resolution_row);
@@ -2063,6 +2093,19 @@ public:
int(TextureMappingZone::TopVisibleRecolorAggressive)) :
TextureMappingZone::DefaultTopVisiblePerimeterRecolorAggressiveness;
}
int top_visible_perimeter_recolor_above_layers() const
{
return m_top_visible_perimeter_recolor_above_layers_spin ?
std::clamp(m_top_visible_perimeter_recolor_above_layers_spin->GetValue(),
TextureMappingZone::MinTopVisiblePerimeterRecolorAboveLayers,
TextureMappingZone::MaxTopVisiblePerimeterRecolorAboveLayers) :
TextureMappingZone::DefaultTopVisiblePerimeterRecolorAboveLayers;
}
bool top_visible_perimeter_recolor_point_sampling() const
{
return m_top_visible_perimeter_recolor_point_sampling_checkbox != nullptr &&
m_top_visible_perimeter_recolor_point_sampling_checkbox->GetValue();
}
bool use_legacy_fixed_color_mode() const { return m_use_legacy_fixed_color_mode_checkbox && m_use_legacy_fixed_color_mode_checkbox->GetValue(); }
bool high_speed_image_texture_sampling() const { return true; }
bool dithering_enabled() const { return m_dithering_enabled_checkbox && m_dithering_enabled_checkbox->GetValue(); }
@@ -2408,6 +2451,8 @@ private:
m_recolor_top_visible_perimeter_sections_checkbox->Enable(perimeter_path_mode);
if (m_use_modulated_overhang_geometry_for_support_checkbox != nullptr)
m_use_modulated_overhang_geometry_for_support_checkbox->Enable(perimeter_path_v2_mode);
if (m_top_visible_perimeter_recolor_point_sampling_checkbox != nullptr)
m_top_visible_perimeter_recolor_point_sampling_checkbox->Enable(perimeter_path_v2_mode);
const bool top_visible_enabled =
perimeter_path_mode &&
top_visible_checked;
@@ -2415,6 +2460,10 @@ private:
m_top_visible_perimeter_recolor_aggressiveness_label->Enable(top_visible_enabled);
if (m_top_visible_perimeter_recolor_aggressiveness_choice != nullptr)
m_top_visible_perimeter_recolor_aggressiveness_choice->Enable(top_visible_enabled);
if (m_top_visible_perimeter_recolor_above_layers_label != nullptr)
m_top_visible_perimeter_recolor_above_layers_label->Enable(top_visible_enabled);
if (m_top_visible_perimeter_recolor_above_layers_spin != nullptr)
m_top_visible_perimeter_recolor_above_layers_spin->Enable(top_visible_enabled);
layout_current_options_page();
if (!fit_dialog)
return;
@@ -2478,6 +2527,9 @@ private:
wxCheckBox *m_recolor_top_visible_perimeter_sections_checkbox {nullptr};
wxStaticText *m_top_visible_perimeter_recolor_aggressiveness_label {nullptr};
wxChoice *m_top_visible_perimeter_recolor_aggressiveness_choice {nullptr};
wxStaticText *m_top_visible_perimeter_recolor_above_layers_label {nullptr};
wxSpinCtrl *m_top_visible_perimeter_recolor_above_layers_spin {nullptr};
wxCheckBox *m_top_visible_perimeter_recolor_point_sampling_checkbox {nullptr};
wxCheckBox *m_compact_offset_mode_checkbox {nullptr};
wxCheckBox *m_dithering_enabled_checkbox {nullptr};
wxChoice *m_dithering_method_choice {nullptr};
@@ -6662,6 +6714,8 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
updated.recolor_small_perimeter_loops,
updated.recolor_top_visible_perimeter_sections,
updated.top_visible_perimeter_recolor_aggressiveness,
updated.top_visible_perimeter_recolor_above_layers,
updated.top_visible_perimeter_recolor_point_sampling,
updated.compact_offset_mode,
updated.use_legacy_fixed_color_mode,
updated.minimum_visibility_offset_enabled,
@@ -6704,6 +6758,8 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
updated.recolor_small_perimeter_loops = dlg.recolor_small_perimeter_loops();
updated.recolor_top_visible_perimeter_sections = dlg.recolor_top_visible_perimeter_sections();
updated.top_visible_perimeter_recolor_aggressiveness = dlg.top_visible_perimeter_recolor_aggressiveness();
updated.top_visible_perimeter_recolor_above_layers = dlg.top_visible_perimeter_recolor_above_layers();
updated.top_visible_perimeter_recolor_point_sampling = dlg.top_visible_perimeter_recolor_point_sampling();
updated.compact_offset_mode = dlg.compact_offset_mode();
updated.use_legacy_fixed_color_mode = dlg.use_legacy_fixed_color_mode();
updated.high_resolution_sampling = true;