mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 23:25:59 +08:00
Added greedy sort for ExtrusionLine in the perimeter generator.
This commit is contained in:
parent
66a18fb60f
commit
8616758354
@ -8,6 +8,7 @@
|
|||||||
#include "ExtrusionJunction.hpp"
|
#include "ExtrusionJunction.hpp"
|
||||||
#include "../../Polyline.hpp"
|
#include "../../Polyline.hpp"
|
||||||
#include "../../Polygon.hpp"
|
#include "../../Polygon.hpp"
|
||||||
|
#include "BoundingBox.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
class ThickPolyline;
|
class ThickPolyline;
|
||||||
@ -218,6 +219,53 @@ static inline Polygon to_polygon(const ExtrusionLine &line)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static BoundingBox get_extents(const ExtrusionLine &extrusion_line)
|
||||||
|
{
|
||||||
|
BoundingBox bbox;
|
||||||
|
for (const ExtrusionJunction &junction : extrusion_line.junctions)
|
||||||
|
bbox.merge(junction.p);
|
||||||
|
return bbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BoundingBox get_extents(const std::vector<ExtrusionLine> &extrusion_lines)
|
||||||
|
{
|
||||||
|
BoundingBox bbox;
|
||||||
|
for (const ExtrusionLine &extrusion_line : extrusion_lines)
|
||||||
|
bbox.merge(get_extents(extrusion_line));
|
||||||
|
return bbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BoundingBox get_extents(const std::vector<const ExtrusionLine *> &extrusion_lines)
|
||||||
|
{
|
||||||
|
BoundingBox bbox;
|
||||||
|
for (const ExtrusionLine *extrusion_line : extrusion_lines) {
|
||||||
|
assert(extrusion_line != nullptr);
|
||||||
|
bbox.merge(get_extents(*extrusion_line));
|
||||||
|
}
|
||||||
|
return bbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Points to_points(const ExtrusionLine &extrusion_line)
|
||||||
|
{
|
||||||
|
Points points;
|
||||||
|
points.reserve(extrusion_line.junctions.size());
|
||||||
|
for (const ExtrusionJunction &junction : extrusion_line.junctions)
|
||||||
|
points.emplace_back(junction.p);
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<Points> to_points(const std::vector<const ExtrusionLine *> &extrusion_lines)
|
||||||
|
{
|
||||||
|
std::vector<Points> points;
|
||||||
|
for (const ExtrusionLine *extrusion_line : extrusion_lines) {
|
||||||
|
assert(extrusion_line != nullptr);
|
||||||
|
points.emplace_back(to_points(*extrusion_line));
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
using VariableWidthLines = std::vector<ExtrusionLine>; //<! The ExtrusionLines generated by libArachne
|
using VariableWidthLines = std::vector<ExtrusionLine>; //<! The ExtrusionLines generated by libArachne
|
||||||
|
|
||||||
} // namespace Slic3r::Arachne
|
} // namespace Slic3r::Arachne
|
||||||
|
@ -352,28 +352,62 @@ void PerimeterGenerator::process_arachne()
|
|||||||
blocking[map_extrusion_to_idx.find(before)->second].emplace_back(after_it->second);
|
blocking[map_extrusion_to_idx.find(before)->second].emplace_back(after_it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stack<const Arachne::ExtrusionLine *> unblocked_extrusions;
|
std::vector<bool> processed(all_extrusions.size(), false); // Indicate that the extrusion was already processed.
|
||||||
// Add open extrusions before closed extrusions to ensure that on the top of the stack will be closed extrusions.
|
Point current_position = all_extrusions.front()->junctions.front().p; // Some starting position.
|
||||||
for (size_t extrusion_idx = 0; extrusion_idx < all_extrusions.size(); ++extrusion_idx)
|
std::vector<const Arachne::ExtrusionLine *> ordered_extrusions; // To store our result in. At the end we'll std::swap.
|
||||||
if (!all_extrusions[extrusion_idx]->is_closed && blocked[extrusion_idx] == 0)
|
ordered_extrusions.reserve(all_extrusions.size());
|
||||||
unblocked_extrusions.emplace(all_extrusions[extrusion_idx]);
|
|
||||||
for (size_t extrusion_idx = 0; extrusion_idx < all_extrusions.size(); ++extrusion_idx)
|
|
||||||
if (all_extrusions[extrusion_idx]->is_closed && blocked[extrusion_idx] == 0)
|
|
||||||
unblocked_extrusions.emplace(all_extrusions[extrusion_idx]);
|
|
||||||
|
|
||||||
std::vector<const Arachne::ExtrusionLine *> ordered_extrusions;
|
while (ordered_extrusions.size() < all_extrusions.size()) {
|
||||||
while (!unblocked_extrusions.empty()) {
|
size_t best_candidate = 0;
|
||||||
const Arachne::ExtrusionLine *extrusion = unblocked_extrusions.top();
|
double best_distance_sqr = std::numeric_limits<double>::max();
|
||||||
unblocked_extrusions.pop();
|
bool is_best_closed = false;
|
||||||
ordered_extrusions.emplace_back(extrusion);
|
|
||||||
|
|
||||||
for (const size_t blocking_idx : blocking[map_extrusion_to_idx.find(extrusion)->second]) {
|
std::vector<size_t> available_candidates;
|
||||||
--blocked[blocking_idx];
|
for (size_t candidate = 0; candidate < all_extrusions.size(); ++candidate) {
|
||||||
if (blocked[blocking_idx] == 0)
|
if (processed[candidate] || blocked[candidate])
|
||||||
unblocked_extrusions.emplace(all_extrusions[blocking_idx]);
|
continue; // Not a valid candidate.
|
||||||
|
available_candidates.push_back(candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(available_candidates.begin(), available_candidates.end(), [&all_extrusions](const size_t a_idx, const size_t b_idx) -> bool {
|
||||||
|
return all_extrusions[a_idx]->is_closed < all_extrusions[b_idx]->is_closed;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const size_t candidate_path_idx : available_candidates) {
|
||||||
|
auto& path = all_extrusions[candidate_path_idx];
|
||||||
|
|
||||||
|
if (path->junctions.empty()) { // No vertices in the path. Can't find the start position then or really plan it in. Put that at the end.
|
||||||
|
if (best_distance_sqr == std::numeric_limits<double>::max()) {
|
||||||
|
best_candidate = candidate_path_idx;
|
||||||
|
is_best_closed = path->is_closed;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Point candidate_position = path->junctions.front().p;
|
||||||
|
double distance_sqr = (current_position - candidate_position).cast<double>().norm();
|
||||||
|
if (distance_sqr < best_distance_sqr) { // Closer than the best candidate so far.
|
||||||
|
if (path->is_closed || (!path->is_closed && best_distance_sqr != std::numeric_limits<double>::max()) || (!path->is_closed && !is_best_closed)) {
|
||||||
|
best_candidate = candidate_path_idx;
|
||||||
|
best_distance_sqr = distance_sqr;
|
||||||
|
is_best_closed = path->is_closed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &best_path = all_extrusions[best_candidate];
|
||||||
|
ordered_extrusions.push_back(best_path);
|
||||||
|
processed[best_candidate] = true;
|
||||||
|
for (size_t unlocked_idx : blocking[best_candidate])
|
||||||
|
blocked[unlocked_idx]--;
|
||||||
|
|
||||||
|
if(!best_path->junctions.empty()) { //If all paths were empty, the best path is still empty. We don't upate the current position then.
|
||||||
|
if(best_path->is_closed)
|
||||||
|
current_position = best_path->junctions[0].p; //We end where we started.
|
||||||
|
else
|
||||||
|
current_position = best_path->junctions.back().p; //Pick the other end from where we started.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(ordered_extrusions.size() == all_extrusions.size());
|
|
||||||
|
|
||||||
for (const Arachne::ExtrusionLine *extrusion : ordered_extrusions) {
|
for (const Arachne::ExtrusionLine *extrusion : ordered_extrusions) {
|
||||||
if (extrusion->empty())
|
if (extrusion->empty())
|
||||||
@ -415,13 +449,13 @@ void PerimeterGenerator::process_arachne()
|
|||||||
for (ExPolygon &ex : infill_contour)
|
for (ExPolygon &ex : infill_contour)
|
||||||
ex.simplify_p(m_scaled_resolution, &pp);
|
ex.simplify_p(m_scaled_resolution, &pp);
|
||||||
// collapse too narrow infill areas
|
// collapse too narrow infill areas
|
||||||
coord_t min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
|
auto min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
|
||||||
// append infill areas to fill_surfaces
|
// append infill areas to fill_surfaces
|
||||||
this->fill_surfaces->append(
|
this->fill_surfaces->append(
|
||||||
offset_ex(offset2_ex(
|
offset_ex(offset2_ex(
|
||||||
union_ex(pp),
|
union_ex(pp),
|
||||||
float(-min_perimeter_infill_spacing / 2.),
|
float(-min_perimeter_infill_spacing / 2.),
|
||||||
float(min_perimeter_infill_spacing / 2.)), inset),
|
float(min_perimeter_infill_spacing / 2.)), float(inset)),
|
||||||
stInternal);
|
stInternal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user