Calibration help: first 2 item

- bed leveling calibration
 - filament flow calibration (need some more pics)
This commit is contained in:
supermerill 2020-05-18 23:57:58 +02:00 committed by supermerill
parent af437e3f32
commit 073591d600
55 changed files with 1358 additions and 19 deletions

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Bed level calibration</title>
</head>
<body>
<h1>Bed level calibration</h1>
<p>This calibration is the first one to do, because it's mandatory to make a print stick on the build plate.</p>
<p>This calibration is made to do the fine tuning. Please level roughly the printer before: move your nozzle to 0.2mm, then you must be able to move a paper between the nozzle and the plater, but you have to be able to feel the nozzle touching it. With that, you should be able to level the bed with a ~0.1mm precision.</p>
<h2>How it works</h2>
<p>First, select your printer and your default print profile, with the filament profile for a filament you have. Note that this works with your first extruder if you have multiple ones.</p>
<p>When clicking on the Generate button, the program will create and slice the test print. You have to send it to your printer and print it. After the print end, check the result of each corners and the middle one against the photo below. You will have to tune your printer/firmware to correct the height if needed.</p>
<h2>Results</h2>
<table>
<tbody>
<tr>
<td><img src="./low_ll.jpg" alt="too low, by far" width="100" height="200" /></td>
<td><img src="./low_l.jpg" alt="too low, by far" width="100" height="200" /></td>
<td><img src="./low.jpg" alt="too low, by far" width="100" height="200" /></td>
<td><img src="./good.jpg" alt="too low, by far" width="100" height="200" /></td>
<td><img src="./high.jpg" alt="too low, by far" width="100" height="200" /></td>
<td><img src="./high_h.jpg" alt="too low, by far" width="100" height="200" /></td>
<td><img src="./high_hh.jpg" alt="too low, by far" width="100" height="200" /></td>
</tr>
<tr>
<td style="text-align: center;">Too far away</td>
<td style="text-align: center;">Too far</td>
<td style="text-align: center;">Too far:<br />You can spot<br />a little gap</td>
<td style="text-align: center;">perfect</td>
<td style="text-align: center;">Too near</td>
<td style="text-align: center;">Trap!<br />It's too near:<br />check the thickness<br />with your fingers!</td>
<td style="text-align: center;">Far too near<br />Dangerous<br />for the bed</td>
</tr>
</table>
<h2>How to tune your printer</h2>
<p><strong>If your printer has screws</strong>, use them to lift or drop the bed below the patch that need an adjust. Don't forget to print the test after the adjust to verify the compensation. Be careful, most of the time, a half-turn means 0.2mm of height, which equals (often) to the height of the first layer, so&nbsp; if you lift the bed, never turn more than that and prefer adjusting by quarter-turn at most.</p>
<p><strong>If it doesnt</strong>, you have to use the software or modify the firmware configuration, refer to the manual of your printer.</p>
<h2>Advices</h2>
<p>If your filament have a hard time sticking to the bed, you can try to :</p>
<ul>
<li>Increase the first layer width, it will increase the squish (pressure) without any over-extrusion. You can go as far as 200% nozzle width, but 150% should be enough. (Advanced setting, print -> width)</li>
<li>Reduce first layer printing speed, to let it time to stick. (Advanced setting, print -> speed)</li>
<li>You can disable/enable z-hop for the first layer by increasing "only lift z"-&gt; above Z" to a higher value than your first layer height. Enbaling it may pull the filament from the bed and diabling may let the nozzle strke &amp; push the deposited filament, so you have to test and keep the best. (Advanced setting, printer -> extruder)</li>
</ul>
<h2>Notes</h2>
<p>After the filament flow calibration, if it appears that the flow was very wrong, you may want to redo this calibration just after.</p>
<p>Most of the calibrations need to done is the right order. This one is the first to do.</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Document HTML</title>
</head>
<body>
<h1>hello you</h1>
bonjour le monde
</body>
</html>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Filament flow calibration</title>
</head>
<body>
<h1>Filament flow calibration</h1>
<p>You need to do the bed level calibration before this one.</p>
<p>This test will print five tests samples with various level of flow. You can choose the flow difference between each steps. You should start with the 10% one. After verifying the result with the help of the tabel below, you have to modify the filamant extrusion multiplier in your filament preset (if the -20 is the best, change the multiplier from 1 to 0.8, see the formula below). Don't forget to save it afterwards. You can continue with the 2.5 step if you want a bit more precision.</p>
<h2>Results</h2>
<table>
<tbody>
<h4>Exemple:</h4>
<tr>
<td><img src="./m20.jpg" alt="too low, by far" width="150" height="150" /></td>
<td><img src="./m10.jpg" alt="too low, by far" width="150" height="150" /></td>
<td><img src="./0_v1.jpg" alt="too low, by far" width="150" height="150" /></td>
<td><img src="./p10.jpg" alt="too low, by far" width="150" height="150" /></td>
<td><img src="./p20.jpg" alt="too low, by far" width="150" height="150" /></td>
</tr>
<tr>
<td style="text-align: center;">not flat</td>
<td style="text-align: center;">not flat</td>
<td style="text-align: center;">not flat</td>
<td style="text-align: center;">flat<br />But the circle<br />isn't flat enough</td>
<td style="text-align: center;">Flat surface<br />and good circle</td>
</tr>
<p>So here, I should </p>
</table>
<p>The flow you want to choose is the lowest that don't create gaps in the top surface. Here it seems that the good flow is below +20. So you have to change your extrusion multiplier to 1.2 and print the second set of test (or put 1.15 and call it for now).</p>
<h2>How to tune your printer</h2>
<p>You have to change the extrusion multiplier for the filament you calibrate for (and save it). Formula for the new extrusion multipler: new_multiplier = ( (100 + choosen_number) / 100 ) * old_multiplier<br />
Exemple: first step, i choose the -10, so i have ((100-10)/100) * 1 = (0.9) * 1 = 0.9<br />
second step i chooe +5, so i have ((100+5)/100) * 0.9 = (1.05) * 0.9 = 0.945
</p>
<p>If you want to make this change permanent and left your extrusion multipler to 1 in slic3r++, you can change your firmware configuration by mutiplying (or dividing, depends of the firmware/setting) the 'extruder speed setting' (e-step, step_distance) by this extrusion multipler.</p>
<h2>Advice</h2>
<p>Before doing this test, it's preferable to calibrate your extruder (it's easier on bowden setup):</p>
<ul>
<li>Remove the extruder bowden tube from the output of the extruder (or remove the extruder assembly from the nozzle assembly if you have a direct-extruder)</li>
<li>Put the filament through it (by hand or using the software control)</li>
<li>Cut the filament flush with the output of the extruder. Measure with your spring-steel ruler that you measure just 0mm. If not, note the value and don't forget to remove it from every other measure you do.</li>
<li>Ask your extruder to extrude 200mm of filament (gcode: G1 E200).</li>
<li>Measure the length o the extruded filament. Repeat this process two times more if you want to be more precise.</li>
<li>You have to change your extruder multiplier (estep, step_distance) by multipliying (or dividing, depending on your firmware) the current value by (200 / average_measured_value).</li>
<p>Note that this value may change if you change the pressure the extuder exerce against the filament.</p>
</ul>
<h2>Notes</h2>
<p>It's very difficult to tune the flow below the 2% mark, and no filament is consistent enought to warrant it anyway. A filament that have a guarantee of +-0,03mm have a ~7% variation between the low and high end cross section.</p>
<p>Most of the calibrations need to done is the right order. This one should be the second.</p>
<p>You may want to re-do the bed level calibration is the result is below 0.9 or higher than 1.1.</p>
<p>Note that the filament extrusion multipler can change with a different filament material, as a softer one can be squished/dented more by the extruder and so have a lower diameter in the extruder gears.</p>
<p>If your printer extruder eat the filament and can't complete the top layer, you have to increase the ironing distribution (by 5% increment). (Expert seting, print -> infill)</p>
</body>
</html>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Filament temperature calibration</title>
</head>
<body>
<h1>Filament flow calibration</h1>
<p>You need to do the bed level calibration before this one.</p>
<p>This test will print five tests samples with various level of flow. You can choose the flow difference between each steps. You should start with the 10% one. After verifying the result with the help of the tabel below, you have to modify the filamant extrusion multiplier in your filament preset (if the -20 is the best, change the multiplier from 1 to 0.8, see the formula below). Don't forget to save it afterwards. You can continue with the 2.5 step if you want a bit more precision.</p>
<h2>Results</h2>
<table>
<tbody>
<tr>
<td><img src="./low_ll.jpg" alt="too low, by far" width="100" height="200" /></td>
<td><img src="./low_l.jpg" alt="too low, by far" width="100" height="200" /></td>
<td><img src="./low.jpg" alt="too low, by far" width="100" height="200" /></td>
<td><img src="./good.jpg" alt="too low, by far" width="100" height="200" /></td>
<td><img src="./high.jpg" alt="too low, by far" width="100" height="200" /></td>
<td><img src="./high_h.jpg" alt="too low, by far" width="100" height="200" /></td>
<td><img src="./high_hh.jpg" alt="too low, by far" width="100" height="200" /></td>
</tr>
<tr>
<td style="text-align: center;">not enough flow</td>
<td style="text-align: center;">Too far</td>
<td style="text-align: center;">Too far:<br />You can spot<br />a little gap</td>
<td style="text-align: center;">ok</td>
<td style="text-align: center;">ok</td>
<td style="text-align: center;">Trap!<br />It's too near:<br />check the thickness<br />of the patch!</td>
<td style="text-align: center;">Far too near.<br />Dangerous<br />for the bed</td>
</tr>
</table>
<p>The flow you want to choose is the lowest that don't create gaps in the top surface.</p>
<h2>How to tune your printer</h2>
<p>You have to change the extrusion multiplier for the filament you calibrate for (and save it). Formula for the new extrusion multipler: new_multiplier = ( (100 + choosen_number) / 100 ) * old_multiplier<br />
Exemple: first step, i choose the -10, so i have ((100-10)/100) * 1 = (0.9) * 1 = 0.9<br />
second step i chooe +5, so i have ((100+5)/100) * 0.9 = (1.05) * 0.9 = 0.945
</p>
<p>If you want to make this change permanent and left your extrusion multipler to 1 in slic3r++, you can change your firmware configuration by mutiplying (or dividing, depends of the firmware/setting) the 'extruder speed setting' (e-step, step_distance) by this extrusion multipler.</p>
<h2>Advice</h2>
<p>Before doing this test, it's preferable to calibrate your extruder (it's easier on bowden setup):</p>
<ul>
<li>Remove the extruder bowden tube from the output of the extruder (or remove the extruder assembly from the nozzle assembly if you have a direct-extruder)</li>
<li>Put the filament through it (by hand or using the software control)</li>
<li>Cut the filament flush with the output of the extruder. Measure with your spring-steel ruler that you measure just 0mm. If not, note the value and don't forget to remove it from every other measure you do.</li>
<li>Ask your extruder to extrude 200mm of filament (gcode: G1 E200).</li>
<li>Measure the length o the extruded filament. Repeat this process two times more if you want to be more precise.</li>
<li>You have to change your extruder multiplier (estep, step_distance) by multipliying (or dividing, depending on your firmware) the current value by (200 / average_measured_value).</li>
<p>Note that this value may change if you change the pressure the extuder exerce against the filament.</p>
</ul>
<h2>Notes</h2>
<p>It's very difficult to tune the flow below the 2% mark, and no filament is consistent enought to warrant it anyway. A filament that have a guarantee of +-0,03mm have a ~7% variation between the low and high end cross section.</p>
<p>Most of the calibrations need to done is the right order. This one should be the second.</p>
<p>You may want to re-do the bed level calibration is the result is below 0.9 or higher than 1.1.</p>
<p>Note that the filament extrusion multipler can change with a different filament material, as a softer one can be squished/dented more by the extruder and so have a lower diameter in the extruder gears.</p>
<p>If your printer extruder eat the filament and can't complete the top layer, you have to increase the ironing distribution (by 5% increment). (Expert seting, print -> infill)</p>
</body>
</html>

