mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-08 16:21:14 +00:00
Merge remote-tracking branch 'upstream/main' into belt/baseChanges
Conflicts resolved in src/libslic3r/GCode.cpp and src/slic3r/GUI/GUI_Factories.cpp. GCode.cpp: combined upstream's air-filtration per-extruder gating (activate_air_filtration_during_print / _on_completion), the new extrusion-role-change gcode lambda, ZAA's path.z_contoured arc-fit disable, raft-aware slow_down_layers branch, and Vec3d/Line3 ZAA plumbing with the local belt-printer changes (path_on_first_layer, effective_layer_index_for_point, should_disable_arc_fitting). All auto-merged m_writer.X() calls converted to m_writer->X() to match the local unique_ptr<GCodeWriter> refactor. GUI_Factories.cpp: inserted brim_flow_ratio in the Support category list and renumbered around the local build_plate_tilt_x/y entries. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+328
-110
@@ -1,5 +1,6 @@
|
||||
#include "BoundingBox.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "GCodeWriter.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "libslic3r.h"
|
||||
@@ -24,11 +25,13 @@
|
||||
#include "Time.hpp"
|
||||
#include "GCode/ExtrusionProcessor.hpp"
|
||||
#include <algorithm>
|
||||
#include <cfloat>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
@@ -94,6 +97,16 @@ static const float g_purge_volume_one_time = 135.f;
|
||||
static const int g_max_flush_count = 4;
|
||||
static const size_t g_max_label_object = 64;
|
||||
|
||||
static bool is_bambu_x2d_printer(const FullPrintConfig &config)
|
||||
{
|
||||
return config.printer_model.value == "Bambu Lab X2D";
|
||||
}
|
||||
|
||||
static int hotend_id_for_gcode_placeholder(const FullPrintConfig &config, int hotend_id)
|
||||
{
|
||||
return is_bambu_x2d_printer(config) ? -1 : hotend_id;
|
||||
}
|
||||
|
||||
Vec2d travel_point_1;
|
||||
Vec2d travel_point_2;
|
||||
Vec2d travel_point_3;
|
||||
@@ -835,6 +848,10 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
|
||||
config.set_key_value("previous_extruder", new ConfigOptionInt(old_filament_id));
|
||||
config.set_key_value("next_extruder", new ConfigOptionInt(new_filament_id));
|
||||
config.set_key_value("current_hotend", new ConfigOptionInt(old_extruder_id >= 0 ?
|
||||
hotend_id_for_gcode_placeholder(gcodegen.m_config, old_extruder_id) : -1));
|
||||
config.set_key_value("next_hotend",
|
||||
new ConfigOptionInt(hotend_id_for_gcode_placeholder(gcodegen.m_config, (int) gcodegen.get_extruder_id(new_filament_id))));
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z));
|
||||
config.set_key_value("toolchange_z", new ConfigOptionFloat(z));
|
||||
@@ -916,6 +933,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
|
||||
auto flush_v_speed = m_print_config->filament_flush_volumetric_speed.values;
|
||||
auto flush_temps = m_print_config->filament_flush_temp.values;
|
||||
auto filament_cooling_before_tower = m_print_config->filament_cooling_before_tower.values;
|
||||
for (size_t idx = 0; idx < flush_v_speed.size(); ++idx) {
|
||||
if (flush_v_speed[idx] == 0)
|
||||
flush_v_speed[idx] = m_print_config->filament_max_volumetric_speed.get_at(idx);
|
||||
@@ -924,8 +942,13 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
if (flush_temps[idx] == 0)
|
||||
flush_temps[idx] = m_print_config->nozzle_temperature_range_high.get_at(idx);
|
||||
}
|
||||
if (filament_cooling_before_tower.size() < m_print_config->filament_type.values.size())
|
||||
filament_cooling_before_tower.resize(m_print_config->filament_type.values.size(), m_print_config->filament_cooling_before_tower.get_at(0));
|
||||
if (tcr.is_contact || gcodegen.m_layer_index == 0)
|
||||
std::fill(filament_cooling_before_tower.begin(), filament_cooling_before_tower.end(), 0);
|
||||
config.set_key_value("flush_volumetric_speeds", new ConfigOptionFloats(flush_v_speed));
|
||||
config.set_key_value("flush_temperatures", new ConfigOptionInts(flush_temps));
|
||||
config.set_key_value("filament_cooling_before_tower", new ConfigOptionFloats(filament_cooling_before_tower));
|
||||
config.set_key_value("flush_length", new ConfigOptionFloat(purge_length));
|
||||
config.set_key_value("wipe_avoid_perimeter", new ConfigOptionBool(is_used_travel_avoid_perimeter));
|
||||
config.set_key_value("wipe_avoid_pos_x", new ConfigOptionFloat(wipe_avoid_pos_x));
|
||||
@@ -1956,6 +1979,7 @@ namespace DoExport {
|
||||
//if (ret.size() < MAX_TAGS_COUNT) check(_(L("Color Change G-code")), config.color_change_gcode.value);
|
||||
//Orca
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Change extrusion role G-code")), config.change_extrusion_role_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Process change extrusion role G-code")), config.process_change_extrusion_role_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Pause G-code")), config.machine_pause_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Template Custom G-code")), config.template_custom_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) {
|
||||
@@ -1972,6 +1996,13 @@ namespace DoExport {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret.size() < MAX_TAGS_COUNT) {
|
||||
for (const std::string& value : config.filament_change_extrusion_role_gcode.values) {
|
||||
check(_(L("Filament change extrusion role G-code")), value);
|
||||
if (ret.size() == MAX_TAGS_COUNT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
//BBS: no custom_gcode_per_print_z, don't need to check
|
||||
//if (ret.size() < MAX_TAGS_COUNT) {
|
||||
// const CustomGCode::Info& custom_gcode_per_print_z = print.model().custom_gcode_per_print_z;
|
||||
@@ -2418,6 +2449,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
m_max_layer_z = 0.f;
|
||||
m_last_width = 0.f;
|
||||
m_is_role_based_fan_on.fill(false);
|
||||
m_role_based_fan_marker_layer.fill(-1);
|
||||
|
||||
m_fan_mover.release();
|
||||
|
||||
@@ -2513,7 +2545,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
} else
|
||||
m_enable_extrusion_role_markers = false;
|
||||
|
||||
if (!print.config().small_area_infill_flow_compensation_model.empty())
|
||||
if (m_config.small_area_infill_flow_compensation.value && !m_config.small_area_infill_flow_compensation_model.empty())
|
||||
m_small_area_infill_flow_compensator = make_unique<SmallAreaInfillFlowCompensator>(print.config());
|
||||
|
||||
// Process file_start_gcode - written at the very top of the file, before any header
|
||||
@@ -2818,7 +2850,10 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
this->placeholder_parser().set("first_non_support_filaments", new ConfigOptionInts(first_non_support_filaments));
|
||||
this->placeholder_parser().set("initial_no_support_tool", initial_non_support_extruder_id);
|
||||
this->placeholder_parser().set("initial_no_support_extruder", initial_non_support_extruder_id);
|
||||
this->placeholder_parser().set("initial_no_support_hotend",
|
||||
hotend_id_for_gcode_placeholder(m_config, (int) get_extruder_id(initial_non_support_extruder_id)));
|
||||
this->placeholder_parser().set("current_extruder", initial_extruder_id);
|
||||
this->placeholder_parser().set("current_hotend", hotend_id_for_gcode_placeholder(m_config, extruder_id));
|
||||
//Orca: set the key for compatibilty
|
||||
this->placeholder_parser().set("retraction_distance_when_cut", m_config.retraction_distances_when_cut.get_at(initial_extruder_id));
|
||||
this->placeholder_parser().set("long_retraction_when_cut", m_config.long_retractions_when_cut.get_at(initial_extruder_id));
|
||||
@@ -2833,7 +2868,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
this->placeholder_parser().set("long_retractions_when_ec",new ConfigOptionBoolsNullable(m_config.long_retractions_when_ec));
|
||||
|
||||
this->placeholder_parser().set("max_additional_fan", max_additional_fan);
|
||||
this->placeholder_parser().set("first_x_layer_fan_speed", 0); // TODO: Orca hack to support BBL profiles
|
||||
this->placeholder_parser().set("first_x_layer_fan_speed", new ConfigOptionFloats(m_config.first_x_layer_fan_speed));
|
||||
this->placeholder_parser().set("close_additional_fan_first_x_layers", new ConfigOptionInts(m_config.close_additional_fan_first_x_layers));
|
||||
this->placeholder_parser().set("additional_fan_full_speed_layer", new ConfigOptionInts(m_config.additional_fan_full_speed_layer));
|
||||
|
||||
auto flush_v_speed = m_config.filament_flush_volumetric_speed.values;
|
||||
auto flush_temps = m_config.filament_flush_temp.values;
|
||||
@@ -2847,6 +2884,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
}
|
||||
this->placeholder_parser().set("flush_volumetric_speeds", new ConfigOptionFloats(flush_v_speed));
|
||||
this->placeholder_parser().set("flush_temperatures", new ConfigOptionInts(flush_temps));
|
||||
this->placeholder_parser().set("filament_cooling_before_tower", new ConfigOptionFloatsNullable(m_config.filament_cooling_before_tower));
|
||||
//Set variable for total layer count so it can be used in custom gcode.
|
||||
this->placeholder_parser().set("total_layer_count", m_layer_count);
|
||||
// Useful for sequential prints.
|
||||
@@ -3138,15 +3176,16 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
this->_print_first_layer_extruder_temperatures(file, print, machine_start_gcode, initial_extruder_id, true);
|
||||
}
|
||||
// Orca: when activate_air_filtration is set on any extruder, find and set the highest during_print_exhaust_fan_speed
|
||||
bool activate_air_filtration = false;
|
||||
bool activate_air_filtration_during_print = false;
|
||||
int during_print_exhaust_fan_speed = 0;
|
||||
for (const auto &extruder : m_writer->extruders()) {
|
||||
activate_air_filtration |= m_config.activate_air_filtration.get_at(extruder.id());
|
||||
if (m_config.activate_air_filtration.get_at(extruder.id()))
|
||||
if (m_config.activate_air_filtration.get_at(extruder.id()) && m_config.activate_air_filtration_during_print.get_at(extruder.id())) {
|
||||
activate_air_filtration_during_print = true;
|
||||
during_print_exhaust_fan_speed = std::max(during_print_exhaust_fan_speed,
|
||||
m_config.during_print_exhaust_fan_speed.get_at(extruder.id()));
|
||||
}
|
||||
}
|
||||
if (activate_air_filtration)
|
||||
if (activate_air_filtration_during_print)
|
||||
file.write(m_writer->set_exhaust_fan(during_print_exhaust_fan_speed, true));
|
||||
|
||||
print.throw_if_canceled();
|
||||
@@ -3448,13 +3487,16 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
if (activate_chamber_temp_control && max_chamber_temp > 0)
|
||||
file.write(m_writer->set_chamber_temperature(0, false)); //close chamber_temperature
|
||||
|
||||
if (activate_air_filtration) {
|
||||
int complete_print_exhaust_fan_speed = 0;
|
||||
for (const auto& extruder : m_writer->extruders())
|
||||
if (m_config.activate_air_filtration.get_at(extruder.id()))
|
||||
complete_print_exhaust_fan_speed = std::max(complete_print_exhaust_fan_speed, m_config.complete_print_exhaust_fan_speed.get_at(extruder.id()));
|
||||
file.write(m_writer->set_exhaust_fan(complete_print_exhaust_fan_speed, true));
|
||||
bool activate_air_filtration_on_completion = false;
|
||||
int complete_print_exhaust_fan_speed = 0;
|
||||
for (const auto& extruder : m_writer->extruders()) {
|
||||
if (m_config.activate_air_filtration.get_at(extruder.id()) && m_config.activate_air_filtration_on_completion.get_at(extruder.id())) {
|
||||
activate_air_filtration_on_completion = true;
|
||||
complete_print_exhaust_fan_speed = std::max(complete_print_exhaust_fan_speed, m_config.complete_print_exhaust_fan_speed.get_at(extruder.id()));
|
||||
}
|
||||
}
|
||||
if (activate_air_filtration_on_completion)
|
||||
file.write(m_writer->set_exhaust_fan(complete_print_exhaust_fan_speed, true));
|
||||
// adds tags for time estimators
|
||||
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Last_Line_M73_Placeholder).c_str());
|
||||
file.write_format("; EXECUTABLE_BLOCK_END\n\n");
|
||||
@@ -3545,6 +3587,30 @@ void GCode::export_layer_filaments(GCodeProcessorResult* result)
|
||||
iter->second.emplace_back(idx, idx);
|
||||
}
|
||||
}
|
||||
|
||||
result->filament_change_sequence.clear();
|
||||
result->nozzle_change_sequence.clear();
|
||||
|
||||
int prev_sequence_filament = -1;
|
||||
int prev_sequence_nozzle = -1;
|
||||
for (size_t layer_idx = 0; layer_idx < m_sorted_layer_filaments.size(); ++layer_idx) {
|
||||
for (unsigned int filament_id : m_sorted_layer_filaments[layer_idx]) {
|
||||
int nozzle_id = 0;
|
||||
if (filament_id < filament_map.size() && filament_map[filament_id] > 0)
|
||||
nozzle_id = filament_map[filament_id] - 1;
|
||||
if (prev_sequence_nozzle != nozzle_id || prev_sequence_filament != static_cast<int>(filament_id)) {
|
||||
result->nozzle_change_sequence.emplace_back(static_cast<unsigned int>(nozzle_id));
|
||||
result->filament_change_sequence.emplace_back(filament_id);
|
||||
prev_sequence_nozzle = nozzle_id;
|
||||
prev_sequence_filament = static_cast<int>(filament_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result->optimal_assignment.clear();
|
||||
result->optimal_assignment.reserve(filament_map.size());
|
||||
for (int nozzle_id : filament_map)
|
||||
result->optimal_assignment.emplace_back(nozzle_id > 0 ? nozzle_id - 1 : 0);
|
||||
}
|
||||
|
||||
//BBS
|
||||
@@ -4519,8 +4585,7 @@ LayerResult GCode::process_layer(
|
||||
break;
|
||||
}
|
||||
case CalibMode::Calib_Temp_Tower: {
|
||||
auto offset = static_cast<unsigned int>(print_z / 10.001) * 5;
|
||||
gcode += writer().set_temperature(print.calib_params().start - offset);
|
||||
gcode += writer().set_temperature(this->interpolate_value_across_layers(static_cast<float>(print.calib_params().start), static_cast<float>(print.calib_params().end), 5.0f));
|
||||
break;
|
||||
}
|
||||
case CalibMode::Calib_VFA_Tower: {
|
||||
@@ -5494,6 +5559,7 @@ void GCode::apply_print_config(const PrintConfig &print_config)
|
||||
&m_config.time_lapse_gcode,
|
||||
&m_config.change_filament_gcode,
|
||||
&m_config.change_extrusion_role_gcode,
|
||||
&m_config.process_change_extrusion_role_gcode,
|
||||
&m_config.printing_by_object_gcode,
|
||||
&m_config.machine_pause_gcode,
|
||||
&m_config.template_custom_gcode,
|
||||
@@ -5503,7 +5569,8 @@ void GCode::apply_print_config(const PrintConfig &print_config)
|
||||
}
|
||||
for (auto opt : std::initializer_list<ConfigOptionStrings*>{
|
||||
&m_config.filament_start_gcode,
|
||||
&m_config.filament_end_gcode
|
||||
&m_config.filament_end_gcode,
|
||||
&m_config.filament_change_extrusion_role_gcode
|
||||
}) {
|
||||
if (opt->empty())
|
||||
for (int i = 0; i < opt->size(); ++i)
|
||||
@@ -5583,12 +5650,12 @@ void GCode::set_extruders(const std::vector<unsigned int> &extruder_ids)
|
||||
void GCode::set_origin(const Vec2d &pointf)
|
||||
{
|
||||
// if origin increases (goes towards right), last_pos decreases because it goes towards left
|
||||
const Point translate(
|
||||
const Point3 translate(
|
||||
scale_(m_origin(0) - pointf(0)),
|
||||
scale_(m_origin(1) - pointf(1))
|
||||
);
|
||||
m_last_pos += translate;
|
||||
m_wipe.path.translate(translate);
|
||||
m_wipe.path.translate(translate.to_point());
|
||||
m_origin = pointf;
|
||||
}
|
||||
|
||||
@@ -5665,11 +5732,15 @@ static std::unique_ptr<EdgeGrid::Grid> calculate_layer_edge_grid(const Layer& la
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, double speed, const ExtrusionEntitiesPtr& region_perimeters, const Point* start_point)
|
||||
std::string GCode::extrude_loop(const ExtrusionLoop& loop_ref,
|
||||
const std::string& description,
|
||||
double speed,
|
||||
const ExtrusionEntitiesPtr& region_perimeters,
|
||||
const Point* start_point)
|
||||
{
|
||||
|
||||
// get a copy; don't modify the orientation of the original loop object otherwise
|
||||
// next copies (if any) would not detect the correct orientation
|
||||
ExtrusionLoop loop = loop_ref;
|
||||
|
||||
bool is_hole = (loop.loop_role() & elrHole) == elrHole;
|
||||
|
||||
@@ -5744,13 +5815,14 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
||||
const double nozzle_diam = nozzle_diameter;
|
||||
|
||||
// note: previous & next are inverted to extrude "in the opposite direction, and we are "rewinding"
|
||||
Point previous_point = paths.front().polyline.points[1];
|
||||
Point current_point = paths.front().polyline.points.front();
|
||||
Point next_point = paths.back().polyline.points.back();
|
||||
Point previous_point = Point(paths.front().polyline.points[1].x(), paths.front().polyline.points[1].y());
|
||||
Point current_point = Point(paths.front().polyline.points.front().x(), paths.front().polyline.points.front().y());
|
||||
Point next_point = Point(paths.back().polyline.points.back().x(), paths.back().polyline.points.back().y());
|
||||
|
||||
// can happen if seam_gap is null
|
||||
if (next_point == current_point) {
|
||||
next_point = paths.back().polyline.points[paths.back().polyline.points.size() - 2];
|
||||
const Point3 &p3 = paths.back().polyline.points[paths.back().polyline.points.size() - 2];
|
||||
next_point = Point(p3.x(), p3.y());
|
||||
}
|
||||
|
||||
Point a = next_point; // second point
|
||||
@@ -5797,7 +5869,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
||||
// inside the model
|
||||
if(discoveredTouchingLines > 1){
|
||||
// use extrude instead of travel_to_xy to trigger the unretract
|
||||
ExtrusionPath fake_path_wipe(Polyline{pt, current_point}, paths.front());
|
||||
ExtrusionPath fake_path_wipe(Polyline3(Points3{Point3(pt), Point3(current_point)}), paths.front());
|
||||
fake_path_wipe.set_force_no_extrusion(true);
|
||||
fake_path_wipe.mm3_per_mm = 0;
|
||||
//fake_path_wipe.set_extrusion_role(erExternalPerimeter);
|
||||
@@ -5833,7 +5905,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
||||
if (!enable_seam_slope) {
|
||||
for (ExtrusionPaths::iterator path = paths.begin(); path != paths.end(); ++path) {
|
||||
gcode += this->_extrude(*path, description, speed_for_path(*path));
|
||||
// Orca: Adaptive PA - dont adapt PA after the first pultipath extrusion is completed
|
||||
// Orca: Adaptive PA - dont adapt PA after the first multipath extrusion is completed
|
||||
// as we have already set the PA value to the average flow over the totality of the path
|
||||
// in the first extrude move
|
||||
// TODO: testing is needed with slope seams and adaptive PA.
|
||||
@@ -5891,10 +5963,12 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
||||
for (ExtrusionPath &path : paths) {
|
||||
//BBS: Don't need to save duplicated point into wipe path
|
||||
if (!m_wipe.path.empty() && !path.empty() &&
|
||||
m_wipe.path.last_point() == path.first_point())
|
||||
m_wipe.path.append(path.polyline.points.begin() + 1, path.polyline.points.end());
|
||||
else
|
||||
m_wipe.path.append(path.polyline); // TODO: don't limit wipe to last path
|
||||
m_wipe.path.last_point() == Point(path.first_point().x(), path.first_point().y())) {
|
||||
// Convert Points3 to Points
|
||||
for (auto it = path.polyline.points.begin() + 1; it != path.polyline.points.end(); ++it)
|
||||
m_wipe.path.append(Point(it->x(), it->y()));
|
||||
} else
|
||||
m_wipe.path.append(path.polyline.to_polyline()); // TODO: don't limit wipe to last path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5904,8 +5978,10 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
||||
// the side depends on the original winding order of the polygon (inwards for contours, outwards for holes)
|
||||
//FIXME improve the algorithm in case the loop is tiny.
|
||||
//FIXME improve the algorithm in case the loop is split into segments with a low number of points (see the Point b query).
|
||||
Point a = paths.front().polyline.points[1]; // second point
|
||||
Point b = *(paths.back().polyline.points.end()-3); // second to last point
|
||||
const Point3 &a3 = paths.front().polyline.points[1]; // second point
|
||||
Point a = Point(a3.x(), a3.y());
|
||||
const Point3 &b3 = *(paths.back().polyline.points.end()-3); // second to last point
|
||||
Point b = Point(b3.x(), b3.y());
|
||||
if (is_hole == loop.is_counter_clockwise()) {
|
||||
// swap points
|
||||
Point c = a; a = b; b = c;
|
||||
@@ -5919,8 +5995,8 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
||||
// create the destination point along the first segment and rotate it
|
||||
// we make sure we don't exceed the segment length because we don't know
|
||||
// the rotation of the second segment so we might cross the object boundary
|
||||
Vec2d p1 = paths.front().polyline.points.front().cast<double>();
|
||||
Vec2d p2 = paths.front().polyline.points[1].cast<double>();
|
||||
Vec2d p1 = paths.front().polyline.points.front().cast<double>().head<2>();
|
||||
Vec2d p2 = paths.front().polyline.points[1].cast<double>().head<2>();
|
||||
Vec2d v = p2 - p1;
|
||||
double nd = scale_(EXTRUDER_CONFIG(nozzle_diameter));
|
||||
double l2 = v.squaredNorm();
|
||||
@@ -5932,19 +6008,20 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
||||
if (nd * nd < l2)
|
||||
pt = (p1 + threshold * v * (nd / sqrt(l2))).cast<coord_t>();
|
||||
//Point pt = ((nd * nd >= l2) ? (p1+v*0.4): (p1 + 0.2 * v * (nd / sqrt(l2)))).cast<coord_t>();
|
||||
pt.rotate(angle, paths.front().polyline.points.front());
|
||||
const Point3 ¢er3 = paths.front().polyline.points.front();
|
||||
pt.rotate(angle, Point(center3.x(), center3.y()));
|
||||
// generate the travel move
|
||||
gcode += m_writer->extrude_to_xy(this->point_to_gcode(pt), 0,"move inwards before travel",true);
|
||||
gcode += m_writer->extrude_to_xy(this->point_to_gcode(pt), 0, "move inwards before travel", true);
|
||||
}
|
||||
|
||||
return gcode;
|
||||
}
|
||||
|
||||
std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string description, double speed)
|
||||
std::string GCode::extrude_multi_path(const ExtrusionMultiPath& multipath, const std::string& description, double speed)
|
||||
{
|
||||
// extrude along the path
|
||||
std::string gcode;
|
||||
|
||||
|
||||
//Orca: calculate multipath average mm3_per_mm value over the length of the path.
|
||||
//This is used for adaptive PA
|
||||
m_multi_flow_segment_path_pa_set = false; // always emit PA on the first path of the multi-path
|
||||
@@ -5961,8 +6038,8 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string
|
||||
if (total_multipath_length > 0.0)
|
||||
m_multi_flow_segment_path_average_mm3_per_mm = weighted_sum_mm3_per_mm / total_multipath_length;
|
||||
// Orca: end of multipath average mm3_per_mm value calculation
|
||||
|
||||
for (ExtrusionPath path : multipath.paths){
|
||||
|
||||
for (const ExtrusionPath &path : multipath.paths){
|
||||
gcode += this->_extrude(path, description, speed);
|
||||
// Orca: Adaptive PA - dont adapt PA after the first pultipath extrusion is completed
|
||||
// as we have already set the PA value to the average flow over the totality of the path
|
||||
@@ -5973,13 +6050,15 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string
|
||||
// BBS
|
||||
if (m_wipe.enable && FILAMENT_CONFIG(wipe)) {
|
||||
m_wipe.path = Polyline();
|
||||
for (ExtrusionPath &path : multipath.paths) {
|
||||
for (const ExtrusionPath &path : multipath.paths) {
|
||||
//BBS: Don't need to save duplicated point into wipe path
|
||||
if (!m_wipe.path.empty() && !path.empty() &&
|
||||
m_wipe.path.last_point() == path.first_point())
|
||||
m_wipe.path.append(path.polyline.points.begin() + 1, path.polyline.points.end());
|
||||
else
|
||||
m_wipe.path.append(path.polyline); // TODO: don't limit wipe to last path
|
||||
m_wipe.path.last_point() == Point(path.first_point().x(), path.first_point().y())) {
|
||||
// Convert Points3 to Points
|
||||
for (auto it = path.polyline.points.begin() + 1; it != path.polyline.points.end(); ++it)
|
||||
m_wipe.path.append(Point(it->x(), it->y()));
|
||||
} else
|
||||
m_wipe.path.append(path.polyline.to_polyline()); // TODO: don't limit wipe to last path
|
||||
}
|
||||
m_wipe.path.reverse();
|
||||
}
|
||||
@@ -5987,7 +6066,10 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string
|
||||
return gcode;
|
||||
}
|
||||
|
||||
std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string description, double speed, const ExtrusionEntitiesPtr& region_perimeters)
|
||||
std::string GCode::extrude_entity(const ExtrusionEntity& entity,
|
||||
const std::string& description,
|
||||
double speed,
|
||||
const ExtrusionEntitiesPtr& region_perimeters)
|
||||
{
|
||||
if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(&entity))
|
||||
return this->extrude_path(*path, description, speed);
|
||||
@@ -6000,7 +6082,7 @@ std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string des
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string GCode::extrude_path(ExtrusionPath path, std::string description, double speed)
|
||||
std::string GCode::extrude_path(const ExtrusionPath& path, const std::string& description, double speed)
|
||||
{
|
||||
// Orca: Reset average multipath flow as this is a single line, single extrude volumetric speed path
|
||||
m_multi_flow_segment_path_pa_set = false;
|
||||
@@ -6008,17 +6090,17 @@ std::string GCode::extrude_path(ExtrusionPath path, std::string description, dou
|
||||
// description += ExtrusionEntity::role_to_string(path.role());
|
||||
std::string gcode = this->_extrude(path, description, speed);
|
||||
if (m_wipe.enable && FILAMENT_CONFIG(wipe)) {
|
||||
m_wipe.path = path.polyline;
|
||||
m_wipe.path = path.polyline.to_polyline();
|
||||
if (is_tree(this->config().support_type) && (path.role() == erSupportMaterial || path.role() == erSupportMaterialInterface || path.role() == erSupportTransition)) {
|
||||
if ((m_wipe.path.first_point() - m_wipe.path.last_point()).cast<double>().norm() > scale_(0.2)) {
|
||||
double min_dist = scale_(0.2);
|
||||
int i = 0;
|
||||
for (; i < path.polyline.points.size(); i++) {
|
||||
double dist = (path.polyline.points[i] - path.last_point()).cast<double>().norm();
|
||||
double dist = (path.polyline.points[i] - path.last_point3()).cast<double>().norm();
|
||||
if (dist < min_dist) min_dist = dist;
|
||||
if (min_dist < scale_(0.2) && dist > min_dist) break;
|
||||
}
|
||||
m_wipe.path = Polyline(Points(path.polyline.points.begin() + i - 1, path.polyline.points.end()));
|
||||
m_wipe.path = Polyline3(Points3(path.polyline.points.begin() + i - 1, path.polyline.points.end())).to_polyline();
|
||||
}
|
||||
} else
|
||||
m_wipe.path.reverse();
|
||||
@@ -6061,11 +6143,11 @@ std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectBy
|
||||
extrusions.emplace_back(ee);
|
||||
if (! extrusions.empty()) {
|
||||
m_config.apply(print.get_print_region(®ion - &by_region.front()).config());
|
||||
chain_and_reorder_extrusion_entities(extrusions, &m_last_pos);
|
||||
chain_and_reorder_extrusion_entities(extrusions, m_last_pos.to_point());
|
||||
for (const ExtrusionEntity *fill : extrusions) {
|
||||
auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill);
|
||||
if (eec) {
|
||||
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities)
|
||||
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos.to_point()).entities)
|
||||
gcode += this->extrude_entity(*ee, extrusion_name);
|
||||
} else
|
||||
gcode += this->extrude_entity(*fill, extrusion_name);
|
||||
@@ -6096,7 +6178,7 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
|
||||
if (extrusions.empty())
|
||||
return gcode;
|
||||
|
||||
chain_and_reorder_extrusion_entities(extrusions, &m_last_pos);
|
||||
chain_and_reorder_extrusion_entities(extrusions, m_last_pos.to_point());
|
||||
|
||||
const double support_speed = m_config.support_speed.value;
|
||||
const double support_interface_speed = m_config.get_abs_value("support_interface_speed");
|
||||
@@ -6274,21 +6356,41 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
// Move to first point of extrusion path
|
||||
// path is 2D. But in slope lift case, lift z is done in travel_to function.
|
||||
// Add m_need_change_layer_lift_z when change_layer in case of no lift if m_last_pos is equal to path.first_point() by chance
|
||||
if (!m_last_pos_defined || m_last_pos != path.first_point() || m_need_change_layer_lift_z || slope_need_z_travel) {
|
||||
Point first_point = path.first_point();
|
||||
if (!m_last_pos_defined || m_last_pos.to_point() != first_point || m_need_change_layer_lift_z || slope_need_z_travel) {
|
||||
const bool _last_pos_undefined = !m_last_pos_defined;
|
||||
gcode += this->travel_to(
|
||||
path.first_point(),
|
||||
path.role(),
|
||||
"move to first " + description + " point",
|
||||
sloped == nullptr ? DBL_MAX : get_sloped_z(sloped->slope_begin.z_ratio)
|
||||
);
|
||||
m_need_change_layer_lift_z = false;
|
||||
// Orca: ensure Z matches planned layer height
|
||||
if (_last_pos_undefined && !slope_need_z_travel) {
|
||||
gcode += this->writer().travel_to_z(m_nominal_z, "ensure Z matches planned layer height", true);
|
||||
|
||||
double z = DBL_MAX;
|
||||
if (sloped != nullptr) {
|
||||
z = get_sloped_z(sloped->slope_begin.z_ratio);
|
||||
} else if (path.z_contoured && !path.polyline.lines().empty()) {
|
||||
z = unscale_(path.polyline.lines().begin()->a.z()) + m_nominal_z;
|
||||
}
|
||||
|
||||
gcode += this->travel_to(first_point, path.role(), "move to first " + description + " point", z);
|
||||
|
||||
// Orca: ensure Z matches planned layer height
|
||||
if (!slope_need_z_travel && (_last_pos_undefined || m_need_change_layer_lift_z)) {
|
||||
const std::string z_sync_comment = _last_pos_undefined ?
|
||||
"ensure Z matches planned layer height" : ""; // no comment for normal layer-Z lift
|
||||
gcode += this->writer().travel_to_z(m_nominal_z, z_sync_comment, true);
|
||||
}
|
||||
m_need_change_layer_lift_z = false;
|
||||
}
|
||||
|
||||
if (path.z_contoured && !path.polyline.lines().empty()) {
|
||||
double current_z = m_writer->get_position().z();
|
||||
double first_z = unscale_(path.polyline.lines().begin()->a.z()) + m_nominal_z;
|
||||
if (GCodeFormatter::quantize_xyzf(first_z) != GCodeFormatter::quantize_xyzf(current_z)) {
|
||||
gcode += m_writer->travel_to_z(first_z, "set Z for contouring", true);
|
||||
}
|
||||
}
|
||||
if (!path.z_contoured && sloped == nullptr) {
|
||||
double current_z = m_writer->get_position().z();
|
||||
if (GCodeFormatter::quantize_xyzf(current_z) != GCodeFormatter::quantize_xyzf(m_nominal_z)) {
|
||||
gcode += this->writer().travel_to_z(m_nominal_z, "reset Z after contouring", true);
|
||||
}
|
||||
}
|
||||
|
||||
// if needed, write the gcode_label_objects_end then gcode_label_objects_start
|
||||
// should be already done by travel_to, but just in case
|
||||
@@ -6355,7 +6457,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
}
|
||||
|
||||
// calculate effective extrusion length per distance unit (e_per_mm)
|
||||
double filament_flow_ratio = m_config.option<ConfigOptionFloats>("filament_flow_ratio")->get_at(0);
|
||||
double filament_flow_ratio = FILAMENT_CONFIG(filament_flow_ratio);
|
||||
// We set _mm3_per_mm to effectove flow = Geometric volume * print flow ratio * filament flow ratio * role-based-flow-ratios
|
||||
auto _mm3_per_mm = path.mm3_per_mm * this->config().print_flow_ratio;
|
||||
_mm3_per_mm *= filament_flow_ratio;
|
||||
@@ -6366,6 +6468,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
_mm3_per_mm *= m_config.bottom_solid_infill_flow_ratio;
|
||||
} else if (path.role() == erInternalBridgeInfill) {
|
||||
_mm3_per_mm *= m_config.internal_bridge_flow;
|
||||
} else if (path.role() == erBrim) {
|
||||
_mm3_per_mm *= m_config.brim_flow_ratio;
|
||||
} else if (sloped) {
|
||||
_mm3_per_mm *= m_config.scarf_joint_flow_ratio;
|
||||
}
|
||||
@@ -6448,17 +6552,18 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
|
||||
if (speed == 0)
|
||||
speed = filament_max_volumetric_speed / _mm3_per_mm;
|
||||
if (path_on_first_layer) {
|
||||
// Use the FirstLayerPlane-aware effective layer index when active so
|
||||
// the speed fade tracks perpendicular distance from the plane on
|
||||
// belt printers; otherwise this falls back to the slicing layer id.
|
||||
const int _layer = this->effective_layer_index_for_point(path_point_mm);
|
||||
if (path_on_first_layer || object_layer_over_raft()) {
|
||||
//BBS: for solid infill of first layer, speed can be higher as long as
|
||||
//wall lines have be attached
|
||||
if (path.role() != erBottomSurface)
|
||||
speed = m_config.get_abs_value("initial_layer_speed");
|
||||
}
|
||||
else if(m_config.slow_down_layers > 1){
|
||||
// Use the FirstLayerPlane-aware effective layer index when active so
|
||||
// the speed fade tracks perpendicular distance from the plane on
|
||||
// belt printers; otherwise this falls back to the slicing layer id.
|
||||
const int _layer = this->effective_layer_index_for_point(path_point_mm);
|
||||
if (path.role() != erBottomSurface) {
|
||||
speed = is_perimeter(path.role()) ? m_config.get_abs_value("initial_layer_speed") :
|
||||
m_config.get_abs_value("initial_layer_infill_speed");
|
||||
}
|
||||
} else if (m_config.slow_down_layers > 1 && m_config.raft_layers == 0) {
|
||||
if (_layer > 0 && _layer < m_config.slow_down_layers) {
|
||||
const auto first_layer_speed =
|
||||
is_perimeter(path.role())
|
||||
@@ -6468,7 +6573,18 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
speed = std::min(
|
||||
speed,
|
||||
Slic3r::lerp(first_layer_speed, speed,
|
||||
(double)_layer / m_config.slow_down_layers));
|
||||
(double) (_layer) / m_config.slow_down_layers));
|
||||
}
|
||||
}
|
||||
} else if (m_config.slow_down_layers > 1 && m_config.raft_layers > 0 ) {
|
||||
|
||||
if (_layer > m_config.raft_layers && (_layer - m_config.raft_layers) < m_config.slow_down_layers) {
|
||||
const auto first_layer_speed
|
||||
= is_perimeter(path.role()) ? m_config.get_abs_value("initial_layer_speed") :
|
||||
m_config.get_abs_value("initial_layer_infill_speed");
|
||||
if (first_layer_speed < speed) {
|
||||
speed = std::min(speed, Slic3r::lerp(first_layer_speed, speed,
|
||||
(double) (_layer - m_config.raft_layers) / m_config.slow_down_layers));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6531,14 +6647,14 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
bool variable_speed = false;
|
||||
std::vector<ProcessedPoint> new_points {};
|
||||
|
||||
if (m_config.enable_overhang_speed && !path_on_first_layer &&
|
||||
if (m_config.enable_overhang_speed && !path_on_first_layer && !object_layer_over_raft() &&
|
||||
(is_bridge(path.role()) || is_perimeter(path.role()))) {
|
||||
bool is_external = is_external_perimeter(path.role());
|
||||
double ref_speed = is_external ? m_config.get_abs_value("outer_wall_speed") : m_config.get_abs_value("inner_wall_speed");
|
||||
if (ref_speed == 0)
|
||||
ref_speed = FILAMENT_CONFIG(filament_max_volumetric_speed) / _mm3_per_mm;
|
||||
|
||||
if (EXTRUDER_CONFIG(filament_max_volumetric_speed) > 0) {
|
||||
if (FILAMENT_CONFIG(filament_max_volumetric_speed) > 0) {
|
||||
ref_speed = std::min(ref_speed, FILAMENT_CONFIG(filament_max_volumetric_speed) / _mm3_per_mm);
|
||||
}
|
||||
if (sloped) {
|
||||
@@ -6619,15 +6735,29 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
// Orca: End of dynamic PA trigger flag segment
|
||||
|
||||
//Orca: process custom gcode for extrusion role change
|
||||
if (path.role() != m_last_extrusion_role && !m_config.change_extrusion_role_gcode.value.empty()) {
|
||||
if (path.role() != m_last_extrusion_role) {
|
||||
const auto current_filament_id = m_writer->filament()->id();
|
||||
const std::string& machine_role_change_gcode = m_config.change_extrusion_role_gcode.value;
|
||||
const std::string& filament_role_change_gcode = m_config.filament_change_extrusion_role_gcode.get_at(current_filament_id);
|
||||
const std::string& process_role_change_gcode = m_config.process_change_extrusion_role_gcode.value;
|
||||
|
||||
if (!machine_role_change_gcode.empty() || !filament_role_change_gcode.empty() || !process_role_change_gcode.empty()) {
|
||||
DynamicConfig config;
|
||||
config.set_key_value("extrusion_role", new ConfigOptionString(extrusion_role_to_string_for_parser(path.role())));
|
||||
config.set_key_value("last_extrusion_role", new ConfigOptionString(extrusion_role_to_string_for_parser(m_last_extrusion_role)));
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(m_layer == nullptr ? m_last_height : m_layer->print_z));
|
||||
gcode += this->placeholder_parser_process("change_extrusion_role_gcode",
|
||||
m_config.change_extrusion_role_gcode.value, m_writer->filament()->id(), &config)
|
||||
+ "\n";
|
||||
|
||||
const auto append_role_gcode = [this, current_filament_id, &config, &gcode](const std::string& key, const std::string& templ) {
|
||||
if (templ.empty())
|
||||
return;
|
||||
gcode += this->placeholder_parser_process(key, templ, current_filament_id, &config) + "\n";
|
||||
};
|
||||
|
||||
append_role_gcode("change_extrusion_role_gcode", machine_role_change_gcode);
|
||||
append_role_gcode("filament_change_extrusion_role_gcode", filament_role_change_gcode);
|
||||
append_role_gcode("process_change_extrusion_role_gcode", process_role_change_gcode);
|
||||
}
|
||||
}
|
||||
|
||||
// extrude arc or line
|
||||
@@ -6754,11 +6884,14 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
assert(m_enable_cooling_markers);
|
||||
|
||||
if (fan_on) {
|
||||
if (!m_is_role_based_fan_on[role]) {
|
||||
// Orca: CoolingBuffer consumes role fan markers per layer, so continuing
|
||||
// role-based fan regions need a fresh START marker on each new layer.
|
||||
if (!m_is_role_based_fan_on[role] || m_role_based_fan_marker_layer[role] != m_layer_index) {
|
||||
gcode += ";";
|
||||
gcode += marker_prefix;
|
||||
gcode += "_FAN_START\n";
|
||||
m_is_role_based_fan_on[role] = true;
|
||||
m_role_based_fan_marker_layer[role] = m_layer_index;
|
||||
}
|
||||
} else {
|
||||
if (m_is_role_based_fan_on[role]) {
|
||||
@@ -6766,6 +6899,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
gcode += marker_prefix;
|
||||
gcode += "_FAN_END\n";
|
||||
m_is_role_based_fan_on[role] = false;
|
||||
m_role_based_fan_marker_layer[role] = -1;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -6848,10 +6982,12 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
}
|
||||
// BBS: use G1 if not enable arc fitting or has no arc fitting result or in spiral_mode mode or we are doing sloped extrusion
|
||||
// Attention: G2 and G3 is not supported in spiral_mode mode
|
||||
if (!m_config.enable_arc_fitting || path.polyline.fitting_result.empty() || m_config.spiral_mode || sloped != nullptr || this->should_disable_arc_fitting()) {
|
||||
if (!m_config.enable_arc_fitting || path.polyline.fitting_result.empty() || m_config.spiral_mode || sloped != nullptr || path.z_contoured || this->should_disable_arc_fitting()) {
|
||||
double path_length = 0.;
|
||||
double total_length = sloped == nullptr ? 0. : path.polyline.length() * SCALING_FACTOR;
|
||||
for (const Line& line : path.polyline.lines()) {
|
||||
double saved_z = m_writer->get_position().z();
|
||||
|
||||
for (const Line3& line : path.polyline.lines()) {
|
||||
std::string tempDescription = description;
|
||||
const double line_length = line.length() * SCALING_FACTOR;
|
||||
if (line_length < EPSILON)
|
||||
@@ -6866,16 +7002,35 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
tempDescription += Slic3r::format(" | Old Flow Value: %0.5f Length: %0.5f",oldE, line_length);
|
||||
}
|
||||
}
|
||||
if (sloped == nullptr) {
|
||||
if (path.z_contoured) {
|
||||
// ZAA: Z anti-aliased extrusion with variable Z per point
|
||||
Vec2d dest2d = this->point_to_gcode(line.b.to_point());
|
||||
coordf_t z_diff = unscale_(line.b.z());
|
||||
|
||||
double extrusion_ratio = 1;
|
||||
if (path.role() != erIroning) {
|
||||
extrusion_ratio = (path.height + z_diff) / path.height;
|
||||
}
|
||||
|
||||
double e = dE * extrusion_ratio;
|
||||
|
||||
double z = m_nominal_z + z_diff;
|
||||
if (z < 0.1) {
|
||||
throw RuntimeError("GCode: very low z");
|
||||
}
|
||||
gcode += m_writer->extrude_to_xyz(Vec3d(dest2d.x(), dest2d.y(), z), e,
|
||||
GCodeWriter::full_gcode_comment ? tempDescription : "");
|
||||
|
||||
} else if (sloped == nullptr) {
|
||||
// Normal extrusion
|
||||
gcode += m_writer->extrude_to_xy(
|
||||
this->point_to_gcode(line.b),
|
||||
this->point_to_gcode(line.b.to_point()),
|
||||
dE,
|
||||
GCodeWriter::full_gcode_comment ? tempDescription : "", path.is_force_no_extrusion());
|
||||
} else {
|
||||
// Sloped extrusion
|
||||
const auto [z_ratio, e_ratio] = sloped->interpolate(path_length / total_length);
|
||||
Vec2d dest2d = this->point_to_gcode(line.b);
|
||||
Vec2d dest2d = this->point_to_gcode(line.b.to_point());
|
||||
Vec3d dest3d(dest2d(0), dest2d(1), get_sloped_z(z_ratio));
|
||||
gcode += m_writer->extrude_to_xyz(
|
||||
dest3d,
|
||||
@@ -6894,7 +7049,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
size_t end_index = fitting_result[fitting_index].end_point_index;
|
||||
for (size_t point_index = start_index + 1; point_index < end_index + 1; point_index++) {
|
||||
tempDescription = description;
|
||||
const Line line = Line(path.polyline.points[point_index - 1], path.polyline.points[point_index]);
|
||||
const Line line = Line(path.polyline.points[point_index - 1].to_point(), path.polyline.points[point_index].to_point());
|
||||
const double line_length = line.length() * SCALING_FACTOR;
|
||||
if (line_length < EPSILON)
|
||||
continue;
|
||||
@@ -6952,14 +7107,14 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
double total_length = 0;
|
||||
if (sloped != nullptr) {
|
||||
// Calculate total extrusion length
|
||||
Points p;
|
||||
Points3 p;
|
||||
p.reserve(new_points.size());
|
||||
std::transform(new_points.begin(), new_points.end(), std::back_inserter(p), [](const ProcessedPoint& pp) { return pp.p; });
|
||||
Polyline l(p);
|
||||
Polyline3 l(p);
|
||||
total_length = l.length() * SCALING_FACTOR;
|
||||
}
|
||||
gcode += m_writer->set_speed(last_set_speed, "", comment);
|
||||
Vec2d prev = this->point_to_gcode_quantized(new_points[0].p);
|
||||
Vec3d prev = this->point_to_gcode_quantized(new_points[0].p);
|
||||
bool pre_fan_enabled = false;
|
||||
bool cur_fan_enabled = false;
|
||||
if( m_enable_cooling_markers && enable_overhang_bridge_fan)
|
||||
@@ -6973,7 +7128,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
std::string tempDescription = description;
|
||||
const ProcessedPoint &processed_point = new_points[i];
|
||||
const ProcessedPoint &pre_processed_point = new_points[i-1];
|
||||
Vec2d p = this->point_to_gcode_quantized(processed_point.p);
|
||||
Vec3d p = this->point_to_gcode_quantized(processed_point.p);
|
||||
if (m_enable_cooling_markers) {
|
||||
if (enable_overhang_bridge_fan) {
|
||||
cur_fan_enabled = check_overhang_fan(processed_point.overlap, path.role());
|
||||
@@ -7055,9 +7210,26 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
tempDescription += Slic3r::format(" | Old Flow Value: %0.5f Length: %0.5f",oldE, line_length);
|
||||
}
|
||||
}
|
||||
if (sloped == nullptr) {
|
||||
if (path.z_contoured) {
|
||||
Vec2d dest2d = p.head<2>();
|
||||
coordf_t z_diff = unscale_(processed_point.p.z());
|
||||
|
||||
double extrusion_ratio = 1;
|
||||
if (path.role() != erIroning) {
|
||||
extrusion_ratio = (path.height + z_diff) / path.height;
|
||||
}
|
||||
|
||||
double e = dE * extrusion_ratio;
|
||||
|
||||
double z = m_nominal_z + z_diff;
|
||||
if (z < 0.1) {
|
||||
throw RuntimeError("GCode: very low z");
|
||||
}
|
||||
gcode += m_writer->extrude_to_xyz(Vec3d(dest2d.x(), dest2d.y(), z), e,
|
||||
GCodeWriter::full_gcode_comment ? tempDescription : "");
|
||||
} else if (sloped == nullptr) {
|
||||
// Normal extrusion
|
||||
gcode += m_writer->extrude_to_xy(p, dE, GCodeWriter::full_gcode_comment ? tempDescription : "");
|
||||
gcode += m_writer->extrude_to_xy(p.head<2>(), dE, GCodeWriter::full_gcode_comment ? tempDescription : "");
|
||||
} else {
|
||||
// Sloped extrusion
|
||||
const auto [z_ratio, e_ratio] = sloped->interpolate(path_length / total_length);
|
||||
@@ -7110,14 +7282,29 @@ std::string GCode::extrusion_role_to_string_for_parser(const ExtrusionRole & rol
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the interpolated value for the current layer between start_value and end_value
|
||||
float GCode::interpolate_value_across_layers(float start_value, float end_value) const {
|
||||
if (m_layer_index == 1) {
|
||||
// Calculate the interpolated value for the current layer between start_value and end_value.
|
||||
// Step will create equal layers steps from first to last value.
|
||||
// Step = 0 means gradual interpolation finishing at last value.
|
||||
float GCode::interpolate_value_across_layers(float start_value, float end_value, float step) const
|
||||
{
|
||||
if (m_layer_index <= 1) {
|
||||
return start_value;
|
||||
} else {
|
||||
float ratio = (m_layer_index - 2.0f) / (m_layer_count - 3.0f);
|
||||
ratio = std::max(0.0f, std::min(1.0f, ratio)); // clamp
|
||||
return start_value + ratio * (end_value - start_value);
|
||||
}
|
||||
else {
|
||||
bool use_steps = step > 0.f;
|
||||
if (use_steps) {
|
||||
if (start_value > end_value) {
|
||||
start_value += step;
|
||||
} else {
|
||||
end_value += step;
|
||||
}
|
||||
}
|
||||
float ratio = m_layer_index / (m_layer_count - 1.f);
|
||||
float value = start_value + ratio * (end_value - start_value);
|
||||
if (use_steps) {
|
||||
value = trunc(value / step) * step;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7174,16 +7361,25 @@ std::string GCode::travel_to(const Point& point, ExtrusionRole role, std::string
|
||||
unsigned int acceleration_to_set = 0;
|
||||
|
||||
if (this->on_first_layer()) {
|
||||
if (m_config.default_acceleration.value > 0 && m_config.initial_layer_acceleration.value > 0) {
|
||||
acceleration_to_set = (unsigned int) floor(m_config.initial_layer_acceleration.value + 0.5);
|
||||
unsigned int initial_layer_travel_acceleration = m_config.get_abs_value("initial_layer_travel_acceleration");
|
||||
double initial_layer_travel_jerk = m_config.get_abs_value("initial_layer_travel_jerk");
|
||||
|
||||
if (m_config.default_acceleration.value > 0 && initial_layer_travel_acceleration > 0) {
|
||||
acceleration_to_set = (unsigned int) floor(initial_layer_travel_acceleration + 0.5);
|
||||
}
|
||||
|
||||
if (m_config.default_jerk.value > 0 && m_config.initial_layer_jerk.value > 0) {
|
||||
jerk_to_set = m_config.initial_layer_jerk.value;
|
||||
if (m_config.default_jerk.value > 0 && initial_layer_travel_jerk > 0) {
|
||||
jerk_to_set = initial_layer_travel_jerk;
|
||||
}
|
||||
} else {
|
||||
} else { // ORCA: Handle short-travel acceleration and jerk for outer perimeters (if applicable)
|
||||
const bool is_short_travel = travel.length() < scale_(EXTRUDER_CONFIG(retraction_minimum_travel));
|
||||
|
||||
if (m_config.default_acceleration.value > 0) {
|
||||
if (role == erExternalPerimeter && travel.length() < scale_(EXTRUDER_CONFIG(retraction_minimum_travel))) {
|
||||
if (role == erOverhangPerimeter && is_short_travel) {
|
||||
const double bridge_acceleration = m_config.get_abs_value("bridge_acceleration");
|
||||
|
||||
if (bridge_acceleration > 0)
|
||||
acceleration_to_set = (unsigned int) floor(bridge_acceleration + 0.5);
|
||||
} else if (role == erExternalPerimeter && is_short_travel) {
|
||||
if (m_config.outer_wall_acceleration.value > 0)
|
||||
acceleration_to_set = (unsigned int) floor(m_config.outer_wall_acceleration.value + 0.5);
|
||||
} else {
|
||||
@@ -7193,7 +7389,7 @@ std::string GCode::travel_to(const Point& point, ExtrusionRole role, std::string
|
||||
}
|
||||
|
||||
if (m_config.default_jerk.value > 0) {
|
||||
if (role == erExternalPerimeter && travel.length() < scale_(EXTRUDER_CONFIG(retraction_minimum_travel))) {
|
||||
if ((role == erExternalPerimeter || role == erOverhangPerimeter) && is_short_travel) {
|
||||
if (m_config.outer_wall_jerk.value > 0)
|
||||
jerk_to_set = m_config.outer_wall_jerk.value;
|
||||
} else {
|
||||
@@ -7602,6 +7798,7 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
||||
float filament_area = float((M_PI / 4.f) * pow(m_config.filament_diameter.get_at(new_filament_id), 2));
|
||||
//BBS: add handling for filament change in start gcode
|
||||
int old_filament_id = -1;
|
||||
int old_extruder_id = -1;
|
||||
if (m_writer->filament() != nullptr || m_start_gcode_filament != -1) {
|
||||
std::vector<float> flush_matrix(cast<float>(get_flush_volumes_matrix(m_config.flush_volumes_matrix.values, new_extruder_id, m_config.nozzle_diameter.values.size())));
|
||||
const unsigned int number_of_extruders = (unsigned int) (m_config.filament_colour.values.size()); // if is multi_extruder only use the fist extruder matrix
|
||||
@@ -7611,7 +7808,7 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
||||
assert(m_start_gcode_filament < number_of_extruders);
|
||||
|
||||
old_filament_id = m_writer->filament() != nullptr ? m_writer->filament()->id() : m_start_gcode_filament;
|
||||
int old_extruder_id = m_writer->filament() != nullptr ? m_writer->filament()->extruder_id() : get_extruder_id(m_start_gcode_filament);
|
||||
old_extruder_id = m_writer->filament() != nullptr ? m_writer->filament()->extruder_id() : get_extruder_id(m_start_gcode_filament);
|
||||
|
||||
old_retract_length = m_config.retraction_length.get_at(old_filament_id);
|
||||
old_retract_length_toolchange = m_config.retract_length_toolchange.get_at(old_filament_id);
|
||||
@@ -7657,6 +7854,9 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
||||
dyn_config.set_key_value("outer_wall_volumetric_speed", new ConfigOptionFloat(outer_wall_volumetric_speed));
|
||||
dyn_config.set_key_value("previous_extruder", new ConfigOptionInt(old_filament_id));
|
||||
dyn_config.set_key_value("next_extruder", new ConfigOptionInt((int)new_filament_id));
|
||||
dyn_config.set_key_value("current_hotend",
|
||||
new ConfigOptionInt(old_filament_id >= 0 ? hotend_id_for_gcode_placeholder(m_config, old_extruder_id) : -1));
|
||||
dyn_config.set_key_value("next_hotend", new ConfigOptionInt(hotend_id_for_gcode_placeholder(m_config, new_extruder_id)));
|
||||
dyn_config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||
dyn_config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
|
||||
dyn_config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
@@ -7709,7 +7909,8 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
||||
}
|
||||
|
||||
auto flush_v_speed = m_print->config().filament_flush_volumetric_speed.values;
|
||||
auto flush_temps =m_print->config().filament_flush_temp.values;
|
||||
auto flush_temps = m_print->config().filament_flush_temp.values;
|
||||
auto filament_cooling_before_tower = m_print->config().filament_cooling_before_tower.values;
|
||||
for (size_t idx = 0; idx < flush_v_speed.size(); ++idx) {
|
||||
if (flush_v_speed[idx] == 0)
|
||||
flush_v_speed[idx] = m_print->config().filament_max_volumetric_speed.get_at(idx);
|
||||
@@ -7718,8 +7919,12 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
||||
if (flush_temps[idx] == 0)
|
||||
flush_temps[idx] = m_print->config().nozzle_temperature_range_high.get_at(idx);
|
||||
}
|
||||
if (filament_cooling_before_tower.size() < m_print->config().filament_type.values.size())
|
||||
filament_cooling_before_tower.resize(m_print->config().filament_type.values.size(), m_print->config().filament_cooling_before_tower.get_at(0));
|
||||
std::fill(filament_cooling_before_tower.begin(), filament_cooling_before_tower.end(), 0);
|
||||
dyn_config.set_key_value("flush_volumetric_speeds", new ConfigOptionFloats(flush_v_speed));
|
||||
dyn_config.set_key_value("flush_temperatures", new ConfigOptionInts(flush_temps));
|
||||
dyn_config.set_key_value("filament_cooling_before_tower", new ConfigOptionFloats(filament_cooling_before_tower));
|
||||
dyn_config.set_key_value("flush_length", new ConfigOptionFloat(wipe_length));
|
||||
|
||||
int flush_count = std::min(g_max_flush_count, (int)std::round(wipe_volume / g_purge_volume_one_time));
|
||||
@@ -7792,6 +7997,7 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
||||
}
|
||||
|
||||
this->placeholder_parser().set("current_extruder", new_filament_id);
|
||||
this->placeholder_parser().set("current_hotend", hotend_id_for_gcode_placeholder(m_config, new_extruder_id));
|
||||
this->placeholder_parser().set("retraction_distance_when_cut", m_config.retraction_distances_when_cut.get_at(new_filament_id));
|
||||
this->placeholder_parser().set("long_retraction_when_cut", m_config.long_retractions_when_cut.get_at(new_filament_id));
|
||||
this->placeholder_parser().set("retraction_distance_when_ec", m_config.retraction_distances_when_ec.get_at(new_filament_id));
|
||||
@@ -7914,6 +8120,13 @@ Vec2d GCode::point_to_gcode(const Point &point) const
|
||||
return unscale(point) + m_origin - extruder_offset;
|
||||
}
|
||||
|
||||
Vec3d GCode::point_to_gcode(const Point3& point) const
|
||||
{
|
||||
Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset);
|
||||
Vec2d xy = unscale(point.to_point()) + m_origin - extruder_offset;
|
||||
return Vec3d(xy.x(), xy.y(), unscale_(point.z()));
|
||||
}
|
||||
|
||||
// convert a model-space scaled point into G-code coordinates
|
||||
Point GCode::gcode_to_point(const Vec2d &point) const
|
||||
{
|
||||
@@ -7931,6 +8144,11 @@ Vec2d GCode::point_to_gcode_quantized(const Point& point) const
|
||||
return { GCodeFormatter::quantize_xyzf(p.x()), GCodeFormatter::quantize_xyzf(p.y()) };
|
||||
}
|
||||
|
||||
Vec3d GCode::point_to_gcode_quantized(const Point3& point) const
|
||||
{
|
||||
Vec3d p = this->point_to_gcode(point);
|
||||
return {GCodeFormatter::quantize_xyzf(p.x()), GCodeFormatter::quantize_xyzf(p.y()), GCodeFormatter::quantize_xyzf(p.z())};
|
||||
}
|
||||
|
||||
// Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed
|
||||
// during infill/perimeter wiping, or normally (depends on wiping_entities parameter)
|
||||
|
||||
Reference in New Issue
Block a user