OrcaSlicer/src/libslic3r/Fill/FillConcentric.cpp
Noisyfox 075a08bca8
Initial port of the new ensure vertical thickness algorithm from PrusaSlicer (#2382)
* Initial port of the new ensure vertical thickness algorithm from PrusaSlicer.

Based on prusa3d/PrusaSlicer@1a0d8f5130

* Remove code related to "Detect narrow internal solid infill" as it's handled by the new ensuring code

* Support different internal solid infill pattern

* Ignore removed options

---------

Co-authored-by: Pavel Mikuš <pavel.mikus.mail@seznam.cz>
Co-authored-by: SoftFever <softfeverever@gmail.com>
2023-10-19 19:55:05 +08:00

150 lines
6.3 KiB
C++

///|/ Copyright (c) Prusa Research 2016 - 2023 Vojtěch Bubník @bubnikv, Lukáš Hejl @hejllukas
///|/
///|/ ported from lib/Slic3r/Fill/Concentric.pm:
///|/ Copyright (c) Prusa Research 2016 Vojtěch Bubník @bubnikv
///|/ Copyright (c) Slic3r 2011 - 2015 Alessandro Ranellucci @alranel
///|/ Copyright (c) 2012 Mark Hindess
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#include "../ClipperUtils.hpp"
#include "../ExPolygon.hpp"
#include "../Surface.hpp"
#include "../VariableWidth.hpp"
#include "Arachne/WallToolPaths.hpp"
#include "FillConcentric.hpp"
#include <libslic3r/ShortestPath.hpp>
namespace Slic3r {
void FillConcentric::_fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon expolygon,
Polylines &polylines_out)
{
// no rotation is supported for this infill pattern
BoundingBox bounding_box = expolygon.contour.bounding_box();
coord_t min_spacing = scale_(this->spacing);
coord_t distance = coord_t(min_spacing / params.density);
if (params.density > 0.9999f && !params.dont_adjust) {
distance = this->_adjust_solid_spacing(bounding_box.size()(0), distance);
this->spacing = unscale<double>(distance);
}
Polygons loops = to_polygons(expolygon);
ExPolygons last { std::move(expolygon) };
while (! last.empty()) {
last = offset2_ex(last, -(distance + min_spacing/2), +min_spacing/2);
append(loops, to_polygons(last));
}
// generate paths from the outermost to the innermost, to avoid
// adhesion problems of the first central tiny loops
loops = union_pt_chained_outside_in(loops);
// split paths using a nearest neighbor search
size_t iPathFirst = polylines_out.size();
Point last_pos(0, 0);
for (const Polygon &loop : loops) {
polylines_out.emplace_back(loop.split_at_index(last_pos.nearest_point_index(loop.points)));
last_pos = polylines_out.back().last_point();
}
// clip the paths to prevent the extruder from getting exactly on the first point of the loop
// Keep valid paths only.
size_t j = iPathFirst;
for (size_t i = iPathFirst; i < polylines_out.size(); ++ i) {
polylines_out[i].clip_end(this->loop_clipping);
if (polylines_out[i].is_valid()) {
if (j < i)
polylines_out[j] = std::move(polylines_out[i]);
++ j;
}
}
if (j < polylines_out.size())
polylines_out.erase(polylines_out.begin() + j, polylines_out.end());
//TODO: return ExtrusionLoop objects to get better chained paths,
// otherwise the outermost loop starts at the closest point to (0, 0).
// We want the loops to be split inside the G-code generator to get optimum path planning.
}
void FillConcentric::_fill_surface_single(const FillParams& params,
unsigned int thickness_layers,
const std::pair<float, Point>& direction,
ExPolygon expolygon,
ThickPolylines& thick_polylines_out)
{
assert(params.use_arachne);
assert(this->print_config != nullptr && this->print_object_config != nullptr);
// no rotation is supported for this infill pattern
Point bbox_size = expolygon.contour.bounding_box().size();
coord_t min_spacing = scaled<coord_t>(this->spacing);
if (params.density > 0.9999f && !params.dont_adjust) {
coord_t loops_count = std::max(bbox_size.x(), bbox_size.y()) / min_spacing + 1;
Polygons polygons = offset(expolygon, float(min_spacing) / 2.f);
double min_nozzle_diameter = *std::min_element(print_config->nozzle_diameter.values.begin(), print_config->nozzle_diameter.values.end());
Arachne::WallToolPathsParams input_params;
input_params.min_bead_width = 0.85 * min_nozzle_diameter;
input_params.min_feature_size = 0.25 * min_nozzle_diameter;
input_params.wall_transition_length = 1.0 * min_nozzle_diameter;
input_params.wall_transition_angle = 10;
input_params.wall_transition_filter_deviation = 0.25 * min_nozzle_diameter;
input_params.wall_distribution_count = 1;
Arachne::WallToolPaths wallToolPaths(polygons, min_spacing, min_spacing, loops_count, 0, params.layer_height, input_params);
std::vector<Arachne::VariableWidthLines> loops = wallToolPaths.getToolPaths();
std::vector<const Arachne::ExtrusionLine*> all_extrusions;
for (Arachne::VariableWidthLines& loop : loops) {
if (loop.empty())
continue;
for (const Arachne::ExtrusionLine& wall : loop)
all_extrusions.emplace_back(&wall);
}
// Split paths using a nearest neighbor search.
size_t firts_poly_idx = thick_polylines_out.size();
Point last_pos(0, 0);
for (const Arachne::ExtrusionLine* extrusion : all_extrusions) {
if (extrusion->empty())
continue;
ThickPolyline thick_polyline = Arachne::to_thick_polyline(*extrusion);
if (extrusion->is_closed)
thick_polyline.start_at_index(last_pos.nearest_point_index(thick_polyline.points));
thick_polylines_out.emplace_back(std::move(thick_polyline));
last_pos = thick_polylines_out.back().last_point();
}
// clip the paths to prevent the extruder from getting exactly on the first point of the loop
// Keep valid paths only.
size_t j = firts_poly_idx;
for (size_t i = firts_poly_idx; i < thick_polylines_out.size(); ++i) {
thick_polylines_out[i].clip_end(this->loop_clipping);
if (thick_polylines_out[i].is_valid()) {
if (j < i)
thick_polylines_out[j] = std::move(thick_polylines_out[i]);
++j;
}
}
if (j < thick_polylines_out.size())
thick_polylines_out.erase(thick_polylines_out.begin() + int(j), thick_polylines_out.end());
reorder_by_shortest_traverse(thick_polylines_out);
}
else {
Polylines polylines;
this->_fill_surface_single(params, thickness_layers, direction, expolygon, polylines);
append(thick_polylines_out, to_thick_polylines(std::move(polylines), min_spacing));
}
}
} // namespace Slic3r