Binary file not shown.

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Document HTML</title>
</head>
<body>
<h1>hello you</h1>
bonjour le monde
</body>
</html>

View File

@ -125,7 +125,7 @@ group:sidetext_width$3:Advanced
setting:infill_first
group:Advanced Infill
line:Ironing tuning
setting:label_width$6:width$5:fill_smooth_width
setting:label_width$6:width$5:sidetext_width$7:fill_smooth_width
setting:label_width$9:width$5:fill_smooth_distribution
end_line
@ -157,16 +157,16 @@ group:Raft
setting:raft_layers
group:Options for support material and raft
line:Z-offset
setting:support_material_contact_distance_type
setting:support_material_contact_distance_top
setting:support_material_contact_distance_bottom
setting:width$12:support_material_contact_distance_type
setting:width$6:support_material_contact_distance_top
setting:width$6:support_material_contact_distance_bottom
end_line
setting:support_material_pattern
setting:support_material_with_sheath
setting:support_material_spacing
setting:support_material_angle
setting:support_material_buildplate_only
setting:support_material_xy_spacing
setting:sidetext_width$7:support_material_xy_spacing
setting:dont_support_bridges
setting:support_material_synchronize_layers
group:Options for support material interface

View File

@ -215,7 +215,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
if (surface.has_fill_solid()) {
density = 100.;
fill_pattern = ipRectilinear;
fill_pattern = ipRectilinearWGapFill;
if (surface.has_pos_external() && !is_bridge)
fill_pattern = surface.has_pos_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value;
else if (!is_bridge)

View File

@ -48,7 +48,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
case ipSmoothHilbert: return new FillSmoothHilbert();
case ipRectiWithPerimeter: return new FillRectilinear2Peri();
case ipSawtooth: return new FillRectilinearSawtooth();
default: throw std::invalid_argument("unknown type");
default: throw std::invalid_argument("unknown type : "+type);
}
}

View File

