add scarf seam

This commit is contained in:
Wang YB
2024-05-21 11:32:40 +08:00
parent 0b00c61781
commit e77259c80b
16 changed files with 555 additions and 21 deletions

View File

@@ -9,6 +9,9 @@
#include <limits> #include <limits>
#include <sstream> #include <sstream>
//w37
#include "libslic3r/Utils.hpp"
namespace Slic3r { namespace Slic3r {
void ExtrusionPath::intersect_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const void ExtrusionPath::intersect_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const
@@ -334,4 +337,48 @@ double ExtrusionLoop::min_mm3_per_mm() const
return min_mm3_per_mm; return min_mm3_per_mm;
} }
//w37
bool ExtrusionLoop::check_seam_point_angle(double angle_threshold, double min_arm_length) const
{
// go through all the points in the loop and check if the angle between two segments(AB and BC) is less than the threshold
size_t idx_prev = 0;
size_t idx_curr = 0;
size_t idx_next = 0;
float distance_to_prev = 0;
float distance_to_next = 0;
const auto _polygon = polygon();
const Points &points = _polygon.points;
std::vector<float> lengths{};
for (size_t point_idx = 0; point_idx < points.size() - 1; ++point_idx) {
lengths.push_back((unscale(points[point_idx]) - unscale(points[point_idx + 1])).norm());
}
lengths.push_back(std::max((unscale(points[0]) - unscale(points[points.size() - 1])).norm(), 0.1));
// push idx_prev far enough back as initialization
while (distance_to_prev < min_arm_length) {
idx_prev = Slic3r::prev_idx_modulo(idx_prev, points.size());
distance_to_prev += lengths[idx_prev];
}
// push idx_next forward as far as needed
while (distance_to_next < min_arm_length) {
distance_to_next += lengths[idx_next];
idx_next = Slic3r::next_idx_modulo(idx_next, points.size());
}
// Calculate angle between idx_prev, idx_curr, idx_next.
const Point &p0 = points[idx_prev];
const Point &p1 = points[idx_curr];
const Point &p2 = points[idx_next];
const auto a = angle(p0 - p1, p2 - p1);
if (a > 0 ? a < angle_threshold : a > -angle_threshold) {
return false;
}
return true;
}
} }

View File

