mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-22 00:29:53 +03:00
Compare commits
11 Commits
fix/plugin
...
nightly-bu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b292a06b3f | ||
|
|
cc1fe80073 | ||
|
|
b86501cd3c | ||
|
|
ae0193899d | ||
|
|
5d9b641093 | ||
|
|
8390d55127 | ||
|
|
23f8ad88d1 | ||
|
|
21f830bf24 | ||
|
|
dfb93e0332 | ||
|
|
355a21626e | ||
|
|
8de1ff37bd |
@@ -24,6 +24,8 @@
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <csignal>
|
||||
#include <atomic>
|
||||
#include <new>
|
||||
|
||||
#if defined(__linux__) || defined(__LINUX__)
|
||||
#include <condition_variable>
|
||||
@@ -7608,6 +7610,9 @@ LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
|
||||
}*/
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
// Guards against a failed allocation inside the dump re-entering the new-handler.
|
||||
static std::atomic<bool> g_dump_in_progress{false};
|
||||
|
||||
extern "C" {
|
||||
__declspec(dllexport) int __stdcall orcaslicer_main(int argc, wchar_t **argv)
|
||||
{
|
||||
@@ -7626,10 +7631,22 @@ extern "C" {
|
||||
//AddVectoredExceptionHandler(1, CBaseException::UnhandledExceptionFilter);
|
||||
SET_DEFULTER_HANDLER();
|
||||
#endif
|
||||
// Dump before unwinding, while the stack still names what asked for the memory. Throwing
|
||||
// std::bad_alloc is standard-permitted here and is what reaches generic_exception_handle().
|
||||
std::set_new_handler([]() {
|
||||
int *a = nullptr;
|
||||
*a = 0;
|
||||
});
|
||||
if (!g_dump_in_progress.exchange(true)) {
|
||||
try {
|
||||
// A null EXCEPTION_POINTERS walks the calling thread as it stands.
|
||||
CBaseException base(GetCurrentProcess(), GetCurrentProcessId(), NULL, nullptr);
|
||||
base.ShowCallstack();
|
||||
} catch (...) {
|
||||
// A failed dump must not displace the std::bad_alloc owed to the caller.
|
||||
}
|
||||
// ObjParser recovers from std::bad_alloc, so let a later one dump again.
|
||||
g_dump_in_progress = false;
|
||||
}
|
||||
throw std::bad_alloc();
|
||||
});
|
||||
// Call the UTF8 main.
|
||||
return CLI().run(argc, argv_ptrs.data());
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include "CustomGCode.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Line.hpp"
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
@@ -99,9 +101,87 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|
||||
m_max_jerk_z = LIMITS(machine_max_jerk_z);
|
||||
m_max_jerk_e = LIMITS(machine_max_jerk_e);
|
||||
m_resolution = print_config.resolution.value;
|
||||
|
||||
#undef LIMITS
|
||||
#undef LIMITS_UINT
|
||||
// Orca: capture the printable area(s) so a spiral lift can be skipped when its
|
||||
// circle would leave the boundary and collide with the print limits. Full polygons
|
||||
// are stored (not a bounding box) so the check stays correct for non-rectangular
|
||||
// beds, and per-extruder areas are kept so printers with different boundaries per
|
||||
// extruder use the right limit for whichever extruder is active.
|
||||
auto to_scaled_polygon = [](const Pointfs &pts) {
|
||||
Polygon poly;
|
||||
poly.points.reserve(pts.size());
|
||||
for (const Vec2d &p : pts)
|
||||
poly.points.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y())));
|
||||
poly.make_counter_clockwise();
|
||||
return poly;
|
||||
};
|
||||
|
||||
m_bed_printable_area.points.clear();
|
||||
m_extruder_printable_areas.clear();
|
||||
|
||||
if (print_config.printable_area.values.size() >= 3)
|
||||
m_bed_printable_area = to_scaled_polygon(print_config.printable_area.values);
|
||||
|
||||
const std::vector<Pointfs> &extruder_areas = print_config.extruder_printable_area.values;
|
||||
if (!extruder_areas.empty()) {
|
||||
m_extruder_printable_areas.resize(extruder_areas.size());
|
||||
for (size_t i = 0; i < extruder_areas.size(); ++i) {
|
||||
if (extruder_areas[i].size() < 3) {
|
||||
// No dedicated area for this extruder: it can reach the whole bed.
|
||||
m_extruder_printable_areas[i] = m_bed_printable_area;
|
||||
continue;
|
||||
}
|
||||
Polygon extruder_poly = to_scaled_polygon(extruder_areas[i]);
|
||||
if (m_bed_printable_area.points.size() < 3) {
|
||||
m_extruder_printable_areas[i] = std::move(extruder_poly);
|
||||
continue;
|
||||
}
|
||||
// The reachable area is the extruder area clipped to the bed. Bed shapes are
|
||||
// convex in practice, so keep the largest resulting contour.
|
||||
Polygons clipped = intersection(extruder_poly, m_bed_printable_area);
|
||||
const Polygon *largest = nullptr;
|
||||
double best_area = 0.;
|
||||
for (const Polygon &p : clipped) {
|
||||
double a = std::abs(p.area());
|
||||
if (a > best_area) { best_area = a; largest = &p; }
|
||||
}
|
||||
m_extruder_printable_areas[i] = largest ? *largest : std::move(extruder_poly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Polygon *GCodeWriter::active_printable_area() const
|
||||
{
|
||||
if (const Extruder *e = this->filament()) {
|
||||
size_t id = e->extruder_id();
|
||||
if (id < m_extruder_printable_areas.size() && m_extruder_printable_areas[id].points.size() >= 3)
|
||||
return &m_extruder_printable_areas[id];
|
||||
}
|
||||
if (m_bed_printable_area.points.size() >= 3)
|
||||
return &m_bed_printable_area;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool GCodeWriter::spiral_lift_fits_printable_area(const Vec2d ¢er, double radius) const
|
||||
{
|
||||
const Polygon *area = this->active_printable_area();
|
||||
if (area == nullptr)
|
||||
return true; // Boundary unknown: don't restrict (preserve previous behavior).
|
||||
|
||||
const Point c = Point::new_scale(center.x(), center.y());
|
||||
const double r_scaled = scale_(radius);
|
||||
const double r2 = r_scaled * r_scaled;
|
||||
|
||||
// The spiral traces a full circle of `radius` around `center`, so the center must lie
|
||||
// inside the printable area and every edge must be at least `radius` away from it.
|
||||
if (!area->contains(c))
|
||||
return false;
|
||||
const Points &pts = area->points;
|
||||
for (size_t i = 0, n = pts.size(); i < n; ++i)
|
||||
if (Line::distance_to_squared(c, pts[i], pts[(i + 1) % n]) < r2)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids)
|
||||
@@ -731,14 +811,19 @@ std::string GCodeWriter::eager_lift(const LiftType type) {
|
||||
}
|
||||
|
||||
// BBS: spiral lift only safe with known position
|
||||
// TODO: check the arc will move within bed area
|
||||
if (type == LiftType::SpiralLift && this->is_current_position_clear()) {
|
||||
double radius = target_lift / (2 * PI * atan(filament()->travel_slope()));
|
||||
// static spiral alignment when no move in x,y plane.
|
||||
// spiral centra is a radius distance to the right (y=0)
|
||||
// spiral centra is a radius distance to the right (y=0)
|
||||
Vec2d ij_offset = { radius, 0 };
|
||||
if (target_lift > 0) {
|
||||
// Orca: keep the spiral inside the active extruder's printable area, otherwise
|
||||
// fall back to a normal lift to avoid colliding with the print boundary. m_pos
|
||||
// includes the plate offset, so remove it to match the printable area coordinates.
|
||||
const Vec2d spiral_center = { m_pos.x() - m_x_offset + ij_offset.x(), m_pos.y() - m_y_offset + ij_offset.y() };
|
||||
if (target_lift > 0 && this->spiral_lift_fits_printable_area(spiral_center, radius)) {
|
||||
lift_move = this->_spiral_travel_to_z(m_pos(2) + target_lift, ij_offset, "spiral lift Z");
|
||||
} else if (target_lift > 0) {
|
||||
lift_move = _travel_to_z(m_pos(2) + target_lift, "normal lift Z");
|
||||
}
|
||||
}
|
||||
//BBS: if position is unknown use normal lift
|
||||
@@ -793,7 +878,15 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co
|
||||
double radius = delta(2) / (2 * PI * atan(this->filament()->travel_slope()));
|
||||
Vec2d ij_offset = radius * delta_no_z.normalized();
|
||||
ij_offset = { -ij_offset(1), ij_offset(0) };
|
||||
slop_move = this->_spiral_travel_to_z(target(2), ij_offset, "spiral lift Z");
|
||||
// Orca: only perform the spiral lift if its full circle stays inside the
|
||||
// printable area of the active extruder, otherwise fall back to a normal
|
||||
// lift to avoid colliding with the print boundary. `source` is already in
|
||||
// bed coordinates (plate offset removed), matching the printable area.
|
||||
const Vec2d spiral_center = { source.x() + ij_offset.x(), source.y() + ij_offset.y() };
|
||||
if (this->spiral_lift_fits_printable_area(spiral_center, radius))
|
||||
slop_move = this->_spiral_travel_to_z(target(2), ij_offset, "spiral lift Z");
|
||||
else
|
||||
slop_move = _travel_to_z(target.z(), "normal lift Z");
|
||||
}
|
||||
//BBS: SlopeLift
|
||||
else if (m_to_lift_type == LiftType::SlopeLift &&
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <charconv>
|
||||
#include "Extruder.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "GCode/CoolingBuffer.hpp"
|
||||
|
||||
@@ -181,6 +182,14 @@ public:
|
||||
|
||||
// Orca: slicing resolution in mm
|
||||
double m_resolution = 0.01;
|
||||
// Orca: printable area polygons (scaled, bed coordinates) used to keep spiral lifts
|
||||
// from colliding with the print boundary. m_extruder_printable_areas holds the
|
||||
// per-extruder reachable area (intersected with the bed) when a printer defines
|
||||
// different boundaries per extruder; m_bed_printable_area is the global fallback.
|
||||
// Storing full polygons (rather than a bounding box) keeps the check correct for
|
||||
// non-rectangular beds such as delta/circular printers.
|
||||
Polygon m_bed_printable_area;
|
||||
std::vector<Polygon> m_extruder_printable_areas;
|
||||
|
||||
std::string m_gcode_label_objects_start;
|
||||
std::string m_gcode_label_objects_end;
|
||||
@@ -197,6 +206,10 @@ public:
|
||||
|
||||
std::string _travel_to_z(double z, const std::string &comment);
|
||||
std::string _spiral_travel_to_z(double z, const Vec2d &ij_offset, const std::string &comment);
|
||||
// Orca: printable area of the active extruder (per-extruder when configured, otherwise the bed). Null when unknown.
|
||||
const Polygon *active_printable_area() const;
|
||||
// Orca: true if a full spiral-lift circle (center in bed coordinates, mm) fits inside the active printable area.
|
||||
bool spiral_lift_fits_printable_area(const Vec2d ¢er, double radius) const;
|
||||
std::string _retract(double length, double restart_extra, const std::string &comment);
|
||||
std::string set_acceleration_internal(Acceleration type, unsigned int acceleration);
|
||||
|
||||
|
||||
@@ -3504,7 +3504,7 @@ inline t_config_option_keys deep_diff(const ConfigBase &config_this, const Confi
|
||||
if (this_opt != nullptr && other_opt != nullptr && *this_opt != *other_opt)
|
||||
{
|
||||
//BBS: add bed_exclude_area
|
||||
if (opt_key == "printable_area" || opt_key == "bed_exclude_area" || opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "thumbnails" || opt_key == "wrapping_exclude_area", "slicing_pipeline_plugin") {
|
||||
if (opt_key == "printable_area" || opt_key == "bed_exclude_area" || opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "thumbnails" || opt_key == "wrapping_exclude_area" || opt_key == "slicing_pipeline_plugin") {
|
||||
// Scalar variable, or a vector variable, which is independent from number of extruders,
|
||||
// thus the vector is presented to the user as a single input.
|
||||
diff.emplace_back(opt_key);
|
||||
|
||||
@@ -3605,7 +3605,8 @@ std::vector<std::set<int>> Print::get_physical_unprintable_filaments(const std::
|
||||
return physical_unprintables;
|
||||
|
||||
auto get_unprintable_extruder_id = [&](unsigned int filament_idx) -> int {
|
||||
int status = m_config.filament_printable.values[filament_idx];
|
||||
// filament_printable may be shorter than the filament count; get_at() clamps.
|
||||
int status = m_config.filament_printable.get_at(filament_idx);
|
||||
for (int i = 0; i < extruder_num; ++i) {
|
||||
if (!(status >> i & 1)) {
|
||||
return i;
|
||||
|
||||
@@ -771,6 +771,7 @@ CustomGCode::Info CalibPressureAdvancePattern::generate_custom_gcodes(const Dyna
|
||||
}
|
||||
}
|
||||
|
||||
gcode << m_writer.reset_e();
|
||||
gcode << m_writer.set_pressure_advance(m_params.start);
|
||||
gcode << "; end pressure advance pattern for layer\n";
|
||||
|
||||
|
||||
@@ -35,10 +35,10 @@ struct Calib_Params
|
||||
{
|
||||
Calib_Params() : mode(CalibMode::Calib_None){};
|
||||
int extruder_id = 0;
|
||||
double start, end, step;
|
||||
bool print_numbers;
|
||||
double freqStartX, freqEndX, freqStartY, freqEndY;
|
||||
int test_model;
|
||||
double start = 0.0, end = 1.0, step = 0.1;
|
||||
bool print_numbers = false;
|
||||
double freqStartX = 0.0, freqEndX = 1.0, freqStartY = 0.0, freqEndY = 1.0;
|
||||
int test_model = 0;
|
||||
std::string shaper_type;
|
||||
std::vector<double> accelerations;
|
||||
std::vector<double> speeds;
|
||||
|
||||
@@ -558,6 +558,7 @@ namespace Slic3r
|
||||
}
|
||||
else
|
||||
{
|
||||
Slic3r::GUI::wxGetApp().reset_unsigned_plugin_warning();
|
||||
if (m_agent)
|
||||
{
|
||||
if (it->second->connection_type() != "lan" || it->second->connection_type().empty())
|
||||
|
||||
@@ -1043,14 +1043,14 @@ void TextCtrl::propagate_value()
|
||||
|
||||
void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/) {
|
||||
m_disable_change_event = !change_event;
|
||||
|
||||
if (m_opt.nullable) {
|
||||
const bool m_is_na_val = value.empty() || (boost::any_cast<wxString>(value) == _(L("N/A")));
|
||||
if (!m_is_na_val)
|
||||
m_last_meaningful_value = value;
|
||||
text_ctrl()->SetValue(boost::any_cast<wxString>(value)); // BBS
|
||||
}
|
||||
else
|
||||
text_ctrl()->SetValue(value.empty() ? "" : boost::any_cast<wxString>(value)); // BBS // BBS: null value
|
||||
|
||||
text_ctrl()->SetValue(value.empty() ? wxString() : boost::any_cast<wxString>(value));
|
||||
m_disable_change_event = false;
|
||||
|
||||
if (!change_event) {
|
||||
@@ -1187,18 +1187,24 @@ void CheckBox::set_value(const boost::any& value, bool change_event)
|
||||
m_disable_change_event = !change_event;
|
||||
if (m_opt.nullable) {
|
||||
const bool is_value_unsigned_char = value.type() == typeid(unsigned char);
|
||||
bool bool_value = false;
|
||||
|
||||
m_is_na_val = value.empty() || (is_value_unsigned_char &&
|
||||
boost::any_cast<unsigned char>(value) == ConfigOptionBoolsNullable::nil_value());
|
||||
if (!m_is_na_val)
|
||||
m_last_meaningful_value = is_value_unsigned_char ? value : static_cast<unsigned char>(boost::any_cast<bool>(value));
|
||||
|
||||
const auto bool_value = is_value_unsigned_char ?
|
||||
boost::any_cast<unsigned char>(value) != 0 :
|
||||
boost::any_cast<bool>(value);
|
||||
dynamic_cast<::CheckBox*>(window)->SetValue(m_is_na_val ? false : bool_value); // BBS
|
||||
if (!m_is_na_val) {
|
||||
bool_value = is_value_unsigned_char ?
|
||||
boost::any_cast<unsigned char>(value) != 0 :
|
||||
boost::any_cast<bool>(value);
|
||||
m_last_meaningful_value = is_value_unsigned_char ? value : static_cast<unsigned char>(bool_value);
|
||||
}
|
||||
|
||||
dynamic_cast<::CheckBox*>(window)->SetValue(bool_value);
|
||||
}
|
||||
else if (!value.empty()) // BBS: null value
|
||||
else if (!value.empty()){ // BBS: null value
|
||||
dynamic_cast<::CheckBox*>(window)->SetValue(boost::any_cast<bool>(value)); // BBS
|
||||
}
|
||||
|
||||
dynamic_cast<::CheckBox*>(window)->SetHalfChecked(value.empty());
|
||||
m_disable_change_event = false;
|
||||
}
|
||||
|
||||
@@ -6127,18 +6127,23 @@ bool GUI_App::process_network_msg(std::string dev_id, std::string msg)
|
||||
}
|
||||
else if (msg == "unsigned_studio") {
|
||||
BOOST_LOG_TRIVIAL(info) << "process_network_msg, unsigned_studio";
|
||||
MessageDialog
|
||||
msg_dlg(nullptr,
|
||||
_L("To use OrcaSlicer with Bambu Lab printers, you need to enable LAN mode and Developer mode on your printer.\n\n"
|
||||
"Please go to your printer's settings and:\n"
|
||||
"1. Turn on LAN mode\n"
|
||||
"2. Enable Developer mode\n\n"
|
||||
"Developer mode allows the printer to work exclusively through local network access, "
|
||||
"enabling full functionality with OrcaSlicer."),
|
||||
_L("Network Plug-in Restriction"), wxAPPLY | wxOK);
|
||||
m_show_error_msgdlg = true;
|
||||
msg_dlg.ShowModal();
|
||||
m_show_error_msgdlg = false;
|
||||
// Plugin re-emits this on every subscribe retry; latch it so it shows
|
||||
// once per connection episode.
|
||||
if (!m_show_error_msgdlg && !m_unsigned_plugin_warning_shown) {
|
||||
m_unsigned_plugin_warning_shown = true;
|
||||
MessageDialog
|
||||
msg_dlg(nullptr,
|
||||
_L("To use OrcaSlicer with Bambu Lab printers, you need to enable LAN mode and Developer mode on your printer.\n\n"
|
||||
"Please go to your printer's settings and:\n"
|
||||
"1. Turn on LAN mode\n"
|
||||
"2. Enable Developer mode\n\n"
|
||||
"Developer mode allows the printer to work exclusively through local network access, "
|
||||
"enabling full functionality with OrcaSlicer."),
|
||||
_L("Network Plug-in Restriction"), wxAPPLY | wxOK);
|
||||
m_show_error_msgdlg = true;
|
||||
msg_dlg.ShowModal();
|
||||
m_show_error_msgdlg = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,6 +343,7 @@ private:
|
||||
public:
|
||||
//try again when subscription fails
|
||||
void on_start_subscribe_again(std::string dev_id);
|
||||
void reset_unsigned_plugin_warning() { m_unsigned_plugin_warning_shown = false; }
|
||||
std::string get_local_models_path();
|
||||
bool OnInit() override;
|
||||
int OnExit() override;
|
||||
|
||||
@@ -3299,7 +3299,19 @@ static std::vector<std::string> intersect(std::vector<std::string> const& l, std
|
||||
static std::vector<std::string> concat(std::vector<std::string> const& l, std::vector<std::string> const& r)
|
||||
{
|
||||
std::vector<std::string> t;
|
||||
std::set_union(l.begin(), l.end(), r.begin(), r.end(), std::back_inserter(t));
|
||||
bool l_is_sorted = std::is_sorted(l.begin(), l.end());
|
||||
bool r_is_sorted = std::is_sorted(r.begin(), r.end());
|
||||
|
||||
if (l_is_sorted && r_is_sorted) {
|
||||
std::set_union(l.begin(), l.end(), r.begin(), r.end(), std::back_inserter(t));
|
||||
return t;
|
||||
}
|
||||
|
||||
std::vector<std::string> l_sorted = l;
|
||||
std::vector<std::string> r_sorted = r;
|
||||
std::sort(l_sorted.begin(), l_sorted.end());
|
||||
std::sort(r_sorted.begin(), r_sorted.end());
|
||||
std::set_union(l_sorted.begin(), l_sorted.end(), r_sorted.begin(), r_sorted.end(), std::back_inserter(t));
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ TroubleshootDialog::TroubleshootDialog()
|
||||
Fit();
|
||||
});
|
||||
|
||||
auto link_wiki = new HyperLink(this, _L("Wiki Guide"));
|
||||
auto link_wiki = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/troubleshoot_center");
|
||||
|
||||
// RIGHT SIZER //////////////////////
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "libslic3r/calib.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
@@ -38,3 +42,69 @@ TEST_CASE("Zero calibration line width resolves to a positive default", "[Calib]
|
||||
REQUIRE(pattern.line_width() > 0.);
|
||||
REQUIRE(pattern.line_width_first_layer() > 0.);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct EndState { double final_e; double max_e; };
|
||||
|
||||
EndState simulate_absolute_e(const std::string &gcode)
|
||||
{
|
||||
double final_e = 0.;
|
||||
double max_e = 0.;
|
||||
|
||||
std::istringstream lines(gcode);
|
||||
std::string line;
|
||||
while (std::getline(lines, line)) {
|
||||
std::istringstream words(line);
|
||||
std::string op;
|
||||
if (!(words >> op))
|
||||
continue;
|
||||
if (op != "G1" && op != "G0" && op != "G92")
|
||||
continue;
|
||||
|
||||
std::string word;
|
||||
while (words >> word) {
|
||||
if (word.size() >= 2 && word[0] == 'E') {
|
||||
final_e = std::stod(word.substr(1));
|
||||
max_e = std::max(max_e, final_e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {final_e, max_e};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("PA pattern resets the extruder after the final layer in absolute E mode", "[Calib][Regression]")
|
||||
{
|
||||
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||
config.set_deserialize_strict({
|
||||
{"use_relative_e_distances", "0"},
|
||||
{"line_width", "0.45"},
|
||||
{"initial_layer_line_width", "0.45"},
|
||||
});
|
||||
|
||||
Model model;
|
||||
model.add_object("cube", "", make_cube(20, 20, 20))->add_instance();
|
||||
|
||||
Calib_Params params;
|
||||
params.mode = CalibMode::Calib_PA_Pattern;
|
||||
params.start = 0.;
|
||||
params.end = 0.08;
|
||||
params.step = 0.002;
|
||||
|
||||
CalibPressureAdvancePattern pattern(params, config, /* is_bbl_machine */ false, *model.objects.front(), Vec3d(0, 0, 0));
|
||||
const CustomGCode::Info info = pattern.generate_custom_gcodes(config, /* is_bbl_machine */ false, *model.objects.front(),
|
||||
Vec3d(0, 0, 0));
|
||||
|
||||
std::string gcode;
|
||||
for (const CustomGCode::Item &item : info.gcodes)
|
||||
gcode += item.extra;
|
||||
|
||||
const EndState state = simulate_absolute_e(gcode);
|
||||
|
||||
REQUIRE(state.max_e > 1.);
|
||||
REQUIRE_THAT(state.final_e, Catch::Matchers::WithinAbs(0., 1e-9));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user