@ -2821,7 +2821,9 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s
}
// calculate extrusion length per distance unit
double e_per_mm_per_height = m_writer.extruder()->e_per_mm3() * path->mm3_per_mm / this->m_layer->height;
double e_per_mm_per_height = (path->mm3_per_mm / this->m_layer->height)
* m_writer.extruder()->e_per_mm3()
* this->config().print_extrusion_multiplier.get_abs_value(1);
if (m_writer.extrusion_axis().empty()) e_per_mm_per_height = 0;
{
std::string comment = m_config.gcode_comments ? description : "";
@ -3322,7 +3324,9 @@ std::string GCode::extrude_multi_path3D(const ExtrusionMultiPath3D &multipath3D,
gcode += this->_before_extrude(path, description, speed);
// calculate extrusion length per distance unit
double e_per_mm = m_writer.extruder()->e_per_mm3() * path.mm3_per_mm;
double e_per_mm = path.mm3_per_mm
* m_writer.extruder()->e_per_mm3()
* this->config().print_extrusion_multiplier.get_abs_value(1);
if (m_writer.extrusion_axis().empty()) e_per_mm = 0;
double path_length = 0.;
{
@ -3389,7 +3393,9 @@ std::string GCode::extrude_path_3D(const ExtrusionPath3D &path, const std::strin
std::string gcode = this->_before_extrude(path, description, speed);
// calculate extrusion length per distance unit
double e_per_mm = m_writer.extruder()->e_per_mm3() * path.mm3_per_mm;
double e_per_mm = path.mm3_per_mm
* m_writer.extruder()->e_per_mm3()
* this->config().print_extrusion_multiplier.get_abs_value(1);
if (m_writer.extrusion_axis().empty()) e_per_mm = 0;
double path_length = 0.;
{
@ -3548,7 +3554,9 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string &descri
std::string gcode = this->_before_extrude(path, description, speed);
// calculate extrusion length per distance unit
double e_per_mm = m_writer.extruder()->e_per_mm3() * path.mm3_per_mm;
double e_per_mm = path.mm3_per_mm
* m_writer.extruder()->e_per_mm3()
* this->config().print_extrusion_multiplier.get_abs_value(1);
if (this->m_layer_index <= 0) e_per_mm *= this->config().first_layer_flow_ratio.get_abs_value(1);
if (m_writer.extrusion_axis().empty()) e_per_mm = 0;
double path_length = 0.;

View File

@ -873,12 +873,25 @@ void PrintConfigDef::init_fff_params()
def->label = L("Extrusion multiplier");
def->category = OptionCategory::filament;
def->tooltip = L("This factor changes the amount of flow proportionally. You may need to tweak "
"this setting to get nice surface finish and correct single wall widths. "
"Usual values are between 0.9 and 1.1. If you think you need to change this more, "
"check filament diameter and your firmware E steps.");
"this setting to get nice surface finish and correct single wall widths. "
"Usual values are between 0.9 and 1.1. If you think you need to change this more, "
"check filament diameter and your firmware E steps.");
def->mode = comSimple;
def->set_default_value(new ConfigOptionFloats { 1. });
def = this->add("print_extrusion_multiplier", coPercent);
def->label = L("Extrusion multiplier");
def->category = OptionCategory::width;
def->tooltip = L("This factor changes the amount of flow proportionally. You may need to tweak "
"this setting to get nice surface finish and correct single wall widths. "
"Usual values are between 0.9 and 1.1. If you think you need to change this more, "
"check filament diameter and your firmware E steps."
" This print setting is multiplied against the extrusion_multiplier from the filament tab."
" Its only purpose is to offer the same functionality but with a per-object basis.");
def->mode = comSimple;
def->min = 2;
def->set_default_value(new ConfigOptionPercent(100));
def = this->add("extrusion_width", coFloatOrPercent);
def->label = L("Default extrusion width");
def->category = OptionCategory::width;
@ -1720,7 +1733,7 @@ void PrintConfigDef::init_fff_params()
" It assume infinite acceleration for this time estimation, and only takes into account G1 and G0 moves. Use 0 to deactivate, negative to remove the 'D' option.");
def->sidetext = L("s");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
def->set_default_value(new ConfigOptionFloat(-1));
{
struct AxisDefault {

View File

@ -631,6 +631,7 @@ public:
ConfigOptionFloat perimeter_speed;
// Total number of perimeters.
ConfigOptionInt perimeters;
ConfigOptionPercent print_extrusion_multiplier;
ConfigOptionFloatOrPercent small_perimeter_speed;
ConfigOptionEnum<InfillPattern> solid_fill_pattern;
ConfigOptionFloat solid_infill_below_area;
@ -710,6 +711,7 @@ protected:
OPT_PTR(perimeter_loop_seam);
OPT_PTR(perimeter_speed);
OPT_PTR(perimeters);
OPT_PTR(print_extrusion_multiplier);
OPT_PTR(small_perimeter_speed);
OPT_PTR(solid_fill_pattern);
OPT_PTR(solid_infill_below_area);

View File

@ -18,6 +18,14 @@ set(SLIC3R_GUI_SOURCES
GUI/BackgroundSlicingProcess.hpp
GUI/BitmapCache.cpp
GUI/BitmapCache.hpp
GUI/CalibrationBedDialog.cpp
GUI/CalibrationBedDialog.hpp
GUI/CalibrationBridgeDialog.cpp
GUI/CalibrationBridgeDialog.hpp
GUI/CalibrationFlowDialog.cpp
GUI/CalibrationFlowDialog.hpp
GUI/CalibrationTempDialog.cpp
GUI/CalibrationTempDialog.hpp
GUI/ConfigSnapshotDialog.cpp
GUI/ConfigSnapshotDialog.hpp
GUI/3DScene.cpp

View File

@ -163,8 +163,8 @@ void GLIndexedVertexArray::render(
const std::pair<size_t, size_t>& tverts_range,
const std::pair<size_t, size_t>& qverts_range) const
{
assert(this->vertices_and_normals_interleaved_VBO_id != 0);
assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0);
// assert(this->vertices_and_normals_interleaved_VBO_id != 0);
// assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0);
// Render using the Vertex Buffer Objects.
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id));

View File

@ -0,0 +1,216 @@
#include "CalibrationBedDialog.hpp"
#include "I18N.hpp"
#include "libslic3r/Utils.hpp"
#include "GUI.hpp"
#include "GUI_ObjectList.hpp"
#include "tab.hpp"
#include <wx/scrolwin.h>
#include <wx/display.h>
#include <wx/file.h>
#include "wxExtensions.hpp"
#if ENABLE_SCROLLABLE
static wxSize get_screen_size(wxWindow* window)
{
const auto idx = wxDisplay::GetFromWindow(window);
wxDisplay display(idx != wxNOT_FOUND ? idx : 0u);
return display.GetClientArea().GetSize();
}
#endif // ENABLE_SCROLLABLE
namespace Slic3r {
namespace GUI {
CalibrationBedDialog::CalibrationBedDialog(GUI_App* app, MainFrame* mainframe)
: DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("Bed calibration - test objects generation")),
#if ENABLE_SCROLLABLE
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
#else
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
#endif // ENABLE_SCROLLABLE
{
this->gui_app = app;
this->main_frame = mainframe;
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
// fonts
const wxFont& font = wxGetApp().normal_font();
const wxFont& bold_font = wxGetApp().bold_font();
SetFont(font);
auto main_sizer = new wxBoxSizer(wxVERTICAL);
//html
std::cout << "display test.html\n";
html_viewer = new wxHtmlWindow(this, wxID_ANY,
wxDefaultPosition, wxSize(800, 500), wxHW_SCROLLBAR_AUTO);
html_viewer->LoadPage("./resources/calibration/bed_leveling/bed_leveling.html");
main_sizer->Add(html_viewer, 1, wxEXPAND | wxALL, 5);
wxStdDialogButtonSizer* buttons = new wxStdDialogButtonSizer();
wxButton* bt = new wxButton(this, wxID_FILE1, _(L("Generate")));
bt->Bind(wxEVT_BUTTON, &CalibrationBedDialog::create_geometry, this);
buttons->Add(bt);
wxButton* close = new wxButton(this, wxID_CLOSE, _(L("Close")));
close->Bind(wxEVT_BUTTON, &CalibrationBedDialog::closeMe, this);
buttons->AddButton(close);
close->SetDefault();
close->SetFocus();
SetAffirmativeId(wxID_CLOSE);
buttons->Realize();
main_sizer->Add(buttons, 0, wxEXPAND | wxALL, 5);
SetSizer(main_sizer);
main_sizer->SetSizeHints(this);
}
void CalibrationBedDialog::closeMe(wxCommandEvent& event_args) {
gui_app->delete_calibration_dialog();
}
void CalibrationBedDialog::create_geometry(wxCommandEvent& event_args) {
Plater* plat = this->main_frame->plater();
Model& model = plat->model();
plat->reset();
std::vector<size_t> objs_idx = plat->load_files(std::vector<std::string>{
"./resources/calibration/bed_leveling/patch.amf",
"./resources/calibration/bed_leveling/patch.amf",
"./resources/calibration/bed_leveling/patch.amf",
"./resources/calibration/bed_leveling/patch.amf",
"./resources/calibration/bed_leveling/patch.amf"}, true, false);
assert(objs_idx.size() == 5);
const DynamicPrintConfig* printConfig = this->gui_app->get_tab(Preset::TYPE_PRINT)->get_config();
const DynamicPrintConfig* printerConfig = this->gui_app->get_tab(Preset::TYPE_PRINTER)->get_config();
/// --- scale ---
//model is created for a 0.4 nozzle, scale xy with nozzle size.
const ConfigOptionFloats* nozzle_diameter = printerConfig->option<ConfigOptionFloats>("nozzle_diameter");
assert(nozzle_diameter->values.size() > 0);
float xyScale = nozzle_diameter->values[0] / 0.4;
//scale z with the first_layer_height
const ConfigOptionFloatOrPercent* first_layer_height = printConfig->option<ConfigOptionFloatOrPercent>("first_layer_height");
float zscale = first_layer_height->get_abs_value(nozzle_diameter->values[0]) / 0.2;
//do scaling
if (xyScale < 0.9 || 1.2 < xyScale) {
for (size_t i = 0; i < 5; i++)
model.objects[objs_idx[i]]->scale(xyScale, xyScale, zscale);
} else {
for (size_t i = 0; i < 5; i++)
model.objects[objs_idx[i]]->scale(1, 1, zscale);
}
/// --- rotate ---
const ConfigOptionPoints* bed_shape = printerConfig->option<ConfigOptionPoints>("bed_shape");
if (bed_shape->values.size() == 4) {
model.objects[objs_idx[0]]->rotate(PI / 4, { 0,0,1 });
model.objects[objs_idx[1]]->rotate(5 * PI / 4, { 0,0,1 });
model.objects[objs_idx[3]]->rotate(3 * PI / 4, { 0,0,1 });
model.objects[objs_idx[4]]->rotate(7 * PI / 4, { 0,0,1 });
} else {
model.objects[objs_idx[3]]->rotate(PI / 2, { 0,0,1 });
model.objects[objs_idx[4]]->rotate(PI / 2, { 0,0,1 });
}
/// --- translate ---
//three first will stay with this orientation (top left, middle, bottom right)
//last two with 90deg (top left, middle, bottom right)
//get position for patches
Vec2d bed_size = BoundingBoxf(bed_shape->values).size();
Vec2d bed_min = BoundingBoxf(bed_shape->values).min;
float offsetx = 10 + 10 * xyScale;
float offsety = 10 + 10 * xyScale;
if (bed_shape->values.size() > 4) {
offsetx = bed_size.x() / 2 - bed_size.x() * std::sqrtf(2) / 4 + 10 * xyScale;
offsety = bed_size.y() / 2 - bed_size.y() * std::sqrtf(2) / 4 + 10 * xyScale;
}
bool large_enough = bed_shape->values.size() == 4 ?
(bed_size.x() > offsetx * 3 && bed_size.y() > offsety * 3) :
(bed_size.x() > offsetx * 2 + 10 * xyScale && bed_size.y() > offsety * 2 + 10 * xyScale);
if (!large_enough){
//problem : too small, use arrange instead and let the user place them.
plat->arrange();
//TODO add message
} else {
model.objects[objs_idx[0]]->translate({ bed_min.x() + offsetx, bed_min.y() + bed_size.y() - offsety,0 });
model.objects[objs_idx[1]]->translate({ bed_min.x() + bed_size.x() - offsetx,bed_min.y() + offsety , 0 });
model.objects[objs_idx[2]]->translate({ bed_min.x() + bed_size.x()/2, bed_min.y() + bed_size.y() / 2, 0 });
model.objects[objs_idx[3]]->translate({ bed_min.x() + offsetx, bed_min.y() + offsety, 0 });
model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() - offsetx,bed_min.y() + bed_size.y() - offsety,0 });
}
/// --- main config, please modify object config when possible ---
DynamicPrintConfig new_print_config = *printConfig; //make a copy
new_print_config.set_key_value("complete_objects", new ConfigOptionBool(true));
new_print_config.set_key_value("skirts", new ConfigOptionInt(2));
/// --- custom config ---
for (size_t i = 0; i < 5; i++) {
model.objects[objs_idx[i]]->config.set_key_value("perimeters", new ConfigOptionInt(2));
model.objects[objs_idx[i]]->config.set_key_value("bottom_solid_layers", new ConfigOptionInt(2));
model.objects[objs_idx[i]]->config.set_key_value("gap_fill", new ConfigOptionBool(false));
model.objects[objs_idx[i]]->config.set_key_value("first_layer_extrusion_width", new ConfigOptionFloatOrPercent(140, true));
model.objects[objs_idx[i]]->config.set_key_value("bottom_fill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinearWGapFill));
}
if (bed_shape->values.size() == 4) {
model.objects[objs_idx[0]]->config.set_key_value("fill_angle", new ConfigOptionFloat(90));
model.objects[objs_idx[1]]->config.set_key_value("fill_angle", new ConfigOptionFloat(90));
model.objects[objs_idx[2]]->config.set_key_value("fill_angle", new ConfigOptionFloat(45));
model.objects[objs_idx[3]]->config.set_key_value("fill_angle", new ConfigOptionFloat(0));
model.objects[objs_idx[4]]->config.set_key_value("fill_angle", new ConfigOptionFloat(0));
} else {
for (size_t i = 0; i < 3; i++)
for (size_t i = 3; i < 5; i++)
model.objects[objs_idx[i]]->config.set_key_value("fill_angle", new ConfigOptionFloat(135));
}
//update plater
this->gui_app->get_tab(Preset::TYPE_PRINT)->load_config(new_print_config);
plat->on_config_change(new_print_config);
plat->changed_objects(objs_idx);
this->gui_app->get_tab(Preset::TYPE_PRINT)->update_dirty();
//update everything, easier to code.
this->gui_app->obj_list()->update_after_undo_redo();
//if(!plat->is_background_process_update_scheduled())
// plat->schedule_background_process();
plat->reslice();
plat->select_view_3D("Preview");
}
void CalibrationBedDialog::on_dpi_changed(const wxRect& suggested_rect)
{
msw_buttons_rescale(this, em_unit(), { wxID_OK });
Layout();
Fit();
Refresh();
}
wxPanel* CalibrationBedDialog::create_header(wxWindow* parent, const wxFont& bold_font)
{
wxPanel* panel = new wxPanel(parent);
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
wxFont header_font = bold_font;
#ifdef __WXOSX__
header_font.SetPointSize(14);
#else
header_font.SetPointSize(bold_font.GetPointSize() + 2);
#endif // __WXOSX__
sizer->AddStretchSpacer();
// text
wxStaticText* text = new wxStaticText(panel, wxID_ANY, _(L("Keyboard shortcuts")));
text->SetFont(header_font);
sizer->Add(text, 0, wxALIGN_CENTER_VERTICAL);
sizer->AddStretchSpacer();
panel->SetSizer(sizer);
return panel;
}
} // namespace GUI
} // namespace Slic3r

View File

@ -0,0 +1,41 @@
#ifndef slic3r_GUI_CalibrationBedDialog_hpp_
#define slic3r_GUI_CalibrationBedDialog_hpp_
#include <wx/wx.h>
#include <map>
#include <vector>
#include "GUI_App.hpp"
#include "GUI_Utils.hpp"
#include "MainFrame.hpp"
#include "wxExtensions.hpp"
#include <wx/html/htmlwin.h>
namespace Slic3r {
namespace GUI {
class CalibrationBedDialog : public DPIDialog
{
public:
CalibrationBedDialog(GUI_App* app, MainFrame* mainframe);
protected:
void on_dpi_changed(const wxRect &suggested_rect) override;
private:
void closeMe(wxCommandEvent& event_args);
void create_geometry(wxCommandEvent& event_args);
wxPanel* create_header(wxWindow* parent, const wxFont& bold_font);
wxHtmlWindow* html_viewer;
MainFrame* main_frame;
GUI_App* gui_app;
};
} // namespace GUI
} // namespace Slic3r
#endif

View File

@ -0,0 +1,196 @@
#include "CalibrationBridgeDialog.hpp"
#include "I18N.hpp"
#include "libslic3r/Utils.hpp"
#include "GUI.hpp"
#include "tab.hpp"
#include <wx/scrolwin.h>
#include <wx/display.h>
#include <wx/file.h>
#include "wxExtensions.hpp"
#if ENABLE_SCROLLABLE
static wxSize get_screen_size(wxWindow* window)
{
const auto idx = wxDisplay::GetFromWindow(window);
wxDisplay display(idx != wxNOT_FOUND ? idx : 0u);
return display.GetClientArea().GetSize();
}
#endif // ENABLE_SCROLLABLE
namespace Slic3r {
namespace GUI {
CalibrationBridgeDialog::CalibrationBridgeDialog(GUI_App* app, MainFrame* mainframe)
: DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("Bridge calibration - test objects generation")),
#if ENABLE_SCROLLABLE
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
#else
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
#endif // ENABLE_SCROLLABLE
{
this->gui_app = app;
this->main_frame = mainframe;
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
// fonts
const wxFont& font = wxGetApp().normal_font();
const wxFont& bold_font = wxGetApp().bold_font();
SetFont(font);
auto main_sizer = new wxBoxSizer(wxVERTICAL);
//html
std::cout << "display test.html\n";
html_viewer = new wxHtmlWindow(this, wxID_ANY,
wxDefaultPosition, wxSize(400, 400), wxHW_SCROLLBAR_AUTO);
html_viewer->LoadPage("./resources/calibration/bed_leveling/bed_leveling.html");
main_sizer->Add(html_viewer, 1, wxEXPAND | wxALL, 5);
wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxAPPLY| wxCLOSE);
buttons->GetApplyButton()->Bind(wxEVT_BUTTON, &CalibrationBridgeDialog::create_geometry, this);
this->SetEscapeId(wxCLOSE);
main_sizer->Add(buttons, 0, wxEXPAND | wxALL, 5);
SetSizer(main_sizer);
main_sizer->SetSizeHints(this);
}
void CalibrationBridgeDialog::create_geometry(wxCommandEvent& event_args) {
Plater* plat = this->main_frame->plater();
Model& model = plat->model();
plat->reset();
std::vector<size_t> objs_idx = plat->load_files(std::vector<std::string>{
"./resources/calibration/bed_leveling/patch.amf",
"./resources/calibration/bed_leveling/patch.amf",
"./resources/calibration/bed_leveling/patch.amf",
"./resources/calibration/bed_leveling/patch.amf",
"./resources/calibration/bed_leveling/patch.amf"}, true, false);
assert(objs_idx.size() == 5);
const DynamicPrintConfig* printConfig = this->gui_app->get_tab(Preset::TYPE_PRINT)->get_config();
const DynamicPrintConfig* printerConfig = this->gui_app->get_tab(Preset::TYPE_PRINTER)->get_config();
/// --- scale ---
//model is created for a 0.4 nozzle, scale xy with nozzle size.
const ConfigOptionFloats* nozzle_diameter = printerConfig->option<ConfigOptionFloats>("nozzle_diameter");
assert(nozzle_diameter->values.size() > 0);
float xyScale = nozzle_diameter->values[0] / 0.4;
//scale z with the first_layer_height
const ConfigOptionFloatOrPercent* first_layer_height = printConfig->option<ConfigOptionFloatOrPercent>("first_layer_height");
float zscale = first_layer_height->get_abs_value(nozzle_diameter->values[0]) / 0.2;
//do scaling
if (xyScale < 0.9 || 1.2 < xyScale) {
for (size_t i = 0; i < 5; i++)
model.objects[objs_idx[i]]->scale(xyScale, xyScale, zscale);
}
/// --- rotate ---
const ConfigOptionPoints* bed_shape = printerConfig->option<ConfigOptionPoints>("bed_shape");
if (bed_shape->values.size() == 4) {
model.objects[objs_idx[0]]->rotate(PI / 4, { 0,0,1 });
model.objects[objs_idx[1]]->rotate(5 * PI / 4, { 0,0,1 });
model.objects[objs_idx[3]]->rotate(3 * PI / 4, { 0,0,1 });
model.objects[objs_idx[4]]->rotate(7 * PI / 4, { 0,0,1 });
} else {
model.objects[objs_idx[3]]->rotate(PI / 2, { 0,0,1 });
model.objects[objs_idx[4]]->rotate(PI / 2, { 0,0,1 });
}
/// --- translate ---
//three first will stay with this orientation (top left, middle, bottom right)
//last two with 90deg (top left, middle, bottom right)
//get position for patches
Vec2d bed_size = BoundingBoxf(bed_shape->values).size();
Vec2d bed_min = BoundingBoxf(bed_shape->values).min;
float offsetx = 10 + 10 * xyScale;
float offsety = 10 + 10 * xyScale;
if (bed_shape->values.size() > 4) {
offsetx = bed_size.x() / 2 - bed_size.x() * std::sqrtf(2) / 4 + 10 * xyScale;
offsety = bed_size.y() / 2 - bed_size.y() * std::sqrtf(2) / 4 + 10 * xyScale;
}
bool large_enough = bed_shape->values.size() == 4 ?
(bed_size.x() > offsetx * 3 && bed_size.y() > offsety * 3) :
(bed_size.x() > offsetx * 2 + 10 * xyScale && bed_size.y() > offsety * 2 + 10 * xyScale);
if (!large_enough){
//problem : too small, use arrange instead and let the user place them.
model.arrange_objects(20);
//TODO add message
} else {
model.objects[objs_idx[0]]->translate({ bed_min.x() + offsetx, bed_min.y() + bed_size.y() - offsety,0 });
model.objects[objs_idx[1]]->translate({ bed_min.x() + bed_size.x() - offsetx,bed_min.y() + offsety , 0 });
model.objects[objs_idx[2]]->translate({ bed_min.x() + bed_size.x()/2, bed_min.y() + bed_size.y() / 2, 0 });
model.objects[objs_idx[3]]->translate({ bed_min.x() + offsetx, bed_min.y() + offsety, 0 });
model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() - offsetx,bed_min.y() + bed_size.y() - offsety,0 });
}
/// --- main config, please modify object config when possible ---
DynamicPrintConfig new_print_config = *printConfig; //make a copy
new_print_config.set_key_value("complete_objects", new ConfigOptionBool(true));
new_print_config.set_key_value("skirts", new ConfigOptionInt(0));
/// --- custom config ---
for (size_t i = 0; i < 5; i++) {
model.objects[objs_idx[i]]->config.set_key_value("perimeters", new ConfigOptionInt(2));
model.objects[objs_idx[i]]->config.set_key_value("bottom_solid_layers", new ConfigOptionInt(2));
model.objects[objs_idx[i]]->config.set_key_value("gap_fill", new ConfigOptionBool(false));
model.objects[objs_idx[i]]->config.set_key_value("first_layer_extrusion_width", new ConfigOptionFloatOrPercent(140, true));
model.objects[objs_idx[i]]->config.set_key_value("bottom_fill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinearWGapFill));
}
if (bed_shape->values.size() == 4) {
model.objects[objs_idx[0]]->config.set_key_value("fill_angle", new ConfigOptionFloat(90));
model.objects[objs_idx[1]]->config.set_key_value("fill_angle", new ConfigOptionFloat(90));
model.objects[objs_idx[2]]->config.set_key_value("fill_angle", new ConfigOptionFloat(45));
model.objects[objs_idx[3]]->config.set_key_value("fill_angle", new ConfigOptionFloat(0));
model.objects[objs_idx[4]]->config.set_key_value("fill_angle", new ConfigOptionFloat(0));
} else {
for (size_t i = 0; i < 3; i++)
for (size_t i = 3; i < 5; i++)
model.objects[objs_idx[i]]->config.set_key_value("fill_angle", new ConfigOptionFloat(135));
}
//update plater
this->gui_app->get_tab(Preset::TYPE_PRINT)->load_config(new_print_config);
plat->on_config_change(new_print_config);
plat->changed_objects(objs_idx);
//if(!plat->is_background_process_update_scheduled())
// plat->schedule_background_process();
plat->reslice();
plat->select_view_3D("Preview");
}
void CalibrationBridgeDialog::on_dpi_changed(const wxRect& suggested_rect)
{
msw_buttons_rescale(this, em_unit(), { wxID_OK });
Layout();
Fit();
Refresh();
}
wxPanel* CalibrationBridgeDialog::create_header(wxWindow* parent, const wxFont& bold_font)
{
wxPanel* panel = new wxPanel(parent);
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
wxFont header_font = bold_font;
#ifdef __WXOSX__
header_font.SetPointSize(14);
#else
header_font.SetPointSize(bold_font.GetPointSize() + 2);
#endif // __WXOSX__
sizer->AddStretchSpacer();
// text
wxStaticText* text = new wxStaticText(panel, wxID_ANY, _(L("Keyboard shortcuts")));
text->SetFont(header_font);
sizer->Add(text, 0, wxALIGN_CENTER_VERTICAL);
sizer->AddStretchSpacer();
panel->SetSizer(sizer);
return panel;
}
} // namespace GUI
} // namespace Slic3r

