SPE-1950: Optimization of computation complexity of perimeter ordering for Arachne generator.

The previous implementation during the grouping of perimeters using depth-first searches unnecessarily searched nodes that had no impact on grouping, which significantly increased the search space.

Cherry-picked from prusa3d/PrusaSlicer@86309ba939

Co-authored-by: Lukáš Hejl <hejl.lukas@gmail.com>
This commit is contained in:
Noisyfox 2024-12-22 17:53:03 +08:00
parent babb84c70a
commit 47ec9b9b06
2 changed files with 37 additions and 26 deletions

View file

@ -1,4 +1,10 @@
#include <stack>
#include <algorithm>
#include <cmath>
#include "PerimeterOrder.hpp"
#include "libslic3r/Arachne/utils/ExtrusionJunction.hpp"
#include "libslic3r/Point.hpp"
namespace Slic3r::Arachne::PerimeterOrder {
@ -128,7 +134,7 @@ static std::vector<const PerimeterExtrusion *> ordered_perimeter_extrusions_to_m
const Point &extrusion_start_position = extrusion_line.junctions.front().p;
const double distance_sqr = (current_position - extrusion_start_position).cast<double>().squaredNorm();
if (distance_sqr < nearest_distance_sqr) {
if (extrusion_line.is_closed || (!extrusion_line.is_closed && nearest_distance_sqr != std::numeric_limits<double>::max()) || (!extrusion_line.is_closed && !is_nearest_closed)) {
if (extrusion_line.is_closed || (!extrusion_line.is_closed && nearest_distance_sqr == std::numeric_limits<double>::max()) || (!extrusion_line.is_closed && !is_nearest_closed)) {
nearest_extrusion_idx = extrusion_idx;
nearest_distance_sqr = distance_sqr;
is_nearest_closed = extrusion_line.is_closed;
@ -184,7 +190,7 @@ static std::vector<size_t> order_of_grouped_perimeter_extrusions_to_minimize_dis
const Point &extrusion_start_position = external_perimeter_extrusion_line.junctions.front().p;
const double distance_sqr = (current_position - extrusion_start_position).cast<double>().squaredNorm();
if (distance_sqr < nearest_distance_sqr) {
if (external_perimeter_extrusion_line.is_closed || (!external_perimeter_extrusion_line.is_closed && nearest_distance_sqr != std::numeric_limits<double>::max()) || (!external_perimeter_extrusion_line.is_closed && !is_nearest_closed)) {
if (external_perimeter_extrusion_line.is_closed || (!external_perimeter_extrusion_line.is_closed && nearest_distance_sqr == std::numeric_limits<double>::max()) || (!external_perimeter_extrusion_line.is_closed && !is_nearest_closed)) {
nearest_grouped_extrusions_idx = grouped_extrusion_idx;
nearest_distance_sqr = distance_sqr;
is_nearest_closed = external_perimeter_extrusion_line.is_closed;
@ -219,33 +225,32 @@ static PerimeterExtrusions extract_ordered_perimeter_extrusions(const PerimeterE
while (!stack.empty()) {
const PerimeterExtrusion *current_extrusion = stack.top();
const size_t current_extrusion_idx = current_extrusion - sorted_perimeter_extrusions.data();
stack.pop();
visited[current_extrusion_idx] = true;
if (visited[current_extrusion_idx])
continue;
if (current_extrusion->nearest_external_perimeter == &perimeter_extrusion)
if (current_extrusion->nearest_external_perimeter == &perimeter_extrusion) {
grouped_extrusions.back().extrusions.emplace_back(current_extrusion);
if (current_extrusion->adjacent_perimeter_extrusions.size() == 1) {
const PerimeterExtrusion *adjacent_extrusion = current_extrusion->adjacent_perimeter_extrusions.front();
stack.push(adjacent_extrusion);
} else if (current_extrusion->adjacent_perimeter_extrusions.size() > 1) {
// When there is more than one available candidate, then order candidates to minimize distances between
// candidates and also to minimize the distance from the current_position.
std::vector<const PerimeterExtrusion *> available_candidates;
for (const PerimeterExtrusion *adjacent_extrusion : current_extrusion->adjacent_perimeter_extrusions) {
if (const size_t adjacent_extrusion_idx = adjacent_extrusion - sorted_perimeter_extrusions.data(); !visited[adjacent_extrusion_idx])
available_candidates.emplace_back(adjacent_extrusion);
}
std::vector<const PerimeterExtrusion *> adjacent_extrusions = ordered_perimeter_extrusions_to_minimize_distances(Point::Zero(), available_candidates);
std::reverse(adjacent_extrusions.begin(), adjacent_extrusions.end());
for (const PerimeterExtrusion *adjacent_extrusion : adjacent_extrusions)
stack.push(adjacent_extrusion);
}
visited[current_extrusion_idx] = true;
std::vector<const PerimeterExtrusion *> available_candidates;
for (const PerimeterExtrusion *adjacent_extrusion : current_extrusion->adjacent_perimeter_extrusions) {
const size_t adjacent_extrusion_idx = adjacent_extrusion - sorted_perimeter_extrusions.data();
if (!visited[adjacent_extrusion_idx] && !adjacent_extrusion->is_external_perimeter() && adjacent_extrusion->nearest_external_perimeter == &perimeter_extrusion) {
available_candidates.emplace_back(adjacent_extrusion);
}
}
if (available_candidates.size() == 1) {
stack.push(available_candidates.front());
} else if (available_candidates.size() > 1) {
// When there is more than one available candidate, then order candidates to minimize distances between
// candidates and also to minimize the distance from the current_position.
std::vector<const PerimeterExtrusion *> adjacent_extrusions = ordered_perimeter_extrusions_to_minimize_distances(Point::Zero(), available_candidates);
for (auto extrusion_it = adjacent_extrusions.rbegin(); extrusion_it != adjacent_extrusions.rend(); ++extrusion_it) {
stack.push(*extrusion_it);
}
}
}
if (!external_perimeters_first)
@ -253,7 +258,6 @@ static PerimeterExtrusions extract_ordered_perimeter_extrusions(const PerimeterE
}
const std::vector<size_t> grouped_extrusion_order = order_of_grouped_perimeter_extrusions_to_minimize_distances(Point::Zero(), grouped_extrusions);
assert(grouped_extrusion_order.size() == grouped_ordered_extrusions.size());
PerimeterExtrusions ordered_extrusions;
for (size_t order_idx : grouped_extrusion_order) {

View file

@ -1,7 +1,14 @@
#ifndef slic3r_GCode_PerimeterOrder_hpp_
#define slic3r_GCode_PerimeterOrder_hpp_
#include <Arachne/utils/ExtrusionLine.hpp>
#include <stddef.h>
#include <limits>
#include <vector>
#include <cstddef>
#include "libslic3r/Arachne/utils/ExtrusionLine.hpp"
#include "libslic3r/BoundingBox.hpp"
#include "libslic3r/Polygon.hpp"
namespace Slic3r::Arachne::PerimeterOrder {