diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index f8b54909375..a7568dace16 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -511,6 +511,7 @@ struct TopSurfaceImageRegionPlan { bool contoning_supersampled_cells_enabled = false; bool contoning_polygonize_color_regions_enabled = false; bool contoning_fast_mode_enabled = TextureMappingZone::DefaultTopSurfaceContoningFastModeEnabled; + int contoning_polygonization_mode = TextureMappingZone::DefaultTopSurfaceContoningPolygonizationMode; int contoning_polygonize_resolution = TextureMappingZone::DefaultTopSurfaceContoningPolygonizeResolution; bool contoning_surface_anchored_stacks_enabled = false; bool contoning_surface_anchored_stack_optimizations_enabled = TextureMappingZone::DefaultTopSurfaceContoningSurfaceAnchoredStackOptimizationsEnabled; @@ -2277,6 +2278,7 @@ struct TopSurfaceImageContoningStackPlanKey { bool blue_noise { false }; bool polygonize { false }; bool fast_mode { false }; + int polygonization_mode { TextureMappingZone::DefaultTopSurfaceContoningPolygonizationMode }; int polygonize_resolution { 1 }; bool surface_anchored_stack_optimizations { false }; bool td_adjustment { false }; @@ -2313,6 +2315,7 @@ struct TopSurfaceImageContoningStackPlanKey { blue_noise, polygonize, fast_mode, + polygonization_mode, polygonize_resolution, surface_anchored_stack_optimizations, td_adjustment, @@ -2346,6 +2349,7 @@ struct TopSurfaceImageContoningStackPlanKey { rhs.blue_noise, rhs.polygonize, rhs.fast_mode, + rhs.polygonization_mode, rhs.polygonize_resolution, rhs.surface_anchored_stack_optimizations, rhs.td_adjustment, @@ -3058,6 +3062,217 @@ static ExPolygons top_surface_image_contoning_polygonized_area_from_grid_label(c throw_if_canceled); } +static std::vector top_surface_image_contoning_shared_gaussian_partition_grid(const std::vector &grid, + int cols, + int rows, + const std::vector &ids, + const ThrowIfCanceled *throw_if_canceled) +{ + if (grid.empty() || ids.empty() || cols <= 0 || rows <= 0 || grid.size() != size_t(cols) * size_t(rows)) + return grid; + + int max_id = -1; + for (int id : ids) + if (id >= 0) + max_id = std::max(max_id, id); + if (max_id < 0) + return grid; + + std::vector id_to_slot(size_t(max_id) + 1, -1); + std::vector active_ids; + active_ids.reserve(ids.size()); + for (int id : ids) { + if (id < 0 || id > max_id || id_to_slot[size_t(id)] >= 0) + continue; + id_to_slot[size_t(id)] = int(active_ids.size()); + active_ids.emplace_back(id); + } + if (active_ids.empty()) + return grid; + + static constexpr std::array kernel = { 1, 4, 6, 4, 1 }; + std::vector out(grid.size(), -1); + std::vector scores(active_ids.size(), 0); + for (int row = 0; row < rows; ++row) { + check_canceled(throw_if_canceled); + for (int col = 0; col < cols; ++col) { + const size_t idx = size_t(row) * size_t(cols) + size_t(col); + const int center_id = grid[idx]; + if (center_id < 0 || center_id > max_id || id_to_slot[size_t(center_id)] < 0) + continue; + + std::fill(scores.begin(), scores.end(), 0); + for (int dy = -2; dy <= 2; ++dy) { + const int yy = row + dy; + if (yy < 0 || yy >= rows) + continue; + for (int dx = -2; dx <= 2; ++dx) { + const int xx = col + dx; + if (xx < 0 || xx >= cols) + continue; + const int neighbor_id = grid[size_t(yy) * size_t(cols) + size_t(xx)]; + if (neighbor_id < 0 || neighbor_id > max_id) + continue; + const int slot = id_to_slot[size_t(neighbor_id)]; + if (slot < 0) + continue; + scores[size_t(slot)] += kernel[size_t(dy + 2)] * kernel[size_t(dx + 2)]; + } + } + + int best_slot = id_to_slot[size_t(center_id)]; + int best_score = scores[size_t(best_slot)]; + for (size_t slot = 0; slot < scores.size(); ++slot) { + if (scores[slot] > best_score) { + best_slot = int(slot); + best_score = scores[slot]; + } + } + out[idx] = active_ids[size_t(best_slot)]; + } + } + + return out; +} + +static int top_surface_image_contoning_best_completion_index(const std::vector &areas, + const ExPolygons &leftover, + const std::vector &fallback_indices, + coord_t touch_radius) +{ + int best_index = -1; + double best_contact = 0.; + double best_area = 0.; + ExPolygons expanded_leftover = top_surface_clip_offset_ex(leftover, float(touch_radius)); + for (int index : fallback_indices) { + if (index < 0 || size_t(index) >= areas.size() || areas[size_t(index)].empty()) + continue; + const ExPolygons contact = + top_surface_clip_intersection_ex(expanded_leftover, areas[size_t(index)], ApplySafetyOffset::Yes); + const double contact_area = top_surface_image_abs_area(contact); + const double area = top_surface_image_abs_area(areas[size_t(index)]); + if (contact_area > best_contact + EPSILON || + (std::abs(contact_area - best_contact) <= EPSILON && area > best_area)) { + best_index = index; + best_contact = contact_area; + best_area = area; + } + } + if (best_index >= 0) + return best_index; + for (int index : fallback_indices) { + if (index < 0 || size_t(index) >= areas.size() || areas[size_t(index)].empty()) + continue; + const double area = top_surface_image_abs_area(areas[size_t(index)]); + if (area > best_area) { + best_index = index; + best_area = area; + } + } + if (best_index >= 0) + return best_index; + for (int index : fallback_indices) + if (index >= 0 && size_t(index) < areas.size()) + return index; + return -1; +} + +static void top_surface_image_contoning_complete_indexed_area(std::vector &areas, + const ExPolygons &target_area, + const std::vector &fallback_indices, + float line_width_mm, + const ThrowIfCanceled *throw_if_canceled) +{ + if (areas.empty() || target_area.empty() || fallback_indices.empty()) + return; + + ExPolygons covered; + for (const ExPolygons &area : areas) { + check_canceled(throw_if_canceled); + if (!area.empty()) + append(covered, area); + } + + ExPolygons leftover = covered.empty() ? + top_surface_clip_union_ex(target_area) : + top_surface_clip_diff_ex(target_area, top_surface_clip_union_ex(covered), ApplySafetyOffset::Yes); + if (leftover.empty()) + return; + + const coord_t touch_radius = + std::max(1, scale_(std::clamp(double(line_width_mm) * 0.25, 0.02, 0.20))); + for (ExPolygon &leftover_part : leftover) { + check_canceled(throw_if_canceled); + ExPolygons piece; + piece.emplace_back(std::move(leftover_part)); + const int index = top_surface_image_contoning_best_completion_index(areas, piece, fallback_indices, touch_radius); + if (index < 0) + continue; + append(areas[size_t(index)], std::move(piece)); + areas[size_t(index)] = top_surface_clip_union_ex(areas[size_t(index)]); + } +} + +static std::vector top_surface_image_contoning_vector_border_shared_gaussian_partition_areas( + const std::vector &grid, + int cols, + int rows, + const std::vector &ids, + size_t area_count, + coord_t min_x, + coord_t min_y, + coord_t step, + const BoundingBox &bbox, + const ExPolygons &target_area, + float min_feature_mm, + bool cleanup_optimizations_enabled, + const ThrowIfCanceled *throw_if_canceled) +{ + std::vector areas(area_count); + if (grid.empty() || ids.empty() || area_count == 0 || target_area.empty() || + cols <= 0 || rows <= 0 || grid.size() != size_t(cols) * size_t(rows)) + return areas; + + const std::vector partition_grid = + top_surface_image_contoning_shared_gaussian_partition_grid(grid, cols, rows, ids, throw_if_canceled); + + ExPolygons taken; + for (int id : ids) { + check_canceled(throw_if_canceled); + if (id < 0 || size_t(id) >= areas.size()) + continue; + ExPolygons raw_area = + top_surface_image_contoning_raw_partition_hierarchy_area_from_grid_label(partition_grid, + cols, + rows, + id, + min_x, + min_y, + step, + bbox, + throw_if_canceled); + if (raw_area.empty()) + continue; + ExPolygons clean_area = top_surface_image_contoning_clean_area(std::move(raw_area), + target_area, + taken, + min_feature_mm, + cleanup_optimizations_enabled, + throw_if_canceled); + if (clean_area.empty()) + continue; + areas[size_t(id)] = std::move(clean_area); + append(taken, areas[size_t(id)]); + } + + top_surface_image_contoning_complete_indexed_area(areas, + target_area, + ids, + min_feature_mm > 0.f ? min_feature_mm : 0.4f, + throw_if_canceled); + return areas; +} + static std::vector top_surface_image_contoning_component_regions_from_grid( const std::vector &label_grid, int cols, @@ -3073,6 +3288,7 @@ static std::vector top_surface_image_conto float min_feature_mm, bool polygonize_color_regions, bool fast_mode_enabled, + int polygonization_mode, bool cleanup_optimizations_enabled, bool lower_surface, const ThrowIfCanceled *throw_if_canceled) @@ -3132,7 +3348,16 @@ static std::vector top_surface_image_conto return lhs < rhs; }); - const bool raw_partition_hierarchy_convert = fast_mode_enabled && polygonize_color_regions; + const int effective_polygonization_mode = + TextureMappingZone::effective_top_surface_contoning_polygonization_mode(polygonization_mode); + const bool vector_border_shared_gaussian_partition = + fast_mode_enabled && + polygonize_color_regions && + effective_polygonization_mode == int(TextureMappingZone::ContoningPolygonizationVectorBorderSharedGaussianPartition); + const bool raw_partition_hierarchy_convert = + fast_mode_enabled && + polygonize_color_regions && + effective_polygonization_mode == int(TextureMappingZone::ContoningPolygonizationMarchingSquares); const ExPolygons empty_blocked_area; ExPolygons valid_area; if (!raw_partition_hierarchy_convert) { @@ -3153,6 +3378,35 @@ static std::vector top_surface_image_conto return regions; } + if (vector_border_shared_gaussian_partition) { + std::vector component_areas = + top_surface_image_contoning_vector_border_shared_gaussian_partition_areas(component_grid, + cols, + rows, + component_order, + size_t(max_component_id) + 1, + min_x, + min_y, + step, + bbox, + valid_area, + min_feature_mm, + cleanup_optimizations_enabled, + throw_if_canceled); + for (int component_id : component_order) { + check_canceled(throw_if_canceled); + if (component_id <= 0 || size_t(component_id) >= component_areas.size() || + component_areas[size_t(component_id)].empty()) + continue; + TopSurfaceImageContoningVectorRegion region; + region.bottom_to_top.emplace_back(static_cast(component_id)); + region.cell_count = cell_counts[size_t(component_id)]; + region.area = std::move(component_areas[size_t(component_id)]); + regions.emplace_back(std::move(region)); + } + return regions; + } + ExPolygons taken; for (int component_id : component_order) { check_canceled(throw_if_canceled); @@ -3231,6 +3485,7 @@ static std::vector top_surface_image_conto float min_feature_mm, bool polygonize_color_regions, bool fast_mode_enabled, + int polygonization_mode, bool cleanup_optimizations_enabled, const ThrowIfCanceled *throw_if_canceled) { @@ -3256,7 +3511,44 @@ static std::vector top_surface_image_conto return lhs < rhs; }); - const bool raw_partition_hierarchy_convert = fast_mode_enabled && polygonize_color_regions; + const int effective_polygonization_mode = + TextureMappingZone::effective_top_surface_contoning_polygonization_mode(polygonization_mode); + const bool vector_border_shared_gaussian_partition = + fast_mode_enabled && + polygonize_color_regions && + effective_polygonization_mode == int(TextureMappingZone::ContoningPolygonizationVectorBorderSharedGaussianPartition); + const bool raw_partition_hierarchy_convert = + fast_mode_enabled && + polygonize_color_regions && + effective_polygonization_mode == int(TextureMappingZone::ContoningPolygonizationMarchingSquares); + if (vector_border_shared_gaussian_partition) { + std::vector label_areas = + top_surface_image_contoning_vector_border_shared_gaussian_partition_areas(label_grid, + cols, + rows, + label_order, + labels.size(), + min_x, + min_y, + step, + bbox, + area, + min_feature_mm, + cleanup_optimizations_enabled, + throw_if_canceled); + for (int label : label_order) { + check_canceled(throw_if_canceled); + if (label < 0 || size_t(label) >= label_areas.size() || label_areas[size_t(label)].empty()) + continue; + TopSurfaceImageContoningVectorRegion region; + region.bottom_to_top = labels[size_t(label)].bottom_to_top; + region.cell_count = cell_counts[size_t(label)]; + region.area = std::move(label_areas[size_t(label)]); + regions.emplace_back(std::move(region)); + } + return regions; + } + ExPolygons covered_parts; const ExPolygons empty_blocked_area; for (int label : label_order) { @@ -4643,6 +4935,7 @@ static void top_surface_image_contoning_solve_anchored_region( plan.contoning_min_feature_mm, plan.contoning_polygonize_color_regions_enabled, plan.contoning_fast_mode_enabled, + plan.contoning_polygonization_mode, plan.contoning_surface_anchored_stack_optimizations_enabled, throw_if_canceled); top_surface_image_debug_accumulate_timing_step(debug_timing.steps, @@ -4690,6 +4983,7 @@ static void top_surface_image_contoning_solve_anchored_region( plan.contoning_min_feature_mm, plan.contoning_polygonize_color_regions_enabled, plan.contoning_fast_mode_enabled, + plan.contoning_polygonization_mode, plan.contoning_surface_anchored_stack_optimizations_enabled, source_surface == TopSurfaceImageSourceSurface::Bottom && plan.contoning_td_adjustment_enabled, @@ -5090,6 +5384,9 @@ static TopSurfaceImageContoningStackPlanKey top_surface_image_contoning_anchored key.blue_noise = false; key.polygonize = plan.contoning_polygonize_color_regions_enabled; key.fast_mode = plan.contoning_fast_mode_enabled; + key.polygonization_mode = plan.contoning_polygonize_color_regions_enabled && plan.contoning_fast_mode_enabled ? + TextureMappingZone::effective_top_surface_contoning_polygonization_mode(plan.contoning_polygonization_mode) : + TextureMappingZone::DefaultTopSurfaceContoningPolygonizationMode; key.polygonize_resolution = plan.contoning_polygonize_color_regions_enabled ? TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution(plan.contoning_polygonize_resolution) : 1; @@ -5380,6 +5677,7 @@ static std::vector top_surface_image_conto plan.contoning_min_feature_mm, plan.contoning_polygonize_color_regions_enabled, plan.contoning_fast_mode_enabled, + plan.contoning_polygonization_mode, plan.contoning_surface_anchored_stack_optimizations_enabled, source_surface == TopSurfaceImageSourceSurface::Bottom && plan.contoning_td_adjustment_enabled, @@ -5632,6 +5930,9 @@ static TopSurfaceImageContoningStackPlanKey top_surface_image_contoning_stack_pl key.blue_noise = use_blue_noise_error_diffusion; key.polygonize = plan.contoning_polygonize_color_regions_enabled; key.fast_mode = plan.contoning_fast_mode_enabled; + key.polygonization_mode = plan.contoning_polygonize_color_regions_enabled && plan.contoning_fast_mode_enabled ? + TextureMappingZone::effective_top_surface_contoning_polygonization_mode(plan.contoning_polygonization_mode) : + TextureMappingZone::DefaultTopSurfaceContoningPolygonizationMode; key.polygonize_resolution = plan.contoning_polygonize_color_regions_enabled ? TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution(plan.contoning_polygonize_resolution) : 1; @@ -5728,6 +6029,7 @@ static std::vector top_surface_image_conto plan.contoning_min_feature_mm, plan.contoning_polygonize_color_regions_enabled, plan.contoning_fast_mode_enabled, + plan.contoning_polygonization_mode, plan.contoning_surface_anchored_stack_optimizations_enabled, source_surface == TopSurfaceImageSourceSurface::Bottom && plan.contoning_td_adjustment_enabled, @@ -6320,7 +6622,8 @@ static std::vector top_surface_image_region_plans( plan.contoning_supersampled_cells_enabled = zone->effective_top_surface_contoning_supersampled_cells_enabled(); plan.contoning_polygonize_color_regions_enabled = zone->top_surface_contoning_polygonize_color_regions_enabled; - plan.contoning_fast_mode_enabled = zone->top_surface_contoning_fast_mode_enabled; + plan.contoning_fast_mode_enabled = zone->effective_top_surface_contoning_fast_mode_enabled(); + plan.contoning_polygonization_mode = zone->effective_top_surface_contoning_polygonization_mode(); plan.contoning_polygonize_resolution = TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution(zone->top_surface_contoning_polygonize_resolution); plan.contoning_surface_anchored_stacks_enabled = diff --git a/src/libslic3r/TextureMapping.cpp b/src/libslic3r/TextureMapping.cpp index 1a575a95287..0cfcb44da57 100644 --- a/src/libslic3r/TextureMapping.cpp +++ b/src/libslic3r/TextureMapping.cpp @@ -751,6 +751,25 @@ static int top_surface_contoning_color_prediction_mode_from_name(std::string nam return TextureMappingZone::DefaultTopSurfaceContoningColorPredictionMode; } +static std::string top_surface_contoning_polygonization_mode_name(int mode) +{ + if (TextureMappingZone::effective_top_surface_contoning_polygonization_mode(mode) == + int(TextureMappingZone::ContoningPolygonizationMarchingSquares)) + return "marching_squares"; + return "vector_border_shared_gaussian_partition"; +} + +static int top_surface_contoning_polygonization_mode_from_name(std::string name) +{ + std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) { + const char lowered = char(std::tolower(c)); + return lowered == '-' || lowered == ' ' ? '_' : lowered; + }); + if (name == "marching_squares" || name == "marching_square") + return int(TextureMappingZone::ContoningPolygonizationMarchingSquares); + return TextureMappingZone::DefaultTopSurfaceContoningPolygonizationMode; +} + static std::string top_visible_recolor_aggressiveness_name(int mode) { switch (clamp_int(mode, @@ -1197,7 +1216,8 @@ bool TextureMappingZone::operator==(const TextureMappingZone &rhs) const effective_top_surface_contoning_supersampled_cells_enabled() == rhs.effective_top_surface_contoning_supersampled_cells_enabled() && top_surface_contoning_polygonize_color_regions_enabled == rhs.top_surface_contoning_polygonize_color_regions_enabled && - top_surface_contoning_fast_mode_enabled == rhs.top_surface_contoning_fast_mode_enabled && + effective_top_surface_contoning_fast_mode_enabled() == rhs.effective_top_surface_contoning_fast_mode_enabled() && + effective_top_surface_contoning_polygonization_mode() == rhs.effective_top_surface_contoning_polygonization_mode() && TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution(top_surface_contoning_polygonize_resolution) == TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution(rhs.top_surface_contoning_polygonize_resolution) && effective_top_surface_contoning_surface_anchored_stacks_enabled() == rhs.effective_top_surface_contoning_surface_anchored_stacks_enabled() && @@ -1609,7 +1629,9 @@ std::string TextureMappingManager::serialize_entries() texture["top_surface_contoning_polygonize_color_regions_enabled"] = zone.top_surface_contoning_polygonize_color_regions_enabled; texture["top_surface_contoning_fast_mode_enabled"] = - zone.top_surface_contoning_fast_mode_enabled; + zone.effective_top_surface_contoning_fast_mode_enabled(); + texture["top_surface_contoning_polygonization_mode"] = + top_surface_contoning_polygonization_mode_name(zone.top_surface_contoning_polygonization_mode); texture["top_surface_contoning_polygonize_resolution"] = TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution(zone.top_surface_contoning_polygonize_resolution); texture["top_surface_contoning_surface_anchored_stacks_enabled"] = @@ -1923,6 +1945,14 @@ void TextureMappingManager::load_entries(const std::string &serialized, zone.top_surface_contoning_fast_mode_enabled = texture.value("top_surface_contoning_fast_mode_enabled", TextureMappingZone::DefaultTopSurfaceContoningFastModeEnabled); + auto polygonization_mode_it = texture.find("top_surface_contoning_polygonization_mode"); + zone.top_surface_contoning_polygonization_mode = + polygonization_mode_it != texture.end() && polygonization_mode_it->is_string() ? + top_surface_contoning_polygonization_mode_from_name(polygonization_mode_it->get()) : + TextureMappingZone::normalize_top_surface_contoning_polygonization_mode( + polygonization_mode_it != texture.end() && polygonization_mode_it->is_number_integer() ? + polygonization_mode_it->get() : + TextureMappingZone::DefaultTopSurfaceContoningPolygonizationMode); auto polygonize_resolution_it = texture.find("top_surface_contoning_polygonize_resolution"); zone.top_surface_contoning_polygonize_resolution = TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution( diff --git a/src/libslic3r/TextureMapping.hpp b/src/libslic3r/TextureMapping.hpp index 091ed409566..438d7572f19 100644 --- a/src/libslic3r/TextureMapping.hpp +++ b/src/libslic3r/TextureMapping.hpp @@ -95,6 +95,11 @@ struct TextureMappingZone ContoningColorPredictionBeerLambertRgb = 2 }; + enum TopSurfaceContoningPolygonizationMode : uint8_t { + ContoningPolygonizationVectorBorderSharedGaussianPartition = 0, + ContoningPolygonizationMarchingSquares = 1 + }; + enum FilamentColorMode : uint8_t { FilamentColorAny = 0, FilamentColorRGB = 1, @@ -208,6 +213,8 @@ struct TextureMappingZone static constexpr bool DefaultTopSurfaceContoningSupersampledCellsEnabled = false; static constexpr bool DefaultTopSurfaceContoningPolygonizeColorRegionsEnabled = true; static constexpr bool DefaultTopSurfaceContoningFastModeEnabled = true; + static constexpr int DefaultTopSurfaceContoningPolygonizationMode = + int(ContoningPolygonizationVectorBorderSharedGaussianPartition); static constexpr int DefaultTopSurfaceContoningPolygonizeResolution = 4; static constexpr bool DefaultTopSurfaceContoningSurfaceAnchoredStacksEnabled = true; static constexpr bool DefaultTopSurfaceContoningSurfaceAnchoredStackOptimizationsEnabled = true; @@ -266,16 +273,22 @@ struct TextureMappingZone static int effective_top_surface_contoning_flat_surface_infill_mode(int mode) { - if (!ShowExperimentalTopSurfaceContoningOptions) - return SlicerDefaultTopSurfaceContoningFlatSurfaceInfillMode; - return mode == int(ContoningFlatSurfaceInfillDefault) ? + const int stored_mode = stored_top_surface_contoning_flat_surface_infill_mode(mode); + return stored_mode == int(ContoningFlatSurfaceInfillDefault) ? SlicerDefaultTopSurfaceContoningFlatSurfaceInfillMode : - mode; + stored_mode; } static int stored_top_surface_contoning_flat_surface_infill_mode(int mode) { - return ShowExperimentalTopSurfaceContoningOptions ? mode : DefaultTopSurfaceContoningFlatSurfaceInfillMode; + const int clamped_mode = std::clamp(mode, + int(ContoningFlatSurfaceInfillDefault), + int(ContoningFlatSurfaceInfillRectilinearWithBoundary)); + if (ShowExperimentalTopSurfaceContoningOptions) + return clamped_mode; + return clamped_mode == int(ContoningFlatSurfaceInfillRectilinear) ? + clamped_mode : + DefaultTopSurfaceContoningFlatSurfaceInfillMode; } static int stored_top_surface_contoning_perimeter_mode(int mode) @@ -333,6 +346,23 @@ struct TextureMappingZone return ShowExperimentalTopSurfaceContoningOptions && value; } + static bool effective_top_surface_contoning_fast_mode_enabled(bool value) + { + return ShowExperimentalTopSurfaceContoningOptions ? value : true; + } + + static constexpr int normalize_top_surface_contoning_polygonization_mode(int mode) + { + return mode == int(ContoningPolygonizationMarchingSquares) ? + int(ContoningPolygonizationMarchingSquares) : + DefaultTopSurfaceContoningPolygonizationMode; + } + + static constexpr int effective_top_surface_contoning_polygonization_mode(int mode) + { + return normalize_top_surface_contoning_polygonization_mode(mode); + } + static bool effective_top_surface_contoning_surface_scatter_enabled(bool td_adjustment, bool surface_scatter, bool td_effective_alpha) @@ -444,6 +474,7 @@ struct TextureMappingZone bool top_surface_contoning_supersampled_cells_enabled = DefaultTopSurfaceContoningSupersampledCellsEnabled; bool top_surface_contoning_polygonize_color_regions_enabled = DefaultTopSurfaceContoningPolygonizeColorRegionsEnabled; bool top_surface_contoning_fast_mode_enabled = DefaultTopSurfaceContoningFastModeEnabled; + int top_surface_contoning_polygonization_mode = DefaultTopSurfaceContoningPolygonizationMode; int top_surface_contoning_polygonize_resolution = DefaultTopSurfaceContoningPolygonizeResolution; bool top_surface_contoning_surface_anchored_stacks_enabled = DefaultTopSurfaceContoningSurfaceAnchoredStacksEnabled; bool top_surface_contoning_surface_anchored_stack_optimizations_enabled = DefaultTopSurfaceContoningSurfaceAnchoredStackOptimizationsEnabled; @@ -603,6 +634,18 @@ struct TextureMappingZone top_surface_contoning_supersampled_cells_enabled); } + bool effective_top_surface_contoning_fast_mode_enabled() const + { + return TextureMappingZone::effective_top_surface_contoning_fast_mode_enabled( + top_surface_contoning_fast_mode_enabled); + } + + int effective_top_surface_contoning_polygonization_mode() const + { + return TextureMappingZone::effective_top_surface_contoning_polygonization_mode( + top_surface_contoning_polygonization_mode); + } + bool effective_top_surface_contoning_surface_scatter_enabled() const { return TextureMappingZone::effective_top_surface_contoning_surface_scatter_enabled( @@ -639,13 +682,15 @@ struct TextureMappingZone top_surface_contoning_replace_top_perimeters_with_infill = false; top_surface_contoning_recolor_surrounding_perimeters = false; top_surface_contoning_perimeter_mode = DefaultTopSurfaceContoningPerimeterMode; - top_surface_contoning_flat_surface_infill_mode = DefaultTopSurfaceContoningFlatSurfaceInfillMode; + top_surface_contoning_flat_surface_infill_mode = + stored_top_surface_contoning_flat_surface_infill_mode(top_surface_contoning_flat_surface_infill_mode); top_surface_contoning_surface_anchored_stacks_enabled = true; top_surface_contoning_surface_anchored_stack_optimizations_enabled = true; top_surface_contoning_beam_search_stack_expansion_enabled = true; top_surface_contoning_layer_phase_enabled = false; top_surface_contoning_blue_noise_error_diffusion_enabled = false; top_surface_contoning_supersampled_cells_enabled = false; + top_surface_contoning_fast_mode_enabled = true; } else if (top_surface_contoning_replace_top_perimeters_with_infill) { top_surface_contoning_recolor_surrounding_perimeters = false; } @@ -718,6 +763,7 @@ struct TextureMappingZone top_surface_contoning_supersampled_cells_enabled = DefaultTopSurfaceContoningSupersampledCellsEnabled; top_surface_contoning_polygonize_color_regions_enabled = DefaultTopSurfaceContoningPolygonizeColorRegionsEnabled; top_surface_contoning_fast_mode_enabled = DefaultTopSurfaceContoningFastModeEnabled; + top_surface_contoning_polygonization_mode = DefaultTopSurfaceContoningPolygonizationMode; top_surface_contoning_polygonize_resolution = DefaultTopSurfaceContoningPolygonizeResolution; top_surface_contoning_surface_anchored_stacks_enabled = DefaultTopSurfaceContoningSurfaceAnchoredStacksEnabled; top_surface_contoning_surface_anchored_stack_optimizations_enabled = DefaultTopSurfaceContoningSurfaceAnchoredStackOptimizationsEnabled; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index cce33c68067..434e263bd10 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2138,6 +2138,19 @@ static int texture_mapping_contoning_color_prediction_mode_from_choice_selection } } +static int texture_mapping_contoning_polygonization_mode_choice_selection(int mode) +{ + return TextureMappingZone::effective_top_surface_contoning_polygonization_mode(mode) == + int(TextureMappingZone::ContoningPolygonizationMarchingSquares) ? 1 : 0; +} + +static int texture_mapping_contoning_polygonization_mode_from_choice_selection(int selection) +{ + return selection == 1 ? + int(TextureMappingZone::ContoningPolygonizationMarchingSquares) : + TextureMappingZone::DefaultTopSurfaceContoningPolygonizationMode; +} + class TextureMappingAdvancedOptionsDialog : public wxDialog { public: @@ -2197,6 +2210,7 @@ public: bool top_surface_contoning_supersampled_cells_enabled, bool top_surface_contoning_polygonize_color_regions_enabled, bool top_surface_contoning_fast_mode_enabled, + int top_surface_contoning_polygonization_mode, int top_surface_contoning_polygonize_resolution, bool top_surface_contoning_surface_anchored_stacks_enabled, bool top_surface_contoning_surface_anchored_stack_optimizations_enabled, @@ -2849,30 +2863,47 @@ public: evt.Skip(); queue_top_surface_contoning_message_resize_wrap(); }); + auto *contoning_flat_infill_row = new wxBoxSizer(wxHORIZONTAL); + contoning_flat_infill_row->Add(new wxStaticText(m_top_surface_contoning_panel, wxID_ANY, _L("Infill type")), + 0, + wxALIGN_CENTER_VERTICAL | wxRIGHT, + gap); + wxArrayString contoning_flat_infill_choices; + auto add_contoning_flat_infill_choice = [&](const wxString &label, int mode) { + contoning_flat_infill_choices.Add(label); + m_top_surface_contoning_flat_surface_infill_modes.push_back(mode); + }; + add_contoning_flat_infill_choice(_L("Default (Boundary Skin variable width)"), + int(TextureMappingZone::ContoningFlatSurfaceInfillDefault)); + add_contoning_flat_infill_choice(_L("Rectilinear"), + int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinear)); if (TextureMappingZone::ShowExperimentalTopSurfaceContoningOptions) { - auto *contoning_flat_infill_row = new wxBoxSizer(wxHORIZONTAL); - contoning_flat_infill_row->Add(new wxStaticText(m_top_surface_contoning_panel, wxID_ANY, _L("Flat surface infill mode")), - 0, - wxALIGN_CENTER_VERTICAL | wxRIGHT, - gap); - wxArrayString contoning_flat_infill_choices; - contoning_flat_infill_choices.Add(_L("Default (Boundary Skin variable width)")); - contoning_flat_infill_choices.Add(_L("Rectilinear")); - contoning_flat_infill_choices.Add(_L("Concentric")); - contoning_flat_infill_choices.Add(_L("Boundary Skin (fixed width)")); - contoning_flat_infill_choices.Add(_L("Boundary Skin (variable width)")); - contoning_flat_infill_choices.Add(_L("Spiral")); - contoning_flat_infill_choices.Add(_L("Boundary Skin Hybrid")); - contoning_flat_infill_choices.Add(_L("Rectilinear with Boundary")); - m_top_surface_contoning_flat_surface_infill_choice = - new wxChoice(m_top_surface_contoning_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, contoning_flat_infill_choices); - m_top_surface_contoning_flat_surface_infill_choice->SetSelection( - std::clamp(top_surface_contoning_flat_surface_infill_mode, - int(TextureMappingZone::ContoningFlatSurfaceInfillDefault), - int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinearWithBoundary))); - contoning_flat_infill_row->Add(m_top_surface_contoning_flat_surface_infill_choice, 1, wxEXPAND); - top_surface_contoning_root->Add(contoning_flat_infill_row, 0, wxEXPAND | wxTOP, gap); + add_contoning_flat_infill_choice(_L("Concentric"), + int(TextureMappingZone::ContoningFlatSurfaceInfillConcentric)); + add_contoning_flat_infill_choice(_L("Boundary Skin (fixed width)"), + int(TextureMappingZone::ContoningFlatSurfaceInfillBoundarySkinFixed)); + add_contoning_flat_infill_choice(_L("Boundary Skin (variable width)"), + int(TextureMappingZone::ContoningFlatSurfaceInfillBoundarySkinVariable)); + add_contoning_flat_infill_choice(_L("Spiral"), + int(TextureMappingZone::ContoningFlatSurfaceInfillSpiral)); + add_contoning_flat_infill_choice(_L("Boundary Skin Hybrid"), + int(TextureMappingZone::ContoningFlatSurfaceInfillBoundarySkinHybrid)); + add_contoning_flat_infill_choice(_L("Rectilinear with Boundary"), + int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinearWithBoundary)); } + m_top_surface_contoning_flat_surface_infill_choice = + new wxChoice(m_top_surface_contoning_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, contoning_flat_infill_choices); + const int stored_flat_infill_mode = + TextureMappingZone::stored_top_surface_contoning_flat_surface_infill_mode(top_surface_contoning_flat_surface_infill_mode); + const auto flat_infill_mode_it = std::find(m_top_surface_contoning_flat_surface_infill_modes.begin(), + m_top_surface_contoning_flat_surface_infill_modes.end(), + stored_flat_infill_mode); + m_top_surface_contoning_flat_surface_infill_choice->SetSelection( + flat_infill_mode_it != m_top_surface_contoning_flat_surface_infill_modes.end() ? + int(flat_infill_mode_it - m_top_surface_contoning_flat_surface_infill_modes.begin()) : + 0); + contoning_flat_infill_row->Add(m_top_surface_contoning_flat_surface_infill_choice, 1, wxEXPAND); + top_surface_contoning_root->Add(contoning_flat_infill_row, 0, wxEXPAND | wxTOP, gap); top_surface_box->Add(m_top_surface_contoning_panel, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap); m_top_surface_image_fixed_coloring_filaments_checkbox = new wxCheckBox(top_surface_page, wxID_ANY, _L("Fixed top-surface coloring filaments")); @@ -3065,16 +3096,35 @@ public: 0, wxEXPAND | wxTOP | wxBOTTOM, gap / 2); - m_top_surface_contoning_fast_mode_checkbox = - new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Fast mode")); - m_top_surface_contoning_fast_mode_checkbox->SetValue(top_surface_contoning_fast_mode_enabled); - m_top_surface_contoning_fast_mode_checkbox->SetMinSize( - wxSize(-1, std::max(m_top_surface_contoning_fast_mode_checkbox->GetBestSize().GetHeight(), FromDIP(24)))); - contoning_checkboxes_root->Add(m_top_surface_contoning_fast_mode_checkbox, + m_top_surface_contoning_polygonization_mode_panel = new wxPanel(m_top_surface_contoning_checkboxes_panel, wxID_ANY); + auto *contoning_polygonization_mode_row = new wxBoxSizer(wxHORIZONTAL); + m_top_surface_contoning_polygonization_mode_panel->SetSizer(contoning_polygonization_mode_row); + contoning_polygonization_mode_row->Add(new wxStaticText(m_top_surface_contoning_polygonization_mode_panel, wxID_ANY, _L("Technique")), + 0, + wxALIGN_CENTER_VERTICAL | wxRIGHT, + gap); + wxArrayString contoning_polygonization_mode_choices; + contoning_polygonization_mode_choices.Add(_L("Vector-border shared Gaussian partition")); + contoning_polygonization_mode_choices.Add(_L("Marching squares")); + m_top_surface_contoning_polygonization_mode_choice = + new wxChoice(m_top_surface_contoning_polygonization_mode_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, contoning_polygonization_mode_choices); + m_top_surface_contoning_polygonization_mode_choice->SetSelection( + texture_mapping_contoning_polygonization_mode_choice_selection(top_surface_contoning_polygonization_mode)); + contoning_polygonization_mode_row->Add(m_top_surface_contoning_polygonization_mode_choice, 1, wxEXPAND); + contoning_checkboxes_root->Add(m_top_surface_contoning_polygonization_mode_panel, 0, wxEXPAND | wxTOP | wxBOTTOM, gap / 2); if (TextureMappingZone::ShowExperimentalTopSurfaceContoningOptions) { + m_top_surface_contoning_fast_mode_checkbox = + new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Fast mode")); + m_top_surface_contoning_fast_mode_checkbox->SetValue(top_surface_contoning_fast_mode_enabled); + m_top_surface_contoning_fast_mode_checkbox->SetMinSize( + wxSize(-1, std::max(m_top_surface_contoning_fast_mode_checkbox->GetBestSize().GetHeight(), FromDIP(24)))); + contoning_checkboxes_root->Add(m_top_surface_contoning_fast_mode_checkbox, + 0, + wxEXPAND | wxTOP | wxBOTTOM, + gap / 2); m_top_surface_contoning_surface_anchored_stacks_checkbox = new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Surface-anchored stacks")); m_top_surface_contoning_surface_anchored_stacks_checkbox->SetValue(top_surface_contoning_surface_anchored_stacks_enabled); @@ -3581,13 +3631,12 @@ public: } int top_surface_contoning_flat_surface_infill_mode() const { - if (!TextureMappingZone::ShowExperimentalTopSurfaceContoningOptions) - return TextureMappingZone::DefaultTopSurfaceContoningFlatSurfaceInfillMode; - return m_top_surface_contoning_flat_surface_infill_choice != nullptr ? - std::clamp(m_top_surface_contoning_flat_surface_infill_choice->GetSelection(), - int(TextureMappingZone::ContoningFlatSurfaceInfillDefault), - int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinearWithBoundary)) : - TextureMappingZone::DefaultTopSurfaceContoningFlatSurfaceInfillMode; + if (m_top_surface_contoning_flat_surface_infill_choice != nullptr) { + const int selection = m_top_surface_contoning_flat_surface_infill_choice->GetSelection(); + if (selection >= 0 && size_t(selection) < m_top_surface_contoning_flat_surface_infill_modes.size()) + return m_top_surface_contoning_flat_surface_infill_modes[size_t(selection)]; + } + return TextureMappingZone::DefaultTopSurfaceContoningFlatSurfaceInfillMode; } bool top_surface_contoning_layer_phase_enabled() const { @@ -3627,10 +3676,19 @@ public: } bool top_surface_contoning_fast_mode_enabled() const { + if (!TextureMappingZone::ShowExperimentalTopSurfaceContoningOptions) + return true; return m_top_surface_contoning_fast_mode_checkbox != nullptr ? m_top_surface_contoning_fast_mode_checkbox->GetValue() : TextureMappingZone::DefaultTopSurfaceContoningFastModeEnabled; } + int top_surface_contoning_polygonization_mode() const + { + return m_top_surface_contoning_polygonization_mode_choice != nullptr ? + texture_mapping_contoning_polygonization_mode_from_choice_selection( + m_top_surface_contoning_polygonization_mode_choice->GetSelection()) : + TextureMappingZone::DefaultTopSurfaceContoningPolygonizationMode; + } int top_surface_contoning_polygonize_resolution() const { if (m_top_surface_contoning_polygonize_resolution_choice == nullptr) @@ -4581,6 +4639,10 @@ private: m_top_surface_contoning_polygonize_resolution_panel->Show(polygonize_color_regions); if (m_top_surface_contoning_polygonize_resolution_choice != nullptr) m_top_surface_contoning_polygonize_resolution_choice->Enable(polygonize_color_regions); + if (m_top_surface_contoning_polygonization_mode_panel != nullptr) + m_top_surface_contoning_polygonization_mode_panel->Show(polygonize_color_regions); + if (m_top_surface_contoning_polygonization_mode_choice != nullptr) + m_top_surface_contoning_polygonization_mode_choice->Enable(polygonize_color_regions); if (m_top_surface_contoning_surface_anchored_stacks_checkbox != nullptr) { m_top_surface_contoning_surface_anchored_stacks_checkbox->Show(contoning); m_top_surface_contoning_surface_anchored_stacks_checkbox->Enable(contoning); @@ -4666,6 +4728,7 @@ private: wxStaticText *m_top_surface_contoning_pattern_recommendation_text {nullptr}; wxStaticText *m_top_surface_contoning_shell_warning_text {nullptr}; wxChoice *m_top_surface_contoning_flat_surface_infill_choice {nullptr}; + std::vector m_top_surface_contoning_flat_surface_infill_modes; wxPanel *m_top_surface_contoning_checkboxes_panel {nullptr}; wxCheckBox *m_top_surface_contoning_color_lower_surfaces_checkbox {nullptr}; wxCheckBox *m_top_surface_contoning_only_one_perimeter_around_shell_infill_checkbox {nullptr}; @@ -4680,6 +4743,8 @@ private: wxCheckBox *m_top_surface_contoning_supersampled_cells_checkbox {nullptr}; wxCheckBox *m_top_surface_contoning_polygonize_color_regions_checkbox {nullptr}; wxCheckBox *m_top_surface_contoning_fast_mode_checkbox {nullptr}; + wxPanel *m_top_surface_contoning_polygonization_mode_panel {nullptr}; + wxChoice *m_top_surface_contoning_polygonization_mode_choice {nullptr}; wxPanel *m_top_surface_contoning_polygonize_resolution_panel {nullptr}; wxChoice *m_top_surface_contoning_polygonize_resolution_choice {nullptr}; wxCheckBox *m_top_surface_contoning_surface_anchored_stacks_checkbox {nullptr}; @@ -9716,6 +9781,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) updated.top_surface_contoning_supersampled_cells_enabled, updated.top_surface_contoning_polygonize_color_regions_enabled, updated.top_surface_contoning_fast_mode_enabled, + updated.top_surface_contoning_polygonization_mode, updated.top_surface_contoning_polygonize_resolution, updated.top_surface_contoning_surface_anchored_stacks_enabled, updated.top_surface_contoning_surface_anchored_stack_optimizations_enabled, @@ -9800,6 +9866,8 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) dlg.top_surface_contoning_polygonize_color_regions_enabled(); updated.top_surface_contoning_fast_mode_enabled = dlg.top_surface_contoning_fast_mode_enabled(); + updated.top_surface_contoning_polygonization_mode = + dlg.top_surface_contoning_polygonization_mode(); updated.top_surface_contoning_polygonize_resolution = dlg.top_surface_contoning_polygonize_resolution(); updated.top_surface_contoning_surface_anchored_stacks_enabled =