View File

@ -0,0 +1,39 @@
#ifndef slic3r_GUI_CalibrationBridgeDialog_hpp_
#define slic3r_GUI_CalibrationBridgeDialog_hpp_
#include <wx/wx.h>
#include <map>
#include <vector>
#include "GUI_App.hpp"
#include "GUI_Utils.hpp"
#include "MainFrame.hpp"
#include "wxExtensions.hpp"
#include <wx/html/htmlwin.h>
namespace Slic3r {
namespace GUI {
class CalibrationBridgeDialog : public DPIDialog
{
public:
CalibrationBridgeDialog(GUI_App* app, MainFrame* mainframe);
protected:
void on_dpi_changed(const wxRect &suggested_rect) override;
private:
void create_geometry(wxCommandEvent& event_args);
wxPanel* create_header(wxWindow* parent, const wxFont& bold_font);
wxHtmlWindow* html_viewer;
MainFrame* main_frame;
GUI_App* gui_app;
};
} // namespace GUI
} // namespace Slic3r
#endif

View File

@ -0,0 +1,272 @@
#include "CalibrationFlowDialog.hpp"
#include "I18N.hpp"
#include "libslic3r/Utils.hpp"
#include "GLCanvas3D.hpp "
#include "GUI.hpp"
#include "GUI_ObjectList.hpp"
#include "tab.hpp"
#include <wx/scrolwin.h>
#include <wx/display.h>
#include <wx/file.h>
#include "wxExtensions.hpp"
#if ENABLE_SCROLLABLE
static wxSize get_screen_size(wxWindow* window)
{
const auto idx = wxDisplay::GetFromWindow(window);
wxDisplay display(idx != wxNOT_FOUND ? idx : 0u);
return display.GetClientArea().GetSize();
}
#endif // ENABLE_SCROLLABLE
namespace Slic3r {
namespace GUI {
CalibrationFlowDialog::CalibrationFlowDialog(GUI_App* app, MainFrame* mainframe)
: DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("Flow calibration - test objects generation")),
#if ENABLE_SCROLLABLE
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
#else
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
#endif // ENABLE_SCROLLABLE
{
this->gui_app = app;
this->main_frame = mainframe;
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
// fonts
const wxFont& font = wxGetApp().normal_font();
const wxFont& bold_font = wxGetApp().bold_font();
SetFont(font);
auto main_sizer = new wxBoxSizer(wxVERTICAL);
//html
html_viewer = new wxHtmlWindow(this, wxID_ANY,
wxDefaultPosition, wxSize(600, 500), wxHW_SCROLLBAR_AUTO);
html_viewer->SetMinSize(wxSize(1000, 500));
html_viewer->LoadPage("./resources/calibration/filament_flow/filament_flow.html");
main_sizer->Add(html_viewer, 1, wxEXPAND | wxALL, 5);
wxStdDialogButtonSizer* buttons = new wxStdDialogButtonSizer();
wxButton* bt = new wxButton(this, wxID_FILE1, _(L("Generate 10% intervals")));
bt->Bind(wxEVT_BUTTON, &CalibrationFlowDialog::create_geometry_10, this);
buttons->Add(bt);
bt = new wxButton(this, wxID_FILE2, _(L("Generate 2.5% intervals")));
bt->Bind(wxEVT_BUTTON, &CalibrationFlowDialog::create_geometry_2_5, this);
buttons->Add(bt);
wxButton* close = new wxButton(this, wxID_CLOSE, _(L("Close")));
close->Bind(wxEVT_BUTTON, &CalibrationFlowDialog::closeMe, this);
buttons->AddButton(close);
close->SetDefault();
close->SetFocus();
SetAffirmativeId(wxID_CLOSE);
buttons->Realize();
main_sizer->Add(buttons, 0, wxEXPAND | wxALL, 5);
SetSizer(main_sizer);
main_sizer->SetSizeHints(this);
this->SetEscapeId(wxCLOSE);
this->SetAffirmativeId(wxCLOSE);
}
void CalibrationFlowDialog::closeMe(wxCommandEvent& event_args) {
gui_app->delete_calibration_dialog();
}
void CalibrationFlowDialog::create_geometry_10(wxCommandEvent& event_args) {
create_geometry(80.f, 10.f);
}
void CalibrationFlowDialog::create_geometry_2_5(wxCommandEvent& event_args) {
create_geometry(92.f, 2.F);
}
void CalibrationFlowDialog::add_part(ModelObject* model_object, std::string input_file, Vec3d move, Vec3d scale) {
Model model;
try {
model = Model::read_from_file(input_file);
}
catch (std::exception & e) {
auto msg = _(L("Error!")) + " " + input_file + " : " + e.what() + ".";
show_error(this, msg);
exit(1);
}
for (ModelObject *object : model.objects) {
Vec3d delta = Vec3d::Zero();
if (model_object->origin_translation != Vec3d::Zero())
{
object->center_around_origin();
delta = model_object->origin_translation - object->origin_translation;
}
for (ModelVolume *volume : object->volumes) {
volume->translate(delta + move);
if (scale != Vec3d{ 1,1,1 })
volume->scale(scale);
ModelVolume* new_volume = model_object->add_volume(*volume);
new_volume->set_type(ModelVolumeType::MODEL_PART);
new_volume->name = boost::filesystem::path(input_file).filename().string();
//volumes_info.push_back(std::make_pair(from_u8(new_volume->name), new_volume->get_mesh_errors_count() > 0));
// set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
//move to bed
/* const TriangleMesh& hull = new_volume->get_convex_hull();
float min_z = std::numeric_limits<float>::max();
for (const stl_facet& facet : hull.stl.facet_start) {
for (int i = 0; i < 3; ++i)
min_z = std::min(min_z, Vec3f::UnitZ().dot(facet.vertex[i]));
}
volume->translate(Vec3d(0,0,-min_z));*/
}
}
}
void CalibrationFlowDialog::create_geometry(float start, float delta) {
Plater* plat = this->main_frame->plater();
Model& model = plat->model();
plat->reset();
std::vector<size_t> objs_idx = plat->load_files(std::vector<std::string>{
"./resources/calibration/filament_flow/filament_flow_test_cube.amf",
"./resources/calibration/filament_flow/filament_flow_test_cube.amf",
"./resources/calibration/filament_flow/filament_flow_test_cube.amf",
"./resources/calibration/filament_flow/filament_flow_test_cube.amf",
"./resources/calibration/filament_flow/filament_flow_test_cube.amf"}, true, false);
assert(objs_idx.size() == 5);
const DynamicPrintConfig* printConfig = this->gui_app->get_tab(Preset::TYPE_PRINT)->get_config();
const DynamicPrintConfig* printerConfig = this->gui_app->get_tab(Preset::TYPE_PRINTER)->get_config();
/// --- scale ---
// model is created for a 0.4 nozzle, scale xy with nozzle size.
const ConfigOptionFloats* nozzle_diameter = printerConfig->option<ConfigOptionFloats>("nozzle_diameter");
assert(nozzle_diameter->values.size() > 0);
float xyScale = nozzle_diameter->values[0] / 0.4;
//scale z to have 6 layers
const ConfigOptionFloatOrPercent* first_layer_height = printConfig->option<ConfigOptionFloatOrPercent>("first_layer_height");
const ConfigOptionFloat* layer_height = printConfig->option<ConfigOptionFloat>("layer_height");
float zscale = first_layer_height->get_abs_value(nozzle_diameter->values[0]) + 5 * layer_height->value;
zscale *= (1 + 0.3 * (10. / delta));
//do scaling
if (xyScale < 0.9 || 1.2 < xyScale) {
for (size_t i = 0; i < 5; i++)
model.objects[objs_idx[i]]->scale(xyScale, xyScale, zscale);
} else {
for (size_t i = 0; i < 5; i++)
model.objects[objs_idx[i]]->scale(1, 1, zscale);
}
//add sub-part after scale
float zshift = (1 - zscale) / 2;
if (delta == 10.f && start == 80.f) {
add_part(model.objects[objs_idx[0]], "./resources/calibration/filament_flow/m20.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[1]], "./resources/calibration/filament_flow/m10.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[2]], "./resources/calibration/filament_flow/_0.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[3]], "./resources/calibration/filament_flow/p10.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[4]], "./resources/calibration/filament_flow/p20.amf", Vec3d{ 9,0,zshift });
} else if (delta == 2.f && start == 92.f) {
add_part(model.objects[objs_idx[0]], "./resources/calibration/filament_flow/m8.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[1]], "./resources/calibration/filament_flow/m6.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[2]], "./resources/calibration/filament_flow/m4.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[3]], "./resources/calibration/filament_flow/m2.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[4]], "./resources/calibration/filament_flow/_0.amf", Vec3d{ 9,0,zshift });
}
for (size_t i = 0; i < 5; i++) {
add_part(model.objects[objs_idx[i]], "./resources/calibration/filament_flow/O.amf", Vec3d{ 0,0,zscale/2.f + 0.5 }, Vec3d{1,1,xyScale });
}
/// --- translate ---;
const ConfigOptionFloat* extruder_clearance_radius = printConfig->option<ConfigOptionFloat>("extruder_clearance_radius");
const ConfigOptionPoints* bed_shape = printerConfig->option<ConfigOptionPoints>("bed_shape");
Vec2d bed_size = BoundingBoxf(bed_shape->values).size();
Vec2d bed_min = BoundingBoxf(bed_shape->values).min;
float offsetx = 5 + extruder_clearance_radius->value + 10 * xyScale;
float offsety = 5 + extruder_clearance_radius->value + 10 * xyScale;
model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx, bed_min.y() + bed_size.y() / 2 - offsety * 1.5, 0 });
model.objects[objs_idx[1]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx, bed_min.y() + bed_size.y() / 2 , 0 });
model.objects[objs_idx[2]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx, bed_min.y() + bed_size.y() / 2 + offsety * 1.5, 0 });
model.objects[objs_idx[3]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx, bed_min.y() + bed_size.y() / 2 - offsety , 0 });
model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx, bed_min.y() + bed_size.y() / 2 + offsety , 0 });
//TODO: if not enough space, forget about complete_objects
/// --- main config, please modify object config when possible ---
DynamicPrintConfig new_print_config = *printConfig; //make a copy
new_print_config.set_key_value("complete_objects", new ConfigOptionBool(true));
/// --- custom config ---
for (size_t i = 0; i < 5; i++) {
model.objects[objs_idx[i]]->config.set_key_value("brim_width", new ConfigOptionFloat(nozzle_diameter->values[0] * 3));
model.objects[objs_idx[i]]->config.set_key_value("brim_ears", new ConfigOptionBool(false));
model.objects[objs_idx[i]]->config.set_key_value("perimeters", new ConfigOptionInt(3));
model.objects[objs_idx[i]]->config.set_key_value("only_one_perimeter_top", new ConfigOptionBool(true));
model.objects[objs_idx[i]]->config.set_key_value("enforce_full_fill_volume", new ConfigOptionBool(true));
model.objects[objs_idx[i]]->config.set_key_value("bottom_solid_layers", new ConfigOptionInt(5));
model.objects[objs_idx[i]]->config.set_key_value("top_solid_layers", new ConfigOptionInt(100));
model.objects[objs_idx[i]]->config.set_key_value("thin_walls", new ConfigOptionBool(true));
model.objects[objs_idx[i]]->config.set_key_value("thin_walls_min_width", new ConfigOptionFloatOrPercent(50,true));
model.objects[objs_idx[i]]->config.set_key_value("gap_fill", new ConfigOptionBool(true));
model.objects[objs_idx[i]]->config.set_key_value("layer_height", new ConfigOptionFloat(nozzle_diameter->values[0]/2));
model.objects[objs_idx[i]]->config.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(nozzle_diameter->values[0] / 2, false));
model.objects[objs_idx[i]]->config.set_key_value("external_infill_margin", new ConfigOptionFloatOrPercent(100, true));
model.objects[objs_idx[i]]->config.set_key_value("solid_fill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinearWGapFill));
model.objects[objs_idx[i]]->config.set_key_value("top_fill_pattern", new ConfigOptionEnum<InfillPattern>(ipSmooth));
//set extrusion mult : 80 90 100 110 120
model.objects[objs_idx[i]]->config.set_key_value("print_extrusion_multiplier", new ConfigOptionPercent(start + (float)i * delta));
}
//update plater
this->gui_app->get_tab(Preset::TYPE_PRINT)->load_config(new_print_config);
plat->on_config_change(new_print_config);
plat->changed_objects(objs_idx);
this->gui_app->get_tab(Preset::TYPE_PRINT)->update_dirty();
//update everything, easier to code.
ObjectList* obj = this->gui_app->obj_list();
obj->update_after_undo_redo();
plat->reslice();
plat->select_view_3D("Preview");
}
void CalibrationFlowDialog::on_dpi_changed(const wxRect& suggested_rect)
{
msw_buttons_rescale(this, em_unit(), { wxID_OK });
Layout();
Fit();
Refresh();
}
wxPanel* CalibrationFlowDialog::create_header(wxWindow* parent, const wxFont& bold_font)
{
wxPanel* panel = new wxPanel(parent);
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
wxFont header_font = bold_font;
#ifdef __WXOSX__
header_font.SetPointSize(14);
#else
header_font.SetPointSize(bold_font.GetPointSize() + 2);
#endif // __WXOSX__
sizer->AddStretchSpacer();
// text
wxStaticText* text = new wxStaticText(panel, wxID_ANY, _(L("Keyboard shortcuts")));
text->SetFont(header_font);
sizer->Add(text, 0, wxALIGN_CENTER_VERTICAL);
sizer->AddStretchSpacer();
panel->SetSizer(sizer);
return panel;
}
} // namespace GUI
} // namespace Slic3r