@@ -326,6 +326,8 @@ public:
append(dst, p.polyline.points); append(dst, p.polyline.points);
} }
double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; }
//w37
bool check_seam_point_angle(double angle_threshold = 0.174, double min_arm_length = 0.025) const;
#ifndef NDEBUG #ifndef NDEBUG
bool validate() const { bool validate() const {

View File

@@ -2952,10 +2952,12 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC
// Extrude all loops CCW. // Extrude all loops CCW.
bool is_hole = loop_src.is_clockwise(); bool is_hole = loop_src.is_clockwise();
Point seam_point = this->last_position.has_value() ? *this->last_position : Point::Zero(); Point seam_point = this->last_position.has_value() ? *this->last_position : Point::Zero();
if (! m_config.spiral_vase && comment_is_perimeter(description)) { //w37
if ((!m_config.spiral_vase && comment_is_perimeter(description)) || (this->config().seam_slope_type == SeamScarfType::None) &&comment_is_perimeter(description) ) {
assert(m_layer != nullptr); assert(m_layer != nullptr);
seam_point = m_seam_placer.place_seam(m_layer, loop_src, m_config.external_perimeters_first, seam_point); seam_point = m_seam_placer.place_seam(m_layer, loop_src, m_config.external_perimeters_first, seam_point);
} }
// Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns, // Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns,
// thus empty path segments will not be produced by G-code export. // thus empty path segments will not be produced by G-code export.
GCode::SmoothPath smooth_path = smooth_path_cache.resolve_or_fit_split_with_seam( GCode::SmoothPath smooth_path = smooth_path_cache.resolve_or_fit_split_with_seam(
@@ -2978,8 +2980,95 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC
// Extrude along the smooth path. // Extrude along the smooth path.
std::string gcode; std::string gcode;
for (const GCode::SmoothPathElement &el : smooth_path)
gcode += this->_extrude(el.path_attributes, el.path, description, speed); //w37
double ext_length = 0;
double inner_length = 0;
double start_height = 0;
bool enable_seam_slope = loop_src.check_seam_point_angle(m_config.scarf_angle_threshold.value * M_PI / 180.0);
if (this->config().seam_slope_start_height.percent)
start_height = this->config().seam_slope_start_height * this->config().layer_height / 100;
else
start_height = this->config().seam_slope_start_height;
double height_for_lift = this->config().layer_height - start_height;
if (enable_seam_slope)
for (const GCode::SmoothPathElement &el : smooth_path) {
Vec2d prev_exact = this->point_to_gcode(el.path.front().point);
Vec2d prev = GCodeFormatter::quantize(prev_exact);
auto it = el.path.begin();
auto end = el.path.end();
double sum_lift = 0;
for (++it; it != end; ++it) {
Vec2d p_exact = this->point_to_gcode(it->point);
Vec2d p = GCodeFormatter::quantize(p_exact);
double line_length = (p - prev).norm();
/* if (el.path_attributes.role.is_external_perimeter())
ext_length += line_length;
if (el.path_attributes.role.is_perimeter())
inner_length += line_length;*/
double x1 = prev.x();
double x2 = p.x();
double y1 = prev.y();
double y2 = p.y();
double temp_length = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
if (el.path_attributes.role.is_external_perimeter())
ext_length += temp_length;
if (el.path_attributes.role.is_perimeter())
inner_length += temp_length;
prev = p;
prev_exact = p_exact;
}
/* for (int i = 0; i < el.path.size() - 1; i++) {
double x1 = el.path[i].point.x();
double x2 = el.path[i + 1].point.x();
double y1 = el.path[i].point.y();
double y2 = el.path[i+1].point.y();
double temp_length = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
if (el.path_attributes.role.is_external_perimeter())
ext_length += temp_length;
if (el.path_attributes.role.is_perimeter())
inner_length += temp_length;
}*/
}
//w37
double ext_ratio = 0;
if (ext_length != 0)
ext_ratio = height_for_lift / ext_length;
double inner_ratio = 0;
if (inner_length != 0)
inner_ratio = height_for_lift / inner_length;
if (!this->config().seam_slope_entire_loop && ext_length > this->config().seam_slope_min_length) {
ext_ratio = height_for_lift / this->config().seam_slope_min_length;
}
if (!this->config().seam_slope_entire_loop && inner_length > this->config().seam_slope_min_length) {
inner_ratio = height_for_lift / this->config().seam_slope_min_length;
}
//GCode::SmoothPath new_path = smooth_path;
//if (this->config().seam_slope_type != SeamScarfType::None) {
//GCode::SmoothPath new_path = smooth_path;
// set_step_path(new_path, this->config().seam_slope_steps);
//}
//w37
for (const GCode::SmoothPathElement &el : smooth_path) {
if (((this->config().seam_slope_type == SeamScarfType::None) || (this->config().seam_slope_type == SeamScarfType::External && is_hole))|| !enable_seam_slope)
gcode += this->_extrude(el.path_attributes, el.path, description, speed);
else {
if (el.path_attributes.role.is_external_perimeter() && this->config().seam_slope_type != SeamScarfType::None)
gcode += this->_extrude(el.path_attributes, el.path, description, speed, ext_ratio);
else if (el.path_attributes.role.is_perimeter() && this->config().seam_slope_type != SeamScarfType::None &&
this->config().seam_slope_inner_walls)
gcode += this->_extrude(el.path_attributes, el.path, description, speed, inner_ratio);
else if (el.path_attributes.role.is_perimeter() && this->config().seam_slope_type != SeamScarfType::None &&
!this->config().seam_slope_inner_walls)
gcode += this->_extrude(el.path_attributes, el.path, description, speed);
}
//this->sum_lift_z = 0;
//this->sum_lift_z_ext = 0;
}
this->sum_lift_z = 0;
this->sum_lift_z_ext = 0;
// reset acceleration // reset acceleration
gcode += m_writer.set_print_acceleration(fast_round_up<unsigned int>(m_config.default_acceleration.value)); gcode += m_writer.set_print_acceleration(fast_round_up<unsigned int>(m_config.default_acceleration.value));
@@ -3220,7 +3309,19 @@ std::string GCodeGenerator::travel_to_first_position(const Vec3crd& point, const
gcode += insert_gcode(); gcode += insert_gcode();
gcode += this->writer().get_travel_to_xy_gcode(gcode_point.head<2>(), comment); gcode += this->writer().get_travel_to_xy_gcode(gcode_point.head<2>(), comment);
gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), comment); //w37
//gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), comment);
//w37
double start_height = 0;
if (this->config().seam_slope_start_height.percent)
start_height = this->config().seam_slope_start_height * this->config().layer_height / 100;
else
start_height = this->config().seam_slope_start_height;
double height_for_lift = this->config().layer_height - start_height;
if (this->config().seam_slope_type != SeamScarfType::None && (role.is_external_perimeter() ||role.is_perimeter())&& !this->on_first_layer())
gcode += this->writer().get_travel_to_z_gcode(gcode_point.z() - height_for_lift, comment);
else
gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), comment);
this->m_avoid_crossing_perimeters.reset_once_modifiers(); this->m_avoid_crossing_perimeters.reset_once_modifiers();
this->last_position = point.head<2>(); this->last_position = point.head<2>();
@@ -3247,7 +3348,9 @@ std::string GCodeGenerator::_extrude(
const ExtrusionAttributes &path_attr, const ExtrusionAttributes &path_attr,
const Geometry::ArcWelder::Path &path, const Geometry::ArcWelder::Path &path,
const std::string_view description, const std::string_view description,
double speed) double speed,
//w37
double radio)
{ {
std::string gcode; std::string gcode;
const std::string_view description_bridge = path_attr.role.is_bridge() ? " (bridge)"sv : ""sv; const std::string_view description_bridge = path_attr.role.is_bridge() ? " (bridge)"sv : ""sv;
@@ -3281,6 +3384,18 @@ std::string GCodeGenerator::_extrude(
return m_writer.multiple_extruders ? "" : m_label_objects.maybe_change_instance(m_writer); return m_writer.multiple_extruders ? "" : m_label_objects.maybe_change_instance(m_writer);
})}; })};
gcode += travel_gcode; gcode += travel_gcode;
//w37
if (this->config().seam_slope_type != SeamScarfType::None &&
(path_attr.role.is_external_perimeter() || path_attr.role.is_perimeter()) && !this->on_first_layer()) {
double start_height = 0;
if (this->config().seam_slope_start_height.percent)
start_height = this->config().seam_slope_start_height * this->config().layer_height / 100;
else
start_height = this->config().seam_slope_start_height;
double height_for_lift = this->config().layer_height - start_height;
gcode += this->m_writer.get_travel_to_z_gcode(this->m_last_layer_z - height_for_lift, comment);
}
} }
} }
@@ -3483,10 +3598,30 @@ std::string GCodeGenerator::_extrude(
comment = description; comment = description;
comment += description_bridge; comment += description_bridge;
} }
//w37
//Geometry::ArcWelder::Path new_path = path;
int seam_slope_steps = this->config().seam_slope_steps;
// if (path.size() < seam_slope_steps)
// set_step_path(&new_path, seam_slope_steps);
Vec2d prev_exact = this->point_to_gcode(path.front().point); Vec2d prev_exact = this->point_to_gcode(path.front().point);
Vec2d prev = GCodeFormatter::quantize(prev_exact); Vec2d prev = GCodeFormatter::quantize(prev_exact);
auto it = path.begin(); auto it = path.begin();
auto end = path.end(); auto end = path.end();
//w37
double sum_lift = 0;
double start_height = 0;
if (this->config().seam_slope_start_height.percent)
start_height = this->config().seam_slope_start_height * this->config().layer_height / 100;
else
start_height = this->config().seam_slope_start_height;
double height_for_lift = this->config().layer_height - start_height;
std::vector<Vec3d> point_lift;
std::vector<double> length_vec;
std::vector<double> radio_vec;
bool is_first_loop = true ;
Vec2d first_point ;
Vec2d end_point;
for (++ it; it != end; ++ it) { for (++ it; it != end; ++ it) {
Vec2d p_exact = this->point_to_gcode(it->point); Vec2d p_exact = this->point_to_gcode(it->point);
Vec2d p = GCodeFormatter::quantize(p_exact); Vec2d p = GCodeFormatter::quantize(p_exact);
@@ -3511,8 +3646,57 @@ std::string GCodeGenerator::_extrude(
} }
if (radius == 0) { if (radius == 0) {
// Extrude line segment. // Extrude line segment.
if (const double line_length = (p - prev).norm(); line_length > 0) //w37
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); double curt_length = 0;
if (radio!=0) {
double x1 = p.x();
double x2 = prev.x();
double y1 = p.y();
double y2 = prev.y();
curt_length = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
if (const double line_length = (p - prev).norm(); line_length > 0) {
if (curt_length == 0 || this->on_first_layer() || this->sum_lift_z >= height_for_lift)
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
else {
/* if (path_attr.role.is_external_perimeter()) {
double cur_lift = curt_length * radio;
if (this->sum_lift_z_ext + cur_lift >= height_for_lift)
cur_lift = height_for_lift - this->sum_lift_z_ext;
Vec3d new_p(p.x(), p.y(), this->m_last_layer_z - height_for_lift + this->sum_lift_z_ext + cur_lift);
gcode += m_writer.extrude_to_xyz(new_p, e_per_mm * line_length, comment);
this->sum_lift_z_ext += cur_lift;
}
if (path_attr.role.is_perimeter()) {
double cur_lift = curt_length * radio;
if (this->sum_lift_z + cur_lift >= height_for_lift)
cur_lift = height_for_lift - this->sum_lift_z;
Vec3d new_p(p.x(), p.y(), this->m_last_layer_z - height_for_lift + this->sum_lift_z + cur_lift);
gcode += m_writer.extrude_to_xyz(new_p, e_per_mm * line_length, comment);
this->sum_lift_z += cur_lift;
}*/
double cur_lift = curt_length * radio;
if (this->sum_lift_z + cur_lift >= height_for_lift)
cur_lift = height_for_lift - this->sum_lift_z;
double lift_radio = 0;
lift_radio = (start_height + this->sum_lift_z + cur_lift) / this->config().layer_height;
Vec3d new_p(p.x(), p.y(), this->m_last_layer_z - height_for_lift + this->sum_lift_z + cur_lift);
if (is_first_loop) {
first_point = prev;
is_first_loop = false;
}
end_point = p;
point_lift.emplace_back(new_p);
length_vec.emplace_back(line_length);
radio_vec.emplace_back(lift_radio);
//lift_radio += 0.2;
//if (lift_radio > 1)
// lift_radio = 1;
gcode += m_writer.extrude_to_xyz(new_p, e_per_mm * line_length * lift_radio , comment);
this->sum_lift_z += cur_lift;
}
}
} else { } else {
double angle = Geometry::ArcWelder::arc_angle(prev.cast<double>(), p.cast<double>(), double(radius)); double angle = Geometry::ArcWelder::arc_angle(prev.cast<double>(), p.cast<double>(), double(radius));
assert(angle > 0); assert(angle > 0);
@@ -3526,6 +3710,65 @@ std::string GCodeGenerator::_extrude(
} }
} }
//w37
if (this->config().seam_slope_type != SeamScarfType::None &&
(path_attr.role.is_external_perimeter() || path_attr.role.is_perimeter()) && !this->on_first_layer() && radio != 0) {
prev_exact = this->point_to_gcode(path.front().point);
prev = GCodeFormatter::quantize(prev_exact);
it = path.begin();
end = path.end();
length_vec[0] += (first_point - end_point).norm();
for (int i = 0; i < point_lift.size(); i++) {
Vec3d cur_point = point_lift[i];
double line_length = length_vec[i];
double wipe_radio = radio_vec[i];
Vec2d cur_point2d(cur_point.x(), cur_point.y());
gcode += m_writer.extrude_to_xy(cur_point2d, e_per_mm * line_length * (1 - wipe_radio), comment);
}
/* for (++it; it != end; ++it) {
Vec2d p_exact = this->point_to_gcode(it->point);
Vec2d p = GCodeFormatter::quantize(p_exact);
assert(p != prev);
if (p != prev) {
// Center of the radius to be emitted into the G-code: Either by radius or by center offset.
double radius = 0;
Vec2d ij;
if (it->radius != 0) {
// Extrude an arc.
assert(m_config.arc_fitting == ArcFittingType::EmitCenter);
radius = unscaled<double>(it->radius);
{
// Calculate quantized IJ circle center offset.
ij = GCodeFormatter::quantize(Vec2d(
Geometry::ArcWelder::arc_center(prev_exact.cast<double>(), p_exact.cast<double>(), double(radius), it->ccw()) -
prev));
if (ij == Vec2d::Zero())
// Don't extrude a degenerated circle.
radius = 0;
}
}
if (radius == 0) {
// Extrude line segment.
double curt_length = 0;
if (radio != 0) {
double x1 = p.x();
double x2 = prev.x();
double y1 = p.y();
double y2 = prev.y();
curt_length = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
if (const double line_length = (p - prev).norm(); line_length > 0) {
if (curt_length != 0 || !this->on_first_layer())
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length/10, comment);
}
}
prev = p;
prev_exact = p_exact;
}
}*/
}
if (m_enable_cooling_markers) 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\n" : ";_EXTRUDE_END\n";

