Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsupermerill <merill@free.fr>2021-09-06 19:21:41 +0300
committersupermerill <merill@free.fr>2021-09-06 19:21:41 +0300
commit70d9ca80ff0f82928ac260a5106121316866767b (patch)
treeacd4cc8266287b307218b425b22e1f1b84d3f41c
parentc582f369f2066b337bc2e9adada60418da2a3748 (diff)
parent2795295ff0e13e12d1e36aeb504fe83d0899900e (diff)
Merge branch 'merill-merge'2.3.57.0
-rw-r--r--resources/icons/Slic3r-gcodeviewer.icobin0 -> 120117 bytes
-rw-r--r--resources/icons/Slic3r-gcodeviewer_128px.pngbin0 -> 8999 bytes
-rw-r--r--resources/icons/Slic3r-gcodeviewer_192px.pngbin0 -> 13322 bytes
-rw-r--r--resources/icons/Slic3r-gcodeviewer_32px.pngbin0 -> 1942 bytes
-rw-r--r--resources/ui_layout/extruder.ui2
-rw-r--r--resources/ui_layout/filament.ui5
-rw-r--r--resources/ui_layout/print.ui2
-rw-r--r--resources/ui_layout/printer_fff.ui6
-rw-r--r--src/PrusaSlicer.cpp4
-rw-r--r--src/libslic3r/AppConfig.cpp3
-rw-r--r--src/libslic3r/AppConfig.hpp2
-rw-r--r--src/libslic3r/Arrange.cpp6
-rw-r--r--src/libslic3r/BoundingBox.cpp6
-rw-r--r--src/libslic3r/BoundingBox.hpp2
-rw-r--r--src/libslic3r/ClipperUtils.cpp2
-rw-r--r--src/libslic3r/Config.cpp133
-rw-r--r--src/libslic3r/Config.hpp104
-rw-r--r--src/libslic3r/EdgeGrid.cpp22
-rw-r--r--src/libslic3r/EdgeGrid.hpp12
-rw-r--r--src/libslic3r/ElephantFootCompensation.cpp14
-rw-r--r--src/libslic3r/ExPolygon.hpp22
-rw-r--r--src/libslic3r/Extruder.cpp4
-rw-r--r--src/libslic3r/ExtrusionEntity.hpp2
-rw-r--r--src/libslic3r/Fill/FillAdaptive.cpp8
-rw-r--r--src/libslic3r/Fill/FillBase.cpp8
-rw-r--r--src/libslic3r/Fill/FillConcentric.cpp4
-rw-r--r--src/libslic3r/Fill/FillGyroid.cpp2
-rw-r--r--src/libslic3r/Fill/FillLine.cpp2
-rw-r--r--src/libslic3r/Fill/FillRectilinear.cpp30
-rw-r--r--src/libslic3r/Flow.cpp2
-rw-r--r--src/libslic3r/Format/3mf.cpp33
-rw-r--r--src/libslic3r/GCode.cpp536
-rw-r--r--src/libslic3r/GCode.hpp7
-rw-r--r--src/libslic3r/GCode/AvoidCrossingPerimeters.cpp2
-rw-r--r--src/libslic3r/GCode/CoolingBuffer.cpp64
-rw-r--r--src/libslic3r/GCode/GCodeProcessor.cpp136
-rw-r--r--src/libslic3r/GCode/GCodeProcessor.hpp2
-rw-r--r--src/libslic3r/GCodeReader.hpp8
-rw-r--r--src/libslic3r/GCodeWriter.cpp2
-rw-r--r--src/libslic3r/MedialAxis.cpp85
-rw-r--r--src/libslic3r/MedialAxis.hpp2
-rw-r--r--src/libslic3r/Milling/MillingPostProcess.cpp19
-rw-r--r--src/libslic3r/PlaceholderParser.cpp142
-rw-r--r--src/libslic3r/Polyline.hpp6
-rw-r--r--src/libslic3r/Preset.cpp10
-rw-r--r--src/libslic3r/Print.cpp308
-rw-r--r--src/libslic3r/Print.hpp29
-rw-r--r--src/libslic3r/PrintBase.cpp50
-rw-r--r--src/libslic3r/PrintBase.hpp17
-rw-r--r--src/libslic3r/PrintConfig.cpp465
-rw-r--r--src/libslic3r/PrintConfig.hpp15
-rw-r--r--src/libslic3r/PrintObject.cpp109
-rw-r--r--src/libslic3r/PrintRegion.cpp6
-rw-r--r--src/libslic3r/Slicing.cpp23
-rw-r--r--src/libslic3r/Slicing.hpp2
-rw-r--r--src/libslic3r/SupportMaterial.cpp2
-rw-r--r--src/libslic3r/libslic3r.h19
-rw-r--r--src/slic3r/GUI/3DBed.cpp8
-rw-r--r--src/slic3r/GUI/CalibrationAbstractDialog.cpp1
-rw-r--r--src/slic3r/GUI/ConfigManipulation.cpp3
-rw-r--r--src/slic3r/GUI/GLCanvas3D.cpp63
-rw-r--r--src/slic3r/GUI/GLCanvas3D.hpp8
-rw-r--r--src/slic3r/GUI/GUI_Preview.cpp20
-rw-r--r--src/slic3r/GUI/GUI_Preview.hpp1
-rw-r--r--src/slic3r/GUI/MainFrame.cpp6
-rw-r--r--src/slic3r/GUI/Plater.cpp47
-rw-r--r--src/slic3r/GUI/Preferences.cpp204
-rw-r--r--src/slic3r/GUI/Preferences.hpp1
-rw-r--r--src/slic3r/GUI/PresetHints.cpp39
-rw-r--r--src/slic3r/GUI/Tab.cpp15
70 files changed, 1944 insertions, 980 deletions
diff --git a/resources/icons/Slic3r-gcodeviewer.ico b/resources/icons/Slic3r-gcodeviewer.ico
new file mode 100644
index 000000000..7183c99a6
--- /dev/null
+++ b/resources/icons/Slic3r-gcodeviewer.ico
Binary files differ
diff --git a/resources/icons/Slic3r-gcodeviewer_128px.png b/resources/icons/Slic3r-gcodeviewer_128px.png
new file mode 100644
index 000000000..da39950bf
--- /dev/null
+++ b/resources/icons/Slic3r-gcodeviewer_128px.png
Binary files differ
diff --git a/resources/icons/Slic3r-gcodeviewer_192px.png b/resources/icons/Slic3r-gcodeviewer_192px.png
new file mode 100644
index 000000000..4991c74c0
--- /dev/null
+++ b/resources/icons/Slic3r-gcodeviewer_192px.png
Binary files differ
diff --git a/resources/icons/Slic3r-gcodeviewer_32px.png b/resources/icons/Slic3r-gcodeviewer_32px.png
new file mode 100644
index 000000000..730281354
--- /dev/null
+++ b/resources/icons/Slic3r-gcodeviewer_32px.png
Binary files differ
diff --git a/resources/ui_layout/extruder.ui b/resources/ui_layout/extruder.ui
index 458b92150..f3dee38f7 100644
--- a/resources/ui_layout/extruder.ui
+++ b/resources/ui_layout/extruder.ui
@@ -29,7 +29,9 @@ group:Retraction
setting:idx:retract_restart_extra
setting:idx:retract_before_travel
setting:idx:retract_layer_change
+group:Retraction wipe
setting:idx:wipe
+ setting:idx:wipe_speed
setting:idx:retract_before_wipe
setting:idx:wipe_extra_perimeter
group:Retraction when tool is disabled (advanced settings for multi-extruder setups)
diff --git a/resources/ui_layout/filament.ui b/resources/ui_layout/filament.ui
index acc8a3cbc..38ada3066 100644
--- a/resources/ui_layout/filament.ui
+++ b/resources/ui_layout/filament.ui
@@ -30,7 +30,10 @@ page:Cooling:time
group:Fan speed - default
setting:label$Run the fan at default speed when possible:fan_always_on
setting:min_fan_speed
- setting:bridge_fan_speed
+ line:Bridges fan speed
+ setting:label$:bridge_fan_speed
+ setting:label$Infill bridges:bridge_internal_fan_speed
+ end_line
setting:top_fan_speed
setting:external_perimeter_fan_speed
line:Disable fan for the first
diff --git a/resources/ui_layout/print.ui b/resources/ui_layout/print.ui
index 981f69aad..6a7107bfc 100644
--- a/resources/ui_layout/print.ui
+++ b/resources/ui_layout/print.ui
@@ -106,6 +106,7 @@ group:Modifying slices
line:Convert round vertical holes to polyholes
setting:label$_:hole_to_polyhole
setting:hole_to_polyhole_threshold
+ setting:hole_to_polyhole_twisted
end_line
group:Other
setting:clip_multipart_objects
@@ -257,6 +258,7 @@ group:Speed for non-print moves
end_line
group:sidetext_width$7:Modifiers
line:First layer speed
+ setting:label_width$8:width$4:first_layer_min_speed
setting:label_width$8:width$4:first_layer_speed
setting:label_width$8:width$4:first_layer_infill_speed
end_line
diff --git a/resources/ui_layout/printer_fff.ui b/resources/ui_layout/printer_fff.ui
index c5d4cd6d2..4cba9879d 100644
--- a/resources/ui_layout/printer_fff.ui
+++ b/resources/ui_layout/printer_fff.ui
@@ -19,6 +19,11 @@ group:silent_mode_event:Firmware
setting:gcode_precision_xyz
setting:gcode_precision_e
end_line
+ line:Processing limit
+ setting:max_gcode_per_second
+ setting:min_length
+ end_line
+ setting:gcode_filename_illegal_char
group:Cooling fan
line:Speedup
setting:label$Speedup time:fan_speedup_time
@@ -40,7 +45,6 @@ group:Advanced
setting:use_relative_e_distances
setting:use_firmware_retraction
setting:use_volumetric_e
- setting:min_length
setting:variable_layer_height
page:Custom G-code:cog
diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp
index 24ba4a1b2..a02876484 100644
--- a/src/PrusaSlicer.cpp
+++ b/src/PrusaSlicer.cpp
@@ -471,8 +471,8 @@ int CLI::run(int argc, char **argv)
sla_print.set_status_callback(
[](const PrintBase::SlicingStatus& s)
{
- if(s.percent >= 0) // FIXME: is this sufficient?
- printf("%3d%s %s\n", s.percent, "% =>", s.text.c_str());
+ if(s.percent >= 0 && s.args.empty()) // FIXME: is this sufficient?
+ printf("%3d%s %s\n", s.percent, "% =>", s.main_text.c_str());
});
PrintBase *print = (printer_technology == ptFFF) ? static_cast<PrintBase*>(&fff_print) : static_cast<PrintBase*>(&sla_print);
diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp
index 3824fb749..bd01b0892 100644
--- a/src/libslic3r/AppConfig.cpp
+++ b/src/libslic3r/AppConfig.cpp
@@ -69,6 +69,9 @@ void AppConfig::set_defaults()
if (get("freecad_path").empty())
set("freecad_path", ".");
+ if (get("show_overwrite_dialog").empty())
+ set("show_overwrite_dialog", "1");
+
if (get("tab_icon_size").empty())
set("tab_icon_size", "32");
diff --git a/src/libslic3r/AppConfig.hpp b/src/libslic3r/AppConfig.hpp
index 0a53a5330..c3f68abad 100644
--- a/src/libslic3r/AppConfig.hpp
+++ b/src/libslic3r/AppConfig.hpp
@@ -123,6 +123,8 @@ public:
std::string get_last_output_dir(const std::string& alt, const bool removable = false) const;
void update_last_output_dir(const std::string &dir, const bool removable = false);
+ bool get_show_overwrite_dialog() const { return get("show_overwrite_dialog") != "0"; }
+
// reset the current print / filament / printer selections, so that
// the PresetBundle::load_selections(const AppConfig &config) call will select
// the first non-default preset when called.
diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp
index 3800d49e3..46722d1d6 100644
--- a/src/libslic3r/Arrange.cpp
+++ b/src/libslic3r/Arrange.cpp
@@ -528,10 +528,10 @@ inline coord_t width(const BoundingBox& box) { return box.max.x() - box.min.x();
inline coord_t height(const BoundingBox& box) { return box.max.y() - box.min.y(); }
inline double area(const BoundingBox& box) { return double(width(box)) * height(box); }
inline double poly_area(const Points &pts) { return std::abs(Polygon::area(pts)); }
-inline double distance_to(const Point& p1, const Point& p2)
+inline coordf_t distance_to(const Point& p1, const Point& p2)
{
- double dx = p2.x() - p1.x();
- double dy = p2.y() - p1.y();
+ coordf_t dx = coordf_t(p2.x() - p1.x());
+ coordf_t dy = coordf_t(p2.y() - p1.y());
return std::sqrt(dx*dx + dy*dy);
}
diff --git a/src/libslic3r/BoundingBox.cpp b/src/libslic3r/BoundingBox.cpp
index eb4e042a0..de02ac18b 100644
--- a/src/libslic3r/BoundingBox.cpp
+++ b/src/libslic3r/BoundingBox.cpp
@@ -161,11 +161,11 @@ BoundingBox3Base<PointClass>::size() const
template Vec3f BoundingBox3Base<Vec3f>::size() const;
template Vec3d BoundingBox3Base<Vec3d>::size() const;
-template <class PointClass> double BoundingBoxBase<PointClass>::radius() const
+template <class PointClass> coordf_t BoundingBoxBase<PointClass>::radius() const
{
assert(this->defined);
- double x = this->max(0) - this->min(0);
- double y = this->max(1) - this->min(1);
+ coordf_t x = coordf_t(this->max(0) - this->min(0));
+ coordf_t y = coordf_t(this->max(1) - this->min(1));
return 0.5 * sqrt(x*x+y*y);
}
template double BoundingBoxBase<Point>::radius() const;
diff --git a/src/libslic3r/BoundingBox.hpp b/src/libslic3r/BoundingBox.hpp
index 8de28af5c..5262c48d3 100644
--- a/src/libslic3r/BoundingBox.hpp
+++ b/src/libslic3r/BoundingBox.hpp
@@ -43,7 +43,7 @@ public:
void merge(const BoundingBoxBase<PointClass> &bb);
void scale(double factor);
PointClass size() const;
- double radius() const;
+ coordf_t radius() const;
void translate(coordf_t x, coordf_t y) { assert(this->defined); PointClass v(x, y); this->min += v; this->max += v; }
void translate(const Vec2d &v) { this->min += v; this->max += v; }
void offset(coordf_t delta);
diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp
index 0528c137a..45bb08599 100644
--- a/src/libslic3r/ClipperUtils.cpp
+++ b/src/libslic3r/ClipperUtils.cpp
@@ -1230,7 +1230,7 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false));
//tiny holes can be reduced to giberish, get rid of them.
for (auto it = holes.begin(); it != holes.end();)
- if (ClipperLib::Area(*it) < CLIPPER_OFFSET_SCALE*CLIPPER_OFFSET_SCALE) {
+ if (ClipperLib::Area(*it) < double(CLIPPER_OFFSET_SCALE) * double(CLIPPER_OFFSET_SCALE)) {
it = holes.erase(it);
}
else ++it;
diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp
index 24f2a44af..8964d73b0 100644
--- a/src/libslic3r/Config.cpp
+++ b/src/libslic3r/Config.cpp
@@ -657,12 +657,15 @@ bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, con
opt->set_phony(false);
else
opt->set_phony(false);
+
+ if (optdef->is_vector_extruder)
+ static_cast<ConfigOptionVectorBase*>(opt)->set_is_extruder_size(true);
return success;
}
// Return an absolute value of a possibly relative config variable.
// For example, return absolute infill extrusion width, either from an absolute value, or relative to the layer height.
-double ConfigBase::get_abs_value(const t_config_option_key &opt_key) const
+double ConfigBase::get_computed_value(const t_config_option_key &opt_key, int extruder_id) const
{
// Get stored option value.
const ConfigOption *raw_opt = this->option(opt_key);
@@ -670,52 +673,92 @@ double ConfigBase::get_abs_value(const t_config_option_key &opt_key) const
std::stringstream ss; ss << "You can't define an option that need " << opt_key << " without defining it!";
throw std::runtime_error(ss.str());
}
- if (raw_opt->type() == coFloat)
- return static_cast<const ConfigOptionFloat*>(raw_opt)->value;
- if (raw_opt->type() == coInt)
- return static_cast<const ConfigOptionInt*>(raw_opt)->value;
- if (raw_opt->type() == coBool)
- return static_cast<const ConfigOptionBool*>(raw_opt)->value?1:0;
- const ConfigOptionDef* opt_def = nullptr;
- const ConfigOptionPercent* cast_opt = nullptr;
- if (raw_opt->type() == coFloatOrPercent) {
- if(!static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->percent)
- return static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->value;
- // Get option definition.
- const ConfigDef *def = this->def();
- if (def == nullptr)
- throw NoDefinitionException(opt_key);
- opt_def = def->get(opt_key);
- cast_opt = static_cast<const ConfigOptionFloatOrPercent*>(raw_opt);
- assert(opt_def != nullptr);
- }
- if (raw_opt->type() == coPercent) {
- // Get option definition.
- const ConfigDef* def = this->def();
- if (def == nullptr)
- throw NoDefinitionException(opt_key);
- opt_def = def->get(opt_key);
- assert(opt_def != nullptr);
- cast_opt = static_cast<const ConfigOptionPercent*>(raw_opt);
- }
- if (opt_def != nullptr) {
- //if over no other key, it's most probably a simple %
- if (opt_def->ratio_over == "")
- return cast_opt->get_abs_value(1);
- if (opt_def->ratio_over == "nozzle_diameter") {
- //use the first... i guess.
- //TODO: find a better way, like a "current_extruder_idx" config option.
- if (this->option(opt_def->ratio_over) == nullptr) {
- std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " need nozzle_diameter but can't acess it. Please use get_abs_value(nozzle_diam).";
- throw std::runtime_error(ss.str());
+
+ if (!raw_opt->is_vector()) {
+ if (raw_opt->type() == coFloat)
+ return static_cast<const ConfigOptionFloat*>(raw_opt)->value;
+ if (raw_opt->type() == coInt)
+ return static_cast<const ConfigOptionInt*>(raw_opt)->value;
+ if (raw_opt->type() == coBool)
+ return static_cast<const ConfigOptionBool*>(raw_opt)->value ? 1 : 0;
+ const ConfigOptionDef* opt_def = nullptr;
+ const ConfigOptionPercent* cast_opt = nullptr;
+ if (raw_opt->type() == coFloatOrPercent) {
+ if (!static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->percent)
+ return static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->value;
+ // Get option definition.
+ const ConfigDef* def = this->def();
+ if (def == nullptr)
+ throw NoDefinitionException(opt_key);
+ opt_def = def->get(opt_key);
+ cast_opt = static_cast<const ConfigOptionFloatOrPercent*>(raw_opt);
+ assert(opt_def != nullptr);
+ }
+ if (raw_opt->type() == coPercent) {
+ // Get option definition.
+ const ConfigDef* def = this->def();
+ if (def == nullptr)
+ throw NoDefinitionException(opt_key);
+ opt_def = def->get(opt_key);
+ assert(opt_def != nullptr);
+ cast_opt = static_cast<const ConfigOptionPercent*>(raw_opt);
+ }
+ if (opt_def != nullptr) {
+ //if over no other key, it's most probably a simple %
+ if (opt_def->ratio_over == "")
+ return cast_opt->get_abs_value(1);
+ // Compute absolute value over the absolute value of the base option.
+ //FIXME there are some ratio_over chains, which end with empty ratio_with.
+ // For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly.
+ if (!opt_def->ratio_over.empty() && opt_def->ratio_over != "depends")
+ return cast_opt->get_abs_value(this->get_computed_value(opt_def->ratio_over));
+
+ std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " has no valid ratio_over to compute of";
+ throw ConfigurationError(ss.str());
+ }
+ } else {
+ // check if it's an extruder_id array
+ const ConfigOptionVectorBase* vector_opt = static_cast<const ConfigOptionVectorBase*>(raw_opt);
+ if (vector_opt->is_extruder_size()) {
+ if (extruder_id < 0) {
+ const ConfigOption* opt_extruder_id = nullptr;
+ if ((opt_extruder_id = this->option("extruder")) == nullptr)
+ if ((opt_extruder_id = this->option("current_extruder")) == nullptr
+ || opt_extruder_id->getInt() < 0 || opt_extruder_id->getInt() >= vector_opt->size()) {
+ std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " need to has the extuder id to get the right value, but it's not available";
+ throw ConfigurationError(ss.str());
+ }
+ extruder_id = opt_extruder_id->getInt();
+ }
+
+ if (raw_opt->type() == coFloats || raw_opt->type() == coInts || raw_opt->type() == coBools)
+ return vector_opt->getFloat(extruder_id);
+ if (raw_opt->type() == coFloatsOrPercents) {
+ const ConfigOptionFloatsOrPercents* opt_fl_per = static_cast<const ConfigOptionFloatsOrPercents*>(raw_opt);
+ if (!opt_fl_per->values[extruder_id].percent)
+ return opt_fl_per->values[extruder_id].value;
+
+ const ConfigDef* def = this->def();
+ if (def == nullptr)
+ throw NoDefinitionException(opt_key);
+ const ConfigOptionDef* opt_def = def->get(opt_key);
+ if (!opt_def->ratio_over.empty() && opt_def->ratio_over != "depends")
+ return opt_fl_per->get_abs_value(extruder_id, this->get_computed_value(opt_def->ratio_over, extruder_id));
+ std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " has no valid ratio_over to compute of";
+ throw ConfigurationError(ss.str());
+ }
+ if (raw_opt->type() == coPercents) {
+ const ConfigOptionPercents* opt_per = static_cast<const ConfigOptionPercents*>(raw_opt);
+ const ConfigDef* def = this->def();
+ if (def == nullptr)
+ throw NoDefinitionException(opt_key);
+ const ConfigOptionDef* opt_def = def->get(opt_key);
+ if (!opt_def->ratio_over.empty() && opt_def->ratio_over != "depends")
+ return opt_per->get_abs_value(extruder_id, this->get_computed_value(opt_def->ratio_over, extruder_id));
+ std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " has no valid ratio_over to compute of";
+ throw ConfigurationError(ss.str());
}
- return cast_opt->get_abs_value(static_cast<const ConfigOptionFloats*>(this->option(opt_def->ratio_over))->values[0]);
}
- // Compute absolute value over the absolute value of the base option.
- //FIXME there are some ratio_over chains, which end with empty ratio_with.
- // For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly.
- return opt_def->ratio_over.empty() ? 0. :
- cast_opt->get_abs_value(this->get_abs_value(opt_def->ratio_over));
}
std::stringstream ss; ss << "ConfigBase::get_abs_value(): "<< opt_key<<" has not a valid option type for get_abs_value()";
throw ConfigurationError(ss.str());
diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp
index 736b24400..e257b4ade 100644
--- a/src/libslic3r/Config.hpp
+++ b/src/libslic3r/Config.hpp
@@ -296,16 +296,20 @@ struct ConfigSubstitutionContext
ConfigSubstitutions substitutions;
};
+
// A generic value of a configuration option.
class ConfigOption {
public:
// if true, this option doesn't need to be saved, it's a computed value from an other configOption.
// uint32_t because macos crash if it's a bool. and it doesn't change the size of the object because of alignment.
- uint32_t phony;
-
+ uint32_t flags;
+ enum FlagsConfigOption : uint8_t {
+ FCO_PHONY = 1,
+ FCO_EXTRUDER_ARRAY = 1 << 1,
+ };
- ConfigOption() : phony(false) {}
- ConfigOption(bool phony) : phony(uint32_t(phony)) {}
+ ConfigOption() : flags(false) {}
+ ConfigOption(bool phony) : flags(uint32_t(FlagsConfigOption::FCO_PHONY)) {}
virtual ~ConfigOption() {}
@@ -327,8 +331,8 @@ public:
virtual bool nullable() const { return false; }
// A scalar is nil, or all values of a vector are nil.
virtual bool is_nil() const { return false; }
- bool is_phony() const { return phony != 0; }
- void set_phony(bool phony) { this->phony = phony ? 1 : 0; }
+ bool is_phony() const { return (flags & FCO_PHONY) != 0; }
+ void set_phony(bool phony) { if (phony) this->flags |= FCO_PHONY; else this->flags &= uint8_t(0xFF ^ FCO_PHONY); }
// Is this option overridden by another option?
// An option overrides another option if it is not nil and not equal.
virtual bool overriden_by(const ConfigOption *rhs) const {
@@ -344,7 +348,7 @@ public:
}
private:
friend class cereal::access;
- template<class Archive> void serialize(Archive& ar) { ar(this->phony); }
+ template<class Archive> void serialize(Archive& ar) { ar(this->flags); }
};
typedef ConfigOption* ConfigOptionPtr;
@@ -365,7 +369,7 @@ public:
throw ConfigurationError("ConfigOptionSingle: Assigning an incompatible type");
assert(dynamic_cast<const ConfigOptionSingle<T>*>(rhs));
this->value = static_cast<const ConfigOptionSingle<T>*>(rhs)->value;
- this->phony = rhs->phony;
+ this->flags = rhs->flags;
}
bool operator==(const ConfigOption &rhs) const override
@@ -381,7 +385,7 @@ public:
private:
friend class cereal::access;
- template<class Archive> void serialize(Archive & ar) { ar(this->phony); ar(this->value); }
+ template<class Archive> void serialize(Archive & ar) { ar(this->flags); ar(this->value); }
};
// Value of a vector valued option (bools, ints, floats, strings, points)
@@ -408,6 +412,11 @@ public:
virtual bool empty() const = 0;
// Is the value nil? That should only be possible if this->nullable().
virtual bool is_nil(size_t idx) const = 0;
+ // Get if the size of this vector is/should be the same as nozzle_diameter
+ bool is_extruder_size() const { return (flags & FCO_EXTRUDER_ARRAY) != 0; }
+ void set_is_extruder_size(bool is_extruder_size) {
+ if (is_extruder_size) this->flags |= FCO_EXTRUDER_ARRAY; else this->flags &= uint8_t(0xFF ^ FCO_EXTRUDER_ARRAY); }
+ virtual double getFloat(int idx) const { throw BadOptionTypeException("Calling ConfigOption::getFloat(idx) on a non-numeric arrray ConfigOptionVectorBase"); }
// We just overloaded and hid two base class virtual methods.
// Let's show it was intentional (warnings).
@@ -440,7 +449,7 @@ public:
throw ConfigurationError("ConfigOptionVector: Assigning an incompatible type");
assert(dynamic_cast<const ConfigOptionVector<T>*>(rhs));
this->values = static_cast<const ConfigOptionVector<T>*>(rhs)->values;
- this->phony = rhs->phony;
+ this->flags = rhs->flags;
}
// Set from a vector of ConfigOptions.
@@ -597,7 +606,7 @@ public:
private:
friend class cereal::access;
- template<class Archive> void serialize(Archive & ar) { ar(this->phony); ar(this->values); }
+ template<class Archive> void serialize(Archive & ar) { ar(this->flags); ar(this->values); }
};
class ConfigOptionFloat : public ConfigOptionSingle<double>
@@ -667,6 +676,7 @@ public:
// A scalar is nil, or all values of a vector are nil.
bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v)) return false; return true; }
bool is_nil(size_t idx) const override { return std::isnan(this->values[idx]); }
+ virtual double getFloat(int idx) const override { return values[idx]; }
std::string serialize() const override
{
@@ -813,6 +823,7 @@ public:
// A scalar is nil, or all values of a vector are nil.
bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; }
bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); }
+ virtual double getFloat(int idx) const override { return values[idx]; }
std::string serialize() const override
{
@@ -1142,6 +1153,12 @@ public:
// A scalar is nil, or all values of a vector are nil.
bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v.value)) return false; return true; }
bool is_nil(size_t idx) const override { return std::isnan(this->values[idx].value); }
+ double get_abs_value(size_t i, double ratio_over) const {
+ if (this->is_nil(i)) return 0;
+ const FloatOrPercent& data = this->get_at(i);
+ if (data.percent) return ratio_over * data.value / 100;
+ return data.value;
+ }
std::string serialize() const override
{
@@ -1436,6 +1453,7 @@ public:
// A scalar is nil, or all values of a vector are nil.
bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; }
bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); }
+ virtual double getFloat(int idx) const override { return values[idx]?1:0; }
bool& get_at(size_t i) {
assert(! this->values.empty());
@@ -1553,7 +1571,7 @@ public:
throw ConfigurationError("ConfigOptionEnum<T>: Assigning an incompatible type");
// rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
this->value = (T)rhs->getInt();
- this->phony = rhs->phony;
+ this->flags = rhs->flags;
}
std::string serialize() const override
@@ -1639,7 +1657,7 @@ public:
throw ConfigurationError("ConfigOptionEnumGeneric: Assigning an incompatible type");
// rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
this->value = rhs->getInt();
- this->phony = rhs->phony;
+ this->flags = rhs->flags;
}
std::string serialize() const override
@@ -1677,7 +1695,13 @@ public:
bool nullable = false;
// Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor.
Slic3r::clonable_ptr<const ConfigOption> default_value;
- void set_default_value(const ConfigOption* ptr) { this->default_value = Slic3r::clonable_ptr<const ConfigOption>(ptr); }
+ void set_default_value(const ConfigOption* ptr) {
+ this->default_value = Slic3r::clonable_ptr<const ConfigOption>(ptr);
+ }
+ void set_default_value(ConfigOptionVectorBase* ptr) {
+ ptr->set_is_extruder_size(this->is_vector_extruder);
+ this->default_value = Slic3r::clonable_ptr<const ConfigOption>(ptr);
+ }
template<typename T> const T* get_default_value() const { return static_cast<const T*>(this->default_value.get()); }
// Create an empty option to be used as a base for deserialization of DynamicConfig.
@@ -1686,34 +1710,40 @@ public:
ConfigOption* create_default_option() const;
template<class Archive> ConfigOption* load_option_from_archive(Archive &archive) const {
- if (this->nullable) {
+ ConfigOption* opt;
+ ConfigOptionVectorBase* opt_vec = nullptr;
+ if (this->nullable) {
switch (this->type) {
- case coFloats: { auto opt = new ConfigOptionFloatsNullable(); archive(*opt); return opt; }
- case coInts: { auto opt = new ConfigOptionIntsNullable(); archive(*opt); return opt; }
- case coPercents: { auto opt = new ConfigOptionPercentsNullable();archive(*opt); return opt; }
- case coBools: { auto opt = new ConfigOptionBoolsNullable(); archive(*opt); return opt; }
+ case coFloats: { opt = opt_vec = new ConfigOptionFloatsNullable(); break; }
+ case coInts: { opt = opt_vec = new ConfigOptionIntsNullable(); break; }
+ case coPercents: { opt = opt_vec = new ConfigOptionPercentsNullable(); break; }
+ case coBools: { opt = opt_vec = new ConfigOptionBoolsNullable(); break; }
default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key);
}
} else {
switch (this->type) {
- case coFloat: { auto opt = new ConfigOptionFloat(); archive(*opt); return opt; }
- case coFloats: { auto opt = new ConfigOptionFloats(); archive(*opt); return opt; }
- case coInt: { auto opt = new ConfigOptionInt(); archive(*opt); return opt; }
- case coInts: { auto opt = new ConfigOptionInts(); archive(*opt); return opt; }
- case coString: { auto opt = new ConfigOptionString(); archive(*opt); return opt; }
- case coStrings: { auto opt = new ConfigOptionStrings(); archive(*opt); return opt; }
- case coPercent: { auto opt = new ConfigOptionPercent(); archive(*opt); return opt; }
- case coPercents: { auto opt = new ConfigOptionPercents(); archive(*opt); return opt; }
- case coFloatOrPercent: { auto opt = new ConfigOptionFloatOrPercent(); archive(*opt); return opt; }
- case coPoint: { auto opt = new ConfigOptionPoint(); archive(*opt); return opt; }
- case coPoints: { auto opt = new ConfigOptionPoints(); archive(*opt); return opt; }
- case coPoint3: { auto opt = new ConfigOptionPoint3(); archive(*opt); return opt; }
- case coBool: { auto opt = new ConfigOptionBool(); archive(*opt); return opt; }
- case coBools: { auto opt = new ConfigOptionBools(); archive(*opt); return opt; }
- case coEnum: { auto opt = new ConfigOptionEnumGeneric(this->enum_keys_map); archive(*opt); return opt; }
+ case coFloat: { opt = new ConfigOptionFloat(); break;}
+ case coFloats: { opt = opt_vec = new ConfigOptionFloats(); break; }
+ case coInt: { opt = new ConfigOptionInt(); break; }
+ case coInts: { opt = opt_vec = new ConfigOptionInts(); break; }
+ case coString: { opt = new ConfigOptionString(); break; }
+ case coStrings: { opt = opt_vec = new ConfigOptionStrings(); break; }
+ case coPercent: { opt = new ConfigOptionPercent(); break; }
+ case coPercents: { opt = opt_vec = new ConfigOptionPercents(); break; }
+ case coFloatOrPercent: { opt = new ConfigOptionFloatOrPercent(); break; }
+ case coPoint: { opt = new ConfigOptionPoint(); break; }
+ case coPoints: { opt = opt_vec = new ConfigOptionPoints(); break; }
+ case coPoint3: { opt = new ConfigOptionPoint3(); break; }
+ case coBool: { opt = new ConfigOptionBool(); break; }
+ case coBools: { opt = opt_vec = new ConfigOptionBools(); break; }
+ case coEnum: { opt = new ConfigOptionEnumGeneric(this->enum_keys_map); break; }
default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key);
}
}
+ if (opt_vec != nullptr)
+ opt_vec->set_is_extruder_size (this->is_vector_extruder);
+ archive(*opt);
+ return opt;
}
template<class Archive> ConfigOption* save_option_to_archive(Archive &archive, const ConfigOption *opt) const {
@@ -1785,7 +1815,9 @@ public:
// For text input: If true, the GUI text box spans the complete page width.
bool full_width = false;
// For text input: If true, the GUI formats text as code (fixed-width)
- bool is_code = false;
+ bool is_code = false;
+ // For array settign: If true, It has the same size as the number of extruders.
+ bool is_vector_extruder = false;
// Not editable. Currently only used for the display of the number of threads.
bool readonly = false;
// Can be phony. if not present at laoding, mark it as phony. Also adapt the gui to look for phony status.
@@ -2045,7 +2077,7 @@ public:
void set_deserialize_strict(std::initializer_list<SetDeserializeItem> items)
{ ConfigSubstitutionContext ctxt{ ForwardCompatibilitySubstitutionRule::Disable }; this->set_deserialize(items, ctxt); }
- double get_abs_value(const t_config_option_key &opt_key) const;
+ double get_computed_value(const t_config_option_key &opt_key, int extruder_id = -1) const;
double get_abs_value(const t_config_option_key &opt_key, double ratio_over) const;
void setenv_() const;
ConfigSubstitutions load(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule);
diff --git a/src/libslic3r/EdgeGrid.cpp b/src/libslic3r/EdgeGrid.cpp
index 2e1453736..d75acdfca 100644
--- a/src/libslic3r/EdgeGrid.cpp
+++ b/src/libslic3r/EdgeGrid.cpp
@@ -1213,8 +1213,8 @@ bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radiu
// Signum of the distance field at pt.
int sign_min = 0;
bool on_segment = false;
- for (int r = bbox.min(1); r <= bbox.max(1); ++ r) {
- for (int c = bbox.min(0); c <= bbox.max(0); ++ c) {
+ for (coord_t r = bbox.min(1); r <= bbox.max(1); ++ r) {
+ for (coord_t c = bbox.min(0); c <= bbox.max(0); ++ c) {
const Cell &cell = m_cells[r * m_cols + c];
for (size_t i = cell.begin; i < cell.end; ++ i) {
const Slic3r::Points &pts = *m_contours[m_cell_data[i].first];
@@ -1301,7 +1301,7 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset, bool fill_holes) co
std::vector<char> cell_inside2(cell_inside);
for (int r = 1; r + 1 < int(cell_rows); ++ r) {
for (int c = 1; c + 1 < int(cell_cols); ++ c) {
- int addr = r * cell_cols + c;
+ int addr = r * int(cell_cols) + c;
if ((cell_inside2[addr - 1] && cell_inside2[addr + 1]) ||
(cell_inside2[addr - cell_cols] && cell_inside2[addr + cell_cols]))
cell_inside[addr] = true;
@@ -1483,8 +1483,8 @@ bool EdgeGrid::Grid::has_intersecting_edges() const
void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path, size_t scale)
{
- unsigned int w = (bbox.max(0) - bbox.min(0) + resolution - 1) / resolution;
- unsigned int h = (bbox.max(1) - bbox.min(1) + resolution - 1) / resolution;
+ uint32_t w = uint32_t((bbox.max(0) - bbox.min(0) + resolution - 1) / resolution);
+ uint32_t h = uint32_t((bbox.max(1) - bbox.min(1) + resolution - 1) / resolution);
std::vector<uint8_t> pixels(w * h * 3, 0);
@@ -1501,7 +1501,7 @@ void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coo
#else
if (grid.signed_distance(pt, search_radius, min_dist)) {
#endif
- float s = 255 * std::abs(min_dist) / float(display_blend_radius);
+ float s = float(255 * std::abs(min_dist)) / float(display_blend_radius);
int is = std::max(0, std::min(255, int(floor(s + 0.5f))));
if (min_dist < 0) {
if (on_segment) {
@@ -1548,7 +1548,7 @@ void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coo
}
}
- float dgrid = fabs(min_dist) / float(grid.resolution());
+ float dgrid = fabs(float(min_dist)) / float(grid.resolution());
float igrid = floor(dgrid + 0.5f);
dgrid = std::abs(dgrid - igrid) * float(grid.resolution()) / float(resolution);
if (dgrid < 1.f) {
@@ -1559,7 +1559,7 @@ void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coo
pxl[2] = (unsigned char)(t * pxl[2]);
if (igrid > 0.f) {
// Other than zero iso contour.
- int g = pxl[1] + 255.f * (1.f - t);
+ int g = int(pxl[1] + 255.f * (1.f - t));
pxl[1] = std::min(g, 255);
}
}
@@ -1572,7 +1572,7 @@ void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coo
// Find all pairs of intersectiong edges from the set of polygons.
std::vector<std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge>> intersecting_edges(const Polygons &polygons)
{
- double len = 0;
+ coordf_t len = 0;
size_t cnt = 0;
BoundingBox bbox;
for (const Polygon &poly : polygons) {
@@ -1592,7 +1592,7 @@ std::vector<std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge>>
bbox.offset(20);
EdgeGrid::Grid grid;
grid.set_bbox(bbox);
- grid.create(polygons, len);
+ grid.create(polygons, coord_t(len));
out = grid.intersecting_edges();
}
return out;
@@ -1612,7 +1612,7 @@ void export_intersections_to_svg(const std::string &filename, const Polygons &po
intersecting_contours.insert(ie.second.first);
}
// Highlight the contours with intersections.
- coord_t line_width = coord_t(scale_(0.01));
+ coord_t line_width = scale_t(0.01);
for (const Points *ic : intersecting_contours) {
svg.draw_outline(Polygon(*ic), "green");
svg.draw_outline(Polygon(*ic), "black", line_width);
diff --git a/src/libslic3r/EdgeGrid.hpp b/src/libslic3r/EdgeGrid.hpp
index c3bc869d4..3141b440f 100644
--- a/src/libslic3r/EdgeGrid.hpp
+++ b/src/libslic3r/EdgeGrid.hpp
@@ -88,10 +88,10 @@ public:
assert(m_bbox.contains(p2));
p1 -= m_bbox.min;
p2 -= m_bbox.min;
- assert(p1.x() >= 0 && p1.x() < m_cols * m_resolution);
- assert(p1.y() >= 0 && p1.y() < m_rows * m_resolution);
- assert(p2.x() >= 0 && p2.x() < m_cols * m_resolution);
- assert(p2.y() >= 0 && p2.y() < m_rows * m_resolution);
+ assert(p1.x() >= 0 && p1.x() < coord_t(m_cols) * m_resolution);
+ assert(p1.y() >= 0 && p1.y() < coord_t(m_rows) * m_resolution);
+ assert(p2.x() >= 0 && p2.x() < coord_t(m_cols) * m_resolution);
+ assert(p2.y() >= 0 && p2.y() < coord_t(m_rows) * m_resolution);
// Get the cells of the end points.
coord_t ix = p1(0) / m_resolution;
coord_t iy = p1(1) / m_resolution;
@@ -248,9 +248,9 @@ public:
std::pair<std::vector<std::pair<size_t, size_t>>::const_iterator, std::vector<std::pair<size_t, size_t>>::const_iterator> cell_data_range(coord_t row, coord_t col) const
{
assert(row >= 0);
- assert(row < m_rows);
+ assert(row < (coord_t)m_rows);
assert(col >= 0);
- assert(col < m_cols);
+ assert(col < (coord_t)m_cols);
const EdgeGrid::Grid::Cell &cell = m_cells[row * m_cols + col];
return std::make_pair(m_cell_data.begin() + cell.begin, m_cell_data.begin() + cell.end);
}
diff --git a/src/libslic3r/ElephantFootCompensation.cpp b/src/libslic3r/ElephantFootCompensation.cpp
index 83288929c..fac733c5b 100644
--- a/src/libslic3r/ElephantFootCompensation.cpp
+++ b/src/libslic3r/ElephantFootCompensation.cpp
@@ -536,14 +536,14 @@ static bool validate_expoly_orientation(const ExPolygon &expoly)
#endif /* NDEBUG */
ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, double min_contour_width, const double compensation)
-{
+{
assert(validate_expoly_orientation(input_expoly));
- double scaled_compensation = scale_(compensation);
- min_contour_width = scale_(min_contour_width);
- double min_contour_width_compensated = min_contour_width + 2. * scaled_compensation;
+ coordf_t scaled_compensation = scale_d(compensation);
+ coordf_t scaled_min_contour_width = scale_d(min_contour_width);
+ coordf_t min_contour_width_compensated = scaled_min_contour_width + 2. * scaled_compensation;
// Make the search radius a bit larger for the averaging in contour_distance over a fan of rays to work.
- double search_radius = min_contour_width_compensated + min_contour_width * 0.5;
+ coordf_t search_radius = min_contour_width_compensated + scaled_min_contour_width * 0.5;
BoundingBox bbox = get_extents(input_expoly.contour);
Point bbox_size = bbox.size();
@@ -578,12 +578,12 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, double min_c
for (float &d : dists) {
// printf("Point %d, Distance: %lf\n", int(&d - dists.data()), unscale<double>(d));
// Convert contour width to available compensation distance.
- if (d < min_contour_width)
+ if (d < scaled_min_contour_width)
d = 0.f;
else if (d > min_contour_width_compensated)
d = - float(scaled_compensation);
else
- d = - (d - float(min_contour_width)) / 2.f;
+ d = - (d - float(scaled_min_contour_width)) / 2.f;
assert(d >= - float(scaled_compensation) && d <= 0.f);
}
// smooth_compensation(dists, 0.4f, 10);
diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp
index fbb5ed75a..c827025f9 100644
--- a/src/libslic3r/ExPolygon.hpp
+++ b/src/libslic3r/ExPolygon.hpp
@@ -202,10 +202,10 @@ inline Polylines to_polylines(ExPolygon &&src)
Polyline &pl = polylines[idx ++];
pl.points = std::move(src.contour.points);
pl.points.push_back(pl.points.front());
- for (Polygons::const_iterator ith = src.holes.begin(); ith != src.holes.end(); ++ith) {
+ for (Polygon& ith : src.holes) {
Polyline &pl = polylines[idx ++];
- pl.points = std::move(ith->points);
- pl.points.push_back(ith->points.front());
+ pl.points = std::move(ith.points);
+ pl.points.push_back(pl.points.front());
}
assert(idx == polylines.size());
return polylines;
@@ -216,14 +216,14 @@ inline Polylines to_polylines(ExPolygons &&src)
Polylines polylines;
polylines.assign(number_polygons(src), Polyline());
size_t idx = 0;
- for (ExPolygons::const_iterator it = src.begin(); it != src.end(); ++it) {
+ for (ExPolygon& ex_poly : src) {
Polyline &pl = polylines[idx ++];
- pl.points = std::move(it->contour.points);
+ pl.points = std::move(ex_poly.contour.points);
pl.points.push_back(pl.points.front());
- for (Polygons::const_iterator ith = it->holes.begin(); ith != it->holes.end(); ++ith) {
+ for (Polygon& ith : ex_poly.holes) {
Polyline &pl = polylines[idx ++];
- pl.points = std::move(ith->points);
- pl.points.push_back(ith->points.front());
+ pl.points = std::move(ith.points);
+ pl.points.push_back(pl.points.front());
}
}
assert(idx == polylines.size());
@@ -243,9 +243,9 @@ inline Polygons to_polygons(const ExPolygons &src)
{
Polygons polygons;
polygons.reserve(number_polygons(src));
- for (ExPolygons::const_iterator it = src.begin(); it != src.end(); ++it) {
- polygons.push_back(it->contour);
- polygons.insert(polygons.end(), it->holes.begin(), it->holes.end());
+ for (const ExPolygon& ex_poly : src) {
+ polygons.push_back(ex_poly.contour);
+ polygons.insert(polygons.end(), ex_poly.holes.begin(), ex_poly.holes.end());
}
return polygons;
}
diff --git a/src/libslic3r/Extruder.cpp b/src/libslic3r/Extruder.cpp
index e9783a75d..d6c0fc49f 100644
--- a/src/libslic3r/Extruder.cpp
+++ b/src/libslic3r/Extruder.cpp
@@ -221,12 +221,12 @@ double Extruder::retract_restart_extra_toolchange() const
int16_t Extruder::temp_offset() const
{
- return m_config->extruder_temperature_offset.get_at(m_id);
+ return int16_t(m_config->extruder_temperature_offset.get_at(m_id));
}
int8_t Extruder::fan_offset() const
{
- return m_config->extruder_fan_offset.get_at(m_id);
+ return int8_t(m_config->extruder_fan_offset.get_at(m_id));
}
double Mill::retract_lift() const {
diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp
index c062456de..a675ae9e7 100644
--- a/src/libslic3r/ExtrusionEntity.hpp
+++ b/src/libslic3r/ExtrusionEntity.hpp
@@ -435,7 +435,7 @@ public:
ExtrusionLoop(ExtrusionPaths &&paths, ExtrusionLoopRole role = elrDefault) : paths(std::move(paths)), m_loop_role(role) { assert(this->first_point() == this->paths.back().polyline.points.back()); }
ExtrusionLoop(const ExtrusionPath &path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role)
{ this->paths.push_back(path); }
- ExtrusionLoop(const ExtrusionPath &&path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role)
+ ExtrusionLoop(ExtrusionPath &&path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role)
{ this->paths.emplace_back(std::move(path)); }
virtual bool is_loop() const override{ return true; }
virtual bool can_reverse() const override { return false; }
diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp
index 14515f511..fc49e9b88 100644
--- a/src/libslic3r/Fill/FillAdaptive.cpp
+++ b/src/libslic3r/Fill/FillAdaptive.cpp
@@ -638,11 +638,11 @@ static inline Intersection* get_nearest_intersection(std::vector<std::pair<Inter
// Create a line representing the anchor aka hook extrusion based on line_to_offset
// translated in the direction of the intersection line (intersection.intersect_line).
-static Line create_offset_line(Line offset_line, const Intersection &intersection, const double scaled_offset)
+static Line create_offset_line(Line offset_line, const Intersection &intersection, const coordf_t scaled_offset)
{
offset_line.translate((perp(intersection.closest_line->vector().cast<double>().normalized()) * (intersection.left ? scaled_offset : - scaled_offset)).cast<coord_t>());
// Extend the line by a small value to guarantee a collision with adjacent lines
- offset_line.extend(coord_t(scaled_offset * 1.16)); // / cos(PI/6)
+ offset_line.extend(coordf_t(coord_t(scaled_offset * 1.16))); // / cos(PI/6)
return offset_line;
}
@@ -1385,8 +1385,8 @@ void Filler::_fill_surface_single(
}
#endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */
- const auto hook_length = coordf_t(std::min<float>(std::numeric_limits<coord_t>::max(), scale_(params.anchor_length)));
- const auto hook_length_max = coordf_t(std::min<float>(std::numeric_limits<coord_t>::max(), scale_(params.anchor_length_max)));
+ const coordf_t hook_length = std::min<coordf_t>((coordf_t)std::numeric_limits<coord_t>::max(), scale_d(params.anchor_length));
+ const coordf_t hook_length_max = std::min<coordf_t>((coordf_t)std::numeric_limits<coord_t>::max(), scale_d(params.anchor_length_max));
Polylines all_polylines_with_hooks = all_polylines.size() > 1 ? connect_lines_using_hooks(std::move(all_polylines), expolygon, this->get_spacing(), hook_length, hook_length_max) : std::move(all_polylines);
diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp
index d028e4510..619b41629 100644
--- a/src/libslic3r/Fill/FillBase.cpp
+++ b/src/libslic3r/Fill/FillBase.cpp
@@ -243,8 +243,8 @@ Fill::do_gap_fill(const ExPolygons& gapfill_areas, const FillParams& params, Ext
// offset2_ex(gapfill_areas, double(-max / 2), double(+max / 2)),
// true);
ExPolygons gapfill_areas_collapsed = offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2));
- double minarea = params.flow.scaled_width() * params.flow.scaled_width();
- if (params.config != nullptr) minarea = scale_(params.config->gap_fill_min_area.get_abs_value(params.flow.width)) * params.flow.scaled_width();
+ double minarea = double(params.flow.scaled_width()) * double(params.flow.scaled_width());
+ if (params.config != nullptr) minarea = scale_d(params.config->gap_fill_min_area.get_abs_value(params.flow.width)) * double(params.flow.scaled_width());
for (const ExPolygon& ex : gapfill_areas_collapsed) {
//remove too small gaps that are too hard to fill.
//ie one that are smaller than an extrusion with width of min and a length of max.
@@ -2109,8 +2109,8 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
assert(params.anchor_length >= 0.);
assert(params.anchor_length_max >= 0.01f);
assert(params.anchor_length_max >= params.anchor_length);
- const double anchor_length = scale_(params.anchor_length);
- const double anchor_length_max = scale_(params.anchor_length_max);
+ const coordf_t anchor_length = scale_d(params.anchor_length);
+ const coordf_t anchor_length_max = scale_d(params.anchor_length_max);
#if 0
append(polylines_out, infill_ordered);
diff --git a/src/libslic3r/Fill/FillConcentric.cpp b/src/libslic3r/Fill/FillConcentric.cpp
index 10b76c357..86de14193 100644
--- a/src/libslic3r/Fill/FillConcentric.cpp
+++ b/src/libslic3r/Fill/FillConcentric.cpp
@@ -174,8 +174,8 @@ FillConcentricWGapFill::fill_surface_extrusion(
ExPolygons gapfill_areas = diff_ex({ surface->expolygon }, offset_ex(expp, double(scale_(0.5 * this->get_spacing()))));
gapfill_areas = union_ex(gapfill_areas, true);
if (gapfill_areas.size() > 0) {
- double minarea = params.flow.scaled_width() * params.flow.scaled_width();
- if (params.config != nullptr) minarea = scale_(params.config->gap_fill_min_area.get_abs_value(params.flow.width)) * params.flow.scaled_width();
+ double minarea = double(params.flow.scaled_width()) * double(params.flow.scaled_width());
+ if (params.config != nullptr) minarea = scale_d(params.config->gap_fill_min_area.get_abs_value(params.flow.width)) * double(params.flow.scaled_width());
for (int i = 0; i < gapfill_areas.size(); i++) {
if (gapfill_areas[i].area() < minarea) {
gapfill_areas.erase(gapfill_areas.begin() + i);
diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp
index 8209bc3b0..c51cdf914 100644
--- a/src/libslic3r/Fill/FillGyroid.cpp
+++ b/src/libslic3r/Fill/FillGyroid.cpp
@@ -184,7 +184,7 @@ void FillGyroid::_fill_surface_single(
if (! polylines.empty()) {
// Remove very small bits, but be careful to not remove infill lines connecting thin walls!
// The infill perimeter lines should be separated by around a single infill line width.
- const double minlength = scale_(0.8 * this->get_spacing());
+ const coordf_t minlength = scale_d(0.8 * this->get_spacing());
polylines.erase(
std::remove_if(polylines.begin(), polylines.end(), [minlength](const Polyline &pl) { return pl.length() < minlength; }),
polylines.end());
diff --git a/src/libslic3r/Fill/FillLine.cpp b/src/libslic3r/Fill/FillLine.cpp
index de4df4893..eb2a17af5 100644
--- a/src/libslic3r/Fill/FillLine.cpp
+++ b/src/libslic3r/Fill/FillLine.cpp
@@ -94,7 +94,7 @@ void FillLine::_fill_surface_single(
// offset the expolygon by max(min_spacing/2, extra)
ExPolygon expolygon_off;
{
- ExPolygons expolygons_off = offset_ex(expolygon, this->_min_spacing/2);
+ ExPolygons expolygons_off = offset_ex(expolygon, coordf_t(this->_min_spacing / 2));
if (! expolygons_off.empty()) {
// When expanding a polygon, the number of islands could only shrink. Therefore the offset_ex shall generate exactly one expanded island for one input island.
assert(expolygons_off.size() == 1);
diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp
index e47e121f8..1dd8acd3d 100644
--- a/src/libslic3r/Fill/FillRectilinear.cpp
+++ b/src/libslic3r/Fill/FillRectilinear.cpp
@@ -2819,8 +2819,8 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
ExPolygonWithOffset poly_with_offset(
surface->expolygon,
- rotate_vector.first,
- float(scale_(0 /*this->overlap*/ - (0.5 - INFILL_OVERLAP_OVER_SPACING) * this->get_spacing())),
- float(scale_(0 /*this->overlap*/ - 0.5f * this->get_spacing())));
+ (scale_t(0 /*this->overlap*/ - (0.5 - INFILL_OVERLAP_OVER_SPACING) * this->get_spacing())),
+ (scale_t(0 /*this->overlap*/ - 0.5f * this->get_spacing())));
if (poly_with_offset.n_contours_inner == 0) {
// Not a single infill line fits.
//Prusa: maybe one shall trigger the gap fill here?
@@ -2956,24 +2956,24 @@ bool FillRectilinear::fill_surface_by_multilines(const Surface* surface, FillPar
{
assert(sweep_params.size() > 1);
assert(!params.full_infill());
- params.density /= double(sweep_params.size());
+ params.density /= float(sweep_params.size());
assert(params.density > 0.0001f && params.density <= 1.f);
- ExPolygonWithOffset poly_with_offset_base(surface->expolygon, 0, float(scale_(this->overlap - 0.5 * this->get_spacing())));
+ ExPolygonWithOffset poly_with_offset_base(surface->expolygon, 0, scale_t(this->overlap - 0.5 * this->get_spacing()));
if (poly_with_offset_base.n_contours == 0)
// Not a single infill line fits.
return true;
Polylines fill_lines;
- coord_t line_width = coord_t(scale_(this->get_spacing()));
- coord_t line_spacing = coord_t(scale_(this->get_spacing()) / params.density);
+ coord_t line_width = scale_t(this->get_spacing());
+ coord_t line_spacing = scale_t(this->get_spacing() / params.density);
std::pair<float, Point> rotate_vector = this->_infill_direction(surface);
for (const SweepParams& sweep : sweep_params) {
size_t n_fill_lines_initial = fill_lines.size();
// Rotate polygons so that we can work with vertical lines here
double angle = rotate_vector.first + sweep.angle_base;
- ExPolygonWithOffset poly_with_offset(poly_with_offset_base, -angle);
+ ExPolygonWithOffset poly_with_offset(poly_with_offset_base, float(-angle));
BoundingBox bounding_box = poly_with_offset.bounding_box_src();
// Don't produce infill lines, which fully overlap with the infill perimeter.
coord_t x_min = bounding_box.min.x() + line_width + coord_t(SCALED_EPSILON);
@@ -3096,10 +3096,10 @@ FillRectilinearPeri::fill_surface_extrusion(const Surface *surface, const FillPa
Polylines polylines_1;
//generate perimeter:
ExPolygons path_perimeter = offset2_ex(surface->expolygon,
- scale_(-this->get_spacing()), scale_(this->get_spacing() / 2),
- ClipperLib::jtMiter, scale_(this->get_spacing()) * 10);
+ scale_d(-this->get_spacing()), scale_d(this->get_spacing() / 2),
+ ClipperLib::jtMiter, scale_d(this->get_spacing()) * 10);
//fix a bug that can happens when (positive) offsetting with a big miter limit and two island merge. See https://github.com/supermerill/SuperSlicer/issues/609
- path_perimeter = intersection_ex(path_perimeter, offset_ex(surface->expolygon, scale_(-this->get_spacing() / 2)));
+ path_perimeter = intersection_ex(path_perimeter, offset_ex(surface->expolygon, scale_d(-this->get_spacing() / 2)));
for (ExPolygon &expolygon : path_perimeter) {
expolygon.contour.make_counter_clockwise();
polylines_1.push_back(expolygon.contour.split_at_index(0));
@@ -3133,7 +3133,7 @@ FillRectilinearPeri::fill_surface_extrusion(const Surface *surface, const FillPa
Polylines polylines_2;
bool canFill = true;
//50% overlap with the new perimeter
- ExPolygons path_inner = offset2_ex(surface->expolygon, scale_(-this->get_spacing() * 1.5), scale_(this->get_spacing()));
+ ExPolygons path_inner = offset2_ex(surface->expolygon, scale_d(-this->get_spacing() * 1.5), scale_d(this->get_spacing()));
for (ExPolygon &expolygon : path_inner) {
Surface surfInner(*surface, expolygon);
if (!fill_surface_by_lines(&surfInner, params, 0.f, 0.f, polylines_2)) {
@@ -3203,7 +3203,7 @@ Polylines FillScatteredRectilinear::fill_surface(const Surface *surface, const F
Polylines polylines_out;
// Offset the pattern randomly using the current layer index as the generator
- float offset = randomFloatFromSeed((uint32_t) layer_id) * 0.5f * this->get_spacing();
+ float offset = (float)randomFloatFromSeed((uint32_t) layer_id) * 0.5f * this->get_spacing();
if (!fill_surface_by_lines(surface, params, 0.f, offset, polylines_out)) {
printf("FillScatteredRectilinear::fill_surface() failed to fill a region.\n");
@@ -3307,7 +3307,7 @@ FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const Fi
current_extrusion->push_back(last, tooth_zhop);
// add new extrusion that go down with no nozzle_flow / sqrt(2)
- extrusions->paths.push_back(ExtrusionPath3D(good_role, params.flow.mm3_per_mm() / std::sqrt(2), params.flow.width / std::sqrt(2), params.flow.height));
+ extrusions->paths.push_back(ExtrusionPath3D(good_role, params.flow.mm3_per_mm() / std::sqrt(2), float(params.flow.width / std::sqrt(2)), params.flow.height));
current_extrusion = &(extrusions->paths.back());
current_extrusion->push_back(last, tooth_zhop);
//add next point
@@ -3438,7 +3438,7 @@ FillRectilinearWGapFill::fill_surface_extrusion(const Surface *surface, const Fi
eec->entities, polylines_rectilinear,
good_role,
params.flow.mm3_per_mm() * params.flow_mult * flow_mult_exact_volume,
- params.flow.width * params.flow_mult * flow_mult_exact_volume,
+ params.flow.width * params.flow_mult * float(flow_mult_exact_volume),
params.flow.height);
coll_nosort->entities.push_back(eec);
@@ -3452,7 +3452,7 @@ FillRectilinearWGapFill::fill_surface_extrusion(const Surface *surface, const Fi
gapfill_areas.insert(gapfill_areas.end(), unextruded_areas.begin(), unextruded_areas.end());
gapfill_areas = union_ex(gapfill_areas, true);
if (gapfill_areas.size() > 0) {
- const double minarea = scale_(params.config->gap_fill_min_area.get_abs_value(params.flow.width)) * params.flow.scaled_width();
+ const double minarea = scale_d(params.config->gap_fill_min_area.get_abs_value(params.flow.width)) * double(params.flow.scaled_width());
for (int i = 0; i < gapfill_areas.size(); i++) {
if (gapfill_areas[i].area() < minarea) {
gapfill_areas.erase(gapfill_areas.begin() + i);
diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp
index 72e3ecb94..b13eb3f87 100644
--- a/src/libslic3r/Flow.cpp
+++ b/src/libslic3r/Flow.cpp
@@ -290,7 +290,7 @@ Flow support_material_1st_layer_flow(const PrintObject *object, float layer_heig
const auto &width = (object->config().first_layer_extrusion_width.value > 0) ? object->config().first_layer_extrusion_width : object->config().support_material_extrusion_width;
float slice_height = layer_height;
if (layer_height <= 0.f && !object->print()->config().nozzle_diameter.empty()){
- slice_height = (float)(object->config().first_layer_height.get_abs_value(object->print()->config().nozzle_diameter.get_at(0)));
+ slice_height = (float)object->get_first_layer_height();
}
return Flow::new_from_config_width(
frSupportMaterial,
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index fe98c0518..8db4a24d4 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -2109,8 +2109,8 @@ namespace Slic3r {
bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config, const std::string &file_path);
- bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data, const std::string &file_path);
- bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig* config);
+ bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const DynamicPrintConfig& print_config, const IdToObjectDataMap &objects_data, const std::string &file_path);
+ bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig& config);
};
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data)
@@ -2211,7 +2211,7 @@ namespace Slic3r {
// Adds custom gcode per height file ("Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml").
// All custom gcode per height of whole Model are stored here
- if (!_add_custom_gcode_per_print_z_file_to_archive(archive, model, config))
+ if (!_add_custom_gcode_per_print_z_file_to_archive(archive, model, *config))
{
close_zip_writer(&archive);
boost::filesystem::remove(filename);
@@ -2238,21 +2238,21 @@ namespace Slic3r {
// This file contains all the attributes of all ModelObjects and their ModelVolumes (names, parameter overrides).
// As there is just a single Indexed Triangle Set data stored per ModelObject, offsets of volumes into their respective Indexed Triangle Set data
// is stored here as well.
- if (!_add_model_config_file_to_archive(archive, model, objects_data, MODEL_CONFIG_FILE))
+ if (!_add_model_config_file_to_archive(archive, model, *config, objects_data, MODEL_CONFIG_FILE))
{
close_zip_writer(&archive);
boost::filesystem::remove(filename);
return false;
}
// also add prusa
- if (!_add_model_config_file_to_archive(archive, model, objects_data, MODEL_PRUSA_CONFIG_FILE))
+ if (!_add_model_config_file_to_archive(archive, model, *config, objects_data, MODEL_PRUSA_CONFIG_FILE))
{
close_zip_writer(&archive);
boost::filesystem::remove(filename);
return false;
}
// also superslicer for backward comp, just for some version from 2.3.56
- if (!_add_model_config_file_to_archive(archive, model, objects_data, MODEL_SUPER_CONFIG_FILE))
+ if (!_add_model_config_file_to_archive(archive, model, *config, objects_data, MODEL_SUPER_CONFIG_FILE))
{
close_zip_writer(&archive);
boost::filesystem::remove(filename);
@@ -2787,7 +2787,7 @@ namespace Slic3r {
return true;
}
- bool _3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data, const std::string &file_path)
+ bool _3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const DynamicPrintConfig& print_config, const IdToObjectDataMap &objects_data, const std::string &file_path)
{
std::stringstream stream;
// Store mesh transformation in full precision, as the volumes are stored transformed and they need to be transformed back
@@ -2802,6 +2802,7 @@ namespace Slic3r {
const ModelObject* obj = obj_metadata.second.object;
if (obj != nullptr)
{
+ DynamicPrintConfig obj_config_wparent; // part of the chain of config, used as reference to convert configs to prusa config
// Output of instances count added because of github #3435, currently not used by PrusaSlicer
stream << " <" << OBJECT_TAG << " " << ID_ATTR << "=\"" << obj_metadata.first << "\" " << INSTANCESCOUNT_ATTR << "=\"" << obj->instances.size() << "\">\n";
@@ -2812,10 +2813,13 @@ namespace Slic3r {
// stores object's config data
if (file_path == MODEL_PRUSA_CONFIG_FILE) {
+ assert(obj->config.get().parent == nullptr);
+ obj_config_wparent = obj->config.get();
+ obj_config_wparent.parent = &print_config;
for (std::string key : obj->config.keys()) {
// convert to prusa config
std::string value = obj->config.opt_serialize(key);
- obj->config.to_prusa(key, value);
+ obj_config_wparent.to_prusa(key, value);
if (!key.empty())
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << value << "\"/>\n";
}
@@ -2884,10 +2888,13 @@ namespace Slic3r {
// stores volume's config data
if (file_path == MODEL_PRUSA_CONFIG_FILE) {
+ assert(volume->config.get().parent == nullptr);
+ DynamicPrintConfig copy_config = volume->config.get();
+ copy_config.parent = &obj_config_wparent;
for (std::string key : volume->config.keys()) {
// convert to prusa config
std::string value = volume->config.opt_serialize(key);
- volume->config.to_prusa(key, value);
+ copy_config.to_prusa(key, value);
if (!key.empty())
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << value << "\"/>\n";
}
@@ -2918,7 +2925,7 @@ namespace Slic3r {
return true;
}
-bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archive& archive, Model& model, const DynamicPrintConfig* config)
+bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archive& archive, Model& model, const DynamicPrintConfig& config)
{
std::string out = "";
@@ -2940,9 +2947,9 @@ bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archiv
code_tree.put("<xmlattr>.extra" , code.extra );
// add gcode field data for the old version of the PrusaSlicer
- std::string gcode = code.type == CustomGCode::ColorChange ? config->opt_string("color_change_gcode") :
- code.type == CustomGCode::PausePrint ? config->opt_string("pause_print_gcode") :
- code.type == CustomGCode::Template ? config->opt_string("template_custom_gcode") :
+ std::string gcode = code.type == CustomGCode::ColorChange ? config.opt_string("color_change_gcode") :
+ code.type == CustomGCode::PausePrint ? config.opt_string("pause_print_gcode") :
+ code.type == CustomGCode::Template ? config.opt_string("template_custom_gcode") :
code.type == CustomGCode::ToolChange ? "tool_change" : code.extra;
code_tree.put("<xmlattr>.gcode" , gcode );
}
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index 8121e3f43..2ee128c92 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -158,6 +158,8 @@ std::string Wipe::wipe(GCode& gcodegen, bool toolchange)
/* Reduce feedrate a bit; travel speed is often too high to move on existing material.
Too fast = ripping of existing material; too slow = short wipe path, thus more blob. */
double wipe_speed = gcodegen.writer().config.travel_speed.value * 0.8;
+ if(gcodegen.writer().tool_is_extruder() && gcodegen.writer().config.wipe_speed.get_at(gcodegen.writer().tool()->id()) > 0)
+ wipe_speed = gcodegen.writer().config.wipe_speed.get_at(gcodegen.writer().tool()->id());
// get the retraction length
double length = gcodegen.writer().tool()->retract_length();
@@ -173,7 +175,7 @@ std::string Wipe::wipe(GCode& gcodegen, bool toolchange)
/* Calculate how long we need to travel in order to consume the required
amount of retraction. In other words, how far do we move in XY at wipe_speed
for the time needed to consume retract_length at retract_speed? */
- double wipe_dist = scale_(length / gcodegen.writer().tool()->retract_speed() * wipe_speed);
+ coordf_t wipe_dist = scale_d(length / gcodegen.writer().tool()->retract_speed() * wipe_speed);
/* Take the stored wipe path and replace first point with the current actual position
(they might be different, for example, in case of loop clipping). */
@@ -190,7 +192,7 @@ std::string Wipe::wipe(GCode& gcodegen, bool toolchange)
if (!wipe_path.empty()) {
// add tag for processor
gcode += ";" + GCodeProcessor::Wipe_Start_Tag + "\n";
- for (const Line& line : wipe_path.lines()) {
+ for (const Line& line : wipe_path.lines()) {
double segment_length = line.length();
/* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
due to rounding (TODO: test and/or better math for this) */
@@ -223,7 +225,7 @@ static inline void set_extra_lift(const Layer& layer, const Print& print, GCodeW
//get biggest first layer height and set extra lift for first travel, to be safe.
double extra_lift_value = 0;
for (const PrintObject* obj : print.objects())
- extra_lift_value = std::max(extra_lift_value, obj->config().first_layer_height.get_abs_value(print.config().nozzle_diameter.get_at(0)));
+ extra_lift_value = std::max(extra_lift_value, print.get_object_first_layer_height(*obj));
writer.set_extra_lift(extra_lift_value * 2);
}
}
@@ -235,13 +237,13 @@ static inline void set_extra_lift(const Layer& layer, const Print& print, GCodeW
std::string WipeTowerIntegration::append_tcr(GCode& gcodegen, const WipeTower::ToolChangeResult& tcr, int new_extruder_id, double z) const
{
- if (new_extruder_id != -1 && new_extruder_id != tcr.new_tool)
+ if (new_extruder_id != -1 && new_extruder_id != tcr.new_tool)
throw Slic3r::InvalidArgument("Error: WipeTowerIntegration::append_tcr was asked to do a toolchange it didn't expect.");
- std::string gcode;
+ std::string gcode;
- // Toolchangeresult.gcode assumes the wipe tower corner is at the origin (except for priming lines)
- // We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position
+ // Toolchangeresult.gcode assumes the wipe tower corner is at the origin (except for priming lines)
+ // We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position
float alpha = m_wipe_tower_rotation / 180.f * float(M_PI);
auto transform_wt_pt = [&alpha, this](const Vec2f& pt) -> Vec2f {
@@ -250,112 +252,112 @@ static inline void set_extra_lift(const Layer& layer, const Print& print, GCodeW
return out;
};
- Vec2f start_pos = tcr.start_pos;
- Vec2f end_pos = tcr.end_pos;
+ Vec2f start_pos = tcr.start_pos;
+ Vec2f end_pos = tcr.end_pos;
if (! tcr.priming) {
start_pos = transform_wt_pt(start_pos);
end_pos = transform_wt_pt(end_pos);
- }
+ }
- Vec2f wipe_tower_offset = tcr.priming ? Vec2f::Zero() : m_wipe_tower_pos;
- float wipe_tower_rotation = tcr.priming ? 0.f : alpha;
+ Vec2f wipe_tower_offset = tcr.priming ? Vec2f::Zero() : m_wipe_tower_pos;
+ float wipe_tower_rotation = tcr.priming ? 0.f : alpha;
- std::string tcr_rotated_gcode = post_process_wipe_tower_moves(tcr, wipe_tower_offset, wipe_tower_rotation);
+ std::string tcr_rotated_gcode = post_process_wipe_tower_moves(tcr, wipe_tower_offset, wipe_tower_rotation);
- //if needed, write the gcode_label_objects_end then priming tower
- if (!gcodegen.m_gcode_label_objects_end.empty()) {
- gcode += gcodegen.m_gcode_label_objects_end;
- gcodegen.m_gcode_label_objects_end = "";
- }
+ //if needed, write the gcode_label_objects_end then priming tower
+ if (!gcodegen.m_gcode_label_objects_end.empty()) {
+ gcode += gcodegen.m_gcode_label_objects_end;
+ gcodegen.m_gcode_label_objects_end = "";
+ }
- if (! tcr.priming) {
- // Move over the wipe tower.
- // Retract for a tool change, using the toolchange retract value and setting the priming extra length.
- gcode += gcodegen.retract(true);
- gcodegen.m_avoid_crossing_perimeters.use_external_mp_once();
- Polyline polyline = gcodegen.travel_to(
- gcode,
- wipe_tower_point_to_object_point(gcodegen, start_pos),
- erMixed);
- gcodegen.write_travel_to(gcode, polyline, "Travel to a Wipe Tower");
- gcode += gcodegen.unretract();
- }
+ if (! tcr.priming) {
+ // Move over the wipe tower.
+ // Retract for a tool change, using the toolchange retract value and setting the priming extra length.
+ gcode += gcodegen.retract(true);
+ gcodegen.m_avoid_crossing_perimeters.use_external_mp_once();
+ Polyline polyline = gcodegen.travel_to(
+ gcode,
+ wipe_tower_point_to_object_point(gcodegen, start_pos),
+ erMixed);
+ gcodegen.write_travel_to(gcode, polyline, "Travel to a Wipe Tower");
+ gcode += gcodegen.unretract();
+ }
- double current_z = gcodegen.writer().get_position().z();
- if (z == -1.) // in case no specific z was provided, print at current_z pos
- z = current_z;
- if (! is_approx(z, current_z)) {
- gcode += gcodegen.writer().retract();
- gcode += gcodegen.writer().travel_to_z(z, "Travel down to the last wipe tower layer.");
- gcode += gcodegen.writer().unretract();
- }
+ double current_z = gcodegen.writer().get_position().z();
+ if (z == -1.) // in case no specific z was provided, print at current_z pos
+ z = current_z;
+ if (! is_approx(z, current_z)) {
+ gcode += gcodegen.writer().retract();
+ gcode += gcodegen.writer().travel_to_z(z, "Travel down to the last wipe tower layer.");
+ gcode += gcodegen.writer().unretract();
+ }
- // Process the end filament gcode.
- std::string end_filament_gcode_str;
- if (gcodegen.writer().tool() != nullptr && gcodegen.writer().tool_is_extruder()) {
- // Process the custom end_filament_gcode in case of single_extruder_multi_material.
- uint16_t old_extruder_id = gcodegen.writer().tool()->id();
- const std::string& end_filament_gcode = gcodegen.config().end_filament_gcode.get_at(old_extruder_id);
- if (gcodegen.writer().tool() != nullptr && ! end_filament_gcode.empty()) {
- DynamicConfig config;
- int previous_extruder_id = gcodegen.writer().tool() ? (int)gcodegen.writer().tool()->id() : -1;
- config.set_key_value("previous_extruder", new ConfigOptionInt(previous_extruder_id));
- config.set_key_value("next_extruder", new ConfigOptionInt((int)new_extruder_id));
- config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index));
- config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z));
- end_filament_gcode_str = gcodegen.placeholder_parser_process("end_filament_gcode", end_filament_gcode, old_extruder_id, &config);
- check_add_eol(end_filament_gcode_str);
+ // Process the end filament gcode.
+ std::string end_filament_gcode_str;
+ if (gcodegen.writer().tool() != nullptr && gcodegen.writer().tool_is_extruder()) {
+ // Process the custom end_filament_gcode in case of single_extruder_multi_material.
+ uint16_t old_extruder_id = gcodegen.writer().tool()->id();
+ const std::string& end_filament_gcode = gcodegen.config().end_filament_gcode.get_at(old_extruder_id);
+ if (gcodegen.writer().tool() != nullptr && ! end_filament_gcode.empty()) {
+ DynamicConfig config;
+ int previous_extruder_id = gcodegen.writer().tool() ? (int)gcodegen.writer().tool()->id() : -1;
+ config.set_key_value("previous_extruder", new ConfigOptionInt(previous_extruder_id));
+ config.set_key_value("next_extruder", new ConfigOptionInt((int)new_extruder_id));
+ config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index));
+ config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z));
+ end_filament_gcode_str = gcodegen.placeholder_parser_process("end_filament_gcode", end_filament_gcode, old_extruder_id, &config);
+ check_add_eol(end_filament_gcode_str);
+ }
}
- }
- // Process the custom toolchange_gcode. If it is empty, provide a simple Tn command to change the filament.
- // Otherwise, leave control to the user completely.
- std::string toolchange_gcode_str;
+ // Process the custom toolchange_gcode. If it is empty, provide a simple Tn command to change the filament.
+ // Otherwise, leave control to the user completely.
+ std::string toolchange_gcode_str;
- if (tcr.priming || (new_extruder_id >= 0 && gcodegen.writer().need_toolchange(new_extruder_id)))
- toolchange_gcode_str += gcodegen.toolchange(new_extruder_id, tcr.print_z);
+ if (tcr.priming || (new_extruder_id >= 0 && gcodegen.writer().need_toolchange(new_extruder_id)))
+ toolchange_gcode_str += gcodegen.toolchange(new_extruder_id, tcr.print_z);
- gcodegen.placeholder_parser().set("current_extruder", new_extruder_id);
+ gcodegen.placeholder_parser().set("current_extruder", new_extruder_id);
- // Process the start filament gcode.
- std::string start_filament_gcode_str;
+ // Process the start filament gcode.
+ std::string start_filament_gcode_str;
const std::string& start_filament_gcode = gcodegen.config().start_filament_gcode.get_at(new_extruder_id);
if (!start_filament_gcode.empty()) {
- // Process the start_filament_gcode for the active filament only.
- DynamicConfig config;
- config.set_key_value("filament_extruder_id", new ConfigOptionInt(new_extruder_id));
- config.set_key_value("previous_extruder", new ConfigOptionInt(gcodegen.writer().tool() ? (int)gcodegen.writer().tool()->id() : -1));
- config.set_key_value("next_extruder", new ConfigOptionInt(new_extruder_id));
- config.set_key_value("layer_num", new ConfigOptionInt(0));
- config.set_key_value("layer_z", new ConfigOptionFloat(z));
- start_filament_gcode_str = gcodegen.placeholder_parser_process("start_filament_gcode", start_filament_gcode, new_extruder_id, &config);
- check_add_eol(start_filament_gcode_str);
- }
+ // Process the start_filament_gcode for the active filament only.
+ DynamicConfig config;
+ config.set_key_value("filament_extruder_id", new ConfigOptionInt(new_extruder_id));
+ config.set_key_value("previous_extruder", new ConfigOptionInt(gcodegen.writer().tool() ? (int)gcodegen.writer().tool()->id() : -1));
+ config.set_key_value("next_extruder", new ConfigOptionInt(new_extruder_id));
+ config.set_key_value("layer_num", new ConfigOptionInt(0));
+ config.set_key_value("layer_z", new ConfigOptionFloat(z));
+ start_filament_gcode_str = gcodegen.placeholder_parser_process("start_filament_gcode", start_filament_gcode, new_extruder_id, &config);
+ check_add_eol(start_filament_gcode_str);
+ }
- // Insert the end filament, toolchange, and start filament gcode into the generated gcode.
- DynamicConfig config;
- config.set_key_value("end_filament_gcode", new ConfigOptionString(end_filament_gcode_str));
- config.set_key_value("toolchange_gcode", new ConfigOptionString(toolchange_gcode_str));
- config.set_key_value("start_filament_gcode", new ConfigOptionString(start_filament_gcode_str));
- std::string tcr_gcode, tcr_escaped_gcode = gcodegen.placeholder_parser_process("tcr_rotated_gcode", tcr_rotated_gcode, new_extruder_id, &config);
- unescape_string_cstyle(tcr_escaped_gcode, tcr_gcode);
- gcode += tcr_gcode;
- check_add_eol(toolchange_gcode_str);
-
- if (gcodegen.writer().tool() && gcodegen.m_config.filament_enable_toolchange_part_fan.values[gcodegen.writer().tool()->id()]) {
- //if the fan may have been changed silently by the wipetower, recover it.
- gcode += gcodegen.m_writer.set_fan(gcodegen.m_writer.get_fan(), true);
- }
+ // Insert the end filament, toolchange, and start filament gcode into the generated gcode.
+ DynamicConfig config;
+ config.set_key_value("end_filament_gcode", new ConfigOptionString(end_filament_gcode_str));
+ config.set_key_value("toolchange_gcode", new ConfigOptionString(toolchange_gcode_str));
+ config.set_key_value("start_filament_gcode", new ConfigOptionString(start_filament_gcode_str));
+ std::string tcr_gcode, tcr_escaped_gcode = gcodegen.placeholder_parser_process("tcr_rotated_gcode", tcr_rotated_gcode, new_extruder_id, &config);
+ unescape_string_cstyle(tcr_escaped_gcode, tcr_gcode);
+ gcode += tcr_gcode;
+ check_add_eol(toolchange_gcode_str);
+
+ if (gcodegen.writer().tool() && gcodegen.m_config.filament_enable_toolchange_part_fan.values[gcodegen.writer().tool()->id()]) {
+ //if the fan may have been changed silently by the wipetower, recover it.
+ gcode += gcodegen.m_writer.set_fan(gcodegen.m_writer.get_fan(), true);
+ }
- // A phony move to the end position at the wipe tower.
- gcodegen.writer().travel_to_xy(end_pos.cast<double>());
- gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos));
+ // A phony move to the end position at the wipe tower.
+ gcodegen.writer().travel_to_xy(end_pos.cast<double>());
+ gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos));
if (!is_approx(z, current_z)) {
- gcode += gcodegen.writer().retract();
- gcode += gcodegen.writer().travel_to_z(current_z, "Travel back up to the topmost object layer.");
- gcode += gcodegen.writer().unretract();
- } else {
+ gcode += gcodegen.writer().retract();
+ gcode += gcodegen.writer().travel_to_z(current_z, "Travel back up to the topmost object layer.");
+ gcode += gcodegen.writer().unretract();
+ } else {
// Prepare a future wipe.
gcodegen.m_wipe.reset_path();
for (const Vec2f& wipe_pt : tcr.wipe_path)
@@ -367,10 +369,10 @@ static inline void set_extra_lift(const Layer& layer, const Print& print, GCodeW
return gcode;
}
- // This function postprocesses gcode_original, rotates and moves all G1 extrusions and returns resulting gcode
- // Starting position has to be supplied explicitely (otherwise it would fail in case first G1 command only contained one coordinate)
- std::string WipeTowerIntegration::post_process_wipe_tower_moves(const WipeTower::ToolChangeResult& tcr, const Vec2f& translation, float angle) const
- {
+// This function postprocesses gcode_original, rotates and moves all G1 extrusions and returns resulting gcode
+// Starting position has to be supplied explicitely (otherwise it would fail in case first G1 command only contained one coordinate)
+std::string WipeTowerIntegration::post_process_wipe_tower_moves(const WipeTower::ToolChangeResult& tcr, const Vec2f& translation, float angle) const
+{
Vec2f extruder_offset = m_extruder_offsets[tcr.initial_tool].cast<float>();
std::istringstream gcode_str(tcr.gcode);
@@ -388,7 +390,7 @@ static inline void set_extra_lift(const Layer& layer, const Print& print, GCodeW
// WT generator can override this by appending the never_skip_tag
if (line.find("G1 ") == 0) {
bool never_skip = false;
- auto it = line.find(WipeTower::never_skip_tag());
+ auto it = line.find(WipeTower::never_skip_tag());
if (it != std::string::npos) {
// remove the tag and remember we saw it
never_skip = true;
@@ -399,7 +401,7 @@ static inline void set_extra_lift(const Layer& layer, const Print& print, GCodeW
line_str >> std::noskipws; // don't skip whitespace
char ch = 0;
while (line_str >> ch) {
- if (ch == 'X' || ch == 'Y')
+ if (ch == 'X' || ch == 'Y')
line_str >> (ch == 'X' ? pos.x() : pos.y());
else
line_out << ch;
@@ -439,7 +441,7 @@ static inline void set_extra_lift(const Layer& layer, const Print& print, GCodeW
}
}
return gcode_out;
- }
+}
std::string WipeTowerIntegration::prime(GCode& gcodegen)
@@ -454,33 +456,32 @@ static inline void set_extra_lift(const Layer& layer, const Print& print, GCodeW
std::string WipeTowerIntegration::tool_change(GCode& gcodegen, int extruder_id, bool finish_layer)
{
- std::string gcode;
- assert(m_layer_idx >= 0);
+ std::string gcode;
+ assert(m_layer_idx >= 0);
if (!m_brim_done || gcodegen.writer().need_toolchange(extruder_id) || finish_layer) {
- if (m_layer_idx < (int)m_tool_changes.size()) {
+ if (m_layer_idx < (int)m_tool_changes.size()) {
if (!(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size()))
throw Slic3r::RuntimeError("Wipe tower generation failed, possibly due to empty first layer.");
-
- // Calculate where the wipe tower layer will be printed. -1 means that print z will not change,
- // resulting in a wipe tower with sparse layers.
- double wipe_tower_z = -1;
- bool ignore_sparse = false;
- if (gcodegen.config().wipe_tower_no_sparse_layers.value) {
- wipe_tower_z = m_last_wipe_tower_print_z;
- ignore_sparse = (m_brim_done && m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool);
+ // Calculate where the wipe tower layer will be printed. -1 means that print z will not change,
+ // resulting in a wipe tower with sparse layers.
+ double wipe_tower_z = -1;
+ bool ignore_sparse = false;
+ if (gcodegen.config().wipe_tower_no_sparse_layers.value) {
+ wipe_tower_z = m_last_wipe_tower_print_z;
+ ignore_sparse = (m_brim_done && m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool);
if (m_tool_change_idx == 0 && !ignore_sparse)
- wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height;
+ wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height;
}
if (!ignore_sparse) {
- gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id, wipe_tower_z);
- m_last_wipe_tower_print_z = wipe_tower_z;
+ gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id, wipe_tower_z);
+ m_last_wipe_tower_print_z = wipe_tower_z;
+ }
}
- }
- m_brim_done = true;
- }
- return gcode;
+ m_brim_done = true;
+ }
+ return gcode;
}
// Print is finished. Now it remains to unload the filament safely with ramming over the wipe tower.
@@ -575,8 +576,8 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
// Remember last layer with extrusions.
if (has_extrusions)
- last_extrusion_layer = &layers_to_print.back();
- }
+ last_extrusion_layer = &layers_to_print.back();
+ }
}
return layers_to_print;
@@ -740,31 +741,34 @@ namespace DoExport {
excluded.insert(erMixed);
excluded.insert(erNone);
excluded.insert(erWipeTower);
- if (config->get_abs_value("perimeter_speed") != 0 && config->get_abs_value("small_perimeter_speed") != 0) {
+ if (config->option("perimeter_speed") != nullptr && config->option("perimeter_speed")->getFloat() != 0
+ && config->option("small_perimeter_speed") != nullptr && config->option("small_perimeter_speed")->getFloat() != 0) {
excluded.insert(erPerimeter);
excluded.insert(erSkirt);
}
- if (config->get_abs_value("external_perimeter_speed") != 0 && config->get_abs_value("small_perimeter_speed") != 0)
+ if (config->option("external_perimeter_speed") != nullptr && config->option("external_perimeter_speed")->getFloat() != 0
+ && config->option("small_perimeter_speed") != nullptr && config->option("small_perimeter_speed")->getFloat() != 0)
excluded.insert(erExternalPerimeter);
- if (config->get_abs_value("overhangs_speed") != 0 && config->get_abs_value("small_perimeter_speed") != 0)
+ if (config->option("overhangs_speed") != nullptr && config->option("overhangs_speed")->getFloat() != 0
+ && config->option("small_perimeter_speed") != nullptr && config->option("small_perimeter_speed")->getFloat() != 0)
excluded.insert(erOverhangPerimeter);
- if (config->get_abs_value("gap_fill_speed") != 0)
+ if (config->option("gap_fill_speed") != nullptr && config->option("gap_fill_speed")->getFloat() != 0)
excluded.insert(erGapFill);
- if (config->get_abs_value("thin_walls_speed") != 0)
+ if (config->option("thin_walls_speed") != nullptr && config->option("thin_walls_speed")->getFloat() != 0)
excluded.insert(erThinWall);
- if (config->get_abs_value("infill_speed") != 0)
+ if (config->option("infill_speed") != nullptr && config->option("infill_speed")->getFloat() != 0)
excluded.insert(erInternalInfill);
- if (config->get_abs_value("solid_infill_speed") != 0)
+ if (config->option("solid_infill_speed") != nullptr && config->option("solid_infill_speed")->getFloat() != 0)
excluded.insert(erSolidInfill);
- if (config->get_abs_value("top_solid_infill_speed") != 0)
+ if (config->option("top_solid_infill_speed") != nullptr && config->option("top_solid_infill_speed")->getFloat() != 0)
excluded.insert(erTopSolidInfill);
- if (config->get_abs_value("bridge_speed") != 0)
+ if (config->option("bridge_speed") != nullptr && config->option("bridge_speed")->getFloat() != 0)
excluded.insert(erBridgeInfill);
- if (config->get_abs_value("bridge_speed_internal") != 0)
+ if (config->option("bridge_speed_internal") != nullptr && config->option("bridge_speed_internal")->getFloat() != 0)
excluded.insert(erInternalBridgeInfill);
- if (config->get_abs_value("support_material_speed") != 0)
+ if (config->option("support_material_speed") != nullptr && config->option("support_material_speed")->getFloat() != 0)
excluded.insert(erSupportMaterial);
- if (config->get_abs_value("support_material_interface_speed") != 0)
+ if (config->option("support_material_interface_speed") != nullptr && config->option("support_material_interface_speed")->getFloat() != 0)
excluded.insert(erSupportMaterialInterface);
}
virtual void use(const ExtrusionPath& path) override {
@@ -1087,6 +1091,8 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
{
PROFILE_FUNC();
+ m_last_status_update = std::chrono::system_clock::now();
+
// modifies m_silent_time_estimator_enabled
DoExport::init_gcode_processor(print.config(), m_processor, m_silent_time_estimator_enabled);
@@ -1185,7 +1191,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// Write some terse information on the slicing parameters.
const PrintObject *first_object = print.objects().front();
const double layer_height = first_object->config().layer_height.value;
- const double first_layer_height = first_object->config().first_layer_height.get_abs_value(m_config.nozzle_diameter.empty()?0.:m_config.nozzle_diameter.get_at(0));
+ const double first_layer_height = print.get_first_layer_height();
for (const PrintRegion* region : print.regions()) {
_write_format(file, "; external perimeters extrusion width = %.2fmm\n", region->flow(frExternalPerimeter, layer_height, false, false, -1., *first_object).width);
_write_format(file, "; perimeters extrusion width = %.2fmm\n", region->flow(frPerimeter, layer_height, false, false, -1., *first_object).width);
@@ -1290,7 +1296,8 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
}
// We don't allow switching of extruders per layer by Model::custom_gcode_per_print_z in sequential mode.
// Use the extruder IDs collected from Regions.
- this->set_extruders(print.extruders());
+ std::set<uint16_t> extruder_set = print.extruders();
+ this->set_extruders(std::vector<uint16_t>(extruder_set.begin(), extruder_set.end()));
if(has_milling)
m_writer.set_mills(std::vector<uint16_t>() = { 0 });
} else {
@@ -1811,11 +1818,11 @@ void GCode::print_machine_envelope(FILE *file, Print &print)
int(print.config().machine_max_acceleration_extruding.values.front() + 0.5),
int(print.config().machine_max_acceleration_travel.values.front() + 0.5));
if (std::set<uint8_t>{gcfRepRap}.count(print.config().gcode_flavor.value) > 0)
- _write_format(file, "M566 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n",
- print.config().machine_max_jerk_x.values.front(),
- print.config().machine_max_jerk_y.values.front(),
- print.config().machine_max_jerk_z.values.front(),
- print.config().machine_max_jerk_e.values.front());
+ _write_format(file, "M566 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/min\n",
+ print.config().machine_max_jerk_x.values.front() * 60,
+ print.config().machine_max_jerk_y.values.front() * 60,
+ print.config().machine_max_jerk_z.values.front() * 60,
+ print.config().machine_max_jerk_e.values.front() * 60);
if (std::set<uint8_t>{gcfMarlin, gcfLerdge, gcfRepetier}.count(print.config().gcode_flavor.value) > 0)
_write_format(file, "M205 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n",
print.config().machine_max_jerk_x.values.front(),
@@ -2712,6 +2719,13 @@ void GCode::process_layer(
_write(file, gcode);
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
log_memory_info();
+
+
+ std::chrono::time_point<std::chrono::system_clock> end_export_layer = std::chrono::system_clock::now();
+ if ((static_cast<std::chrono::duration<double>>(end_export_layer - m_last_status_update)).count() > 0.2) {
+ m_last_status_update = std::chrono::system_clock::now();
+ print.set_status(int((layer.id() * 100) / layer_count()), std::string(L("Generating G-code layer %s / %s")), std::vector<std::string>{ std::to_string(layer.id()), std::to_string(layer_count()) }, PrintBase::SlicingStatus::DEFAULT);
+ }
}
void GCode::apply_print_config(const PrintConfig &print_config)
@@ -2865,8 +2879,8 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s
// apply the small/external? perimeter speed
if (speed == -1 && is_perimeter(paths.front().role()) && loop.length() <=
scale_(this->m_config.small_perimeter_max_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)))) {
- double min_length = scale_(this->m_config.small_perimeter_min_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
- double max_length = scale_(this->m_config.small_perimeter_max_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
+ coordf_t min_length = scale_d(this->m_config.small_perimeter_min_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
+ coordf_t max_length = scale_d(this->m_config.small_perimeter_max_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
if (loop.length() <= min_length) {
speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed);
} else {
@@ -2913,7 +2927,7 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s
Vec2d p1 = paths.front().polyline.points.front().cast<double>();
Vec2d p2 = paths.front().polyline.points[1].cast<double>();
Vec2d v = p2 - p1;
- double nd = scale_(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, paths.front().width));
+ double nd = scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, paths.front().width));
double l2 = v.squaredNorm();
// Shift by no more than a nozzle diameter.
//FIXME Hiding the seams will not work nicely for very densely discretized contours!
@@ -3061,7 +3075,7 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s
Vec2d p1 = paths.front().polyline.points.front().cast<double>();
Vec2d p2 = paths.front().polyline.points[1].cast<double>();
Vec2d v = p2 - p1;
- double nd = scale_(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, paths.front().width));
+ coordf_t nd = scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, paths.front().width));
double l2 = v.squaredNorm();
// Shift by no more than a nozzle diameter.
//FIXME Hiding the seams will not work nicely for very densely discretized contours!
@@ -3182,8 +3196,8 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
// apply the small perimeter speed
if (speed == -1 && is_perimeter(paths.front().role()) && loop.length() <=
scale_(this->m_config.small_perimeter_max_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)))) {
- double min_length = scale_(this->m_config.small_perimeter_min_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
- double max_length = scale_(this->m_config.small_perimeter_max_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
+ double min_length = scale_d(this->m_config.small_perimeter_min_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
+ double max_length = scale_d(this->m_config.small_perimeter_max_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
if (loop.length() <= min_length) {
speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed);
} else {
@@ -3218,7 +3232,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
//extra wipe before the little move.
if (EXTRUDER_CONFIG_WITH_DEFAULT(wipe_extra_perimeter, 0) > 0) {
- coord_t wipe_dist = scale_(EXTRUDER_CONFIG_WITH_DEFAULT(wipe_extra_perimeter,0));
+ coordf_t wipe_dist = scale_(EXTRUDER_CONFIG_WITH_DEFAULT(wipe_extra_perimeter,0));
ExtrusionPaths paths_wipe;
for (int i = 0; i < paths.size(); i++) {
ExtrusionPath& path = paths[i];
@@ -3276,7 +3290,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
Vec2d current_pos = current_point.cast<double>();
Vec2d next_pos = next_point.cast<double>();
Vec2d vec_dist = next_pos - current_pos;
- double nd = scale_(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter,0));
+ double nd = scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter,0));
double l2 = vec_dist.squaredNorm();
// Shift by no more than a nozzle diameter.
//FIXME Hiding the seams will not work nicely for very densely discretized contours!
@@ -3366,16 +3380,21 @@ void GCode::use(const ExtrusionEntityCollection &collection) {
}
}
-std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &description, double speed) {
+std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &description, double speed_mm_per_sec) {
ExtrusionPath simplifed_path = path;
- const double scaled_min_length = scale_(this->config().min_length.value);
- if (scaled_min_length > 0 && !m_last_too_small.empty()) {
+ const coordf_t scaled_min_length = scale_d(this->config().min_length.value);
+ const double max_gcode_per_second = this->config().max_gcode_per_second.value;
+ double current_scaled_min_length = scaled_min_length;
+ if (max_gcode_per_second > 0) {
+ current_scaled_min_length = std::max(current_scaled_min_length, scale_(_compute_speed_mm_per_sec(path, speed_mm_per_sec)) / max_gcode_per_second);
+ }
+ if (current_scaled_min_length > 0 && !m_last_too_small.empty()) {
//descr += " trys fusion " + std::to_string(unscaled(m_last_too_small.last_point().x())) + " , " + std::to_string(unscaled(path.first_point().x()));
//ensure that it's a continous thing
- if (m_last_too_small.last_point().distance_to_square(path.first_point()) < scaled_min_length*scaled_min_length /*&& m_last_too_small.first_point().distance_to_square(path.first_point()) > EPSILON*/) {
+ if (m_last_too_small.last_point().distance_to_square(path.first_point()) < current_scaled_min_length * current_scaled_min_length /*&& m_last_too_small.first_point().distance_to_square(path.first_point()) > EPSILON*/) {
//descr += " ! fusion " + std::to_string(simplifed_path.polyline.points.size());
- simplifed_path.height = (m_last_too_small.height * m_last_too_small.length() + simplifed_path.height * simplifed_path.length()) / (m_last_too_small.length() + simplifed_path.length());
+ simplifed_path.height = float(m_last_too_small.height * m_last_too_small.length() + simplifed_path.height * simplifed_path.length()) / float(m_last_too_small.length() + simplifed_path.length());
simplifed_path.mm3_per_mm = (m_last_too_small.mm3_per_mm * m_last_too_small.length() + simplifed_path.mm3_per_mm * simplifed_path.length()) / (m_last_too_small.length() + simplifed_path.length());
simplifed_path.polyline.points.insert(simplifed_path.polyline.points.begin(), m_last_too_small.polyline.points.begin(), m_last_too_small.polyline.points.end()-1);
assert(simplifed_path.height == simplifed_path.height);
@@ -3383,11 +3402,11 @@ std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &de
}
m_last_too_small.polyline.points.clear();
}
- if (scaled_min_length > 0) {
+ if (current_scaled_min_length > 0) {
// it's an alternative to simplifed_path.simplify(scale_(this->config().min_length)); with more enphasis ont he segment length that on the feature detail.
// because tolerance = min_length /10, douglas_peucker will erase more points if angles are shallower than 6° and then the '_plus' will kick in to keep a bit more.
// if angles are all bigger than 6°, then the douglas_peucker will do all the work.
- simplifed_path.polyline.points = MultiPoint::_douglas_peucker_plus(simplifed_path.polyline.points, scaled_min_length / 10, scaled_min_length);
+ simplifed_path.polyline.points = MultiPoint::_douglas_peucker_plus(simplifed_path.polyline.points, current_scaled_min_length / 10, current_scaled_min_length);
}
//else simplifed_path.simplify(SCALED_RESOLUTION); //should already be simplified
if (scaled_min_length > 0 && simplifed_path.length() < scaled_min_length) {
@@ -3395,7 +3414,7 @@ std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &de
return "";
}
- std::string gcode = this->_extrude(simplifed_path, description, speed);
+ std::string gcode = this->_extrude(simplifed_path, description, speed_mm_per_sec);
if (m_wipe.enable) {
m_wipe.path = std::move(simplifed_path.polyline);
@@ -3545,11 +3564,11 @@ void GCode::_post_process(std::string& what, bool flush) {
if (this->m_fan_mover.get() == nullptr)
this->m_fan_mover.reset(new Slic3r::FanMover(
this->m_writer,
- std::abs(this->config().fan_speedup_time.value),
+ std::abs((float)this->config().fan_speedup_time.value),
this->config().fan_speedup_time.value > 0,
this->config().use_relative_e_distances.value,
this->config().fan_speedup_overhangs.value,
- this->config().fan_kickstart.value));
+ (float)this->config().fan_kickstart.value));
what = this->m_fan_mover->process_gcode(what, flush);
}
@@ -3680,7 +3699,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string &descri
double mult2 = 1 - coeff;
double sum = 0;
//Create a point
- Point inter_point1 = line.point_at(scale_(length1));
+ Point inter_point1 = line.point_at(scale_d(length1));
//extrude very reduced
gcode += m_writer.extrude_to_xy(
this->point_to_gcode(inter_point1),
@@ -3689,7 +3708,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string &descri
sum += e_per_mm * (length1) * mult1;
if (line_length - length1 > length2) {
- Point inter_point2 = line.point_at(scale_(length2));
+ Point inter_point2 = line.point_at(scale_d(length2));
//extrude reduced
gcode += m_writer.extrude_to_xy(
this->point_to_gcode(inter_point2),
@@ -3737,6 +3756,102 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string &descri
return gcode;
}
+double_t GCode::_compute_speed_mm_per_sec(const ExtrusionPath& path, double speed) {
+
+ // set speed
+ if (speed < 0) {
+ //if speed == -1, then it's means "choose yourself, but if it's -1 < speed <0 , then it's a scaling from small_periemter.
+ //it's a bit hacky, so if you want to rework it, help yourself.
+ float factor = float(-speed);
+ if (path.role() == erPerimeter) {
+ speed = m_config.get_computed_value("perimeter_speed");
+ } else if (path.role() == erExternalPerimeter) {
+ speed = m_config.get_computed_value("external_perimeter_speed");
+ } else if (path.role() == erBridgeInfill) {
+ speed = m_config.get_computed_value("bridge_speed");
+ } else if (path.role() == erInternalBridgeInfill) {
+ speed = m_config.get_computed_value("bridge_speed_internal");
+ } else if (path.role() == erOverhangPerimeter) {
+ speed = m_config.get_computed_value("overhangs_speed");
+ } else if (path.role() == erInternalInfill) {
+ speed = m_config.get_computed_value("infill_speed");
+ } else if (path.role() == erSolidInfill) {
+ speed = m_config.get_computed_value("solid_infill_speed");
+ } else if (path.role() == erTopSolidInfill) {
+ speed = m_config.get_computed_value("top_solid_infill_speed");
+ } else if (path.role() == erThinWall) {
+ speed = m_config.get_computed_value("thin_walls_speed");
+ } else if (path.role() == erGapFill) {
+ speed = m_config.get_computed_value("gap_fill_speed");
+ } else if (path.role() == erIroning) {
+ speed = m_config.get_computed_value("ironing_speed");
+ } else if (path.role() == erNone) {
+ speed = m_config.get_computed_value("travel_speed");
+ } else if (path.role() == erMilling) {
+ speed = m_config.get_computed_value("milling_speed");
+ } else {
+ throw Slic3r::InvalidArgument("Invalid speed");
+ }
+ //don't modify bridge speed
+ if (factor < 1 && !(is_bridge(path.role()))) {
+ float small_speed = (float)m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed);
+ //apply factor between feature speed and small speed
+ speed = (speed * factor) + double((1.f - factor) * small_speed);
+ }
+ }
+ if (m_volumetric_speed != 0. && speed == 0) {
+ //if m_volumetric_speed, use the max size for thinwall & gapfill, to avoid variations
+ double vol_speed = m_volumetric_speed / path.mm3_per_mm;
+ if (vol_speed > m_config.max_print_speed.value)
+ vol_speed = m_config.max_print_speed.value;
+ // if using a % of an auto speed, use the % over the volumetric speed.
+ if (path.role() == erExternalPerimeter) {
+ speed = m_config.external_perimeter_speed.get_abs_value(vol_speed);
+ } else if (path.role() == erInternalBridgeInfill) {
+ speed = m_config.bridge_speed_internal.get_abs_value(vol_speed);
+ } else if (path.role() == erOverhangPerimeter) {
+ speed = m_config.overhangs_speed.get_abs_value(vol_speed);
+ } else if (path.role() == erSolidInfill) {
+ speed = m_config.solid_infill_speed.get_abs_value(vol_speed);
+ } else if (path.role() == erTopSolidInfill) {
+ speed = m_config.top_solid_infill_speed.get_abs_value(vol_speed);
+ }
+ if (speed == 0) {
+ speed = vol_speed;
+ }
+ }
+ if (speed == 0) // this code shouldn't trigger as if it's 0, you have to get a m_volumetric_speed
+ speed = m_config.max_print_speed.value;
+ if (this->on_first_layer()) {
+ const double base_speed = speed;
+ if (path.role() == erInternalInfill || path.role() == erSolidInfill) {
+ double first_layer_infill_speed = m_config.first_layer_infill_speed.get_abs_value(base_speed);
+ if (first_layer_infill_speed > 0)
+ speed = std::min(first_layer_infill_speed, speed);
+ } else {
+ double first_layer_speed = m_config.first_layer_speed.get_abs_value(base_speed);
+ if (first_layer_speed > 0)
+ speed = std::min(first_layer_speed, speed);
+ }
+ double first_layer_min_speed = m_config.first_layer_min_speed.get_abs_value(base_speed);
+ speed = std::max(first_layer_min_speed, speed);
+ }
+ // cap speed with max_volumetric_speed anyway (even if user is not using autospeed)
+ if (m_config.max_volumetric_speed.value > 0 && path.mm3_per_mm > 0) {
+ speed = std::min(m_config.max_volumetric_speed.value / path.mm3_per_mm, speed);
+ }
+ double filament_max_volumetric_speed = EXTRUDER_CONFIG_WITH_DEFAULT(filament_max_volumetric_speed, 0);
+ if (filament_max_volumetric_speed > 0) {
+ speed = std::min(filament_max_volumetric_speed / path.mm3_per_mm, speed);
+ }
+ double filament_max_speed = EXTRUDER_CONFIG_WITH_DEFAULT(filament_max_speed, 0);
+ if (filament_max_speed > 0) {
+ speed = std::min(filament_max_speed, speed);
+ }
+
+ return speed;
+}
+
std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string &description_in, double speed) {
std::string gcode;
std::string description{ description_in };
@@ -3774,7 +3889,7 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
coordf_t length = poly_start.length();
if (length > SCALED_EPSILON) {
Polyline poly_end;
- coordf_t min_length = scale_(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.5)) * 20;
+ coordf_t min_length = scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.5)) * 20;
if (poly_start.size() > 2 && length > min_length * 3) {
//if complex travel, try to deccelerate only at the end, unless it's less than ~ 20 nozzle
if (poly_start.lines().back().length() < min_length) {
@@ -3813,92 +3928,7 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
// compensate retraction
gcode += this->unretract();
- // set speed
- if (speed < 0) {
- //if speed == -1, then it's means "choose yourself, but if it's -1 < speed <0 , then it's a scaling from small_periemter.
- //it's a bit hacky, so if you want to rework it, help yourself.
- float factor = (-speed);
- if (path.role() == erPerimeter) {
- speed = m_config.get_abs_value("perimeter_speed");
- } else if (path.role() == erExternalPerimeter) {
- speed = m_config.get_abs_value("external_perimeter_speed");
- } else if (path.role() == erBridgeInfill) {
- speed = m_config.get_abs_value("bridge_speed");
- } else if (path.role() == erInternalBridgeInfill) {
- speed = m_config.get_abs_value("bridge_speed_internal");
- } else if (path.role() == erOverhangPerimeter) {
- speed = m_config.get_abs_value("overhangs_speed");
- } else if (path.role() == erInternalInfill) {
- speed = m_config.get_abs_value("infill_speed");
- } else if (path.role() == erSolidInfill) {
- speed = m_config.get_abs_value("solid_infill_speed");
- } else if (path.role() == erTopSolidInfill) {
- speed = m_config.get_abs_value("top_solid_infill_speed");
- } else if (path.role() == erThinWall) {
- speed = m_config.get_abs_value("thin_walls_speed");
- } else if (path.role() == erGapFill) {
- speed = m_config.get_abs_value("gap_fill_speed");
- } else if (path.role() == erIroning) {
- speed = m_config.get_abs_value("ironing_speed");
- } else if (path.role() == erNone) {
- speed = m_config.get_abs_value("travel_speed");
- } else if (path.role() == erMilling) {
- speed = m_config.get_abs_value("milling_speed");
- } else {
- throw Slic3r::InvalidArgument("Invalid speed");
- }
- //don't modify bridge speed
- if (factor < 1 && !(is_bridge(path.role()))) {
- float small_speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed);
- //apply factor between feature speed and small speed
- speed = (speed * factor) + double((1.f - factor) * small_speed);
- }
- }
- if (m_volumetric_speed != 0. && speed == 0) {
- //if m_volumetric_speed, use the max size for thinwall & gapfill, to avoid variations
- double vol_speed = m_volumetric_speed / path.mm3_per_mm;
- if (vol_speed > m_config.max_print_speed.value)
- vol_speed = m_config.max_print_speed.value;
- // if using a % of an auto speed, use the % over the volumetric speed.
- if (path.role() == erExternalPerimeter) {
- speed = m_config.get_abs_value("external_perimeter_speed", vol_speed);
- } else if (path.role() == erInternalBridgeInfill) {
- speed = m_config.get_abs_value("bridge_speed_internal", vol_speed);
- } else if (path.role() == erOverhangPerimeter) {
- speed = m_config.get_abs_value("overhangs_speed", vol_speed);
- } else if (path.role() == erSolidInfill) {
- speed = m_config.get_abs_value("solid_infill_speed", vol_speed);
- } else if (path.role() == erTopSolidInfill) {
- speed = m_config.get_abs_value("top_solid_infill_speed", vol_speed);
- }
- if(speed == 0){
- speed = vol_speed;
- }
- }
- if (speed == 0) // this code shouldn't trigger as if it's 0, you have to get a m_volumetric_speed
- speed = m_config.max_print_speed.value;
- if (this->on_first_layer())
- if (path.role() == erInternalInfill || path.role() == erSolidInfill) {
- double first_layer_infill_speed = m_config.get_abs_value("first_layer_infill_speed", speed);
- if(first_layer_infill_speed > 0)
- speed = std::min(first_layer_infill_speed, speed);
- } else {
- double first_layer_speed = m_config.get_abs_value("first_layer_speed", speed);
- if (first_layer_speed > 0)
- speed = std::min(first_layer_speed, speed);
- }
- // cap speed with max_volumetric_speed anyway (even if user is not using autospeed)
- if (m_config.max_volumetric_speed.value > 0 && path.mm3_per_mm > 0) {
- speed = std::min(m_config.max_volumetric_speed.value / path.mm3_per_mm, speed);
- }
- double filament_max_volumetric_speed = EXTRUDER_CONFIG_WITH_DEFAULT(filament_max_volumetric_speed, 0);
- if (filament_max_volumetric_speed > 0) {
- speed = std::min(filament_max_volumetric_speed / path.mm3_per_mm, speed);
- }
- double filament_max_speed = EXTRUDER_CONFIG_WITH_DEFAULT(filament_max_speed, 0);
- if (filament_max_speed > 0) {
- speed = std::min(filament_max_speed, speed);
- }
+ speed = _compute_speed_mm_per_sec(path, speed);
double F = speed * 60; // convert mm/sec to mm/min
// extrude arc or line
@@ -3965,7 +3995,9 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
std::string comment;
if (m_enable_cooling_markers) {
- if (is_bridge(path.role()))
+ if(path.role() == erInternalBridgeInfill)
+ gcode += ";_BRIDGE_INTERNAL_FAN_START\n";
+ else if (is_bridge(path.role()))
gcode += ";_BRIDGE_FAN_START\n";
else if (ExtrusionRole::erTopSolidInfill == path.role())
gcode += ";_TOP_FAN_START\n";
@@ -3984,7 +4016,9 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
std::string GCode::_after_extrude(const ExtrusionPath &path) {
std::string gcode;
if (m_enable_cooling_markers)
- if (is_bridge(path.role()))
+ if (path.role() == erInternalBridgeInfill)
+ gcode += ";_BRIDGE_INTERNAL_FAN_END\n";
+ else if (is_bridge(path.role()))
gcode += ";_BRIDGE_FAN_END\n";
else if (ExtrusionRole::erTopSolidInfill == path.role())
gcode += ";_TOP_FAN_END\n";
@@ -4274,9 +4308,9 @@ Vec2d GCode::point_to_gcode(const Point &point) const
// convert a model-space scaled point into G-code coordinates
Vec3d GCode::point_to_gcode(const Point &point, const coord_t z_offset) const {
Vec2d extruder_offset = EXTRUDER_CONFIG_WITH_DEFAULT(extruder_offset, Vec2d(0, 0)); //FIXME : mill ofsset
- Vec3d ret_vec(unscale_(point.x()) + m_origin.x() - extruder_offset.x(),
- unscale_(point.y()) + m_origin.y() - extruder_offset.y(),
- unscale_(z_offset));
+ Vec3d ret_vec(unscaled(point.x()) + m_origin.x() - extruder_offset.x(),
+ unscaled(point.y()) + m_origin.y() - extruder_offset.y(),
+ unscaled(z_offset));
return ret_vec;
}
diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp
index a116d5dfe..a5bfb881e 100644
--- a/src/libslic3r/GCode.hpp
+++ b/src/libslic3r/GCode.hpp
@@ -23,6 +23,7 @@
#include <memory>
#include <map>
#include <string>
+#include <chrono>
#ifdef HAS_PRESSURE_EQUALIZER
#include "GCode/PressureEqualizer.hpp"
@@ -342,7 +343,7 @@ private:
AvoidCrossingPerimeters m_avoid_crossing_perimeters;
bool m_enable_loop_clipping;
// If enabled, the G-code generator will put following comments at the ends
- // of the G-code lines: _EXTRUDE_SET_SPEED, _WIPE, _BRIDGE_FAN_START, _BRIDGE_FAN_END
+ // of the G-code lines: _EXTRUDE_SET_SPEED, _WIPE, _BRIDGE_FAN_START, _BRIDGE_FAN_END, _BRIDGE_INTERNAL_FAN_START, _BRIDGE_INTERNAL_FAN_END
// Those comments are received and consumed (removed from the G-code) by the CoolingBuffer.pm Perl module.
bool m_enable_cooling_markers;
// Markers for the Pressure Equalizer to recognize the extrusion type.
@@ -409,6 +410,9 @@ private:
bool m_silent_time_estimator_enabled;
+ //for gui status update
+ std::chrono::time_point<std::chrono::system_clock> m_last_status_update;
+
// Processor
GCodeProcessor m_processor;
@@ -430,6 +434,7 @@ private:
std::string _extrude(const ExtrusionPath &path, const std::string &description, double speed = -1);
std::string _before_extrude(const ExtrusionPath &path, const std::string &description, double speed = -1);
+ double_t _compute_speed_mm_per_sec(const ExtrusionPath& path, double speed = -1);
std::string _after_extrude(const ExtrusionPath &path);
void print_machine_envelope(FILE *file, Print &print);
void _print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, uint16_t first_printing_extruder_id, bool wait);
diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp
index f9abd92d0..0a3a3eabb 100644
--- a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp
+++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp
@@ -483,7 +483,7 @@ static bool need_wipe(const GCode &gcodegen,
// called by get_perimeter_spacing() / get_perimeter_spacing_external()
static inline float get_default_perimeter_spacing(const PrintObject &print_object)
{
- std::vector<uint16_t> printing_extruders = print_object.object_extruders();
+ std::set<uint16_t> printing_extruders = print_object.object_extruders();
assert(!printing_extruders.empty());
float avg_extruder = 0;
for(uint16_t extruder_id : printing_extruders)
diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp
index b96fee5df..1cd36d8a3 100644
--- a/src/libslic3r/GCode/CoolingBuffer.cpp
+++ b/src/libslic3r/GCode/CoolingBuffer.cpp
@@ -34,22 +34,24 @@ void CoolingBuffer::reset()
struct CoolingLine
{
- enum Type {
+ enum Type : uint32_t {
TYPE_SET_TOOL = 1 << 0,
TYPE_EXTRUDE_END = 1 << 1,
TYPE_BRIDGE_FAN_START = 1 << 2,
TYPE_BRIDGE_FAN_END = 1 << 3,
- TYPE_TOP_FAN_START = 1 << 4,
- TYPE_TOP_FAN_END = 1 << 5,
- TYPE_G0 = 1 << 6,
- TYPE_G1 = 1 << 7,
- TYPE_ADJUSTABLE = 1 << 8,
- TYPE_EXTERNAL_PERIMETER = 1 << 9,
+ TYPE_BRIDGE_INTERNAL_FAN_START = 1 << 4,
+ TYPE_BRIDGE_INTERNAL_FAN_END = 1 << 5,
+ TYPE_TOP_FAN_START = 1 << 6,
+ TYPE_TOP_FAN_END = 1 << 7,
+ TYPE_G0 = 1 << 8,
+ TYPE_G1 = 1 << 9,
+ TYPE_ADJUSTABLE = 1 << 10,
+ TYPE_EXTERNAL_PERIMETER = 1 << 11,
// The line sets a feedrate.
- TYPE_HAS_F = 1 << 10,
- TYPE_WIPE = 1 << 11,
- TYPE_G4 = 1 << 12,
- TYPE_G92 = 1 << 13,
+ TYPE_HAS_F = 1 << 12,
+ TYPE_WIPE = 1 << 13,
+ TYPE_G4 = 1 << 14,
+ TYPE_G92 = 1 << 15,
};
CoolingLine(unsigned int type, size_t line_start, size_t line_end) :
@@ -487,6 +489,10 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
line.type = CoolingLine::TYPE_BRIDGE_FAN_START;
} else if (boost::starts_with(sline, ";_BRIDGE_FAN_END")) {
line.type = CoolingLine::TYPE_BRIDGE_FAN_END;
+ } else if (boost::starts_with(sline, ";_BRIDGE_INTERNAL_FAN_START")) {
+ line.type = CoolingLine::TYPE_BRIDGE_INTERNAL_FAN_START;
+ } else if (boost::starts_with(sline, ";_BRIDGE_INTERNAL_FAN_END")) {
+ line.type = CoolingLine::TYPE_BRIDGE_INTERNAL_FAN_END;
} else if (boost::starts_with(sline, ";_TOP_FAN_START")) {
line.type = CoolingLine::TYPE_TOP_FAN_START;
} else if (boost::starts_with(sline, ";_TOP_FAN_END")) {
@@ -735,22 +741,27 @@ std::string CoolingBuffer::apply_layer_cooldown(
int fan_speed = -1;
bool bridge_fan_control = false;
int bridge_fan_speed = 0;
+ bool bridge_internal_fan_control = false;
+ int bridge_internal_fan_speed = 0;
bool top_fan_control = false;
int top_fan_speed = 0;
bool ext_peri_fan_control = false;
int ext_peri_fan_speed = 0;
- auto change_extruder_set_fan = [this, layer_id, layer_time, &new_gcode, &fan_speed, &bridge_fan_control, &bridge_fan_speed, &top_fan_control, &top_fan_speed, &ext_peri_fan_control, &ext_peri_fan_speed]() {
+ auto change_extruder_set_fan = [this, layer_id, layer_time, &new_gcode, &fan_speed, &bridge_fan_control, &bridge_fan_speed, &bridge_internal_fan_control, &bridge_internal_fan_speed, &top_fan_control, &top_fan_speed, &ext_peri_fan_control, &ext_peri_fan_speed]() {
const FullPrintConfig &config = m_gcodegen.config();
#define EXTRUDER_CONFIG(OPT) config.OPT.get_at(m_current_extruder)
int min_fan_speed = EXTRUDER_CONFIG(min_fan_speed);
bridge_fan_speed = EXTRUDER_CONFIG(bridge_fan_speed);
+ bridge_internal_fan_speed = EXTRUDER_CONFIG(bridge_internal_fan_speed);
top_fan_speed = EXTRUDER_CONFIG(top_fan_speed);
ext_peri_fan_speed = EXTRUDER_CONFIG(external_perimeter_fan_speed);
// 0 is deprecated for disable: take care of temp settings.
if (bridge_fan_speed == 0) bridge_fan_speed = -1;
+ if (bridge_internal_fan_speed == 0) bridge_internal_fan_speed = -1;
if (ext_peri_fan_speed == 0) ext_peri_fan_speed = -1;
if (top_fan_speed == 0) top_fan_speed = -1;
if (bridge_fan_speed == 1) bridge_fan_speed = 0;
+ if (bridge_internal_fan_speed == 1) bridge_internal_fan_speed = 0;
if (ext_peri_fan_speed == 1) ext_peri_fan_speed = 0;
if (top_fan_speed == 1) top_fan_speed = 0;
// end deprecation
@@ -771,6 +782,8 @@ std::string CoolingBuffer::apply_layer_cooldown(
fan_speed_new = int(floor(t * min_fan_speed + (1. - t) * max_fan_speed) + 0.5);
if (bridge_fan_speed >= 0 && bridge_fan_speed < max_fan_speed)
bridge_fan_speed = int(floor(t * bridge_fan_speed + (1. - t) * max_fan_speed) + 0.5);
+ if (bridge_internal_fan_speed >= 0 && bridge_internal_fan_speed < max_fan_speed)
+ bridge_internal_fan_speed = int(floor(t * bridge_internal_fan_speed + (1. - t) * max_fan_speed) + 0.5);
if (top_fan_speed >= 0 && top_fan_speed < max_fan_speed)
top_fan_speed = int(floor(t * top_fan_speed + (1. - t) * max_fan_speed) + 0.5);
if (ext_peri_fan_speed >= 0 && ext_peri_fan_speed < max_fan_speed)
@@ -787,16 +800,27 @@ std::string CoolingBuffer::apply_layer_cooldown(
// Ramp up the fan speed from disable_fan_first_layers to full_fan_speed_layer.
float factor = float(int(layer_id + 1) - disable_fan_first_layers) / float(full_fan_speed_layer - disable_fan_first_layers);
fan_speed_new = clamp(0, 255, int(float(fan_speed_new ) * factor + 0.5f));
- if(bridge_fan_speed >= 0)
+ if (bridge_fan_speed >= 0)
bridge_fan_speed = clamp(0, 255, int(float(bridge_fan_speed) * factor + 0.5f));
+ if (bridge_internal_fan_speed >= 0)
+ bridge_internal_fan_speed = clamp(0, 255, int(float(bridge_internal_fan_speed) * factor + 0.5f));
}
#undef EXTRUDER_CONFIG
bridge_fan_control = bridge_fan_speed > fan_speed_new && bridge_fan_speed >= 0;
+ bridge_internal_fan_control = bridge_internal_fan_speed > fan_speed_new && bridge_internal_fan_speed >= 0;
top_fan_control = top_fan_speed != fan_speed_new && top_fan_speed >= 0;
ext_peri_fan_control = ext_peri_fan_speed != fan_speed_new && ext_peri_fan_speed >= 0;
+ // if bridge_internal_fan is disabled, it takes teh value of bridge_fan_control
+ if (!bridge_internal_fan_control && bridge_fan_control) {
+ bridge_internal_fan_control = true;
+ bridge_internal_fan_speed = bridge_fan_speed;
+ }
+
} else {
bridge_fan_control = false;
bridge_fan_speed = 0;
+ bridge_internal_fan_control = false;
+ bridge_internal_fan_speed = 0;
top_fan_control = false;
top_fan_speed = 0;
ext_peri_fan_control = false;
@@ -837,6 +861,16 @@ std::string CoolingBuffer::apply_layer_cooldown(
fan_need_set = true;
current_fan_sections.erase(CoolingLine::TYPE_BRIDGE_FAN_START);
}
+ } else if (line->type & CoolingLine::TYPE_BRIDGE_INTERNAL_FAN_START) {
+ if (bridge_internal_fan_control && current_fan_sections.find(CoolingLine::TYPE_BRIDGE_INTERNAL_FAN_START) == current_fan_sections.end()) {
+ fan_need_set = true;
+ current_fan_sections.insert(CoolingLine::TYPE_BRIDGE_INTERNAL_FAN_START);
+ }
+ } else if (line->type & CoolingLine::TYPE_BRIDGE_INTERNAL_FAN_END) {
+ if (bridge_internal_fan_control || current_fan_sections.find(CoolingLine::TYPE_BRIDGE_INTERNAL_FAN_START) != current_fan_sections.end()) {
+ fan_need_set = true;
+ current_fan_sections.erase(CoolingLine::TYPE_BRIDGE_INTERNAL_FAN_START);
+ }
} else if (line->type & CoolingLine::TYPE_TOP_FAN_START) {
if (top_fan_control && current_fan_sections.find(CoolingLine::TYPE_TOP_FAN_START) == current_fan_sections.end()) {
fan_need_set = true;
@@ -931,8 +965,10 @@ std::string CoolingBuffer::apply_layer_cooldown(
}
if (fan_need_set) {
//choose the speed with highest priority
- if(current_fan_sections.find(CoolingLine::TYPE_BRIDGE_FAN_START) != current_fan_sections.end())
+ if (current_fan_sections.find(CoolingLine::TYPE_BRIDGE_FAN_START) != current_fan_sections.end())
new_gcode += m_gcodegen.writer().set_fan(bridge_fan_speed);
+ else if (current_fan_sections.find(CoolingLine::TYPE_BRIDGE_INTERNAL_FAN_START) != current_fan_sections.end())
+ new_gcode += m_gcodegen.writer().set_fan(bridge_internal_fan_speed);
else if (current_fan_sections.find(CoolingLine::TYPE_TOP_FAN_START) != current_fan_sections.end())
new_gcode += m_gcodegen.writer().set_fan(top_fan_speed);
else if (current_fan_sections.find(CoolingLine::TYPE_EXTERNAL_PERIMETER) != current_fan_sections.end())
diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp
index 51e6fbb7a..9dcd96975 100644
--- a/src/libslic3r/GCode/GCodeProcessor.cpp
+++ b/src/libslic3r/GCode/GCodeProcessor.cpp
@@ -581,7 +581,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
#endif // ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
if (m_flavor != gcfMarlin) {
- double time_estimation_compensation = config.get_abs_value("time_estimation_compensation");
+ double time_estimation_compensation = config.get_computed_value("time_estimation_compensation");
for (auto& machine : this->m_time_processor.machines) {
machine.time_acceleration = float(time_estimation_compensation);
}
@@ -678,7 +678,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
}
}
- if (m_flavor == gcfMarlin) {
+ const ConfigOptionEnum<MachineLimitsUsage>* machine_limits_usage = config.option<ConfigOptionEnum<MachineLimitsUsage>>("machine_limits_usage");
+ if (machine_limits_usage && machine_limits_usage->value != MachineLimitsUsage::Ignore) {
const ConfigOptionFloats* machine_max_acceleration_x = config.option<ConfigOptionFloats>("machine_max_acceleration_x");
if (machine_max_acceleration_x != nullptr)
m_time_processor.machine_limits.machine_max_acceleration_x.values = machine_max_acceleration_x->values;
@@ -772,7 +773,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
}
if (m_flavor != gcfMarlin) {
- double time_estimation_compensation = config.get_abs_value("time_estimation_compensation");
+ double time_estimation_compensation = config.get_computed_value("time_estimation_compensation");
for (auto& machine : this->m_time_processor.machines) {
machine.time_acceleration = float(time_estimation_compensation);
}
@@ -940,7 +941,6 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
m_result.moves[i].layer_duration = 0;
}
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
- std::cout << "\n";
m_mm3_per_mm_compare.output();
m_height_compare.output();
m_width_compare.output();
@@ -1050,7 +1050,6 @@ void GCodeProcessor::process_klipper_ACTIVATE_EXTRUDER(const GCodeReader::GCodeL
void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
{
-/* std::cout << line.raw() << std::endl; */
// update start position
m_start_position = m_end_position;
@@ -1078,6 +1077,8 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
{
case 0: { process_G0(line); break; } // Move
case 1: { process_G1(line); break; } // Move
+ case 2: { process_G2_G3(line, false); break; } // Move
+ case 3: { process_G2_G3(line, true); break; } // Move
case 10: { process_G10(line); break; } // Retract
case 11: { process_G11(line); break; } // Unretract
case 20: { process_G20(line); break; } // Set Units to Inches
@@ -1876,6 +1877,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
if (type == EMoveType::Extrude && m_end_position[Z] == 0.0f)
type = EMoveType::Travel;
+ float height_saved = -1;
if (type == EMoveType::Extrude) {
double delta_xyz = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]));
#if !ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
@@ -1935,9 +1937,10 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
// cross section: rectangle + 2 semicircles
m_width = float(delta_pos[E] * (M_PI * sqr(filament_radius)) / (delta_xyz * m_height) + (1.0 - 0.25 * M_PI) * m_height);
- // if teh value seems wrong, fall back to circular extrusion from flow
+ // if the value seems wrong, fall back to circular extrusion from flow
if (m_width > m_height * 10 || m_width < m_height) {
m_width = 2 * std::sqrt(m_mm3_per_mm / float(PI));
+ height_saved = m_height;
m_height = m_width;
}
}
@@ -1952,7 +1955,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
// time estimate section
auto move_length = [](const AxisCoords& delta_pos) {
- float sq_xyz_length = (float)sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]);
+ float sq_xyz_length = (float)sqr(delta_pos[X]) + (float)sqr(delta_pos[Y]) + (float)sqr(delta_pos[Z]);
return (sq_xyz_length > 0.0f) ? std::sqrt(sq_xyz_length) : std::abs(delta_pos[E]);
};
@@ -2114,6 +2117,123 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
// store move
store_move_vertex(type);
+
+ //restore
+ if(height_saved > 0)
+ m_height = height_saved;
+}
+
+void GCodeProcessor::emit_G1_from_G2(Vec2d dest, float e, float f) {
+ GCodeReader::FakeGCodeLine line_fake;
+ line_fake.set_x(dest.x());
+ line_fake.set_y(dest.y());
+ //line_fake.set_z(dest.z());
+ line_fake.set_e(e);
+ if( f > 0)
+ line_fake.set_f(f);
+ process_G1(line_fake);
+}
+
+void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line, bool direct)
+{
+ //check it has everything
+ float i = 0, j = 0;
+ bool has_i = line.has_value('I', i);
+ bool has_j = line.has_value('J', j);
+ if(!((line.has_x() || line.has_y()) && (has_i || has_j)))
+ return;
+ //compute points
+ // compute mult factor
+ float lengthsScaleFactor = (m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f;
+ Vec2d p_start = { m_end_position[Axis::X], m_end_position[Axis::Y] };
+ Vec2d p_end = { line.x() * lengthsScaleFactor, line.y() * lengthsScaleFactor };
+ Vec2d p_center = { i * lengthsScaleFactor, j * lengthsScaleFactor };
+ p_center += p_start;
+ // if relative positioning
+ if ((m_global_positioning_type == EPositioningType::Relative)) {
+ Vec2d p_to_add = { m_start_position[Axis::X], m_start_position[Axis::Y] };
+ p_end += p_to_add;
+ p_center += p_to_add;
+ }
+ // get missing values
+ if (!line.has_x())
+ p_end.x() = p_start.x();
+ if (!line.has_y())
+ p_end.y() = p_start.y();
+ if (!has_i)
+ p_center.x() = p_start.x();
+ if (!has_j)
+ p_center.y() = p_start.y();
+
+ //compute angles
+ double min_dist = m_width == 0 ? 1 : m_width * 4;
+ const double pi2 = 2 * PI;
+ const double radius = (p_start - p_center).norm();
+ const double radius2 = (p_end - p_center).norm();
+ if (std::abs(radius - radius2) > min_dist*0.1) {
+ BOOST_LOG_TRIVIAL(error) << "error, radius from start & end are too different in command '" << line.raw() << "'.";
+ return;
+ }
+ Vec2d p_start_rel = p_start - p_center;
+ Vec2d p_end_rel = p_end - p_center;
+ const double a1 = atan2(p_start_rel.y(), p_start_rel.x());
+ const double a2 = atan2(p_end_rel.y(), p_end_rel.x());
+ double adiff = a2 - a1;
+ //if (a1 < 0)
+ // a1 += pi2;
+ //if (a2 < 0)
+ // a2 += pi2;
+ if (adiff > pi2)
+ adiff -= pi2;
+ if (adiff < -pi2)
+ adiff += pi2;
+ //check order
+ if (direct) {
+ if (adiff < 0)
+ adiff += pi2;
+ } else {
+ if (adiff > 0)
+ adiff -= pi2;
+ }
+ double distance = std::abs(adiff * radius);
+ //get E
+ float dE = 0;
+ float start_e = m_start_position[E];
+ bool e_relative = true;
+ if (line.has_e()) {
+ e_relative = (m_e_local_positioning_type == EPositioningType::Relative);
+ double ret = line.e() * lengthsScaleFactor;
+#if ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
+ if (m_use_volumetric_e) {
+ float filament_diameter = (static_cast<size_t>(m_extruder_id) < m_filament_diameters.size()) ? m_filament_diameters[m_extruder_id] : m_filament_diameters.back();
+ float filament_radius = 0.5f * filament_diameter;
+ double area_filament_cross_section = M_PI * sqr(filament_radius);
+ ret /= area_filament_cross_section;
+ }
+#endif // ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
+ dE = e_relative ? ret : m_origin[E] + ret - start_e;
+ }
+
+ //compute how much sections we need (~1 per 4 * width/nozzle)
+ int nb_sections = std::min(30, 1 + int(distance / min_dist));
+ Vec2d p_current = p_start;
+ float angle_incr = adiff / nb_sections;
+ float dE_incr = dE / nb_sections;
+ float current_angle = a1;
+ //create smaller sections
+ for (int i = 1; i < nb_sections;i++) {
+ current_angle += angle_incr;
+ p_current = { std::cos(current_angle) * radius, std::sin(current_angle) * radius };
+ p_current += p_center;
+ emit_G1_from_G2(p_current, e_relative ? dE_incr : start_e + i * dE_incr, line.has_f() ? line.f() : -1);
+ // update start position for next fake G1
+ m_start_position[X] = p_current.x();
+ m_start_position[Y] = p_current.y();
+ m_start_position[E] += dE_incr;
+ }
+ //emit last
+ emit_G1_from_G2(p_end, e_relative ? dE_incr : start_e + dE, line.has_f() ? line.f() : -1);
+
}
void GCodeProcessor::process_G10(const GCodeReader::GCodeLine& line)
@@ -2375,6 +2495,7 @@ void GCodeProcessor::process_M204(const GCodeReader::GCodeLine& line)
void GCodeProcessor::process_M205(const GCodeReader::GCodeLine& line)
{
+ // Note: Sprinter / Marlin gcode
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
if (static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i) == PrintEstimatedTimeStatistics::ETimeMode::Normal ||
m_time_processor.machine_envelope_processing_enabled) {
@@ -2460,6 +2581,7 @@ void GCodeProcessor::process_M402(const GCodeReader::GCodeLine& line)
void GCodeProcessor::process_M566(const GCodeReader::GCodeLine& line)
{
+ // RepRapFirmware gcode
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
if (line.has_x())
set_option_value(m_time_processor.machine_limits.machine_max_jerk_x, i, line.x() * MMMIN_TO_MMSEC);
diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp
index 8c1dfaf7e..d672fc5ea 100644
--- a/src/libslic3r/GCode/GCodeProcessor.hpp
+++ b/src/libslic3r/GCode/GCodeProcessor.hpp
@@ -507,6 +507,8 @@ namespace Slic3r {
// Move
void process_G0(const GCodeReader::GCodeLine& line);
void process_G1(const GCodeReader::GCodeLine& line);
+ void process_G2_G3(const GCodeReader::GCodeLine& line, bool direct);
+ void emit_G1_from_G2(Vec2d dest, float de, float f);
// Retract
void process_G10(const GCodeReader::GCodeLine& line);
diff --git a/src/libslic3r/GCodeReader.hpp b/src/libslic3r/GCodeReader.hpp
index d90a23160..cb20e2642 100644
--- a/src/libslic3r/GCodeReader.hpp
+++ b/src/libslic3r/GCodeReader.hpp
@@ -72,6 +72,14 @@ public:
uint32_t m_mask;
friend class GCodeReader;
};
+ class FakeGCodeLine : public GCodeLine {
+ public:
+ void set_x(float x) { m_axis[X] = x; m_mask = (m_mask | (1 << int(X))); }
+ void set_y(float y) { m_axis[Y] = y; m_mask = (m_mask | (1 << int(Y))); }
+ void set_z(float z) { m_axis[Z] = z; m_mask = (m_mask | (1 << int(Z))); }
+ void set_e(float e) { m_axis[E] = e; m_mask = (m_mask | (1 << int(E))); }
+ void set_f(float f) { m_axis[F] = f; m_mask = (m_mask | (1 << int(F))); }
+ };
typedef std::function<void(GCodeReader&, const GCodeLine&)> callback_t;
diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp
index e9ababa33..2211e521a 100644
--- a/src/libslic3r/GCodeWriter.cpp
+++ b/src/libslic3r/GCodeWriter.cpp
@@ -27,7 +27,7 @@ std::string to_string_nozero(double value, int32_t max_precision) {
//first, get the int part, to see how many digit it takes
int long10 = 0;
if (intpart > 9)
- long10 = std::floor(std::log10(std::abs(intpart)));
+ long10 = (int)std::floor(std::log10(std::abs(intpart)));
//set the usable precision: there is only 15-16 decimal digit in a double
ss << std::fixed << std::setprecision(int(std::min(15 - long10, int(max_precision)))) << value;
std::string ret = ss.str();
diff --git a/src/libslic3r/MedialAxis.cpp b/src/libslic3r/MedialAxis.cpp
index 9c2c9a21f..22a26950a 100644
--- a/src/libslic3r/MedialAxis.cpp
+++ b/src/libslic3r/MedialAxis.cpp
@@ -191,10 +191,14 @@ bool
MedialAxis::validate_edge(const VD::edge_type* edge, Lines &lines, std::map<const VD::edge_type*, std::pair<coordf_t, coordf_t> > &thickness)
{
// prevent overflows and detect almost-infinite edges
- if (std::abs(edge->vertex0()->x()) > double(CLIPPER_MAX_COORD_UNSCALED) ||
- std::abs(edge->vertex0()->y()) > double(CLIPPER_MAX_COORD_UNSCALED) ||
+ if (std::abs(edge->vertex0()->x()) > double(CLIPPER_MAX_COORD_UNSCALED) ||
+ std::abs(edge->vertex0()->y()) > double(CLIPPER_MAX_COORD_UNSCALED) ||
std::abs(edge->vertex1()->x()) > double(CLIPPER_MAX_COORD_UNSCALED) ||
- std::abs(edge->vertex1()->y()) > double(CLIPPER_MAX_COORD_UNSCALED))
+ std::abs(edge->vertex1()->y()) > double(CLIPPER_MAX_COORD_UNSCALED) ||
+ std::isnan(edge->vertex0()->x()) ||
+ std::isnan(edge->vertex0()->y()) ||
+ std::isnan(edge->vertex1()->x()) ||
+ std::isnan(edge->vertex1()->y()) )
return false;
// construct the line representing this edge of the Voronoi diagram
@@ -350,9 +354,9 @@ remove_point_too_near(ThickPolyline* to_reduce)
void
add_point_same_percent(ThickPolyline* pattern, ThickPolyline* to_modify)
{
- const double to_modify_length = to_modify->length();
+ const coordf_t to_modify_length = to_modify->length();
const double percent_epsilon = SCALED_EPSILON / to_modify_length;
- const double pattern_length = pattern->length();
+ const coordf_t pattern_length = pattern->length();
double percent_length = 0;
for (size_t idx_point = 1; idx_point < pattern->points.size() - 1; ++idx_point) {
@@ -390,10 +394,10 @@ add_point_same_percent(ThickPolyline* pattern, ThickPolyline* to_modify)
/// return 1 for an angle of 90° and 0 for an angle of 0° or 180°
double
get_coeff_from_angle_countour(Point &point, const ExPolygon &contour, coord_t min_dist_between_point) {
- double nearest_dist = point.distance_to(contour.contour.points.front());
+ coordf_t nearest_dist = point.distance_to(contour.contour.points.front());
Point point_nearest = contour.contour.points.front();
size_t id_nearest = 0;
- double near_dist = nearest_dist;
+ coordf_t near_dist = nearest_dist;
Point point_near = point_nearest;
size_t id_near = 0;
for (size_t id_point = 1; id_point < contour.contour.points.size(); ++id_point) {
@@ -581,8 +585,8 @@ MedialAxis::remove_bits(ThickPolylines &pp)
if (polyline.width.back() > 0) continue;
//check my length is small
- coord_t length = (coord_t)polyline.length();
- if (length > max_width*1.5) {
+ coordf_t length = polyline.length();
+ if (length > coordf_t(max_width) * 1.5) {
continue;
}
@@ -609,11 +613,11 @@ MedialAxis::remove_bits(ThickPolylines &pp)
if (nb_better_than_me < 2) continue;
//check if the length of the polyline is small vs width of the other lines
- double max_width = 0;
+ coord_t max_width = 0;
for (int i = 0; i < crosspoint.size(); i++) {
max_width = std::max(max_width, pp[crosspoint[i]].width[0]);
}
- if (length > max_width + min_width)
+ if (length > coordf_t(max_width + min_width))
continue;
//delete the now unused polyline
@@ -819,10 +823,10 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con
}*/
// find anchor
Point best_anchor;
- double shortest_dist = (double)max_width;
+ coordf_t shortest_dist = (coordf_t)max_width;
for (const ExPolygon& a : anchors) {
Point p_maybe_inside = a.contour.centroid();
- double test_dist = new_bound.distance_to(p_maybe_inside) + new_back.distance_to(p_maybe_inside);
+ coordf_t test_dist = new_bound.distance_to(p_maybe_inside) + new_back.distance_to(p_maybe_inside);
//if (test_dist < max_width / 2 && (test_dist < shortest_dist || shortest_dist < 0)) {
double angle_test = new_back.ccw_angle(p_maybe_inside, line.a);
if (angle_test > PI) angle_test = 2 * PI - angle_test;
@@ -1092,12 +1096,12 @@ MedialAxis::main_fusion(ThickPolylines& pp)
polyline.width[idx_point] = max_width;
//failsafe: try to not go out of the radius of the section, take the width of the merging point for that. (and with some offset)
coord_t main_branch_width = pp[biggest_main_branch_id].width.front();
- coord_t main_branch_dist = pp[biggest_main_branch_id].points.front().distance_to(polyline.points[idx_point]);
- coord_t max_width_from_main = std::sqrt(main_branch_width*main_branch_width + main_branch_dist*main_branch_dist);
+ coordf_t main_branch_dist = pp[biggest_main_branch_id].points.front().distance_to(polyline.points[idx_point]);
+ coord_t max_width_from_main = (coord_t)std::sqrt(main_branch_width*main_branch_width + main_branch_dist*main_branch_dist);
if (find_main_branch && polyline.width[idx_point] > max_width_from_main)
polyline.width[idx_point] = max_width_from_main;
if (find_main_branch && polyline.width[idx_point] > pp[biggest_main_branch_id].width.front() * 1.1)
- polyline.width[idx_point] = pp[biggest_main_branch_id].width.front() * 1.1;
+ polyline.width[idx_point] = coord_t(pp[biggest_main_branch_id].width.front() * 1.1);
//std::cout << "main fusion, max dist : " << max_width_from_main << "\n";
++idx_point;
@@ -1377,7 +1381,7 @@ MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_siz
while (changes) {
changes = false;
- double shortest_size = min_size;
+ coordf_t shortest_size = (coordf_t) min_size;
size_t shortest_idx = -1;
for (size_t i = 0; i < pp.size(); ++i) {
ThickPolyline& polyline = pp[i];
@@ -1403,19 +1407,19 @@ MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_siz
}
void
-MedialAxis::check_width(ThickPolylines& pp, double max_width, std::string msg)
+MedialAxis::check_width(ThickPolylines& pp, coord_t max_width, std::string msg)
{
//remove empty polyline
int nb = 0;
for (size_t i = 0; i < pp.size(); ++i) {
for (size_t j = 0; j < pp[i].width.size(); ++j) {
- if (pp[i].width[j] > max_width * 1.01) {
- std::cout << "Error " << msg << " width " << unscaled(pp[i].width[j]) << "(" << i << ":" << j << ") > " << unscaled(max_width) << "\n";
+ if (pp[i].width[j] > coord_t(max_width * 1.01)) {
+ BOOST_LOG_TRIVIAL(error) << "Error " << msg << " width " << unscaled(pp[i].width[j]) << "(" << i << ":" << j << ") > " << unscaled(max_width) << "\n";
nb++;
}
}
}
- if (nb > 0) std::cout << "== nbBig = " << nb << " ==\n";
+ if (nb > 0) BOOST_LOG_TRIVIAL(error) << "== nbBig = " << nb << " ==\n";
}
void
@@ -1428,7 +1432,7 @@ MedialAxis::ensure_not_overextrude(ThickPolylines& pp)
for (ThickPolyline& polyline : pp) {
for (ThickLine &l : polyline.thicklines()) {
surface += l.length() * (l.a_width + l.b_width) / 2;
- double width_mean = (l.a_width + l.b_width) / 2;
+ coord_t width_mean = (l.a_width + l.b_width) / 2;
volume += height * (width_mean - height * (1. - 0.25 * PI)) * l.length();
}
}
@@ -1449,8 +1453,8 @@ MedialAxis::ensure_not_overextrude(ThickPolylines& pp)
//reduce width
double reduce_by = boundsVolume / volume;
for (ThickPolyline& polyline : pp) {
- for (coordf_t &width : polyline.width) {
- width *= reduce_by;
+ for (coord_t &width : polyline.width) {
+ width = coord_t( double(width) * reduce_by);
}
}
}
@@ -1511,9 +1515,10 @@ MedialAxis::grow_to_nozzle_diameter(ThickPolylines& pp, const ExPolygons& anchor
//compute the min width
coord_t min_width = this->nozzle_diameter;
if (this->height > 0) min_width = Flow::new_from_spacing(
- float(unscale_(this->nozzle_diameter)),
- float(unscale_(this->nozzle_diameter)),
- float(unscale_(this->height)), false).scaled_width();
+ float(unscaled(this->nozzle_diameter)),
+ float(unscaled(this->nozzle_diameter)),
+ float(unscaled(this->height)),
+ false).scaled_width();
//ensure the width is not lower than min_width.
for (ThickPolyline& polyline : pp) {
for (int i = 0; i < polyline.points.size(); ++i) {
@@ -1534,8 +1539,8 @@ void
MedialAxis::taper_ends(ThickPolylines& pp)
{
// minimum size of the taper: be sure to extrude at least the "round edges" of the extrusion (0-spacing extrusion).
- const coord_t min_size = std::max(this->nozzle_diameter * 0.1, this->height * (1. - 0.25 * PI));
- const coordf_t length = std::min(this->taper_size, (this->nozzle_diameter - min_size) / 2);
+ const coord_t min_size = (coord_t) std::max(this->nozzle_diameter * 0.1, this->height * (1. - 0.25 * PI));
+ const coordf_t length = (coordf_t) std::min(this->taper_size, (this->nozzle_diameter - min_size) / 2);
if (length <= SCALED_RESOLUTION) return;
//ensure the width is not lower than min_size.
for (ThickPolyline& polyline : pp) {
@@ -1589,9 +1594,9 @@ check_circular(ExPolygon& expolygon, coord_t max_variation) {
if (expolygon.contour.concave_points().empty() && expolygon.contour.points.size() > 3) {
// Computing circle center
Point center = expolygon.contour.centroid();
- double radius_min = std::numeric_limits<float>::max(), radius_max = 0;
+ coordf_t radius_min = std::numeric_limits<float>::max(), radius_max = 0;
for (int i = 0; i < expolygon.contour.points.size(); ++i) {
- double dist = expolygon.contour.points[i].distance_to(center);
+ coordf_t dist = expolygon.contour.points[i].distance_to(center);
radius_min = std::min(radius_min, dist);
radius_max = std::max(radius_max, dist);
}
@@ -1630,7 +1635,7 @@ MedialAxis::build(ThickPolylines &polylines_out)
if (this->expolygon.area() < this->min_width * this->min_width) return;
//check for circular shape
- double radius = check_circular(this->expolygon, this->min_width/4);
+ coordf_t radius = check_circular(this->expolygon, this->min_width/4);
if (radius > 0 && this->expolygon.contour.points.size() > 4) {
ExPolygons miniPeri = offset_ex(this->expolygon.contour, -radius / 2);
if (miniPeri.size() == 1 && miniPeri[0].holes.size() == 0) {
@@ -1738,9 +1743,9 @@ MedialAxis::build(ThickPolylines &polylines_out)
/* Find the maximum width returned; we're going to use this for validating and
filtering the output segments. */
- double max_w = 0;
+ coord_t max_w = 0;
for (ThickPolylines::const_iterator it = pp.begin(); it != pp.end(); ++it)
- max_w = std::max(max_w, *std::max_element(it->width.begin(), it->width.end()));
+ max_w = std::max(max_w, (coord_t)*std::max_element(it->width.begin(), it->width.end()));
//for (auto &p : pp) {
// std::cout << "Start polyline : ";
@@ -1843,7 +1848,7 @@ MedialAxis::build(ThickPolylines &polylines_out)
// svg.Close();
//}
- remove_too_short_polylines(pp, (coord_t)max_w * 2);
+ remove_too_short_polylines(pp, max_w * 2);
//{
// std::stringstream stri;
// stri << "medial_axis_8_tooshort_" << id << ".svg";
@@ -1903,7 +1908,7 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
// this value determines granularity of adaptive width, as G-code does not allow
// variable extrusion within a single move; this value shall only affect the amount
// of segments, and any pruning shall be performed before we apply this tolerance
- const double tolerance = 4*SCALED_RESOLUTION;//scale_(0.05);
+ const coord_t tolerance = 4 * SCALED_RESOLUTION;//scale_(0.05);
ExtrusionEntityCollection coll;
for (const ThickPolyline &p : polylines) {
@@ -1919,16 +1924,16 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
assert(line.a_width >= 0);
assert(line.b_width >= 0);
- double thickness_delta = fabs(line.a_width - line.b_width);
- if (thickness_delta > tolerance && ceil(thickness_delta / tolerance) > 2) {
- const uint16_t segments = 1+(uint16_t) std::min(16000.0, ceil(thickness_delta / tolerance));
+ coord_t thickness_delta = std::abs(line.a_width - line.b_width);
+ if (thickness_delta > tolerance && ceil(float(thickness_delta) / float(tolerance)) > 2) {
+ const uint16_t segments = 1 + (uint16_t) std::min((uint32_t)16000, (uint32_t)ceil(float(thickness_delta) / float(tolerance)));
Points pp;
std::vector<coordf_t> width;
{
for (size_t j = 0; j < segments; ++j) {
pp.push_back(line.a.interpolate(((double)j) / segments, line.b));
double percent_width = ((double)j) / (segments-1);
- width.push_back(line.a_width*(1 - percent_width) + line.b_width*percent_width);
+ width.push_back(line.a_width * (1 - percent_width) + line.b_width * percent_width);
}
pp.push_back(line.b);
diff --git a/src/libslic3r/MedialAxis.hpp b/src/libslic3r/MedialAxis.hpp
index bc208e3f5..69bd94268 100644
--- a/src/libslic3r/MedialAxis.hpp
+++ b/src/libslic3r/MedialAxis.hpp
@@ -109,7 +109,7 @@ class MedialAxis {
/// taper the ends of polylines (don't activate that for gapfill)
void taper_ends(ThickPolylines& pp);
//cleaning method
- void check_width(ThickPolylines& pp, double max_width, std::string msg);
+ void check_width(ThickPolylines& pp, coord_t max_width, std::string msg);
//removing small extrusion that won't be useful and will harm print. A bit like fusion_corners but more lenient and with just del.
void remove_bits(ThickPolylines& pp);
};
diff --git a/src/libslic3r/Milling/MillingPostProcess.cpp b/src/libslic3r/Milling/MillingPostProcess.cpp
index 4e40ce553..50147de21 100644
--- a/src/libslic3r/Milling/MillingPostProcess.cpp
+++ b/src/libslic3r/Milling/MillingPostProcess.cpp
@@ -8,7 +8,7 @@ namespace Slic3r {
void MillingPostProcess::getExtrusionLoop(const Layer* layer, Polygon& poly, Polylines& entrypoints, ExtrusionEntityCollection& out_coll) {
- const double milling_diameter = scale_(this->print_config->milling_diameter.get_at(0));
+ const coord_t milling_diameter = scale_t(this->print_config->milling_diameter.get_at(0));
//get the longest polyline
Polyline best_polyline;
@@ -22,8 +22,8 @@ namespace Slic3r {
//get two pair of points that are at less than max_dist.
int32_t first_point_extract_idx = 1;
int32_t first_point_idx = -1;
- const double dist_max_square = milling_diameter * milling_diameter / 4;
- double best_dist = dist_max_square;
+ const coordf_t dist_max_square = coordf_t(milling_diameter) * coordf_t(milling_diameter / 4);
+ coordf_t best_dist = dist_max_square;
for (int32_t idx = 0; idx < poly.points.size(); idx++) {
if (poly.points[idx].distance_to_square(best_polyline.points[first_point_extract_idx]) < best_dist) {
best_dist = poly.points[idx].distance_to_square(best_polyline.points[first_point_extract_idx]);
@@ -91,7 +91,7 @@ namespace Slic3r {
if (contour.polyline.points.size() > 3)
contour.polyline.points.push_back(contour.polyline.points[1]);
contour.mm3_per_mm = 0;
- contour.width = this->print_config->milling_diameter.get_at(0);
+ contour.width = (float)this->print_config->milling_diameter.get_at(0);
contour.height = (float)layer->height;
out_coll.append(std::move(contour));
return;
@@ -102,18 +102,18 @@ namespace Slic3r {
{
if (!can_be_milled(layer)) return ExtrusionEntityCollection();
- const double milling_diameter = scale_(this->print_config->milling_diameter.get_at(0));
+ const coord_t milling_diameter = scale_t(this->print_config->milling_diameter.get_at(0));
ExPolygons milling_lines;
for (const Surface& surf : slices->surfaces) {
- ExPolygons surf_milling = offset_ex(surf.expolygon, milling_diameter/2, ClipperLib::jtRound);
+ ExPolygons surf_milling = offset_ex(surf.expolygon, double(milling_diameter / 2), ClipperLib::jtRound);
for (const ExPolygon& expoly : surf_milling)
// expoly.simplify(SCALED_RESOLUTION, &milling_lines); // should already be done
milling_lines.push_back(expoly);
}
milling_lines = union_ex(milling_lines);
- ExPolygons secured_points = offset_ex(milling_lines, milling_diameter / 3);
+ ExPolygons secured_points = offset_ex(milling_lines, double(milling_diameter / 3));
ExPolygons entrypoints;
for (const ExPolygon& expoly : secured_points)
// expoly.simplify(SCALED_RESOLUTION, &entrypoints); // should already be done
@@ -137,8 +137,11 @@ namespace Slic3r {
}
bool MillingPostProcess::can_be_milled(const Layer* layer) {
+ double max_first_layer = 0;
+ for (double diam : this->print_config->nozzle_diameter.values)
+ max_first_layer = std::max(max_first_layer, config->milling_after_z.get_abs_value(this->object_config->first_layer_height.get_abs_value(diam)));
return !print_config->milling_diameter.values.empty() && config->milling_post_process
- && layer->bottom_z() >= config->milling_after_z.get_abs_value(this->object_config->first_layer_height.get_abs_value(this->print_config->nozzle_diameter.values.front()));
+ && layer->bottom_z() >= max_first_layer;
}
ExPolygons MillingPostProcess::get_unmillable_areas(const Layer* layer)
diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp
index 0255e278b..00f199e02 100644
--- a/src/libslic3r/PlaceholderParser.cpp
+++ b/src/libslic3r/PlaceholderParser.cpp
@@ -666,6 +666,85 @@ namespace client
return opt;
}
+
+ // copy of ConfigBase::get_computed_value
+ double get_computed_value(const t_config_option_key& opt_key) const
+ {
+ // Get stored option value.
+ const ConfigOption* raw_opt = this->optptr(opt_key);
+ if (raw_opt == nullptr) {
+ std::stringstream ss; ss << "You can't define an option that need " << opt_key << " without defining it!";
+ throw std::runtime_error(ss.str());
+ }
+
+ if (!raw_opt->is_vector()) {
+ if (raw_opt->type() == coFloat)
+ return static_cast<const ConfigOptionFloat*>(raw_opt)->value;
+ if (raw_opt->type() == coInt)
+ return static_cast<const ConfigOptionInt*>(raw_opt)->value;
+ if (raw_opt->type() == coBool)
+ return static_cast<const ConfigOptionBool*>(raw_opt)->value ? 1 : 0;
+ const ConfigOptionDef* opt_def = nullptr;
+ const ConfigOptionPercent* cast_opt = nullptr;
+ if (raw_opt->type() == coFloatOrPercent) {
+ if (!static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->percent)
+ return static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->value;
+ // Get option definition.
+ opt_def = print_config_def.get(opt_key);
+ cast_opt = static_cast<const ConfigOptionFloatOrPercent*>(raw_opt);
+ assert(opt_def != nullptr);
+ }
+ if (raw_opt->type() == coPercent) {
+ // Get option definition.
+ opt_def = print_config_def.get(opt_key);
+ assert(opt_def != nullptr);
+ cast_opt = static_cast<const ConfigOptionPercent*>(raw_opt);
+ }
+ if (opt_def != nullptr) {
+ //if over no other key, it's most probably a simple %
+ if (opt_def->ratio_over == "")
+ return cast_opt->get_abs_value(1);
+ // Compute absolute value over the absolute value of the base option.
+ //FIXME there are some ratio_over chains, which end with empty ratio_with.
+ // For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly.
+ if (!opt_def->ratio_over.empty() && opt_def->ratio_over != "depends")
+ return cast_opt->get_abs_value(this->get_computed_value(opt_def->ratio_over));
+
+ std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " has no valid ratio_over to compute of";
+ throw ConfigurationError(ss.str());
+ }
+ } else {
+ // check if it's an extruder_id array
+ const ConfigOptionVectorBase* vector_opt = static_cast<const ConfigOptionVectorBase*>(raw_opt);
+ if (vector_opt->is_extruder_size()) {
+
+ if (raw_opt->type() == coFloats || raw_opt->type() == coInts || raw_opt->type() == coBools)
+ return vector_opt->getFloat(current_extruder_id);
+ if (raw_opt->type() == coFloatsOrPercents) {
+ const ConfigOptionFloatsOrPercents* opt_fl_per = static_cast<const ConfigOptionFloatsOrPercents*>(raw_opt);
+ if (!opt_fl_per->values[current_extruder_id].percent)
+ return opt_fl_per->values[current_extruder_id].value;
+
+ const ConfigOptionDef* opt_def = print_config_def.get(opt_key);
+ if (!opt_def->ratio_over.empty() && opt_def->ratio_over != "depends")
+ return opt_fl_per->get_abs_value(current_extruder_id, this->get_computed_value(opt_def->ratio_over));
+ std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " has no valid ratio_over to compute of";
+ throw ConfigurationError(ss.str());
+ }
+ if (raw_opt->type() == coPercents) {
+ const ConfigOptionPercents* opt_per = static_cast<const ConfigOptionPercents*>(raw_opt);
+ const ConfigOptionDef* opt_def = print_config_def.get(opt_key);
+ if (!opt_def->ratio_over.empty() && opt_def->ratio_over != "depends")
+ return opt_per->get_abs_value(current_extruder_id, this->get_computed_value(opt_def->ratio_over));
+ std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " has no valid ratio_over to compute of";
+ throw ConfigurationError(ss.str());
+ }
+ }
+ }
+ std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " has not a valid option type for get_abs_value()";
+ throw ConfigurationError(ss.str());
+ }
+
const ConfigOption* resolve_symbol(const std::string &opt_key) const { return this->optptr(opt_key); }
template <typename Iterator>
@@ -754,8 +833,13 @@ namespace client
OptWithPos<Iterator> &opt,
expr<Iterator> &output)
{
- if (opt.opt->is_vector())
- ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range);
+ std::string opt_key(opt.it_range.begin(), opt.it_range.end());
+ if (opt.opt->is_vector()) {
+ const ConfigOptionDef* opt_def = print_config_def.get(opt_key);
+ if (!opt_def->is_vector_extruder)
+ ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range);
+ }
+ const ConfigOptionDef* opt_def;
switch (opt.opt->type()) {
case coFloat: output.set_d(opt.opt->getFloat()); break;
case coInt: output.set_i(opt.opt->getInt()); break;
@@ -765,7 +849,6 @@ namespace client
case coBool: output.set_b(opt.opt->getBool()); break;
case coFloatOrPercent:
{
- std::string opt_key(opt.it_range.begin(), opt.it_range.end());
if (boost::ends_with(opt_key, "extrusion_width")) {
// Extrusion width use the first nozzle diameter
output.set_d(Flow::extrusion_width(opt_key, *ctx, static_cast<unsigned int>(ctx->current_extruder_id)));
@@ -774,7 +857,7 @@ namespace client
output.set_d(opt.opt->getFloat());
} else {
// Resolve dependencies using the "ratio_over" link to a parent value.
- const ConfigOptionDef *opt_def = print_config_def.get(opt_key);
+ opt_def = print_config_def.get(opt_key);
assert(opt_def != nullptr);
double v = opt.opt->getFloat() * 0.01; // percent to ratio
for (;;) {
@@ -787,20 +870,53 @@ namespace client
v *= Flow::extrusion_width(opt_def->ratio_over, static_cast<const ConfigOptionFloatOrPercent*>(opt_parent), *ctx, static_cast<unsigned int>(ctx->current_extruder_id));
break;
}
- if (opt_parent->type() == coFloat || opt_parent->type() == coFloatOrPercent) {
- v *= opt_parent->getFloat();
- if (opt_parent->type() == coFloat || ! static_cast<const ConfigOptionFloatOrPercent*>(opt_parent)->percent)
- break;
- v *= 0.01; // percent to ratio
- }
- // Continue one level up in the "ratio_over" hierarchy.
- opt_def = print_config_def.get(opt_def->ratio_over);
- assert(opt_def != nullptr);
+ double val = ctx->get_computed_value(opt_def->ratio_over);
+ v *= val;
+ break;
+ // if (opt_parent->type() == coFloat || opt_parent->type() == coFloatOrPercent) {
+ // v *= opt_parent->getFloat();
+ // if (opt_parent->type() == coFloat || ! static_cast<const ConfigOptionFloatOrPercent*>(opt_parent)->percent)
+ // break;
+ // v *= 0.01; // percent to ratio
+ //}
+ //// Continue one level up in the "ratio_over" hierarchy.
+ //opt_def = print_config_def.get(opt_def->ratio_over);
+ //assert(opt_def != nullptr);
}
output.set_d(v);
}
break;
}
+ case coInts:
+ opt_def = print_config_def.get(opt_key);
+ if (opt_def->is_vector_extruder) {
+ output.set_i((int)((ConfigOptionVectorBase*)opt.opt)->getFloat(ctx->current_extruder_id));
+ break;
+ } else
+ ctx->throw_exception("Unknown scalar variable type", opt.it_range);
+ case coFloats:
+ case coPercents:
+ opt_def = print_config_def.get(opt_key);
+ if (opt_def->is_vector_extruder) {
+ output.set_d(((ConfigOptionVectorBase*)opt.opt)->getFloat(ctx->current_extruder_id));
+ break;
+ } else
+ ctx->throw_exception("Unknown scalar variable type", opt.it_range);
+ case coStrings:
+ opt_def = print_config_def.get(opt_key);
+ if (opt_def->is_vector_extruder) {
+ output.set_s(((ConfigOptionStrings*)opt.opt)->values[ctx->current_extruder_id]);
+ break;
+ } else
+ ctx->throw_exception("Unknown scalar variable type", opt.it_range);
+ case coPoints:
+ opt_def = print_config_def.get(opt_key);
+ if (opt_def->is_vector_extruder) {
+ output.set_s(to_string(((ConfigOptionPoints*)opt.opt)->values[ctx->current_extruder_id]));
+ break;
+ }else
+ ctx->throw_exception("Unknown scalar variable type", opt.it_range);
+ //TODO: coFloatOrPercents
default:
ctx->throw_exception("Unknown scalar variable type", opt.it_range);
}
diff --git a/src/libslic3r/Polyline.hpp b/src/libslic3r/Polyline.hpp
index b13317323..d3250484a 100644
--- a/src/libslic3r/Polyline.hpp
+++ b/src/libslic3r/Polyline.hpp
@@ -24,7 +24,9 @@ public:
explicit Polyline(const Points &points) : MultiPoint(points) {}
explicit Polyline(Points &&points) : MultiPoint(std::move(points)) {}
Polyline& operator=(const Polyline &other) { points = other.points; return *this; }
- Polyline& operator=(Polyline &&other) { points = std::move(other.points); return *this; }
+ Polyline& operator=(Polyline&& other) { points = std::move(other.points); return *this; }
+ bool operator==(const Polyline& other) const { return points == other.points; }
+ bool operator!=(const Polyline& other) const { return points != other.points; }
static Polyline new_scale(const std::vector<Vec2d> &points) {
Polyline pl;
pl.points.reserve(points.size());
@@ -152,7 +154,7 @@ class ThickPolyline : public Polyline {
public:
enum StartPos : int8_t{tpspBegin = -1, tpspBoth = 0, tpspEnd = 1};
/// width size must be == point size
- std::vector<coordf_t> width;
+ std::vector<coord_t> width;
/// if true => it's an endpoint, if false it join an other ThickPolyline. first is at front(), second is at back()
std::pair<bool, bool> endpoints;
//if it's important to begin at a specific bit.
diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp
index 482cdc43d..66ae0080f 100644
--- a/src/libslic3r/Preset.cpp
+++ b/src/libslic3r/Preset.cpp
@@ -502,6 +502,7 @@ const std::vector<std::string>& Preset::print_options()
// speeds
"external_perimeter_speed",
"first_layer_speed",
+ "first_layer_min_speed",
"infill_speed",
"perimeter_speed",
"small_perimeter_speed",
@@ -597,6 +598,7 @@ const std::vector<std::string>& Preset::print_options()
"hole_size_threshold",
"hole_to_polyhole",
"hole_to_polyhole_threshold",
+ "hole_to_polyhole_twisted",
"threads",
// wipe tower
"wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging",
@@ -673,6 +675,7 @@ const std::vector<std::string>& Preset::filament_options()
"min_fan_speed",
"max_fan_speed",
"bridge_fan_speed",
+ "bridge_internal_fan_speed",
"top_fan_speed",
"disable_fan_first_layers",
"fan_below_layer_time",
@@ -683,7 +686,7 @@ const std::vector<std::string>& Preset::filament_options()
"external_perimeter_fan_speed",
// Retract overrides
"filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel",
- "filament_retract_layer_change", "filament_wipe", "filament_wipe_extra_perimeter", "filament_retract_before_wipe",
+ "filament_retract_layer_change", "filament_wipe", "filament_wipe_speed", "filament_wipe_extra_perimeter", "filament_retract_before_wipe",
// Profile compatibility
"filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits"
//merill adds
@@ -722,11 +725,14 @@ const std::vector<std::string>& Preset::printer_options()
"fan_speedup_overhangs",
"fan_speedup_time",
"fan_percentage",
- "gcode_flavor",
+ "gcode_filename_illegal_char",
+ "gcode_flavor",
"gcode_precision_xyz",
+ "gcode_precision_e",
"use_relative_e_distances",
"use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
"min_length",
+ "max_gcode_per_second",
//FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset.
"host_type", "print_host", "printhost_apikey", "printhost_cafile", "printhost_port",
"single_extruder_multi_material",
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index 6b5008893..767eae486 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -81,6 +81,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
"between_objects_gcode",
"bridge_acceleration",
"bridge_fan_speed",
+ "bridge_internal_fan_speed",
"colorprint_heights",
"complete_objects_sort",
"cooling",
@@ -117,15 +118,18 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
"first_layer_flow_ratio",
"first_layer_speed",
"first_layer_infill_speed",
+ "first_layer_min_speed",
"full_fan_speed_layer",
"gap_fill_speed",
"gcode_comments",
+ "gcode_filename_illegal_char",
"gcode_label_objects",
"gcode_precision_xyz",
"gcode_precision_e",
"infill_acceleration",
"layer_gcode",
"max_fan_speed",
+ "max_gcode_per_second",
"max_print_height",
"max_print_speed",
"max_volumetric_speed",
@@ -180,6 +184,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
"use_volumetric_e",
"variable_layer_height",
"wipe",
+ "wipe_speed",
"wipe_extra_perimeter"
};
@@ -350,10 +355,9 @@ bool Print::is_step_done(PrintObjectStep step) const
}
// returns 0-based indices of used extruders
-std::vector<uint16_t> Print::object_extruders(const PrintObjectPtrs &objects) const
+std::set<uint16_t> Print::object_extruders(const PrintObjectPtrs &objects) const
{
- std::vector<uint16_t> extruders;
- extruders.reserve(m_regions.size() * 3);
+ std::set<uint16_t> extruders;
std::vector<unsigned char> region_used(m_regions.size(), false);
for (const PrintObject *object : objects)
for (const std::vector<std::pair<t_layer_height_range, int>> &volumes_per_region : object->region_volumes)
@@ -362,14 +366,13 @@ std::vector<uint16_t> Print::object_extruders(const PrintObjectPtrs &objects) co
for (size_t idx_region = 0; idx_region < m_regions.size(); ++ idx_region)
if (region_used[idx_region])
m_regions[idx_region]->collect_object_printing_extruders(extruders);
- sort_remove_duplicates(extruders);
return extruders;
}
// returns 0-based indices of used extruders
-std::vector<uint16_t> Print::support_material_extruders() const
+std::set<uint16_t> Print::support_material_extruders() const
{
- std::vector<uint16_t> extruders;
+ std::set<uint16_t> extruders;
bool support_uses_current_extruder = false;
auto num_extruders = (uint16_t)m_config.nozzle_diameter.size();
@@ -380,7 +383,7 @@ std::vector<uint16_t> Print::support_material_extruders() const
support_uses_current_extruder = true;
else {
uint16_t i = (uint16_t)object->config().support_material_extruder - 1;
- extruders.emplace_back((i >= num_extruders) ? 0 : i);
+ extruders.insert((i >= num_extruders) ? 0 : i);
}
if (object->config().support_material_interface_layers > 0) {
assert(object->config().support_material_interface_extruder >= 0);
@@ -388,7 +391,7 @@ std::vector<uint16_t> Print::support_material_extruders() const
support_uses_current_extruder = true;
else {
uint16_t i = (uint16_t)object->config().support_material_interface_extruder - 1;
- extruders.emplace_back((i >= num_extruders) ? 0 : i);
+ extruders.insert((i >= num_extruders) ? 0 : i);
}
}
}
@@ -398,16 +401,14 @@ std::vector<uint16_t> Print::support_material_extruders() const
// Add all object extruders to the support extruders as it is not know which one will be used to print supports.
append(extruders, this->object_extruders(m_objects));
- sort_remove_duplicates(extruders);
return extruders;
}
// returns 0-based indices of used extruders
-std::vector<uint16_t> Print::extruders() const
+std::set<uint16_t> Print::extruders() const
{
- std::vector<uint16_t> extruders = this->object_extruders(m_objects);
+ std::set<uint16_t> extruders = this->object_extruders(m_objects);
append(extruders, this->support_material_extruders());
- sort_remove_duplicates(extruders);
return extruders;
}
@@ -1279,6 +1280,8 @@ bool Print::has_skirt() const
static inline bool sequential_print_horizontal_clearance_valid(const Print &print)
{
+ if (print.config().extruder_clearance_radius == 0)
+ return true;
Polygons convex_hulls_other;
std::map<ObjectID, Polygon> map_model_object_to_convex_hull;
const double dist_grow = PrintConfig::min_object_distance(&print.default_region_config()) * 2;
@@ -1365,6 +1368,41 @@ static inline bool sequential_print_vertical_clearance_valid(const Print &print)
return it == print_instances_ordered.end() || (*it)->print_object->height() <= scale_(print.config().extruder_clearance_height.value);
}
+
+double Print::get_object_first_layer_height(const PrintObject& object) const {
+ std::set<uint16_t> object_extruders;
+ for (size_t region_id = 0; region_id < object.region_volumes.size(); ++region_id) {
+ if (object.region_volumes[region_id].empty()) continue;
+ const PrintRegion* region = this->regions()[region_id];
+ PrintRegion::collect_object_printing_extruders(config(), object.config(), region->config(), object_extruders);
+ }
+ //get object first layer height
+ double object_first_layer_height = object.config().first_layer_height.value;
+ if (object.config().first_layer_height.percent) {
+ object_first_layer_height = 1000000000;
+ for (uint16_t extruder_id : object_extruders) {
+ double nozzle_diameter = config().nozzle_diameter.values[extruder_id];
+ object_first_layer_height = std::min(object_first_layer_height, object.config().first_layer_height.get_abs_value(nozzle_diameter));
+ }
+ }
+ return object_first_layer_height;
+}
+
+double Print::get_first_layer_height() const
+{
+ if (m_objects.empty())
+ throw Slic3r::InvalidArgument("first_layer_height() can't be called without PrintObjects");
+
+ double min_layer_height = 10000000000.;
+ for(PrintObject* obj : m_objects)
+ min_layer_height = std::fmin(min_layer_height, get_object_first_layer_height(*obj));
+
+ if(min_layer_height == 10000000000.)
+ throw Slic3r::InvalidArgument("first_layer_height() can't be computed");
+
+ return min_layer_height;
+}
+
// Precondition: Print::validate() requires the Print::apply() to be called its invocation.
std::pair<PrintBase::PrintValidationError, std::string> Print::validate() const
{
@@ -1401,8 +1439,8 @@ std::pair<PrintBase::PrintValidationError, std::string> Print::validate() const
if (this->has_wipe_tower() && ! m_objects.empty()) {
// Make sure all extruders use same diameter filament and have the same nozzle diameter
// EPSILON comparison is used for nozzles and 10 % tolerance is used for filaments
- double first_nozzle_diam = m_config.nozzle_diameter.get_at(extruders().front());
- double first_filament_diam = m_config.filament_diameter.get_at(extruders().front());
+ double first_nozzle_diam = m_config.nozzle_diameter.get_at(*extruders().begin());
+ double first_filament_diam = m_config.filament_diameter.get_at(*extruders().begin());
for (const auto& extruder_idx : extruders()) {
double nozzle_diam = m_config.nozzle_diameter.get_at(extruder_idx);
double filament_diam = m_config.filament_diameter.get_at(extruder_idx);
@@ -1502,7 +1540,7 @@ std::pair<PrintBase::PrintValidationError, std::string> Print::validate() const
}
{
- std::vector<uint16_t> extruders = this->extruders();
+ std::set<uint16_t> extruders = this->extruders();
// Find the smallest used nozzle diameter and the number of unique nozzle diameters.
double min_nozzle_diameter = std::numeric_limits<double>::max();
@@ -1522,6 +1560,7 @@ std::pair<PrintBase::PrintValidationError, std::string> Print::validate() const
return L("One or more object were assigned an extruder that the printer does not have.");
#endif
+ const double print_first_layer_height = get_first_layer_height();
for (PrintObject *object : m_objects) {
if (object->config().raft_layers > 0 || object->config().support_material.value) {
if ((object->config().support_material_extruder == 0 || object->config().support_material_interface_extruder == 0) && max_nozzle_diameter - min_nozzle_diameter > EPSILON) {
@@ -1545,50 +1584,49 @@ std::pair<PrintBase::PrintValidationError, std::string> Print::validate() const
}
}
}
-
+
+ const double object_first_layer_height = get_object_first_layer_height(*object);
// validate layer_height for each region
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++region_id) {
if (object->region_volumes[region_id].empty()) continue;
const PrintRegion* region = this->regions()[region_id];
- std::vector<uint16_t> object_extruders;
+ std::set<uint16_t> object_extruders;
PrintRegion::collect_object_printing_extruders(config(), object->config(), region->config(), object_extruders);
- //object->region_volumes[region_id].front().first.second < object->layers()
double layer_height = object->config().layer_height.value;
for (uint16_t extruder_id : object_extruders) {
double min_layer_height = config().min_layer_height.values[extruder_id];
double max_layer_height = config().max_layer_height.values[extruder_id];
double nozzle_diameter = config().nozzle_diameter.values[extruder_id];
- double first_layer_height = object->config().first_layer_height.get_abs_value(nozzle_diameter);
if (max_layer_height < EPSILON) max_layer_height = nozzle_diameter * 0.75;
-
+ double skirt_width = Flow::new_from_config_width(frPerimeter, *Flow::extrusion_option("skirt_extrusion_width", m_default_region_config), (float)m_config.nozzle_diameter.get_at(extruder_id), print_first_layer_height).width;
//check first layer
- if (object->region_volumes[region_id].front().first.first < first_layer_height) {
- if (first_layer_height + EPSILON < min_layer_height)
- return { PrintBase::PrintValidationError::pveWrongSettings, (boost::format(L("First layer height can't be greater than %s")) % "min layer height").str() };
+ if (object->region_volumes[region_id].front().first.first < object_first_layer_height) {
+ if (object_first_layer_height + EPSILON < min_layer_height)
+ return { PrintBase::PrintValidationError::pveWrongSettings, (boost::format(L("First layer height can't be thinner than %s")) % "min layer height").str() };
for (auto tuple : std::vector<std::pair<double, const char*>>{
{nozzle_diameter, "nozzle diameter"},
{max_layer_height, "max layer height"},
- {skirt_flow(extruder_id).width, "skirt extrusion width"},
- {region->width(FlowRole::frSupportMaterial, true, *object), "support material extrusion width"},
+ {skirt_width, "skirt extrusion width"},
+ {object->config().support_material ? region->width(FlowRole::frSupportMaterial, true, *object) : object_first_layer_height, "support material extrusion width"},
{region->width(FlowRole::frPerimeter, true, *object), "perimeter extrusion width"},
{region->width(FlowRole::frExternalPerimeter, true, *object), "perimeter extrusion width"},
{region->width(FlowRole::frInfill, true, *object), "infill extrusion width"},
{region->width(FlowRole::frSolidInfill, true, *object), "solid infill extrusion width"},
{region->width(FlowRole::frTopSolidInfill, true, *object), "top solid infill extrusion width"},
})
- if (first_layer_height > tuple.first + EPSILON)
+ if (object_first_layer_height > tuple.first + EPSILON)
return { PrintBase::PrintValidationError::pveWrongSettings, (boost::format(L("First layer height can't be greater than %s")) % tuple.second).str() };
}
//check not-first layer
if (object->region_volumes[region_id].front().first.second > layer_height) {
if (layer_height + EPSILON < min_layer_height)
- return { PrintBase::PrintValidationError::pveWrongSettings, (boost::format(L("First layer height can't be greater than %s")) % "min layer height").str() };
+ return { PrintBase::PrintValidationError::pveWrongSettings, (boost::format(L("First layer height can't be higher than %s")) % "min layer height").str() };
for (auto tuple : std::vector<std::pair<double, const char*>>{
{nozzle_diameter, "nozzle diameter"},
{max_layer_height, "max layer height"},
- {skirt_flow(extruder_id).width, "skirt extrusion width"},
- {region->width(FlowRole::frSupportMaterial, false, *object), "support material extrusion width"},
+ {skirt_width, "skirt extrusion width"},
+ {object->config().support_material ? region->width(FlowRole::frSupportMaterial, false, *object) : layer_height, "support material extrusion width"},
{region->width(FlowRole::frPerimeter, false, *object), "perimeter extrusion width"},
{region->width(FlowRole::frExternalPerimeter, false, *object), "perimeter extrusion width"},
{region->width(FlowRole::frInfill, false, *object), "infill extrusion width"},
@@ -1670,13 +1708,6 @@ BoundingBox Print::total_bounding_box() const
}
#endif
-double Print::skirt_first_layer_height() const
-{
- if (m_objects.empty())
- throw Slic3r::InvalidArgument("skirt_first_layer_height() can't be called without PrintObjects");
- return m_objects.front()->config().get_abs_value("first_layer_height");
-}
-
Flow Print::brim_flow(size_t extruder_id, const PrintObjectConfig& brim_config) const
{
//use default region, but current object config.
@@ -1686,18 +1717,44 @@ Flow Print::brim_flow(size_t extruder_id, const PrintObjectConfig& brim_config)
frPerimeter,
*Flow::extrusion_option("brim_extrusion_width", tempConf),
(float)m_config.nozzle_diameter.get_at(extruder_id),
- (float)this->skirt_first_layer_height()
+ (float)get_first_layer_height()
);
}
-Flow Print::skirt_flow(size_t extruder_id) const
+Flow Print::skirt_flow(size_t extruder_id, bool first_layer/*=false*/) const
{
+ if (m_objects.empty())
+ throw Slic3r::InvalidArgument("skirt_first_layer_height() can't be called without PrintObjects");
+
+ //get extruder used to compute first layer height
+ double max_nozzle_diam;
+ for (PrintObject* pobject : m_objects) {
+ PrintObject& object = *pobject;
+ std::set<uint16_t> object_extruders;
+ for (size_t region_id = 0; region_id < object.region_volumes.size(); ++region_id) {
+ if (object.region_volumes[region_id].empty()) continue;
+ const PrintRegion* region = this->regions()[region_id];
+ PrintRegion::collect_object_printing_extruders(config(), object.config(), region->config(), object_extruders);
+ }
+ //get object first layer extruder
+ int first_layer_extruder = 0;
+ double object_first_layer_height = object.config().first_layer_height.value;
+ if (object.config().first_layer_height.percent) {
+ object_first_layer_height = 1000000000;
+ for (uint16_t extruder_id : object_extruders) {
+ double nozzle_diameter = config().nozzle_diameter.values[extruder_id];
+ max_nozzle_diam = std::max(max_nozzle_diam, nozzle_diameter);
+ }
+ }
+ }
+
+
//send m_default_object_config becasue it's the lowest config needed (extrusion_option need config from object & print)
return Flow::new_from_config_width(
frPerimeter,
*Flow::extrusion_option("skirt_extrusion_width", m_default_region_config),
- (float)m_config.nozzle_diameter.get_at(extruder_id),
- (float)this->skirt_first_layer_height()
+ (float)max_nozzle_diam,
+ (float)get_first_layer_height()
);
}
@@ -1829,10 +1886,9 @@ void Print::process()
if (config().complete_objects && !config().complete_objects_one_brim) {
for (PrintObject *obj : obj_group) {
//get flow
- std::vector<uint16_t> set_extruders = this->object_extruders({ obj });
+ std::set<uint16_t> set_extruders = this->object_extruders({ obj });
append(set_extruders, this->support_material_extruders());
- sort_remove_duplicates(set_extruders);
- Flow flow = this->brim_flow(set_extruders.empty() ? m_regions.front()->config().perimeter_extruder - 1 : set_extruders.front(), obj->config());
+ Flow flow = this->brim_flow(set_extruders.empty() ? m_regions.front()->config().perimeter_extruder - 1 : *set_extruders.begin(), obj->config());
//don't consider other objects/instances. It's not possible because it's duplicated by some code afterward... i think.
brim_area.clear();
//create a brim "pattern" (one per object)
@@ -1854,10 +1910,9 @@ void Print::process()
if (obj_groups.size() > 1)
brim_area = union_ex(brim_area);
//get the first extruder in the list for these objects... replicating gcode generation
- std::vector<uint16_t> set_extruders = this->object_extruders(m_objects);
+ std::set<uint16_t> set_extruders = this->object_extruders(m_objects);
append(set_extruders, this->support_material_extruders());
- sort_remove_duplicates(set_extruders);
- Flow flow = this->brim_flow(set_extruders.empty() ? m_regions.front()->config().perimeter_extruder - 1 : set_extruders.front(), m_default_object_config);
+ Flow flow = this->brim_flow(set_extruders.empty() ? m_regions.front()->config().perimeter_extruder - 1 : *set_extruders.begin(), m_default_object_config);
if (brim_config.brim_ears)
this->_make_brim_ears(flow, obj_group, brim_area, m_brim);
else
@@ -1970,15 +2025,12 @@ void Print::_make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollectio
// Skirt may be printed on several layers, having distinct layer heights,
// but loops must be aligned so can't vary width/spacing
- // TODO: use each extruder's own flow
- double first_layer_height = this->skirt_first_layer_height();
std::vector<size_t> extruders;
std::vector<double> extruders_e_per_mm;
{
- std::vector<uint16_t> set_extruders = this->object_extruders(objects);
+ std::set<uint16_t> set_extruders = this->object_extruders(objects);
append(set_extruders, this->support_material_extruders());
- sort_remove_duplicates(set_extruders);
extruders.reserve(set_extruders.size());
extruders_e_per_mm.reserve(set_extruders.size());
for (unsigned int extruder_id : set_extruders) {
@@ -2033,7 +2085,7 @@ void Print::_make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollectio
erSkirt,
(float)mm3_per_mm, // this will be overridden at G-code export time
flow.width,
- (float)first_layer_height // this will be overridden at G-code export time
+ (float)get_first_layer_height() // this will be overridden at G-code export time
)));
eloop.paths.back().polyline = loop.split_at_first_point();
//we make it clowkwise, but as it will be reversed, it will be ccw
@@ -2076,7 +2128,7 @@ void Print::_make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollectio
append(m_skirt_convex_hull, std::move(poly.points));
}
-void Print::_extrude_brim_from_tree(std::vector<std::vector< BrimLoop>>& loops, const Polygons& frontiers, const Flow& flow, ExtrusionEntityCollection& out, bool reversed/*= false*/) {
+void Print::_extrude_brim_from_tree(std::vector<std::vector<BrimLoop>>& loops, const Polygons& frontiers, const Flow& flow, ExtrusionEntityCollection& out, bool reversed/*= false*/) {
// nest contour loops (same as in perimetergenerator)
for (int d = loops.size() - 1; d >= 1; --d) {
@@ -2089,8 +2141,8 @@ void Print::_extrude_brim_from_tree(std::vector<std::vector< BrimLoop>>& loops,
for (size_t j = 0; j < loops[t].size(); ++j) {
BrimLoop& candidate_parent = loops[t][j];
bool test = reversed
- ? loop.polygon().contains(candidate_parent.line.first_point())
- : candidate_parent.polygon().contains(loop.line.first_point());
+ ? loop.polygon().contains(candidate_parent.lines.front().first_point())
+ : candidate_parent.polygon().contains(loop.lines.front().first_point());
if (test) {
candidate_parent.children.push_back(loop);
contours_d.erase(contours_d.begin() + i);
@@ -2106,28 +2158,35 @@ void Print::_extrude_brim_from_tree(std::vector<std::vector< BrimLoop>>& loops,
NEXT_CONTOUR:;
}
}
+ for (int i = loops.size() - 1; i > 0; --i) {
+ if (loops[i].empty()) {
+ loops.erase(loops.begin() + i);
+ }
+ }
//def
//cut loops if they go inside a forbidden region
- std::function<void(BrimLoop&)> cut_loop = [&frontiers](BrimLoop& to_cut) {
+ std::function<void(BrimLoop&)> cut_loop = [&frontiers, reversed](BrimLoop& to_cut) {
Polylines result;
- if (to_cut.is_loop)
+ if (to_cut.is_loop) {
result = intersection_pl(Polygons{ to_cut.polygon() }, frontiers, true);
- else
- result = intersection_pl(Polylines{ to_cut.line }, frontiers, true);
- if (result.empty())
- to_cut.line.points.clear();
- else {
- if (to_cut.line.points != result[0].points) {
- to_cut.line.points = result[0].points;
+ } else {
+ result = intersection_pl(to_cut.lines, frontiers, true);
+ }
+ if (result.empty()) {
+ to_cut.lines.clear();
+ } else {
+ if (to_cut.lines != result) {
+ to_cut.lines = result;
+ if (reversed) {
+ std::reverse(to_cut.lines.begin(), to_cut.lines.end());
+ }
to_cut.is_loop = false;
}
- for (int i = 1; i < result.size(); i++)
- to_cut.children.insert(to_cut.children.begin() + i - 1, BrimLoop(std::move(result[i])));
}
};
- //calls
+ //calls, deep-first
std::list< std::pair<BrimLoop*,int>> cut_child_first;
for (std::vector<BrimLoop>& loops : loops) {
for (BrimLoop& loop : loops) {
@@ -2153,29 +2212,32 @@ void Print::_extrude_brim_from_tree(std::vector<std::vector< BrimLoop>>& loops,
//def: push into extrusions, in the right order
float mm3_per_mm = float(flow.mm3_per_mm());
float width = float(flow.width);
- float height = float(this->skirt_first_layer_height());
+ float height = float(get_first_layer_height());
int nextIdx = 0;
std::function<void(BrimLoop&, ExtrusionEntityCollection*)>* extrude_ptr;
std::function<void(BrimLoop&, ExtrusionEntityCollection*) > extrude = [&mm3_per_mm, &width, &height, &extrude_ptr, &nextIdx](BrimLoop& to_cut, ExtrusionEntityCollection* parent) {
int idx = nextIdx++;
- bool i_have_line = !to_cut.line.points.empty() && to_cut.line.is_valid();
+ //bool i_have_line = !to_cut.line.points.empty() && to_cut.line.is_valid();
+ bool i_have_line = to_cut.lines.size() > 0 && to_cut.lines.front().size() > 0 && to_cut.lines.front().is_valid();
if (!i_have_line && to_cut.children.empty()) {
//nothing
} else if (i_have_line && to_cut.children.empty()) {
- if (to_cut.line.points.back() == to_cut.line.points.front()) {
- ExtrusionPath path(erSkirt, mm3_per_mm, width, height);
- path.polyline.points = to_cut.line.points;
- parent->entities.emplace_back(new ExtrusionLoop(std::move(path), elrSkirt));
- } else {
- ExtrusionPath* extrusion_path = new ExtrusionPath(erSkirt, mm3_per_mm, width, height);
- parent->entities.push_back(extrusion_path);
- extrusion_path->polyline = to_cut.line;
- }
+ for(Polyline& line : to_cut.lines)
+ if (line.points.back() == line.points.front()) {
+ ExtrusionPath path(erSkirt, mm3_per_mm, width, height);
+ path.polyline.points = line.points;
+ parent->entities.emplace_back(new ExtrusionLoop(std::move(path), elrSkirt));
+ } else {
+ ExtrusionPath* extrusion_path = new ExtrusionPath(erSkirt, mm3_per_mm, width, height);
+ parent->entities.push_back(extrusion_path);
+ extrusion_path->polyline = line;
+ }
} else if (!i_have_line && !to_cut.children.empty()) {
if (to_cut.children.size() == 1) {
(*extrude_ptr)(to_cut.children[0], parent);
} else {
ExtrusionEntityCollection* mycoll = new ExtrusionEntityCollection();
+ //mycoll->no_sort = true;
parent->entities.push_back(mycoll);
for (BrimLoop& child : to_cut.children)
(*extrude_ptr)(child, mycoll);
@@ -2184,19 +2246,21 @@ void Print::_extrude_brim_from_tree(std::vector<std::vector< BrimLoop>>& loops,
ExtrusionEntityCollection* print_me_first = new ExtrusionEntityCollection();
parent->entities.push_back(print_me_first);
print_me_first->no_sort = true;
- if (to_cut.line.points.back() == to_cut.line.points.front()) {
- ExtrusionPath path(erSkirt, mm3_per_mm, width, height);
- path.polyline.points = to_cut.line.points;
- print_me_first->entities.emplace_back(new ExtrusionLoop(std::move(path), elrSkirt));
- } else {
- ExtrusionPath* extrusion_path = new ExtrusionPath(erSkirt, mm3_per_mm, width, height);
- print_me_first->entities.push_back(extrusion_path);
- extrusion_path->polyline = to_cut.line;
- }
+ for (Polyline& line : to_cut.lines)
+ if (line.points.back() == line.points.front()) {
+ ExtrusionPath path(erSkirt, mm3_per_mm, width, height);
+ path.polyline.points = line.points;
+ print_me_first->entities.emplace_back(new ExtrusionLoop(std::move(path), elrSkirt));
+ } else {
+ ExtrusionPath* extrusion_path = new ExtrusionPath(erSkirt, mm3_per_mm, width, height);
+ print_me_first->entities.push_back(extrusion_path);
+ extrusion_path->polyline = line;
+ }
if (to_cut.children.size() == 1) {
(*extrude_ptr)(to_cut.children[0], print_me_first);
} else {
ExtrusionEntityCollection* children = new ExtrusionEntityCollection();
+ //children->no_sort = true;
print_me_first->entities.push_back(children);
for (BrimLoop& child : to_cut.children)
(*extrude_ptr)(child, children);
@@ -2232,13 +2296,7 @@ void Print::_make_brim(const Flow &flow, const PrintObjectPtrs &objects, ExPolyg
if (!object->support_layers().empty()) {
Polygons polys = object->support_layers().front()->support_fills.polygons_covered_by_spacing(float(SCALED_EPSILON));
for (Polygon poly : polys) {
- for (ExPolygon& expoly2 : union_ex(Polygons{ poly })) {
- if (brim_config.brim_inside_holes || brim_config.brim_width_interior > 0) {
- object_islands.emplace_back(brim_offset == 0 ? expoly2 : offset_ex(expoly2, brim_offset)[0]);
- } else {
- object_islands.emplace_back(brim_offset == 0 ? to_expolygon(expoly2.contour) : offset_ex(to_expolygon(expoly2.contour), brim_offset)[0]);
- }
- }
+ object_islands.emplace_back(brim_offset == 0 ? ExPolygon{ poly } : offset_ex(poly, brim_offset)[0]);
}
}
islands.reserve(islands.size() + object_islands.size() * object->m_instances.size());
@@ -2352,31 +2410,29 @@ void Print::_make_brim_ears(const Flow &flow, const PrintObjectPtrs &objects, Ex
if (!object->support_layers().empty()) {
Polygons polys = object->support_layers().front()->support_fills.polygons_covered_by_spacing(float(SCALED_EPSILON));
- for (Polygon poly : polys)
- for (ExPolygon& expoly2 : union_ex(Polygons{ poly }))
- //don't put ears over supports unless it's 100% fill
- if (object->config().support_material_solid_first_layer) {
- if (brim_config.brim_inside_holes || brim_config.brim_width_interior > 0)
- object_islands.push_back(brim_offset == 0 ? expoly2 : offset_ex(expoly2, brim_offset)[0]);
- else
- object_islands.emplace_back(brim_offset == 0 ? to_expolygon(expoly2.contour) : offset_ex(to_expolygon(expoly2.contour), brim_offset)[0]);
- } else {
- unbrimmable_with_support.push_back(expoly2);
- }
+ for (Polygon poly : polys) {
+ //don't put ears over supports unless it's 100% fill
+ if (object->config().support_material_solid_first_layer) {
+ object_islands.push_back(brim_offset == 0 ? ExPolygon{ poly } : offset_ex(poly, brim_offset)[0]);
+ } else {
+ unbrimmable_with_support.push_back(ExPolygon{ poly });
+ }
+ }
}
islands.reserve(islands.size() + object_islands.size() * object->m_instances.size());
+ coord_t ear_detection_length = scale_t(object->config().brim_ears_detection_length.value);
for (const PrintInstance &copy_pt : object->m_instances)
for (const ExPolygon &poly : object_islands) {
islands.push_back(poly);
islands.back().translate(copy_pt.shift.x(), copy_pt.shift.y());
Polygon decimated_polygon = poly.contour;
// brim_ears_detection_length codepath
- if (object->config().brim_ears_detection_length.value > 0) {
+ if (ear_detection_length > 0) {
//decimate polygon
Points points = poly.contour.points;
points.push_back(points.front());
- points = MultiPoint::_douglas_peucker(points, scale_(object->config().brim_ears_detection_length.value));
- if (points.size() > 1) {
+ points = MultiPoint::_douglas_peucker(points, ear_detection_length);
+ if (points.size() > 4) { //don't decimate if it's going to be below 4 points, as it's surely enough to fill everything anyway
points.erase(points.end() - 1);
decimated_polygon.points = points;
}
@@ -2457,7 +2513,7 @@ void Print::_make_brim_ears(const Flow &flow, const PrintObjectPtrs &objects, Ex
erSkirt,
float(flow.mm3_per_mm()),
float(flow.width),
- float(this->skirt_first_layer_height())
+ float(get_first_layer_height())
);
unbrimmable = union_ex(unbrimmable, offset_ex(mouse_ears_ex, flow.scaled_spacing()/2));
@@ -2507,15 +2563,17 @@ void Print::_make_brim_interior(const Flow &flow, const PrintObjectPtrs &objects
const PrintObjectConfig &brim_config = objects.front()->config();
coord_t brim_offset = scale_(brim_config.brim_offset.value);
ExPolygons islands;
+ coordf_t spacing;
for (PrintObject *object : objects) {
ExPolygons object_islands;
for (ExPolygon &expoly : object->m_layers.front()->lslices)
object_islands.push_back(brim_offset == 0 ? expoly : offset_ex(expoly, brim_offset)[0]);
if (!object->support_layers().empty()) {
- Polygons polys = object->support_layers().front()->support_fills.polygons_covered_by_spacing(float(SCALED_EPSILON));
- for (Polygon poly : polys)
- for (ExPolygon& expoly2 : union_ex(Polygons{ poly }))
- object_islands.push_back(brim_offset == 0 ? expoly2 : offset_ex(expoly2, brim_offset)[0]);
+ spacing = scaled(object->config().support_material_interface_spacing.value) + support_material_flow(object, float(get_first_layer_height())).scaled_width() * 1.5;
+ Polygons polys = offset2(object->support_layers().front()->support_fills.polygons_covered_by_spacing(float(SCALED_EPSILON)), spacing, -spacing);
+ for (Polygon poly : polys) {
+ object_islands.push_back(brim_offset == 0 ? ExPolygon{ poly } : offset_ex(poly, brim_offset)[0]);
+ }
}
islands.reserve(islands.size() + object_islands.size() * object->instances().size());
for (const PrintInstance &instance : object->instances())
@@ -2802,7 +2860,7 @@ void Print::_make_wipe_tower()
wipe_tower.set_extruder(i);
m_wipe_tower_data.priming = Slic3r::make_unique<std::vector<WipeTower::ToolChangeResult>>(
- wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false));
+ wipe_tower.prime((float)get_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false));
// Lets go through the wipe tower layers and determine pairs of extruder changes for each
// to pass to wipe_tower (so that it can use it for planning the layout of the tower)
@@ -2822,28 +2880,28 @@ void Print::_make_wipe_tower()
float pigmentAft = m_config.filament_wipe_advanced_pigment.get_at(extruder_id);
if (m_config.wipe_advanced_algo.value == waLinear) {
volume_to_wipe += m_config.wipe_advanced_multiplier.value * (pigmentBef - pigmentAft);
- std::cout << "advanced wiping (lin) ";
- std::cout << current_extruder_id << " -> " << extruder_id << " will use " << volume_to_wipe << " mm3\n";
- std::cout << " calculus : " << m_config.wipe_advanced_nozzle_melted_volume << " + " << m_config.wipe_advanced_multiplier.value
+ BOOST_LOG_TRIVIAL(info) << "advanced wiping (lin) ";
+ BOOST_LOG_TRIVIAL(info) << current_extruder_id << " -> " << extruder_id << " will use " << volume_to_wipe << " mm3\n";
+ BOOST_LOG_TRIVIAL(info) << " calculus : " << m_config.wipe_advanced_nozzle_melted_volume << " + " << m_config.wipe_advanced_multiplier.value
<< " * ( " << pigmentBef << " - " << pigmentAft << " )\n";
- std::cout << " = " << m_config.wipe_advanced_nozzle_melted_volume << " + " << (m_config.wipe_advanced_multiplier.value* (pigmentBef - pigmentAft)) << "\n";
+ BOOST_LOG_TRIVIAL(info) << " = " << m_config.wipe_advanced_nozzle_melted_volume << " + " << (m_config.wipe_advanced_multiplier.value* (pigmentBef - pigmentAft)) << "\n";
} else if (m_config.wipe_advanced_algo.value == waQuadra) {
volume_to_wipe += m_config.wipe_advanced_multiplier.value * (pigmentBef - pigmentAft)
+ m_config.wipe_advanced_multiplier.value * (pigmentBef - pigmentAft) * (pigmentBef - pigmentAft) * (pigmentBef - pigmentAft);
- std::cout << "advanced wiping (quadra) ";
- std::cout << current_extruder_id << " -> " << extruder_id << " will use " << volume_to_wipe << " mm3\n";
- std::cout << " calculus : " << m_config.wipe_advanced_nozzle_melted_volume << " + " << m_config.wipe_advanced_multiplier.value
+ BOOST_LOG_TRIVIAL(info) << "advanced wiping (quadra) ";
+ BOOST_LOG_TRIVIAL(info) << current_extruder_id << " -> " << extruder_id << " will use " << volume_to_wipe << " mm3\n";
+ BOOST_LOG_TRIVIAL(info) << " calculus : " << m_config.wipe_advanced_nozzle_melted_volume << " + " << m_config.wipe_advanced_multiplier.value
<< " * ( " << pigmentBef << " - " << pigmentAft << " ) + " << m_config.wipe_advanced_multiplier.value
<< " * ( " << pigmentBef << " - " << pigmentAft << " ) ^3 \n";
- std::cout << " = " << m_config.wipe_advanced_nozzle_melted_volume << " + " << (m_config.wipe_advanced_multiplier.value* (pigmentBef - pigmentAft))
+ BOOST_LOG_TRIVIAL(info) << " = " << m_config.wipe_advanced_nozzle_melted_volume << " + " << (m_config.wipe_advanced_multiplier.value* (pigmentBef - pigmentAft))
<< " + " << (m_config.wipe_advanced_multiplier.value*(pigmentBef - pigmentAft)*(pigmentBef - pigmentAft)*(pigmentBef - pigmentAft))<<"\n";
} else if (m_config.wipe_advanced_algo.value == waHyper) {
volume_to_wipe += m_config.wipe_advanced_multiplier.value * (0.5 + pigmentBef) / (0.5 + pigmentAft);
- std::cout << "advanced wiping (hyper) ";
- std::cout << current_extruder_id << " -> " << extruder_id << " will use " << volume_to_wipe << " mm3\n";
- std::cout << " calculus : " << m_config.wipe_advanced_nozzle_melted_volume << " + " << m_config.wipe_advanced_multiplier.value
+ BOOST_LOG_TRIVIAL(info) << "advanced wiping (hyper) ";
+ BOOST_LOG_TRIVIAL(info) << current_extruder_id << " -> " << extruder_id << " will use " << volume_to_wipe << " mm3\n";
+ BOOST_LOG_TRIVIAL(info) << " calculus : " << m_config.wipe_advanced_nozzle_melted_volume << " + " << m_config.wipe_advanced_multiplier.value
<< " * ( 0.5 + " << pigmentBef << " ) / ( 0.5 + " << pigmentAft << " )\n";
- std::cout << " = " << m_config.wipe_advanced_nozzle_melted_volume << " + " << (m_config.wipe_advanced_multiplier.value * (0.5 + pigmentBef) / (0.5 + pigmentAft)) << "\n";
+ BOOST_LOG_TRIVIAL(info) << " = " << m_config.wipe_advanced_nozzle_melted_volume << " + " << (m_config.wipe_advanced_multiplier.value * (0.5 + pigmentBef) / (0.5 + pigmentAft)) << "\n";
}
}
//filament_wipe_advanced_pigment
diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp
index 300029d02..52a8612ef 100644
--- a/src/libslic3r/Print.hpp
+++ b/src/libslic3r/Print.hpp
@@ -74,8 +74,8 @@ public:
coordf_t bridging_height_avg(const PrintConfig &print_config) const;
// Collect 0-based extruder indices used to print this region's object.
- void collect_object_printing_extruders(std::vector<uint16_t> &object_extruders) const;
- static void collect_object_printing_extruders(const PrintConfig &print_config, const PrintObjectConfig &object_config, const PrintRegionConfig &region_config, std::vector<uint16_t> &object_extruders);
+ void collect_object_printing_extruders(std::set<uint16_t> &object_extruders) const;
+ static void collect_object_printing_extruders(const PrintConfig &print_config, const PrintObjectConfig &object_config, const PrintRegionConfig &region_config, std::set<uint16_t> &object_extruders);
// Methods modifying the PrintRegion's state:
public:
@@ -188,7 +188,8 @@ public:
static SlicingParameters slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z);
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
- std::vector<uint16_t> object_extruders() const;
+ std::set<uint16_t> object_extruders() const;
+ double get_first_layer_height() const;
// Called by make_perimeters()
void slice();
@@ -369,13 +370,14 @@ struct PrintStatistics
class BrimLoop {
public:
- BrimLoop(const Polygon& p) : line(p.split_at_first_point()), is_loop(true) {}
- BrimLoop(const Polyline& l) : line(l), is_loop(false) {}
- Polyline line;
+ BrimLoop(const Polygon& p) : lines(Polylines{ p.split_at_first_point() }), is_loop(true) {}
+ BrimLoop(const Polyline& l) : lines(Polylines{l}), is_loop(false) {}
+ Polylines lines;
std::vector<BrimLoop> children;
- bool is_loop;
+ bool is_loop; // has only one polyline stored and front == back
Polygon polygon() const{
- Polygon poly = Polygon(line.points);
+ assert(is_loop);
+ Polygon poly = Polygon(lines.front().points);
if (poly.points.front() == poly.points.back())
poly.points.resize(poly.points.size() - 1);
return poly;
@@ -431,13 +433,14 @@ public:
// Returns an empty string if valid, otherwise returns an error message.
std::pair<PrintValidationError, std::string> validate() const override;
- double skirt_first_layer_height() const;
Flow brim_flow(size_t extruder_id, const PrintObjectConfig &brim_config) const;
- Flow skirt_flow(size_t extruder_id) const;
+ Flow skirt_flow(size_t extruder_id, bool first_layer=false) const;
+ double get_first_layer_height() const;
+ double get_object_first_layer_height(const PrintObject& object) const;
- std::vector<uint16_t> object_extruders(const PrintObjectPtrs &objects) const;
- std::vector<uint16_t> support_material_extruders() const;
- std::vector<uint16_t> extruders() const;
+ std::set<uint16_t> object_extruders(const PrintObjectPtrs &objects) const;
+ std::set<uint16_t> support_material_extruders() const;
+ std::set<uint16_t> extruders() const;
double max_allowed_layer_height() const;
bool has_support_material() const;
// Make sure the background processing has no access to this model_object during this call!
diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp
index fb5e102c1..e4a0b45cc 100644
--- a/src/libslic3r/PrintBase.cpp
+++ b/src/libslic3r/PrintBase.cpp
@@ -62,12 +62,54 @@ std::string PrintBase::output_filename(const std::string &format, const std::str
cfg.set_key_value("input_filename_base", new ConfigOptionString(filename_base));
}
try {
- boost::filesystem::path filename = format.empty() ?
+ boost::filesystem::path filepath = format.empty() ?
cfg.opt_string("input_filename_base") + default_ext :
this->placeholder_parser().process(format, 0, &cfg);
- if (filename.extension().empty())
- filename = boost::filesystem::change_extension(filename, default_ext);
- return filename.string();
+ //remove unwanted characters
+ std::string forbidden_base;
+ if (const ConfigOptionString* opt = this->placeholder_parser().external_config()->option<ConfigOptionString>("gcode_filename_illegal_char")) {
+ forbidden_base = opt->value;
+ }
+ if (!forbidden_base.empty()) {
+ const std::string filename_init = filepath.stem().string();
+ std::string filename = filename_init;
+ std::string extension = filepath.extension().string();
+ //remove {print_time} and things like that that may be computed after, and re-put them inside it after the replace.
+ std::regex placehoder = std::regex("\\{[a-z_]+\\}");
+ std::smatch matches;
+ std::string::const_iterator searchStart(filename_init.cbegin());
+ while (std::regex_search(searchStart, filename_init.cend(), matches, placehoder)) {
+ for (int i = 0; i < matches.size(); i++) {
+ filename.replace(matches.position(i), matches.length(i), matches.length(i), '_');
+ }
+ searchStart = matches.suffix().first;
+ }
+ //remove unwanted characters from the cleaned string
+ bool regexp_used = false;
+ if (forbidden_base.front() == '(' || forbidden_base.front() == '[') {
+ try {
+ filename = std::regex_replace(filename, std::regex(forbidden_base), "_");
+ regexp_used = true;
+ }catch(std::exception){}
+ }
+ if (!regexp_used) {
+ for(int i=0; i< forbidden_base.size(); i++)
+ std::replace(filename.begin(), filename.end(), forbidden_base.at(i), '_');
+ }
+ //re-put {print_time} and things like that
+ searchStart = (filename_init.cbegin());
+ while (std::regex_search(searchStart, filename_init.cend(), matches, placehoder)) {
+ for (int i = 0; i < matches.size(); i++) {
+ filename.replace(matches.position(i), matches.length(i), matches.str());
+ }
+ searchStart = matches.suffix().first;
+ }
+ // set the path var
+ filepath = filename + extension;
+ }
+ if (filepath.extension().empty())
+ filepath = boost::filesystem::change_extension(filepath, default_ext);
+ return filepath.string();
} catch (std::runtime_error &err) {
throw Slic3r::PlaceholderParserError(L("Failed processing of the output_filename_format template.") + "\n" + err.what());
}
diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp
index 5c0a1ebc9..aecb43089 100644
--- a/src/libslic3r/PrintBase.hpp
+++ b/src/libslic3r/PrintBase.hpp
@@ -389,13 +389,16 @@ public:
virtual void finalize() {}
struct SlicingStatus {
- SlicingStatus(int percent, const std::string &text, unsigned int flags = 0) : percent(percent), text(text), flags(flags) {}
+ SlicingStatus(int percent, const std::string& text, unsigned int flags = 0) : percent(percent), main_text(text), flags(flags) {}
+ SlicingStatus(int percent, const std::string& text, const std::vector<std::string>& args, unsigned int flags = 0)
+ : percent(percent), main_text(text), args(args), flags(flags) {}
SlicingStatus(const PrintBase &print, int warning_step) :
flags(UPDATE_PRINT_STEP_WARNINGS), warning_object_id(print.id()), warning_step(warning_step) {}
SlicingStatus(const PrintObjectBase &print_object, int warning_step) :
flags(UPDATE_PRINT_OBJECT_STEP_WARNINGS), warning_object_id(print_object.id()), warning_step(warning_step) {}
- int percent { -1 };
- std::string text;
+ int percent { -1 };
+ std::string main_text;
+ std::vector<std::string> args;
// Bitmap of flags.
enum FlagBits {
DEFAULT = 0,
@@ -422,8 +425,12 @@ public:
// Register a custom status callback.
void set_status_callback(status_callback_type cb) { m_status_callback = cb; }
// Calls a registered callback to update the status, or print out the default message.
- void set_status(int percent, const std::string &message, unsigned int flags = SlicingStatus::DEFAULT) {
- if (m_status_callback) m_status_callback(SlicingStatus(percent, message, flags));
+ void set_status(int percent, const std::string& message, unsigned int flags = SlicingStatus::DEFAULT) const {
+ if (m_status_callback) m_status_callback(SlicingStatus(percent, message, flags));
+ else printf("%d => %s\n", percent, message.c_str());
+ }
+ void set_status(int percent, const std::string& message, const std::vector<std::string>& args, unsigned int flags = SlicingStatus::DEFAULT) const {
+ if (m_status_callback) m_status_callback(SlicingStatus(percent, message, args, flags));
else printf("%d => %s\n", percent, message.c_str());
}
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index 1f7a633d0..e875d8e29 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -111,7 +111,7 @@ void PrintConfigDef::init_common_params()
def = this->add("layer_height", coFloat);
def->label = L("Base Layer height");
- def->category = OptionCategory::perimeter;
+ def->category = OptionCategory::slicing;
def->tooltip = L("This setting controls the height (and thus the total number) of the slices/layers. "
"Thinner layers give better accuracy but take more time to print.");
def->sidetext = L("mm");
@@ -258,6 +258,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("°C");
def->min = 0;
def->max = 300;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { 0 });
def = this->add("before_layer_gcode", coString);
@@ -330,7 +331,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("bridge_fan_speed", coInts);
def->label = L("Bridges fan speed");
def->category = OptionCategory::cooling;
- def->tooltip = L("This fan speed is enforced during all bridges and overhangs. It won't slow down the fan if it's currently running at a higher speed."
+ def->tooltip = L("This fan speed is enforced during bridges and overhangs. It won't slow down the fan if it's currently running at a higher speed."
"\nSet to 1 to disable the fan."
"\nSet to -1 to disable this override."
"\nCan only be overriden by disable_fan_first_layers.");
@@ -338,7 +339,22 @@ void PrintConfigDef::init_fff_params()
def->min = -1;
def->max = 100;
def->mode = comAdvanced;
- def->set_default_value(new ConfigOptionInts { 100 });
+ def->is_vector_extruder = true;
+ def->set_default_value(new ConfigOptionInts{ 100 });
+
+ def = this->add("bridge_internal_fan_speed", coInts);
+ def->label = L("Infill bridges fan speed");
+ def->category = OptionCategory::cooling;
+ def->tooltip = L("This fan speed is enforced during all infill bridges. It won't slow down the fan if it's currently running at a higher speed."
+ "\nSet to 1 to disable the fan."
+ "\nSet to -1 to disable this override (will take the value of Bridges fan speed)."
+ "\nCan only be overriden by disable_fan_first_layers.");
+ def->sidetext = L("%");
+ def->min = -1;
+ def->max = 100;
+ def->mode = comAdvanced;
+ def->is_vector_extruder = true;
+ def->set_default_value(new ConfigOptionInts{ -1 });
def = this->add("top_fan_speed", coInts);
def->label = L("Top fan speed");
@@ -351,6 +367,7 @@ void PrintConfigDef::init_fff_params()
def->min = -1;
def->max = 100;
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts{ -1 });
def = this->add("bridge_flow_ratio", coPercent);
@@ -501,6 +518,7 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->max = 300;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts{ 0 });
def = this->add("clip_multipart_objects", coBool);
@@ -607,6 +625,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("This flag enables the automatic cooling logic that adjusts print speed "
"and fan speed according to layer printing time.");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionBools { true });
def = this->add("cooling_tube_retraction", coFloat);
@@ -664,6 +683,7 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->max = 1000;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { 3 });
def = this->add("dont_support_bridges", coBool);
@@ -713,6 +733,7 @@ void PrintConfigDef::init_fff_params()
def->full_width = true;
def->height = 120;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionStrings { "; Filament-specific end gcode \n;END gcode for filament\n" });
def = this->add("ensure_vertical_shell_thickness", coBool);
@@ -897,6 +918,7 @@ void PrintConfigDef::init_fff_params()
def->min = -1;
def->max = 100;
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { -1 });
def = this->add("external_perimeter_overlap", coPercent);
@@ -1061,7 +1083,6 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("If you have some problem with the 'Only one perimeter on Top surfaces' option, you can try to activate this on the problematic layer.");
def->set_default_value(new ConfigOptionBool(false));
-
def = this->add("extruder", coInt);
def->gui_type = "i_enum_open";
def->label = L("Extruder");
@@ -1080,6 +1101,23 @@ void PrintConfigDef::init_fff_params()
def->enum_labels.push_back("8");
def->enum_labels.push_back("9");
+ def = this->add("first_layer_extruder", coInt);
+ def->gui_type = "i_enum_open";
+ def->label = L("First layer extruder");
+ def->category = OptionCategory::extruders;
+ def->tooltip = L("The extruder to use (unless more specific extruder settings are specified) for the first layer.");
+ def->min = 0; // 0 = inherit defaults
+ def->enum_labels.push_back(L("default")); // override label for item 0
+ def->enum_labels.push_back("1");
+ def->enum_labels.push_back("2");
+ def->enum_labels.push_back("3");
+ def->enum_labels.push_back("4");
+ def->enum_labels.push_back("5");
+ def->enum_labels.push_back("6");
+ def->enum_labels.push_back("7");
+ def->enum_labels.push_back("8");
+ def->enum_labels.push_back("9");
+
def = this->add("extruder_clearance_height", coFloat);
def->label = L("Height");
def->full_label = L("Extruder clearance height");
@@ -1100,7 +1138,8 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("Set this to the clearance radius around your extruder. "
"If the extruder is not centered, choose the largest value for safety. "
"This setting is used to check for collisions and to display the graphical preview "
- "in the plater.");
+ "in the plater."
+ "\nSet zero to disable clearance checking.");
def->sidetext = L("mm");
def->min = 0;
def->mode = comExpert;
@@ -1113,6 +1152,7 @@ void PrintConfigDef::init_fff_params()
def->gui_type = "color";
// Empty string means no color assigned yet.
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionStrings{ "" });
def = this->add("extruder_offset", coPoints);
@@ -1124,6 +1164,7 @@ void PrintConfigDef::init_fff_params()
"from the XY coordinate).");
def->sidetext = L("mm");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionPoints{ Vec2d(0,0) });
def = this->add("extruder_temperature_offset", coFloats);
@@ -1134,6 +1175,7 @@ void PrintConfigDef::init_fff_params()
"\ninstead of 'M104 S[first_layer_temperature]' in the start_gcode");
def->sidetext = L("°C");
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats{ 0 });
def = this->add("extruder_fan_offset", coPercents);
@@ -1142,6 +1184,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("This offset wil be added to all fan values set in the filament properties. It won't make them go higher than 100% nor lower than 0%.");
def->sidetext = L("%");
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionPercents{ 0 });
@@ -1161,6 +1204,7 @@ void PrintConfigDef::init_fff_params()
"check filament diameter and your firmware E steps.");
def->mode = comSimple;
def->max = 2;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 1. });
def = this->add("print_extrusion_multiplier", coPercent);
@@ -1214,6 +1258,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("If this is enabled, fan will continuously run at base speed if no other setting overrides that speed."
" Useful for PLA, harmful for ABS.");
def->mode = comSimple;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionBools{ false });
def = this->add("fan_below_layer_time", coInts);
@@ -1221,11 +1266,12 @@ void PrintConfigDef::init_fff_params()
def->category = OptionCategory::cooling;
def->tooltip = L("If layer print time is estimated below this number of seconds, fan will be enabled "
"and its speed will be calculated by interpolating the default and maximum speeds."
- "\nSet to 0 to disable.");
+ "\nSet zero to disable.");
def->sidetext = L("approximate seconds");
def->min = 0;
def->max = 1000;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { 60 });
def = this->add("filament_colour", coStrings);
@@ -1235,6 +1281,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("This is only used in the Slic3r interface as a visual help.");
def->gui_type = "color";
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionStrings{ "#29B2B2" });
def = this->add("filament_notes", coStrings);
@@ -1245,6 +1292,7 @@ void PrintConfigDef::init_fff_params()
def->full_width = true;
def->height = 13;
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionStrings { "" });
def = this->add("filament_max_speed", coFloats);
@@ -1256,6 +1304,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats{ 0. });
def = this->add("filament_max_volumetric_speed", coFloats);
@@ -1267,6 +1316,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm³/s");
def->min = 0;
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats{ 0. });
def = this->add("filament_max_wipe_tower_speed", coFloats);
@@ -1284,6 +1334,7 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->max = 200;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0 });
def = this->add("filament_loading_speed", coFloats);
@@ -1292,6 +1343,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 28. });
//skinnydip section starts
@@ -1299,18 +1351,21 @@ void PrintConfigDef::init_fff_params()
def->label = L("Toolchange temperature enabled");
def->tooltip = L("Determines whether toolchange temperatures will be applied");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionBools { false });
def = this->add("filament_use_fast_skinnydip", coBools);
def->label = L("Fast mode");
def->tooltip = L("Experimental: drops nozzle temperature during cooling moves instead of prior to extraction to reduce wait time.");
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionBools { false });
def = this->add("filament_enable_toolchange_part_fan", coBools);
def->label = L("Use part fan to cool hotend");
def->tooltip = L("Experimental setting. May enable the hotend to cool down faster during toolchanges");
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionBools { false });
def = this->add("filament_toolchange_part_fan_speed", coInts);
@@ -1320,12 +1375,14 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->max = 100;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { 50 });
def = this->add("filament_use_skinnydip", coBools);
def->label = L("Enable Skinnydip string reduction");
def->tooltip = L("Skinnydip performs a secondary dip into the meltzone to burn off fine strings of filament");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionBools { false });
def = this->add("filament_melt_zone_pause", coInts);
@@ -1334,6 +1391,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("milliseconds");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { 0 });
def = this->add("filament_cooling_zone_pause", coInts);
@@ -1342,6 +1400,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("milliseconds");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { 0 });
def = this->add("filament_dip_insertion_speed", coFloats);
@@ -1350,6 +1409,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm/sec");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 33. });
def = this->add("filament_dip_extraction_speed", coFloats);
@@ -1358,6 +1418,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm/sec");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 70. });
def = this->add("filament_toolchange_temp", coInts);
@@ -1366,6 +1427,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("°C");
def->min = 0;
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { 200 });
def = this->add("filament_skinnydip_distance", coFloats);
@@ -1374,6 +1436,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm");
def->min = 0;
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 31. });
//skinnydip section ends
@@ -1383,6 +1446,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 3. });
def = this->add("filament_unloading_speed", coFloats);
@@ -1392,6 +1456,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 90. });
def = this->add("filament_unloading_speed_start", coFloats);
@@ -1400,6 +1465,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 100. });
def = this->add("filament_toolchange_delay", coFloats);
@@ -1410,6 +1476,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("s");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("filament_cooling_moves", coInts);
@@ -1419,6 +1486,7 @@ void PrintConfigDef::init_fff_params()
def->max = 0;
def->max = 20;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { 4 });
def = this->add("filament_cooling_initial_speed", coFloats);
@@ -1427,6 +1495,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 2.2 });
def = this->add("filament_minimal_purge_on_wipe_tower", coFloats);
@@ -1438,6 +1507,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm³");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 15. });
def = this->add("filament_cooling_final_speed", coFloats);
@@ -1446,6 +1516,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 3.4 });
def = this->add("filament_load_time", coFloats);
@@ -1454,12 +1525,14 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("s");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0.0 });
def = this->add("filament_ramming_parameters", coStrings);
def->label = L("Ramming parameters");
def->tooltip = L("This string is edited by RammingDialog and contains ramming specific parameters.");
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionStrings { "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0|"
" 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" });
@@ -1469,6 +1542,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("s");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0.0 });
def = this->add("filament_diameter", coFloats);
@@ -1478,6 +1552,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm");
def->min = 0;
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats{ 1.75 });
def = this->add("filament_shrink", coPercents);
@@ -1489,6 +1564,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("%");
def->min = 10;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionPercents{ 100 });
def = this->add("filament_density", coFloats);
@@ -1500,6 +1576,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("g/cm³");
def->min = 0;
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats{ 0. });
def = this->add("filament_type", coStrings);
@@ -1538,6 +1615,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("other8");
def->enum_values.push_back("other9");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionStrings { "PLA" });
def = this->add("filament_soluble", coBools);
@@ -1545,6 +1623,7 @@ void PrintConfigDef::init_fff_params()
def->category = OptionCategory::filament;
def->tooltip = L("Soluble material is most likely used for a soluble support.");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionBools { false });
def = this->add("filament_cost", coFloats);
@@ -1554,6 +1633,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("Enter your filament cost per kg here. This is only for statistical information.");
def->sidetext = L("money/kg");
def->min = 0;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("filament_spool_weight", coFloats);
@@ -1565,6 +1645,7 @@ void PrintConfigDef::init_fff_params()
"of filament on the spool is sufficient to finish the print.");
def->sidetext = L("g");
def->min = 0;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("filament_settings_id", coStrings);
@@ -1774,6 +1855,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("°C");
def->max = 0;
def->max = 300;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { 0 });
def = this->add("first_layer_extrusion_width", coFloatOrPercent);
@@ -1812,11 +1894,11 @@ void PrintConfigDef::init_fff_params()
def = this->add("first_layer_height", coFloatOrPercent);
def->label = L("First layer height");
- def->category = OptionCategory::perimeter;
+ def->category = OptionCategory::slicing;
def->tooltip = L("When printing with very low layer heights, you might still want to print a thicker "
"bottom layer to improve adhesion and tolerance for non perfect build plates. "
"This can be expressed as an absolute value or as a percentage (for example: 75%) "
- "over the default nozzle width.");
+ "over the lowest nozzle diameter used in by the object.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
@@ -1824,14 +1906,14 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionFloatOrPercent(75, true));
def = this->add("first_layer_speed", coFloatOrPercent);
- def->label = L("Default");
+ def->label = L("Max");
def->full_label = L("Default first layer speed");
def->category = OptionCategory::speed;
def->tooltip = L("If expressed as absolute value in mm/s, this speed will be applied to all the print moves "
- "but infill of the first layer, it can be overwritten by the 'default' (default depends of the type of the path) "
- "speed if it's lower than that. If expressed as a percentage "
- "it will scale the current speed."
- "\nSet it at 100% to remove any first layer speed modification (with first_layer_infill_speed).");
+ "but infill of the first layer, it can be overwritten by the 'default' (default depends of the type of the path) "
+ "speed if it's lower than that. If expressed as a percentage "
+ "it will scale the current speed."
+ "\nSet it at 100% to remove any first layer speed modification (with first_layer_infill_speed and first_layer_speed_min).");
def->sidetext = L("mm/s or %");
def->ratio_over = "depends";
def->min = 0;
@@ -1851,6 +1933,20 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloatOrPercent(30, false));
+
+ def = this->add("first_layer_min_speed", coFloatOrPercent);
+ def->label = L("Min");
+ def->full_label = L("Min first layer speed");
+ def->category = OptionCategory::speed;
+ def->tooltip = L("If expressed as absolute value in mm/s, this speed will be applied to all the print moves"
+ ", it can be overwritten by the 'default' (default depends of the type of the path) speed if it's higher than that."
+ " If expressed as a percentage it will scale the current speed."
+ "\nSet zero to disable.");
+ def->sidetext = L("mm/s or %");
+ def->ratio_over = "depends";
+ def->min = 0;
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionFloatOrPercent(0, false));
def = this->add("first_layer_temperature", coInts);
def->label = L("First layer");
@@ -1861,6 +1957,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("°C");
def->min = 0;
def->max = max_temp;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { 200 });
def = this->add("full_fan_speed_layer", coInts);
@@ -1872,6 +1969,7 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->max = 1000;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { 0 });
def = this->add("gap_fill", coBool);
@@ -1935,6 +2033,15 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(0));
+ def = this->add("gcode_filename_illegal_char", coString);
+ def->label = L("Illegal characters");
+ def->full_label = L("Illegal characters for filename");
+ def->category = OptionCategory::output;
+ def->tooltip = L("All characters that are written here will be replaced by '_' when writing the gcode file name."
+ "\nIf the first charater is '[' or '(', then this field will be considered as a regexp (enter '[^a-zA-Z0-9]' to only use ascii char).");
+ def->mode = comExpert;
+ def->set_default_value(new ConfigOptionString(""));
+
def = this->add("gcode_flavor", coEnum);
def->label = L("G-code flavor");
def->category = OptionCategory::general;
@@ -1971,6 +2078,15 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<GCodeFlavor>(gcfSprinter));
+ def = this->add("gcode_filename_illegal_char", coString);
+ def->label = L("Illegal characters");
+ def->full_label = L("Illegal characters for filename");
+ def->category = OptionCategory::output;
+ def->tooltip = L("All characters that are written here will be replaced by '_' when writing the gcode file name."
+ "\nIf the first charater is '[' or '(', then this field will be considered as a regexp (enter '[^a-zA-Z]' to only use ascii char).");
+ def->mode = comExpert;
+ def->set_default_value(new ConfigOptionString(""));
+
def = this->add("gcode_label_objects", coBool);
def->label = L("Label objects");
def->category = OptionCategory::output;
@@ -2558,6 +2674,17 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloats{ 1500., 1250. });
+ def = this->add("max_gcode_per_second", coFloat);
+ def->label = L("Maximum G1 per second");
+ def->category = OptionCategory::speed;
+ def->tooltip = L("If your firmware stops while printing, it may have its gcode queue full."
+ " Set this parameter to merge extrusions into bigger ones to reduce the number of gcode commands the printer has to process each second."
+ "\nNote that reducing your printing speed (at least for the external extrusions) will reduce the number of time this will triggger and so increase quality."
+ "\nSet zero to disable.");
+ def->min = 0;
+ def->mode = comExpert;
+ def->set_default_value(new ConfigOptionFloat(1500));
+
def = this->add("max_fan_speed", coInts);
def->label = L("Max");
def->full_label = L("Max fan speed");
@@ -2567,6 +2694,7 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->max = 100;
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { 100 });
def = this->add("max_layer_height", coFloats);
@@ -2580,6 +2708,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm");
def->min = 0;
def->mode = comSimple;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("max_print_speed", coFloat);
@@ -2601,6 +2730,7 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->max = 100;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionPercents{ 90 });
def = this->add("max_volumetric_speed", coFloat);
@@ -2648,6 +2778,7 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->max = 100;
def->mode = comSimple;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts{ 35 });
def = this->add("fan_percentage", coBool);
@@ -2667,13 +2798,15 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm");
def->min = 0;
def->mode = comSimple;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0.07 });
def = this->add("min_length", coFloat);
def->label = L("Minimum extrusion length");
def->category = OptionCategory::speed;
- def->tooltip = L("Too many too small commands may overload the firmware / connection. Put a higher value here if you see strange slowdown."
- "\n0 to disable.");
+ def->tooltip = L("[Deprecated] Prefer using max_gcode_per_second instead, as it's much better when you have very different speeds for features."
+ "\nToo many too small commands may overload the firmware / connection. Put a higher value here if you see strange slowdown."
+ "\nSet zero to disable.");
def->sidetext = L("mm");
def->min = 0;
def->precision = 8;
@@ -2699,6 +2832,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats{ 10. });
def = this->add("min_skirt_length", coFloat);
@@ -2729,6 +2863,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("This is the diameter of your extruder nozzle (for example: 0.5, 0.35 etc.)");
def->sidetext = L("mm");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats{ 0.4 });
def = this->add("host_type", coEnum);
@@ -3066,7 +3201,7 @@ void PrintConfigDef::init_fff_params()
def->category = OptionCategory::slicing;
def->tooltip = L("Minimum detail resolution, used to simplify the input file for speeding up "
"the slicing job and reducing memory usage. High-resolution models often carry "
- "more details than printers can render. Set to zero to disable any simplification "
+ "more details than printers can render. Set zero to disable any simplification "
"and use full resolution from input. "
"\nNote: Slic3r has an internal working resolution of 0.0001mm."
"\nInfill & Thin areas are simplified up to 0.0125mm.");
@@ -3083,6 +3218,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm");
def->mode = comAdvanced;
def->min = 0;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 2. });
def = this->add("retract_before_wipe", coPercents);
@@ -3092,6 +3228,7 @@ void PrintConfigDef::init_fff_params()
"before doing the wipe movement.");
def->sidetext = L("%");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionPercents { 0. });
def = this->add("retract_layer_change", coBools);
@@ -3099,6 +3236,7 @@ void PrintConfigDef::init_fff_params()
def->category = OptionCategory::extruders;
def->tooltip = L("This flag enforces a retraction whenever a Z move is done (before it).");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionBools { false });
def = this->add("retract_length", coFloats);
@@ -3109,6 +3247,7 @@ void PrintConfigDef::init_fff_params()
"(the length is measured on raw filament, before it enters the extruder).");
def->sidetext = L("mm (zero to disable)");
def->min = 0;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 2. });
def = this->add("print_retract_length", coFloat);
@@ -3127,6 +3266,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm (zero to disable)");
def->mode = comExpert;
def->min = 0;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 10. });
def = this->add("retract_lift", coFloats);
@@ -3136,6 +3276,7 @@ void PrintConfigDef::init_fff_params()
"is triggered. When using multiple extruders, only the setting for the first extruder "
"will be considered.");
def->sidetext = L("mm");
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("retract_lift_above", coFloats);
@@ -3146,6 +3287,7 @@ void PrintConfigDef::init_fff_params()
"absolute Z. You can tune this setting for skipping lift on the first layers.");
def->sidetext = L("mm");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0. });
@@ -3159,6 +3301,7 @@ void PrintConfigDef::init_fff_params()
"to the first layers.");
def->sidetext = L("mm");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("retract_lift_first_layer", coBools);
@@ -3167,6 +3310,7 @@ void PrintConfigDef::init_fff_params()
def->category = OptionCategory::extruders;
def->tooltip = L("Select this option to enforce z-lift on the first layer.");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionBools{ false });
def = this->add("retract_lift_top", coStrings);
@@ -3180,6 +3324,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back(("Not on top"));
def->enum_values.push_back(("Only on top"));
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionStrings{ "All surfaces" });
@@ -3189,6 +3334,7 @@ void PrintConfigDef::init_fff_params()
"this additional amount of filament. This setting is rarely needed.");
def->sidetext = L("mm");
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("retract_restart_extra_toolchange", coFloats);
@@ -3198,6 +3344,7 @@ void PrintConfigDef::init_fff_params()
"this additional amount of filament.");
def->sidetext = L("mm");
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("retract_speed", coFloats);
@@ -3207,6 +3354,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("The speed for retractions (this only applies to the extruder motor).");
def->sidetext = L("mm/s");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 40. });
def = this->add("deretract_speed", coFloats);
@@ -3217,6 +3365,7 @@ void PrintConfigDef::init_fff_params()
"(this only applies to the extruder motor). If left as zero, the retraction speed is used.");
def->sidetext = L("mm/s");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("seam_position", coEnum);
@@ -3345,11 +3494,12 @@ void PrintConfigDef::init_fff_params()
def->category = OptionCategory::cooling;
def->tooltip = L("If layer print time is estimated below this number of seconds, print moves "
"speed will be scaled down to extend duration to this value, if possible."
- "\nSet to 0 to disable.");
+ "\nSet zero to disable.");
def->sidetext = L("approximate seconds");
def->min = 0;
def->max = 1000;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts{ 5 });
def = this->add("small_perimeter_speed", coFloatOrPercent);
@@ -3440,7 +3590,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("cutoff");
def->full_label = L("Curve smoothing cutoff dist");
def->category = OptionCategory::slicing;
- def->tooltip = L("Maximum distance between two points to allow adding new ones. Allow to avoid distorting long strait areas. 0 to disable.");
+ def->tooltip = L("Maximum distance between two points to allow adding new ones. Allow to avoid distorting long strait areas.\nSet zero to disable.");
def->sidetext = L("mm");
def->min = 0;
def->cli = "curve-smoothing-cutoff-dist=f";
@@ -3599,6 +3749,7 @@ void PrintConfigDef::init_fff_params()
def->full_width = true;
def->height = 12;
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionStrings { "; Filament gcode\n" });
def = this->add("model_precision", coFloat);
@@ -3607,7 +3758,7 @@ void PrintConfigDef::init_fff_params()
def->category = OptionCategory::slicing;
def->tooltip = L("This is the rounding error of the input object."
" It's used to align points that should be in the same line."
- " Put 0 to disable.");
+ "\nSet zero to disable.");
def->sidetext = L("mm");
def->min = 0;
def->precision = 8;
@@ -3673,7 +3824,7 @@ void PrintConfigDef::init_fff_params()
" This number allow to keep some if there is a low number of perimeter over the void."
"\nIf this setting is equal or higher than the top/bottom solid layer count, it won't evict anything."
"\nIf this setting is set to 1, it will evict all solid fill are are only over perimeters."
- "\nSet it to 0 to disable.");
+ "\nSet zero to disable.");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(2));
@@ -3781,9 +3932,9 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionInt(0));
def = this->add("support_material_extruder", coInt);
- def->label = L("Support material/raft/skirt extruder");
+ def->label = L("Support material extruder");
def->category = OptionCategory::extruders;
- def->tooltip = L("The extruder to use when printing support material, raft and skirt "
+ def->tooltip = L("The extruder to use when printing support material "
"(1+, 0 to use the current extruder to minimize tool changes).");
def->min = 0;
def->mode = comAdvanced;
@@ -3947,6 +4098,7 @@ void PrintConfigDef::init_fff_params()
def->full_label = L("Nozzle temperature");
def->min = 0;
def->max = max_temp;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionInts { 200 });
def = this->add("print_temperature", coInt);
@@ -4071,6 +4223,7 @@ void PrintConfigDef::init_fff_params()
def->category = OptionCategory::extruders;
def->tooltip = L("Only used for Klipper, where you can name the extruder. If not set, will be 'extruderX' with 'X' replaced by the extruder number.");
def->mode = comExpert;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionStrings(""));
def = this->add("top_infill_extrusion_width", coFloatOrPercent);
@@ -4214,11 +4367,20 @@ void PrintConfigDef::init_fff_params()
def = this->add("wipe", coBools);
def->label = L("Wipe while retracting");
- def->category = OptionCategory::general;
+ def->category = OptionCategory::extruders;
def->tooltip = L("This flag will move the nozzle while retracting to minimize the possible blob "
- "on leaky extruders.");
+ "on leaky extruders.");
def->mode = comAdvanced;
- def->set_default_value(new ConfigOptionBools { false });
+ def->is_vector_extruder = true;
+ def->set_default_value(new ConfigOptionBools{ false });
+
+ def = this->add("wipe_speed", coFloats);
+ def->label = L("Wipe speed");
+ def->category = OptionCategory::extruders;
+ def->tooltip = L("Speed in mm/s of the wipe. If it's faster, it will try to go further away, as the wipe time is set by ( 100% - 'retract before wipe') * 'retaction length' / 'retraction speed'."
+ "\nIf set to zero, the travel speed is used.");
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionFloats{ 0 });
def = this->add("wipe_tower", coBool);
def->label = L("Enable");
@@ -4266,6 +4428,7 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert;
def->min = 0;
def->max = 1;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats{ 0.5 });
def = this->add("wipe_advanced_multiplier", coFloat);
@@ -4356,6 +4519,7 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->sidetext = L("mm");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats{ 0.f });
def = this->add("wipe_tower_bridging", coFloat);
@@ -4426,13 +4590,21 @@ void PrintConfigDef::init_fff_params()
def->full_label = L("Polyhole detection margin");
def->category = OptionCategory::slicing;
def->tooltip = L("Maximum defection of a point to the estimated radius of the circle."
- "\nAs cylinders are often exported as triangles of varying size, points may not be on the circle circumference."
- " This setting allows you some leway to broaden the detection."
- "\nIn mm or in % of the radius.");
+ "\nAs cylinders are often exported as triangles of varying size, points may not be on the circle circumference."
+ " This setting allows you some leway to broaden the detection."
+ "\nIn mm or in % of the radius.");
def->sidetext = L("mm or %");
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloatOrPercent(0.01, false));
+ def = this->add("hole_to_polyhole_twisted", coBool);
+ def->label = L("Twisting");
+ def->full_label = L("Polyhole twist");
+ def->category = OptionCategory::slicing;
+ def->tooltip = L("Rotate the polyhole every layer.");
+ def->mode = comExpert;
+ def->set_default_value(new ConfigOptionBool(true));
+
def = this->add("z_offset", coFloat);
def->label = L("Z offset");
def->category = OptionCategory::general;
@@ -4449,7 +4621,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("Set this to the height moved when your Z motor (or equivalent) turns one step."
"If your motor needs 200 steps to move your head/plater by 1mm, this field should be 1/200 = 0.005."
"\nNote that the gcode will write the z values with 6 digits after the dot if z_step is set (it's 3 digits if it's disabled)."
- "\nPut 0 to disable.");
+ "\nSet zero to disable.");
def->cli = "z-step=f";
def->sidetext = L("mm");
def->min = 0;
@@ -4461,7 +4633,7 @@ void PrintConfigDef::init_fff_params()
for (const char *opt_key : {
// floats
"retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", "retract_restart_extra", "retract_before_travel",
- "wipe_extra_perimeter",
+ "wipe_extra_perimeter", "wipe_speed",
// bools
"retract_layer_change", "wipe",
// percents
@@ -4508,6 +4680,7 @@ void PrintConfigDef::init_extruder_option_keys()
"retract_before_travel",
"wipe",
"wipe_extra_perimeter",
+ "wipe_speed",
"retract_layer_change",
"retract_length_toolchange",
"retract_restart_extra_toolchange",
@@ -4527,7 +4700,8 @@ void PrintConfigDef::init_extruder_option_keys()
"retract_restart_extra",
"retract_speed",
"wipe",
- "wipe_extra_perimeter"
+ "wipe_extra_perimeter",
+ "wipe_speed",
};
assert(std::is_sorted(m_extruder_retract_keys.begin(), m_extruder_retract_keys.end()));
}
@@ -4572,6 +4746,7 @@ void PrintConfigDef::init_milling_params()
def->tooltip = L("This is the diameter of your cutting tool.");
def->sidetext = L("mm");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats(3.14));
def = this->add("milling_offset", coPoints);
@@ -4583,6 +4758,7 @@ void PrintConfigDef::init_milling_params()
"from the XY coordinate).");
def->sidetext = L("mm");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionPoints( Vec2d(0,0) ));
def = this->add("milling_z_offset", coFloats);
@@ -4591,6 +4767,7 @@ void PrintConfigDef::init_milling_params()
def->tooltip = L(".");
def->sidetext = L("mm");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionFloats(0));
def = this->add("milling_z_lift", coFloats);
@@ -4609,6 +4786,7 @@ void PrintConfigDef::init_milling_params()
" previous_extruder is the 'extruder number' of the previous tool, it may be a normal extruder, if it's below the number of extruders."
" The number of extruder is available at [extruder] and the number of milling tool is available at [milling_cutter].");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionStrings(""));
def = this->add("milling_toolchange_end_gcode", coStrings);
@@ -4619,6 +4797,7 @@ void PrintConfigDef::init_milling_params()
" next_extruder is the 'extruder number' of the next tool, it may be a normal extruder, if it's below the number of extruders."
" The number of extruder is available at [extruder]and the number of milling tool is available at [milling_cutter].");
def->mode = comAdvanced;
+ def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionStrings(""));
def = this->add("milling_post_process", coBool);
@@ -5449,99 +5628,124 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
}
}
-void PrintConfigDef::to_prusa(t_config_option_key& opt_key, std::string& value, const DynamicConfig& all_conf) {
-
- std::unordered_set<std::string> to_remove_keys = {
-"thumbnails_color",
-"thumbnails_custom_color",
-"thumbnails_with_bed",
-"thumbnails_with_support",
+std::unordered_set<std::string> prusa_export_to_remove_keys = {
"allow_empty_layers",
"avoid_crossing_not_first_layer",
-"top_fan_speed",
-"over_bridge_flow_ratio",
+"bridge_internal_fan_speed",
"bridge_overlap",
"bridge_speed_internal",
-"brim_inside_holes",
-"brim_width_interior",
-"brim_ears",
+"bridged_infill_margin",
"brim_ears_detection_length",
"brim_ears_max_angle",
"brim_ears_pattern",
+"brim_ears",
+"brim_inside_holes",
"brim_offset",
+"brim_width_interior",
"chamber_temperature",
-"complete_objects_one_skirt",
"complete_objects_one_brim",
+"complete_objects_one_skirt",
"complete_objects_sort",
-"solid_fill_pattern",
+"curve_smoothing_angle_concave",
+"curve_smoothing_angle_convex",
+"curve_smoothing_cutoff_dist",
+"curve_smoothing_precision",
"enforce_full_fill_volume",
+"exact_last_layer_height",
"external_infill_margin",
-"bridged_infill_margin",
"external_perimeter_cut_corners",
+"external_perimeter_extrusion_spacing",
"external_perimeter_fan_speed",
"external_perimeter_overlap",
-"perimeter_overlap",
-"perimeter_bonding",
-"external_perimeters_vase",
-"external_perimeters_nothole",
"external_perimeters_hole",
-"perimeter_loop",
-"perimeter_loop_seam",
-"extra_perimeters_overhangs",
+"external_perimeters_nothole",
+"external_perimeters_vase",
"extra_perimeters_odd_layers",
-"only_one_perimeter_top",
-"only_one_perimeter_top_other_algo",
-"extruder_temperature_offset",
+"extra_perimeters_overhangs",
"extruder_fan_offset",
-"print_extrusion_multiplier",
+"extruder_temperature_offset",
+"extrusion_spacing",
+"fan_kickstart",
+"fan_percentage",
+"fan_speedup_overhangs",
+"fan_speedup_time",
+"feature_gcode",
+"filament_cooling_zone_pause",
+"filament_dip_extraction_speed",
+"filament_dip_insertion_speed",
+"filament_enable_toolchange_part_fan",
+"filament_enable_toolchange_temp",
"filament_max_speed",
"filament_max_wipe_tower_speed",
-"filament_enable_toolchange_temp",
-"filament_use_fast_skinnydip",
-"filament_enable_toolchange_part_fan",
-"filament_toolchange_part_fan_speed",
-"filament_use_skinnydip",
"filament_melt_zone_pause",
-"filament_cooling_zone_pause",
-"filament_dip_insertion_speed",
-"filament_dip_extraction_speed",
-"filament_toolchange_temp",
-"filament_skinnydip_distance",
"filament_shrink",
+"filament_skinnydip_distance",
+"filament_toolchange_part_fan_speed",
+"filament_toolchange_temp",
+"filament_use_fast_skinnydip",
+"filament_use_skinnydip",
+"filament_wipe_advanced_pigment",
"fill_angle_increment",
+"fill_smooth_distribution",
+"fill_smooth_width",
"fill_top_flow_ratio",
"fill_top_flow_ratio",
+"first_layer_extrusion_spacing",
"first_layer_flow_ratio",
-"fill_smooth_width",
-"fill_smooth_distribution",
"first_layer_infill_speed",
-"gap_fill",
+"first_layer_min_speed",
+"first_layer_size_compensation_layers",
+"gap_fill_infill",
"gap_fill_min_area",
"gap_fill_overlap",
-"gap_fill_infill",
-"infill_dense",
+"gap_fill",
+"gcode_filename_illegal_char",
+"hole_size_compensation",
+"hole_size_threshold",
+"hole_to_polyhole_threshold",
+"hole_to_polyhole_twisted",
+"hole_to_polyhole",
"infill_connection",
"infill_dense_algo",
-"feature_gcode",
-"exact_last_layer_height",
-"fan_speedup_time",
-"fan_speedup_overhangs",
-"fan_percentage",
-"fan_kickstart",
+"infill_dense",
+"infill_extrusion_spacing",
"machine_max_acceleration_travel",
"max_speed_reduction",
+"milling_after_z",
+"milling_cutter",
+"milling_diameter",
+"milling_extra_size",
+"milling_offset",
+"milling_post_process",
+"milling_speed",
+"milling_toolchange_end_gcode",
+"milling_toolchange_start_gcode",
+"milling_z_lift",
+"milling_z_offset",
"min_length",
"min_width_top_surface",
-"printhost_apikey",
-"printhost_cafile",
-"print_host",
+"model_precision",
+"no_perimeter_unsupported_algo",
+"only_one_perimeter_top_other_algo",
+"only_one_perimeter_top",
+"over_bridge_flow_ratio",
+"overhangs_reverse_threshold",
+"overhangs_reverse",
"overhangs_speed",
"overhangs_width_speed",
-"overhangs_reverse",
-"overhangs_reverse_threshold",
-"no_perimeter_unsupported_algo",
-"support_material_solid_first_layer",
+"perimeter_bonding",
+"perimeter_extrusion_spacing",
+"perimeter_loop_seam",
+"perimeter_loop",
+"perimeter_overlap",
+"perimeter_round_corners",
+"print_extrusion_multiplier",
+"print_host",
"print_retract_length",
+"print_retract_lift",
+"print_temperature",
+"printhost_apikey",
+"printhost_cafile",
"retract_lift_first_layer",
"retract_lift_top",
"seam_angle_cost",
@@ -5549,65 +5753,46 @@ void PrintConfigDef::to_prusa(t_config_option_key& opt_key, std::string& value,
"skirt_brim",
"skirt_distance_from_brim",
"skirt_extrusion_width",
-"small_perimeter_min_length",
"small_perimeter_max_length",
-"curve_smoothing_angle_convex",
-"curve_smoothing_angle_concave",
-"curve_smoothing_precision",
-"curve_smoothing_cutoff_dist",
-"model_precision",
-"support_material_contact_distance_type",
+"small_perimeter_min_length",
+"solid_fill_pattern",
+"solid_infill_extrusion_spacing",
+"start_gcode_manual",
"support_material_contact_distance_bottom",
+"support_material_contact_distance_type",
"support_material_interface_pattern",
-"print_temperature",
-"print_retract_lift",
-"thin_perimeters",
+"support_material_solid_first_layer",
"thin_perimeters_all",
+"thin_perimeters",
+"thin_walls_merge",
"thin_walls_min_width",
"thin_walls_overlap",
-"thin_walls_merge",
"thin_walls_speed",
+"thumbnails_color",
+"thumbnails_custom_color",
+"thumbnails_with_bed",
+"thumbnails_with_support",
"time_estimation_compensation",
"tool_name",
-"wipe_advanced",
-"wipe_advanced_nozzle_melted_volume",
-"filament_wipe_advanced_pigment",
-"wipe_advanced_multiplier",
+"top_fan_speed",
+"top_infill_extrusion_spacing",
+"travel_acceleration",
+"travel_speed_z",
"wipe_advanced_algo",
-"wipe_tower_brim",
+"wipe_advanced_multiplier",
+"wipe_advanced_nozzle_melted_volume",
+"wipe_advanced",
"wipe_extra_perimeter",
+"wipe_speed",
+"wipe_tower_brim",
"xy_inner_size_compensation",
-"hole_size_compensation",
-"hole_size_threshold",
-"hole_to_polyhole",
-"hole_to_polyhole_threshold",
"z_step",
-"milling_cutter",
-"milling_diameter",
-"milling_offset",
-"milling_z_offset",
-"milling_z_lift",
-"milling_toolchange_start_gcode",
-"milling_toolchange_end_gcode",
-"milling_post_process",
-"milling_extra_size",
-"milling_after_z",
-"milling_speed",
-"extrusion_spacing",
-"first_layer_extrusion_spacing",
-"perimeter_extrusion_spacing",
-"external_perimeter_extrusion_spacing",
-"infill_extrusion_spacing",
-"solid_infill_extrusion_spacing",
-"top_infill_extrusion_spacing",
-"start_gcode_manual",
-"perimeter_round_corners",
-"travel_speed_z",
-"first_layer_size_compensation_layers",
-"travel_acceleration",
- };
+};
+
+void PrintConfigDef::to_prusa(t_config_option_key& opt_key, std::string& value, const DynamicConfig& all_conf) {
+
//looks if it's to be removed, or have to be transformed
- if (to_remove_keys.find(opt_key) != to_remove_keys.end()) {
+ if (prusa_export_to_remove_keys.find(opt_key) != prusa_export_to_remove_keys.end()) {
opt_key = "";
value = "";
} else if (opt_key.find("_pattern") != std::string::npos) {
@@ -5635,7 +5820,7 @@ void PrintConfigDef::to_prusa(t_config_option_key& opt_key, std::string& value,
|| "overhangs_speed" == opt_key || "ironing_speed" == opt_key){
// remove '%'
if (value.find("%") != std::string::npos) {
- value = std::to_string(all_conf.get_abs_value(opt_key));
+ value = std::to_string(all_conf.get_computed_value(opt_key));
}
} else if ("gap_fill_speed" == opt_key && all_conf.has("gap_fill") && !all_conf.option<ConfigOptionBool>("gap_fill")->value) {
value = "0";
@@ -5658,7 +5843,7 @@ void PrintConfigDef::to_prusa(t_config_option_key& opt_key, std::string& value,
double val = all_conf.option<ConfigOptionFloatOrPercent>("support_material_contact_distance_top")->get_abs_value(all_conf.option<ConfigOptionFloats>("nozzle_diameter")->values.front());
if (SupportZDistanceType::zdFilament == dist_type) { // not exact but good enough effort
val += all_conf.option<ConfigOptionFloats>("nozzle_diameter")->values.front();
- val -= all_conf.get_abs_value("layer_height");
+ val -= all_conf.get_computed_value("layer_height", 0);
}
value = boost::lexical_cast<std::string>(val);
}
@@ -5738,7 +5923,6 @@ double min_object_distance(const ConfigBase &cfg)
return ret;
}*/
-
double PrintConfig::min_object_distance() const
{
return PrintConfig::min_object_distance(static_cast<const ConfigBase*>(this));
@@ -5770,7 +5954,9 @@ double PrintConfig::min_object_distance(const ConfigBase *config, double ref_hei
base_dist = extruder_clearance_radius;
}
- const double first_layer_height = config->get_abs_value("first_layer_height");
+ // we use the max nozzle, just to be on the safe side
+ //ideally, we should use print::first_layer_height()
+ const double first_layer_height = dynamic_cast<const ConfigOptionFloatOrPercent*>(config->option("first_layer_height"))->get_abs_value(max_nozzle_diam);
//add the skirt
int skirts = config->option("skirts")->getInt();
if (skirts > 0 && ref_height == 0)
@@ -5789,7 +5975,7 @@ double PrintConfig::min_object_distance(const ConfigBase *config, double ref_hei
//set to 0 becasue it's incorporated into the base_dist, so we don't want to be added in to it again.
skirt_dist = 0;
} else {
- double skirt_height = ((double)config->option("skirt_height")->getInt() - 1) * config->get_abs_value("layer_height") + first_layer_height;
+ double skirt_height = ((double)config->option("skirt_height")->getInt() - 1) * config->get_computed_value("layer_height") + first_layer_height;
if (ref_height <= skirt_height) {
skirt_dist = config->option("skirt_distance")->getFloat();
Flow skirt_flow = Flow::new_from_config_width(
@@ -5845,6 +6031,8 @@ void DynamicPrintConfig::normalize_fdm()
// this->option("support_material_interface_extruder", true)->setInt(extruder);
}
}
+ if (this->has("first_layer_extruder"))
+ this->erase("first_layer_extruder");
if (!this->has("solid_infill_extruder") && this->has("infill_extruder"))
this->option("solid_infill_extruder", true)->setInt(this->option("infill_extruder")->getInt());
@@ -6219,13 +6407,14 @@ bool DynamicPrintConfig::value_changed(const t_config_option_key& opt_key, const
std::string FullPrintConfig::validate()
{
// --layer-height
- if (this->get_abs_value("layer_height") <= 0)
+ if (this->get_computed_value("layer_height") <= 0)
return "Invalid value for --layer-height";
- if (fabs(fmod(this->get_abs_value("layer_height"), SCALING_FACTOR)) > 1e-4)
+ if (fabs(fmod(this->get_computed_value("layer_height"), SCALING_FACTOR)) > 1e-4)
return "--layer-height must be a multiple of print resolution";
// --first-layer-height
- if (this->get_abs_value("first_layer_height") <= 0)
+ //if (this->get_abs_value("first_layer_height") <= 0) //can't do that, as the extruder isn't defined
+ if(this->first_layer_height.value <= 0)
return "Invalid value for --first-layer-height";
// --filament-diameter
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index 8175e11a5..ea6f18673 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -798,6 +798,7 @@ public:
ConfigOptionFloatOrPercent infill_anchor_max;
ConfigOptionBool hole_to_polyhole;
ConfigOptionFloatOrPercent hole_to_polyhole_threshold;
+ ConfigOptionBool hole_to_polyhole_twisted;
ConfigOptionInt infill_extruder;
ConfigOptionFloatOrPercent infill_extrusion_width;
ConfigOptionInt infill_every_layers;
@@ -914,6 +915,7 @@ protected:
OPT_PTR(infill_anchor_max);
OPT_PTR(hole_to_polyhole);
OPT_PTR(hole_to_polyhole_threshold);
+ OPT_PTR(hole_to_polyhole_twisted);
OPT_PTR(infill_extruder);
OPT_PTR(infill_extrusion_width);
OPT_PTR(infill_every_layers);
@@ -1088,12 +1090,14 @@ public:
ConfigOptionFloats filament_cooling_final_speed;
ConfigOptionStrings filament_ramming_parameters;
ConfigOptionBool gcode_comments;
+ ConfigOptionString gcode_filename_illegal_char;
ConfigOptionEnum<GCodeFlavor> gcode_flavor;
ConfigOptionBool gcode_label_objects;
ConfigOptionInt gcode_precision_xyz;
ConfigOptionInts gcode_precision_e;
ConfigOptionString layer_gcode;
ConfigOptionString feature_gcode;
+ ConfigOptionFloat max_gcode_per_second;
ConfigOptionFloat max_print_speed;
ConfigOptionFloat max_volumetric_speed;
#ifdef HAS_PRESSURE_EQUALIZER
@@ -1139,6 +1143,7 @@ public:
ConfigOptionFloat wipe_advanced_multiplier;
ConfigOptionFloats wipe_extra_perimeter;
ConfigOptionEnum<WipeAlgo> wipe_advanced_algo;
+ ConfigOptionFloats wipe_speed;
ConfigOptionFloat z_step;
ConfigOptionString color_change_gcode;
ConfigOptionString pause_print_gcode;
@@ -1201,12 +1206,14 @@ protected:
OPT_PTR(filament_cooling_final_speed);
OPT_PTR(filament_ramming_parameters);
OPT_PTR(gcode_comments);
+ OPT_PTR(gcode_filename_illegal_char);
OPT_PTR(gcode_flavor);
OPT_PTR(gcode_label_objects);
OPT_PTR(gcode_precision_xyz);
OPT_PTR(gcode_precision_e);
OPT_PTR(layer_gcode);
OPT_PTR(feature_gcode);
+ OPT_PTR(max_gcode_per_second);
OPT_PTR(max_print_speed);
OPT_PTR(max_volumetric_speed);
OPT_PTR(milling_z_lift);
@@ -1252,6 +1259,7 @@ protected:
OPT_PTR(wipe_advanced_multiplier);
OPT_PTR(wipe_advanced_algo);
OPT_PTR(wipe_extra_perimeter);
+ OPT_PTR(wipe_speed);
OPT_PTR(z_step);
OPT_PTR(color_change_gcode);
OPT_PTR(pause_print_gcode);
@@ -1276,6 +1284,7 @@ public:
ConfigOptionInts bed_temperature;
ConfigOptionFloatOrPercent bridge_acceleration;
ConfigOptionInts bridge_fan_speed;
+ ConfigOptionInts bridge_internal_fan_speed;
ConfigOptionInts chamber_temperature;
ConfigOptionBool complete_objects;
ConfigOptionBool complete_objects_one_skirt;
@@ -1301,6 +1310,7 @@ public:
ConfigOptionPercent first_layer_flow_ratio;
ConfigOptionFloatOrPercent first_layer_speed;
ConfigOptionFloatOrPercent first_layer_infill_speed;
+ ConfigOptionFloatOrPercent first_layer_min_speed;
ConfigOptionInts first_layer_temperature;
ConfigOptionInts full_fan_speed_layer;
ConfigOptionFloatOrPercent infill_acceleration;
@@ -1375,6 +1385,7 @@ protected:
OPT_PTR(bed_temperature);
OPT_PTR(bridge_acceleration);
OPT_PTR(bridge_fan_speed);
+ OPT_PTR(bridge_internal_fan_speed);
OPT_PTR(chamber_temperature);
OPT_PTR(complete_objects);
OPT_PTR(complete_objects_one_skirt);
@@ -1400,6 +1411,7 @@ protected:
OPT_PTR(first_layer_flow_ratio);
OPT_PTR(first_layer_speed);
OPT_PTR(first_layer_infill_speed);
+ OPT_PTR(first_layer_min_speed);
OPT_PTR(first_layer_temperature);
OPT_PTR(full_fan_speed_layer);
OPT_PTR(infill_acceleration);
@@ -1938,6 +1950,7 @@ public:
const ConfigOption* option(const t_config_option_key &opt_key) const { return m_data.option(opt_key); }
int opt_int(const t_config_option_key &opt_key) const { return m_data.opt_int(opt_key); }
int extruder() const { return opt_int("extruder"); }
+ int first_layer_extruder() const { return opt_int("first_layer_extruder"); }
double opt_float(const t_config_option_key &opt_key) const { return m_data.opt_float(opt_key); }
std::string opt_serialize(const t_config_option_key &opt_key) const { return m_data.opt_serialize(opt_key); }
@@ -1950,8 +1963,6 @@ public:
// Not thread safe! Should not be called from other than the main thread!
void touch() { m_timestamp = ++ s_last_timestamp; }
- void to_prusa(t_config_option_key& opt_key, std::string& value) const
- { m_data.to_prusa(opt_key, value); }
private:
friend class cereal::access;
template<class Archive> void serialize(Archive& ar) { ar(m_timestamp); ar(m_data); }
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 457931b7b..3296f3eb6 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -151,25 +151,41 @@ namespace Slic3r {
}
- Polygon create_polyhole(const Point center, const coord_t radius, const coord_t nozzle_diameter)
+
+ Polygons create_polyholes(const Point center, const coord_t radius, const coord_t nozzle_diameter, bool multiple)
{
// n = max(round(2 * d), 3); // for 0.4mm nozzle
- size_t nb_polygons = (int)std::max(3, (int)std::round(4.0 * unscaled(radius) * 0.4 / unscaled(nozzle_diameter)));
+ size_t nb_edges = (int)std::max(3, (int)std::round(4.0 * unscaled(radius) * 0.4 / unscaled(nozzle_diameter)));
// cylinder(h = h, r = d / cos (180 / n), $fn = n);
- Points pts;
- const float new_radius = radius / std::cos(PI / nb_polygons);
- for (int i = 0; i < nb_polygons; ++i) {
- float angle = (PI * 2 * i) / nb_polygons;
- pts.emplace_back(center.x() + new_radius * cos(angle), center.y() + new_radius * sin(angle));
+ //create x polyholes by rotation if multiple
+ int nb_polyhole = 1;
+ float rotation = 0;
+ if (multiple) {
+ nb_polyhole = 5;
+ rotation = 2 * float(PI) / (nb_edges * nb_polyhole);
+ }
+ Polygons list;
+ for (int i_poly = 0; i_poly < nb_polyhole; i_poly++)
+ list.emplace_back();
+ for (int i_poly = 0; i_poly < nb_polyhole; i_poly++) {
+ Polygon& pts = (((i_poly % 2) == 0) ? list[i_poly / 2] : list[(nb_polyhole + 1) / 2 + i_poly / 2]);
+ const float new_radius = radius / float(std::cos(PI / nb_edges));
+ for (int i_edge = 0; i_edge < nb_edges; ++i_edge) {
+ float angle = rotation * i_poly + (float(PI) * 2 * i_edge) / nb_edges;
+ pts.points.emplace_back(center.x() + new_radius * cos(angle), center.y() + new_radius * sin(angle));
+ }
+ pts.make_clockwise();
}
- return Polygon{ pts };
+ //alternate
+ return list;
}
void PrintObject::_transform_hole_to_polyholes()
{
// get all circular holes for each layer
// the id is center-diameter-extruderid
- std::vector<std::vector<std::pair<std::tuple<Point, float, int, coord_t>, Polygon*>>> layerid2center;
+ //the tuple is Point center; float diameter_max; int extruder_id; coord_t max_variation; bool twist;
+ std::vector<std::vector<std::pair<std::tuple<Point, float, int, coord_t, bool>, Polygon*>>> layerid2center;
for (size_t i = 0; i < this->m_layers.size(); i++) layerid2center.emplace_back();
tbb::parallel_for(
tbb::blocked_range<size_t>(0, m_layers.size()),
@@ -196,9 +212,10 @@ namespace Slic3r {
}
// SCALED_EPSILON was a bit too harsh. Now using a config, as some may want some harsh setting and some don't.
coord_t max_variation = std::max(SCALED_EPSILON, scale_(this->m_layers[layer_idx]->m_regions[region_idx]->region()->config().hole_to_polyhole_threshold.get_abs_value(unscaled(diameter_sum / hole.points.size()))));
+ bool twist = this->m_layers[layer_idx]->m_regions[region_idx]->region()->config().hole_to_polyhole_twisted.value;
if (diameter_max - diameter_min < max_variation * 2) {
layerid2center[layer_idx].emplace_back(
- std::tuple<Point, float, int, coord_t>{center, diameter_max, layer->m_regions[region_idx]->region()->config().perimeter_extruder.value, max_variation}, & hole);
+ std::tuple<Point, float, int, coord_t, bool>{center, diameter_max, layer->m_regions[region_idx]->region()->config().perimeter_extruder.value, max_variation, twist}, & hole);
}
}
}
@@ -209,7 +226,7 @@ namespace Slic3r {
}
});
//sort holes per center-diameter
- std::map<std::tuple<Point, float, int, coord_t>, std::vector<std::pair<Polygon*, int>>> id2layerz2hole;
+ std::map<std::tuple<Point, float, int, coord_t, bool>, std::vector<std::pair<Polygon*, int>>> id2layerz2hole;
//search & find hole that span at least X layers
const size_t min_nb_layers = 2;
@@ -217,7 +234,7 @@ namespace Slic3r {
for (size_t layer_idx = 0; layer_idx < this->m_layers.size(); ++layer_idx) {
for (size_t hole_idx = 0; hole_idx < layerid2center[layer_idx].size(); ++hole_idx) {
//get all other same polygons
- std::tuple<Point, float, int, coord_t>& id = layerid2center[layer_idx][hole_idx].first;
+ std::tuple<Point, float, int, coord_t, bool>& id = layerid2center[layer_idx][hole_idx].first;
float max_z = layers()[layer_idx]->print_z;
std::vector<std::pair<Polygon*, int>> holes;
holes.emplace_back(layerid2center[layer_idx][hole_idx].second, layer_idx);
@@ -225,7 +242,7 @@ namespace Slic3r {
if (layers()[search_layer_idx]->print_z - layers()[search_layer_idx]->height - max_z > EPSILON) break;
//search an other polygon with same id
for (size_t search_hole_idx = 0; search_hole_idx < layerid2center[search_layer_idx].size(); ++search_hole_idx) {
- std::tuple<Point, float, int, coord_t>& search_id = layerid2center[search_layer_idx][search_hole_idx].first;
+ std::tuple<Point, float, int, coord_t, bool>& search_id = layerid2center[search_layer_idx][search_hole_idx].first;
if (std::get<2>(id) == std::get<2>(search_id)
&& std::get<0>(id).distance_to(std::get<0>(search_id)) < std::get<3>(id)
&& std::abs(std::get<1>(id) - std::get<1>(search_id)) < std::get<3>(id)
@@ -246,9 +263,9 @@ namespace Slic3r {
}
//create a polyhole per id and replace holes points by it.
for (auto entry : id2layerz2hole) {
- Polygon polyhole = create_polyhole(std::get<0>(entry.first), std::get<1>(entry.first), scale_(print()->config().nozzle_diameter.get_at(std::get<2>(entry.first) - 1)));
- polyhole.make_clockwise();
+ Polygons polyholes = create_polyholes(std::get<0>(entry.first), std::get<1>(entry.first), scale_(print()->config().nozzle_diameter.get_at(std::get<2>(entry.first) - 1)), std::get<4>(entry.first));
for (auto& poly_to_replace : entry.second) {
+ Polygon polyhole = polyholes[poly_to_replace.second % polyholes.size()];
//search the clone in layers->slices
for (ExPolygon& explo_slice : m_layers[poly_to_replace.second]->lslices) {
for (Polygon& poly_slice : explo_slice.holes) {
@@ -286,6 +303,11 @@ namespace Slic3r {
m_typed_slices = false;
}
+ // atomic counter for gui progress
+ std::atomic<int> atomic_count{ 0 };
+ int nb_layers_update = std::max(1, (int)m_layers.size() / 20);
+ std::chrono::time_point<std::chrono::system_clock> last_update = std::chrono::system_clock::now();
+
// compare each layer to the one below, and mark those slices needing
// one additional inner perimeter, like the top of domed objects-
@@ -359,10 +381,22 @@ namespace Slic3r {
BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - start";
tbb::parallel_for(
tbb::blocked_range<size_t>(0, m_layers.size()),
- [this](const tbb::blocked_range<size_t>& range) {
+ [this, &atomic_count, &last_update, nb_layers_update](const tbb::blocked_range<size_t>& range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
+ std::chrono::time_point<std::chrono::system_clock> start_make_perimeter = std::chrono::system_clock::now();
m_print->throw_if_canceled();
m_layers[layer_idx]->make_perimeters();
+
+ // updating progress
+ int nb_layers_done = (++atomic_count);
+ std::chrono::time_point<std::chrono::system_clock> end_make_perimeter = std::chrono::system_clock::now();
+ if (nb_layers_done % nb_layers_update == 0 || (static_cast<std::chrono::duration<double>>(end_make_perimeter - start_make_perimeter)).count() > 5) {
+ if ((static_cast<std::chrono::duration<double>>(end_make_perimeter - last_update)).count() > 0.2) {
+ // note: i don't care if a thread erase last_update in-between here
+ last_update = std::chrono::system_clock::now();
+ m_print->set_status( int((nb_layers_done * 100) / m_layers.size()), L("Generating perimeters: layer %s / %s"), { std::to_string(nb_layers_done), std::to_string(m_layers.size()) });
+ }
+ }
}
}
);
@@ -531,13 +565,30 @@ namespace Slic3r {
if (this->set_started(posInfill)) {
auto [adaptive_fill_octree, support_fill_octree] = this->prepare_adaptive_infill_data();
+ // atomic counter for gui progress
+ std::atomic<int> atomic_count{ 0 };
+ int nb_layers_update = std::max(1, (int)m_layers.size() / 20);
+ std::chrono::time_point<std::chrono::system_clock> last_update = std::chrono::system_clock::now();
+
BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start";
tbb::parallel_for(
tbb::blocked_range<size_t>(0, m_layers.size()),
- [this, &adaptive_fill_octree = adaptive_fill_octree, &support_fill_octree = support_fill_octree](const tbb::blocked_range<size_t>& range) {
+ [this, &adaptive_fill_octree = adaptive_fill_octree, &support_fill_octree = support_fill_octree, &atomic_count , &last_update, nb_layers_update](const tbb::blocked_range<size_t>& range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
+ std::chrono::time_point<std::chrono::system_clock> start_make_fill = std::chrono::system_clock::now();
m_print->throw_if_canceled();
m_layers[layer_idx]->make_fills(adaptive_fill_octree.get(), support_fill_octree.get());
+
+ // updating progress
+ int nb_layers_done = (++atomic_count);
+ std::chrono::time_point<std::chrono::system_clock> end_make_fill = std::chrono::system_clock::now();
+ if (nb_layers_done % nb_layers_update == 0 || (static_cast<std::chrono::duration<double>>(end_make_fill - start_make_fill)).count() > 5) {
+ if ((static_cast<std::chrono::duration<double>>(end_make_fill - last_update)).count() > 0.2) {
+ // note: i don't care if a thread erase last_update in-between here
+ last_update = std::chrono::system_clock::now();
+ m_print->set_status( int((nb_layers_done * 100) / m_layers.size()), L("Infilling layer %s / %s"), { std::to_string(nb_layers_done), std::to_string(m_layers.size()) });
+ }
+ }
}
}
);
@@ -2226,7 +2277,7 @@ namespace Slic3r {
size_t num_extruders = print_config.nozzle_diameter.size();
object_config = object_config_from_model_object(object_config, model_object, num_extruders);
- std::vector<uint16_t> object_extruders;
+ std::set<uint16_t> object_extruders;
for (const ModelVolume* model_volume : model_object.volumes)
if (model_volume->is_model_part()) {
PrintRegion::collect_object_printing_extruders(
@@ -2244,7 +2295,6 @@ namespace Slic3r {
region_config_from_model_volume(default_region_config, &range_and_config.second.get(), *model_volume, num_extruders),
object_extruders);
}
- sort_remove_duplicates(object_extruders);
if (object_max_z <= 0.f)
object_max_z = (float)model_object.raw_bounding_box().size().z();
@@ -2252,17 +2302,29 @@ namespace Slic3r {
}
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
- std::vector<uint16_t> PrintObject::object_extruders() const
+ std::set<uint16_t> PrintObject::object_extruders() const
{
- std::vector<uint16_t> extruders;
- extruders.reserve(this->region_volumes.size() * 3);
+ std::set<uint16_t> extruders;
for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++idx_region)
if (!this->region_volumes[idx_region].empty())
m_print->get_region(idx_region)->collect_object_printing_extruders(extruders);
- sort_remove_duplicates(extruders);
return extruders;
}
+ double PrintObject::get_first_layer_height() const
+ {
+ //get object first layer height
+ double object_first_layer_height = config().first_layer_height.value;
+ if (config().first_layer_height.percent) {
+ object_first_layer_height = 1000000000;
+ for (uint16_t extruder_id : object_extruders()) {
+ double nozzle_diameter = print()->config().nozzle_diameter.values[extruder_id];
+ object_first_layer_height = std::fmin(object_first_layer_height, config().first_layer_height.get_abs_value(nozzle_diameter));
+ }
+ }
+ return object_first_layer_height;
+ }
+
bool PrintObject::update_layer_height_profile(const ModelObject& model_object, const SlicingParameters& slicing_parameters, std::vector<coordf_t>& layer_height_profile)
{
bool updated = false;
@@ -3829,4 +3891,5 @@ static void fix_mesh_connectivity(TriangleMesh &mesh)
return (it == m_layers.begin()) ? nullptr : *(--it);
}
+
} // namespace Slic3r
diff --git a/src/libslic3r/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp
index e62b34ea6..94f1a65f3 100644
--- a/src/libslic3r/PrintRegion.cpp
+++ b/src/libslic3r/PrintRegion.cpp
@@ -108,13 +108,13 @@ coordf_t PrintRegion::bridging_height_avg(const PrintConfig &print_config) const
return this->nozzle_dmr_avg(print_config) * sqrt(m_config.bridge_flow_ratio.get_abs_value(1));
}
-void PrintRegion::collect_object_printing_extruders(const PrintConfig &print_config, const PrintObjectConfig &object_config, const PrintRegionConfig &region_config, std::vector<uint16_t> &object_extruders)
+void PrintRegion::collect_object_printing_extruders(const PrintConfig &print_config, const PrintObjectConfig &object_config, const PrintRegionConfig &region_config, std::set<uint16_t> &object_extruders)
{
// These checks reflect the same logic used in the GUI for enabling/disabling extruder selection fields.
auto num_extruders = (int)print_config.nozzle_diameter.size();
auto emplace_extruder = [num_extruders, &object_extruders](int extruder_id) {
int i = std::max(0, extruder_id - 1);
- object_extruders.emplace_back((i >= num_extruders) ? 0 : i);
+ object_extruders.insert((i >= num_extruders) ? 0 : i);
};
if (region_config.perimeters.value > 0 || object_config.brim_width.value > 0)
emplace_extruder(region_config.perimeter_extruder);
@@ -124,7 +124,7 @@ void PrintRegion::collect_object_printing_extruders(const PrintConfig &print_con
emplace_extruder(region_config.solid_infill_extruder);
}
-void PrintRegion::collect_object_printing_extruders(std::vector<uint16_t> &object_extruders) const
+void PrintRegion::collect_object_printing_extruders(std::set<uint16_t> &object_extruders) const
{
// PrintRegion, if used by some PrintObject, shall have all the extruders set to an existing printer extruder.
// If not, then there must be something wrong with the Print::apply() function.
diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp
index 76003b45f..6423f750a 100644
--- a/src/libslic3r/Slicing.cpp
+++ b/src/libslic3r/Slicing.cpp
@@ -72,17 +72,32 @@ coordf_t Slicing::max_layer_height_from_nozzle(const DynamicPrintConfig &print_c
return check_z_step(std::max(min_layer_height, (max_layer_height == 0.) ? (0.75 * nozzle_dmr) : max_layer_height), print_config.opt_float("z_step"));
}
+
SlicingParameters SlicingParameters::create_from_config(
const PrintConfig &print_config,
const PrintObjectConfig &object_config,
coordf_t object_height,
- const std::vector<uint16_t> &object_extruders)
+ const std::set<uint16_t> &object_extruders)
{
//first layer height is got from the first_layer_height setting unless the value was garbage.
// if the first_layer_height setting depends of the nozzle width, use the first one. Apply the z_step
- coordf_t first_layer_height = (object_config.first_layer_height.get_abs_value(print_config.nozzle_diameter.empty() ? 0. : print_config.nozzle_diameter.get_at(0)) <= 0) ?
- object_config.layer_height.value :
- object_config.first_layer_height.get_abs_value(print_config.nozzle_diameter.get_at(0));
+
+ //get object first layer height
+ double first_layer_height = object_config.first_layer_height.value;
+ if (object_config.first_layer_height.percent) {
+ first_layer_height = 1000000000.;
+ for (uint16_t extruder_id : object_extruders) {
+ if (print_config.nozzle_diameter.size() <= extruder_id)
+ break;
+ double nozzle_diameter = print_config.nozzle_diameter.values[extruder_id];
+ first_layer_height = std::min(first_layer_height, object_config.first_layer_height.get_abs_value(nozzle_diameter));
+ }
+ if (first_layer_height == 1000000000.)
+ first_layer_height = 0;
+ }
+
+ if (first_layer_height == 0)
+ object_config.layer_height.value;
first_layer_height = check_z_step(first_layer_height, print_config.z_step);
// If object_config.support_material_extruder == 0 resp. object_config.support_material_interface_extruder == 0,
// print_config.nozzle_diameter.get_at(size_t(-1)) returns the 0th nozzle diameter,
diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp
index e8e0888c8..4d18e342f 100644
--- a/src/libslic3r/Slicing.hpp
+++ b/src/libslic3r/Slicing.hpp
@@ -35,7 +35,7 @@ struct SlicingParameters
const PrintConfig &print_config,
const PrintObjectConfig &object_config,
coordf_t object_height,
- const std::vector<uint16_t> &object_extruders);
+ const std::set<uint16_t> &object_extruders);
// Has any raft layers?
bool has_raft() const { return raft_layers() > 0; }
diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp
index d85d77a77..f7d751b14 100644
--- a/src/libslic3r/SupportMaterial.cpp
+++ b/src/libslic3r/SupportMaterial.cpp
@@ -172,7 +172,7 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object
m_can_merge_support_regions = m_object_config->support_material_extruder.value == m_object_config->support_material_interface_extruder.value;
if (! m_can_merge_support_regions && (m_object_config->support_material_extruder.value == 0 || m_object_config->support_material_interface_extruder.value == 0)) {
// One of the support extruders is of "don't care" type.
- auto object_extruders = m_object->print()->object_extruders(m_object->print()->objects());
+ std::set<uint16_t> object_extruders = m_object->print()->object_extruders(m_object->print()->objects());
if (object_extruders.size() == 1 &&
*object_extruders.begin() == std::max<unsigned int>(m_object_config->support_material_extruder.value, m_object_config->support_material_interface_extruder.value))
// Object is printed with the same extruder as the support.
diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h
index 71103513b..1c5057687 100644
--- a/src/libslic3r/libslic3r.h
+++ b/src/libslic3r/libslic3r.h
@@ -16,6 +16,7 @@
#include <stdint.h>
#include <stdarg.h>
#include <vector>
+#include <set>
#include <cassert>
#include <cmath>
#include <type_traits>
@@ -99,11 +100,10 @@ extern Semver SEMVER;
template<typename T, typename Q>
inline T unscale(Q v) { return T(v) * T(SCALING_FACTOR); }
-inline double unscaled(double v) { return v * SCALING_FACTOR; }
-inline coordf_t unscale_(coord_t v) { return v * SCALING_FACTOR; }
-inline coord_t scale_t(coordf_t v) { return (coord_t)(v * UNSCALING_FACTOR); }
-inline double scale_d(coordf_t v) { return (v * UNSCALING_FACTOR); }
-inline double scale_d(coord_t v) { return (double(v) * UNSCALING_FACTOR); }
+inline double unscaled(coord_t v) { return double(v) * SCALING_FACTOR; }
+inline double unscaled(coordf_t v) { return v * SCALING_FACTOR; }
+inline coord_t scale_t(double v) { return coord_t(v * UNSCALING_FACTOR); }
+inline coordf_t scale_d(double v) { return coordf_t(v * UNSCALING_FACTOR); }
enum Axis {
X=0,
@@ -126,6 +126,15 @@ inline void append(std::vector<T>& dest, const std::vector<T>& src)
}
template <typename T>
+inline void append(std::set<T>& dest, const std::set<T>& src)
+{
+ if (dest.empty())
+ dest = src;
+ else
+ dest.insert(src.begin(), src.end());
+}
+
+template <typename T>
inline void append(std::vector<T>& dest, std::vector<T>&& src)
{
if (dest.empty())
diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp
index 4dcea595e..54ddeac97 100644
--- a/src/slic3r/GUI/3DBed.cpp
+++ b/src/slic3r/GUI/3DBed.cpp
@@ -337,7 +337,11 @@ void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox)
Polylines axes_lines;
Polylines axes_lines_big;
Polylines axes_lines_small;
- for (coord_t x = bed_bbox.min(0), idx= 0; x <= bed_bbox.max(0); x += scale_(5.0), idx++) {
+ coord_t square = scale_(5);
+ while (bed_bbox.radius() > square * 100) {
+ square *= 10;
+ }
+ for (coord_t x = bed_bbox.min(0), idx= 0; x <= bed_bbox.max(0); x += square, idx++) {
Polyline line;
line.append(Point(x, bed_bbox.min(1)));
line.append(Point(x, bed_bbox.max(1)));
@@ -348,7 +352,7 @@ void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox)
else
axes_lines.push_back(line);
}
- for (coord_t y = bed_bbox.min(1), idx = 0; y <= bed_bbox.max(1); y += scale_(5.0), idx++) {
+ for (coord_t y = bed_bbox.min(1), idx = 0; y <= bed_bbox.max(1); y += square, idx++) {
Polyline line;
line.append(Point(bed_bbox.min(0), y));
line.append(Point(bed_bbox.max(0), y));
diff --git a/src/slic3r/GUI/CalibrationAbstractDialog.cpp b/src/slic3r/GUI/CalibrationAbstractDialog.cpp
index 4b72513f6..620ce5e46 100644
--- a/src/slic3r/GUI/CalibrationAbstractDialog.cpp
+++ b/src/slic3r/GUI/CalibrationAbstractDialog.cpp
@@ -124,6 +124,7 @@ ModelObject* CalibrationAbstractDialog::add_part(ModelObject* model_object, std:
// set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
+ new_volume->config.set_key_value("first_layer_extruder", new ConfigOptionInt(0));
//move to bed
/* const TriangleMesh& hull = new_volume->get_convex_hull();
diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp
index 9fcf901e5..532c5d29b 100644
--- a/src/slic3r/GUI/ConfigManipulation.cpp
+++ b/src/slic3r/GUI/ConfigManipulation.cpp
@@ -430,7 +430,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
for (auto el : { "solid_fill_pattern", "infill_connection_solid" })
toggle_field(el, has_solid_infill); // should be top_solid_layers") > 1 || bottom_solid_layers") > 1
- toggle_field("hole_to_polyhole_threshold", config->opt_bool("hole_to_polyhole"));
+ for (auto el : { "hole_to_polyhole_threshold", "hole_to_polyhole_twisted" })
+ toggle_field(el, config->opt_bool("hole_to_polyhole"));
bool have_default_acceleration = config->option<ConfigOptionFloatOrPercent>("default_acceleration")->value > 0;
for (auto el : { "perimeter_acceleration", "infill_acceleration",
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 92811abb4..2157709e9 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -65,6 +65,7 @@
#include <float.h>
#include <algorithm>
#include <cmath>
+#include <set>
#include "DoubleSlider.hpp"
#include <imgui/imgui_internal.h>
@@ -1339,9 +1340,10 @@ void GLCanvas3D::reset_volumes(bool is_destroying)
_set_current();
- m_selection.clear(is_destroying);
- m_volumes.clear();
- m_dirty = true;
+ m_selection.clear(is_destroying);
+ m_volumes.release_geometry();
+ m_volumes.clear();
+ m_dirty = true;
if(!is_destroying)
_set_warning_texture(WarningTexture::ObjectOutside, false);
@@ -2326,21 +2328,21 @@ static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume&
vol_old.finalize_geometry(gl_initialized);
}
-void GLCanvas3D::load_gcode_preview(const GCodeProcessor::Result& gcode_result)
+void GLCanvas3D::load_gcode_preview(const GCodeProcessor::Result& gcode_result, const std::vector<std::string>& str_tool_colors)
{
- m_gcode_viewer.load(gcode_result, *this->fff_print(), m_initialized);
+ if (m_dirty_gcode) {
+ m_dirty_gcode = false;
+ m_gcode_viewer.load(gcode_result, *this->fff_print(), m_initialized);
- if (wxGetApp().is_editor()) {
- m_gcode_viewer.update_shells_color_by_extruder(m_config);
- _show_warning_texture_if_needed(WarningTexture::ToolpathOutside);
- }
-}
+ if (wxGetApp().is_editor()) {
+ m_gcode_viewer.update_shells_color_by_extruder(m_config);
+ _show_warning_texture_if_needed(WarningTexture::ToolpathOutside);
+ }
-void GLCanvas3D::refresh_gcode_preview(const GCodeProcessor::Result& gcode_result, const std::vector<std::string>& str_tool_colors)
-{
- m_gcode_viewer.refresh(gcode_result, str_tool_colors);
- set_as_dirty();
- request_extra_frame();
+ m_gcode_viewer.refresh(gcode_result, str_tool_colors);
+ set_as_dirty();
+ request_extra_frame();
+ }
}
#if ENABLE_RENDER_PATH_REFRESH_AFTER_OPTIONS_CHANGE
@@ -2367,23 +2369,27 @@ void GLCanvas3D::load_sla_preview()
void GLCanvas3D::load_preview(const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values)
{
- const Print *print = this->fff_print();
+ const Print* print = this->fff_print();
if (print == nullptr)
return;
_set_current();
- // Release OpenGL data before generating new data.
- this->reset_volumes();
+ if (m_dirty_preview || m_volumes.empty()) {
+ m_dirty_preview = false;
+ // Release OpenGL data before generating new data.
+ this->reset_volumes();
+ //note: this isn't releasing all the memory in all os, can make it crash on linux for exemple.
- _load_print_toolpaths();
- _load_wipe_tower_toolpaths(str_tool_colors);
- for (const PrintObject* object : print->objects())
+ _load_print_toolpaths();
+ _load_wipe_tower_toolpaths(str_tool_colors);
+ for (const PrintObject* object : print->objects())
_load_print_object_toolpaths(*object, str_tool_colors, color_print_values);
- _update_toolpath_volumes_outside_state();
- _show_warning_texture_if_needed(WarningTexture::ToolpathOutside);
+ _update_toolpath_volumes_outside_state();
+ _show_warning_texture_if_needed(WarningTexture::ToolpathOutside);
}
+}
void GLCanvas3D::bind_event_handlers()
{
@@ -4835,7 +4841,7 @@ bool GLCanvas3D::_init_collapse_toolbar()
bool GLCanvas3D::_set_current()
{
return m_context != nullptr && m_canvas->SetCurrent(*m_context);
- }
+}
void GLCanvas3D::_resize(unsigned int w, unsigned int h)
{
@@ -5801,9 +5807,11 @@ void GLCanvas3D::_load_print_toolpaths()
//skirt & brim from objects
for (const PrintObject* print_object : print->objects()) {
if (!print_object->brim().empty())
- _3DScene::extrusionentity_to_verts(print_object->brim(), print_zs[i], Point(0, 0), *volume);
+ for(const PrintInstance& inst : print_object->instances())
+ _3DScene::extrusionentity_to_verts(print_object->brim(), print_zs[i], inst.shift, *volume);
if (print_object->skirt_first_layer())
- _3DScene::extrusionentity_to_verts(*print_object->skirt_first_layer(), print_zs[i], Point(0, 0), *volume);
+ for (const PrintInstance& inst : print_object->instances())
+ _3DScene::extrusionentity_to_verts(*print_object->skirt_first_layer(), print_zs[i], inst.shift, *volume);
}
}
//skirts from print
@@ -5812,7 +5820,8 @@ void GLCanvas3D::_load_print_toolpaths()
//skirts from objects
for (const PrintObject* print_object : print->objects()) {
if ( !print_object->skirt().empty() && (i != 0 || !print_object->skirt_first_layer()))
- _3DScene::extrusionentity_to_verts(print_object->skirt(), print_zs[i], Point(0, 0), *volume);
+ for (const PrintInstance& inst : print_object->instances())
+ _3DScene::extrusionentity_to_verts(print_object->skirt(), print_zs[i], inst.shift, *volume);
}
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
if (volume->indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index 7d6238c80..a13df2036 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -475,6 +475,8 @@ private:
// Screen is only refreshed from the OnIdle handler if it is dirty.
bool m_dirty;
+ bool m_dirty_preview = true;
+ bool m_dirty_gcode = true;
bool m_initialized;
bool m_apply_zoom_to_volumes_filter;
mutable std::vector<int> m_hover_volume_idxs;
@@ -557,6 +559,9 @@ public:
void post_event(wxEvent &&event);
void set_as_dirty();
+ void set_preview_dirty() { m_dirty_preview = true; }
+ bool is_preview_dirty() { return m_dirty_preview; }
+ void set_gcode_viewer_dirty() { m_dirty_gcode = true; }
void set_items_show(bool show_objects, bool show_gcode);
unsigned int get_volumes_count() const;
@@ -666,8 +671,7 @@ public:
void reload_scene(bool refresh_immediately, bool force_full_scene_refresh = false);
- void load_gcode_preview(const GCodeProcessor::Result& gcode_result);
- void refresh_gcode_preview(const GCodeProcessor::Result& gcode_result, const std::vector<std::string>& str_tool_colors);
+ void load_gcode_preview(const GCodeProcessor::Result& gcode_result, const std::vector<std::string>& str_tool_colors);
#if ENABLE_RENDER_PATH_REFRESH_AFTER_OPTIONS_CHANGE
void refresh_gcode_preview_render_paths();
#endif // ENABLE_RENDER_PATH_REFRESH_AFTER_OPTIONS_CHANGE
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index d6e8cc242..207b8f597 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -416,8 +416,9 @@ void Preview::reload_print(bool keep_volumes)
#ifdef __linux__
m_volumes_cleanup_required ||
#endif /* __linux__ */
- !keep_volumes)
+ (!keep_volumes && m_canvas->is_preview_dirty()))
{
+ m_canvas->set_preview_dirty();
m_canvas->reset_volumes();
m_loaded = false;
#ifdef __linux__
@@ -1020,8 +1021,9 @@ void Preview::load_print_as_fff(bool keep_z_range)
m_canvas->set_selected_extruder(0);
if (current_force_state == ForceState::ForceGcode || (gcode_preview_data_valid && current_force_state != ForceState::ForceExtrusions)) {
// Load the real G-code preview.
- m_canvas->load_gcode_preview(*m_gcode_result);
- m_canvas->refresh_gcode_preview(*m_gcode_result, colors);
+ if (current_force_state == ForceState::NoForce)
+ m_canvas->set_items_show(false, true);
+ m_canvas->load_gcode_preview(*m_gcode_result, colors);
m_left_sizer->Show(m_bottom_toolbar_panel);
m_left_sizer->Layout();
Refresh();
@@ -1029,6 +1031,8 @@ void Preview::load_print_as_fff(bool keep_z_range)
m_loaded = true;
} else {
// Load the initial preview based on slices, not the final G-code.
+ if (current_force_state == ForceState::NoForce)
+ m_canvas->set_items_show(true, false);
m_canvas->load_preview(colors, color_print_values);
m_left_sizer->Hide(m_bottom_toolbar_panel);
m_left_sizer->Layout();
@@ -1039,8 +1043,9 @@ void Preview::load_print_as_fff(bool keep_z_range)
// all layers filtered out
hide_layers_slider();
m_canvas_widget->Refresh();
- } else
+ } else {
update_layers_slider(zs, keep_z_range);
+ }
}
#if ENABLE_PREVIEW_TYPE_CHANGE
@@ -1071,6 +1076,13 @@ void Preview::load_print_as_fff(bool keep_z_range)
#endif // ENABLE_PREVIEW_TYPE_CHANGE
}
+void Preview::reset_gcode_toolpaths()
+{
+ if (current_force_state == ForceState::NoForce)
+ m_canvas->set_items_show(true, false);
+ m_canvas->reset_gcode_toolpaths();
+}
+
void Preview::load_print_as_sla()
{
if (m_loaded || (m_process->current_printer_technology() != ptSLA))
diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp
index 8c72d7a3f..5b4d7f50e 100644
--- a/src/slic3r/GUI/GUI_Preview.hpp
+++ b/src/slic3r/GUI/GUI_Preview.hpp
@@ -203,6 +203,7 @@ Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSl
bool can_display_gcode();
bool can_display_volume();
+ void reset_gcode_toolpaths();
private:
ForceState current_force_state = ForceState::NoForce;
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 1dac5e694..c5269a882 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -1700,7 +1700,7 @@ void MainFrame::quick_slice(const int qs)
wxFileDialog dlg(this, from_u8((boost::format(_utf8(L("Save %s file as:"))) % ((qs & qsExportSVG) ? _L("SVG") : _L("G-code"))).str()),
wxGetApp().app_config->get_last_output_dir(get_dir_name(output_file)), get_base_name(input_file),
qs & qsExportSVG ? file_wildcards(FT_SVG) : file_wildcards(FT_GCODE),
- wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+ wxFD_SAVE | (wxGetApp().app_config->get_show_overwrite_dialog() ? wxFD_OVERWRITE_PROMPT : 0));
if (dlg.ShowModal() != wxID_OK)
return;
output_file = dlg.GetPath();
@@ -1711,7 +1711,7 @@ void MainFrame::quick_slice(const int qs)
else if (qs & qsExportPNG) {
wxFileDialog dlg(this, _L("Save zip file as:"),
wxGetApp().app_config->get_last_output_dir(get_dir_name(output_file)),
- get_base_name(output_file), "*.sl1", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+ get_base_name(output_file), "*.sl1", wxFD_SAVE | (wxGetApp().app_config->get_show_overwrite_dialog() ? wxFD_OVERWRITE_PROMPT : 0));
if (dlg.ShowModal() != wxID_OK)
return;
output_file = dlg.GetPath();
@@ -1773,7 +1773,7 @@ void MainFrame::repair_stl()
{
wxFileDialog dlg( this, L("Save OBJ file (less prone to coordinate errors than STL) as:"),
get_dir_name(output_file), get_base_name(output_file, ".obj"),
- file_wildcards(FT_OBJ), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+ file_wildcards(FT_OBJ), wxFD_SAVE | (wxGetApp().app_config->get_show_overwrite_dialog() ? wxFD_OVERWRITE_PROMPT : 0));
if (dlg.ShowModal() != wxID_OK)
return;
output_file = dlg.GetPath();
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 4337cb5f9..fcd568603 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -2750,7 +2750,7 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type)
wxFileDialog dlg(q, dlg_title,
from_path(output_file.parent_path()), from_path(output_file.filename()),
- wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+ wildcard, wxFD_SAVE |(wxGetApp().app_config->get_show_overwrite_dialog() ? wxFD_OVERWRITE_PROMPT : 0) );
if (dlg.ShowModal() != wxID_OK)
return wxEmptyString;
@@ -3576,8 +3576,14 @@ void Plater::priv::set_current_panel(wxTitledPanel* panel)
// FIXME: it may be better to have a single function making this check and let it be called wherever needed
bool export_in_progress = this->background_process.is_export_scheduled();
bool model_fits = view3D->check_volumes_outside_state() != ModelInstancePVS_Partly_Outside;
- if (!model.objects.empty() && !export_in_progress && model_fits)
- this->q->reslice();
+
+ if (!model.objects.empty() && !export_in_progress && model_fits) {
+ //check if already slicing
+ bool already_running = this->background_process.state() == BackgroundSlicingProcess::State::STATE_RUNNING ||
+ this->background_process.state() == BackgroundSlicingProcess::State::STATE_STARTED;
+ if(!already_running)
+ this->q->reslice();
+ }
// keeps current gcode preview, if any
preview->reload_print(true);
}
@@ -3669,7 +3675,24 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
}
this->statusbar()->set_progress(evt.status.percent);
- this->statusbar()->set_status_text(_(evt.status.text) + wxString::FromUTF8("…"));
+ if (evt.status.args.empty()) {
+ this->statusbar()->set_status_text(_(evt.status.main_text) + wxString::FromUTF8("…"));
+ } else {
+ std::vector<wxString> arg_lst;
+ for (std::string str : evt.status.args)
+ arg_lst.push_back(_(str));
+ //FIXME use var-args list
+ if (arg_lst.size() == 1)
+ this->statusbar()->set_status_text(wxString::Format(_(evt.status.main_text), arg_lst[0]));
+ else if (arg_lst.size() == 2)
+ this->statusbar()->set_status_text(wxString::Format(_(evt.status.main_text), arg_lst[0], arg_lst[1]));
+ else if (arg_lst.size() == 3)
+ this->statusbar()->set_status_text(wxString::Format(_(evt.status.main_text), arg_lst[0], arg_lst[1], arg_lst[2]));
+ else if (arg_lst.size() == 4)
+ this->statusbar()->set_status_text(wxString::Format(_(evt.status.main_text), arg_lst[0], arg_lst[1], arg_lst[2], arg_lst[3]));
+ else
+ this->statusbar()->set_status_text(wxString::Format(_(evt.status.main_text), arg_lst[0], arg_lst[1], arg_lst[2], arg_lst[3], arg_lst[4]));
+ }
//notification_manager->set_progress_bar_percentage("Slicing progress", (float)evt.status.percent / 100.0f);
}
if (evt.status.flags & (PrintBase::SlicingStatus::RELOAD_SCENE | PrintBase::SlicingStatus::RELOAD_SLA_SUPPORT_POINTS)) {
@@ -3722,6 +3745,7 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
void Plater::priv::on_slicing_completed(wxCommandEvent & evt)
{
+ preview->get_canvas3d()->set_gcode_viewer_dirty();
// auto_switch_preview == 0 means "no force tab change"
// auto_switch_preview == 1 means "force tab change"
// auto_switch_preview == 2 means "force tab change only if already on a plater one"
@@ -3753,6 +3777,8 @@ void Plater::priv::on_slicing_began()
{
clear_warnings();
notification_manager->close_notification_of_type(NotificationType::SlicingComplete);
+ preview->get_canvas3d()->set_gcode_viewer_dirty();
+ preview->get_canvas3d()->set_preview_dirty();
}
void Plater::priv::add_warning(const Slic3r::PrintStateBase::Warning& warning, size_t oid)
{
@@ -4390,7 +4416,7 @@ void Plater::priv::enable_preview_moves_slider(bool enable)
void Plater::priv::reset_gcode_toolpaths()
{
- preview->get_canvas3d()->reset_gcode_toolpaths();
+ preview->reset_gcode_toolpaths();
}
bool Plater::priv::can_set_instance_to_object() const
@@ -5506,12 +5532,12 @@ void Plater::export_gcode(bool prefer_removable)
fs::path output_path;
{
- std::string ext = default_output_file.extension().string();
+ std::string ext = default_output_file.extension().string();
wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _L("Save G-code file as:") : _L("Save SL1 / SL1S file as:"),
start_dir,
from_path(default_output_file.filename()),
GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : boost::iequals(ext, ".sl1s") ? FT_SL1S : FT_SL1, ext),
- wxFD_SAVE | wxFD_OVERWRITE_PROMPT
+ wxFD_SAVE | (wxGetApp().app_config->get_show_overwrite_dialog() ? wxFD_OVERWRITE_PROMPT : 0)
);
if (dlg.ShowModal() == wxID_OK)
output_path = into_path(dlg.GetPath());
@@ -6126,9 +6152,14 @@ void Plater::force_print_bed_update()
void Plater::on_activate()
{
-#if defined(__linux__) || defined(_WIN32)
// Activating the main frame, and no window has keyboard focus.
// Set the keyboard focus to the visible Canvas3D.
+#if defined(__linux__)
+ if (this->p->view3D->IsShown() && wxWindow::FindFocus() != this->p->view3D->get_wxglcanvas())
+ this->p->view3D->get_wxglcanvas()->SetFocus();
+ else if (this->p->preview->IsShown() && wxWindow::FindFocus() != this->p->view3D->get_wxglcanvas())
+ this->p->preview->get_wxglcanvas()->SetFocus();
+#elif defined(_WIN32)
if (this->p->view3D->IsShown() && wxWindow::FindFocus() != this->p->view3D->get_wxglcanvas())
CallAfter([this]() { this->p->view3D->get_wxglcanvas()->SetFocus(); });
else if (this->p->preview->IsShown() && wxWindow::FindFocus() != this->p->view3D->get_wxglcanvas())
diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp
index 258eaf0ee..07051d939 100644
--- a/src/slic3r/GUI/Preferences.cpp
+++ b/src/slic3r/GUI/Preferences.cpp
@@ -35,12 +35,29 @@ static std::shared_ptr<ConfigOptionsGroup>create_options_tab(const wxString& tit
return optgroup;
}
-static void activate_options_tab(std::shared_ptr<ConfigOptionsGroup> optgroup)
+std::shared_ptr<ConfigOptionsGroup> PreferencesDialog::create_general_options_group(const wxString& title, wxNotebook* tabs)
+{
+
+ std::shared_ptr<ConfigOptionsGroup> optgroup = std::make_shared<ConfigOptionsGroup>((wxPanel*)tabs->GetPage(0), title);
+ optgroup->title_width = 40;
+ optgroup->label_width = 40;
+ optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
+ if (opt_key == "default_action_on_close_application" || opt_key == "default_action_on_select_preset")
+ m_values[opt_key] = boost::any_cast<bool>(value) ? "none" : "discard";
+ else if (std::unordered_set<std::string>{ "splash_screen_editor", "splash_screen_gcodeviewer", "auto_switch_preview" }.count(opt_key) > 0)
+ m_values[opt_key] = boost::any_cast<std::string>(value);
+ else
+ m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0";
+ };
+ return optgroup;
+}
+
+static void activate_options_tab(std::shared_ptr<ConfigOptionsGroup> optgroup, int padding = 20)
{
optgroup->activate();
optgroup->update_visibility(comSimple);
wxBoxSizer* sizer = static_cast<wxBoxSizer*>(static_cast<wxPanel*>(optgroup->parent())->GetSizer());
- sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 20);
+ sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, padding);
}
void PreferencesDialog::build()
@@ -55,45 +72,33 @@ void PreferencesDialog::build()
// Add "General" tab
m_optgroup_general = create_options_tab(_L("General"), tabs);
- m_optgroup_general->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
- if (opt_key == "default_action_on_close_application" || opt_key == "default_action_on_select_preset")
- m_values[opt_key] = boost::any_cast<bool>(value) ? "none" : "discard";
- else if (std::unordered_set<std::string>{ "splash_screen_editor" ,"splash_screen_gcodeviewer" ,"auto_switch_preview" }.count(opt_key) > 0)
- m_values[opt_key] = boost::any_cast<std::string>(value);
- else
- m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0";
- };
bool is_editor = wxGetApp().is_editor();
ConfigOptionDef def;
Option option(def, "");
- if (is_editor) {
- def.label = L("Remember output directory");
- def.type = coBool;
- def.tooltip = L("If this is enabled, Slic3r will prompt the last output directory "
- "instead of the one containing the input files.");
- def.set_default_value(new ConfigOptionBool{ app_config->has("remember_output_path") ? app_config->get("remember_output_path") == "1" : true });
- option = Option(def, "remember_output_path");
- m_optgroup_general->append_single_option_line(option);
- def.label = L("Auto-center parts");
- def.type = coBool;
- def.tooltip = L("If this is enabled, Slic3r will auto-center objects "
- "around the print bed center.");
- def.set_default_value(new ConfigOptionBool{ app_config->get("autocenter") == "1" });
- option = Option(def, "autocenter");
- m_optgroup_general->append_single_option_line(option);
+ if (is_editor) {
- def.label = L("Background processing");
- def.type = coBool;
- def.tooltip = L("If this is enabled, Slic3r will pre-process objects as soon "
- "as they\'re loaded in order to save time when exporting G-code.");
- def.set_default_value(new ConfigOptionBool{ app_config->get("background_processing") == "1" });
- option = Option(def, "background_processing");
- m_optgroup_general->append_single_option_line(option);
+ //activate_options_tab(m_optgroup_general, 3);
+ m_optgroup_general = create_general_options_group(_L("Automation"), tabs);
+
+ def.label = L("Auto-center parts");
+ def.type = coBool;
+ def.tooltip = L("If this is enabled, Slic3r will auto-center objects "
+ "around the print bed center.");
+ def.set_default_value(new ConfigOptionBool{ app_config->get("autocenter") == "1" });
+ option = Option(def, "autocenter");
+ m_optgroup_general->append_single_option_line(option);
+
+ def.label = L("Background processing");
+ def.type = coBool;
+ def.tooltip = L("If this is enabled, Slic3r will pre-process objects as soon "
+ "as they\'re loaded in order to save time when exporting G-code.");
+ def.set_default_value(new ConfigOptionBool{ app_config->get("background_processing") == "1" });
+ option = Option(def, "background_processing");
+ m_optgroup_general->append_single_option_line(option);
- if (is_editor) {
def_combobox_auto_switch_preview.label = L("Switch to Preview when sliced");
def_combobox_auto_switch_preview.type = coStrings;
def_combobox_auto_switch_preview.tooltip = L("When an object is sliced, it will switch your view from the curent view to the "
@@ -104,7 +109,7 @@ void PreferencesDialog::build()
def_combobox_auto_switch_preview.enum_values.push_back(_u8L("Switch when possible"));
def_combobox_auto_switch_preview.enum_values.push_back(_u8L("Only if on plater"));
def_combobox_auto_switch_preview.enum_values.push_back(_u8L("Only when GCode is ready"));
- if(app_config->get("auto_switch_preview") == "0")
+ if (app_config->get("auto_switch_preview") == "0")
def_combobox_auto_switch_preview.set_default_value(new ConfigOptionStrings{ def_combobox_auto_switch_preview.enum_values[0] });
else if (app_config->get("auto_switch_preview") == "1")
def_combobox_auto_switch_preview.set_default_value(new ConfigOptionStrings{ def_combobox_auto_switch_preview.enum_values[1] });
@@ -116,23 +121,60 @@ void PreferencesDialog::build()
def_combobox_auto_switch_preview.set_default_value(new ConfigOptionStrings{ def_combobox_auto_switch_preview.enum_values[2] });
option = Option(def_combobox_auto_switch_preview, "auto_switch_preview");
m_optgroup_general->append_single_option_line(option);
- }
- // Please keep in sync with ConfigWizard
- def.label = L("Check for application updates");
- def.type = coBool;
- def.tooltip = L("If enabled, Slic3r will check for the new versions of itself online. When a new version becomes available a notification is displayed at the next application startup (never during program usage). This is only a notification mechanisms, no automatic installation is done.");
- def.set_default_value(new ConfigOptionBool(app_config->get("version_check") == "1"));
- option = Option(def, "version_check");
- m_optgroup_general->append_single_option_line(option);
- // Please keep in sync with ConfigWizard
- def.label = L("Export sources full pathnames to 3mf and amf");
- def.type = coBool;
- def.tooltip = L("If enabled, allows the Reload from disk command to automatically find and load the files when invoked.");
- def.set_default_value(new ConfigOptionBool(app_config->get("export_sources_full_pathnames") == "1"));
- option = Option(def, "export_sources_full_pathnames");
- m_optgroup_general->append_single_option_line(option);
+ activate_options_tab(m_optgroup_general, 3);
+ m_optgroup_general = create_general_options_group(_L("Presets and updates"), tabs);
+
+ // Please keep in sync with ConfigWizard
+ def.label = L("Check for application updates");
+ def.type = coBool;
+ def.tooltip = L("If enabled, Slic3r will check for the new versions of itself online. When a new version becomes available a notification is displayed at the next application startup (never during program usage). This is only a notification mechanisms, no automatic installation is done.");
+ def.set_default_value(new ConfigOptionBool(app_config->get("version_check") == "1"));
+ option = Option(def, "version_check");
+ m_optgroup_general->append_single_option_line(option);
+
+ // Please keep in sync with ConfigWizard
+ def.label = L("Update built-in Presets automatically");
+ def.type = coBool;
+ def.tooltip = L("If enabled, Slic3r downloads updates of built-in system presets in the background. These updates are downloaded into a separate temporary location. When a new preset version becomes available it is offered at application startup.");
+ def.set_default_value(new ConfigOptionBool(app_config->get("preset_update") == "1"));
+ option = Option(def, "preset_update");
+ m_optgroup_general->append_single_option_line(option);
+
+ def.label = L("Suppress \" - default - \" presets");
+ def.type = coBool;
+ def.tooltip = L("Suppress \" - default - \" presets in the Print / Filament / Printer "
+ "selections once there are any other valid presets available.");
+ def.set_default_value(new ConfigOptionBool{ app_config->get("no_defaults") == "1" });
+ option = Option(def, "no_defaults");
+ m_optgroup_general->append_single_option_line(option);
+
+ def.label = L("Show incompatible print and filament presets");
+ def.type = coBool;
+ def.tooltip = L("When checked, the print and filament presets are shown in the preset editor "
+ "even if they are marked as incompatible with the active printer");
+ def.set_default_value(new ConfigOptionBool{ app_config->get("show_incompatible_presets") == "1" });
+ option = Option(def, "show_incompatible_presets");
+ m_optgroup_general->append_single_option_line(option);
+
+ def.label = L("Main GUI always in expert mode");
+ def.type = coBool;
+ def.tooltip = L("If enabled, the gui will be in expert mode even if the simple or advanced mode is selected (but not the setting tabs).");
+ def.set_default_value(new ConfigOptionBool{ app_config->get("objects_always_expert") == "1" });
+ option = Option(def, "objects_always_expert");
+ m_optgroup_general->append_single_option_line(option);
+
+ activate_options_tab(m_optgroup_general, 3);
+ m_optgroup_general = create_general_options_group(_L("Files"), tabs);
+
+ // Please keep in sync with ConfigWizard
+ def.label = L("Export sources full pathnames to 3mf and amf");
+ def.type = coBool;
+ def.tooltip = L("If enabled, allows the Reload from disk command to automatically find and load the files when invoked.");
+ def.set_default_value(new ConfigOptionBool(app_config->get("export_sources_full_pathnames") == "1"));
+ option = Option(def, "export_sources_full_pathnames");
+ m_optgroup_general->append_single_option_line(option);
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
#ifdef _WIN32
@@ -153,36 +195,16 @@ void PreferencesDialog::build()
#endif // _WIN32
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
- // Please keep in sync with ConfigWizard
- def.label = L("Update built-in Presets automatically");
- def.type = coBool;
- def.tooltip = L("If enabled, Slic3r downloads updates of built-in system presets in the background. These updates are downloaded into a separate temporary location. When a new preset version becomes available it is offered at application startup.");
- def.set_default_value(new ConfigOptionBool(app_config->get("preset_update") == "1"));
- option = Option(def, "preset_update");
- m_optgroup_general->append_single_option_line(option);
+ def.label = L("Remember output directory");
+ def.type = coBool;
+ def.tooltip = L("If this is enabled, Slic3r will prompt the last output directory "
+ "instead of the one containing the input files.");
+ def.set_default_value(new ConfigOptionBool{ app_config->has("remember_output_path") ? app_config->get("remember_output_path") == "1" : true });
+ option = Option(def, "remember_output_path");
+ m_optgroup_general->append_single_option_line(option);
- def.label = L("Suppress \" - default - \" presets");
- def.type = coBool;
- def.tooltip = L("Suppress \" - default - \" presets in the Print / Filament / Printer "
- "selections once there are any other valid presets available.");
- def.set_default_value(new ConfigOptionBool{ app_config->get("no_defaults") == "1" });
- option = Option(def, "no_defaults");
- m_optgroup_general->append_single_option_line(option);
-
- def.label = L("Show incompatible print and filament presets");
- def.type = coBool;
- def.tooltip = L("When checked, the print and filament presets are shown in the preset editor "
- "even if they are marked as incompatible with the active printer");
- def.set_default_value(new ConfigOptionBool{ app_config->get("show_incompatible_presets") == "1" });
- option = Option(def, "show_incompatible_presets");
- m_optgroup_general->append_single_option_line(option);
-
- def.label = L("Main GUI always in expert mode");
- def.type = coBool;
- def.tooltip = L("If enabled, the gui will be in expert mode even if the simple or advanced mode is selected (but not the setting tabs).");
- def.set_default_value(new ConfigOptionBool{ app_config->get("objects_always_expert") == "1" });
- option = Option(def, "objects_always_expert");
- m_optgroup_general->append_single_option_line(option);
+ activate_options_tab(m_optgroup_general, 3);
+ m_optgroup_general = create_general_options_group(_L("Dialogs"), tabs);
def.label = L("Show drop project dialog");
def.type = coBool;
@@ -191,6 +213,13 @@ void PreferencesDialog::build()
option = Option(def, "show_drop_project_dialog");
m_optgroup_general->append_single_option_line(option);
+ def.label = L("Show overwrite dialog.");
+ def.type = coBool;
+ def.tooltip = L("If this is enabled, Slic3r will prompt for when overwriting files from save dialogs.");
+ def.set_default_value(new ConfigOptionBool{ app_config->has("show_overwrite_dialog") ? app_config->get("show_overwrite_dialog") == "1" : true });
+ option = Option(def, "show_overwrite_dialog");
+ m_optgroup_general->append_single_option_line(option);
+
#if __APPLE__
def.label = (boost::format(_u8L("Allow just a single %1% instance")) % SLIC3R_APP_NAME).str();
@@ -201,9 +230,9 @@ void PreferencesDialog::build()
def.type = coBool;
def.tooltip = L("If this is enabled, when starting Slic3r and another instance of the same Slic3r is already running, that instance will be reactivated instead.");
#endif
- def.set_default_value(new ConfigOptionBool{ app_config->has("single_instance") ? app_config->get("single_instance") == "1" : false });
- option = Option(def, "single_instance");
- m_optgroup_general->append_single_option_line(option);
+ def.set_default_value(new ConfigOptionBool{ app_config->has("single_instance") ? app_config->get("single_instance") == "1" : false });
+ option = Option(def, "single_instance");
+ m_optgroup_general->append_single_option_line(option);
def.label = L("Ask for unsaved changes when closing application");
def.type = coBool;
@@ -256,6 +285,11 @@ void PreferencesDialog::build()
m_optgroup_general->append_single_option_line(option);
#endif
+ if (is_editor) {
+ activate_options_tab(m_optgroup_general, 3);
+ m_optgroup_general = create_general_options_group(_L("Splash screen"), tabs);
+ }
+
// Show/Hide splash screen
def.label = L("Show splash screen");
def.type = coBool;
@@ -274,7 +308,7 @@ void PreferencesDialog::build()
// splashscreen image
{
ConfigOptionDef def_combobox;
- def_combobox.label = L("Splashscreen image");
+ def_combobox.label = L("Splash screen image");
def_combobox.type = coStrings;
def_combobox.tooltip = L("Choose the image to use as splashscreen");
def_combobox.gui_type = "f_enum_open";
@@ -294,6 +328,10 @@ void PreferencesDialog::build()
#if ENABLE_CTRL_M_ON_WINDOWS
#if defined(_WIN32) || defined(__APPLE__)
+ if (is_editor) {
+ activate_options_tab(m_optgroup_general, 3);
+ m_optgroup_general = create_general_options_group(_L("Others"), tabs);
+ }
def.label = L("Enable support for legacy 3DConnexion devices");
def.type = coBool;
def.tooltip = L("If enabled, the legacy 3DConnexion devices settings dialog is available by pressing CTRL+M");
@@ -303,7 +341,7 @@ void PreferencesDialog::build()
#endif // _WIN32 || __APPLE__
#endif // ENABLE_CTRL_M_ON_WINDOWS
- activate_options_tab(m_optgroup_general);
+ activate_options_tab(m_optgroup_general, m_optgroup_general->parent()->GetSizer()->GetItemCount() > 1 ? 3 : 20);
// Add "Paths" tab
diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp
index 1fc0961e1..16beaec4e 100644
--- a/src/slic3r/GUI/Preferences.hpp
+++ b/src/slic3r/GUI/Preferences.hpp
@@ -47,6 +47,7 @@ protected:
void layout();
void create_icon_size_slider();
void create_settings_mode_widget();
+ std::shared_ptr<ConfigOptionsGroup> create_general_options_group(const wxString& title, wxNotebook* tabs);
};
} // GUI
diff --git a/src/slic3r/GUI/PresetHints.cpp b/src/slic3r/GUI/PresetHints.cpp
index 459df570a..0955bbcd9 100644
--- a/src/slic3r/GUI/PresetHints.cpp
+++ b/src/slic3r/GUI/PresetHints.cpp
@@ -22,6 +22,7 @@ std::string PresetHints::cooling_description(const Preset &preset)
int max_fan_speed = preset.config.opt_int("max_fan_speed", 0);
int top_fan_speed = preset.config.opt_int("top_fan_speed", 0);
int bridge_fan_speed = preset.config.opt_int("bridge_fan_speed", 0);
+ int bridge_internal_fan_speed = preset.config.opt_int("bridge_internal_fan_speed", 0);
int ext_peri_fan_speed = preset.config.opt_int("external_perimeter_fan_speed", 0);
int disable_fan_first_layers = preset.config.opt_int("disable_fan_first_layers", 0);
int slowdown_below_layer_time = preset.config.opt_int("slowdown_below_layer_time", 0);
@@ -32,9 +33,11 @@ std::string PresetHints::cooling_description(const Preset &preset)
//for the time being, -1 shoudl eb for disabel, but it's 0 from legacy.
if (top_fan_speed == 0) top_fan_speed = -1;
if (bridge_fan_speed == 0) bridge_fan_speed = -1;
+ if (bridge_internal_fan_speed == 0) bridge_internal_fan_speed = -1;
if (ext_peri_fan_speed == 0) ext_peri_fan_speed = -1;
if (top_fan_speed == 1) top_fan_speed = 0;
if (bridge_fan_speed == 1) bridge_fan_speed = 0;
+ if (bridge_internal_fan_speed == 1) bridge_internal_fan_speed = 0;
if (ext_peri_fan_speed == 1) ext_peri_fan_speed = 0;
//if (preset.config.opt_bool("cooling", 0)) {
@@ -52,6 +55,9 @@ std::string PresetHints::cooling_description(const Preset &preset)
if (bridge_fan_speed >= 0 && bridge_fan_speed > min_fan_speed) {
out += ", " + (boost::format(_utf8(L("at %1%%% over bridges"))) % bridge_fan_speed).str();
}
+ if (bridge_internal_fan_speed >= 0 && bridge_internal_fan_speed > min_fan_speed) {
+ out += ", " + (boost::format(_utf8(L("at %1%%% over infill bridges"))) % bridge_internal_fan_speed).str();
+ }
if (disable_fan_first_layers > 1)
out += ", " + (boost::format(_utf8(L("except for the first %1% layers where the fan is disabled"))) % disable_fan_first_layers).str();
else if (disable_fan_first_layers == 1)
@@ -79,9 +85,14 @@ std::string PresetHints::cooling_description(const Preset &preset)
}
if (bridge_fan_speed > max_fan_speed) {
out += ", " + (boost::format(_utf8(L("at %1%%% over bridges"))) % bridge_fan_speed).str();
- }else if (bridge_fan_speed > min_fan_speed) {
+ } else if (bridge_fan_speed > min_fan_speed) {
out += ", " + (boost::format(_utf8(L("at %1%%% over bridges"))) % bridge_fan_speed).str() + " " + L("if it's above the current computed fan speed value");
}
+ if (bridge_internal_fan_speed > max_fan_speed) {
+ out += ", " + (boost::format(_utf8(L("at %1%%% over infill bridges"))) % bridge_internal_fan_speed).str();
+ } else if (bridge_internal_fan_speed > min_fan_speed) {
+ out += ", " + (boost::format(_utf8(L("at %1%%% over infill bridges"))) % bridge_internal_fan_speed).str() + " " + L("if it's above the current computed fan speed value");
+ }
if (disable_fan_first_layers > 1)
out += " ; " + ((boost::format(_utf8(L("except for the first %1% layers where the fan is disabled"))) % disable_fan_first_layers).str());
else if (disable_fan_first_layers == 1)
@@ -118,6 +129,7 @@ std::string PresetHints::cooling_description(const Preset &preset)
//tooltip for Depractaed values
bridge_fan_speed = preset.config.opt_int("bridge_fan_speed", 0);
+ bridge_internal_fan_speed = preset.config.opt_int("bridge_internal_fan_speed", 0);
ext_peri_fan_speed = preset.config.opt_int("external_perimeter_fan_speed", 0);
top_fan_speed = preset.config.opt_int("top_fan_speed", 0);
if (top_fan_speed == 0)
@@ -126,6 +138,8 @@ std::string PresetHints::cooling_description(const Preset &preset)
out += "\n\n!!! 0 for the External perimeters fan speed is Deprecated, please set it to -1 to disable it !!!";
if (bridge_fan_speed == 0)
out += "\n\n!!! 0 for the Bridge fan speed is Deprecated, please set it to -1 to disable it !!!";
+ if (bridge_internal_fan_speed == 0)
+ out += "\n\n!!! 0 for the Infill bridge fan speed is Deprecated, please set it to -1 to disable it !!!";
return out;
}
@@ -183,7 +197,8 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
const auto &support_material_extrusion_width = *print_config.option<ConfigOptionFloatOrPercent>("support_material_extrusion_width");
const auto &top_infill_extrusion_width = *print_config.option<ConfigOptionFloatOrPercent>("top_infill_extrusion_width");
const auto &first_layer_speed = *print_config.option<ConfigOptionFloatOrPercent>("first_layer_speed");
- const auto &first_layer_infill_speed = *print_config.option<ConfigOptionFloatOrPercent>("first_layer_infill_speed");
+ const auto& first_layer_infill_speed = *print_config.option<ConfigOptionFloatOrPercent>("first_layer_infill_speed");
+ const auto& first_layer_min_speed = *print_config.option<ConfigOptionFloatOrPercent>("first_layer_infill_speed");
// Index of an extruder assigned to a feature. If set to 0, an active extruder will be used for a multi-material print.
// If different from idx_extruder, it will not be taken into account for this hint.
@@ -214,16 +229,24 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
const float bfr = bridging ? bridge_flow_ratio : 0.f;
double max_flow = 0.;
std::string max_flow_extrusion_type;
- auto limit_by_first_layer_speed = [&first_layer_speed, first_layer](double speed_normal, double speed_max) {
- if (first_layer && first_layer_speed.value > 0)
+ auto limit_by_first_layer_speed = [&first_layer_min_speed , &first_layer_speed, first_layer](double speed_normal, double speed_max) {
+ if (first_layer) {
+ const double base_speed = speed_normal;
// Apply the first layer limit.
- speed_normal = first_layer_speed.get_abs_value(speed_normal);
+ if (first_layer_speed.value > 0)
+ speed_normal = std::min(first_layer_speed.get_abs_value(base_speed), speed_normal);
+ speed_normal = std::max(first_layer_min_speed.get_abs_value(base_speed), speed_normal);
+ }
return (speed_normal > 0.) ? speed_normal : speed_max;
};
- auto limit_infill_by_first_layer_speed = [&first_layer_infill_speed, first_layer](double speed_normal, double speed_max) {
- if (first_layer && first_layer_infill_speed.value > 0)
+ auto limit_infill_by_first_layer_speed = [&first_layer_min_speed, &first_layer_infill_speed, first_layer](double speed_normal, double speed_max) {
+ if (first_layer) {
+ const double base_speed = speed_normal;
// Apply the first layer limit.
- speed_normal = first_layer_infill_speed.get_abs_value(speed_normal);
+ if(first_layer_infill_speed.value > 0)
+ speed_normal = std::min(first_layer_infill_speed.get_abs_value(base_speed), speed_normal);
+ speed_normal = std::max(first_layer_min_speed.get_abs_value(base_speed), speed_normal);
+ }
return (speed_normal > 0.) ? speed_normal : speed_max;
};
if (perimeter_extruder_active) {
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index a20d10839..5ea82a7dd 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -2263,6 +2263,7 @@ void TabFilament::add_filament_overrides_page()
"filament_retract_before_travel",
"filament_retract_layer_change",
"filament_wipe",
+ "filament_wipe_speed",
"filament_wipe_extra_perimeter",
"filament_retract_before_wipe"
})
@@ -2290,6 +2291,7 @@ void TabFilament::update_filament_overrides_page()
"filament_retract_before_travel",
"filament_retract_layer_change",
"filament_wipe",
+ "filament_wipe_speed",
"filament_wipe_extra_perimeter",
"filament_retract_before_wipe"
};
@@ -2912,17 +2914,20 @@ void TabPrinter::toggle_options()
// some options only apply when not using firmware retraction
vec.resize(0);
- vec = { "retract_speed", "deretract_speed", "retract_before_wipe", "retract_restart_extra", "wipe" };
+ vec = { "retract_speed", "deretract_speed", "retract_before_wipe", "retract_restart_extra", "wipe", "wipe_speed" };
for (auto el : vec) {
field = get_field(el, i);
if (field)
field->toggle(retraction && !use_firmware_retraction);
}
- bool wipe = m_config->opt_bool("wipe", i);
- field = get_field("retract_before_wipe", i);
- if (field)
- field->toggle(wipe);
+ bool wipe = m_config->opt_bool("wipe", i) && have_retract_length;
+ vec = { "retract_before_wipe", "wipe_speed" };
+ for (auto el : vec) {
+ field = get_field(el, i);
+ if (field)
+ field->toggle(wipe);
+ }
if (use_firmware_retraction && wipe) {
wxMessageDialog dialog(parent(),