View File

@ -0,0 +1,43 @@
#ifndef slic3r_GUI_CalibrationFlowDialog_hpp_
#define slic3r_GUI_CalibrationFlowDialog_hpp_
#include <wx/wx.h>
#include <map>
#include <vector>
#include "GUI_App.hpp"
#include "GUI_Utils.hpp"
#include "MainFrame.hpp"
#include "wxExtensions.hpp"
#include <wx/html/htmlwin.h>
namespace Slic3r {
namespace GUI {
class CalibrationFlowDialog : public DPIDialog
{
public:
CalibrationFlowDialog(GUI_App* app, MainFrame* mainframe);
protected:
void on_dpi_changed(const wxRect &suggested_rect) override;
private:
void closeMe(wxCommandEvent& event_args);
void create_geometry_10(wxCommandEvent& event_args);
void create_geometry_2_5(wxCommandEvent& event_args);
void add_part(ModelObject* model_object, std::string input_file, Vec3d move, Vec3d scale = Vec3d{ 1,1,1 });
void create_geometry(float start, float delta);
wxPanel* create_header(wxWindow* parent, const wxFont& bold_font);
wxHtmlWindow* html_viewer;
MainFrame* main_frame;
GUI_App* gui_app;
};
} // namespace GUI
} // namespace Slic3r
#endif

