update libslic3r

This commit is contained in:
QIDI TECH
2025-08-04 10:13:51 +08:00
parent e3f49c2fb5
commit 8d4d60ec48
96 changed files with 4993 additions and 1903 deletions

View File

@@ -14,6 +14,7 @@
#include <thread>
#include <unordered_set>
#include "OverhangDetector.hpp"
#include "FuzzySkin.hpp"
static const double narrow_loop_length_threshold = 10;
//QDS: when the width of expolygon is smaller than
@@ -44,21 +45,20 @@ public:
bool is_smaller_width_perimeter;
// Depth in the hierarchy. External perimeter has depth = 0. An external perimeter could be both a contour and a hole.
unsigned short depth;
// Should this contur be fuzzyfied on path generation?
bool fuzzify;
// Slow down speed for circle
bool need_circle_compensation = false;
// Children contour, may be both CCW and CW oriented (outer contours or holes).
std::vector<PerimeterGeneratorLoop> children;
PerimeterGeneratorLoop(const Polygon &polygon, unsigned short depth, bool is_contour, bool fuzzify, bool is_small_width_perimeter = false, bool need_circle_compensation_ = false) :
polygon(polygon), is_contour(is_contour), is_smaller_width_perimeter(is_small_width_perimeter), depth(depth), fuzzify(fuzzify), need_circle_compensation(need_circle_compensation_) {}
PerimeterGeneratorLoop(const Polygon &polygon, unsigned short depth, bool is_contour, bool is_small_width_perimeter = false, bool need_circle_compensation_ = false) :
polygon(polygon), is_contour(is_contour), is_smaller_width_perimeter(is_small_width_perimeter), depth(depth), need_circle_compensation(need_circle_compensation_) {}
// External perimeter. It may be CCW or CW oriented (outer contour or hole contour).
bool is_external() const { return this->depth == 0; }
// An island, which may have holes, but it does not have another internal island.
bool is_internal_contour() const;
};
#if 0
// Thanks Cura developers for this function.
static void fuzzy_polygon(Polygon &poly, double fuzzy_skin_thickness, double fuzzy_skin_point_distance)
{
@@ -138,7 +138,7 @@ static void fuzzy_extrusion_line(Arachne::ExtrusionLine& ext_lines, double fuzzy
if (out.size() >= 3)
ext_lines.junctions = std::move(out);
}
#endif
using PerimeterGeneratorLoops = std::vector<PerimeterGeneratorLoop>;
static void lowpass_filter_by_paths_overhang_degree(ExtrusionPaths& paths) {
@@ -454,7 +454,6 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
// loops is an arrayref of ::Loop objects
// turn each one into an ExtrusionLoop object
ExtrusionEntityCollection coll;
Polygon fuzzified;
for (const PerimeterGeneratorLoop &loop : loops) {
bool is_external = loop.is_external();
bool is_small_width = loop.is_smaller_width_perimeter;
@@ -509,12 +508,10 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
extrusion_width = perimeter_generator.perimeter_flow.width();
}
// Apply fuzzy skin if it is enabled for at least some part of the polygon.
const Polygon polygon = apply_fuzzy_skin(loop.polygon, *(perimeter_generator.config), *(perimeter_generator.perimeter_regions),
perimeter_generator.layer_id, loop.depth, loop.is_contour);
const Polygon &polygon = loop.fuzzify ? fuzzified : loop.polygon;
if (loop.fuzzify) {
fuzzified = loop.polygon;
fuzzy_polygon(fuzzified, scaled<float>(perimeter_generator.config->fuzzy_skin_thickness.value), scaled<float>(perimeter_generator.config->fuzzy_skin_point_distance.value));
}
if (perimeter_generator.config->detect_overhang_wall && perimeter_generator.layer_id > perimeter_generator.object_config->raft_layers) {
// get non 100% overhang paths by intersecting this loop with the grown lower slices
// prepare grown lower layer slices for overhang detection
@@ -534,22 +531,6 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
bool detect_overhang_degree = perimeter_generator.config->enable_overhang_speed.get_at(get_extruder_index(*(perimeter_generator.print_config), perimeter_generator.config->wall_filament - 1))
&& perimeter_generator.config->fuzzy_skin == FuzzySkinType::None;
//QDS: fuzziy skin may generate a line that approximates a point, which can cause the clipper to get empty results
if (loop.fuzzify && remain_polines.empty() && inside_polines.empty()) {
bool inside_contour = false;
for (const Polygon cliped_polygon : lower_polygons_series_clipped) {
if (cliped_polygon.contains(polygon.first_point())) {
inside_contour = true;
break;
}
}
if (inside_contour)
inside_polines.push_back(to_polyline(polygon));
else
remain_polines.push_back(to_polyline(polygon));
}
if (!detect_overhang_degree) {
if (!inside_polines.empty())
extrusion_paths_append(
@@ -597,12 +578,14 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
}
}
// get 100% overhang paths by checking what parts of this loop fall
// outside the grown lower slices (thus where the distance between
// the loop centerline and original lower slices is >= half nozzle diameter
if (remain_polines.size() != 0) {
if (!((perimeter_generator.object_config->enable_support || perimeter_generator.object_config->enforce_support_layers > 0)
&& perimeter_generator.object_config->support_top_z_distance.value == 0)) {
if (!((perimeter_generator.object_config->enable_support || perimeter_generator.object_config->enforce_support_layers > 0) &&
perimeter_generator.object_config->support_top_z_distance.value == 0) &&
detect_overhang_degree) {
//detect if the overhang perimeter is bridge
detect_bridge_wall(perimeter_generator,
paths,
@@ -623,6 +606,9 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
}
if (paths.empty())
continue;
// Reapply the nearest point search for starting point.
// We allow polyline reversal because Clipper may have randomly reversed polylines during clipping.
chain_and_reorder_extrusion_paths(paths, &paths.front().first_point());
@@ -847,8 +833,9 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
perimeter_generator.loop_nodes->push_back(std::move(node));
}
if (pg_extrusion.fuzzify)
fuzzy_extrusion_line(*extrusion, scaled<float>(perimeter_generator.config->fuzzy_skin_thickness.value), scaled<float>(perimeter_generator.config->fuzzy_skin_point_distance.value));
// Apply fuzzy skin if it is enabled for at least some part of the ExtrusionLine.
*extrusion = apply_fuzzy_skin(*extrusion, *(perimeter_generator.config), *(perimeter_generator.perimeter_regions), perimeter_generator.layer_id,
pg_extrusion.extrusion->inset_idx, !pg_extrusion.extrusion->is_closed || pg_extrusion.is_contour);
ExtrusionPaths paths;
// detect overhanging/bridging perimeters
@@ -1245,19 +1232,17 @@ void PerimeterGenerator::process_classic()
break;
}
{
const bool fuzzify_contours = this->config->fuzzy_skin != FuzzySkinType::None && ((i == 0 && this->layer_id > 0) || this->config->fuzzy_skin == FuzzySkinType::AllWalls);
const bool fuzzify_holes = fuzzify_contours && (this->config->fuzzy_skin == FuzzySkinType::All || this->config->fuzzy_skin == FuzzySkinType::AllWalls);
for (const ExPolygon& expolygon : offsets) {
// Outer contour may overlap with an inner contour,
// inner contour may overlap with another inner contour,
// outer contour may overlap with itself.
//FIXME evaluate the overlaps, annotate each point with an overlap depth,
// compensate for the depth of intersection.
contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true, fuzzify_contours, false, counter_circle_compensation));
contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true, false, counter_circle_compensation));
if (!expolygon.holes.empty()) {
holes[i].reserve(holes[i].size() + expolygon.holes.size());
for (const Polygon &hole : expolygon.holes)
holes[i].emplace_back(hole, i, false, fuzzify_holes, false, is_compensation_hole(hole));
holes[i].emplace_back(hole, i, false, false, is_compensation_hole(hole));
}
}
@@ -1293,11 +1278,11 @@ void PerimeterGenerator::process_classic()
}
for (const ExPolygon& expolygon : offsets_with_smaller_width) {
contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true, fuzzify_contours, true, counter_circle_compensation));
contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true, true, counter_circle_compensation));
if (!expolygon.holes.empty()) {
holes[i].reserve(holes[i].size() + expolygon.holes.size());
for (const Polygon& hole : expolygon.holes)
holes[i].emplace_back(PerimeterGeneratorLoop(hole, i, false, fuzzify_contours, true, is_compensation_hole(hole)));
holes[i].emplace_back(PerimeterGeneratorLoop(hole, i, false, true, is_compensation_hole(hole)));
}
}
}
@@ -1934,46 +1919,6 @@ void PerimeterGenerator::process_arachne()
}
}
if (this->layer_id > 0 && this->config->fuzzy_skin != FuzzySkinType::None) {
std::vector<PerimeterGeneratorArachneExtrusion*> closed_loop_extrusions;
for (PerimeterGeneratorArachneExtrusion& extrusion : ordered_extrusions)
if (extrusion.extrusion->inset_idx == 0) {
if (extrusion.extrusion->is_closed && this->config->fuzzy_skin == FuzzySkinType::External) {
closed_loop_extrusions.emplace_back(&extrusion);
}
else {
extrusion.fuzzify = true;
}
}
if (this->config->fuzzy_skin == FuzzySkinType::External) {
ClipperLib_Z::Paths loops_paths;
loops_paths.reserve(closed_loop_extrusions.size());
for (const auto& cl_extrusion : closed_loop_extrusions) {
assert(cl_extrusion->extrusion->junctions.front() == cl_extrusion->extrusion->junctions.back());
size_t loop_idx = &cl_extrusion - &closed_loop_extrusions.front();
ClipperLib_Z::Path loop_path;
loop_path.reserve(cl_extrusion->extrusion->junctions.size() - 1);
for (auto junction_it = cl_extrusion->extrusion->junctions.begin(); junction_it != std::prev(cl_extrusion->extrusion->junctions.end()); ++junction_it)
loop_path.emplace_back(junction_it->p.x(), junction_it->p.y(), loop_idx);
loops_paths.emplace_back(loop_path);
}
ClipperLib_Z::Clipper clipper;
clipper.AddPaths(loops_paths, ClipperLib_Z::ptSubject, true);
ClipperLib_Z::PolyTree loops_polytree;
clipper.Execute(ClipperLib_Z::ctUnion, loops_polytree, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd);
for (const ClipperLib_Z::PolyNode* child_node : loops_polytree.Childs) {
// The whole contour must have the same index.
coord_t polygon_idx = child_node->Contour.front().z();
bool has_same_idx = std::all_of(child_node->Contour.begin(), child_node->Contour.end(),
[&polygon_idx](const ClipperLib_Z::IntPoint& point) -> bool { return polygon_idx == point.z(); });
if (has_same_idx)
closed_loop_extrusions[polygon_idx]->fuzzify = true;
}
}
}
// QDS. adjust wall generate seq
if (this->object_config->wall_sequence == WallSequence::InnerOuterInner) {
if (ordered_extrusions.size() > 2) { // 3 walls minimum needed to do inner outer inner ordering
@@ -2092,4 +2037,38 @@ std::vector<Polygons> PerimeterGenerator::generate_lower_polygons_series(float w
return lower_polygons_series;
}
PerimeterRegion::PerimeterRegion(const LayerRegion &layer_region) : region(&layer_region.region())
{
this->expolygons = to_expolygons(layer_region.slices.surfaces);
this->bbox = get_extents(this->expolygons);
}
bool PerimeterRegion::has_compatible_perimeter_regions(const PrintRegionConfig &config, const PrintRegionConfig &other_config)
{
return config.fuzzy_skin == other_config.fuzzy_skin && config.fuzzy_skin_thickness == other_config.fuzzy_skin_thickness
&& config.fuzzy_skin_point_distance == other_config.fuzzy_skin_point_distance;
}
void PerimeterRegion::merge_compatible_perimeter_regions(PerimeterRegions &perimeter_regions)
{
if (perimeter_regions.size() <= 1) { return; }
PerimeterRegions perimeter_regions_merged;
for (auto it_curr_region = perimeter_regions.begin(); it_curr_region != perimeter_regions.end();) {
PerimeterRegion current_merge = *it_curr_region;
auto it_next_region = std::next(it_curr_region);
for (; it_next_region != perimeter_regions.end() && has_compatible_perimeter_regions(it_next_region->region->config(), it_curr_region->region->config());
++it_next_region) {
Slic3r::append(current_merge.expolygons, std::move(it_next_region->expolygons));
current_merge.bbox.merge(it_next_region->bbox);
}
if (std::distance(it_curr_region, it_next_region) > 1) { current_merge.expolygons = union_ex(current_merge.expolygons); }
perimeter_regions_merged.emplace_back(std::move(current_merge));
it_curr_region = it_next_region;
}
perimeter_regions = perimeter_regions_merged;
}
}