View File

@@ -166,6 +166,10 @@ public:
std::optional<Point> last_position; std::optional<Point> last_position;
//w37
double sum_lift_z_ext = 0;
double sum_lift_z = 0;
private: private:
class GCodeOutputStream { class GCodeOutputStream {
public: public:
@@ -267,6 +271,45 @@ private:
std::string extrude_multi_path(const ExtrusionMultiPath &multipath, bool reverse, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.); std::string extrude_multi_path(const ExtrusionMultiPath &multipath, bool reverse, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.);
std::string extrude_path(const ExtrusionPath &path, bool reverse, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.); std::string extrude_path(const ExtrusionPath &path, bool reverse, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.);
//w37
void set_step_path(GCode::SmoothPath &path, const int steps)
{
double max_line_length =0;
double nums_line = 0;
int p1_i_index=-1;
int p1_j_index=-1;
Line max_line;
for (int i = 0; i < path.size(); i++) {
nums_line += path[i].path.size() - 1;
}
while (nums_line < steps) {
for (int i = 0; i < path.size(); i++) {
for (int j = 0; j < path[i].path.size() - 1; j++) {
Point p1 = path[i].path[j].point;
Point p2 = path[i].path[j + 1].point;
Line cur_l(p1, p2);
if (cur_l.length() > max_line_length) {
max_line_length = cur_l.length();
p1_i_index = i;
p1_j_index = j;
max_line = cur_l;
}
}
}
if (p1_i_index >= 0 && p1_j_index >= 0) {
Point midpt = max_line.midpoint();
Geometry::ArcWelder::Segment temp_val;
temp_val.point = midpt;
path[p1_i_index].path.insert(path[p1_i_index].path.begin() +1+ p1_j_index, temp_val);
}
nums_line = 0;
for (int i = 0; i < path.size(); i++) {
nums_line += path[i].path.size() - 1;
}
}
}
struct InstanceToPrint struct InstanceToPrint
{ {
InstanceToPrint(size_t object_layer_to_print_id, const PrintObject &print_object, size_t instance_id) : InstanceToPrint(size_t object_layer_to_print_id, const PrintObject &print_object, size_t instance_id) :
@@ -457,8 +500,9 @@ private:
// Back-pointer to Print (const). // Back-pointer to Print (const).
const Print* m_print; const Print* m_print;
//w37
std::string _extrude( std::string _extrude(
const ExtrusionAttributes &attribs, const Geometry::ArcWelder::Path &path, const std::string_view description, double speed = -1); const ExtrusionAttributes &attribs, const Geometry::ArcWelder::Path &path, const std::string_view description, double speed = -1,double ratio = 0);
void print_machine_envelope(GCodeOutputStream &file, const Print &print); void print_machine_envelope(GCodeOutputStream &file, const Print &print);
void _print_first_layer_bed_temperature(GCodeOutputStream &file, const Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait); void _print_first_layer_bed_temperature(GCodeOutputStream &file, const Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, const Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait); void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, const Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);

View File

@@ -668,8 +668,14 @@ for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::
m_result.max_print_height = config.max_print_height; m_result.max_print_height = config.max_print_height;
const ConfigOptionBool* spiral_vase = config.option<ConfigOptionBool>("spiral_vase"); const ConfigOptionBool* spiral_vase = config.option<ConfigOptionBool>("spiral_vase");
//w37
if (spiral_vase != nullptr) if (spiral_vase != nullptr)
m_spiral_vase_active = spiral_vase->value; m_detect_layer_based_on_tag = spiral_vase->value;//m_spiral_vase_active = spiral_vase->value;
//w37
const ConfigOptionBool *has_scarf_joint_seam = config.option<ConfigOptionBool>("has_scarf_joint_seam");
if (has_scarf_joint_seam != nullptr)
m_detect_layer_based_on_tag = m_detect_layer_based_on_tag || has_scarf_joint_seam->value;
const ConfigOptionFloat* z_offset = config.option<ConfigOptionFloat>("z_offset"); const ConfigOptionFloat* z_offset = config.option<ConfigOptionFloat>("z_offset");
if (z_offset != nullptr) if (z_offset != nullptr)
@@ -950,8 +956,14 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
m_result.max_print_height = max_print_height->value; m_result.max_print_height = max_print_height->value;
const ConfigOptionBool* spiral_vase = config.option<ConfigOptionBool>("spiral_vase"); const ConfigOptionBool* spiral_vase = config.option<ConfigOptionBool>("spiral_vase");
//w37
if (spiral_vase != nullptr) if (spiral_vase != nullptr)
m_spiral_vase_active = spiral_vase->value; m_detect_layer_based_on_tag = spiral_vase->value;//m_spiral_vase_active = spiral_vase->value;
//w37
const ConfigOptionBool *has_scarf_joint_seam = config.option<ConfigOptionBool>("has_scarf_joint_seam");
if (has_scarf_joint_seam != nullptr)
m_detect_layer_based_on_tag = m_detect_layer_based_on_tag || has_scarf_joint_seam->value;
const ConfigOptionFloat* z_offset = config.option<ConfigOptionFloat>("z_offset"); const ConfigOptionFloat* z_offset = config.option<ConfigOptionFloat>("z_offset");
if (z_offset != nullptr) if (z_offset != nullptr)
@@ -1022,7 +1034,11 @@ void GCodeProcessor::reset()
m_options_z_corrector.reset(); m_options_z_corrector.reset();
m_spiral_vase_active = false; //w37
//m_spiral_vase_active = false;
m_detect_layer_based_on_tag = false;
m_seams_count = 0;
m_kissslicer_toolchange_time_correction = 0.0f; m_kissslicer_toolchange_time_correction = 0.0f;
m_single_extruder_multi_material = false; m_single_extruder_multi_material = false;
@@ -1989,12 +2005,14 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
// layer change tag // layer change tag
if (comment == reserved_tag(ETags::Layer_Change)) { if (comment == reserved_tag(ETags::Layer_Change)) {
++m_layer_id; ++m_layer_id;
if (m_spiral_vase_active) { //w37
if (m_detect_layer_based_on_tag) { // if (m_spiral_vase_active) {
if (m_result.moves.empty() || m_result.spiral_vase_layers.empty()) if (m_result.moves.empty() || m_result.spiral_vase_layers.empty())
// add a placeholder for layer height. the actual value will be set inside process_G1() method // add a placeholder for layer height. the actual value will be set inside process_G1() method
m_result.spiral_vase_layers.push_back({ FLT_MAX, { 0, 0 } }); m_result.spiral_vase_layers.push_back({ FLT_MAX, { 0, 0 } });
else { else {
const size_t move_id = m_result.moves.size() - 1; //w37
const size_t move_id = m_result.moves.size() - 1 - m_seams_count;//const size_t move_id = m_result.moves.size() - 1;
if (!m_result.spiral_vase_layers.empty()) if (!m_result.spiral_vase_layers.empty())
m_result.spiral_vase_layers.back().second.second = move_id; m_result.spiral_vase_layers.back().second.second = move_id;
// add a placeholder for layer height. the actual value will be set inside process_G1() method // add a placeholder for layer height. the actual value will be set inside process_G1() method
@@ -2880,7 +2898,8 @@ void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes
m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]); m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]);
} }
if (m_spiral_vase_active && !m_result.spiral_vase_layers.empty()) { //w37
if (m_detect_layer_based_on_tag && !m_result.spiral_vase_layers.empty()) {//if (m_spiral_vase_active && !m_result.spiral_vase_layers.empty()) {
if (m_result.spiral_vase_layers.back().first == FLT_MAX && delta_pos[Z] >= 0.0) if (m_result.spiral_vase_layers.back().first == FLT_MAX && delta_pos[Z] >= 0.0)
// replace layer height placeholder with correct value // replace layer height placeholder with correct value
m_result.spiral_vase_layers.back().first = static_cast<float>(m_end_position[Z]); m_result.spiral_vase_layers.back().first = static_cast<float>(m_end_position[Z]);
@@ -4437,6 +4456,11 @@ void GCodeProcessor::store_move_vertex(EMoveType type, bool internal_only)
internal_only internal_only
}); });
//w37
if (type == EMoveType::Seam) {
m_seams_count++;
}
// stores stop time placeholders for later use // stores stop time placeholders for later use
if (type == EMoveType::Color_change || type == EMoveType::Pause_Print) { if (type == EMoveType::Color_change || type == EMoveType::Pause_Print) {
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) { for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {

View File

@@ -596,7 +596,10 @@ namespace Slic3r {
SeamsDetector m_seams_detector; SeamsDetector m_seams_detector;
OptionsZCorrector m_options_z_corrector; OptionsZCorrector m_options_z_corrector;
size_t m_last_default_color_id; size_t m_last_default_color_id;
bool m_spiral_vase_active; //w37
//bool m_spiral_vase_active;
bool m_detect_layer_based_on_tag{false};
int m_seams_count;
float m_kissslicer_toolchange_time_correction; float m_kissslicer_toolchange_time_correction;
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time; std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
@@ -676,6 +679,10 @@ namespace Slic3r {
std::vector<std::pair<EMoveType, float>> get_moves_time(PrintEstimatedStatistics::ETimeMode mode) const; std::vector<std::pair<EMoveType, float>> get_moves_time(PrintEstimatedStatistics::ETimeMode mode) const;
std::vector<std::pair<GCodeExtrusionRole, float>> get_roles_time(PrintEstimatedStatistics::ETimeMode mode) const; std::vector<std::pair<GCodeExtrusionRole, float>> get_roles_time(PrintEstimatedStatistics::ETimeMode mode) const;
std::vector<float> get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const; std::vector<float> get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const;
//w37
void detect_layer_based_on_tag(bool enabled) {
m_detect_layer_based_on_tag = enabled;
}
private: private:
void apply_config(const DynamicPrintConfig& config); void apply_config(const DynamicPrintConfig& config);

View File

@@ -444,7 +444,8 @@ std::string GCodeWriter::extrude_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &i
return w.string(); return w.string();
} }
#if 0 //w37
//#if 0
std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std::string_view comment) std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std::string_view comment)
{ {
m_pos = point; m_pos = point;
@@ -453,11 +454,12 @@ std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std
GCodeG1Formatter w; GCodeG1Formatter w;
w.emit_xyz(point); w.emit_xyz(point);
w.emit_e(m_extrusion_axis, m_extruder->E()); //w37
w.emit_e(m_extrusion_axis, m_extruder->extrude(dE).second);
w.emit_comment(this->config.gcode_comments, comment); w.emit_comment(this->config.gcode_comments, comment);
return w.string(); return w.string();
} }
#endif //#endif
std::string GCodeWriter::retract(bool before_wipe) std::string GCodeWriter::retract(bool before_wipe)
{ {

View File

@@ -84,7 +84,8 @@ public:
std::string travel_to_z(double z, const std::string_view comment = {}); std::string travel_to_z(double z, const std::string_view comment = {});
std::string extrude_to_xy(const Vec2d &point, double dE, const std::string_view comment = {}); std::string extrude_to_xy(const Vec2d &point, double dE, const std::string_view comment = {});
std::string extrude_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, double dE, const std::string_view comment); std::string extrude_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, double dE, const std::string_view comment);
// std::string extrude_to_xyz(const Vec3d &point, double dE, const std::string_view comment = {}); //w37
std::string extrude_to_xyz(const Vec3d &point, double dE, const std::string_view comment = {});
std::string retract(bool before_wipe = false); std::string retract(bool before_wipe = false);
std::string retract_for_toolchange(bool before_wipe = false); std::string retract_for_toolchange(bool before_wipe = false);
std::string unretract(); std::string unretract();

View File

@@ -367,6 +367,16 @@ public:
Model* get_model() { return m_model; } Model* get_model() { return m_model; }
const Model* get_model() const { return m_model; } const Model* get_model() const { return m_model; }
//w37
int get_backup_id() const;
template<typename T> const T *get_config_value(const DynamicPrintConfig &global_config, const std::string &config_option)
{
if (config.has(config_option))
return static_cast<const T *>(config.option(config_option));
else
return global_config.option<T>(config_option);
}
ModelVolume* add_volume(const TriangleMesh &mesh); ModelVolume* add_volume(const TriangleMesh &mesh);
ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART); ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART);
ModelVolume* add_volume(const ModelVolume &volume, ModelVolumeType type = ModelVolumeType::INVALID); ModelVolume* add_volume(const ModelVolume &volume, ModelVolumeType type = ModelVolumeType::INVALID);

View File

@@ -495,6 +495,9 @@ static std::vector<std::string> s_Preset_print_options {
,"top_solid_infill_flow_ratio", "bottom_solid_infill_flow_ratio" ,"top_solid_infill_flow_ratio", "bottom_solid_infill_flow_ratio"
//w33 //w33
,"ironing_pattern" ,"ironing_pattern"
//w37
,"seam_slope_type", "seam_slope_conditional", "scarf_angle_threshold", "seam_slope_start_height", "seam_slope_entire_loop", "seam_slope_min_length",
"seam_slope_steps", "seam_slope_inner_walls"
}; };
static std::vector<std::string> s_Preset_filament_options { static std::vector<std::string> s_Preset_filament_options {

View File

@@ -980,6 +980,28 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
new_full_config.option("physical_printer_settings_id", true); new_full_config.option("physical_printer_settings_id", true);
new_full_config.normalize_fdm(); new_full_config.normalize_fdm();
//w37
{
const auto &o = model.objects;
const auto opt_has_scarf_joint_seam = [](const DynamicConfig &c) {
return c.has("seam_slope_type") && c.opt_enum<SeamScarfType>("seam_slope_type") != SeamScarfType::None;
};
const bool has_scarf_joint_seam = std::any_of(o.begin(), o.end(), [&new_full_config, &opt_has_scarf_joint_seam](ModelObject *obj) {
return obj->get_config_value<ConfigOptionEnum<SeamScarfType>>(new_full_config, "seam_slope_type")->value !=
SeamScarfType::None ||
std::any_of(obj->volumes.begin(), obj->volumes.end(),
[&opt_has_scarf_joint_seam](const ModelVolume *v) { return opt_has_scarf_joint_seam(v->config.get()); }) ||
std::any_of(obj->layer_config_ranges.begin(), obj->layer_config_ranges.end(),
[&opt_has_scarf_joint_seam](const auto &r) { return opt_has_scarf_joint_seam(r.second.get()); });
});
if (has_scarf_joint_seam) {
new_full_config.set("has_scarf_joint_seam", true);
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", has_scarf_joint_seam:" << has_scarf_joint_seam;
}
// Find modified keys of the various configs. Resolve overrides extruder retract values by filament profiles. // Find modified keys of the various configs. Resolve overrides extruder retract values by filament profiles.
DynamicPrintConfig filament_overrides; DynamicPrintConfig filament_overrides;
t_config_option_keys print_diff = print_config_diffs(m_config, new_full_config, filament_overrides); t_config_option_keys print_diff = print_config_diffs(m_config, new_full_config, filament_overrides);

View File

@@ -170,6 +170,14 @@ static const t_config_enum_values s_keys_map_SeamPosition {
}; };
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SeamPosition) CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SeamPosition)
//w37
static t_config_enum_values s_keys_map_SeamScarfType{
{"none", int(SeamScarfType::None)},
{"external", int(SeamScarfType::External)},
{"all", int(SeamScarfType::All)},
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SeamScarfType)
static const t_config_enum_values s_keys_map_SLADisplayOrientation = { static const t_config_enum_values s_keys_map_SLADisplayOrientation = {
{ "landscape", sladoLandscape}, { "landscape", sladoLandscape},
{ "portrait", sladoPortrait} { "portrait", sladoPortrait}
@@ -1984,6 +1992,11 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<MachineLimitsUsage>(MachineLimitsUsage::TimeEstimateOnly)); def->set_default_value(new ConfigOptionEnum<MachineLimitsUsage>(MachineLimitsUsage::TimeEstimateOnly));
//w37
def = this->add("has_scarf_joint_seam", coBool);
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
{ {
struct AxisDefault { struct AxisDefault {
std::string name; std::string name;
@@ -2679,6 +2692,69 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert; def->mode = comExpert;
def->set_default_value(new ConfigOptionPercent(15)); def->set_default_value(new ConfigOptionPercent(15));
//w37
def = this->add("seam_slope_type", coEnum);
def->label = L("Scarf joint seam (beta)");
def->tooltip = L("Use scarf joint to minimize seam visibility and increase seam strength.");
def->set_enum<SeamScarfType>({{"none", L("None")}, {"external", L("Contour")}, {"all", L("Contour and hole")}});
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<SeamScarfType>(SeamScarfType::None));
def = this->add("seam_slope_conditional", coBool);
def->label = L("Conditional scarf joint");
def->tooltip = L(
"Apply scarf joints only to smooth perimeters where traditional seams do not conceal the seams at sharp corners effectively.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true));
def = this->add("scarf_angle_threshold", coInt);
def->label = L("Conditional angle threshold");
def->tooltip = L(
"This option sets the threshold angle for applying a conditional scarf joint seam.\nIf the maximum angle within the perimeter loop "
"exceeds this value (indicating the absence of sharp corners), a scarf joint seam will be used. The default value is 155°.");
def->mode = comAdvanced;
def->sidetext = L("°");
def->min = 0;
def->max = 180;
def->set_default_value(new ConfigOptionInt(155));
def = this->add("seam_slope_start_height", coFloatOrPercent);
def->label = L("Scarf start height");
def->tooltip = L("Start height of the scarf.\n"
"This amount can be specified in millimeters or as a percentage of the current layer height. The default value for "
"this parameter is 0.");
def->sidetext = L("mm or %");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0.1, false));
def = this->add("seam_slope_entire_loop", coBool);
def->label = L("Scarf around entire wall");
def->tooltip = L("The scarf extends to the entire length of the wall.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("seam_slope_min_length", coFloat);
def->label = L("Scarf length");
def->tooltip = L("Length of the scarf. Setting this parameter to zero effectively disables the scarf.");
def->sidetext = L("mm");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(10));
def = this->add("seam_slope_steps", coInt);
def->label = L("Scarf steps");
def->tooltip = L("Minimum number of segments of each scarf.");
def->min = 1;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(10));
def = this->add("seam_slope_inner_walls", coBool);
def->label = L("Scarf joint for inner walls");
def->tooltip = L("Use scarf joint for inner walls as well.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true));
def = this->add("staggered_inner_seams", coBool); def = this->add("staggered_inner_seams", coBool);
def->label = L("Staggered inner seams"); def->label = L("Staggered inner seams");
// TRN PrintSettings: "Staggered inner seams" // TRN PrintSettings: "Staggered inner seams"

View File

@@ -106,6 +106,13 @@ enum SeamPosition {
spRandom, spNearest, spAligned, spRear spRandom, spNearest, spAligned, spRear
}; };
//w37
enum class SeamScarfType {
None,
External,
All,
};
enum SLAMaterial { enum SLAMaterial {
slamTough, slamTough,
slamFlex, slamFlex,
@@ -168,6 +175,8 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialPattern)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialStyle) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialStyle)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialInterfacePattern) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialInterfacePattern)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SeamPosition) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SeamPosition)
//w37
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SeamScarfType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SLADisplayOrientation) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SLADisplayOrientation)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SLAPillarConnectionMode) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SLAPillarConnectionMode)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SLASupportTreeType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SLASupportTreeType)
@@ -607,6 +616,15 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, only_one_wall_first_layer)) ((ConfigOptionBool, only_one_wall_first_layer))
//w27 //w27
((ConfigOptionBool, precise_z_height)) ((ConfigOptionBool, precise_z_height))
//w37
((ConfigOptionEnum<SeamScarfType>, seam_slope_type))
((ConfigOptionBool, seam_slope_conditional))
((ConfigOptionInt, scarf_angle_threshold))
((ConfigOptionFloatOrPercent, seam_slope_start_height))
((ConfigOptionBool, seam_slope_entire_loop))
((ConfigOptionFloat, seam_slope_min_length))
((ConfigOptionInt, seam_slope_steps))
((ConfigOptionBool, seam_slope_inner_walls))
) )
PRINT_CONFIG_CLASS_DEFINE( PRINT_CONFIG_CLASS_DEFINE(
@@ -707,6 +725,8 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloats, machine_min_travel_rate)) ((ConfigOptionFloats, machine_min_travel_rate))
// M205 S... [mm/sec] // M205 S... [mm/sec]
((ConfigOptionFloats, machine_min_extruding_rate)) ((ConfigOptionFloats, machine_min_extruding_rate))
//w37
((ConfigOptionBool, has_scarf_joint_seam))
) )
PRINT_CONFIG_CLASS_DEFINE( PRINT_CONFIG_CLASS_DEFINE(

View File

@@ -884,6 +884,16 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "seam_gap" || opt_key == "seam_gap"
|| opt_key == "seam_preferred_direction" || opt_key == "seam_preferred_direction"
|| opt_key == "seam_preferred_direction_jitter" || opt_key == "seam_preferred_direction_jitter"
//w37
|| opt_key == "seam_slope_type"
|| opt_key == "seam_slope_conditional"
|| opt_key == "scarf_angle_threshold"
|| opt_key == "seam_slope_start_height"
|| opt_key == "seam_slope_entire_loop"
|| opt_key == "seam_slope_min_length"
|| opt_key == "seam_slope_steps"
|| opt_key == "seam_slope_inner_walls"
|| opt_key == "support_material_speed" || opt_key == "support_material_speed"
|| opt_key == "support_material_interface_speed" || opt_key == "support_material_interface_speed"
|| opt_key == "bridge_speed" || opt_key == "bridge_speed"

View File

@@ -380,6 +380,17 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
bool is_top_one_wall = config->opt_enum<TopOneWallType>("top_one_wall_type") != TopOneWallType::Disable; bool is_top_one_wall = config->opt_enum<TopOneWallType>("top_one_wall_type") != TopOneWallType::Disable;
toggle_field("top_area_threshold", is_top_one_wall); toggle_field("top_area_threshold", is_top_one_wall);
//w37
toggle_field("seam_slope_type", !has_spiral_vase);
bool has_seam_slope = !has_spiral_vase && config->opt_enum<SeamScarfType>("seam_slope_type") != SeamScarfType::None;
toggle_field("seam_slope_conditional", has_seam_slope);
toggle_field("scarf_angle_threshold", has_seam_slope && config->opt_bool("seam_slope_conditional"));
toggle_field("seam_slope_start_height", has_seam_slope);
toggle_field("seam_slope_entire_loop", has_seam_slope);
toggle_field("seam_slope_min_length", has_seam_slope);
toggle_field("seam_slope_steps", has_seam_slope);
toggle_field("seam_slope_inner_walls", has_seam_slope);
toggle_field("seam_slope_min_length", !config->opt_bool("seam_slope_entire_loop"));
} }
void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config) void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config)

View File

@@ -1465,6 +1465,18 @@ void TabPrint::build()
//Y21 //Y21
optgroup->append_single_option_line("seam_gap", category_path + "seam-gap"); optgroup->append_single_option_line("seam_gap", category_path + "seam-gap");
optgroup->append_single_option_line("staggered_inner_seams", category_path + "staggered-inner-seams"); optgroup->append_single_option_line("staggered_inner_seams", category_path + "staggered-inner-seams");
//w37
optgroup->append_single_option_line("seam_slope_type");
optgroup->append_single_option_line("seam_slope_conditional");
optgroup->append_single_option_line("scarf_angle_threshold");
optgroup->append_single_option_line("seam_slope_start_height");
optgroup->append_single_option_line("seam_slope_entire_loop");
optgroup->append_single_option_line("seam_slope_min_length");
//optgroup->append_single_option_line("seam_slope_steps");
optgroup->append_single_option_line("seam_slope_inner_walls");
optgroup->append_single_option_line("external_perimeters_first", category_path + "external-perimeters-first"); optgroup->append_single_option_line("external_perimeters_first", category_path + "external-perimeters-first");
optgroup->append_single_option_line("gap_fill_enabled", category_path + "fill-gaps"); optgroup->append_single_option_line("gap_fill_enabled", category_path + "fill-gaps");
optgroup->append_single_option_line("perimeter_generator"); optgroup->append_single_option_line("perimeter_generator");