View File

@ -0,0 +1,196 @@
#include "CalibrationTempDialog.hpp"
#include "I18N.hpp"
#include "libslic3r/Utils.hpp"
#include "GUI.hpp"
#include "tab.hpp"
#include <wx/scrolwin.h>
#include <wx/display.h>
#include <wx/file.h>
#include "wxExtensions.hpp"
#if ENABLE_SCROLLABLE
static wxSize get_screen_size(wxWindow* window)
{
const auto idx = wxDisplay::GetFromWindow(window);
wxDisplay display(idx != wxNOT_FOUND ? idx : 0u);
return display.GetClientArea().GetSize();
}
#endif // ENABLE_SCROLLABLE
namespace Slic3r {
namespace GUI {
CalibrationTempDialog::CalibrationTempDialog(GUI_App* app, MainFrame* mainframe)
: DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("Temp calibration - test objects generation")),
#if ENABLE_SCROLLABLE
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
#else
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
#endif // ENABLE_SCROLLABLE
{
this->gui_app = app;
this->main_frame = mainframe;
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
// fonts
const wxFont& font = wxGetApp().normal_font();
const wxFont& bold_font = wxGetApp().bold_font();
SetFont(font);
auto main_sizer = new wxBoxSizer(wxVERTICAL);
//html
std::cout << "display test.html\n";
html_viewer = new wxHtmlWindow(this, wxID_ANY,
wxDefaultPosition, wxSize(400, 400), wxHW_SCROLLBAR_AUTO);
html_viewer->LoadPage("./resources/calibration/bed_leveling/bed_leveling.html");
main_sizer->Add(html_viewer, 1, wxEXPAND | wxALL, 5);
wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxAPPLY| wxCLOSE);
buttons->GetApplyButton()->Bind(wxEVT_BUTTON, &CalibrationTempDialog::create_geometry, this);
this->SetEscapeId(wxCLOSE);
main_sizer->Add(buttons, 0, wxEXPAND | wxALL, 5);
SetSizer(main_sizer);
main_sizer->SetSizeHints(this);
}
void CalibrationTempDialog::create_geometry(wxCommandEvent& event_args) {
Plater* plat = this->main_frame->plater();
Model& model = plat->model();
plat->reset();
std::vector<size_t> objs_idx = plat->load_files(std::vector<std::string>{
"./resources/calibration/bed_leveling/patch.amf",
"./resources/calibration/bed_leveling/patch.amf",
"./resources/calibration/bed_leveling/patch.amf",
"./resources/calibration/bed_leveling/patch.amf",
"./resources/calibration/bed_leveling/patch.amf"}, true, false);
assert(objs_idx.size() == 5);
const DynamicPrintConfig* printConfig = this->gui_app->get_tab(Preset::TYPE_PRINT)->get_config();
const DynamicPrintConfig* printerConfig = this->gui_app->get_tab(Preset::TYPE_PRINTER)->get_config();
/// --- scale ---
//model is created for a 0.4 nozzle, scale xy with nozzle size.
const ConfigOptionFloats* nozzle_diameter = printerConfig->option<ConfigOptionFloats>("nozzle_diameter");
assert(nozzle_diameter->values.size() > 0);
float xyScale = nozzle_diameter->values[0] / 0.4;
//scale z with the first_layer_height
const ConfigOptionFloatOrPercent* first_layer_height = printConfig->option<ConfigOptionFloatOrPercent>("first_layer_height");
float zscale = first_layer_height->get_abs_value(nozzle_diameter->values[0]) / 0.2;
//do scaling
if (xyScale < 0.9 || 1.2 < xyScale) {
for (size_t i = 0; i < 5; i++)
model.objects[objs_idx[i]]->scale(xyScale, xyScale, zscale);
}
/// --- rotate ---
const ConfigOptionPoints* bed_shape = printerConfig->option<ConfigOptionPoints>("bed_shape");
if (bed_shape->values.size() == 4) {
model.objects[objs_idx[0]]->rotate(PI / 4, { 0,0,1 });
model.objects[objs_idx[1]]->rotate(5 * PI / 4, { 0,0,1 });
model.objects[objs_idx[3]]->rotate(3 * PI / 4, { 0,0,1 });
model.objects[objs_idx[4]]->rotate(7 * PI / 4, { 0,0,1 });
} else {
model.objects[objs_idx[3]]->rotate(PI / 2, { 0,0,1 });
model.objects[objs_idx[4]]->rotate(PI / 2, { 0,0,1 });
}
/// --- translate ---
//three first will stay with this orientation (top left, middle, bottom right)
//last two with 90deg (top left, middle, bottom right)
//get position for patches
Vec2d bed_size = BoundingBoxf(bed_shape->values).size();
Vec2d bed_min = BoundingBoxf(bed_shape->values).min;
float offsetx = 10 + 10 * xyScale;
float offsety = 10 + 10 * xyScale;
if (bed_shape->values.size() > 4) {
offsetx = bed_size.x() / 2 - bed_size.x() * std::sqrtf(2) / 4 + 10 * xyScale;
offsety = bed_size.y() / 2 - bed_size.y() * std::sqrtf(2) / 4 + 10 * xyScale;
}
bool large_enough = bed_shape->values.size() == 4 ?
(bed_size.x() > offsetx * 3 && bed_size.y() > offsety * 3) :
(bed_size.x() > offsetx * 2 + 10 * xyScale && bed_size.y() > offsety * 2 + 10 * xyScale);
if (!large_enough){
//problem : too small, use arrange instead and let the user place them.
model.arrange_objects(20);
//TODO add message
} else {
model.objects[objs_idx[0]]->translate({ bed_min.x() + offsetx, bed_min.y() + bed_size.y() - offsety,0 });
model.objects[objs_idx[1]]->translate({ bed_min.x() + bed_size.x() - offsetx,bed_min.y() + offsety , 0 });
model.objects[objs_idx[2]]->translate({ bed_min.x() + bed_size.x()/2, bed_min.y() + bed_size.y() / 2, 0 });
model.objects[objs_idx[3]]->translate({ bed_min.x() + offsetx, bed_min.y() + offsety, 0 });
model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() - offsetx,bed_min.y() + bed_size.y() - offsety,0 });
}
/// --- main config, please modify object config when possible ---
DynamicPrintConfig new_print_config = *printConfig; //make a copy
new_print_config.set_key_value("complete_objects", new ConfigOptionBool(true));
new_print_config.set_key_value("skirts", new ConfigOptionInt(0));
/// --- custom config ---
for (size_t i = 0; i < 5; i++) {
model.objects[objs_idx[i]]->config.set_key_value("perimeters", new ConfigOptionInt(2));
model.objects[objs_idx[i]]->config.set_key_value("bottom_solid_layers", new ConfigOptionInt(2));
model.objects[objs_idx[i]]->config.set_key_value("gap_fill", new ConfigOptionBool(false));
model.objects[objs_idx[i]]->config.set_key_value("first_layer_extrusion_width", new ConfigOptionFloatOrPercent(140, true));
model.objects[objs_idx[i]]->config.set_key_value("bottom_fill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinearWGapFill));
}
if (bed_shape->values.size() == 4) {
model.objects[objs_idx[0]]->config.set_key_value("fill_angle", new ConfigOptionFloat(90));
model.objects[objs_idx[1]]->config.set_key_value("fill_angle", new ConfigOptionFloat(90));
model.objects[objs_idx[2]]->config.set_key_value("fill_angle", new ConfigOptionFloat(45));
model.objects[objs_idx[3]]->config.set_key_value("fill_angle", new ConfigOptionFloat(0));
model.objects[objs_idx[4]]->config.set_key_value("fill_angle", new ConfigOptionFloat(0));
} else {
for (size_t i = 0; i < 3; i++)
for (size_t i = 3; i < 5; i++)
model.objects[objs_idx[i]]->config.set_key_value("fill_angle", new ConfigOptionFloat(135));
}
//update plater
this->gui_app->get_tab(Preset::TYPE_PRINT)->load_config(new_print_config);
plat->on_config_change(new_print_config);
plat->changed_objects(objs_idx);
//if(!plat->is_background_process_update_scheduled())
// plat->schedule_background_process();
plat->reslice();
plat->select_view_3D("Preview");
}
void CalibrationTempDialog::on_dpi_changed(const wxRect& suggested_rect)
{
msw_buttons_rescale(this, em_unit(), { wxID_OK });
Layout();
Fit();
Refresh();
}
wxPanel* CalibrationTempDialog::create_header(wxWindow* parent, const wxFont& bold_font)
{
wxPanel* panel = new wxPanel(parent);
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
wxFont header_font = bold_font;
#ifdef __WXOSX__
header_font.SetPointSize(14);
#else
header_font.SetPointSize(bold_font.GetPointSize() + 2);
#endif // __WXOSX__
sizer->AddStretchSpacer();
// text
wxStaticText* text = new wxStaticText(panel, wxID_ANY, _(L("Keyboard shortcuts")));
text->SetFont(header_font);
sizer->Add(text, 0, wxALIGN_CENTER_VERTICAL);
sizer->AddStretchSpacer();
panel->SetSizer(sizer);
return panel;
}
} // namespace GUI
} // namespace Slic3r

