Added greedy sort for ExtrusionLine in the perimeter generator.

This commit is contained in:
Lukáš Hejl 2022-04-25 09:24:28 +02:00
parent 66a18fb60f
commit 8616758354
2 changed files with 102 additions and 20 deletions

View file

@ -8,6 +8,7 @@
#include "ExtrusionJunction.hpp"
#include "../../Polyline.hpp"
#include "../../Polygon.hpp"
#include "BoundingBox.hpp"
namespace Slic3r {
class ThickPolyline;
@ -218,6 +219,53 @@ static inline Polygon to_polygon(const ExtrusionLine &line)
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
} // namespace Slic3r::Arachne

View file

@ -352,28 +352,62 @@ void PerimeterGenerator::process_arachne()
blocking[map_extrusion_to_idx.find(before)->second].emplace_back(after_it->second);
}
std::stack<const Arachne::ExtrusionLine *> unblocked_extrusions;
// Add open extrusions before closed extrusions to ensure that on the top of the stack will be closed extrusions.
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]);
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<bool> processed(all_extrusions.size(), false); // Indicate that the extrusion was already processed.
Point current_position = all_extrusions.front()->junctions.front().p; // Some starting position.
std::vector<const Arachne::ExtrusionLine *> ordered_extrusions; // To store our result in. At the end we'll std::swap.
ordered_extrusions.reserve(all_extrusions.size());
std::vector<const Arachne::ExtrusionLine *> ordered_extrusions;
while (!unblocked_extrusions.empty()) {
const Arachne::ExtrusionLine *extrusion = unblocked_extrusions.top();
unblocked_extrusions.pop();
ordered_extrusions.emplace_back(extrusion);
while (ordered_extrusions.size() < all_extrusions.size()) {
size_t best_candidate = 0;
double best_distance_sqr = std::numeric_limits<double>::max();
bool is_best_closed = false;
for (const size_t blocking_idx : blocking[map_extrusion_to_idx.find(extrusion)->second]) {
--blocked[blocking_idx];
if (blocked[blocking_idx] == 0)
unblocked_extrusions.emplace(all_extrusions[blocking_idx]);
std::vector<size_t> available_candidates;
for (size_t candidate = 0; candidate < all_extrusions.size(); ++candidate) {
if (processed[candidate] || blocked[candidate])
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) {
if (extrusion->empty())
@ -415,13 +449,13 @@ void PerimeterGenerator::process_arachne()
for (ExPolygon &ex : infill_contour)
ex.simplify_p(m_scaled_resolution, &pp);
// 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
this->fill_surfaces->append(
offset_ex(offset2_ex(
union_ex(pp),
float(-min_perimeter_infill_spacing / 2.),
float(min_perimeter_infill_spacing / 2.)), inset),
float(min_perimeter_infill_spacing / 2.)), float(inset)),
stInternal);
}
}