From b5685b34f82907f375b5e3828f8588329e01da4f Mon Sep 17 00:00:00 2001 From: sentientstardust Date: Mon, 1 Jun 2026 17:37:02 +0100 Subject: [PATCH] Add Mid Gaussian shared chain fit polygonization mode --- src/libslic3r/Fill/Fill.cpp | 702 ++++++++++++++++++++++++++++++- src/libslic3r/TextureMapping.cpp | 14 +- src/libslic3r/TextureMapping.hpp | 8 +- src/slic3r/GUI/Plater.cpp | 24 +- 4 files changed, 735 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index dbf8ebf2814..f0a8e625639 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -3087,6 +3087,507 @@ static ExPolygons top_surface_image_contoning_raw_partition_hierarchy_area_from_ return top_surface_image_contoning_hierarchy_expolygons(std::move(polygons), throw_if_canceled); } +struct TopSurfaceImageContoningSharedChainVertex { + int col { 0 }; + int row { 0 }; + + bool operator<(const TopSurfaceImageContoningSharedChainVertex &rhs) const + { + return std::tie(col, row) < std::tie(rhs.col, rhs.row); + } + + bool operator==(const TopSurfaceImageContoningSharedChainVertex &rhs) const + { + return col == rhs.col && row == rhs.row; + } + + bool operator!=(const TopSurfaceImageContoningSharedChainVertex &rhs) const + { + return !(*this == rhs); + } +}; + +struct TopSurfaceImageContoningSharedChainLabelPair { + int first { -1 }; + int second { -1 }; + + bool operator<(const TopSurfaceImageContoningSharedChainLabelPair &rhs) const + { + return std::tie(first, second) < std::tie(rhs.first, rhs.second); + } + + bool operator==(const TopSurfaceImageContoningSharedChainLabelPair &rhs) const + { + return first == rhs.first && second == rhs.second; + } +}; + +struct TopSurfaceImageContoningSharedChainEdgeKey { + TopSurfaceImageContoningSharedChainVertex a; + TopSurfaceImageContoningSharedChainVertex b; + + bool operator<(const TopSurfaceImageContoningSharedChainEdgeKey &rhs) const + { + return std::tie(a, b) < std::tie(rhs.a, rhs.b); + } +}; + +struct TopSurfaceImageContoningSharedChainEdge { + TopSurfaceImageContoningSharedChainVertex a; + TopSurfaceImageContoningSharedChainVertex b; + int left_label { -1 }; + int right_label { -1 }; +}; + +struct TopSurfaceImageContoningSharedChain { + TopSurfaceImageContoningSharedChainLabelPair labels; + std::vector vertices; + bool closed { false }; +}; + +struct TopSurfaceImageContoningDirectedSharedChain { + int label { -1 }; + TopSurfaceImageContoningSharedChainVertex start; + TopSurfaceImageContoningSharedChainVertex end; + Points points; + bool closed { false }; +}; + +static TopSurfaceImageContoningSharedChainLabelPair top_surface_image_contoning_shared_chain_label_pair(int lhs, int rhs) +{ + return lhs <= rhs ? + TopSurfaceImageContoningSharedChainLabelPair{ lhs, rhs } : + TopSurfaceImageContoningSharedChainLabelPair{ rhs, lhs }; +} + +static TopSurfaceImageContoningSharedChainEdgeKey top_surface_image_contoning_shared_chain_edge_key( + TopSurfaceImageContoningSharedChainVertex a, + TopSurfaceImageContoningSharedChainVertex b) +{ + if (b < a) + std::swap(a, b); + return TopSurfaceImageContoningSharedChainEdgeKey{ a, b }; +} + +static void top_surface_image_contoning_add_shared_chain_label_pair( + std::vector &pairs, + const TopSurfaceImageContoningSharedChainLabelPair &pair) +{ + if (std::find(pairs.begin(), pairs.end(), pair) == pairs.end()) + pairs.emplace_back(pair); +} + +static void top_surface_image_contoning_add_shared_chain_edge( + std::map &edges, + TopSurfaceImageContoningSharedChainVertex start, + TopSurfaceImageContoningSharedChainVertex end, + int left_label, + int right_label) +{ + if (start == end || left_label == right_label || (left_label < 0 && right_label < 0)) + return; + const TopSurfaceImageContoningSharedChainEdgeKey key = + top_surface_image_contoning_shared_chain_edge_key(start, end); + if (edges.find(key) != edges.end()) + return; + edges.emplace(key, TopSurfaceImageContoningSharedChainEdge{ start, end, left_label, right_label }); +} + +static std::map +top_surface_image_contoning_shared_chain_edges_from_grid(const std::vector &grid, int cols, int rows) +{ + std::map edges; + if (grid.empty() || cols <= 0 || rows <= 0 || grid.size() != size_t(cols) * size_t(rows)) + return edges; + + for (int row = 0; row < rows; ++row) { + for (int col = 0; col + 1 < cols; ++col) { + const int left_label = grid[size_t(row) * size_t(cols) + size_t(col)]; + const int right_label = grid[size_t(row) * size_t(cols) + size_t(col + 1)]; + if (left_label == right_label) + continue; + top_surface_image_contoning_add_shared_chain_edge(edges, + TopSurfaceImageContoningSharedChainVertex{ col + 1, row }, + TopSurfaceImageContoningSharedChainVertex{ col + 1, row + 1 }, + left_label, + right_label); + } + } + + for (int row = 0; row + 1 < rows; ++row) { + for (int col = 0; col < cols; ++col) { + const int lower_label = grid[size_t(row) * size_t(cols) + size_t(col)]; + const int upper_label = grid[size_t(row + 1) * size_t(cols) + size_t(col)]; + if (lower_label == upper_label) + continue; + top_surface_image_contoning_add_shared_chain_edge(edges, + TopSurfaceImageContoningSharedChainVertex{ col, row + 1 }, + TopSurfaceImageContoningSharedChainVertex{ col + 1, row + 1 }, + upper_label, + lower_label); + } + } + + for (int col = 0; col < cols; ++col) { + const int bottom_label = grid[size_t(col)]; + if (bottom_label >= 0) + top_surface_image_contoning_add_shared_chain_edge(edges, + TopSurfaceImageContoningSharedChainVertex{ col, 0 }, + TopSurfaceImageContoningSharedChainVertex{ col + 1, 0 }, + bottom_label, + -1); + const int top_label = grid[size_t(rows - 1) * size_t(cols) + size_t(col)]; + if (top_label >= 0) + top_surface_image_contoning_add_shared_chain_edge(edges, + TopSurfaceImageContoningSharedChainVertex{ col + 1, rows }, + TopSurfaceImageContoningSharedChainVertex{ col, rows }, + top_label, + -1); + } + + for (int row = 0; row < rows; ++row) { + const int left_label = grid[size_t(row) * size_t(cols)]; + if (left_label >= 0) + top_surface_image_contoning_add_shared_chain_edge(edges, + TopSurfaceImageContoningSharedChainVertex{ 0, row + 1 }, + TopSurfaceImageContoningSharedChainVertex{ 0, row }, + left_label, + -1); + const int right_label = grid[size_t(row) * size_t(cols) + size_t(cols - 1)]; + if (right_label >= 0) + top_surface_image_contoning_add_shared_chain_edge(edges, + TopSurfaceImageContoningSharedChainVertex{ cols, row }, + TopSurfaceImageContoningSharedChainVertex{ cols, row + 1 }, + right_label, + -1); + } + + return edges; +} + +static bool top_surface_image_contoning_shared_chain_is_used( + const std::map, bool> &used, + const TopSurfaceImageContoningSharedChainLabelPair &labels, + TopSurfaceImageContoningSharedChainVertex a, + TopSurfaceImageContoningSharedChainVertex b) +{ + if (b < a) + std::swap(a, b); + return used.find(std::make_tuple(labels, a, b)) != used.end(); +} + +static void top_surface_image_contoning_mark_shared_chain_used( + std::map, bool> &used, + const TopSurfaceImageContoningSharedChainLabelPair &labels, + TopSurfaceImageContoningSharedChainVertex a, + TopSurfaceImageContoningSharedChainVertex b) +{ + if (b < a) + std::swap(a, b); + used.emplace(std::make_tuple(labels, a, b), true); +} + +static std::vector top_surface_image_contoning_extract_shared_chains( + const std::map &edges, + const ThrowIfCanceled *throw_if_canceled) +{ + std::map>> pair_adj; + std::map global_degree; + std::map> global_pairs; + + for (const auto &entry : edges) { + const TopSurfaceImageContoningSharedChainEdge &edge = entry.second; + const TopSurfaceImageContoningSharedChainLabelPair labels = + top_surface_image_contoning_shared_chain_label_pair(edge.left_label, edge.right_label); + pair_adj[labels][edge.a].emplace_back(edge.b); + pair_adj[labels][edge.b].emplace_back(edge.a); + ++global_degree[edge.a]; + ++global_degree[edge.b]; + top_surface_image_contoning_add_shared_chain_label_pair(global_pairs[edge.a], labels); + top_surface_image_contoning_add_shared_chain_label_pair(global_pairs[edge.b], labels); + } + + auto is_junction = [&global_degree, &global_pairs](const TopSurfaceImageContoningSharedChainVertex &vertex) { + auto degree_it = global_degree.find(vertex); + const int degree = degree_it == global_degree.end() ? 0 : degree_it->second; + auto pair_it = global_pairs.find(vertex); + const size_t pair_count = pair_it == global_pairs.end() ? 0 : pair_it->second.size(); + return degree != 2 || pair_count != 1; + }; + + std::vector chains; + std::map, bool> used; + + for (const auto &pair_entry : pair_adj) { + check_canceled(throw_if_canceled); + const TopSurfaceImageContoningSharedChainLabelPair &labels = pair_entry.first; + const auto &adj = pair_entry.second; + std::vector> pair_edges; + for (const auto &adj_entry : adj) { + for (const TopSurfaceImageContoningSharedChainVertex &neighbor : adj_entry.second) + if (adj_entry.first < neighbor) + pair_edges.emplace_back(adj_entry.first, neighbor); + } + + for (const auto &edge : pair_edges) { + if (top_surface_image_contoning_shared_chain_is_used(used, labels, edge.first, edge.second)) + continue; + if (!is_junction(edge.first) && !is_junction(edge.second)) + continue; + + TopSurfaceImageContoningSharedChainVertex start = edge.first; + TopSurfaceImageContoningSharedChainVertex next = edge.second; + if (!is_junction(start) && is_junction(next)) + std::swap(start, next); + + TopSurfaceImageContoningSharedChain chain; + chain.labels = labels; + chain.vertices.emplace_back(start); + chain.vertices.emplace_back(next); + top_surface_image_contoning_mark_shared_chain_used(used, labels, start, next); + + TopSurfaceImageContoningSharedChainVertex previous = start; + TopSurfaceImageContoningSharedChainVertex current = next; + while (!is_junction(current)) { + const auto adj_it = adj.find(current); + if (adj_it == adj.end()) + break; + bool advanced = false; + for (const TopSurfaceImageContoningSharedChainVertex &candidate : adj_it->second) { + if (candidate == previous || + top_surface_image_contoning_shared_chain_is_used(used, labels, current, candidate)) + continue; + chain.vertices.emplace_back(candidate); + top_surface_image_contoning_mark_shared_chain_used(used, labels, current, candidate); + previous = current; + current = candidate; + advanced = true; + break; + } + if (!advanced) + break; + } + chains.emplace_back(std::move(chain)); + } + + for (const auto &edge : pair_edges) { + if (top_surface_image_contoning_shared_chain_is_used(used, labels, edge.first, edge.second)) + continue; + + TopSurfaceImageContoningSharedChain chain; + chain.labels = labels; + chain.vertices.emplace_back(edge.first); + chain.vertices.emplace_back(edge.second); + top_surface_image_contoning_mark_shared_chain_used(used, labels, edge.first, edge.second); + + TopSurfaceImageContoningSharedChainVertex previous = edge.first; + TopSurfaceImageContoningSharedChainVertex current = edge.second; + while (true) { + const auto adj_it = adj.find(current); + if (adj_it == adj.end()) + break; + bool advanced = false; + for (const TopSurfaceImageContoningSharedChainVertex &candidate : adj_it->second) { + if (candidate == previous) + continue; + if (candidate == chain.vertices.front()) { + chain.closed = true; + top_surface_image_contoning_mark_shared_chain_used(used, labels, current, candidate); + advanced = false; + break; + } + if (top_surface_image_contoning_shared_chain_is_used(used, labels, current, candidate)) + continue; + chain.vertices.emplace_back(candidate); + top_surface_image_contoning_mark_shared_chain_used(used, labels, current, candidate); + previous = current; + current = candidate; + advanced = true; + break; + } + if (!advanced) + break; + } + chains.emplace_back(std::move(chain)); + } + } + + return chains; +} + +static Point top_surface_image_contoning_shared_chain_point(TopSurfaceImageContoningSharedChainVertex vertex, + coord_t min_x, + coord_t min_y, + coord_t step, + const BoundingBox &bbox) +{ + const coord_t x = std::min(min_x + coord_t(vertex.col) * step, bbox.max.x()); + const coord_t y = std::min(min_y + coord_t(vertex.row) * step, bbox.max.y()); + return Point(x, y); +} + +static Points top_surface_image_contoning_simplified_shared_chain_points( + const std::vector &vertices, + bool closed, + coord_t min_x, + coord_t min_y, + coord_t step, + const BoundingBox &bbox, + double tolerance) +{ + Points points; + points.reserve(vertices.size() + (closed ? 1 : 0)); + for (TopSurfaceImageContoningSharedChainVertex vertex : vertices) { + Point point = top_surface_image_contoning_shared_chain_point(vertex, min_x, min_y, step, bbox); + if (points.empty() || points.back() != point) + points.emplace_back(point); + } + if ((!closed && points.size() < 2) || (closed && points.size() < 3)) + return {}; + + if (closed) { + Points closed_points = points; + closed_points.emplace_back(closed_points.front()); + Points simplified = MultiPoint::_douglas_peucker(closed_points, tolerance); + if (!simplified.empty() && simplified.front() == simplified.back()) + simplified.pop_back(); + simplified.erase(std::unique(simplified.begin(), simplified.end()), simplified.end()); + if (simplified.size() >= 2 && simplified.front() == simplified.back()) + simplified.pop_back(); + return simplified.size() >= 3 ? simplified : points; + } + + Points simplified = MultiPoint::_douglas_peucker(points, tolerance); + simplified.erase(std::unique(simplified.begin(), simplified.end()), simplified.end()); + return simplified.size() >= 2 ? simplified : points; +} + +static bool top_surface_image_contoning_shared_chain_label_is_left( + const std::map &edges, + TopSurfaceImageContoningSharedChainVertex start, + TopSurfaceImageContoningSharedChainVertex end, + int label) +{ + const auto edge_it = edges.find(top_surface_image_contoning_shared_chain_edge_key(start, end)); + if (edge_it == edges.end()) + return true; + const TopSurfaceImageContoningSharedChainEdge &edge = edge_it->second; + const bool same_direction = edge.a == start && edge.b == end; + const int left_label = same_direction ? edge.left_label : edge.right_label; + return label == left_label; +} + +static double top_surface_image_contoning_shared_chain_angle(const Point &from, const Point &to) +{ + return std::atan2(double(to.y() - from.y()), double(to.x() - from.x())); +} + +static double top_surface_image_contoning_shared_chain_clockwise_delta(double reference_angle, double candidate_angle) +{ + double delta = reference_angle - candidate_angle; + while (delta < 0.) + delta += 2. * PI; + while (delta >= 2. * PI) + delta -= 2. * PI; + return delta; +} + +static int top_surface_image_contoning_next_shared_chain_index( + const std::vector &chains, + const std::vector &candidates, + const std::vector &used, + const Point &previous_point, + const Point ¤t_point) +{ + int best_index = -1; + double best_delta = std::numeric_limits::max(); + const double reference_angle = top_surface_image_contoning_shared_chain_angle(current_point, previous_point); + for (int candidate_index : candidates) { + if (candidate_index < 0 || size_t(candidate_index) >= chains.size() || used[size_t(candidate_index)]) + continue; + const TopSurfaceImageContoningDirectedSharedChain &candidate = chains[size_t(candidate_index)]; + if (candidate.points.size() < 2) + continue; + const double candidate_angle = + top_surface_image_contoning_shared_chain_angle(candidate.points.front(), candidate.points[1]); + const double delta = + top_surface_image_contoning_shared_chain_clockwise_delta(reference_angle, candidate_angle); + if (delta < best_delta) { + best_delta = delta; + best_index = candidate_index; + } + } + return best_index; +} + +static bool top_surface_image_contoning_append_shared_chain_polygons( + const std::vector &chains, + Polygons &polygons, + const ThrowIfCanceled *throw_if_canceled) +{ + if (chains.empty()) + return true; + + std::map> start_to_chain; + for (size_t idx = 0; idx < chains.size(); ++idx) + if (!chains[idx].closed && chains[idx].points.size() >= 2) + start_to_chain[chains[idx].start].emplace_back(int(idx)); + + std::vector used(chains.size(), false); + for (size_t idx = 0; idx < chains.size(); ++idx) { + check_canceled(throw_if_canceled); + if (used[idx] || chains[idx].closed || chains[idx].points.size() < 2) + continue; + + used[idx] = true; + Points loop = chains[idx].points; + const TopSurfaceImageContoningSharedChainVertex start = chains[idx].start; + TopSurfaceImageContoningSharedChainVertex current = chains[idx].end; + + size_t guard = 0; + while (current != start && guard++ <= chains.size()) { + auto candidates_it = start_to_chain.find(current); + if (candidates_it == start_to_chain.end()) + return false; + if (loop.size() < 2) + return false; + const int next_index = + top_surface_image_contoning_next_shared_chain_index(chains, + candidates_it->second, + used, + loop[loop.size() - 2], + loop.back()); + if (next_index < 0) + return false; + used[size_t(next_index)] = true; + const Points &next_points = chains[size_t(next_index)].points; + loop.insert(loop.end(), next_points.begin() + 1, next_points.end()); + current = chains[size_t(next_index)].end; + } + + if (current != start || loop.size() < 3) + return false; + if (loop.size() >= 2 && loop.front() == loop.back()) + loop.pop_back(); + loop.erase(std::unique(loop.begin(), loop.end()), loop.end()); + if (loop.size() >= 3) { + Polygon polygon(std::move(loop)); + top_surface_image_contoning_remove_collinear_points(polygon); + if (polygon.points.size() >= 3 && std::abs(polygon.area()) > 0.) + polygons.emplace_back(std::move(polygon)); + } + } + + return true; +} + static ExPolygons top_surface_image_contoning_polygonized_area_from_grid_label(const std::vector &grid, int cols, int rows, @@ -3351,6 +3852,147 @@ static std::vector top_surface_image_contoning_vector_border_shared_ return areas; } +static std::vector top_surface_image_contoning_mid_gaussian_shared_chain_fit_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 ThrowIfCanceled *throw_if_canceled) +{ + std::vector areas(area_count); + if (grid.empty() || ids.empty() || area_count == 0 || + 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); + const double fit_tolerance = std::max(1.0, double(step) * 0.16); + const std::map edges = + top_surface_image_contoning_shared_chain_edges_from_grid(partition_grid, cols, rows); + const std::vector chains = + top_surface_image_contoning_extract_shared_chains(edges, throw_if_canceled); + std::vector polygons(area_count); + std::vector> open_chains(area_count); + + for (const TopSurfaceImageContoningSharedChain &chain : chains) { + check_canceled(throw_if_canceled); + if (chain.vertices.size() < 2) + continue; + Points chain_points = + top_surface_image_contoning_simplified_shared_chain_points(chain.vertices, + chain.closed, + min_x, + min_y, + step, + bbox, + fit_tolerance); + if ((!chain.closed && chain_points.size() < 2) || (chain.closed && chain_points.size() < 3)) + continue; + + std::array chain_labels = { chain.labels.first, chain.labels.second }; + for (int label : chain_labels) { + if (label < 0 || size_t(label) >= area_count) + continue; + + Points directed_points = chain_points; + TopSurfaceImageContoningSharedChainVertex start = chain.vertices.front(); + TopSurfaceImageContoningSharedChainVertex end = chain.vertices.back(); + const bool label_is_left = + top_surface_image_contoning_shared_chain_label_is_left(edges, + chain.vertices[0], + chain.vertices[1], + label); + if (!label_is_left) { + std::reverse(directed_points.begin(), directed_points.end()); + std::swap(start, end); + } + + if (chain.closed) { + Polygon polygon(std::move(directed_points)); + top_surface_image_contoning_remove_collinear_points(polygon); + if (polygon.points.size() >= 3 && std::abs(polygon.area()) > 0.) + polygons[size_t(label)].emplace_back(std::move(polygon)); + } else { + TopSurfaceImageContoningDirectedSharedChain directed_chain; + directed_chain.label = label; + directed_chain.start = start; + directed_chain.end = end; + directed_chain.points = std::move(directed_points); + open_chains[size_t(label)].emplace_back(std::move(directed_chain)); + } + } + } + + bool shared_chain_success = true; + for (int id : ids) { + check_canceled(throw_if_canceled); + if (id < 0 || size_t(id) >= area_count) + continue; + if (!top_surface_image_contoning_append_shared_chain_polygons(open_chains[size_t(id)], + polygons[size_t(id)], + throw_if_canceled)) { + shared_chain_success = false; + break; + } + } + + if (shared_chain_success) { + for (int id : ids) { + check_canceled(throw_if_canceled); + if (id < 0 || size_t(id) >= areas.size()) + continue; + if (polygons[size_t(id)].empty()) { + areas[size_t(id)] = + 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); + continue; + } + areas[size_t(id)] = + top_surface_image_contoning_hierarchy_expolygons(std::move(polygons[size_t(id)]), throw_if_canceled); + if (areas[size_t(id)].empty()) + areas[size_t(id)] = + 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); + } + } else { + for (int id : ids) { + check_canceled(throw_if_canceled); + if (id < 0 || size_t(id) >= areas.size()) + continue; + areas[size_t(id)] = + 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); + } + } + return areas; +} + static std::vector top_surface_image_contoning_component_regions_from_grid( const std::vector &label_grid, int cols, @@ -3432,13 +4074,17 @@ static std::vector top_surface_image_conto fast_mode_enabled && polygonize_color_regions && effective_polygonization_mode == int(TextureMappingZone::ContoningPolygonizationVectorBorderSharedGaussianPartition); + const bool mid_gaussian_shared_chain_fit = + fast_mode_enabled && + polygonize_color_regions && + effective_polygonization_mode == int(TextureMappingZone::ContoningPolygonizationMidGaussianSharedChainFit); 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) { + if (!raw_partition_hierarchy_convert && !mid_gaussian_shared_chain_fit) { valid_area = top_surface_image_contoning_area_from_grid_label(valid_grid, cols, rows, @@ -3485,6 +4131,32 @@ static std::vector top_surface_image_conto return regions; } + if (mid_gaussian_shared_chain_fit) { + std::vector component_areas = + top_surface_image_contoning_mid_gaussian_shared_chain_fit_areas(component_grid, + cols, + rows, + component_order, + size_t(max_component_id) + 1, + min_x, + min_y, + step, + bbox, + 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); @@ -3595,6 +4267,10 @@ static std::vector top_surface_image_conto fast_mode_enabled && polygonize_color_regions && effective_polygonization_mode == int(TextureMappingZone::ContoningPolygonizationVectorBorderSharedGaussianPartition); + const bool mid_gaussian_shared_chain_fit = + fast_mode_enabled && + polygonize_color_regions && + effective_polygonization_mode == int(TextureMappingZone::ContoningPolygonizationMidGaussianSharedChainFit); const bool raw_partition_hierarchy_convert = fast_mode_enabled && polygonize_color_regions && @@ -3626,6 +4302,30 @@ static std::vector top_surface_image_conto } return regions; } + if (mid_gaussian_shared_chain_fit) { + std::vector label_areas = + top_surface_image_contoning_mid_gaussian_shared_chain_fit_areas(label_grid, + cols, + rows, + label_order, + labels.size(), + min_x, + min_y, + step, + bbox, + 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; diff --git a/src/libslic3r/TextureMapping.cpp b/src/libslic3r/TextureMapping.cpp index 3813b54db66..0b5be5df89b 100644 --- a/src/libslic3r/TextureMapping.cpp +++ b/src/libslic3r/TextureMapping.cpp @@ -859,10 +859,12 @@ static int top_surface_contoning_color_prediction_mode_from_name(std::string nam static std::string top_surface_contoning_polygonization_mode_name(int mode) { - if (TextureMappingZone::effective_top_surface_contoning_polygonization_mode(mode) == - int(TextureMappingZone::ContoningPolygonizationMarchingSquares)) + const int effective_mode = TextureMappingZone::effective_top_surface_contoning_polygonization_mode(mode); + if (effective_mode == int(TextureMappingZone::ContoningPolygonizationMarchingSquares)) return "marching_squares"; - return "vector_border_shared_gaussian_partition"; + if (effective_mode == int(TextureMappingZone::ContoningPolygonizationVectorBorderSharedGaussianPartition)) + return "vector_border_shared_gaussian_partition"; + return "mid_gaussian_shared_chain_fit"; } static int top_surface_contoning_polygonization_mode_from_name(std::string name) @@ -875,6 +877,12 @@ static int top_surface_contoning_polygonization_mode_from_name(std::string name) return int(TextureMappingZone::ContoningPolygonizationMarchingSquares); if (name == "vector_border_shared_gaussian_partition") return int(TextureMappingZone::ContoningPolygonizationVectorBorderSharedGaussianPartition); + if (name == "mid_gaussian_shared_chain_fit" || + name == "mid_gaussian_shared_chain_fit_0_16" || + name == "mid_gaussian_shared_chain_fit_0p16" || + name == "mid_gaussian_shared_chain_fit_0_16_cells" || + name == "mid_gaussian_shared_chain_fit_0p16_cells") + return int(TextureMappingZone::ContoningPolygonizationMidGaussianSharedChainFit); return TextureMappingZone::DefaultTopSurfaceContoningPolygonizationMode; } diff --git a/src/libslic3r/TextureMapping.hpp b/src/libslic3r/TextureMapping.hpp index 632d32443e2..640848f5b3c 100644 --- a/src/libslic3r/TextureMapping.hpp +++ b/src/libslic3r/TextureMapping.hpp @@ -105,7 +105,8 @@ struct TextureMappingZone enum TopSurfaceContoningPolygonizationMode : uint8_t { ContoningPolygonizationVectorBorderSharedGaussianPartition = 0, - ContoningPolygonizationMarchingSquares = 1 + ContoningPolygonizationMarchingSquares = 1, + ContoningPolygonizationMidGaussianSharedChainFit = 2 }; enum FilamentColorMode : uint8_t { @@ -222,7 +223,7 @@ struct TextureMappingZone static constexpr bool DefaultTopSurfaceContoningPolygonizeColorRegionsEnabled = true; static constexpr bool DefaultTopSurfaceContoningFastModeEnabled = true; static constexpr int DefaultTopSurfaceContoningPolygonizationMode = - int(ContoningPolygonizationMarchingSquares); + int(ContoningPolygonizationMidGaussianSharedChainFit); static constexpr int DefaultTopSurfaceContoningPolygonizeResolution = 4; static constexpr bool DefaultTopSurfaceContoningSurfaceAnchoredStacksEnabled = true; static constexpr bool DefaultTopSurfaceContoningSurfaceAnchoredStackOptimizationsEnabled = true; @@ -362,7 +363,8 @@ struct TextureMappingZone static constexpr int normalize_top_surface_contoning_polygonization_mode(int mode) { return mode == int(ContoningPolygonizationVectorBorderSharedGaussianPartition) || - mode == int(ContoningPolygonizationMarchingSquares) ? + mode == int(ContoningPolygonizationMarchingSquares) || + mode == int(ContoningPolygonizationMidGaussianSharedChainFit) ? mode : DefaultTopSurfaceContoningPolygonizationMode; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index a9385f84ff8..a037f319188 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2369,15 +2369,26 @@ static wxString texture_mapping_contoning_color_prediction_default_label() 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; + switch (TextureMappingZone::effective_top_surface_contoning_polygonization_mode(mode)) { + case int(TextureMappingZone::ContoningPolygonizationVectorBorderSharedGaussianPartition): + return 1; + case int(TextureMappingZone::ContoningPolygonizationMarchingSquares): + return 2; + default: + return 0; + } } static int texture_mapping_contoning_polygonization_mode_from_choice_selection(int selection) { - return selection == 1 ? - int(TextureMappingZone::ContoningPolygonizationMarchingSquares) : - int(TextureMappingZone::ContoningPolygonizationVectorBorderSharedGaussianPartition); + switch (selection) { + case 1: + return int(TextureMappingZone::ContoningPolygonizationVectorBorderSharedGaussianPartition); + case 2: + return int(TextureMappingZone::ContoningPolygonizationMarchingSquares); + default: + return int(TextureMappingZone::ContoningPolygonizationMidGaussianSharedChainFit); + } } class TextureMappingAdvancedOptionsDialog : public wxDialog @@ -3358,11 +3369,12 @@ public: 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")), + contoning_polygonization_mode_row->Add(new wxStaticText(m_top_surface_contoning_polygonization_mode_panel, wxID_ANY, _L("Polygonization mode")), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap); wxArrayString contoning_polygonization_mode_choices; + contoning_polygonization_mode_choices.Add(_L("Mid Gaussian shared chain fit")); contoning_polygonization_mode_choices.Add(_L("Vector-border shared Gaussian partition (very slow)")); contoning_polygonization_mode_choices.Add(_L("Marching squares")); m_top_surface_contoning_polygonization_mode_choice =