View File

@ -0,0 +1,39 @@
#ifndef slic3r_GUI_CalibrationTempDialog_hpp_
#define slic3r_GUI_CalibrationTempDialog_hpp_
#include <wx/wx.h>
#include <map>
#include <vector>
#include "GUI_App.hpp"
#include "GUI_Utils.hpp"
#include "MainFrame.hpp"
#include "wxExtensions.hpp"
#include <wx/html/htmlwin.h>
namespace Slic3r {
namespace GUI {
class CalibrationTempDialog : public DPIDialog
{
public:
CalibrationTempDialog(GUI_App* app, MainFrame* mainframe);
protected:
void on_dpi_changed(const wxRect &suggested_rect) override;
private:
void create_geometry(wxCommandEvent& event_args);
wxPanel* create_header(wxWindow* parent, const wxFont& bold_font);
wxHtmlWindow* html_viewer;
MainFrame* main_frame;
GUI_App* gui_app;
};
} // namespace GUI
} // namespace Slic3r
#endif

View File

@ -40,6 +40,10 @@
#include "../Utils/PrintHost.hpp"
#include "../Utils/MacDarkMode.hpp"
#include "slic3r/Config/Snapshot.hpp"
#include "CalibrationBedDialog.hpp"
#include "CalibrationBridgeDialog.hpp"
#include "CalibrationFlowDialog.hpp"
#include "CalibrationTempDialog.hpp"
#include "ConfigSnapshotDialog.hpp"
#include "FirmwareDialog.hpp"
#include "Preferences.hpp"
@ -206,6 +210,8 @@ GUI_App::GUI_App()
GUI_App::~GUI_App()
{
delete_calibration_dialog();
if (app_config != nullptr)
delete app_config;
@ -280,6 +286,7 @@ bool GUI_App::on_init_inner()
// initialize label colors and fonts
init_label_colours();
init_fonts();
wxImage::AddHandler(new wxJPEGHandler());
// If load_language() fails, the application closes.
load_language(wxString(), true);
@ -532,6 +539,44 @@ void GUI_App::keyboard_shortcuts()
dlg.ShowModal();
}
void GUI_App::delete_calibration_dialog() {
if (not_modal_dialog.get() != nullptr) {
not_modal_dialog->Destroy();
}
not_modal_dialog.release();
}
void GUI_App::bed_leveling_dialog()
{
delete_calibration_dialog();
not_modal_dialog.reset(new CalibrationBedDialog(this, mainframe));
not_modal_dialog->Show();
}
void GUI_App::flow_ratio_dialog()
{
delete_calibration_dialog();
not_modal_dialog.reset(new CalibrationFlowDialog(this, mainframe));
not_modal_dialog->Show();
}
void GUI_App::over_bridge_dialog()
{
delete_calibration_dialog();
not_modal_dialog.reset(new CalibrationFlowDialog(this, mainframe));
not_modal_dialog->Show();
}
void GUI_App::bridge_tuning_dialog()
{
delete_calibration_dialog();
not_modal_dialog.reset(new CalibrationBridgeDialog(this, mainframe));
not_modal_dialog->Show();
}
void GUI_App::filament_temperature_dialog()
{
delete_calibration_dialog();
not_modal_dialog.reset(new CalibrationTempDialog(this, mainframe));
not_modal_dialog->Show();
}
// static method accepting a wxWindow object as first parameter
bool GUI_App::catch_error(std::function<void()> cb,
// wxMessageDialog* message_dialog,

View File

@ -131,6 +131,13 @@ public:
void recreate_GUI();
void system_info();
void keyboard_shortcuts();
void delete_calibration_dialog();
void bed_leveling_dialog();
void flow_ratio_dialog();
void filament_temperature_dialog();
void bridge_tuning_dialog();
void over_bridge_dialog();
//void support_tuning(); //have to do multiple, in a submenu
void load_project(wxWindow *parent, wxString& input_file) const;
void import_model(wxWindow *parent, wxArrayString& input_files) const;
static bool catch_error(std::function<void()> cb, const std::string& err);
@ -175,6 +182,7 @@ public:
PresetUpdater* preset_updater{ nullptr };
MainFrame* mainframe{ nullptr };
Plater* plater_{ nullptr };
std::unique_ptr<wxDialog> not_modal_dialog;
wxNotebook* tab_panel() const ;
int extruders_cnt() const;

View File

@ -759,6 +759,22 @@ void MainFrame::init_menubar()
[this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this);
}
// objects menu
auto objectsMenu = new wxMenu();
{
append_menu_item(objectsMenu, wxID_ANY, _(L("Bed/Extruder levelling")), _(L("Create a test print to help you to level your printer bed.")),
[this](wxCommandEvent&) { wxGetApp().bed_leveling_dialog(); });
append_menu_item(objectsMenu, wxID_ANY, _(L("Flow tuning")), _(L("Create a test print to help you to set your filament extrusion multiplier.")),
[this](wxCommandEvent&) { wxGetApp().flow_ratio_dialog(); });
//append_menu_item(objectsMenu, wxID_ANY, _(L("Ironing pattern tuning")), _(L("Create a test print to help you to set your over-bridge flow ratio.")),
// [this](wxCommandEvent&) { wxGetApp().over_bridge_dialog(); });
//append_menu_item(objectsMenu, wxID_ANY, _(L("Filament temperature tuning")), _(L("Create a test print to help you to set your filament temperature.")),
// [this](wxCommandEvent&) { wxGetApp().filament_temperature_dialog(); });
//append_menu_item(objectsMenu, wxID_ANY, _(L("Bridge pattern tuning")), _(L("Create a test print to help you to set your over-bridge flow ratio.")),
// [this](wxCommandEvent&) { wxGetApp().bridge_tuning_dialog(); });
}
// Help menu
auto helpMenu = new wxMenu();
{
@ -809,6 +825,7 @@ void MainFrame::init_menubar()
if (viewMenu) menubar->Append(viewMenu, _(L("&View")));
// Add additional menus from C++
wxGetApp().add_config_menu(menubar);
menubar->Append(objectsMenu, _(L("C&alibration")));
menubar->Append(helpMenu, _(L("&Help")));
SetMenuBar(menubar);

View File

@ -4779,6 +4779,9 @@ void Plater::remove_selected()
Plater::TakeSnapshot snapshot(this, _(L("Delete Selected Objects")));
this->p->view3D->delete_selected();
}
void Plater::arrange() {
p->arrange();
}
void Plater::increase_instances(size_t num)
{

View File

@ -213,6 +213,7 @@ public:
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
void send_gcode();
void eject_drive();
void arrange();
void take_snapshot(const std::string &snapshot_name);
void take_snapshot(const wxString &snapshot_name);

View File

@ -519,7 +519,8 @@ const std::vector<std::string>& Preset::print_options()
, "curve_smoothing_precision"
, "curve_smoothing_cutoff_dist"
, "curve_smoothing_angle_convex"
, "curve_smoothing_angle_concave"
, "curve_smoothing_angle_concave",
"print_extrusion_multiplier"
};
return s_opts;
}

View File

@ -726,7 +726,7 @@ void Tab::update_tab_ui()
void Tab::load_config(const DynamicPrintConfig& config)
{
bool modified = 0;
for(auto opt_key : m_config->diff(config)) {
for (auto opt_key : m_config->diff(config)) {
m_config->set_key_value(opt_key, config.option(opt_key)->clone());
modified = 1;
}