mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-31 03:42:00 +08:00
Rebased pm_arcwelder_overhangs_port to vb_arc_welder
This commit is contained in:
parent
bf6a8dc0b0
commit
fa0986c0c5
@ -103,7 +103,8 @@ inline bool operator==(const ExtrusionFlow &lhs, const ExtrusionFlow &rhs)
|
||||
}
|
||||
|
||||
struct OverhangAttributes {
|
||||
float max_distance_from_prev_layer;
|
||||
float start_distance_from_prev_layer;
|
||||
float end_distance_from_prev_layer;
|
||||
float proximity_to_curled_lines; //value between 0 and 1
|
||||
};
|
||||
|
||||
@ -169,6 +170,7 @@ public:
|
||||
double mm3_per_mm() const { return m_attributes.mm3_per_mm; }
|
||||
// Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
|
||||
double min_mm3_per_mm() const override { return m_attributes.mm3_per_mm; }
|
||||
std::optional<OverhangAttributes>& overhang_attributes_mutable() { return m_attributes.overhang_attributes; }
|
||||
|
||||
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
|
||||
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <cstdlib>
|
||||
#include <chrono>
|
||||
#include <math.h>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
@ -2775,25 +2776,8 @@ std::string GCodeGenerator::_extrude(
|
||||
);
|
||||
}
|
||||
|
||||
std::pair<float, float> dynamic_speed_and_fan_speed{-1, -1};
|
||||
if (path_attr.overhang_attributes.has_value()) {
|
||||
std::vector<std::pair<int, ConfigOptionFloatOrPercent>> overhangs_with_speeds = {{100, ConfigOptionFloatOrPercent{speed, false}}};
|
||||
if (this->m_config.enable_dynamic_overhang_speeds) {
|
||||
overhangs_with_speeds = {{0, m_config.overhang_speed_0},
|
||||
{25, m_config.overhang_speed_1},
|
||||
{50, m_config.overhang_speed_2},
|
||||
{75, m_config.overhang_speed_3},
|
||||
{100, ConfigOptionFloatOrPercent{speed, false}}};
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, ConfigOptionInts>> overhang_w_fan_speeds = {{100, ConfigOptionInts{0}}};
|
||||
if (this->m_config.enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())) {
|
||||
overhang_w_fan_speeds = {{0, m_config.overhang_fan_speed_0},
|
||||
{25, m_config.overhang_fan_speed_1},
|
||||
{50, m_config.overhang_fan_speed_2},
|
||||
{75, m_config.overhang_fan_speed_3},
|
||||
{100, ConfigOptionInts{0}}};
|
||||
}
|
||||
|
||||
double external_perim_reference_speed = m_config.get_abs_value("external_perimeter_speed");
|
||||
if (external_perim_reference_speed == 0)
|
||||
external_perim_reference_speed = m_volumetric_speed / path_attr.mm3_per_mm;
|
||||
@ -2805,58 +2789,13 @@ std::string GCodeGenerator::_extrude(
|
||||
EXTRUDER_CONFIG(filament_max_volumetric_speed) / path_attr.mm3_per_mm);
|
||||
}
|
||||
|
||||
ExtrusionProcessor::calculate_overhang_speed();
|
||||
|
||||
|
||||
new_points = m_extrusion_quality_estimator.estimate_speed_from_extrusion_quality(
|
||||
// FIXME convert estimate_speed_from_extrusion_quality() to smooth paths or move it before smooth path interpolation.
|
||||
Points{}, path_attr, overhangs_with_speeds, overhang_w_fan_speeds, m_writer.extruder()->id(), external_perim_reference_speed,
|
||||
speed);
|
||||
variable_speed_or_fan_speed = std::any_of(new_points.begin(), new_points.end(),
|
||||
[speed](const ProcessedPoint &p) { return p.speed != speed || p.fan_speed != 0; });
|
||||
dynamic_speed_and_fan_speed = ExtrusionProcessor::calculate_overhang_speed(path_attr, this->m_config, m_writer.extruder()->id(),
|
||||
external_perim_reference_speed, speed);
|
||||
}
|
||||
|
||||
// bool variable_speed_or_fan_speed = false;
|
||||
// std::vector<ProcessedPoint> new_points{};
|
||||
// if ((this->m_config.enable_dynamic_overhang_speeds || this->config().enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())) &&
|
||||
// !this->on_first_layer() && path_attr.role.is_perimeter()) {
|
||||
// std::vector<std::pair<int, ConfigOptionFloatOrPercent>> overhangs_with_speeds = {{100, ConfigOptionFloatOrPercent{speed, false}}};
|
||||
// if (this->m_config.enable_dynamic_overhang_speeds) {
|
||||
// overhangs_with_speeds = {{0, m_config.overhang_speed_0},
|
||||
// {25, m_config.overhang_speed_1},
|
||||
// {50, m_config.overhang_speed_2},
|
||||
// {75, m_config.overhang_speed_3},
|
||||
// {100, ConfigOptionFloatOrPercent{speed, false}}};
|
||||
// }
|
||||
|
||||
// std::vector<std::pair<int, ConfigOptionInts>> overhang_w_fan_speeds = {{100, ConfigOptionInts{0}}};
|
||||
// if (this->m_config.enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())) {
|
||||
// overhang_w_fan_speeds = {{0, m_config.overhang_fan_speed_0},
|
||||
// {25, m_config.overhang_fan_speed_1},
|
||||
// {50, m_config.overhang_fan_speed_2},
|
||||
// {75, m_config.overhang_fan_speed_3},
|
||||
// {100, ConfigOptionInts{0}}};
|
||||
// }
|
||||
|
||||
// double external_perim_reference_speed = m_config.get_abs_value("external_perimeter_speed");
|
||||
// if (external_perim_reference_speed == 0)
|
||||
// external_perim_reference_speed = m_volumetric_speed / path_attr.mm3_per_mm;
|
||||
// if (m_config.max_volumetric_speed.value > 0)
|
||||
// external_perim_reference_speed = std::min(external_perim_reference_speed, m_config.max_volumetric_speed.value / path_attr.mm3_per_mm);
|
||||
// if (EXTRUDER_CONFIG(filament_max_volumetric_speed) > 0) {
|
||||
// external_perim_reference_speed = std::min(external_perim_reference_speed,
|
||||
// EXTRUDER_CONFIG(filament_max_volumetric_speed) / path_attr.mm3_per_mm);
|
||||
// }
|
||||
|
||||
// new_points = m_extrusion_quality_estimator.estimate_speed_from_extrusion_quality(
|
||||
// //FIXME convert estimate_speed_from_extrusion_quality() to smooth paths or move it before smooth path interpolation.
|
||||
// Points{},
|
||||
// path_attr, overhangs_with_speeds, overhang_w_fan_speeds,
|
||||
// m_writer.extruder()->id(), external_perim_reference_speed,
|
||||
// speed);
|
||||
// variable_speed_or_fan_speed = std::any_of(new_points.begin(), new_points.end(),
|
||||
// [speed](const ProcessedPoint &p) { return p.speed != speed || p.fan_speed != 0; });
|
||||
// }
|
||||
if (dynamic_speed_and_fan_speed.first > -1) {
|
||||
speed = dynamic_speed_and_fan_speed.first;
|
||||
}
|
||||
|
||||
double F = speed * 60; // convert mm/sec to mm/min
|
||||
|
||||
@ -2919,86 +2858,62 @@ std::string GCodeGenerator::_extrude(
|
||||
cooling_marker_setspeed_comments += ";_EXTERNAL_PERIMETER";
|
||||
}
|
||||
|
||||
//FIXME Variable speed on overhangs is inactive until the code is adapted to smooth path.
|
||||
if (! variable_speed_or_fan_speed) {
|
||||
// F is mm per minute.
|
||||
gcode += m_writer.set_speed(F, "", cooling_marker_setspeed_comments);
|
||||
double path_length = 0.;
|
||||
std::string comment;
|
||||
if (m_config.gcode_comments) {
|
||||
comment = description;
|
||||
comment += description_bridge;
|
||||
}
|
||||
Vec2d prev = this->point_to_gcode_quantized(path.front().point);
|
||||
auto it = path.begin();
|
||||
auto end = path.end();
|
||||
const bool emit_radius = m_config.arc_fitting == ArcFittingType::EmitRadius;
|
||||
for (++ it; it != end; ++ it) {
|
||||
Vec2d p = this->point_to_gcode_quantized(it->point);
|
||||
if (it->radius == 0) {
|
||||
// Extrude line segment.
|
||||
if (const double line_length = (p - prev).norm(); line_length > 0) {
|
||||
path_length += line_length;
|
||||
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
|
||||
}
|
||||
} else {
|
||||
// Extrude an arc.
|
||||
assert(m_config.arc_fitting == ArcFittingType::EmitCenter ||
|
||||
m_config.arc_fitting == ArcFittingType::EmitRadius);
|
||||
double radius = unscaled<double>(it->radius);
|
||||
if (emit_radius)
|
||||
// Only quantize radius if emitting it directly into G-code. Otherwise use the exact radius for calculating the IJ values.
|
||||
radius = GCodeFormatter::quantize_xyzf(radius);
|
||||
Vec2d ij;
|
||||
if (! emit_radius) {
|
||||
// Calculate quantized IJ circle center offset.
|
||||
Vec2d center_raw = Geometry::ArcWelder::arc_center(prev.cast<double>(), p.cast<double>(), double(radius), it->ccw()) - prev;
|
||||
ij = GCodeFormatter::quantize(center_raw);
|
||||
}
|
||||
double angle = Geometry::ArcWelder::arc_angle(prev.cast<double>(), p.cast<double>(), double(radius));
|
||||
assert(angle > 0);
|
||||
const double line_length = angle * std::abs(radius);
|
||||
// F is mm per minute.
|
||||
gcode += m_writer.set_speed(F, "", cooling_marker_setspeed_comments);
|
||||
if (dynamic_speed_and_fan_speed.second >= 0)
|
||||
gcode += ";_SET_FAN_SPEED" + std::to_string(int(dynamic_speed_and_fan_speed.second)) + "\n";
|
||||
double path_length = 0.;
|
||||
std::string comment;
|
||||
if (m_config.gcode_comments) {
|
||||
comment = description;
|
||||
comment += description_bridge;
|
||||
}
|
||||
Vec2d prev = this->point_to_gcode_quantized(path.front().point);
|
||||
auto it = path.begin();
|
||||
auto end = path.end();
|
||||
const bool emit_radius = m_config.arc_fitting == ArcFittingType::EmitRadius;
|
||||
for (++ it; it != end; ++ it) {
|
||||
Vec2d p = this->point_to_gcode_quantized(it->point);
|
||||
if (it->radius == 0) {
|
||||
// Extrude line segment.
|
||||
if (const double line_length = (p - prev).norm(); line_length > 0) {
|
||||
path_length += line_length;
|
||||
const double dE = e_per_mm * line_length;
|
||||
assert(dE > 0);
|
||||
gcode += emit_radius ?
|
||||
m_writer.extrude_to_xy_G2G3R(p, radius, it->ccw(), dE, comment) :
|
||||
m_writer.extrude_to_xy_G2G3IJ(p, ij, it->ccw(), dE, comment);
|
||||
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
|
||||
}
|
||||
prev = p;
|
||||
}
|
||||
} else {
|
||||
std::string marked_comment;
|
||||
if (m_config.gcode_comments) {
|
||||
marked_comment = description;
|
||||
marked_comment += description_bridge;
|
||||
}
|
||||
double last_set_speed = new_points[0].speed * 60.0;
|
||||
double last_set_fan_speed = new_points[0].fan_speed;
|
||||
gcode += m_writer.set_speed(last_set_speed, "", cooling_marker_setspeed_comments);
|
||||
gcode += "\n;_SET_FAN_SPEED" + std::to_string(int(last_set_fan_speed)) + "\n";
|
||||
Vec2d prev = this->point_to_gcode_quantized(new_points[0].p);
|
||||
for (size_t i = 1; i < new_points.size(); i++) {
|
||||
const ProcessedPoint &processed_point = new_points[i];
|
||||
Vec2d p = this->point_to_gcode_quantized(processed_point.p);
|
||||
const double line_length = (p - prev).norm();
|
||||
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, marked_comment);
|
||||
prev = p;
|
||||
double new_speed = processed_point.speed * 60.0;
|
||||
if (last_set_speed != new_speed) {
|
||||
gcode += m_writer.set_speed(new_speed, "", cooling_marker_setspeed_comments);
|
||||
last_set_speed = new_speed;
|
||||
}
|
||||
if (last_set_fan_speed != processed_point.fan_speed) {
|
||||
last_set_fan_speed = processed_point.fan_speed;
|
||||
gcode += "\n;_SET_FAN_SPEED" + std::to_string(int(last_set_fan_speed)) + "\n";
|
||||
} else {
|
||||
// Extrude an arc.
|
||||
assert(m_config.arc_fitting == ArcFittingType::EmitCenter ||
|
||||
m_config.arc_fitting == ArcFittingType::EmitRadius);
|
||||
double radius = unscaled<double>(it->radius);
|
||||
if (emit_radius)
|
||||
// Only quantize radius if emitting it directly into G-code. Otherwise use the exact radius for calculating the IJ values.
|
||||
radius = GCodeFormatter::quantize_xyzf(radius);
|
||||
Vec2d ij;
|
||||
if (! emit_radius) {
|
||||
// Calculate quantized IJ circle center offset.
|
||||
Vec2d center_raw = Geometry::ArcWelder::arc_center(prev.cast<double>(), p.cast<double>(), double(radius), it->ccw()) - prev;
|
||||
ij = GCodeFormatter::quantize(center_raw);
|
||||
}
|
||||
double angle = Geometry::ArcWelder::arc_angle(prev.cast<double>(), p.cast<double>(), double(radius));
|
||||
assert(angle > 0);
|
||||
const double line_length = angle * std::abs(radius);
|
||||
path_length += line_length;
|
||||
const double dE = e_per_mm * line_length;
|
||||
assert(dE > 0);
|
||||
gcode += emit_radius ?
|
||||
m_writer.extrude_to_xy_G2G3R(p, radius, it->ccw(), dE, comment) :
|
||||
m_writer.extrude_to_xy_G2G3IJ(p, ij, it->ccw(), dE, comment);
|
||||
}
|
||||
gcode += "\n;_RESET_FAN_SPEED\n";
|
||||
prev = p;
|
||||
}
|
||||
|
||||
if (m_enable_cooling_markers)
|
||||
gcode += path_attr.role.is_bridge() ? ";_BRIDGE_FAN_END\n" : ";_EXTRUDE_END\n";
|
||||
gcode += path_attr.role.is_bridge() ? ";_BRIDGE_FAN_END" : ";_EXTRUDE_END";
|
||||
|
||||
if (dynamic_speed_and_fan_speed.second >= 0)
|
||||
gcode += ";_RESET_FAN_SPEED";
|
||||
|
||||
gcode += "\n";
|
||||
|
||||
this->set_last_pos(path.back().point);
|
||||
return gcode;
|
||||
|
@ -68,24 +68,27 @@ ExtrusionPaths calculate_and_split_overhanging_extrusions(const ExtrusionPath
|
||||
|
||||
ExtrusionPaths result;
|
||||
ExtrusionAttributes new_attrs = path.attributes();
|
||||
new_attrs.overhang_attributes = std::optional<OverhangAttributes>({calculated_distances[0].first, calculated_distances[0].second});
|
||||
new_attrs.overhang_attributes = std::optional<OverhangAttributes>(
|
||||
{calculated_distances[0].first, calculated_distances[0].first, calculated_distances[0].second});
|
||||
result.emplace_back(new_attrs);
|
||||
result.back().polyline.append(Point::new_scale(extended_points[0].position));
|
||||
size_t sequence_start_index = 0;
|
||||
for (size_t i = 1; i < extended_points.size(); i++) {
|
||||
if (std::abs(calculated_distances[i].first - calculated_distances[i - 1].first) < path.width() * 0.1 &&
|
||||
std::abs(calculated_distances[i].second - calculated_distances[i - 1].second) < 0.1) {
|
||||
result.back().polyline.append(Point::new_scale(extended_points[i].position));
|
||||
result.back().overhang_attributes_mutable()->end_distance_from_prev_layer = extended_points[i].distance;
|
||||
if (std::abs(calculated_distances[sequence_start_index].first - calculated_distances[i - 1].first) < path.width() * 0.05 &&
|
||||
std::abs(calculated_distances[sequence_start_index].second - calculated_distances[i - 1].second) < 0.05) {
|
||||
// do not start new path, the attributes are similar enough
|
||||
} else {
|
||||
result.back().polyline.append(Point::new_scale(extended_points[i].position));
|
||||
new_attrs.overhang_attributes->max_distance_from_prev_layer = calculated_distances[i].first;
|
||||
new_attrs.overhang_attributes->proximity_to_curled_lines = calculated_distances[i].second;
|
||||
} else if (i +1 < extended_points.size()) { // do not start new path if this is last point!
|
||||
// start new path, parameters differ
|
||||
new_attrs.overhang_attributes->start_distance_from_prev_layer = calculated_distances[i].first;
|
||||
new_attrs.overhang_attributes->end_distance_from_prev_layer = calculated_distances[i].first;
|
||||
new_attrs.overhang_attributes->proximity_to_curled_lines = calculated_distances[i].second;
|
||||
sequence_start_index = i;
|
||||
result.emplace_back(new_attrs);
|
||||
}
|
||||
result.back().polyline.append(Point::new_scale(extended_points[i].position));
|
||||
}
|
||||
|
||||
std::cout << "ExtrusionPath " << std::to_string(size_t(&path)) << " split to " << result.size() << " paths";
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
@ -129,4 +132,74 @@ ExtrusionEntityCollection calculate_and_split_overhanging_extrusions(const Extru
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
std::pair<float,float> calculate_overhang_speed(const ExtrusionAttributes &attributes,
|
||||
const FullPrintConfig &config,
|
||||
size_t extruder_id,
|
||||
float external_perim_reference_speed,
|
||||
float default_speed)
|
||||
{
|
||||
assert(attributes.overhang_attributes.has_value());
|
||||
std::vector<std::pair<int, ConfigOptionFloatOrPercent>> overhangs_with_speeds = {
|
||||
{100, ConfigOptionFloatOrPercent{default_speed, false}}};
|
||||
if (config.enable_dynamic_overhang_speeds) {
|
||||
overhangs_with_speeds = {{0, config.overhang_speed_0},
|
||||
{25, config.overhang_speed_1},
|
||||
{50, config.overhang_speed_2},
|
||||
{75, config.overhang_speed_3},
|
||||
{100, ConfigOptionFloatOrPercent{default_speed, false}}};
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, ConfigOptionInts>> overhang_with_fan_speeds = {{100, ConfigOptionInts{0}}};
|
||||
if (config.enable_dynamic_fan_speeds.get_at(extruder_id)) {
|
||||
overhang_with_fan_speeds = {{0, config.overhang_fan_speed_0},
|
||||
{25, config.overhang_fan_speed_1},
|
||||
{50, config.overhang_fan_speed_2},
|
||||
{75, config.overhang_fan_speed_3},
|
||||
{100, ConfigOptionInts{0}}};
|
||||
}
|
||||
|
||||
float speed_base = external_perim_reference_speed > 0 ? external_perim_reference_speed : default_speed;
|
||||
std::map<float, float> speed_sections;
|
||||
for (size_t i = 0; i < overhangs_with_speeds.size(); i++) {
|
||||
float distance = attributes.width * (1.0 - (overhangs_with_speeds[i].first / 100.0));
|
||||
float speed = overhangs_with_speeds[i].second.percent ? (speed_base * overhangs_with_speeds[i].second.value / 100.0) :
|
||||
overhangs_with_speeds[i].second.value;
|
||||
if (speed < EPSILON)
|
||||
speed = speed_base;
|
||||
speed_sections[distance] = speed;
|
||||
}
|
||||
|
||||
std::map<float, float> fan_speed_sections;
|
||||
for (size_t i = 0; i < overhang_with_fan_speeds.size(); i++) {
|
||||
float distance = attributes.width * (1.0 - (overhang_with_fan_speeds[i].first / 100.0));
|
||||
float fan_speed = overhang_with_fan_speeds[i].second.get_at(extruder_id);
|
||||
fan_speed_sections[distance] = fan_speed;
|
||||
}
|
||||
|
||||
auto interpolate_speed = [](const std::map<float, float> &values, float distance) {
|
||||
auto upper_dist = values.lower_bound(distance);
|
||||
if (upper_dist == values.end()) {
|
||||
return values.rbegin()->second;
|
||||
}
|
||||
if (upper_dist == values.begin()) {
|
||||
return upper_dist->second;
|
||||
}
|
||||
|
||||
auto lower_dist = std::prev(upper_dist);
|
||||
float t = (distance - lower_dist->first) / (upper_dist->first - lower_dist->first);
|
||||
return (1.0f - t) * lower_dist->second + t * upper_dist->second;
|
||||
};
|
||||
|
||||
float extrusion_speed = std::min(interpolate_speed(speed_sections, attributes.overhang_attributes->start_distance_from_prev_layer),
|
||||
interpolate_speed(speed_sections, attributes.overhang_attributes->end_distance_from_prev_layer));
|
||||
float curled_base_speed = interpolate_speed(speed_sections,
|
||||
attributes.width * attributes.overhang_attributes->proximity_to_curled_lines);
|
||||
float final_speed = std::min(curled_base_speed, extrusion_speed);
|
||||
float fan_speed = std::min(interpolate_speed(fan_speed_sections, attributes.overhang_attributes->start_distance_from_prev_layer),
|
||||
interpolate_speed(fan_speed_sections, attributes.overhang_attributes->end_distance_from_prev_layer));
|
||||
|
||||
return {final_speed, fan_speed};
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::ExtrusionProcessor
|
@ -15,8 +15,10 @@
|
||||
#include "../Config.hpp"
|
||||
#include "../Line.hpp"
|
||||
#include "../Exception.hpp"
|
||||
#include "../PrintConfig.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
@ -227,147 +229,11 @@ ExtrusionEntityCollection calculate_and_split_overhanging_extrusions(
|
||||
const AABBTreeLines::LinesDistancer<Linef> &unscaled_prev_layer,
|
||||
const AABBTreeLines::LinesDistancer<CurledLine> &prev_layer_curled_lines);
|
||||
|
||||
struct ProcessedPoint
|
||||
{
|
||||
Point p;
|
||||
float speed = 1.0f;
|
||||
int fan_speed = 0;
|
||||
};
|
||||
|
||||
class ExtrusionQualityEstimator
|
||||
{
|
||||
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<Linef>> prev_layer_boundaries;
|
||||
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<Linef>> next_layer_boundaries;
|
||||
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<CurledLine>> prev_curled_extrusions;
|
||||
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<CurledLine>> next_curled_extrusions;
|
||||
const PrintObject *current_object;
|
||||
|
||||
public:
|
||||
void set_current_object(const PrintObject *object) { current_object = object; }
|
||||
|
||||
void prepare_for_new_layer(const Layer *layer)
|
||||
{
|
||||
if (layer == nullptr)
|
||||
return;
|
||||
const PrintObject *object = layer->object();
|
||||
prev_layer_boundaries[object] = next_layer_boundaries[object];
|
||||
next_layer_boundaries[object] = AABBTreeLines::LinesDistancer<Linef>{to_unscaled_linesf(layer->lslices)};
|
||||
prev_curled_extrusions[object] = next_curled_extrusions[object];
|
||||
next_curled_extrusions[object] = AABBTreeLines::LinesDistancer<CurledLine>{layer->curled_lines};
|
||||
}
|
||||
|
||||
std::vector<ProcessedPoint> estimate_speed_from_extrusion_quality(
|
||||
const Points &path,
|
||||
const ExtrusionFlow &flow,
|
||||
const std::vector<std::pair<int, ConfigOptionFloatOrPercent>> overhangs_w_speeds,
|
||||
const std::vector<std::pair<int, ConfigOptionInts>> overhangs_w_fan_speeds,
|
||||
size_t extruder_id,
|
||||
float ext_perimeter_speed,
|
||||
float original_speed)
|
||||
{
|
||||
float speed_base = ext_perimeter_speed > 0 ? ext_perimeter_speed : original_speed;
|
||||
std::map<float, float> speed_sections;
|
||||
for (size_t i = 0; i < overhangs_w_speeds.size(); i++) {
|
||||
float distance = flow.width * (1.0 - (overhangs_w_speeds[i].first / 100.0));
|
||||
float speed = overhangs_w_speeds[i].second.percent ? (speed_base * overhangs_w_speeds[i].second.value / 100.0) :
|
||||
overhangs_w_speeds[i].second.value;
|
||||
if (speed < EPSILON)
|
||||
speed = speed_base;
|
||||
speed_sections[distance] = speed;
|
||||
}
|
||||
|
||||
std::map<float, float> fan_speed_sections;
|
||||
for (size_t i = 0; i < overhangs_w_fan_speeds.size(); i++) {
|
||||
float distance = flow.width * (1.0 - (overhangs_w_fan_speeds[i].first / 100.0));
|
||||
float fan_speed = overhangs_w_fan_speeds[i].second.get_at(extruder_id);
|
||||
fan_speed_sections[distance] = fan_speed;
|
||||
}
|
||||
|
||||
std::vector<ExtendedPoint> extended_points =
|
||||
estimate_points_properties<true, true, true, true>(path, prev_layer_boundaries[current_object], flow.width);
|
||||
|
||||
std::vector<ProcessedPoint> processed_points;
|
||||
processed_points.reserve(extended_points.size());
|
||||
for (size_t i = 0; i < extended_points.size(); i++) {
|
||||
const ExtendedPoint &curr = extended_points[i];
|
||||
const ExtendedPoint &next = extended_points[i + 1 < extended_points.size() ? i + 1 : i];
|
||||
|
||||
// The following code artifically increases the distance to provide slowdown for extrusions that are over curled lines
|
||||
float artificial_distance_to_curled_lines = 0.0;
|
||||
const double dist_limit = 10.0 * flow.width;
|
||||
{
|
||||
Vec2d middle = 0.5 * (curr.position + next.position);
|
||||
auto line_indices = prev_curled_extrusions[current_object].all_lines_in_radius(Point::new_scale(middle), scale_(dist_limit));
|
||||
if (!line_indices.empty()) {
|
||||
double len = (next.position - curr.position).norm();
|
||||
// For long lines, there is a problem with the additional slowdown. If by accident, there is small curled line near
|
||||
// the middle of this long line
|
||||
// The whole segment gets slower unnecesarily. For these long lines, we do additional check whether it is worth slowing
|
||||
// down.
|
||||
// NOTE that this is still quite rough approximation, e.g. we are still checking lines only near the middle point
|
||||
// TODO maybe split the lines into smaller segments before running this alg? but can be demanding, and GCode will be huge
|
||||
if (len > 8) {
|
||||
Vec2d dir = Vec2d(next.position - curr.position) / len;
|
||||
Vec2d right = Vec2d(-dir.y(), dir.x());
|
||||
|
||||
Polygon box_of_influence = {
|
||||
scaled(Vec2d(curr.position + right * dist_limit)),
|
||||
scaled(Vec2d(next.position + right * dist_limit)),
|
||||
scaled(Vec2d(next.position - right * dist_limit)),
|
||||
scaled(Vec2d(curr.position - right * dist_limit)),
|
||||
};
|
||||
|
||||
double projected_lengths_sum = 0;
|
||||
for (size_t idx : line_indices) {
|
||||
const CurledLine &line = prev_curled_extrusions[current_object].get_line(idx);
|
||||
Lines inside = intersection_ln({{line.a, line.b}}, {box_of_influence});
|
||||
if (inside.empty())
|
||||
continue;
|
||||
double projected_length = abs(dir.dot(unscaled(Vec2d((inside.back().b - inside.back().a).cast<double>()))));
|
||||
projected_lengths_sum += projected_length;
|
||||
}
|
||||
if (projected_lengths_sum < 0.4 * len) {
|
||||
line_indices.clear();
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t idx : line_indices) {
|
||||
const CurledLine &line = prev_curled_extrusions[current_object].get_line(idx);
|
||||
float distance_from_curled = unscaled(line_alg::distance_to(line, Point::new_scale(middle)));
|
||||
float dist = flow.width * (1.0 - (distance_from_curled / dist_limit)) *
|
||||
(1.0 - (distance_from_curled / dist_limit)) *
|
||||
(line.curled_height / (flow.height * 10.0f)); // max_curled_height_factor from SupportSpotGenerator
|
||||
artificial_distance_to_curled_lines = std::max(artificial_distance_to_curled_lines, dist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto interpolate_speed = [](const std::map<float, float> &values, float distance) {
|
||||
auto upper_dist = values.lower_bound(distance);
|
||||
if (upper_dist == values.end()) {
|
||||
return values.rbegin()->second;
|
||||
}
|
||||
if (upper_dist == values.begin()) {
|
||||
return upper_dist->second;
|
||||
}
|
||||
|
||||
auto lower_dist = std::prev(upper_dist);
|
||||
float t = (distance - lower_dist->first) / (upper_dist->first - lower_dist->first);
|
||||
return (1.0f - t) * lower_dist->second + t * upper_dist->second;
|
||||
};
|
||||
|
||||
float extrusion_speed = std::min(interpolate_speed(speed_sections, curr.distance),
|
||||
interpolate_speed(speed_sections, next.distance));
|
||||
float curled_base_speed = interpolate_speed(speed_sections, artificial_distance_to_curled_lines);
|
||||
float final_speed = std::min(curled_base_speed, extrusion_speed);
|
||||
float fan_speed = std::min(interpolate_speed(fan_speed_sections, curr.distance),
|
||||
interpolate_speed(fan_speed_sections, next.distance));
|
||||
|
||||
processed_points.push_back({scaled(curr.position), final_speed, int(fan_speed)});
|
||||
}
|
||||
return processed_points;
|
||||
}
|
||||
};
|
||||
std::pair<float, float> calculate_overhang_speed(const ExtrusionAttributes &attributes,
|
||||
const FullPrintConfig &config,
|
||||
size_t extruder_id,
|
||||
float external_perim_reference_speed,
|
||||
float default_speed);
|
||||
|
||||
}} // namespace Slic3r::ExtrusionProcessor
|
||||
|
||||
|
@ -561,9 +561,10 @@ void PrintObject::calculate_overhanging_perimeters()
|
||||
continue;
|
||||
}
|
||||
ExPolygons prev_layer_polygon = l->lower_layer == nullptr ? ExPolygons() : l->lower_layer->lslices;
|
||||
layer_region->m_perimeters = calculate_and_split_overhanging_extrusions(&layer_region->m_perimeters,
|
||||
unscaled_polygons_lines[l->id()],
|
||||
curled_lines[l->id()]);
|
||||
layer_region->m_perimeters =
|
||||
ExtrusionProcessor::calculate_and_split_overhanging_extrusions(&layer_region->m_perimeters,
|
||||
unscaled_polygons_lines[l->id()],
|
||||
curled_lines[l->id()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -327,10 +327,10 @@ std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntit
|
||||
if (entity->length() < scale_(params.min_distance_to_allow_local_supports)) {
|
||||
return {};
|
||||
}
|
||||
const float flow_width = get_flow_width(layer_region, entity->role());
|
||||
std::vector<ExtendedPoint> annotated_points = estimate_points_properties<true, true, true, true>(entity->as_polyline().points,
|
||||
prev_layer_boundary, flow_width,
|
||||
params.bridge_distance);
|
||||
const float flow_width = get_flow_width(layer_region, entity->role());
|
||||
std::vector<ExtrusionProcessor::ExtendedPoint> annotated_points =
|
||||
ExtrusionProcessor::estimate_points_properties<true, true, true, true>(entity->as_polyline().points, prev_layer_boundary,
|
||||
flow_width, params.bridge_distance);
|
||||
|
||||
std::vector<ExtrusionLine> lines_out;
|
||||
lines_out.reserve(annotated_points.size());
|
||||
@ -339,8 +339,8 @@ std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntit
|
||||
std::optional<Vec2d> bridging_dir{};
|
||||
|
||||
for (size_t i = 0; i < annotated_points.size(); ++i) {
|
||||
ExtendedPoint &curr_point = annotated_points[i];
|
||||
const ExtendedPoint &prev_point = i > 0 ? annotated_points[i - 1] : annotated_points[i];
|
||||
ExtrusionProcessor::ExtendedPoint &curr_point = annotated_points[i];
|
||||
const ExtrusionProcessor::ExtendedPoint &prev_point = i > 0 ? annotated_points[i - 1] : annotated_points[i];
|
||||
|
||||
SupportPointCause potential_cause = std::abs(curr_point.curvature) > 0.1 ? SupportPointCause::FloatingBridgeAnchor :
|
||||
SupportPointCause::LongBridge;
|
||||
@ -382,19 +382,19 @@ std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntit
|
||||
|
||||
const float flow_width = get_flow_width(layer_region, entity->role());
|
||||
// Compute only unsigned distance - prev_layer_lines can contain unconnected paths, thus the sign of the distance is unreliable
|
||||
std::vector<ExtendedPoint> annotated_points = estimate_points_properties<true, true, false, false>(entity->as_polyline().points,
|
||||
prev_layer_lines, flow_width,
|
||||
params.bridge_distance);
|
||||
std::vector<ExtrusionProcessor::ExtendedPoint> annotated_points =
|
||||
ExtrusionProcessor::estimate_points_properties<true, true, false, false>(entity->as_polyline().points, prev_layer_lines,
|
||||
flow_width, params.bridge_distance);
|
||||
|
||||
std::vector<ExtrusionLine> lines_out;
|
||||
lines_out.reserve(annotated_points.size());
|
||||
float bridged_distance = annotated_points.front().position != annotated_points.back().position ? (params.bridge_distance + 1.0f) :
|
||||
0.0f;
|
||||
for (size_t i = 0; i < annotated_points.size(); ++i) {
|
||||
ExtendedPoint &curr_point = annotated_points[i];
|
||||
const ExtendedPoint &prev_point = i > 0 ? annotated_points[i - 1] : annotated_points[i];
|
||||
float line_len = (prev_point.position - curr_point.position).norm();
|
||||
ExtrusionLine line_out{prev_point.position.cast<float>(), curr_point.position.cast<float>(), line_len, entity};
|
||||
ExtrusionProcessor::ExtendedPoint &curr_point = annotated_points[i];
|
||||
const ExtrusionProcessor::ExtendedPoint &prev_point = i > 0 ? annotated_points[i - 1] : annotated_points[i];
|
||||
float line_len = (prev_point.position - curr_point.position).norm();
|
||||
ExtrusionLine line_out{prev_point.position.cast<float>(), curr_point.position.cast<float>(), line_len, entity};
|
||||
|
||||
Vec2f middle = 0.5 * (line_out.a + line_out.b);
|
||||
auto [middle_distance, bottom_line_idx, x] = prev_layer_lines.distance_from_lines_extra<false>(middle);
|
||||
@ -1107,12 +1107,13 @@ void estimate_supports_malformations(SupportLayerPtrs &layers, float flow_width,
|
||||
Polygon pol(pl.points);
|
||||
pol.make_counter_clockwise();
|
||||
|
||||
auto annotated_points = estimate_points_properties<true, true, false, false>(pol.points, prev_layer_lines, flow_width);
|
||||
auto annotated_points = ExtrusionProcessor::estimate_points_properties<true, true, false, false>(pol.points, prev_layer_lines,
|
||||
flow_width);
|
||||
|
||||
for (size_t i = 0; i < annotated_points.size(); ++i) {
|
||||
const ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i];
|
||||
const ExtendedPoint &b = annotated_points[i];
|
||||
ExtrusionLine line_out{a.position.cast<float>(), b.position.cast<float>(), float((a.position - b.position).norm()),
|
||||
const ExtrusionProcessor::ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i];
|
||||
const ExtrusionProcessor::ExtendedPoint &b = annotated_points[i];
|
||||
ExtrusionLine line_out{a.position.cast<float>(), b.position.cast<float>(), float((a.position - b.position).norm()),
|
||||
extrusion};
|
||||
|
||||
Vec2f middle = 0.5 * (line_out.a + line_out.b);
|
||||
@ -1182,11 +1183,13 @@ void estimate_malformations(LayerPtrs &layers, const Params ¶ms)
|
||||
Points extrusion_pts;
|
||||
extrusion->collect_points(extrusion_pts);
|
||||
float flow_width = get_flow_width(layer_region, extrusion->role());
|
||||
auto annotated_points = estimate_points_properties<true, true, false, false>(extrusion_pts, prev_layer_lines, flow_width,
|
||||
params.bridge_distance);
|
||||
auto annotated_points = ExtrusionProcessor::estimate_points_properties<true, true, false, false>(extrusion_pts,
|
||||
prev_layer_lines,
|
||||
flow_width,
|
||||
params.bridge_distance);
|
||||
for (size_t i = 0; i < annotated_points.size(); ++i) {
|
||||
const ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i];
|
||||
const ExtendedPoint &b = annotated_points[i];
|
||||
const ExtrusionProcessor::ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i];
|
||||
const ExtrusionProcessor::ExtendedPoint &b = annotated_points[i];
|
||||
ExtrusionLine line_out{a.position.cast<float>(), b.position.cast<float>(), float((a.position - b.position).norm()),
|
||||
extrusion};
|
||||
|
||||
@ -1196,7 +1199,8 @@ void estimate_malformations(LayerPtrs &layers, const Params ¶ms)
|
||||
prev_layer_lines.get_line(bottom_line_idx);
|
||||
|
||||
// correctify the distance sign using slice polygons
|
||||
float sign = (prev_layer_boundary.distance_from_lines<true>(middle.cast<double>()) + 0.5f * flow_width) < 0.0f ? -1.0f : 1.0f;
|
||||
float sign = (prev_layer_boundary.distance_from_lines<true>(middle.cast<double>()) + 0.5f * flow_width) < 0.0f ? -1.0f :
|
||||
1.0f;
|
||||
|
||||
line_out.curled_up_height = estimate_curled_up_height(middle_distance * sign, 0.5 * (a.curvature + b.curvature),
|
||||
l->height, flow_width, bottom_line.curled_up_height, params);
|
||||
|
Loading…
x
Reference in New Issue
Block a user