mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-23 06:33:57 -06:00
pa calib: batch mode for pa pattern (#7199)
* pa calib: batch mode option
This commit is contained in:
parent
538db07127
commit
ecc16bfabf
13 changed files with 299 additions and 106 deletions
|
@ -9468,12 +9468,10 @@ void Plater::calib_pa(const Calib_Params& params)
|
|||
|
||||
void Plater::_calib_pa_pattern(const Calib_Params& params)
|
||||
{
|
||||
// add "handle" cube
|
||||
sidebar().obj_list()->load_generic_subobject("Cube", ModelVolumeType::INVALID);
|
||||
orient();
|
||||
changed_objects({ 0 });
|
||||
_calib_pa_select_added_objects();
|
||||
|
||||
std::vector<double> speeds{params.speeds};
|
||||
std::vector<double> accels{params.accelerations};
|
||||
std::vector<size_t> object_idxs{};
|
||||
/* Set common parameters */
|
||||
DynamicPrintConfig& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||
DynamicPrintConfig& print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
auto filament_config = &wxGetApp().preset_bundle->filaments.get_edited_preset().config;
|
||||
|
@ -9491,17 +9489,18 @@ void Plater::_calib_pa_pattern(const Calib_Params& params)
|
|||
accel = print_config.option<ConfigOptionFloat>("default_acceleration")->value;
|
||||
// Orca: Set all accelerations except first layer, as the first layer accel doesnt affect the PA test since accel
|
||||
// is set to the travel accel before printing the pattern.
|
||||
print_config.set_key_value( "default_acceleration", new ConfigOptionFloat(accel));
|
||||
if (accels.empty()) {
|
||||
accels.assign({accel});
|
||||
const auto msg{_L("INFO:") + "\n" +
|
||||
_L("No accelerations provided for calibration. Use default acceleration value ") + std::to_string(long(accel)) + _L("mm/s²")};
|
||||
get_notification_manager()->push_notification(msg.ToStdString());
|
||||
} else {
|
||||
// set max acceleration in case of batch mode to get correct test pattern size
|
||||
accel = *std::max_element(accels.begin(), accels.end());
|
||||
}
|
||||
print_config.set_key_value( "outer_wall_acceleration", new ConfigOptionFloat(accel));
|
||||
print_config.set_key_value( "inner_wall_acceleration", new ConfigOptionFloat(accel));
|
||||
print_config.set_key_value( "bridge_acceleration", new ConfigOptionFloatOrPercent(accel, false));
|
||||
print_config.set_key_value( "sparse_infill_acceleration", new ConfigOptionFloatOrPercent(accel, false));
|
||||
print_config.set_key_value( "internal_solid_infill_acceleration", new ConfigOptionFloatOrPercent(accel, false));
|
||||
print_config.set_key_value( "top_surface_acceleration", new ConfigOptionFloat(accel));
|
||||
print_config.set_key_value( "travel_acceleration", new ConfigOptionFloat(accel));
|
||||
print_config.set_key_value( "print_sequence", new ConfigOptionEnum(PrintSequence::ByLayer));
|
||||
|
||||
|
||||
//Orca: find jerk value to use in the test
|
||||
if(print_config.option<ConfigOptionFloat>("default_jerk")->value > 0){ // we have set a jerk value
|
||||
auto jerk = print_config.option<ConfigOptionFloat>("outer_wall_jerk")->value; // get outer wall jerk
|
||||
|
@ -9547,12 +9546,24 @@ void Plater::_calib_pa_pattern(const Calib_Params& params)
|
|||
);
|
||||
|
||||
// Orca: Set the outer wall speed to the optimal speed for the test, cap it with max volumetric speed
|
||||
print_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(CalibPressureAdvance::find_optimal_PA_speed(
|
||||
wxGetApp().preset_bundle->full_config(),
|
||||
(fabs(print_config.get_abs_value("line_width", nozzle_diameter)) <= DBL_EPSILON) ?
|
||||
(nozzle_diameter * 1.125) :
|
||||
print_config.get_abs_value("line_width", nozzle_diameter),
|
||||
print_config.get_abs_value("layer_height"), 0)));
|
||||
if (speeds.empty()) {
|
||||
double speed = CalibPressureAdvance::find_optimal_PA_speed(
|
||||
wxGetApp().preset_bundle->full_config(),
|
||||
(fabs(print_config.get_abs_value("line_width", nozzle_diameter)) <= DBL_EPSILON) ?
|
||||
(nozzle_diameter * 1.125) :
|
||||
print_config.get_abs_value("line_width", nozzle_diameter),
|
||||
print_config.get_abs_value("layer_height"), 0);
|
||||
print_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(speed));
|
||||
|
||||
speeds.assign({speed});
|
||||
const auto msg{_L("INFO:") + "\n" +
|
||||
_L("No speeds provided for calibration. Use default optimal speed ") + std::to_string(long(speed)) + _L("mm/s")};
|
||||
get_notification_manager()->push_notification(msg.ToStdString());
|
||||
} else if (speeds.size() == 1) {
|
||||
// If we have single value provided, set speed using global configuration.
|
||||
// per-object config is not set in this case
|
||||
print_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(speeds.front()));
|
||||
}
|
||||
|
||||
wxGetApp().get_tab(Preset::TYPE_PRINT)->update_dirty();
|
||||
wxGetApp().get_tab(Preset::TYPE_FILAMENT)->update_dirty();
|
||||
|
@ -9564,54 +9575,133 @@ void Plater::_calib_pa_pattern(const Calib_Params& params)
|
|||
const DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config();
|
||||
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
|
||||
const bool is_bbl_machine = preset_bundle->is_bbl_vendor();
|
||||
const Vec3d plate_origin = get_partplate_list().get_current_plate_origin();
|
||||
auto cur_plate = get_partplate_list().get_plate(0);
|
||||
|
||||
// add "handle" cube
|
||||
sidebar().obj_list()->load_generic_subobject("Cube", ModelVolumeType::INVALID);
|
||||
auto *cube = model().objects[0];
|
||||
|
||||
CalibPressureAdvancePattern pa_pattern(
|
||||
params,
|
||||
full_config,
|
||||
is_bbl_machine,
|
||||
model(),
|
||||
plate_origin
|
||||
*cube,
|
||||
cur_plate->get_origin()
|
||||
);
|
||||
|
||||
// scale cube to suit test
|
||||
GizmoObjectManipulation& giz_obj_manip = p->view3D->get_canvas3d()->
|
||||
get_gizmos_manager().get_object_manipulation();
|
||||
giz_obj_manip.set_uniform_scaling(true);
|
||||
giz_obj_manip.on_change(
|
||||
"size",
|
||||
0,
|
||||
pa_pattern.handle_xy_size()
|
||||
);
|
||||
giz_obj_manip.set_uniform_scaling(false);
|
||||
giz_obj_manip.on_change(
|
||||
"size",
|
||||
2,
|
||||
pa_pattern.max_layer_z()
|
||||
);
|
||||
// start with pattern centered on plate
|
||||
center_selection();
|
||||
const Vec3d plate_center = get_partplate_list().get_curr_plate()->get_center_origin();
|
||||
giz_obj_manip.on_change(
|
||||
"position",
|
||||
0,
|
||||
plate_center.x() - (pa_pattern.print_size_x() / 2)
|
||||
);
|
||||
giz_obj_manip.on_change(
|
||||
"position",
|
||||
1,
|
||||
plate_center.y() -
|
||||
(pa_pattern.print_size_y() / 2) -
|
||||
pa_pattern.handle_spacing()
|
||||
);
|
||||
/* Having PA pattern configured, we could make a set of polygons resembling N test patterns.
|
||||
* We'll arrange this set of polygons, so we would know position of each test pattern and
|
||||
* could position test cubes later on
|
||||
*
|
||||
* We'll take advantage of already existing cube: scale it up to test pattern size to use
|
||||
* as a reference for objects arrangement. Polygon is slightly oversized to add spaces between patterns.
|
||||
* That arrangement will be used to place 'handle cubes' for each test. */
|
||||
auto cube_bb = cube->raw_bounding_box();
|
||||
cube->scale((pa_pattern.print_size_x() + 4) / cube_bb.size().x(),
|
||||
(pa_pattern.print_size_y() + 4) / cube_bb.size().y(),
|
||||
pa_pattern.max_layer_z() / cube_bb.size().z());
|
||||
|
||||
arrangement::ArrangePolygons arranged_items;
|
||||
{
|
||||
arrangement::ArrangeParams ap;
|
||||
Points bedpts = arrangement::get_shrink_bedpts(&full_config, ap);
|
||||
|
||||
for(size_t i = 0; i < speeds.size() * accels.size(); i++) {
|
||||
arrangement::ArrangePolygon p;
|
||||
cube->instances[0]->get_arrange_polygon(&p);
|
||||
p.bed_idx = 0;
|
||||
arranged_items.emplace_back(p);
|
||||
}
|
||||
|
||||
arrangement::arrange(arranged_items, bedpts, ap);
|
||||
}
|
||||
|
||||
/* scale cube back to the size of test pattern 'handle' */
|
||||
cube_bb = cube->raw_bounding_box();
|
||||
cube->scale(pa_pattern.handle_xy_size() / cube_bb.size().x(),
|
||||
pa_pattern.handle_xy_size() / cube_bb.size().y(),
|
||||
pa_pattern.max_layer_z() / cube_bb.size().z());
|
||||
|
||||
/* Set speed and acceleration on per-object basis and arrange anchor object on the plates.
|
||||
* Test gcode will be genecated during plate slicing */
|
||||
for(size_t test_idx = 0; test_idx < arranged_items.size(); test_idx++) {
|
||||
const auto &ai = arranged_items[test_idx];
|
||||
size_t plate_idx = arranged_items[test_idx].bed_idx;
|
||||
auto tspd = speeds[test_idx % speeds.size()];
|
||||
auto tacc = accels[test_idx / speeds.size()];
|
||||
|
||||
/* make an own copy of anchor cube for each test */
|
||||
auto obj = test_idx == 0 ? cube : model().add_object(*cube);
|
||||
auto obj_idx = std::distance(model().objects.begin(), std::find(model().objects.begin(), model().objects.end(), obj));
|
||||
obj->name.assign(std::string("pa_pattern_") + std::to_string(int(tspd)) + std::string("_") + std::to_string(int(tacc)));
|
||||
|
||||
auto &obj_config = obj->config;
|
||||
if (speeds.size() > 1)
|
||||
obj_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(tspd));
|
||||
if (accels.size() > 1)
|
||||
obj_config.set_key_value("outer_wall_acceleration", new ConfigOptionFloat(tacc));
|
||||
|
||||
auto cur_plate = get_partplate_list().get_plate(plate_idx);
|
||||
if (!cur_plate) {
|
||||
plate_idx = get_partplate_list().create_plate();
|
||||
cur_plate = get_partplate_list().get_plate(plate_idx);
|
||||
}
|
||||
|
||||
object_idxs.emplace_back(obj_idx);
|
||||
get_partplate_list().add_to_plate(obj_idx, 0, plate_idx);
|
||||
const Vec3d obj_offset{unscale<double>(ai.translation(X)),
|
||||
unscale<double>(ai.translation(Y)),
|
||||
0};
|
||||
obj->instances[0]->set_offset(cur_plate->get_origin() + obj_offset + pa_pattern.handle_pos_offset());
|
||||
obj->ensure_on_bed();
|
||||
|
||||
if (obj_idx == 0)
|
||||
sidebar().obj_list()->update_name_for_items();
|
||||
else
|
||||
sidebar().obj_list()->add_object_to_list(obj_idx);
|
||||
}
|
||||
|
||||
pa_pattern.generate_custom_gcodes(
|
||||
full_config,
|
||||
is_bbl_machine,
|
||||
model(),
|
||||
plate_origin
|
||||
);
|
||||
model().calib_pa_pattern = std::make_unique<CalibPressureAdvancePattern>(pa_pattern);
|
||||
changed_objects({ 0 });
|
||||
changed_objects(object_idxs);
|
||||
}
|
||||
|
||||
void Plater::_calib_pa_pattern_gen_gcode()
|
||||
{
|
||||
if (!model().calib_pa_pattern)
|
||||
return;
|
||||
|
||||
auto cur_plate = get_partplate_list().get_curr_plate();
|
||||
if (cur_plate->empty())
|
||||
return;
|
||||
|
||||
/* Container to store custom g-codes genereted by the test generator.
|
||||
* We'll store gcode for all tests on a single plate here. Once the plate handling is done,
|
||||
* all the g-codes will be merged into a single one on per-layer basis */
|
||||
std::vector<CustomGCode::Info> mgc;
|
||||
PresetBundle *preset_bundle = wxGetApp().preset_bundle;
|
||||
|
||||
/* iterate over all cubes on current plate and generate gcode for them */
|
||||
for (auto obj : cur_plate->get_objects_on_this_plate()) {
|
||||
auto gcode = model().calib_pa_pattern->generate_custom_gcodes(
|
||||
preset_bundle->full_config(),
|
||||
preset_bundle->is_bbl_vendor(),
|
||||
*obj,
|
||||
cur_plate->get_origin()
|
||||
);
|
||||
mgc.emplace_back(gcode);
|
||||
}
|
||||
|
||||
// move first item into model custom gcode
|
||||
auto &pcgc = model().plates_custom_gcodes[get_partplate_list().get_curr_plate_index()];
|
||||
pcgc = std::move(mgc[0]);
|
||||
mgc.erase(mgc.begin());
|
||||
|
||||
// concat layer gcodes for each test
|
||||
for (size_t i = 0; i < pcgc.gcodes.size(); i++) {
|
||||
for (auto &gc : mgc) {
|
||||
pcgc.gcodes[i].extra += gc.gcodes[i].extra;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Plater::cut_horizontal(size_t obj_idx, size_t instance_idx, double z, ModelObjectCutAttributes attributes)
|
||||
|
@ -12385,14 +12475,7 @@ void Plater::reslice()
|
|||
|
||||
// Orca: regenerate CalibPressureAdvancePattern custom G-code to apply changes
|
||||
if (model().calib_pa_pattern) {
|
||||
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
|
||||
|
||||
model().calib_pa_pattern->generate_custom_gcodes(
|
||||
wxGetApp().preset_bundle->full_config(),
|
||||
preset_bundle->is_bbl_vendor(),
|
||||
model(),
|
||||
get_partplate_list().get_current_plate_origin()
|
||||
);
|
||||
_calib_pa_pattern_gen_gcode();
|
||||
}
|
||||
|
||||
if (printer_technology() == ptSLA) {
|
||||
|
|
|
@ -820,6 +820,7 @@ private:
|
|||
int start_next_slice();
|
||||
|
||||
void _calib_pa_pattern(const Calib_Params& params);
|
||||
void _calib_pa_pattern_gen_gcode();
|
||||
void _calib_pa_tower(const Calib_Params& params);
|
||||
void _calib_pa_select_added_objects();
|
||||
|
||||
|
|
|
@ -6,7 +6,20 @@
|
|||
#include "MainFrame.hpp"
|
||||
#include <string>
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
void ParseStringValues(std::string str, std::vector<double> &vec)
|
||||
{
|
||||
vec.clear();
|
||||
std::replace(str.begin(), str.end(), ',', ' ');
|
||||
std::istringstream inss(str);
|
||||
std::copy_if(std::istream_iterator<int>(inss), std::istream_iterator<int>(), std::back_inserter(vec),
|
||||
[](int x){ return x > 0; });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
wxBoxSizer* create_item_checkbox(wxString title, wxWindow* parent, bool* value, CheckBox*& checkbox)
|
||||
{
|
||||
wxBoxSizer* m_sizer_checkbox = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
@ -59,14 +72,18 @@ PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater*
|
|||
wxString start_pa_str = _L("Start PA: ");
|
||||
wxString end_pa_str = _L("End PA: ");
|
||||
wxString PA_step_str = _L("PA step: ");
|
||||
wxString sp_accel_str = _L("Accelerations: ");
|
||||
wxString sp_speed_str = _L("Speeds: ");
|
||||
auto text_size = wxWindow::GetTextExtent(start_pa_str);
|
||||
text_size.IncTo(wxWindow::GetTextExtent(end_pa_str));
|
||||
text_size.IncTo(wxWindow::GetTextExtent(PA_step_str));
|
||||
text_size.x = text_size.x * 1.5;
|
||||
text_size.IncTo(wxWindow::GetTextExtent(sp_accel_str));
|
||||
text_size.IncTo(wxWindow::GetTextExtent(sp_speed_str));
|
||||
text_size.x = text_size.x * 1.1;
|
||||
wxStaticBoxSizer* settings_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _L("Settings"));
|
||||
|
||||
auto st_size = FromDIP(wxSize(text_size.x, -1));
|
||||
auto ti_size = FromDIP(wxSize(90, -1));
|
||||
auto ti_size = FromDIP(wxSize(140, -1));
|
||||
// start PA
|
||||
auto start_PA_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto start_pa_text = new wxStaticText(this, wxID_ANY, start_pa_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
|
||||
|
@ -98,6 +115,27 @@ PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater*
|
|||
settings_sizer->Add(create_item_checkbox(_L("Print numbers"), this, &m_params.print_numbers, m_cbPrintNum));
|
||||
m_cbPrintNum->SetValue(false);
|
||||
|
||||
wxTextValidator val_list_validator(wxFILTER_INCLUDE_CHAR_LIST);
|
||||
val_list_validator.SetCharIncludes(wxString("0123456789,"));
|
||||
|
||||
auto sp_accel_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto sp_accel_text = new wxStaticText(this, wxID_ANY, sp_accel_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
|
||||
m_tiBMAccels = new TextInput(this, "", "", "", wxDefaultPosition, ti_size, wxTE_PROCESS_ENTER);
|
||||
m_tiBMAccels->SetToolTip(_L("Comma-separated list of printing accelerations"));
|
||||
m_tiBMAccels->GetTextCtrl()->SetValidator(val_list_validator);
|
||||
sp_accel_sizer->Add(sp_accel_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
sp_accel_sizer->Add(m_tiBMAccels, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
settings_sizer->Add(sp_accel_sizer);
|
||||
|
||||
auto sp_speed_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto sp_speed_text = new wxStaticText(this, wxID_ANY, sp_speed_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
|
||||
m_tiBMSpeeds = new TextInput(this, "", "", "", wxDefaultPosition, ti_size, wxTE_PROCESS_ENTER);
|
||||
m_tiBMSpeeds->SetToolTip(_L("Comma-separated list of printing speeds"));
|
||||
m_tiBMSpeeds->GetTextCtrl()->SetValidator(val_list_validator);
|
||||
sp_speed_sizer->Add(sp_speed_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
sp_speed_sizer->Add(m_tiBMSpeeds, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
settings_sizer->Add(sp_speed_sizer);
|
||||
|
||||
v_sizer->Add(settings_sizer);
|
||||
v_sizer->Add(0, FromDIP(10), 0, wxEXPAND, 5);
|
||||
m_btnStart = new Button(this, _L("OK"));
|
||||
|
@ -146,6 +184,8 @@ void PA_Calibration_Dlg::reset_params() {
|
|||
m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.002));
|
||||
m_cbPrintNum->SetValue(true);
|
||||
m_cbPrintNum->Enable(true);
|
||||
m_tiBMAccels->Enable(false);
|
||||
m_tiBMSpeeds->Enable(false);
|
||||
break;
|
||||
case 2:
|
||||
m_params.mode = CalibMode::Calib_PA_Pattern;
|
||||
|
@ -153,6 +193,8 @@ void PA_Calibration_Dlg::reset_params() {
|
|||
m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.005));
|
||||
m_cbPrintNum->SetValue(true);
|
||||
m_cbPrintNum->Enable(false);
|
||||
m_tiBMAccels->Enable(true);
|
||||
m_tiBMSpeeds->Enable(true);
|
||||
break;
|
||||
default:
|
||||
m_params.mode = CalibMode::Calib_PA_Tower;
|
||||
|
@ -160,6 +202,8 @@ void PA_Calibration_Dlg::reset_params() {
|
|||
m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.002));
|
||||
m_cbPrintNum->SetValue(false);
|
||||
m_cbPrintNum->Enable(false);
|
||||
m_tiBMAccels->Enable(false);
|
||||
m_tiBMSpeeds->Enable(false);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -197,6 +241,8 @@ void PA_Calibration_Dlg::on_start(wxCommandEvent& event) {
|
|||
}
|
||||
|
||||
m_params.print_numbers = m_cbPrintNum->GetValue();
|
||||
ParseStringValues(m_tiBMAccels->GetTextCtrl()->GetValue().ToStdString(), m_params.accelerations);
|
||||
ParseStringValues(m_tiBMSpeeds->GetTextCtrl()->GetValue().ToStdString(), m_params.speeds);
|
||||
|
||||
m_plater->calib_pa(m_params);
|
||||
EndModal(wxID_OK);
|
||||
|
|
|
@ -41,6 +41,8 @@ protected:
|
|||
TextInput* m_tiEndPA;
|
||||
TextInput* m_tiPAStep;
|
||||
CheckBox* m_cbPrintNum;
|
||||
TextInput* m_tiBMAccels;
|
||||
TextInput* m_tiBMSpeeds;
|
||||
Button* m_btnStart;
|
||||
|
||||
Plater* m_plater;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue