mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-14 10:17:55 -06:00
Improve fuzzy skin with modifier (#6759)
* Pass all compatible regions to perimeter generator * Simplify & unify fuzzify detection * Simplify `to_thick_polyline` * Group regions by fuzzy skin settings * Initial code structure of multi-regional fuzzy skin * Determine fuzzy type by all compatible regions * Add fuzzy region debug * Implement the line split algorithm * Do splitted fuzzy in classic mode * Disable debug macros * Fix infinit loop issue when segment points are out of order * Fix path connection * Implement splitted fuzzy in Arachne mode
This commit is contained in:
parent
3d3633f110
commit
9d3d242453
12 changed files with 707 additions and 92 deletions
|
@ -20,6 +20,8 @@
|
|||
#include <unordered_set>
|
||||
#include <thread>
|
||||
#include "libslic3r/AABBTreeLines.hpp"
|
||||
#include "Print.hpp"
|
||||
#include "Algorithm/LineSplit.hpp"
|
||||
static const int overhang_sampling_number = 6;
|
||||
static const double narrow_loop_length_threshold = 10;
|
||||
static const double min_degree_gap = 0.1;
|
||||
|
@ -29,6 +31,8 @@ static const int max_overhang_degree = overhang_sampling_number - 1;
|
|||
//we think it's small detail area and will generate smaller line width for it
|
||||
static constexpr double SMALLER_EXT_INSET_OVERLAP_TOLERANCE = 0.22;
|
||||
|
||||
//#define DEBUG_FUZZY
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Produces a random value between 0 and 1. Thread-safe.
|
||||
|
@ -51,13 +55,11 @@ 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;
|
||||
// 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) :
|
||||
polygon(polygon), is_contour(is_contour), is_smaller_width_perimeter(is_small_width_perimeter), depth(depth), fuzzify(fuzzify) {}
|
||||
PerimeterGeneratorLoop(const Polygon &polygon, unsigned short depth, bool is_contour, bool is_small_width_perimeter = false) :
|
||||
polygon(polygon), is_contour(is_contour), is_smaller_width_perimeter(is_small_width_perimeter), depth(depth) {}
|
||||
// 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.
|
||||
|
@ -65,23 +67,30 @@ public:
|
|||
};
|
||||
|
||||
// Thanks Cura developers for this function.
|
||||
static void fuzzy_polygon(Polygon &poly, double fuzzy_skin_thickness, double fuzzy_skin_point_distance)
|
||||
static void fuzzy_polyline(Points& poly, bool closed, const FuzzySkinConfig& cfg)
|
||||
{
|
||||
const double min_dist_between_points = fuzzy_skin_point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value
|
||||
const double range_random_point_dist = fuzzy_skin_point_distance / 2.;
|
||||
const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value
|
||||
const double range_random_point_dist = cfg.point_distance / 2.;
|
||||
double dist_left_over = random_value() * (min_dist_between_points / 2.); // the distance to be traversed on the line before making the first new point
|
||||
Point* p0 = &poly.points.back();
|
||||
Point* p0 = &poly.back();
|
||||
Points out;
|
||||
out.reserve(poly.points.size());
|
||||
for (Point &p1 : poly.points)
|
||||
{ // 'a' is the (next) new point between p0 and p1
|
||||
out.reserve(poly.size());
|
||||
for (Point &p1 : poly)
|
||||
{
|
||||
if (!closed) {
|
||||
// Skip the first point for open path
|
||||
closed = true;
|
||||
p0 = &p1;
|
||||
continue;
|
||||
}
|
||||
// 'a' is the (next) new point between p0 and p1
|
||||
Vec2d p0p1 = (p1 - *p0).cast<double>();
|
||||
double p0p1_size = p0p1.norm();
|
||||
double p0pa_dist = dist_left_over;
|
||||
for (; p0pa_dist < p0p1_size;
|
||||
p0pa_dist += min_dist_between_points + random_value() * range_random_point_dist)
|
||||
{
|
||||
double r = random_value() * (fuzzy_skin_thickness * 2.) - fuzzy_skin_thickness;
|
||||
double r = random_value() * (cfg.thickness * 2.) - cfg.thickness;
|
||||
out.emplace_back(*p0 + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast<double>().normalized() * r).cast<coord_t>());
|
||||
}
|
||||
dist_left_over = p0pa_dist - p0p1_size;
|
||||
|
@ -95,14 +104,14 @@ static void fuzzy_polygon(Polygon &poly, double fuzzy_skin_thickness, double fuz
|
|||
-- point_idx;
|
||||
}
|
||||
if (out.size() >= 3)
|
||||
poly.points = std::move(out);
|
||||
poly = std::move(out);
|
||||
}
|
||||
|
||||
// Thanks Cura developers for this function.
|
||||
static void fuzzy_extrusion_line(Arachne::ExtrusionLine& ext_lines, double fuzzy_skin_thickness, double fuzzy_skin_point_dist)
|
||||
static void fuzzy_extrusion_line(std::vector<Arachne::ExtrusionJunction>& ext_lines, const FuzzySkinConfig& cfg)
|
||||
{
|
||||
const double min_dist_between_points = fuzzy_skin_point_dist * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value
|
||||
const double range_random_point_dist = fuzzy_skin_point_dist / 2.;
|
||||
const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value
|
||||
const double range_random_point_dist = cfg.point_distance / 2.;
|
||||
double dist_left_over = random_value() * (min_dist_between_points / 2.); // the distance to be traversed on the line before making the first new point
|
||||
|
||||
auto* p0 = &ext_lines.front();
|
||||
|
@ -119,7 +128,7 @@ static void fuzzy_extrusion_line(Arachne::ExtrusionLine& ext_lines, double fuzzy
|
|||
double p0p1_size = p0p1.norm();
|
||||
double p0pa_dist = dist_left_over;
|
||||
for (; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + random_value() * range_random_point_dist) {
|
||||
double r = random_value() * (fuzzy_skin_thickness * 2.) - fuzzy_skin_thickness;
|
||||
double r = random_value() * (cfg.thickness * 2.) - cfg.thickness;
|
||||
out.emplace_back(p0->p + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast<double>().normalized() * r).cast<coord_t>(), p1.w, p1.perimeter_index);
|
||||
}
|
||||
dist_left_over = p0pa_dist - p0p1_size;
|
||||
|
@ -138,7 +147,7 @@ static void fuzzy_extrusion_line(Arachne::ExtrusionLine& ext_lines, double fuzzy
|
|||
out.front().p = out.back().p;
|
||||
|
||||
if (out.size() >= 3)
|
||||
ext_lines.junctions = std::move(out);
|
||||
ext_lines = std::move(out);
|
||||
}
|
||||
|
||||
using PerimeterGeneratorLoops = std::vector<PerimeterGeneratorLoop>;
|
||||
|
@ -453,6 +462,24 @@ static bool detect_steep_overhang(const PrintRegionConfig *config,
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool should_fuzzify(const FuzzySkinConfig& config, const int layer_id, const size_t loop_idx, const bool is_contour)
|
||||
{
|
||||
const auto fuzziy_type = config.type;
|
||||
|
||||
if (fuzziy_type == FuzzySkinType::None) {
|
||||
return false;
|
||||
}
|
||||
if (!config.fuzzy_first_layer && layer_id <= 0) {
|
||||
// Do not fuzzy first layer unless told to
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool fuzzify_contours = loop_idx == 0 || fuzziy_type == FuzzySkinType::AllWalls;
|
||||
const bool fuzzify_holes = fuzzify_contours && (fuzziy_type == FuzzySkinType::All || fuzziy_type == FuzzySkinType::AllWalls);
|
||||
|
||||
return is_contour ? fuzzify_contours : fuzzify_holes;
|
||||
}
|
||||
|
||||
static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perimeter_generator, const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls,
|
||||
bool &steep_overhang_contour, bool &steep_overhang_hole)
|
||||
{
|
||||
|
@ -480,9 +507,6 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
|||
} else {
|
||||
loop_role = loop.is_contour? elrDefault : elrHole;
|
||||
}
|
||||
|
||||
// detect overhanging/bridging perimeters
|
||||
ExtrusionPaths paths;
|
||||
|
||||
// BBS: get lower polygons series, width, mm3_per_mm
|
||||
const std::vector<Polygons> *lower_polygons_series;
|
||||
|
@ -510,24 +534,113 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
|||
extrusion_mm3_per_mm = perimeter_generator.mm3_per_mm();
|
||||
extrusion_width = perimeter_generator.perimeter_flow.width();
|
||||
}
|
||||
const Polygon& polygon = *([&perimeter_generator, &loop, &fuzzified]() ->const Polygon* {
|
||||
const auto& regions = perimeter_generator.regions_by_fuzzify;
|
||||
if (regions.size() == 1) { // optimization
|
||||
const auto& config = regions.begin()->first;
|
||||
const bool fuzzify = should_fuzzify(config, perimeter_generator.layer_id, loop.depth, loop.is_contour);
|
||||
if (!fuzzify) {
|
||||
return &loop.polygon;
|
||||
}
|
||||
|
||||
fuzzified = loop.polygon;
|
||||
fuzzy_polyline(fuzzified.points, true, config);
|
||||
return &fuzzified;
|
||||
}
|
||||
|
||||
const Polygon &polygon = loop.fuzzify ? fuzzified : loop.polygon;
|
||||
if (loop.fuzzify) {
|
||||
// Find all affective regions
|
||||
std::vector<std::pair<const FuzzySkinConfig&, const ExPolygons&>> fuzzified_regions;
|
||||
fuzzified_regions.reserve(regions.size());
|
||||
for (const auto & region : regions) {
|
||||
if (should_fuzzify(region.first, perimeter_generator.layer_id, loop.depth, loop.is_contour)) {
|
||||
fuzzified_regions.emplace_back(region.first, region.second);
|
||||
}
|
||||
}
|
||||
if (fuzzified_regions.empty()) {
|
||||
return &loop.polygon;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FUZZY
|
||||
{
|
||||
int i = 0;
|
||||
for (const auto & r : fuzzified_regions) {
|
||||
BoundingBox bbox = get_extents(perimeter_generator.slices->surfaces);
|
||||
bbox.offset(scale_(1.));
|
||||
::Slic3r::SVG svg(debug_out_path("fuzzy_traverse_loops_%d_%d_%d_region_%d.svg", perimeter_generator.layer_id, loop.is_contour ? 0 : 1, loop.depth, i).c_str(), bbox);
|
||||
svg.draw_outline(perimeter_generator.slices->surfaces);
|
||||
svg.draw_outline(loop.polygon, "green");
|
||||
svg.draw(r.second, "red", 0.5);
|
||||
svg.draw_outline(r.second, "red");
|
||||
svg.Close();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Split the loops into lines with different config, and fuzzy them separately
|
||||
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));
|
||||
}
|
||||
for (const auto& r : fuzzified_regions) {
|
||||
const auto splitted = Algorithm::split_line(fuzzified, r.second, true);
|
||||
if (splitted.empty()) {
|
||||
// No intersection, skip
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fuzzy splitted polygon
|
||||
if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) {
|
||||
// The entire polygon is fuzzified
|
||||
fuzzy_polyline(fuzzified.points, true, r.first);
|
||||
} else {
|
||||
Points segment;
|
||||
segment.reserve(splitted.size());
|
||||
fuzzified.points.clear();
|
||||
|
||||
const auto fuzzy_current_segment = [&segment, &fuzzified, &r]() {
|
||||
fuzzified.points.push_back(segment.front());
|
||||
const auto back = segment.back();
|
||||
fuzzy_polyline(segment, false, r.first);
|
||||
fuzzified.points.insert(fuzzified.points.end(), segment.begin(), segment.end());
|
||||
fuzzified.points.push_back(back);
|
||||
segment.clear();
|
||||
};
|
||||
|
||||
for (const auto& p : splitted) {
|
||||
if (p.clipped) {
|
||||
segment.push_back(p.p);
|
||||
} else {
|
||||
if (segment.empty()) {
|
||||
fuzzified.points.push_back(p.p);
|
||||
} else {
|
||||
segment.push_back(p.p);
|
||||
fuzzy_current_segment();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!segment.empty()) {
|
||||
// Close the loop
|
||||
segment.push_back(splitted.front().p);
|
||||
fuzzy_current_segment();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &fuzzified;
|
||||
}());
|
||||
|
||||
ExtrusionPaths paths;
|
||||
if (perimeter_generator.config->detect_overhang_wall && perimeter_generator.layer_id > perimeter_generator.object_config->raft_layers) {
|
||||
// detect overhanging/bridging perimeters
|
||||
|
||||
// get non 100% overhang paths by intersecting this loop with the grown lower slices
|
||||
// prepare grown lower layer slices for overhang detection
|
||||
BoundingBox bbox(polygon.points);
|
||||
bbox.offset(SCALED_EPSILON);
|
||||
|
||||
// Always reverse extrusion if use fuzzy skin: https://github.com/SoftFever/OrcaSlicer/pull/2413#issuecomment-1769735357
|
||||
if (overhangs_reverse && perimeter_generator.config->fuzzy_skin != FuzzySkinType::None) {
|
||||
if (overhangs_reverse && perimeter_generator.has_fuzzy_skin) {
|
||||
if (loop.is_contour) {
|
||||
steep_overhang_contour = true;
|
||||
} else if (perimeter_generator.config->fuzzy_skin != FuzzySkinType::External) {
|
||||
} else if (perimeter_generator.has_fuzzy_hole) {
|
||||
steep_overhang_hole = true;
|
||||
}
|
||||
}
|
||||
|
@ -548,7 +661,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
|||
|
||||
remain_polines = diff_pl({polygon}, lower_polygons_series_clipped);
|
||||
|
||||
bool detect_overhang_degree = perimeter_generator.config->overhang_speed_classic && perimeter_generator.config->enable_overhang_speed && perimeter_generator.config->fuzzy_skin == FuzzySkinType::None;
|
||||
bool detect_overhang_degree = perimeter_generator.config->overhang_speed_classic && perimeter_generator.config->enable_overhang_speed && !perimeter_generator.has_fuzzy_skin;
|
||||
|
||||
if (!detect_overhang_degree) {
|
||||
if (!inside_polines.empty())
|
||||
|
@ -762,8 +875,6 @@ struct PerimeterGeneratorArachneExtrusion
|
|||
Arachne::ExtrusionLine* extrusion = nullptr;
|
||||
// Indicates if closed ExtrusionLine is a contour or a hole. Used it only when ExtrusionLine is a closed loop.
|
||||
bool is_contour = false;
|
||||
// Should this extrusion be fuzzyfied on path generation?
|
||||
bool fuzzify = false;
|
||||
};
|
||||
|
||||
|
||||
|
@ -866,8 +977,77 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
|
|||
const bool is_external = extrusion->inset_idx == 0;
|
||||
ExtrusionRole role = is_external ? erExternalPerimeter : erPerimeter;
|
||||
|
||||
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));
|
||||
const auto& regions = perimeter_generator.regions_by_fuzzify;
|
||||
const bool is_contour = !extrusion->is_closed || pg_extrusion.is_contour;
|
||||
if (regions.size() == 1) { // optimization
|
||||
const auto& config = regions.begin()->first;
|
||||
const bool fuzzify = should_fuzzify(config, perimeter_generator.layer_id, extrusion->inset_idx, is_contour);
|
||||
if (fuzzify)
|
||||
fuzzy_extrusion_line(extrusion->junctions, config);
|
||||
} else {
|
||||
// Find all affective regions
|
||||
std::vector<std::pair<const FuzzySkinConfig&, const ExPolygons&>> fuzzified_regions;
|
||||
fuzzified_regions.reserve(regions.size());
|
||||
for (const auto& region : regions) {
|
||||
if (should_fuzzify(region.first, perimeter_generator.layer_id, extrusion->inset_idx, is_contour)) {
|
||||
fuzzified_regions.emplace_back(region.first, region.second);
|
||||
}
|
||||
}
|
||||
if (!fuzzified_regions.empty()) {
|
||||
// Split the loops into lines with different config, and fuzzy them separately
|
||||
for (const auto& r : fuzzified_regions) {
|
||||
const auto splitted = Algorithm::split_line(*extrusion, r.second, false);
|
||||
if (splitted.empty()) {
|
||||
// No intersection, skip
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fuzzy splitted extrusion
|
||||
if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) {
|
||||
// The entire polygon is fuzzified
|
||||
fuzzy_extrusion_line(extrusion->junctions, r.first);
|
||||
} else {
|
||||
const auto current_ext = extrusion->junctions;
|
||||
std::vector<Arachne::ExtrusionJunction> segment;
|
||||
segment.reserve(current_ext.size());
|
||||
extrusion->junctions.clear();
|
||||
|
||||
const auto fuzzy_current_segment = [&segment, extrusion, &r]() {
|
||||
extrusion->junctions.push_back(segment.front());
|
||||
const auto back = segment.back();
|
||||
fuzzy_extrusion_line(segment, r.first);
|
||||
extrusion->junctions.insert(extrusion->junctions.end(), segment.begin(), segment.end());
|
||||
extrusion->junctions.push_back(back);
|
||||
segment.clear();
|
||||
};
|
||||
|
||||
const auto to_ex_junction = [¤t_ext](const Algorithm::SplitLineJunction& j) -> Arachne::ExtrusionJunction {
|
||||
Arachne::ExtrusionJunction res = current_ext[j.get_src_index()];
|
||||
if (!j.is_src()) {
|
||||
res.p = j.p;
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
for (const auto& p : splitted) {
|
||||
if (p.clipped) {
|
||||
segment.push_back(to_ex_junction(p));
|
||||
} else {
|
||||
if (segment.empty()) {
|
||||
extrusion->junctions.push_back(to_ex_junction(p));
|
||||
} else {
|
||||
segment.push_back(to_ex_junction(p));
|
||||
fuzzy_current_segment();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!segment.empty()) {
|
||||
fuzzy_current_segment();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExtrusionPaths paths;
|
||||
// detect overhanging/bridging perimeters
|
||||
|
@ -904,10 +1084,10 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
|
|||
is_external ? perimeter_generator.ext_perimeter_flow : perimeter_generator.perimeter_flow);
|
||||
|
||||
// Always reverse extrusion if use fuzzy skin: https://github.com/SoftFever/OrcaSlicer/pull/2413#issuecomment-1769735357
|
||||
if (overhangs_reverse && perimeter_generator.config->fuzzy_skin != FuzzySkinType::None) {
|
||||
if (overhangs_reverse && perimeter_generator.has_fuzzy_skin) {
|
||||
if (pg_extrusion.is_contour) {
|
||||
steep_overhang_contour = true;
|
||||
} else if (perimeter_generator.config->fuzzy_skin != FuzzySkinType::External) {
|
||||
} else if (perimeter_generator.has_fuzzy_hole) {
|
||||
steep_overhang_hole = true;
|
||||
}
|
||||
}
|
||||
|
@ -938,7 +1118,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
|
|||
}
|
||||
}
|
||||
|
||||
if (perimeter_generator.config->overhang_speed_classic && perimeter_generator.config->enable_overhang_speed && perimeter_generator.config->fuzzy_skin == FuzzySkinType::None) {
|
||||
if (perimeter_generator.config->overhang_speed_classic && perimeter_generator.config->enable_overhang_speed && !perimeter_generator.has_fuzzy_skin) {
|
||||
|
||||
Flow flow = is_external ? perimeter_generator.ext_perimeter_flow : perimeter_generator.perimeter_flow;
|
||||
std::map<double, std::vector<Polygons>> clipper_serise;
|
||||
|
@ -1031,7 +1211,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
|
|||
|
||||
chain_and_reorder_extrusion_paths(paths, &start_point);
|
||||
|
||||
if (perimeter_generator.config->enable_overhang_speed && perimeter_generator.config->fuzzy_skin == FuzzySkinType::None) {
|
||||
if (perimeter_generator.config->enable_overhang_speed && !perimeter_generator.has_fuzzy_skin) {
|
||||
// BBS: filter the speed
|
||||
smooth_overhang_level(paths);
|
||||
}
|
||||
|
@ -1642,8 +1822,48 @@ static void reorient_perimeters(ExtrusionEntityCollection &entities, bool steep_
|
|||
}
|
||||
}
|
||||
|
||||
static void group_region_by_fuzzify(PerimeterGenerator& g)
|
||||
{
|
||||
g.regions_by_fuzzify.clear();
|
||||
g.has_fuzzy_skin = false;
|
||||
g.has_fuzzy_hole = false;
|
||||
|
||||
std::unordered_map<FuzzySkinConfig, SurfacesPtr> regions;
|
||||
for (auto region : *g.compatible_regions) {
|
||||
const auto& region_config = region->region().config();
|
||||
const FuzzySkinConfig cfg{
|
||||
region_config.fuzzy_skin,
|
||||
scaled<coord_t>(region_config.fuzzy_skin_thickness.value),
|
||||
scaled<coord_t>(region_config.fuzzy_skin_point_distance.value),
|
||||
region_config.fuzzy_skin_first_layer
|
||||
};
|
||||
auto& surfaces = regions[cfg];
|
||||
for (const auto& surface : region->slices.surfaces) {
|
||||
surfaces.push_back(&surface);
|
||||
}
|
||||
|
||||
if (cfg.type != FuzzySkinType::None) {
|
||||
g.has_fuzzy_skin = true;
|
||||
if (cfg.type != FuzzySkinType::External) {
|
||||
g.has_fuzzy_hole = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (regions.size() == 1) { // optimization
|
||||
g.regions_by_fuzzify[regions.begin()->first] = {};
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& it : regions) {
|
||||
g.regions_by_fuzzify[it.first] = offset_ex(it.second, ClipperSafetyOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void PerimeterGenerator::process_classic()
|
||||
{
|
||||
group_region_by_fuzzify(*this);
|
||||
|
||||
// other perimeters
|
||||
m_mm3_per_mm = this->perimeter_flow.mm3_per_mm();
|
||||
coord_t perimeter_width = this->perimeter_flow.scaled_width();
|
||||
|
@ -1716,7 +1936,7 @@ void PerimeterGenerator::process_classic()
|
|||
|
||||
process_no_bridge(all_surfaces, perimeter_spacing, ext_perimeter_width);
|
||||
// BBS: don't simplify too much which influence arc fitting when export gcode if arc_fitting is enabled
|
||||
double surface_simplify_resolution = (print_config->enable_arc_fitting && this->config->fuzzy_skin == FuzzySkinType::None) ? 0.2 * m_scaled_resolution : m_scaled_resolution;
|
||||
double surface_simplify_resolution = (print_config->enable_arc_fitting && !this->has_fuzzy_skin) ? 0.2 * m_scaled_resolution : m_scaled_resolution;
|
||||
//BBS: reorder the surface to reduce the travel time
|
||||
ExPolygons surface_exp;
|
||||
for (const Surface &surface : all_surfaces)
|
||||
|
@ -1845,32 +2065,29 @@ void PerimeterGenerator::process_classic()
|
|||
break;
|
||||
}
|
||||
{
|
||||
const bool fuzzify_layer = (this->config->fuzzy_skin_first_layer || this->layer_id>0) && this->config->fuzzy_skin != FuzzySkinType::None;
|
||||
const bool fuzzify_contours = fuzzify_layer && (i == 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(expolygon.contour, i, true, fuzzify_contours);
|
||||
contours[i].emplace_back(expolygon.contour, i, true);
|
||||
|
||||
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);
|
||||
holes[i].emplace_back(hole, i, false);
|
||||
}
|
||||
}
|
||||
|
||||
//BBS: save perimeter loop which use smaller width
|
||||
if (i == 0) {
|
||||
for (const ExPolygon& expolygon : offsets_with_smaller_width) {
|
||||
contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true, fuzzify_contours, true));
|
||||
contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true, true));
|
||||
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));
|
||||
holes[i].emplace_back(PerimeterGeneratorLoop(hole, i, false, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2607,6 +2824,8 @@ void bringContoursToFront(std::vector<PerimeterGeneratorArachneExtrusion>& order
|
|||
// "A framework for adaptive width control of dense contour-parallel toolpaths in fused deposition modeling"
|
||||
void PerimeterGenerator::process_arachne()
|
||||
{
|
||||
group_region_by_fuzzify(*this);
|
||||
|
||||
// other perimeters
|
||||
m_mm3_per_mm = this->perimeter_flow.mm3_per_mm();
|
||||
coord_t perimeter_spacing = this->perimeter_flow.scaled_spacing();
|
||||
|
@ -2635,7 +2854,7 @@ void PerimeterGenerator::process_arachne()
|
|||
|
||||
process_no_bridge(all_surfaces, perimeter_spacing, ext_perimeter_width);
|
||||
// BBS: don't simplify too much which influence arc fitting when export gcode if arc_fitting is enabled
|
||||
double surface_simplify_resolution = (print_config->enable_arc_fitting && this->config->fuzzy_skin == FuzzySkinType::None) ? 0.2 * m_scaled_resolution : m_scaled_resolution;
|
||||
double surface_simplify_resolution = (print_config->enable_arc_fitting && !this->has_fuzzy_skin) ? 0.2 * m_scaled_resolution : m_scaled_resolution;
|
||||
// we need to process each island separately because we might have different
|
||||
// extra perimeters for each one
|
||||
for (const Surface& surface : all_surfaces) {
|
||||
|
@ -2845,7 +3064,7 @@ void PerimeterGenerator::process_arachne()
|
|||
}
|
||||
|
||||
auto& best_path = all_extrusions[best_candidate];
|
||||
ordered_extrusions.push_back({ best_path, best_path->is_contour(), false });
|
||||
ordered_extrusions.push_back({ best_path, best_path->is_contour() });
|
||||
processed[best_candidate] = true;
|
||||
for (size_t unlocked_idx : blocking[best_candidate])
|
||||
blocked[unlocked_idx]--;
|
||||
|
@ -2857,21 +3076,6 @@ void PerimeterGenerator::process_arachne()
|
|||
current_position = best_path->junctions.back().p; //Pick the other end from where we started.
|
||||
}
|
||||
}
|
||||
const bool fuzzify_layer = (this->config->fuzzy_skin_first_layer || this->layer_id>0) && this->config->fuzzy_skin != FuzzySkinType::None;
|
||||
if (fuzzify_layer) {
|
||||
for (PerimeterGeneratorArachneExtrusion& extrusion : ordered_extrusions) {
|
||||
if (this->config->fuzzy_skin == FuzzySkinType::AllWalls) {
|
||||
extrusion.fuzzify = true;
|
||||
} else if (extrusion.extrusion->inset_idx == 0) {
|
||||
if (extrusion.extrusion->is_closed && this->config->fuzzy_skin == FuzzySkinType::External) {
|
||||
extrusion.fuzzify = extrusion.is_contour;
|
||||
}
|
||||
else {
|
||||
extrusion.fuzzify = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// printf("New Layer: Layer ID %d\n",layer_id); //debug - new layer
|
||||
if (this->config->wall_sequence == WallSequence::InnerOuterInner && layer_id > 0) { // only enable inner outer inner algorithm after first layer
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue