mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-11 05:31:47 +08:00
fix issues, new implemenetation affecting all extrusions
This commit is contained in:
parent
38a287fec4
commit
0fdb545b55
@ -1,7 +1,5 @@
|
|||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
#include "ExPolygon.hpp"
|
#include "GCode/ExtrusionProcessor.hpp"
|
||||||
#include "Flow.hpp"
|
|
||||||
#include "GCode/OverhangProcessor.hpp"
|
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
#include "GCode.hpp"
|
#include "GCode.hpp"
|
||||||
#include "Exception.hpp"
|
#include "Exception.hpp"
|
||||||
@ -41,7 +39,6 @@
|
|||||||
#include "SVG.hpp"
|
#include "SVG.hpp"
|
||||||
|
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
// Intel redesigned some TBB interface considerably when merging TBB with their oneAPI set of libraries, see GH #7332.
|
// Intel redesigned some TBB interface considerably when merging TBB with their oneAPI set of libraries, see GH #7332.
|
||||||
// We are using quite an old TBB 2017 U7. Before we update our build servers, let's use the old API, which is deprecated in up to date TBB.
|
// We are using quite an old TBB 2017 U7. Before we update our build servers, let's use the old API, which is deprecated in up to date TBB.
|
||||||
@ -2172,12 +2169,12 @@ LayerResult GCode::process_layer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Linef> layer_lines;
|
std::vector<const Layer*> layers_ptrs;
|
||||||
|
layers_ptrs.reserve(layers.size());
|
||||||
for (const LayerToPrint &layer_to_print : layers) {
|
for (const LayerToPrint &layer_to_print : layers) {
|
||||||
std::vector<Linef> object_lines = to_unscaled_linesf(layer_to_print.object_layer->lslices);
|
layers_ptrs.push_back(layer_to_print.object_layer);
|
||||||
layer_lines.insert(layer_lines.end() ,object_lines.begin(), object_lines.end());
|
|
||||||
}
|
}
|
||||||
m_prev_layer_boundary = AABBTreeLines::LinesDistancer<Linef>{std::move(layer_lines)};
|
m_extrusion_quality_estimator.prepare_for_new_layer(layers_ptrs);
|
||||||
|
|
||||||
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
|
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
|
||||||
for (unsigned int extruder_id : layer_tools.extruders)
|
for (unsigned int extruder_id : layer_tools.extruders)
|
||||||
@ -2708,6 +2705,7 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, const std::s
|
|||||||
|
|
||||||
std::string GCode::extrude_entity(const ExtrusionEntity &entity, const std::string_view description, double speed)
|
std::string GCode::extrude_entity(const ExtrusionEntity &entity, const std::string_view description, double speed)
|
||||||
{
|
{
|
||||||
|
m_extrusion_quality_estimator.reset_for_next_extrusion();
|
||||||
if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(&entity))
|
if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(&entity))
|
||||||
return this->extrude_path(*path, description, speed);
|
return this->extrude_path(*path, description, speed);
|
||||||
else if (const ExtrusionMultiPath* multipath = dynamic_cast<const ExtrusionMultiPath*>(&entity))
|
else if (const ExtrusionMultiPath* multipath = dynamic_cast<const ExtrusionMultiPath*>(&entity))
|
||||||
@ -2880,10 +2878,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
|||||||
speed = m_config.get_abs_value("perimeter_speed");
|
speed = m_config.get_abs_value("perimeter_speed");
|
||||||
} else if (path.role() == erExternalPerimeter) {
|
} else if (path.role() == erExternalPerimeter) {
|
||||||
speed = m_config.get_abs_value("external_perimeter_speed");
|
speed = m_config.get_abs_value("external_perimeter_speed");
|
||||||
} else if (path.role() == erOverhangPerimeter) {
|
} else if (path.role() == erOverhangPerimeter || path.role() == erBridgeInfill) {
|
||||||
float quality = estimate_overhang_quality(path, path.width, this->m_prev_layer_boundary);
|
|
||||||
speed = std::max(10.0, quality * m_config.get_abs_value("bridge_speed"));
|
|
||||||
} else if (path.role() == erBridgeInfill) {
|
|
||||||
speed = m_config.get_abs_value("bridge_speed");
|
speed = m_config.get_abs_value("bridge_speed");
|
||||||
} else if (path.role() == erInternalInfill) {
|
} else if (path.role() == erInternalInfill) {
|
||||||
speed = m_config.get_abs_value("infill_speed");
|
speed = m_config.get_abs_value("infill_speed");
|
||||||
@ -2919,6 +2914,15 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
|||||||
EXTRUDER_CONFIG(filament_max_volumetric_speed) / path.mm3_per_mm
|
EXTRUDER_CONFIG(filament_max_volumetric_speed) / path.mm3_per_mm
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool variable_speed = false;
|
||||||
|
double last_set_speed = 0.0;
|
||||||
|
std::vector<float> points_quality{};
|
||||||
|
if (!this->on_first_layer() && is_perimeter(path.role())) {
|
||||||
|
points_quality = m_extrusion_quality_estimator.estimate_extrusion_quality(path);
|
||||||
|
variable_speed = std::any_of(points_quality.begin(), points_quality.end(), [](float q) { return q != 1.0; });
|
||||||
|
}
|
||||||
|
|
||||||
double F = speed * 60; // convert mm/sec to mm/min
|
double F = speed * 60; // convert mm/sec to mm/min
|
||||||
|
|
||||||
// extrude arc or line
|
// extrude arc or line
|
||||||
@ -2981,8 +2985,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
|||||||
}
|
}
|
||||||
|
|
||||||
// F is mm per minute.
|
// F is mm per minute.
|
||||||
|
if (!variable_speed){
|
||||||
gcode += m_writer.set_speed(F, "", comment);
|
gcode += m_writer.set_speed(F, "", comment);
|
||||||
double path_length = 0.;
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::string comment;
|
std::string comment;
|
||||||
if (m_config.gcode_comments) {
|
if (m_config.gcode_comments) {
|
||||||
@ -2992,12 +2998,21 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
|||||||
Vec2d prev = this->point_to_gcode_quantized(path.polyline.points.front());
|
Vec2d prev = this->point_to_gcode_quantized(path.polyline.points.front());
|
||||||
auto it = path.polyline.points.begin();
|
auto it = path.polyline.points.begin();
|
||||||
auto end = path.polyline.points.end();
|
auto end = path.polyline.points.end();
|
||||||
|
int i = 0;
|
||||||
for (++ it; it != end; ++ it) {
|
for (++ it; it != end; ++ it) {
|
||||||
|
if (variable_speed) {
|
||||||
|
double new_speed = std::max(5.0, points_quality[i] * speed);
|
||||||
|
if (last_set_speed != new_speed) {
|
||||||
|
last_set_speed = new_speed;
|
||||||
|
gcode += m_writer.set_speed(new_speed * 60.0, "", comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Vec2d p = this->point_to_gcode_quantized(*it);
|
Vec2d p = this->point_to_gcode_quantized(*it);
|
||||||
const double line_length = (p - prev).norm();
|
const double line_length = (p - prev).norm();
|
||||||
path_length += line_length;
|
|
||||||
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
|
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
|
||||||
prev = p;
|
prev = p;
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_enable_cooling_markers)
|
if (m_enable_cooling_markers)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef slic3r_GCode_hpp_
|
#ifndef slic3r_GCode_hpp_
|
||||||
#define slic3r_GCode_hpp_
|
#define slic3r_GCode_hpp_
|
||||||
|
|
||||||
#include "GCode/OverhangProcessor.hpp"
|
#include "GCode/ExtrusionProcessor.hpp"
|
||||||
#include "JumpPointSearch.hpp"
|
#include "JumpPointSearch.hpp"
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
#include "ExPolygon.hpp"
|
#include "ExPolygon.hpp"
|
||||||
@ -334,7 +334,7 @@ private:
|
|||||||
// Cache for custom seam enforcers/blockers for each layer.
|
// Cache for custom seam enforcers/blockers for each layer.
|
||||||
SeamPlacer m_seam_placer;
|
SeamPlacer m_seam_placer;
|
||||||
|
|
||||||
AABBTreeLines::LinesDistancer<Linef>m_prev_layer_boundary;
|
ExtrusionQualityEstimator m_extrusion_quality_estimator;
|
||||||
|
|
||||||
/* Origin of print coordinates expressed in unscaled G-code coordinates.
|
/* Origin of print coordinates expressed in unscaled G-code coordinates.
|
||||||
This affects the input arguments supplied to the extrude*() and travel_to()
|
This affects the input arguments supplied to the extrude*() and travel_to()
|
||||||
|
150
src/libslic3r/GCode/ExtrusionProcessor.hpp
Normal file
150
src/libslic3r/GCode/ExtrusionProcessor.hpp
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
#ifndef slic3r_ExtrusionProcessor_hpp_
|
||||||
|
#define slic3r_ExtrusionProcessor_hpp_
|
||||||
|
|
||||||
|
#include "../AABBTreeLines.hpp"
|
||||||
|
#include "../SupportSpotsGenerator.hpp"
|
||||||
|
#include "../libslic3r.h"
|
||||||
|
#include "../ExtrusionEntity.hpp"
|
||||||
|
#include "../Layer.hpp"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <limits>
|
||||||
|
#include <numeric>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class SlidingWindowCurvatureAccumulator
|
||||||
|
{
|
||||||
|
float window_size;
|
||||||
|
float total_distance = 0; // accumulated distance
|
||||||
|
float total_curvature = 0; // accumulated signed ccw angles
|
||||||
|
deque<float> distances;
|
||||||
|
deque<float> angles;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SlidingWindowCurvatureAccumulator(float window_size) : window_size(window_size) {}
|
||||||
|
|
||||||
|
void add_point(float distance, float angle)
|
||||||
|
{
|
||||||
|
total_distance += distance;
|
||||||
|
total_curvature += angle;
|
||||||
|
distances.push_back(distance);
|
||||||
|
angles.push_back(angle);
|
||||||
|
|
||||||
|
while (distances.size() > 1 && total_distance > window_size) {
|
||||||
|
total_distance -= distances.front();
|
||||||
|
total_curvature -= angles.front();
|
||||||
|
distances.pop_front();
|
||||||
|
angles.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float get_curvature() const
|
||||||
|
{
|
||||||
|
if (total_distance <= 0.0) { return 0.0; }
|
||||||
|
|
||||||
|
return total_curvature / std::min(total_distance, window_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
total_curvature = 0;
|
||||||
|
total_distance = 0;
|
||||||
|
distances.clear();
|
||||||
|
angles.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CurvatureEstimator
|
||||||
|
{
|
||||||
|
static const size_t sliders_count = 4;
|
||||||
|
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{2.0}, {4.0}, {8.0}, {16.0}};
|
||||||
|
|
||||||
|
public:
|
||||||
|
void add_point(float distance, float angle)
|
||||||
|
{
|
||||||
|
for (SlidingWindowCurvatureAccumulator &slider : sliders) { slider.add_point(distance, angle); }
|
||||||
|
}
|
||||||
|
float get_curvature()
|
||||||
|
{
|
||||||
|
float max_curvature = std::numeric_limits<float>::min();
|
||||||
|
for (const SlidingWindowCurvatureAccumulator &slider : sliders) { max_curvature = std::max(max_curvature, slider.get_curvature()); }
|
||||||
|
return max_curvature;
|
||||||
|
}
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
for (SlidingWindowCurvatureAccumulator &slider : sliders) { slider.reset(); }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExtrusionQualityEstimator
|
||||||
|
{
|
||||||
|
AABBTreeLines::LinesDistancer<Linef> prev_layer_boundary;
|
||||||
|
AABBTreeLines::LinesDistancer<Linef> next_layer_boundary;
|
||||||
|
CurvatureEstimator cestim{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
void prepare_for_new_layer(const std::vector<const Layer *> &layers)
|
||||||
|
{
|
||||||
|
std::vector<Linef> layer_lines;
|
||||||
|
for (const Layer *layer : layers) {
|
||||||
|
if (layer == nullptr) continue;
|
||||||
|
std::vector<Linef> object_lines = to_unscaled_linesf(layer->lslices);
|
||||||
|
layer_lines.insert(layer_lines.end(), object_lines.begin(), object_lines.end());
|
||||||
|
}
|
||||||
|
prev_layer_boundary = next_layer_boundary;
|
||||||
|
next_layer_boundary = AABBTreeLines::LinesDistancer<Linef>{std::move(layer_lines)};
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_for_next_extrusion() { cestim.reset(); }
|
||||||
|
|
||||||
|
std::vector<float> estimate_extrusion_quality(const ExtrusionPath &path)
|
||||||
|
{
|
||||||
|
float flow_width = path.width;
|
||||||
|
float min_malformation_dist = 0.2 * flow_width;
|
||||||
|
float max_malformation_dist = 1.1 * flow_width;
|
||||||
|
float worst_malformation_dist = 0.5 * (min_malformation_dist + max_malformation_dist);
|
||||||
|
|
||||||
|
std::vector<Vec2f> points;
|
||||||
|
Polyline pl = path.as_polyline();
|
||||||
|
points.reserve(pl.size());
|
||||||
|
for (const Point &p : pl) { points.push_back(unscaled(p).cast<float>()); }
|
||||||
|
|
||||||
|
std::vector<float> point_qualities(points.size(), 1.0);
|
||||||
|
for (size_t point_idx = 0; point_idx < points.size(); ++point_idx) {
|
||||||
|
Vec2f b = points[point_idx];
|
||||||
|
|
||||||
|
double dist_from_prev_layer = prev_layer_boundary.signed_distance_from_lines(b.cast<double>()) + flow_width * 0.5f;
|
||||||
|
if (dist_from_prev_layer < min_malformation_dist) continue;
|
||||||
|
|
||||||
|
Vec2f a = points[point_idx > 0 ? point_idx - 1 : point_idx];
|
||||||
|
Vec2f c = points[point_idx < points.size() - 1 ? point_idx + 1 : point_idx];
|
||||||
|
|
||||||
|
const Vec2f v1 = b - a;
|
||||||
|
const Vec2f v2 = c - b;
|
||||||
|
float curr_angle = angle(v1, v2);
|
||||||
|
|
||||||
|
cestim.add_point(v1.norm(), curr_angle);
|
||||||
|
|
||||||
|
float distance_quality = std::min(1.0, std::abs(dist_from_prev_layer - worst_malformation_dist) /
|
||||||
|
(worst_malformation_dist - min_malformation_dist));
|
||||||
|
|
||||||
|
// Curvature is 1 / R, where is radius of the touching sphere
|
||||||
|
// if the radius of the touching sphere is greater than 10 mm, dont lower quality, for sharper corners do lower the quality of the point
|
||||||
|
float curvature_value = std::abs(cestim.get_curvature()) * 10.0f;
|
||||||
|
curvature_value = std::max(curvature_value, 1.0f);
|
||||||
|
distance_quality /= curvature_value;
|
||||||
|
|
||||||
|
point_qualities[point_idx] = distance_quality;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (points.size() > 1) { point_qualities[0] = point_qualities[1]; }
|
||||||
|
|
||||||
|
return point_qualities;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // slic3r_ExtrusionProcessor_hpp_
|
@ -1,121 +0,0 @@
|
|||||||
#ifndef slic3r_OverhangProcessor_hpp_
|
|
||||||
#define slic3r_OverhangProcessor_hpp_
|
|
||||||
|
|
||||||
#include "../AABBTreeLines.hpp"
|
|
||||||
#include "../SupportSpotsGenerator.hpp"
|
|
||||||
#include "../libslic3r.h"
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include <numeric>
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
class SlidingWindowCurvatureAccumulator
|
|
||||||
{
|
|
||||||
float window_size;
|
|
||||||
float total_distance = 0; // accumulated distance
|
|
||||||
float total_curvature = 0; // accumulated signed ccw angles
|
|
||||||
deque<float> distances;
|
|
||||||
deque<float> angles;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SlidingWindowCurvatureAccumulator(float window_size) : window_size(window_size) {}
|
|
||||||
|
|
||||||
void add_point(float distance, float angle)
|
|
||||||
{
|
|
||||||
total_distance += distance;
|
|
||||||
total_curvature += angle;
|
|
||||||
distances.push_back(distance);
|
|
||||||
angles.push_back(angle);
|
|
||||||
|
|
||||||
while (distances.size() > 1 && total_distance > window_size) {
|
|
||||||
total_distance -= distances.front();
|
|
||||||
total_curvature -= angles.front();
|
|
||||||
distances.pop_front();
|
|
||||||
angles.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float get_curvature() const
|
|
||||||
{
|
|
||||||
if (total_distance <= 0.0) { return 0.0; }
|
|
||||||
|
|
||||||
return total_curvature / std::min(total_distance, window_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
total_curvature = 0;
|
|
||||||
total_distance = 0;
|
|
||||||
distances.clear();
|
|
||||||
angles.clear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CurvatureEstimator
|
|
||||||
{
|
|
||||||
static const size_t sliders_count = 4;
|
|
||||||
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{2.0}, {4.0}, {8.0}, {16.0}};
|
|
||||||
|
|
||||||
public:
|
|
||||||
void add_point(float distance, float angle)
|
|
||||||
{
|
|
||||||
for (SlidingWindowCurvatureAccumulator &slider : sliders) { slider.add_point(distance, angle); }
|
|
||||||
}
|
|
||||||
float get_curvature()
|
|
||||||
{
|
|
||||||
float max_curvature = std::numeric_limits<float>::min();
|
|
||||||
for (const SlidingWindowCurvatureAccumulator &slider : sliders) { max_curvature = std::max(max_curvature, slider.get_curvature()); }
|
|
||||||
return max_curvature;
|
|
||||||
}
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
for (SlidingWindowCurvatureAccumulator &slider : sliders) { slider.reset(); }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline float estimate_overhang_quality(const ExtrusionPath &entity,
|
|
||||||
float flow_width,
|
|
||||||
AABBTreeLines::LinesDistancer<Linef> &prev_layer_boundary)
|
|
||||||
{
|
|
||||||
// value of 1 is for nice straigth lines that are either in air or mostly lying on the prev layer.
|
|
||||||
float quality = 1.0;
|
|
||||||
|
|
||||||
float min_malformation_dist = 0.0f;
|
|
||||||
float max_malformation_dist = 0.7 * flow_width;
|
|
||||||
|
|
||||||
CurvatureEstimator cestim{};
|
|
||||||
std::vector<Vec2f> points;
|
|
||||||
Polyline pl = entity.as_polyline();
|
|
||||||
points.reserve(pl.size());
|
|
||||||
for (const Point &p : pl) { points.push_back(unscaled(p).cast<float>()); }
|
|
||||||
|
|
||||||
for (size_t point_idx = 0; point_idx < points.size(); ++point_idx) {
|
|
||||||
Vec2f a = points[point_idx > 0 ? point_idx - 1 : point_idx];
|
|
||||||
Vec2f b = points[point_idx];
|
|
||||||
Vec2f c = points[point_idx < points.size() - 1 ? point_idx + 1 : point_idx];
|
|
||||||
|
|
||||||
const Vec2f v1 = b - a;
|
|
||||||
const Vec2f v2 = c - b;
|
|
||||||
float curr_angle = angle(v1, v2);
|
|
||||||
|
|
||||||
cestim.add_point(v1.norm(), curr_angle);
|
|
||||||
// malformation in concave angles does not happen
|
|
||||||
if (curr_angle < -20.0 * PI / 180.0) { cestim.reset(); }
|
|
||||||
|
|
||||||
double dist_from_prev_layer = prev_layer_boundary.signed_distance_from_lines(b.cast<double>());
|
|
||||||
|
|
||||||
float distance_quality = std::abs(dist_from_prev_layer - (max_malformation_dist + min_malformation_dist) * 0.5);
|
|
||||||
float curvature_quality = std::abs(cestim.get_curvature()) * 10.0f;
|
|
||||||
curvature_quality = std::max(curvature_quality, 1.0f);
|
|
||||||
distance_quality /= curvature_quality;
|
|
||||||
|
|
||||||
if (distance_quality < quality) { quality = 0.8 * quality + 0.2 * distance_quality; }
|
|
||||||
}
|
|
||||||
|
|
||||||
return quality;
|
|
||||||
}
|
|
||||||
|
|
||||||
}; // namespace Slic3r
|
|
||||||
|
|
||||||
#endif // slic3r_OverhangProcessor_hpp_
|
|
Loading…
x
Reference in New Issue
Block a user