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>2020-05-29 22:01:30 +0300
committersupermerill <merill@free.fr>2020-05-29 22:01:30 +0300
commit9b60be0c1aeda35d81cb30fbef05e11c7e7351e3 (patch)
tree837dcfa6cc9b408a47b422c1a99589584cef2c73 /src/libslic3r
parentd0a8bdebe8deec7144d9d6d7519d0be861157397 (diff)
Initial working prototype for the milling post-process
Diffstat (limited to 'src/libslic3r')
-rw-r--r--src/libslic3r/CMakeLists.txt2
-rw-r--r--src/libslic3r/Config.hpp13
-rw-r--r--src/libslic3r/CustomGCode.cpp6
-rw-r--r--src/libslic3r/CustomGCode.hpp2
-rw-r--r--src/libslic3r/Extruder.cpp93
-rw-r--r--src/libslic3r/Extruder.hpp102
-rw-r--r--src/libslic3r/ExtrusionEntity.cpp1
-rw-r--r--src/libslic3r/ExtrusionEntity.hpp5
-rw-r--r--src/libslic3r/GCode.cpp274
-rw-r--r--src/libslic3r/GCode.hpp2
-rw-r--r--src/libslic3r/GCode/CoolingBuffer.cpp10
-rw-r--r--src/libslic3r/GCode/PreviewData.cpp1
-rw-r--r--src/libslic3r/GCode/ToolOrdering.cpp62
-rw-r--r--src/libslic3r/GCode/ToolOrdering.hpp40
-rw-r--r--src/libslic3r/GCode/WipeTower.cpp6
-rw-r--r--src/libslic3r/GCode/WipeTower.hpp14
-rw-r--r--src/libslic3r/GCodeWriter.cpp107
-rw-r--r--src/libslic3r/GCodeWriter.hpp57
-rw-r--r--src/libslic3r/Layer.cpp66
-rw-r--r--src/libslic3r/Layer.hpp7
-rw-r--r--src/libslic3r/LayerRegion.cpp15
-rw-r--r--src/libslic3r/Milling/MillingPostProcess.cpp169
-rw-r--r--src/libslic3r/Milling/MillingPostProcess.hpp49
-rw-r--r--src/libslic3r/PerimeterGenerator.cpp67
-rw-r--r--src/libslic3r/PerimeterGenerator.hpp11
-rw-r--r--src/libslic3r/Print.cpp39
-rw-r--r--src/libslic3r/Print.hpp16
-rw-r--r--src/libslic3r/PrintConfig.cpp147
-rw-r--r--src/libslic3r/PrintConfig.hpp19
-rw-r--r--src/libslic3r/PrintObject.cpp29
-rw-r--r--src/libslic3r/PrintRegion.cpp6
-rw-r--r--src/libslic3r/Slicing.cpp2
-rw-r--r--src/libslic3r/Slicing.hpp2
33 files changed, 1106 insertions, 335 deletions
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index 67e6d5f67..b3039f710 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -121,6 +121,8 @@ add_library(libslic3r STATIC
Line.hpp
MedialAxis.cpp
MedialAxis.hpp
+ Milling/MillingPostProcess.cpp
+ Milling/MillingPostProcess.hpp
Model.cpp
Model.hpp
CustomGCode.cpp
diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp
index 16dcc9fac..488c07326 100644
--- a/src/libslic3r/Config.hpp
+++ b/src/libslic3r/Config.hpp
@@ -66,6 +66,9 @@ enum OptionCategory : int
wipe,
hollowing,
+
+ milling_extruders,
+ milling,
};
std::string toString(OptionCategory opt);
@@ -157,6 +160,10 @@ enum PrinterTechnology : uint8_t
ptSLA = 1 << 1,
// Selective Laser-Sintering
ptSLS = 1 << 2,
+ // CNC
+ ptMill = 1 << 3,
+ // Laser engraving
+ ptLaser = 1 << 4,
// Any technology, useful for parameters compatible with both ptFFF and ptSLA
ptAny = 1+2+4,
// Unknown, useful for command line processing
@@ -774,7 +781,8 @@ class ConfigOptionStrings : public ConfigOptionVector<std::string>
{
public:
ConfigOptionStrings() : ConfigOptionVector<std::string>() {}
- explicit ConfigOptionStrings(size_t n, const std::string &value) : ConfigOptionVector<std::string>(n, value) {}
+ explicit ConfigOptionStrings(const std::string& value) : ConfigOptionVector<std::string>(value) {}
+ explicit ConfigOptionStrings(size_t n, const std::string& value) : ConfigOptionVector<std::string>(n, value) {}
explicit ConfigOptionStrings(const std::vector<std::string> &values) : ConfigOptionVector<std::string>(values) {}
explicit ConfigOptionStrings(std::vector<std::string> &&values) : ConfigOptionVector<std::string>(std::move(values)) {}
explicit ConfigOptionStrings(std::initializer_list<std::string> il) : ConfigOptionVector<std::string>(std::move(il)) {}
@@ -990,7 +998,8 @@ class ConfigOptionPoints : public ConfigOptionVector<Vec2d>
{
public:
ConfigOptionPoints() : ConfigOptionVector<Vec2d>() {}
- explicit ConfigOptionPoints(size_t n, const Vec2d &value) : ConfigOptionVector<Vec2d>(n, value) {}
+ explicit ConfigOptionPoints(const Vec2d& value) : ConfigOptionVector<Vec2d>(value) {}
+ explicit ConfigOptionPoints(size_t n, const Vec2d& value) : ConfigOptionVector<Vec2d>(n, value) {}
explicit ConfigOptionPoints(std::initializer_list<Vec2d> il) : ConfigOptionVector<Vec2d>(std::move(il)) {}
explicit ConfigOptionPoints(const std::vector<Vec2d> &values) : ConfigOptionVector<Vec2d>(values) {}
diff --git a/src/libslic3r/CustomGCode.cpp b/src/libslic3r/CustomGCode.cpp
index 7c505c978..edd921fb8 100644
--- a/src/libslic3r/CustomGCode.cpp
+++ b/src/libslic3r/CustomGCode.cpp
@@ -56,13 +56,13 @@ extern void check_mode_for_custom_gcode_per_print_z(Info& info)
// Return pairs of <print_z, 1-based extruder ID> sorted by increasing print_z from custom_gcode_per_print_z.
// print_z corresponds to the first layer printed with the new extruder.
-std::vector<std::pair<double, unsigned int>> custom_tool_changes(const Info& custom_gcode_per_print_z, size_t num_extruders)
+std::vector<std::pair<double, uint16_t>> custom_tool_changes(const Info& custom_gcode_per_print_z, size_t num_extruders)
{
- std::vector<std::pair<double, unsigned int>> custom_tool_changes;
+ std::vector<std::pair<double, uint16_t>> custom_tool_changes;
for (const Item& custom_gcode : custom_gcode_per_print_z.gcodes)
if (custom_gcode.gcode == ToolChangeCode) {
// If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
- custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast<unsigned int>(custom_gcode.extruder > num_extruders ? 1 : custom_gcode.extruder));
+ custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast<uint16_t>(custom_gcode.extruder > num_extruders ? 1 : custom_gcode.extruder));
}
return custom_tool_changes;
}
diff --git a/src/libslic3r/CustomGCode.hpp b/src/libslic3r/CustomGCode.hpp
index a5ef1cc2e..97d874ecb 100644
--- a/src/libslic3r/CustomGCode.hpp
+++ b/src/libslic3r/CustomGCode.hpp
@@ -81,7 +81,7 @@ extern void check_mode_for_custom_gcode_per_print_z(Info& info);
// Return pairs of <print_z, 1-based extruder ID> sorted by increasing print_z from custom_gcode_per_print_z.
// print_z corresponds to the first layer printed with the new extruder.
-std::vector<std::pair<double, unsigned int>> custom_tool_changes(const Info& custom_gcode_per_print_z, size_t num_extruders);
+std::vector<std::pair<double, uint16_t>> custom_tool_changes(const Info& custom_gcode_per_print_z, size_t num_extruders);
} // namespace CustomGCode
diff --git a/src/libslic3r/Extruder.cpp b/src/libslic3r/Extruder.cpp
index f7a5c5007..20ce3f3dd 100644
--- a/src/libslic3r/Extruder.cpp
+++ b/src/libslic3r/Extruder.cpp
@@ -3,19 +3,31 @@
namespace Slic3r {
-Extruder::Extruder(unsigned int id, GCodeConfig *config) :
+Tool::Tool(uint16_t id, GCodeConfig* config) :
m_id(id),
m_config(config)
{
reset();
-
+}
+
+Extruder::Extruder(uint16_t id, GCodeConfig* config) :
+ Tool(id, config)
+{
+
// cache values that are going to be called often
m_e_per_mm3 = this->extrusion_multiplier();
- if (! m_config->use_volumetric_e)
+ if (!m_config->use_volumetric_e)
m_e_per_mm3 /= this->filament_crossection();
}
-double Extruder::extrude(double dE)
+Mill::Mill(uint16_t mill_id, GCodeConfig* config) :
+ Tool(mill_id, config)
+{
+ m_mill_id = mill_id;
+ m_id = mill_id + (uint16_t)config->retract_length.values.size();
+}
+
+double Tool::extrude(double dE)
{
// in case of relative E distances we always reset to 0 before any output
if (m_config->use_relative_e_distances)
@@ -34,7 +46,7 @@ double Extruder::extrude(double dE)
The restart_extra argument sets the extra length to be used for
unretraction. If we're actually performing a retraction, any restart_extra
value supplied will overwrite the previous one if any. */
-double Extruder::retract(double length, double restart_extra)
+double Tool::retract(double length, double restart_extra)
{
// in case of relative E distances we always reset to 0 before any output
if (m_config->use_relative_e_distances)
@@ -49,7 +61,7 @@ double Extruder::retract(double length, double restart_extra)
return to_retract;
}
-double Extruder::unretract()
+double Tool::unretract()
{
double dE = m_retracted + m_restart_extra;
this->extrude(dE);
@@ -59,7 +71,7 @@ double Extruder::unretract()
}
// Used filament volume in mm^3.
-double Extruder::extruded_volume() const
+double Tool::extruded_volume() const
{
return m_config->use_volumetric_e ?
m_absolute_E + m_retracted :
@@ -67,13 +79,74 @@ double Extruder::extruded_volume() const
}
// Used filament length in mm.
-double Extruder::used_filament() const
+double Tool::used_filament() const
{
return m_config->use_volumetric_e ?
this->extruded_volume() / this->filament_crossection() :
m_absolute_E + m_retracted;
}
+double Tool::filament_diameter() const
+{
+ return 0;
+}
+
+double Tool::filament_density() const
+{
+ return 0;
+}
+
+double Tool::filament_cost() const
+{
+ return 0;
+}
+
+double Tool::extrusion_multiplier() const
+{
+ return 0;
+}
+
+// Return a "retract_before_wipe" percentage as a factor clamped to <0, 1>
+double Tool::retract_before_wipe() const
+{
+ return 0;
+}
+
+double Tool::retract_length() const
+{
+ return 0;
+}
+
+double Tool::retract_lift() const
+{
+ return 0;
+}
+
+int Tool::retract_speed() const
+{
+ return 0;
+}
+
+int Tool::deretract_speed() const
+{
+ return 0;
+}
+
+double Tool::retract_restart_extra() const
+{
+ return 0;
+}
+
+double Tool::retract_length_toolchange() const
+{
+ return 0;
+}
+
+double Tool::retract_restart_extra_toolchange() const
+{
+ return 0;
+}
+
double Extruder::filament_diameter() const
{
return m_config->filament_diameter.get_at(m_id);
@@ -136,4 +209,8 @@ double Extruder::retract_restart_extra_toolchange() const
return m_config->retract_restart_extra_toolchange.get_at(m_id);
}
+double Mill::retract_lift() const {
+ return m_config->milling_z_lift.get_at(m_mill_id);
+}
+
}
diff --git a/src/libslic3r/Extruder.hpp b/src/libslic3r/Extruder.hpp
index e9c6927f8..d57acc7cd 100644
--- a/src/libslic3r/Extruder.hpp
+++ b/src/libslic3r/Extruder.hpp
@@ -8,11 +8,11 @@ namespace Slic3r {
class GCodeConfig;
-class Extruder
+class Tool
{
public:
- Extruder(unsigned int id, GCodeConfig *config);
- virtual ~Extruder() {}
+ Tool(uint16_t id, GCodeConfig *config);
+ virtual ~Tool() {}
void reset() {
m_E = 0;
@@ -21,42 +21,42 @@ public:
m_restart_extra = 0;
}
- unsigned int id() const { return m_id; }
+ uint16_t id() const { return m_id; }
- double extrude(double dE);
- double retract(double length, double restart_extra);
- double unretract();
+ virtual double extrude(double dE);
+ virtual double retract(double length, double restart_extra);
+ virtual double unretract();
double E() const { return m_E; }
void reset_E() { m_E = 0.; }
double e_per_mm(double mm3_per_mm) const { return mm3_per_mm * m_e_per_mm3; }
double e_per_mm3() const { return m_e_per_mm3; }
// Used filament volume in mm^3.
- double extruded_volume() const;
+ virtual double extruded_volume() const;
// Used filament length in mm.
- double used_filament() const;
+ virtual double used_filament() const;
- double filament_diameter() const;
+ virtual double filament_diameter() const;
double filament_crossection() const { return this->filament_diameter() * this->filament_diameter() * 0.25 * PI; }
- double filament_density() const;
- double filament_cost() const;
- double extrusion_multiplier() const;
- double retract_before_wipe() const;
- double retract_length() const;
- double retract_lift() const;
- int retract_speed() const;
- int deretract_speed() const;
- double retract_restart_extra() const;
- double retract_length_toolchange() const;
- double retract_restart_extra_toolchange() const;
-
-private:
+ virtual double filament_density() const;
+ virtual double filament_cost() const;
+ virtual double extrusion_multiplier() const;
+ virtual double retract_before_wipe() const;
+ virtual double retract_length() const;
+ virtual double retract_lift() const;
+ virtual int retract_speed() const;
+ virtual int deretract_speed() const;
+ virtual double retract_restart_extra() const;
+ virtual double retract_length_toolchange() const;
+ virtual double retract_restart_extra_toolchange() const;
+
+protected:
// Private constructor to create a key for a search in std::set.
- Extruder(unsigned int id) : m_id(id) {}
+ Tool(uint16_t id) : m_id(id) {}
// Reference to GCodeWriter instance owned by GCodeWriter.
GCodeConfig *m_config;
// Print-wide global ID of this extruder.
- unsigned int m_id;
+ uint16_t m_id;
// Current state of the extruder axis, may be resetted if use_relative_e_distances.
double m_E;
// Current state of the extruder tachometer, used to output the extruded_volume() and used_filament() statistics.
@@ -68,11 +68,55 @@ private:
double m_e_per_mm3;
};
+
+class Mill : public Tool
+{
+public:
+ Mill(uint16_t mill_id, GCodeConfig* config);
+ virtual ~Mill() {}
+ double retract_lift() const override;
+
+ uint16_t mill_id() const { return m_mill_id; }
+
+protected:
+ // Private constructor to create a key for a search in std::set.
+ Mill(uint16_t tool_id) : Tool(tool_id) {}
+ uint16_t m_mill_id;
+};
+
+class Extruder : public Tool
+{
+public:
+ Extruder(uint16_t id, GCodeConfig* config);
+ virtual ~Extruder() {}
+
+ double filament_diameter() const override;
+ double filament_density() const override;
+ double filament_cost() const override;
+ double extrusion_multiplier() const override;
+ double retract_before_wipe() const override;
+ double retract_length() const override;
+ double retract_lift() const override;
+ int retract_speed() const override;
+ int deretract_speed() const override;
+ double retract_restart_extra() const override;
+ double retract_length_toolchange() const override;
+ double retract_restart_extra_toolchange() const override;
+
+protected:
+ // Private constructor to create a key for a search in std::set.
+ Extruder(uint16_t id) : Tool(id) {}
+};
+
// Sort Extruder objects by the extruder id by default.
-inline bool operator==(const Extruder &e1, const Extruder &e2) { return e1.id() == e2.id(); }
-inline bool operator!=(const Extruder &e1, const Extruder &e2) { return e1.id() != e2.id(); }
-inline bool operator< (const Extruder &e1, const Extruder &e2) { return e1.id() < e2.id(); }
-inline bool operator> (const Extruder &e1, const Extruder &e2) { return e1.id() > e2.id(); }
+inline bool operator==(const Tool& e1, const Tool& e2) { return e1.id() == e2.id(); }
+inline bool operator!=(const Tool& e1, const Tool& e2) { return e1.id() != e2.id(); }
+inline bool operator< (const Tool& e1, const Tool& e2) { return e1.id() < e2.id(); }
+inline bool operator> (const Tool& e1, const Tool& e2) { return e1.id() > e2.id(); }
+inline bool operator==(const Extruder& e1, const Extruder& e2) { return e1.id() == e2.id(); }
+inline bool operator!=(const Extruder& e1, const Extruder& e2) { return e1.id() != e2.id(); }
+inline bool operator< (const Extruder& e1, const Extruder& e2) { return e1.id() < e2.id(); }
+inline bool operator> (const Extruder& e1, const Extruder& e2) { return e1.id() > e2.id(); }
}
diff --git a/src/libslic3r/ExtrusionEntity.cpp b/src/libslic3r/ExtrusionEntity.cpp
index 703ca1f5d..d93620e05 100644
--- a/src/libslic3r/ExtrusionEntity.cpp
+++ b/src/libslic3r/ExtrusionEntity.cpp
@@ -280,6 +280,7 @@ std::string ExtrusionEntity::role_to_string(ExtrusionRole role)
case erSupportMaterial : return L("Support material");
case erSupportMaterialInterface : return L("Support material interface");
case erWipeTower : return L("Wipe tower");
+ case erMilling : return L("Mill");
case erCustom : return L("Custom");
case erMixed : return L("Mixed");
default : assert(false);
diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp
index a6441ccd1..3ef577a9a 100644
--- a/src/libslic3r/ExtrusionEntity.hpp
+++ b/src/libslic3r/ExtrusionEntity.hpp
@@ -29,6 +29,7 @@ enum ExtrusionRole : uint8_t {
erSupportMaterial,
erSupportMaterialInterface,
erWipeTower,
+ erMilling,
erCustom,
// Extrusion role for a collection with multiple extrusion roles.
erMixed,
@@ -175,9 +176,9 @@ public:
Polyline polyline;
// Volumetric velocity. mm^3 of plastic per mm of linear head motion. Used by the G-code generator.
double mm3_per_mm;
- // Width of the extrusion, used for visualization purposes.
+ // Width of the extrusion, used for visualization purposes. Unscaled
float width;
- // Height of the extrusion, used for visualization purposes.
+ // Height of the extrusion, used for visualization purposes. Unscaled
float height;
ExtrusionPath(ExtrusionRole role) : mm3_per_mm(-1), width(-1), height(-1), m_role(role) {};
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index c93303257..495c32bfd 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -91,7 +91,7 @@ NEXT: ;
}
void AvoidCrossingPerimeters::init_external_mp(const Print &print)
-{
+{
m_external_mp = Slic3r::make_unique<MotionPlanner>(union_ex(this->collect_contours_all_layers(print.objects())));
}
@@ -198,10 +198,10 @@ std::string OozePrevention::pre_toolchange(GCode &gcodegen)
"move to standby position");
}
- if (gcodegen.config().standby_temperature_delta.value != 0) {
+ if (gcodegen.config().standby_temperature_delta.value != 0 && gcodegen.writer().tool_is_extruder()) {
// we assume that heating is always slower than cooling, so no need to block
gcode += gcodegen.writer().set_temperature
- (this->_get_temp(gcodegen) + gcodegen.config().standby_temperature_delta.value, false, gcodegen.writer().extruder()->id());
+ (this->_get_temp(gcodegen) + gcodegen.config().standby_temperature_delta.value, false, gcodegen.writer().tool()->id());
}
return gcode;
@@ -209,17 +209,20 @@ std::string OozePrevention::pre_toolchange(GCode &gcodegen)
std::string OozePrevention::post_toolchange(GCode &gcodegen)
{
- return (gcodegen.config().standby_temperature_delta.value != 0) ?
- gcodegen.writer().set_temperature(this->_get_temp(gcodegen), true, gcodegen.writer().extruder()->id()) :
+ return (gcodegen.config().standby_temperature_delta.value != 0 && gcodegen.writer().tool_is_extruder()) ?
+ gcodegen.writer().set_temperature(this->_get_temp(gcodegen), true, gcodegen.writer().tool()->id()) :
std::string();
}
int
OozePrevention::_get_temp(GCode &gcodegen)
{
- return (gcodegen.layer() != NULL && gcodegen.layer()->id() == 0)
- ? gcodegen.config().first_layer_temperature.get_at(gcodegen.writer().extruder()->id())
- : gcodegen.config().temperature.get_at(gcodegen.writer().extruder()->id());
+ if (gcodegen.writer().tool_is_extruder())
+ return (gcodegen.layer() != NULL && gcodegen.layer()->id() == 0)
+ ? gcodegen.config().first_layer_temperature.get_at(gcodegen.writer().tool()->id())
+ : gcodegen.config().temperature.get_at(gcodegen.writer().tool()->id());
+ else
+ return 0;
}
std::string Wipe::wipe(GCode &gcodegen, bool toolchange)
@@ -232,16 +235,16 @@ std::string Wipe::wipe(GCode &gcodegen, bool toolchange)
// get the retraction length
double length = toolchange
- ? gcodegen.writer().extruder()->retract_length_toolchange()
- : gcodegen.writer().extruder()->retract_length();
+ ? gcodegen.writer().tool()->retract_length_toolchange()
+ : gcodegen.writer().tool()->retract_length();
// Shorten the retraction length by the amount already retracted before wipe.
- length *= (1. - gcodegen.writer().extruder()->retract_before_wipe());
+ length *= (1. - gcodegen.writer().tool()->retract_before_wipe());
- if (length > 0) {
+ if (length > 0 && gcodegen.writer().tool()->retract_speed() > 0) {
/* 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().extruder()->retract_speed() * wipe_speed);
+ double wipe_dist = scale_(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). */
@@ -345,13 +348,13 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
// Process the end filament gcode.
std::string end_filament_gcode_str;
- if (gcodegen.writer().extruder() != nullptr) {
+ if (gcodegen.writer().tool() != nullptr && gcodegen.writer().tool_is_extruder()) {
// Process the custom end_filament_gcode in case of single_extruder_multi_material.
- unsigned int old_extruder_id = gcodegen.writer().extruder()->id();
+ unsigned int 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().extruder() != nullptr && ! end_filament_gcode.empty()) {
+ if (gcodegen.writer().tool() != nullptr && ! end_filament_gcode.empty()) {
DynamicConfig config;
- int previous_extruder_id = gcodegen.writer().extruder() ? (int)gcodegen.writer().extruder()->id() : -1;
+ 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));
@@ -368,7 +371,7 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
const std::string& toolchange_gcode = gcodegen.config().toolchange_gcode.value;
if (!toolchange_gcode.empty()) {
DynamicConfig config;
- int previous_extruder_id = gcodegen.writer().extruder() ? (int)gcodegen.writer().extruder()->id() : -1;
+ 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));
@@ -396,7 +399,7 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
// 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().extruder() ? (int)gcodegen.writer().extruder()->id() : -1));
+ 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));
@@ -598,6 +601,8 @@ std::string WipeTowerIntegration::finalize(GCode &gcodegen)
}
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id())
+#define EXTRUDER_CONFIG_WITH_DEFAULT(OPT,DEF) (m_writer.tool_is_extruder()?m_config.OPT.get_at(m_writer.tool()->id()):DEF)
+#define BOOL_EXTRUDER_CONFIG(OPT) m_writer.tool_is_extruder() && m_config.OPT.get_at(m_writer.tool()->id())
// Collect pairs of object_layer + support_layer sorted by print_z.
// object_layer & support_layer are considered to be on the same print_z, if they are not further than EPSILON.
@@ -905,12 +910,12 @@ namespace DoExport {
// send extruder offset data to analyzer
GCodeAnalyzer::ExtruderOffsetsMap extruder_offsets;
unsigned int num_extruders = static_cast<unsigned int>(config.nozzle_diameter.values.size());
- for (unsigned int extruder_id = 0; extruder_id < num_extruders; ++ extruder_id)
- {
- Vec2d offset = config.extruder_offset.get_at(extruder_id);
- if (!offset.isApprox(Vec2d::Zero()))
- extruder_offsets[extruder_id] = offset;
- }
+ for (unsigned int extruder_id = 0; extruder_id < num_extruders; ++extruder_id)
+ {
+ Vec2d offset = config.extruder_offset.get_at(extruder_id);
+ if (!offset.isApprox(Vec2d::Zero()))
+ extruder_offsets[extruder_id] = offset;
+ }
analyzer.set_extruder_offsets(extruder_offsets);
// tell analyzer about the extrusion axis
@@ -1330,6 +1335,19 @@ void GCode::_do_export(Print &print, FILE *file)
bool has_wipe_tower = false;
std::vector<const PrintInstance*> print_object_instances_ordering;
std::vector<const PrintInstance*>::const_iterator print_object_instance_sequential_active;
+ bool has_milling = false;
+ if (!config().milling_diameter.values.empty()) {
+ for (const PrintObject* obj : print.objects()) {
+ for (const Layer *layer : obj->layers()) {
+ for (const LayerRegion *lr : layer->regions()) {
+ if (!lr->milling.empty()) {
+ has_milling = true;
+ break;
+ }
+ }
+ }
+ }
+ }
if (print.config().complete_objects.value) {
// Order object instances for sequential print.
if(print.config().complete_objects_sort.value == cosObject)
@@ -1348,6 +1366,8 @@ void GCode::_do_export(Print &print, FILE *file)
// 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());
+ if(has_milling)
+ m_writer.set_mills(std::vector<uint16_t>() = { 0 });
} else {
// Find tool ordering for all the objects at once, and the initial extruder ID.
// If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it.
@@ -1362,6 +1382,8 @@ void GCode::_do_export(Print &print, FILE *file)
// In non-sequential print, the printing extruders may have been modified by the extruder switches stored in Model::custom_gcode_per_print_z.
// Therefore initialize the printing extruders from there.
this->set_extruders(tool_ordering.all_extruders());
+ if (has_milling)
+ m_writer.set_mills(std::vector<uint16_t>() = { 0 });
// Order object instances using a nearest neighbor search.
print_object_instances_ordering = chain_print_object_instances(print);
}
@@ -1566,22 +1588,25 @@ void GCode::_do_export(Print &print, FILE *file)
{
DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
- config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position()(2) - m_config.z_offset.value));
- if (print.config().single_extruder_multi_material) {
- // Process the end_filament_gcode for the active filament only.
- int extruder_id = m_writer.extruder()->id();
- config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
- _writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(extruder_id), extruder_id, &config));
- } else {
- for (const std::string &end_gcode : print.config().end_filament_gcode.values) {
- int extruder_id = (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front());
+ config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position()(2) - m_config.z_offset.value));
+ config.set_key_value("current_extruder_id", new ConfigOptionInt((int)m_writer.tool()->id()));
+ if (m_writer.tool_is_extruder()) {
+ if (print.config().single_extruder_multi_material) {
+ // Process the end_filament_gcode for the active filament only.
+ int extruder_id = m_writer.tool()->id();
config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
- config.set_key_value("previous_extruder", new ConfigOptionInt(extruder_id));
- config.set_key_value("next_extruder", new ConfigOptionInt(0));
- _writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, extruder_id, &config));
+ _writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(extruder_id), extruder_id, &config));
+ } else {
+ for (const std::string& end_gcode : print.config().end_filament_gcode.values) {
+ int extruder_id = (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front());
+ config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
+ config.set_key_value("previous_extruder", new ConfigOptionInt(extruder_id));
+ config.set_key_value("next_extruder", new ConfigOptionInt(0));
+ _writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, extruder_id, &config));
+ }
}
}
- _writeln(file, this->placeholder_parser_process("end_gcode", print.config().end_gcode, m_writer.extruder()->id(), &config));
+ _writeln(file, this->placeholder_parser_process("end_gcode", print.config().end_gcode, m_writer.tool()->id(), &config));
}
_write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100%
_write(file, m_writer.postamble());
@@ -1889,17 +1914,17 @@ std::string GCode::emit_custom_gcode_per_print_z(
//update stats : weight
double previously_extruded = 0;
for (const auto& tuple : stats.color_extruderid_to_used_weight)
- if (tuple.first == this->m_writer.extruder()->id())
+ if (tuple.first == this->m_writer.tool()->id())
previously_extruded += tuple.second;
- double extruded = this->m_writer.extruder()->filament_density() * this->m_writer.extruder()->extruded_volume();
- stats.color_extruderid_to_used_weight.emplace_back(this->m_writer.extruder()->id(), extruded - previously_extruded);
+ double extruded = this->m_writer.tool()->filament_density() * this->m_writer.tool()->extruded_volume();
+ stats.color_extruderid_to_used_weight.emplace_back(this->m_writer.tool()->id(), extruded - previously_extruded);
//update stats : length
previously_extruded = 0;
for (const auto& tuple : stats.color_extruderid_to_used_filament)
- if (tuple.first == this->m_writer.extruder()->id())
+ if (tuple.first == this->m_writer.tool()->id())
previously_extruded += tuple.second;
- stats.color_extruderid_to_used_filament.emplace_back(this->m_writer.extruder()->id(), this->m_writer.extruder()->used_filament() - previously_extruded);
+ stats.color_extruderid_to_used_filament.emplace_back(this->m_writer.tool()->id(), this->m_writer.tool()->used_filament() - previously_extruded);
}
// we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count
@@ -2085,7 +2110,7 @@ void GCode::process_layer(
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1));
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
gcode += this->placeholder_parser_process("before_layer_gcode",
- print.config().before_layer_gcode.value, m_writer.extruder()->id(), &config)
+ print.config().before_layer_gcode.value, m_writer.tool()->id(), &config)
+ "\n";
}
gcode += this->change_layer(print_z); // this will increase m_layer_index
@@ -2095,7 +2120,7 @@ void GCode::process_layer(
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
gcode += this->placeholder_parser_process("layer_gcode",
- print.config().layer_gcode.value, m_writer.extruder()->id(), &config)
+ print.config().layer_gcode.value, m_writer.tool()->id(), &config)
+ "\n";
}
@@ -2103,7 +2128,7 @@ void GCode::process_layer(
// Transition from 1st to 2nd layer. Adjust nozzle temperatures as prescribed by the nozzle dependent
// first_layer_temperature vs. temperature settings.
for (const Extruder &extruder : m_writer.extruders()) {
- if (print.config().single_extruder_multi_material.value && extruder.id() != m_writer.extruder()->id())
+ if (print.config().single_extruder_multi_material.value && extruder.id() != m_writer.tool()->id())
// In single extruder multi material mode, set the temperature for the current extruder only.
continue;
int temperature = print.config().temperature.get_at(extruder.id());
@@ -2434,6 +2459,81 @@ void GCode::process_layer(
if (m_spiral_vase)
gcode = m_spiral_vase->process_layer(gcode);
+
+ //add milling post-process if enabled
+ if (!config().milling_diameter.values.empty()) {
+ bool milling_ok = false;
+ for (const LayerToPrint& ltp : layers) {
+ if (ltp.object_layer != nullptr) {
+ for (const LayerRegion* lr : ltp.object_layer->regions()) {
+ if (!lr->milling.empty()) {
+ milling_ok = true;
+ break;
+ }
+ }
+ }
+ }
+ if (milling_ok) {
+ //switch to mill
+ gcode += "; milling ok\n";
+ uint32_t current_extruder_filament = m_writer.tool()->id();
+ uint32_t milling_extruder_id = config().nozzle_diameter.values.size();
+ gcode += "; toolchange:\n";
+ gcode += m_writer.toolchange(milling_extruder_id);
+ gcode += "; toolchange done\n";
+ m_placeholder_parser.set("current_extruder", milling_extruder_id);
+ // Append the filament start G-code.
+ const std::string& start_mill_gcode = m_config.milling_toolchange_start_gcode.get_at(0);
+ if (!start_mill_gcode.empty()) {
+ DynamicConfig config;
+ config.set_key_value("previous_extruder", new ConfigOptionInt((int)current_extruder_filament));
+ config.set_key_value("next_extruder", new ConfigOptionInt((int)milling_extruder_id));
+ config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
+ config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
+ // Process the start_mill_gcode for the new filament.
+ gcode += this->placeholder_parser_process("milling_toolchange_start_gcode", start_mill_gcode, current_extruder_filament, &config);
+ check_add_eol(gcode);
+ }
+
+ gcode += "\n; began print:";
+ for (const LayerToPrint& ltp : layers) {
+ if (ltp.object_layer != nullptr) {
+ for (const PrintInstance& print_instance : ltp.object()->instances()){
+ this->set_origin(unscale(print_instance.shift));
+ for (const LayerRegion* lr : ltp.object_layer->regions()) {
+ if (!lr->milling.empty()) {
+ //EXTRUDE MOVES
+ gcode += "; extrude lr->milling\n";
+ gcode += this->extrude_entity(lr->milling, "; milling post-process");
+ }
+ }
+ }
+ }
+ }
+
+ //switch to extruder
+ m_placeholder_parser.set("current_extruder", milling_extruder_id);
+ // Append the filament start G-code.
+ const std::string& end_mill_gcode = m_config.milling_toolchange_end_gcode.get_at(0);
+ if (!end_mill_gcode.empty()) {
+ DynamicConfig config;
+ config.set_key_value("previous_extruder", new ConfigOptionInt((int)milling_extruder_id));
+ config.set_key_value("next_extruder", new ConfigOptionInt((int)current_extruder_filament));
+ config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
+ config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
+ // Process the end_mill_gcode for the new filament.
+ gcode += this->placeholder_parser_process("milling_toolchange_start_gcode", end_mill_gcode, current_extruder_filament, &config);
+ check_add_eol(gcode);
+ }
+ gcode += "; will go back to normal extruder\n";
+ //TODO: change wipetower code to add an other filament change per layer.
+ gcode += (layer_tools.has_wipe_tower && m_wipe_tower) ?
+ m_wipe_tower->tool_change(*this, current_extruder_filament, current_extruder_filament == layer_tools.extruders.back()) :
+ this->set_extruder(current_extruder_filament, print_z);
+ }
+ }
+
+
// Apply cooling logic; this may alter speeds.
if (m_cooling_buffer)
gcode = m_cooling_buffer->process_layer(gcode, layer.id());
@@ -2487,10 +2587,10 @@ void GCode::append_full_config(const Print &print, std::string &str)
str += "; " + key + " = " + cfg.opt_serialize(key) + "\n";
}
-void GCode::set_extruders(const std::vector<unsigned int> &extruder_ids)
+void GCode::set_extruders(const std::vector<uint16_t>& extruder_ids)
{
m_writer.set_extruders(extruder_ids);
-
+
// enable wipe path generation if any extruder has wipe enabled
m_wipe.enable = false;
for (auto id : extruder_ids)
@@ -2533,7 +2633,7 @@ std::string GCode::change_layer(coordf_t print_z)
// Increment a progress bar indicator.
gcode += m_writer.update_progress(++ m_layer_index, m_layer_count);
coordf_t z = print_z + m_config.z_offset.value; // in unscaled coordinates
- if (EXTRUDER_CONFIG(retract_layer_change) && m_writer.will_move_z(z))
+ if (BOOL_EXTRUDER_CONFIG(retract_layer_change) && m_writer.will_move_z(z))
gcode += this->retract();
{
@@ -2756,7 +2856,7 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s
// if polyline was shorter than the clipping distance we'd get a null polyline, so
// we discard it in that case
double clip_length = m_enable_loop_clipping ?
- scale_(EXTRUDER_CONFIG(nozzle_diameter)) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER :
+ scale_(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter,0)) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER :
0;
// get paths
@@ -2776,7 +2876,7 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s
}
//all in unscaled coordinates (hence why it's coordf_t and not coord_t)
- const coordf_t min_height = EXTRUDER_CONFIG(min_layer_height);
+ const coordf_t min_height = EXTRUDER_CONFIG_WITH_DEFAULT(min_layer_height, this->m_layer->height);
const coordf_t bot_init_z = - this->m_layer->height;
//const coordf_t bot_last_z = bot_init_z + this->m_layer->height - EXTRUDER_CONFIG(min_layer_height);
const coordf_t init_z = bot_init_z + min_height;
@@ -2807,7 +2907,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(nozzle_diameter));
+ double nd = scale_(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!
@@ -2856,7 +2956,7 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s
// calculate extrusion length per distance unit
double e_per_mm_per_height = (path->mm3_per_mm / this->m_layer->height)
- * m_writer.extruder()->e_per_mm3()
+ * m_writer.tool()->e_per_mm3()
* this->config().print_extrusion_multiplier.get_abs_value(1);
if (m_writer.extrusion_axis().empty()) e_per_mm_per_height = 0;
{
@@ -2864,7 +2964,7 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s
for (const Line &line : path->polyline.lines()) {
const coordf_t line_length = line.length() * SCALING_FACTOR;
//don't go (much) more than a nozzle_size without a refresh of the z & extrusion rate
- const int nb_sections = std::max(1,int(line_length / EXTRUDER_CONFIG(nozzle_diameter)));
+ const int nb_sections = std::max(1,int(line_length / EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, paths.front().width)));
const coordf_t height_increment = height_per_length * line_length / nb_sections;
Vec3d last_point{ this->point_to_gcode(line.a).x(), this->point_to_gcode(line.a).y(), current_z };
const Vec3d pos_increment{ (this->point_to_gcode(line.b).x() - last_point.x()) / nb_sections,
@@ -2955,7 +3055,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(nozzle_diameter));
+ double nd = scale_(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!
@@ -2971,6 +3071,8 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s
void GCode::split_at_seam_pos(ExtrusionLoop &loop, std::unique_ptr<EdgeGrid::Grid> *lower_layer_edge_grid)
{
+ if (loop.paths.empty())
+ return;
SeamPosition seam_position = m_config.seam_position;
if (loop.loop_role() == elrSkirt)
@@ -2983,7 +3085,7 @@ void GCode::split_at_seam_pos(ExtrusionLoop &loop, std::unique_ptr<EdgeGrid::Gri
loop.split_at(last_pos, false);
} else if (seam_position == spNearest || seam_position == spAligned || seam_position == spRear || seam_position == spHidden) {
Polygon polygon = loop.polygon();
- const coordf_t nozzle_dmr = EXTRUDER_CONFIG(nozzle_diameter);
+ const coordf_t nozzle_dmr = EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, loop.paths.front().width);
const coord_t nozzle_r = coord_t(scale_(0.5 * nozzle_dmr) + 0.5);
// Retrieve the last start position for this object.
@@ -3177,7 +3279,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
//but not for the first layer
&& this->m_layer->id() > 0
//exclude if min_layer_height * 2 > layer_height (increase from 2 to 3 because it's working but uses in-between)
- && this->m_layer->height >= EXTRUDER_CONFIG(min_layer_height) * 2 - EPSILON
+ && this->m_layer->height >= EXTRUDER_CONFIG_WITH_DEFAULT(min_layer_height, 0) * 2 - EPSILON
) {
return extrude_loop_vase(original_loop, description, speed, lower_layer_edge_grid);
}
@@ -3224,7 +3326,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
// if polyline was shorter than the clipping distance we'd get a null polyline, so
// we discard it in that case
double clip_length = m_enable_loop_clipping ?
- scale_(EXTRUDER_CONFIG(nozzle_diameter)) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER :
+ scale_(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter,0)) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER :
0;
// get paths
@@ -3260,8 +3362,8 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
Point next_point = paths.front().polyline.points[1]; // second point
//extra wipe before the little move.
- if (EXTRUDER_CONFIG(wipe_extra_perimeter) > 0) {
- coord_t wipe_dist = scale_(EXTRUDER_CONFIG(wipe_extra_perimeter));
+ if (EXTRUDER_CONFIG_WITH_DEFAULT(wipe_extra_perimeter, 0) > 0) {
+ coord_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];
@@ -3319,7 +3421,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(nozzle_diameter));
+ double nd = scale_(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!
@@ -3359,7 +3461,7 @@ std::string GCode::extrude_multi_path3D(const ExtrusionMultiPath3D &multipath3D,
// calculate extrusion length per distance unit
double e_per_mm = path.mm3_per_mm
- * m_writer.extruder()->e_per_mm3()
+ * m_writer.tool()->e_per_mm3()
* this->config().print_extrusion_multiplier.get_abs_value(1);
if (m_writer.extrusion_axis().empty()) e_per_mm = 0;
double path_length = 0.;
@@ -3428,7 +3530,7 @@ std::string GCode::extrude_path_3D(const ExtrusionPath3D &path, const std::strin
// calculate extrusion length per distance unit
double e_per_mm = path.mm3_per_mm
- * m_writer.extruder()->e_per_mm3()
+ * m_writer.tool()->e_per_mm3()
* this->config().print_extrusion_multiplier.get_abs_value(1);
if (m_writer.extrusion_axis().empty()) e_per_mm = 0;
double path_length = 0.;
@@ -3589,7 +3691,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string &descri
// calculate extrusion length per distance unit
double e_per_mm = path.mm3_per_mm
- * m_writer.extruder()->e_per_mm3()
+ * m_writer.tool()->e_per_mm3()
* this->config().print_extrusion_multiplier.get_abs_value(1);
if (this->m_layer_index <= 0) e_per_mm *= this->config().first_layer_flow_ratio.get_abs_value(1);
if (m_writer.extrusion_axis().empty()) e_per_mm = 0;
@@ -3724,6 +3826,8 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
speed = m_config.get_abs_value("gap_fill_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 std::invalid_argument("Invalid speed");
}
@@ -3742,11 +3846,11 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
m_config.max_volumetric_speed.value / path.mm3_per_mm
);
}
- if (EXTRUDER_CONFIG(filament_max_volumetric_speed) > 0) {
+ if (EXTRUDER_CONFIG_WITH_DEFAULT(filament_max_volumetric_speed,0) > 0) {
// cap speed with max_volumetric_speed anyway (even if user is not using autospeed)
speed = std::min(
speed,
- EXTRUDER_CONFIG(filament_max_volumetric_speed) / path.mm3_per_mm
+ EXTRUDER_CONFIG_WITH_DEFAULT(filament_max_volumetric_speed, speed) / path.mm3_per_mm
);
}
double F = speed * 60; // convert mm/sec to mm/min
@@ -3758,7 +3862,7 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1));
config.set_key_value("layer_z", new ConfigOptionFloat(m_config.z_offset.value));
gcode += this->placeholder_parser_process("feature_gcode",
- m_config.feature_gcode.value, m_writer.extruder()->id(), &config)
+ m_config.feature_gcode.value, m_writer.tool()->id(), &config)
+ "\n";
}
if (m_enable_extrusion_role_markers) {
@@ -3891,7 +3995,7 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role)
{
- if (travel.length() < scale_(EXTRUDER_CONFIG(retract_before_travel))) {
+ if (travel.length() < scale_(EXTRUDER_CONFIG_WITH_DEFAULT(retract_before_travel, 0))) {
// skip retraction if the move is shorter than the configured threshold
return false;
}
@@ -3921,7 +4025,7 @@ std::string GCode::retract(bool toolchange)
{
std::string gcode;
- if (m_writer.extruder() == nullptr)
+ if (m_writer.tool() == nullptr)
return gcode;
// We need to reset e before any extrusion or wipe to allow the reset to happen at the real
@@ -3929,7 +4033,7 @@ std::string GCode::retract(bool toolchange)
gcode += m_writer.reset_e();
// wipe (if it's enabled for this extruder and we have a stored wipe path)
- if (EXTRUDER_CONFIG(wipe) && m_wipe.has_path()) {
+ if (BOOL_EXTRUDER_CONFIG(wipe) && m_wipe.has_path()) {
gcode += toolchange ? m_writer.retract_for_toolchange(true) : m_writer.retract(true);
gcode += m_wipe.wipe(*this, toolchange);
}
@@ -3939,8 +4043,14 @@ std::string GCode::retract(bool toolchange)
methods even if we performed wipe, since this will ensure the entire retraction
length is honored in case wipe path was too short. */
gcode += toolchange ? m_writer.retract_for_toolchange() : m_writer.retract();
- if (toolchange || !this->m_config.retract_lift_not_last_layer.get_at(m_writer.extruder()->id()) || !(this->m_last_extrusion_role == ExtrusionRole::erTopSolidInfill))
- if (m_writer.extruder()->retract_length() > 0 || m_config.use_firmware_retraction)
+ if (toolchange
+ || !(BOOL_EXTRUDER_CONFIG(retract_lift_not_last_layer) && (this->m_last_extrusion_role == ExtrusionRole::erTopSolidInfill ))
+ || !m_writer.tool_is_extruder()
+ )
+ if (m_writer.tool()->retract_length() > 0
+ || m_config.use_firmware_retraction
+ || (!m_writer.tool_is_extruder() && m_writer.tool()->retract_lift() != 0)
+ )
gcode += m_writer.lift();
return gcode;
@@ -3978,14 +4088,14 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
// Always reset the extrusion path, even if the tool change retract is set to zero.
m_wipe.reset_path();
- if (m_writer.extruder() != nullptr) {
+ if (m_writer.tool() != nullptr) {
// Process the custom end_filament_gcode. set_extruder() is only called if there is no wipe tower
// so it should not be injected twice.
- unsigned int old_extruder_id = m_writer.extruder()->id();
+ unsigned int old_extruder_id = m_writer.tool()->id();
const std::string &end_filament_gcode = m_config.end_filament_gcode.get_at(old_extruder_id);
if (! end_filament_gcode.empty()) {
DynamicConfig config;
- config.set_key_value("previous_extruder", new ConfigOptionInt((int)(m_writer.extruder() != nullptr ? m_writer.extruder()->id() : -1)));
+ config.set_key_value("previous_extruder", new ConfigOptionInt((int)(m_writer.tool() != nullptr ? m_writer.tool()->id() : -1)));
config.set_key_value("next_extruder", new ConfigOptionInt((int)extruder_id));
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
@@ -3997,7 +4107,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
// If ooze prevention is enabled, park current extruder in the nearest
// standby point and set it to the standby temperature.
- if (m_ooze_prevention.enable && m_writer.extruder() != nullptr)
+ if (m_ooze_prevention.enable && m_writer.tool() != nullptr)
gcode += m_ooze_prevention.pre_toolchange(*this);
const std::string& toolchange_gcode = m_config.toolchange_gcode.value;
@@ -4006,7 +4116,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
// Process the custom toolchange_gcode. If it is empty, insert just a Tn command.
if (!toolchange_gcode.empty()) {
DynamicConfig config;
- config.set_key_value("previous_extruder", new ConfigOptionInt((int)(m_writer.extruder() != nullptr ? m_writer.extruder()->id() : -1 )));
+ config.set_key_value("previous_extruder", new ConfigOptionInt((int)(m_writer.tool() != nullptr ? m_writer.tool()->id() : -1 )));
config.set_key_value("next_extruder", new ConfigOptionInt((int)extruder_id));
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
@@ -4037,7 +4147,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id);
if (! start_filament_gcode.empty()) {
DynamicConfig config;
- config.set_key_value("previous_extruder", new ConfigOptionInt((int)(m_writer.extruder() != nullptr ? m_writer.extruder()->id() : -1)));
+ config.set_key_value("previous_extruder", new ConfigOptionInt((int)(m_writer.tool() != nullptr ? m_writer.tool()->id() : -1)));
config.set_key_value("next_extruder", new ConfigOptionInt((int)extruder_id));
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
@@ -4055,13 +4165,13 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
// convert a model-space scaled point into G-code coordinates
Vec2d GCode::point_to_gcode(const Point &point) const
{
- Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset);
+ Vec2d extruder_offset = EXTRUDER_CONFIG_WITH_DEFAULT(extruder_offset, Vec2d(0, 0)); //FIXME : mill ofsset
return unscale(point) + m_origin - extruder_offset;
}
// 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(extruder_offset);
+ 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));
@@ -4071,7 +4181,7 @@ Vec3d GCode::point_to_gcode(const Point &point, const coord_t z_offset) const {
// convert a model-space scaled point into G-code coordinates
Point GCode::gcode_to_point(const Vec2d &point) const
{
- Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset);
+ Vec2d extruder_offset = EXTRUDER_CONFIG_WITH_DEFAULT(extruder_offset, Vec2d(0, 0)); //FIXME : mill ofsset
return Point(
scale_(point(0) - m_origin(0) + extruder_offset(0)),
scale_(point(1) - m_origin(1) + extruder_offset(1)));
@@ -4205,6 +4315,8 @@ GCode::extrusion_role_to_string_for_parser(const ExtrusionRole & role) {
return "SupportMaterialInterface";
case erWipeTower:
return "WipeTower";
+ case erMilling:
+ return "Mill";
case erCustom:
case erMixed:
case erCount:
diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp
index 45b4e8487..68f634ff4 100644
--- a/src/libslic3r/GCode.hpp
+++ b/src/libslic3r/GCode.hpp
@@ -240,7 +240,7 @@ private:
void set_last_pos(const Point &pos) { m_last_pos = pos; m_last_pos_defined = true; }
bool last_pos_defined() const { return m_last_pos_defined; }
- void set_extruders(const std::vector<unsigned int> &extruder_ids);
+ void set_extruders(const std::vector<uint16_t> &extruder_ids);
std::string preamble();
std::string change_layer(coordf_t print_z);
std::string visitor_gcode;
diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp
index 81d0b15a0..a088bf33e 100644
--- a/src/libslic3r/GCode/CoolingBuffer.cpp
+++ b/src/libslic3r/GCode/CoolingBuffer.cpp
@@ -294,15 +294,15 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
{
const FullPrintConfig &config = m_gcodegen.config();
const std::vector<Extruder> &extruders = m_gcodegen.writer().extruders();
- unsigned int num_extruders = 0;
+ uint16_t num_extruders = 0;
for (const Extruder &ex : extruders)
- num_extruders = std::max(ex.id() + 1, num_extruders);
+ num_extruders = std::max(uint16_t(ex.id() + 1), num_extruders);
std::vector<PerExtruderAdjustments> per_extruder_adjustments(extruders.size());
std::vector<size_t> map_extruder_to_per_extruder_adjustment(num_extruders, 0);
for (size_t i = 0; i < extruders.size(); ++ i) {
PerExtruderAdjustments &adj = per_extruder_adjustments[i];
- unsigned int extruder_id = extruders[i].id();
+ uint16_t extruder_id = extruders[i].id();
adj.extruder_id = extruder_id;
adj.cooling_slow_down_enabled = config.cooling.get_at(extruder_id);
adj.slowdown_below_layer_time = float(config.slowdown_below_layer_time.get_at(extruder_id));
@@ -311,7 +311,7 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
}
const std::string toolchange_prefix = m_gcodegen.writer().toolchange_prefix();
- unsigned int current_extruder = m_current_extruder;
+ uint16_t current_extruder = m_current_extruder;
PerExtruderAdjustments *adjustment = &per_extruder_adjustments[map_extruder_to_per_extruder_adjustment[current_extruder]];
const char *line_start = gcode.c_str();
const char *line_end = line_start;
@@ -418,7 +418,7 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
line.type = CoolingLine::TYPE_EXTRUDE_END;
active_speed_modifier = size_t(-1);
} else if (boost::starts_with(sline, toolchange_prefix)) {
- unsigned int new_extruder = (unsigned int)atoi(sline.c_str() + toolchange_prefix.size());
+ uint16_t new_extruder = (uint16_t)atoi(sline.c_str() + toolchange_prefix.size());
// Only change extruder in case the number is meaningful. User could provide an out-of-range index through custom gcodes - those shall be ignored.
if (new_extruder < map_extruder_to_per_extruder_adjustment.size()) {
if (new_extruder != current_extruder) {
diff --git a/src/libslic3r/GCode/PreviewData.cpp b/src/libslic3r/GCode/PreviewData.cpp
index b7c77e9a0..014efd39d 100644
--- a/src/libslic3r/GCode/PreviewData.cpp
+++ b/src/libslic3r/GCode/PreviewData.cpp
@@ -124,6 +124,7 @@ const Color GCodePreviewData::Extrusion::Default_Extrusion_Role_Colors[erCount]
Color(0.0f, 0.5f, 0.0f, 1.0f), // erSupportMaterial
Color(0.0f, 0.0f, 0.5f, 1.0f), // erSupportMaterialInterface
Color(0.7f, 0.89f, 0.67f, 1.0f), // erWipeTower
+ Color(0.7f, 0.7, 0.7, 1.0f), // erMilling
Color(1.0f, 1.0f, 0.0f, 1.0f), // erCustom
Color(0.0f, 0.0f, 0.0f, 1.0f) // erMixed
};
diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp
index a77da4966..c9ce9c941 100644
--- a/src/libslic3r/GCode/ToolOrdering.cpp
+++ b/src/libslic3r/GCode/ToolOrdering.cpp
@@ -21,7 +21,7 @@ namespace Slic3r {
// Returns true in case that extruder a comes before b (b does not have to be present). False otherwise.
-bool LayerTools::is_extruder_order(unsigned int a, unsigned int b) const
+bool LayerTools::is_extruder_order(uint16_t a, uint16_t b) const
{
if (a == b)
return false;
@@ -37,32 +37,32 @@ bool LayerTools::is_extruder_order(unsigned int a, unsigned int b) const
}
// Return a zero based extruder from the region, or extruder_override if overriden.
-unsigned int LayerTools::perimeter_extruder(const PrintRegion &region) const
+uint16_t LayerTools::perimeter_extruder(const PrintRegion &region) const
{
assert(region.config().perimeter_extruder.value > 0);
return ((this->extruder_override == 0) ? region.config().perimeter_extruder.value : this->extruder_override) - 1;
}
-unsigned int LayerTools::infill_extruder(const PrintRegion &region) const
+uint16_t LayerTools::infill_extruder(const PrintRegion &region) const
{
assert(region.config().infill_extruder.value > 0);
return ((this->extruder_override == 0) ? region.config().infill_extruder.value : this->extruder_override) - 1;
}
-unsigned int LayerTools::solid_infill_extruder(const PrintRegion &region) const
+uint16_t LayerTools::solid_infill_extruder(const PrintRegion &region) const
{
assert(region.config().solid_infill_extruder.value > 0);
return ((this->extruder_override == 0) ? region.config().solid_infill_extruder.value : this->extruder_override) - 1;
}
// Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden.
-unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, const PrintRegion &region) const
+uint16_t LayerTools::extruder(const ExtrusionEntityCollection &extrusions, const PrintRegion &region) const
{
assert(region.config().perimeter_extruder.value > 0);
assert(region.config().infill_extruder.value > 0);
assert(region.config().solid_infill_extruder.value > 0);
// 1 based extruder ID.
- unsigned int extruder = ((this->extruder_override == 0) ?
+ uint16_t extruder = ((this->extruder_override == 0) ?
(is_infill(extrusions.role()) ?
(is_solid_infill(extrusions.entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) :
region.config().perimeter_extruder.value) :
@@ -72,7 +72,7 @@ unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, c
// For the use case when each object is printed separately
// (print.config().complete_objects is true).
-ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material)
+ToolOrdering::ToolOrdering(const PrintObject &object, uint16_t first_extruder, bool prime_multi_material)
{
if (object.layers().empty())
return;
@@ -89,7 +89,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
}
// Collect extruders reuqired to print the layers.
- this->collect_extruders(object, std::vector<std::pair<double, unsigned int>>());
+ this->collect_extruders(object, std::vector<std::pair<double, uint16_t>>());
// Reorder the extruders to minimize tool switches.
this->reorder_extruders(first_extruder);
@@ -101,7 +101,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
// For the use case when all objects are printed at once.
// (print.config().complete_objects is false).
-ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material)
+ToolOrdering::ToolOrdering(const Print &print, uint16_t first_extruder, bool prime_multi_material)
{
m_print_config_ptr = &print.config();
@@ -128,8 +128,8 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
// Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object.
// Do it only if all the objects were configured to be printed with a single extruder.
- std::vector<std::pair<double, unsigned int>> per_layer_extruder_switches;
- if (auto num_extruders = unsigned(print.config().nozzle_diameter.size());
+ std::vector<std::pair<double, uint16_t>> per_layer_extruder_switches;
+ if (uint16_t num_extruders = uint16_t(print.config().nozzle_diameter.size());
num_extruders > 1 && print.object_extruders(print.objects()).size() == 1 && // the current Print's configuration is CustomGCode::MultiAsSingle
print.model().custom_gcode_per_print_z.mode == CustomGCode::MultiAsSingle) {
// Printing a single extruder platter on a printer with more than 1 extruder (or single-extruder multi-material).
@@ -165,7 +165,7 @@ void ToolOrdering::initialize_layers(std::vector<coordf_t> &zs)
}
// Collect extruders reuqired to print layers.
-void ToolOrdering::collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches)
+void ToolOrdering::collect_extruders(const PrintObject &object, const std::vector<std::pair<double, uint16_t>> &per_layer_extruder_switches)
{
// Collect the support extruders.
for (auto support_layer : object.support_layers()) {
@@ -173,8 +173,8 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
ExtrusionRole role = support_layer->support_fills.role();
bool has_support = role == erMixed || role == erSupportMaterial;
bool has_interface = role == erMixed || role == erSupportMaterialInterface;
- unsigned int extruder_support = object.config().support_material_extruder.value;
- unsigned int extruder_interface = object.config().support_material_interface_extruder.value;
+ uint16_t extruder_support = object.config().support_material_extruder.value;
+ uint16_t extruder_interface = object.config().support_material_interface_extruder.value;
if (has_support)
layer_tools.extruders.push_back(extruder_support);
if (has_interface)
@@ -184,9 +184,9 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
}
// Extruder overrides are ordered by print_z.
- std::vector<std::pair<double, unsigned int>>::const_iterator it_per_layer_extruder_override;
+ std::vector<std::pair<double, uint16_t>>::const_iterator it_per_layer_extruder_override;
it_per_layer_extruder_override = per_layer_extruder_switches.begin();
- unsigned int extruder_override = 0;
+ uint16_t extruder_override = 0;
// Collect the object extruders.
for (auto layer : object.layers()) {
@@ -265,18 +265,18 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
}
// Reorder extruders to minimize layer changes.
-void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
+void ToolOrdering::reorder_extruders(uint16_t last_extruder_id)
{
if (m_layer_tools.empty())
return;
- if (last_extruder_id == (unsigned int)-1) {
+ if (last_extruder_id == (uint16_t)-1) {
// The initial print extruder has not been decided yet.
// Initialize the last_extruder_id with the first non-zero extruder id used for the print.
last_extruder_id = 0;
for (size_t i = 0; i < m_layer_tools.size() && last_extruder_id == 0; ++ i) {
const LayerTools &lt = m_layer_tools[i];
- for (unsigned int extruder_id : lt.extruders)
+ for (uint16_t extruder_id : lt.extruders)
if (extruder_id > 0) {
last_extruder_id = extruder_id;
break;
@@ -302,7 +302,7 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
for (size_t i = 1; i < lt.extruders.size(); ++ i)
if (lt.extruders[i] == last_extruder_id) {
// Move the last extruder to the front.
- memmove(lt.extruders.data() + 1, lt.extruders.data(), i * sizeof(unsigned int));
+ memmove(lt.extruders.data() + 1, lt.extruders.data(), i * sizeof(uint16_t));
lt.extruders.front() = last_extruder_id;
break;
}
@@ -312,7 +312,7 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
// Reindex the extruders, so they are zero based, not 1 based.
for (LayerTools &lt : m_layer_tools)
- for (unsigned int &extruder_id : lt.extruders) {
+ for (uint16_t &extruder_id : lt.extruders) {
assert(extruder_id > 0);
-- extruder_id;
}
@@ -393,7 +393,7 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
// and maybe other problems. We will therefore go through layer_tools and detect and fix this.
// So, if there is a non-object layer starting with different extruder than the last one ended with (or containing more than one extruder),
// we'll mark it with has_wipe tower.
- for (unsigned int i=0; i+1<m_layer_tools.size(); ++i) {
+ for (uint16_t i=0; i+1<m_layer_tools.size(); ++i) {
LayerTools& lt = m_layer_tools[i];
LayerTools& lt_next = m_layer_tools[i+1];
if (lt.extruders.empty() || lt_next.extruders.empty())
@@ -401,7 +401,7 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
if (!lt_next.has_wipe_tower && (lt_next.extruders.front() != lt.extruders.back() || lt_next.extruders.size() > 1))
lt_next.has_wipe_tower = true;
// We should also check that the next wipe tower layer is no further than max_layer_height:
- unsigned int j = i+1;
+ uint16_t j = i+1;
double last_wipe_tower_print_z = lt_next.print_z;
while (++j < m_layer_tools.size()-1 && !m_layer_tools[j].has_wipe_tower)
if (m_layer_tools[j+1].print_z - last_wipe_tower_print_z > max_layer_height) {
@@ -421,14 +421,14 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
void ToolOrdering::collect_extruder_statistics(bool prime_multi_material)
{
- m_first_printing_extruder = (unsigned int)-1;
+ m_first_printing_extruder = (uint16_t)-1;
for (const auto &lt : m_layer_tools)
if (! lt.extruders.empty()) {
m_first_printing_extruder = lt.extruders.front();
break;
}
- m_last_printing_extruder = (unsigned int)-1;
+ m_last_printing_extruder = (uint16_t)-1;
for (auto lt_it = m_layer_tools.rbegin(); lt_it != m_layer_tools.rend(); ++ lt_it)
if (! lt_it->extruders.empty()) {
m_last_printing_extruder = lt_it->extruders.back();
@@ -446,7 +446,7 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material)
// Then set m_first_printing_extruder to the 1st extruder primed.
m_all_printing_extruders.erase(
std::remove_if(m_all_printing_extruders.begin(), m_all_printing_extruders.end(),
- [ this ](const unsigned int eid) { return eid == m_first_printing_extruder; }),
+ [ this ](const uint16_t eid) { return eid == m_first_printing_extruder; }),
m_all_printing_extruders.end());
m_all_printing_extruders.emplace_back(m_first_printing_extruder);
m_first_printing_extruder = m_all_printing_extruders.front();
@@ -482,7 +482,7 @@ void ToolOrdering::assign_custom_gcodes(const Print &print)
for (auto it_lt = m_layer_tools.rbegin(); it_lt != m_layer_tools.rend(); ++ it_lt) {
LayerTools &lt = *it_lt;
// Add the extruders of the current layer to the set of extruders printing at and above this print_z.
- for (unsigned int i : lt.extruders)
+ for (uint16_t i : lt.extruders)
extruder_printing_above[i] = true;
// Skip all custom G-codes above this layer and skip all extruder switches.
for (; custom_gcode_it != custom_gcode_per_print_z.gcodes.rend() && (custom_gcode_it->print_z > lt.print_z + EPSILON || custom_gcode_it->gcode == ToolChangeCode); ++ custom_gcode_it);
@@ -584,7 +584,7 @@ bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, con
// Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange
// and returns volume that is left to be wiped on the wipe tower.
-float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe)
+float WipingExtrusions::mark_wiping_extrusions(const Print& print, uint16_t old_extruder, uint16_t new_extruder, float volume_to_wipe)
{
const LayerTools& lt = *m_layer_tools;
const float min_infill_volume = 0.f; // ignore infill with smaller volume than this
@@ -619,7 +619,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
size_t num_of_copies = object->instances().size();
// iterate through copies (aka PrintObject instances) first, so that we mark neighbouring infills to minimize travel moves
- for (unsigned int copy = 0; copy < num_of_copies; ++copy) {
+ for (uint16_t copy = 0; copy < num_of_copies; ++copy) {
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) {
const auto& region = *object->print()->regions()[region_id];
@@ -683,8 +683,8 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
return;
const LayerTools& lt = *m_layer_tools;
- unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config());
- unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config());
+ uint16_t first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config());
+ uint16_t last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config());
for (const PrintObject* object : print.objects()) {
// Finds this layer:
diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp
index 2252270d4..d105908fe 100644
--- a/src/libslic3r/GCode/ToolOrdering.hpp
+++ b/src/libslic3r/GCode/ToolOrdering.hpp
@@ -35,7 +35,7 @@ public:
// This function goes through all infill entities, decides which ones will be used for wiping and
// marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower:
- float mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe);
+ float mark_wiping_extrusions(const Print& print, uint16_t old_extruder, uint16_t new_extruder, float volume_to_wipe);
void ensure_perimeters_infills_order(const Print& print);
@@ -79,24 +79,24 @@ public:
bool operator< (const LayerTools &rhs) const { return print_z < rhs.print_z; }
bool operator==(const LayerTools &rhs) const { return print_z == rhs.print_z; }
- bool is_extruder_order(unsigned int a, unsigned int b) const;
- bool has_extruder(unsigned int extruder) const { return std::find(this->extruders.begin(), this->extruders.end(), extruder) != this->extruders.end(); }
+ bool is_extruder_order(uint16_t a, uint16_t b) const;
+ bool has_extruder(uint16_t extruder) const { return std::find(this->extruders.begin(), this->extruders.end(), extruder) != this->extruders.end(); }
// Return a zero based extruder from the region, or extruder_override if overriden.
- unsigned int perimeter_extruder(const PrintRegion &region) const;
- unsigned int infill_extruder(const PrintRegion &region) const;
- unsigned int solid_infill_extruder(const PrintRegion &region) const;
+ uint16_t perimeter_extruder(const PrintRegion &region) const;
+ uint16_t infill_extruder(const PrintRegion &region) const;
+ uint16_t solid_infill_extruder(const PrintRegion &region) const;
// Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden.
- unsigned int extruder(const ExtrusionEntityCollection &extrusions, const PrintRegion &region) const;
+ uint16_t extruder(const ExtrusionEntityCollection &extrusions, const PrintRegion &region) const;
coordf_t print_z = 0.;
bool has_object = false;
bool has_support = false;
// Zero based extruder IDs, ordered to minimize tool switches.
- std::vector<unsigned int> extruders;
+ std::vector<uint16_t> extruders;
// If per layer extruder switches are inserted by the G-code preview slider, this value contains the new (1 based) extruder, with which the whole object layer is being printed with.
// If not overriden, it is set to 0.
- unsigned int extruder_override = 0;
+ uint16_t extruder_override = 0;
// Will there be anything extruded on this layer for the wipe tower?
// Due to the support layers possibly interleaving the object layers,
// wipe tower will be disabled for some support only layers.
@@ -127,11 +127,11 @@ public:
// For the use case when each object is printed separately
// (print.config.complete_objects is true).
- ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material = false);
+ ToolOrdering(const PrintObject &object, uint16_t first_extruder, bool prime_multi_material = false);
// For the use case when all objects are printed at once.
// (print.config.complete_objects is false).
- ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material = false);
+ ToolOrdering(const Print &print, uint16_t first_extruder, bool prime_multi_material = false);
void clear() { m_layer_tools.clear(); }
@@ -148,7 +148,7 @@ public:
unsigned int last_extruder() const { return m_last_printing_extruder; }
// For a multi-material print, the printing extruders are ordered in the order they shall be primed.
- const std::vector<unsigned int>& all_extruders() const { return m_all_printing_extruders; }
+ const std::vector<uint16_t>& all_extruders() const { return m_all_printing_extruders; }
// Find LayerTools with the closest print_z.
const LayerTools& tools_for_layer(coordf_t print_z) const;
@@ -160,24 +160,24 @@ public:
std::vector<LayerTools>::const_iterator end() const { return m_layer_tools.end(); }
bool empty() const { return m_layer_tools.empty(); }
std::vector<LayerTools>& layer_tools() { return m_layer_tools; }
- bool has_wipe_tower() const { return ! m_layer_tools.empty() && m_first_printing_extruder != (unsigned int)-1 && m_layer_tools.front().wipe_tower_partitions > 0; }
+ bool has_wipe_tower() const { return ! m_layer_tools.empty() && m_first_printing_extruder != (uint16_t)-1 && m_layer_tools.front().wipe_tower_partitions > 0; }
private:
void initialize_layers(std::vector<coordf_t> &zs);
- void collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches);
- void reorder_extruders(unsigned int last_extruder_id);
+ void collect_extruders(const PrintObject &object, const std::vector<std::pair<double, uint16_t>> &per_layer_extruder_switches);
+ void reorder_extruders(uint16_t last_extruder_id);
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z);
void collect_extruder_statistics(bool prime_multi_material);
- std::vector<LayerTools> m_layer_tools;
+ std::vector<LayerTools> m_layer_tools;
// First printing extruder, including the multi-material priming sequence.
- unsigned int m_first_printing_extruder = (unsigned int)-1;
+ uint16_t m_first_printing_extruder = (uint16_t)-1;
// Final printing extruder.
- unsigned int m_last_printing_extruder = (unsigned int)-1;
+ uint16_t m_last_printing_extruder = (uint16_t)-1;
// All extruders, which extrude some material over m_layer_tools.
- std::vector<unsigned int> m_all_printing_extruders;
+ std::vector<uint16_t> m_all_printing_extruders;
- const PrintConfig* m_print_config_ptr = nullptr;
+ const PrintConfig* m_print_config_ptr = nullptr;
};
diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp
index 9c24cc61c..78e71bd32 100644
--- a/src/libslic3r/GCode/WipeTower.cpp
+++ b/src/libslic3r/GCode/WipeTower.cpp
@@ -624,7 +624,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
// print_z of the first layer.
float first_layer_height,
// Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object.
- const std::vector<unsigned int> &tools,
+ const std::vector<uint16_t> &tools,
// If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower.
// If false, the last priming are will be large enough to wipe the last extruder sufficiently.
bool /*last_wipe_inside_wipe_tower*/)
@@ -672,7 +672,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
writer.set_initial_position(results.back().end_pos);
- unsigned int tool = tools[idx_tool];
+ uint16_t tool = tools[idx_tool];
m_left_to_right = true;
toolchange_Change(writer, tool, m_filpar[tool].material); // Select the tool, set a speed override for soluble and flex materials.
toolchange_Load(writer, cleaning_box); // Prime the tool.
@@ -1371,7 +1371,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
}
// Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box
-void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim, float wipe_volume)
+void WipeTower::plan_toolchange(float z_par, float layer_height_par, uint16_t old_tool, uint16_t new_tool, bool brim, float wipe_volume)
{
assert(m_plan.empty() || m_plan.back().z <= z_par + WT_EPSILON); // refuses to add a layer below the last one
diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp
index 18689eee0..1cfea50e5 100644
--- a/src/libslic3r/GCode/WipeTower.hpp
+++ b/src/libslic3r/GCode/WipeTower.hpp
@@ -25,14 +25,14 @@ public:
struct Extrusion
{
- Extrusion(const Vec2f &pos, float width, unsigned int tool) : pos(pos), width(width), tool(tool) {}
+ Extrusion(const Vec2f &pos, float width, uint16_t tool) : pos(pos), width(width), tool(tool) {}
// End position of this extrusion.
Vec2f pos;
// Width of a squished extrusion, corrected for the roundings of the squished extrusions.
// This is left zero if it is a travel move.
float width;
// Current extruder index.
- unsigned int tool;
+ uint16_t tool;
};
struct ToolChangeResult
@@ -88,7 +88,7 @@ public:
// Appends into internal structure m_plan containing info about the future wipe tower
// to be used before building begins. The entries must be added ordered in z.
- void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim, float wipe_volume = 0.f);
+ void plan_toolchange(float z_par, float layer_height_par, uint16_t old_tool, uint16_t new_tool, bool brim, float wipe_volume = 0.f);
// Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result"
void generate(std::vector<std::vector<ToolChangeResult>> &result);
@@ -146,7 +146,7 @@ public:
// print_z of the first layer.
float first_layer_height,
// Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object.
- const std::vector<unsigned int> &tools,
+ const std::vector<uint16_t> &tools,
// If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower.
// If false, the last priming are will be large enough to wipe the last extruder sufficiently.
bool last_wipe_inside_wipe_tower);
@@ -259,9 +259,9 @@ private:
// State of the wipe tower generator.
- unsigned int m_num_layer_changes = 0; // Layer change counter for the output statistics.
- unsigned int m_num_tool_changes = 0; // Tool change change counter for the output statistics.
- ///unsigned int m_idx_tool_change_in_layer = 0; // Layer change counter in this layer. Counting up to m_max_color_changes.
+ uint32_t m_num_layer_changes = 0; // Layer change counter for the output statistics.
+ uint32_t m_num_tool_changes = 0; // Tool change change counter for the output statistics.
+ ///uint16_t m_idx_tool_change_in_layer = 0; // Layer change counter in this layer. Counting up to m_max_color_changes.
bool m_print_brim = true;
// A fill-in direction (positive Y, negative Y) alternates with each layer.
wipe_shape m_current_shape = SHAPE_NORMAL;
diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp
index b4aa9c172..d666556fa 100644
--- a/src/libslic3r/GCodeWriter.cpp
+++ b/src/libslic3r/GCodeWriter.cpp
@@ -26,18 +26,31 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
print_config.machine_max_acceleration_extruding.values.front() : 0);
}
-void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids)
+void GCodeWriter::set_extruders(std::vector<uint16_t> extruder_ids)
{
std::sort(extruder_ids.begin(), extruder_ids.end());
m_extruders.clear();
m_extruders.reserve(extruder_ids.size());
- for (unsigned int extruder_id : extruder_ids)
+ for (uint16_t extruder_id : extruder_ids)
m_extruders.emplace_back(Extruder(extruder_id, &this->config));
-
+
/* we enable support for multiple extruder if any extruder greater than 0 is used
(even if prints only uses that one) since we need to output Tx commands
first extruder has index 0 */
- this->multiple_extruders = (*std::max_element(extruder_ids.begin(), extruder_ids.end())) > 0;
+ this->multiple_extruders = this->multiple_extruders || (*std::max_element(extruder_ids.begin(), extruder_ids.end())) > 0;
+}
+
+void GCodeWriter::set_mills(std::vector<uint16_t> mill_ids)
+{
+ std::sort(mill_ids.begin(), mill_ids.end());
+ m_millers.clear();
+ m_millers.reserve(mill_ids.size());
+ for (uint16_t mill_id : mill_ids) {
+ m_millers.emplace_back(Mill(mill_id, &this->config));
+ }
+
+ /* we enable support for multiple extruder */
+ this->multiple_extruders = this->multiple_extruders || !mill_ids.empty();
}
std::string GCodeWriter::preamble()
@@ -211,10 +224,10 @@ std::string GCodeWriter::reset_e(bool force)
|| FLAVOR_IS(gcfSailfish))
return "";
- if (m_extruder != nullptr) {
- if (m_extruder->E() == 0. && ! force)
+ if (m_tool != nullptr) {
+ if (m_tool->E() == 0. && ! force)
return "";
- m_extruder->reset_E();
+ m_tool->reset_E();
}
if (! m_extrusion_axis.empty() && ! this->config.use_relative_e_distances) {
@@ -251,18 +264,35 @@ std::string GCodeWriter::toolchange_prefix() const
"T";
}
-std::string GCodeWriter::toolchange(unsigned int extruder_id)
+std::string GCodeWriter::toolchange(unsigned int tool_id)
{
// set the new extruder
- auto it_extruder = Slic3r::lower_bound_by_predicate(m_extruders.begin(), m_extruders.end(), [extruder_id](const Extruder &e) { return e.id() < extruder_id; });
- assert(it_extruder != m_extruders.end() && it_extruder->id() == extruder_id);
- m_extruder = &*it_extruder;
+ /*auto it_extruder = Slic3r::lower_bound_by_predicate(m_extruders.begin(), m_extruders.end(), [tool_id](const Extruder &e) { return e.id() < tool_id; });
+ assert(it_extruder != m_extruders.end() && it_extruder->id() == extruder_id);*/
+ //less optimized but it's easier to modify and it's not needed, as it's not called often.
+ bool found = false;
+ for (Extruder& extruder : m_extruders) {
+ if (tool_id == extruder.id()) {
+ m_tool = &extruder;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ for (Tool& mill : m_millers) {
+ if (tool_id == mill.id()) {
+ m_tool = &mill;
+ found = true;
+ break;
+ }
+ }
+ }
// return the toolchange command
// if we are running a single-extruder setup, just set the extruder and return nothing
std::ostringstream gcode;
if (this->multiple_extruders) {
- gcode << this->toolchange_prefix() << extruder_id;
+ gcode << this->toolchange_prefix() << tool_id;
if (this->config.gcode_comments)
gcode << " ; change extruder";
gcode << "\n";
@@ -375,12 +405,13 @@ std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std:
{
m_pos.x() = point.x();
m_pos.y() = point.y();
- m_extruder->extrude(dE);
+ bool is_extrude = m_tool->extrude(dE) != 0;
std::ostringstream gcode;
gcode << "G1 X" << XYZF_NUM(point.x())
- << " Y" << XYZF_NUM(point.y())
- << " " << m_extrusion_axis << E_NUM(m_extruder->E());
+ << " Y" << XYZF_NUM(point.y());
+ if(is_extrude)
+ gcode << " " << m_extrusion_axis << E_NUM(m_tool->E());
COMMENT(comment);
gcode << "\n";
return gcode.str();
@@ -391,13 +422,14 @@ std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std
m_pos.x() = point.x();
m_pos.y() = point.y();
m_lifted = 0;
- m_extruder->extrude(dE);
+ bool is_extrude = m_tool->extrude(dE) != 0;
std::ostringstream gcode;
gcode << "G1 X" << XYZF_NUM(point.x())
- << " Y" << XYZF_NUM(point.y())
- << " Z" << XYZF_NUM(point.z() + m_pos.z())
- << " " << m_extrusion_axis << E_NUM(m_extruder->E());
+ << " Y" << XYZF_NUM(point.y())
+ << " Z" << XYZF_NUM(point.z() + m_pos.z());
+ if (is_extrude)
+ gcode << " " << m_extrusion_axis << E_NUM(m_tool->E());
COMMENT(comment);
gcode << "\n";
return gcode.str();
@@ -405,22 +437,22 @@ std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std
std::string GCodeWriter::retract(bool before_wipe)
{
- double factor = before_wipe ? m_extruder->retract_before_wipe() : 1.;
+ double factor = before_wipe ? m_tool->retract_before_wipe() : 1.;
assert(factor >= 0. && factor <= 1. + EPSILON);
return this->_retract(
- factor * m_extruder->retract_length(),
- factor * m_extruder->retract_restart_extra(),
+ factor * m_tool->retract_length(),
+ factor * m_tool->retract_restart_extra(),
"retract"
);
}
std::string GCodeWriter::retract_for_toolchange(bool before_wipe)
{
- double factor = before_wipe ? m_extruder->retract_before_wipe() : 1.;
+ double factor = before_wipe ? m_tool->retract_before_wipe() : 1.;
assert(factor >= 0. && factor <= 1. + EPSILON);
return this->_retract(
- factor * m_extruder->retract_length_toolchange(),
- factor * m_extruder->retract_restart_extra_toolchange(),
+ factor * m_tool->retract_length_toolchange(),
+ factor * m_tool->retract_restart_extra_toolchange(),
"retract for toolchange"
);
}
@@ -436,13 +468,13 @@ std::string GCodeWriter::_retract(double length, double restart_extra, const std
// If we use volumetric E values we turn lengths into volumes */
if (this->config.use_volumetric_e) {
- double d = m_extruder->filament_diameter();
+ double d = m_tool->filament_diameter();
double area = d * d * PI/4;
length = length * area;
restart_extra = restart_extra * area;
}
- double dE = m_extruder->retract(length, restart_extra);
+ double dE = m_tool->retract(length, restart_extra);
if (dE != 0) {
if (this->config.use_firmware_retraction) {
if (FLAVOR_IS(gcfMachinekit))
@@ -450,8 +482,8 @@ std::string GCodeWriter::_retract(double length, double restart_extra, const std
else
gcode << "G10 ; retract\n";
} else {
- gcode << "G1 " << m_extrusion_axis << E_NUM(m_extruder->E())
- << " F" << float(m_extruder->retract_speed() * 60.);
+ gcode << "G1 " << m_extrusion_axis << E_NUM(m_tool->E())
+ << " F" << float(m_tool->retract_speed() * 60.);
COMMENT(comment);
gcode << "\n";
}
@@ -470,7 +502,7 @@ std::string GCodeWriter::unretract()
if (FLAVOR_IS(gcfMakerWare))
gcode << "M101 ; extruder on\n";
- double dE = m_extruder->unretract();
+ double dE = m_tool->unretract();
if (dE != 0) {
if (this->config.use_firmware_retraction) {
if (FLAVOR_IS(gcfMachinekit))
@@ -480,8 +512,8 @@ std::string GCodeWriter::unretract()
gcode << this->reset_e();
} else {
// use G1 instead of G0 because G0 will blend the restart with the previous travel move
- gcode << "G1 " << m_extrusion_axis << E_NUM(m_extruder->E())
- << " F" << float(m_extruder->deretract_speed() * 60.);
+ gcode << "G1 " << m_extrusion_axis << E_NUM(m_tool->E())
+ << " F" << float(m_tool->deretract_speed() * 60.);
if (this->config.gcode_comments) gcode << " ; unretract";
gcode << "\n";
}
@@ -497,11 +529,14 @@ std::string GCodeWriter::lift()
{
// check whether the above/below conditions are met
double target_lift = 0;
- {
- double above = this->config.retract_lift_above.get_at(m_extruder->id());
- double below = this->config.retract_lift_below.get_at(m_extruder->id());
+ if(this->tool_is_extruder()){
+ //these two should be in the Tool class methods....
+ double above = this->config.retract_lift_above.get_at(m_tool->id());
+ double below = this->config.retract_lift_below.get_at(m_tool->id());
if (m_pos.z() >= above && (below == 0 || m_pos.z() <= below))
- target_lift = this->config.retract_lift.get_at(m_extruder->id());
+ target_lift = m_tool->retract_lift();
+ } else {
+ target_lift = m_tool->retract_lift();
}
if (this->extra_lift > 0) {
diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp
index 564cf8f9a..a76aae8b6 100644
--- a/src/libslic3r/GCodeWriter.hpp
+++ b/src/libslic3r/GCodeWriter.hpp
@@ -17,27 +17,49 @@ public:
bool multiple_extruders;
GCodeWriter() :
- multiple_extruders(false), m_extrusion_axis("E"), m_extruder(nullptr),
+ multiple_extruders(false), m_extrusion_axis("E"), m_tool(nullptr),
m_single_extruder_multi_material(false),
m_last_acceleration(0), m_max_acceleration(0), m_last_fan_speed(0),
m_last_bed_temperature(0), m_last_bed_temperature_reached(true),
m_lifted(0)
{}
- Extruder* extruder() { return m_extruder; }
- const Extruder* extruder() const { return m_extruder; }
+ Tool* tool() { return m_tool; }
+ const Tool* tool() const { return m_tool; }
- std::string extrusion_axis() const { return m_extrusion_axis; }
- void apply_print_config(const PrintConfig &print_config);
+ std::string extrusion_axis() const { return m_extrusion_axis; }
+ void apply_print_config(const PrintConfig &print_config);
// Extruders are expected to be sorted in an increasing order.
- void set_extruders(std::vector<unsigned int> extruder_ids);
+ void set_extruders(std::vector<uint16_t> extruder_ids);
const std::vector<Extruder>& extruders() const { return m_extruders; }
- std::vector<unsigned int> extruder_ids() const {
- std::vector<unsigned int> out;
- out.reserve(m_extruders.size());
- for (const Extruder &e : m_extruders)
- out.push_back(e.id());
+ std::vector<uint16_t> extruder_ids() const {
+ std::vector<uint16_t> out;
+ out.reserve(m_extruders.size());
+ for (const Extruder& e : m_extruders)
+ out.push_back(e.id());
return out;
}
+ void set_mills(std::vector<uint16_t> extruder_ids);
+ const std::vector<Mill>& mills() const { return m_millers; }
+ std::vector<uint16_t> mill_ids() const {
+ std::vector<uint16_t> out;
+ out.reserve(m_millers.size());
+ for (const Tool& e : m_millers)
+ out.push_back(e.id());
+ return out;
+ }
+ //give the first mill id or an id after the last extruder. Can be used to see if an id is an extruder or a mill
+ uint16_t first_mill() const {
+ if (m_millers.empty()) {
+ uint16_t max = 0;
+ for (const Extruder& e : m_extruders)
+ max = std::max(max, e.id());
+ max++;
+ return (uint16_t)max;
+ }else return m_millers.front().id();
+ }
+ bool tool_is_extruder() const {
+ return m_tool->id() < first_mill();
+ }
std::string preamble();
std::string postamble() const;
std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const;
@@ -47,14 +69,14 @@ public:
std::string reset_e(bool force = false);
std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const;
// return false if this extruder was already selected
- bool need_toolchange(unsigned int extruder_id) const
- { return m_extruder == nullptr || m_extruder->id() != extruder_id; }
- std::string set_extruder(unsigned int extruder_id)
- { return this->need_toolchange(extruder_id) ? this->toolchange(extruder_id) : ""; }
+ bool need_toolchange(unsigned int tool_id) const
+ { return m_tool == nullptr || m_tool->id() != tool_id; }
+ std::string set_tool(unsigned int tool_id)
+ { return this->need_toolchange(tool_id) ? this->toolchange(tool_id) : ""; }
// Prefix of the toolchange G-code line, to be used by the CoolingBuffer to separate sections of the G-code
// printed with the same extruder.
std::string toolchange_prefix() const;
- std::string toolchange(unsigned int extruder_id);
+ std::string toolchange(unsigned int tool_id);
std::string set_speed(double F, const std::string &comment = std::string(), const std::string &cooling_marker = std::string()) const;
std::string travel_to_xy(const Vec2d &point, const std::string &comment = std::string());
std::string travel_to_xyz(const Vec3d &point, const std::string &comment = std::string());
@@ -73,9 +95,10 @@ public:
private:
// Extruders are sorted by their ID, so that binary search is possible.
std::vector<Extruder> m_extruders;
+ std::vector<Mill> m_millers;
std::string m_extrusion_axis;
bool m_single_extruder_multi_material;
- Extruder* m_extruder;
+ Tool* m_tool;
unsigned int m_last_acceleration;
// Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware.
// If set to zero, the limit is not in action.
diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp
index 0729f99ae..b03357d63 100644
--- a/src/libslic3r/Layer.cpp
+++ b/src/libslic3r/Layer.cpp
@@ -220,6 +220,72 @@ void Layer::make_perimeters()
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << " - Done";
}
+void Layer::make_milling_post_process() {
+ if (this->object()->print()->config().milling_diameter.empty()) return;
+
+ BOOST_LOG_TRIVIAL(trace) << "Generating milling_post_process for layer " << this->id();
+
+ // keep track of regions whose perimeters we have already generated
+ std::vector<unsigned char> done(m_regions.size(), false);
+
+ for (LayerRegionPtrs::iterator layerm = m_regions.begin(); layerm != m_regions.end(); ++layerm) {
+ if ((*layerm)->slices().empty()) {
+ (*layerm)->milling.clear();
+ } else {
+ size_t region_id = layerm - m_regions.begin();
+ if (done[region_id])
+ continue;
+ BOOST_LOG_TRIVIAL(trace) << "Generating milling_post_process for layer " << this->id() << ", region " << region_id;
+ done[region_id] = true;
+ const PrintRegionConfig& config = (*layerm)->region()->config();
+
+ // find compatible regions
+ LayerRegionPtrs layerms;
+ layerms.push_back(*layerm);
+ for (LayerRegionPtrs::const_iterator it = layerm + 1; it != m_regions.end(); ++it) {
+ LayerRegion* other_layerm = *it;
+ const PrintRegionConfig& other_config = other_layerm->region()->config();
+ if (other_layerm->slices().empty()) continue;
+ /// !!! add here the settings you want to be added in the per-object menu.
+ /// if you don't do that, objects will share the same region, and the same settings.
+ if (config.milling_post_process == other_config.milling_post_process
+ && config.milling_extra_size == other_config.milling_extra_size
+ && (config.milling_after_z == other_config.milling_after_z ||
+ this->bottom_z() > std::min(config.milling_after_z.get_abs_value(this->object()->print()->config().milling_diameter.values[0]),
+ other_config.milling_after_z.get_abs_value(this->object()->print()->config().milling_diameter.values[0])))) {
+ layerms.push_back(other_layerm);
+ done[it - m_regions.begin()] = true;
+ }
+ }
+
+ if (layerms.size() == 1) { // optimization
+ (*layerm)->make_milling_post_process((*layerm)->slices());
+ } else {
+ SurfaceCollection new_slices;
+ // Use a region if you ned a specific settgin, be sure to choose the good one, curtly there is o need.
+ LayerRegion* layerm_config = layerms.front();
+ {
+ // group slices (surfaces) according to number of extra perimeters
+ std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
+ for (LayerRegion* layerm : layerms) {
+ for (const Surface& surface : layerm->slices().surfaces)
+ slices[surface.extra_perimeters].emplace_back(surface);
+ layerm->milling.clear();
+ }
+ // merge the surfaces assigned to each group
+ for (std::pair<const unsigned short, Surfaces>& surfaces_with_extra_perimeters : slices)
+ new_slices.append(union_ex(surfaces_with_extra_perimeters.second, true), surfaces_with_extra_perimeters.second.front());
+ }
+
+ // make perimeters
+ layerm_config->make_milling_post_process(new_slices);
+
+ }
+ }
+ }
+ BOOST_LOG_TRIVIAL(trace) << "Generating milling_post_process for layer " << this->id() << " - Done";
+}
+
void Layer::make_fills()
{
#ifdef SLIC3R_DEBUG
diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp
index 15ae44d7b..d567518a3 100644
--- a/src/libslic3r/Layer.hpp
+++ b/src/libslic3r/Layer.hpp
@@ -55,6 +55,9 @@ public:
// (this collection contains only ExtrusionEntityCollection objects)
ExtrusionEntityCollection perimeters;
+ // collection of expolygons representing the milling path of the first milling cutter
+ ExtrusionEntityCollection milling;
+
// ordered collection of extrusion paths to fill surfaces
// (this collection contains only ExtrusionEntityCollection objects)
ExtrusionEntityCollection fills;
@@ -62,7 +65,8 @@ public:
Flow flow(FlowRole role, bool bridge = false, double width = -1) const;
void slices_to_fill_surfaces_clipped();
void prepare_fill_surfaces();
- void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces);
+ void make_perimeters(const SurfaceCollection& slices, SurfaceCollection* fill_surfaces);
+ void make_milling_post_process(const SurfaceCollection& slices);
void process_external_surfaces(const Layer *lower_layer, const Polygons *lower_layer_covered);
double infill_area_threshold() const;
// Trim surfaces by trimming polygons. Used by the elephant foot compensation at the 1st layer.
@@ -142,6 +146,7 @@ public:
return false;
}
void make_perimeters();
+ void make_milling_post_process();
void make_fills();
void export_region_slices_to_svg(const char *path) const;
diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp
index d72c0dabb..548e0aa7d 100644
--- a/src/libslic3r/LayerRegion.cpp
+++ b/src/libslic3r/LayerRegion.cpp
@@ -2,6 +2,7 @@
#include "BridgeDetector.hpp"
#include "ClipperUtils.hpp"
#include "Geometry.hpp"
+#include "Milling/MillingPostProcess.hpp"
#include "PerimeterGenerator.hpp"
#include "Print.hpp"
#include "Surface.hpp"
@@ -61,7 +62,6 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
PerimeterGenerator g(
// input:
&slices,
- this->layer()->height,
this->flow(frPerimeter),
&this->region()->config(),
&this->layer()->object()->config(),
@@ -79,7 +79,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
if (this->layer()->upper_layer != NULL)
g.upper_slices = &this->layer()->upper_layer->lslices;
- g.layer_id = (int)this->layer()->id();
+ g.layer = this->layer();
g.ext_perimeter_flow = this->flow(frExternalPerimeter);
g.overhang_flow = this->region()->flow(frPerimeter, -1, true, false, -1, *this->layer()->object());
g.solid_infill_flow = this->flow(frSolidInfill);
@@ -89,6 +89,17 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
this->fill_no_overlap_expolygons = g.fill_no_overlap;
}
+void LayerRegion::make_milling_post_process(const SurfaceCollection& slices) {
+ MillingPostProcess mill(// input:
+ &slices,
+ (this->layer()->lower_layer != nullptr) ? &this->layer()->lower_layer->lslices : nullptr,
+ &this->region()->config(),
+ &this->layer()->object()->config(),
+ &this->layer()->object()->print()->config()
+ );
+ milling = mill.process(this->layer());
+}
+
//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3.
//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 1.5
#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtSquare, 0.
diff --git a/src/libslic3r/Milling/MillingPostProcess.cpp b/src/libslic3r/Milling/MillingPostProcess.cpp
new file mode 100644
index 000000000..0b45bb239
--- /dev/null
+++ b/src/libslic3r/Milling/MillingPostProcess.cpp
@@ -0,0 +1,169 @@
+#include "MillingPostProcess.hpp"
+#include "../Layer.hpp"
+
+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));
+
+ //get the longest polyline
+ Polyline best_polyline;
+ for (Polyline& polyline : entrypoints)
+ if (polyline.size() > best_polyline.size())
+ best_polyline = polyline;
+
+ if (!entrypoints.empty() && best_polyline.size() > 3 ) {
+
+
+ //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;
+ 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]);
+ first_point_idx = idx;
+ }
+ }
+ if (first_point_idx > -1) {
+ //now search the second one
+ int32_t second_point_idx = -1;
+ for (int32_t idx = first_point_idx +1; idx < poly.points.size(); idx++) {
+ if (poly.points[idx].distance_to_square(poly.points[first_point_idx]) > dist_max_square) {
+ second_point_idx = idx;
+ break;
+ }
+ }
+ if(second_point_idx == -1)
+ for (int32_t idx = 0; idx < first_point_idx; idx++) {
+ if (poly.points[idx].distance_to_square(poly.points[first_point_idx]) > dist_max_square) {
+ second_point_idx = idx;
+ break;
+ }
+ }
+
+ int32_t second_point_extract_idx = first_point_extract_idx;
+ if (second_point_idx == -1) {
+ second_point_idx = first_point_idx;
+ } else {
+ //now see if an other extract point is nearer
+ best_dist = poly.points[second_point_idx].distance_to_square(best_polyline.points[second_point_extract_idx]);
+ for (int32_t idx = 0; idx < best_polyline.points.size(); idx++) {
+ if (poly.points[second_point_idx].distance_to_square(best_polyline.points[idx]) < best_dist) {
+ best_dist = poly.points[second_point_idx].distance_to_square(best_polyline.points[idx]);
+ second_point_extract_idx = idx;
+ }
+ }
+ }
+
+ ExtrusionPath contour(erMilling);
+ contour.mm3_per_mm = 0;
+ contour.width = (float)this->print_config->milling_diameter.get_at(0);
+ contour.height = (float)layer->height;
+ contour.polyline.points.push_back(best_polyline.points[first_point_extract_idx]);
+ for (int32_t idx = first_point_idx; idx < poly.points.size(); idx++) {
+ contour.polyline.points.push_back(poly.points[idx]);
+ }
+ if (second_point_idx <= first_point_idx) {
+ for (int32_t idx = 0; idx < poly.points.size(); idx++) {
+ contour.polyline.points.push_back(poly.points[idx]);
+ }
+ }
+ for (int32_t idx = 0; idx < second_point_idx + 1; idx++) {
+ contour.polyline.points.push_back(poly.points[idx]);
+ }
+ contour.polyline.points.push_back(best_polyline.points[second_point_extract_idx]);
+
+ out_coll.append(std::move(contour));
+ return;
+
+
+ }
+ }
+ //default path, without safe-guard up-down.
+ ExtrusionPath contour(erMilling);
+ contour.polyline = poly.split_at_first_point();
+ 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.height = (float)layer->height;
+ out_coll.append(std::move(contour));
+ return;
+
+ }
+
+ ExtrusionEntityCollection MillingPostProcess::process(const Layer* layer)
+ {
+ if (!can_be_milled(layer)) return ExtrusionEntityCollection();
+
+ const double milling_diameter = scale_(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);
+ for (const ExPolygon& expoly : surf_milling)
+ expoly.simplify(SCALED_RESOLUTION, &milling_lines);
+ }
+ milling_lines = union_ex(milling_lines);
+
+ ExPolygons secured_points = offset_ex(milling_lines, milling_diameter / 3);
+ ExPolygons entrypoints;
+ for (const ExPolygon& expoly : secured_points)
+ expoly.simplify(SCALED_RESOLUTION, &entrypoints);
+ entrypoints = union_ex(entrypoints);
+ Polygons entrypoints_poly;
+ for (const ExPolygon& expoly : secured_points)
+ entrypoints_poly.emplace_back(expoly);
+
+ ExtrusionEntityCollection all_milling;
+ for (ExPolygon &ex_poly : milling_lines) {
+ getExtrusionLoop(layer, ex_poly.contour, intersection_pl(offset(ex_poly.contour, milling_diameter / 4), entrypoints_poly), all_milling);
+ for (Polygon& hole : ex_poly.holes) {
+ getExtrusionLoop(layer, hole, intersection_pl(offset(hole, milling_diameter / 3), entrypoints_poly), all_milling);
+ }
+ }
+
+ return all_milling;
+ }
+
+ bool MillingPostProcess::can_be_milled(const Layer* layer) {
+ 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()));
+ }
+
+ ExPolygons MillingPostProcess::get_unmillable_areas(const Layer* layer)
+ {
+ if (!can_be_milled(layer)) return ExPolygons();
+
+ const coord_t milling_radius = scale_(this->print_config->milling_diameter.get_at(0)) / 2;
+
+ ExPolygons milling_lines;
+ ExPolygons surfaces;
+ for (const Surface& surf : slices->surfaces) {
+ ExPolygons surf_milling = offset_ex(surf.expolygon, milling_radius, ClipperLib::jtRound);
+ for (const ExPolygon& expoly : surf_milling)
+ expoly.simplify(SCALED_RESOLUTION, &milling_lines);
+ surfaces.push_back(surf.expolygon);
+ }
+ union_ex(milling_lines, true);
+ union_ex(surfaces, true);
+
+
+ ExPolygons exact_unmillable_area = diff_ex(offset_ex(milling_lines, -milling_radius, ClipperLib::jtRound), surfaces, true);
+ if (exact_unmillable_area.empty())
+ return exact_unmillable_area;
+
+ //increae a bit the computed unmillable_area to be sure the mill will mill all the plastic
+ coord_t safety_offset = milling_radius / 2;
+ ExPolygons safe_umillable = diff_ex(offset_ex(exact_unmillable_area, safety_offset), surfaces, true);
+ ExPolygons safe_umillable_simplified;
+ for (const ExPolygon& expoly : safe_umillable)
+ expoly.simplify(SCALED_RESOLUTION, &safe_umillable_simplified);
+ return union_ex(safe_umillable_simplified, true);
+ }
+
+}
diff --git a/src/libslic3r/Milling/MillingPostProcess.hpp b/src/libslic3r/Milling/MillingPostProcess.hpp
new file mode 100644
index 000000000..5fd168775
--- /dev/null
+++ b/src/libslic3r/Milling/MillingPostProcess.hpp
@@ -0,0 +1,49 @@
+#ifndef slic3r_MillingPostProcess_hpp_
+#define slic3r_MillingPostProcess_hpp_
+
+#include "../libslic3r.h"
+#include <vector>
+#include "../ExPolygonCollection.hpp"
+#include "../Polygon.hpp"
+#include "../Layer.hpp"
+#include "../PrintConfig.hpp"
+#include "../SurfaceCollection.hpp"
+
+namespace Slic3r {
+
+
+class MillingPostProcess {
+public:
+ // Inputs:
+ const SurfaceCollection *slices;
+ const ExPolygons *lower_slices;
+ const PrintRegionConfig *config;
+ const PrintObjectConfig *object_config;
+ const PrintConfig *print_config;
+
+ MillingPostProcess(
+ // Input:
+ const SurfaceCollection* slices,
+ const ExPolygons* lower_slices,
+ const PrintRegionConfig* config,
+ const PrintObjectConfig* object_config,
+ const PrintConfig* print_config)
+ : slices(slices), lower_slices(lower_slices),
+ config(config), object_config(object_config), print_config(print_config)
+ {};
+
+ /// get mill path
+ ExtrusionEntityCollection process(const Layer *layer);
+ /// get the areas that shouldn't be grown because the mill can't go here.
+ ExPolygons get_unmillable_areas(const Layer* layer);
+ bool can_be_milled(const Layer* layer);
+
+private:
+ Polygons _lower_slices_p;
+
+ void getExtrusionLoop(const Layer* layer, Polygon& poly, Polylines& entrypoints, ExtrusionEntityCollection&out_coll);
+};
+
+}
+
+#endif
diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp
index ecdd90e38..2b8287e76 100644
--- a/src/libslic3r/PerimeterGenerator.cpp
+++ b/src/libslic3r/PerimeterGenerator.cpp
@@ -12,6 +12,7 @@
#include "BoundingBox.hpp"
#include "ExPolygon.hpp"
#include "Geometry.hpp"
+#include "Milling/MillingPostProcess.hpp"
#include "Polygon.hpp"
#include "Line.hpp"
#include "ClipperUtils.hpp"
@@ -86,6 +87,19 @@ void PerimeterGenerator::process()
// in the current layer
this->_lower_slices_p = offset(*this->lower_slices, double(scale_(config->overhangs_width.get_abs_value(nozzle_diameter))));
}
+
+ // have to grown the periemters if mill post-process
+ MillingPostProcess miller(this->slices, this->lower_slices, config, object_config, print_config);
+ bool have_to_grow_for_miller = miller.can_be_milled(layer) && config->milling_extra_size.get_abs_value(1) > 0;
+ ExPolygons unmillable;
+ coord_t mill_extra_size = 0;
+ if (have_to_grow_for_miller) {
+ unmillable = miller.get_unmillable_areas(layer);
+ double spacing_vs_width = ext_perimeter_flow.width - ext_perimeter_flow.spacing();
+ mill_extra_size = scale_(config->milling_extra_size.get_abs_value(spacing_vs_width));
+ have_to_grow_for_miller = mill_extra_size > SCALED_EPSILON;
+ }
+
// we need to process each island separately because we might have different
// extra perimeters for each one
@@ -287,7 +301,7 @@ void PerimeterGenerator::process()
}
surface_idx = 0;
- const int extra_odd_perimeter = (config->extra_perimeters_odd_layers && layer_id % 2 == 1 ? 1:0);
+ const int extra_odd_perimeter = (config->extra_perimeters_odd_layers && layer->id() % 2 == 1 ? 1:0);
for (const Surface &surface : all_surfaces) {
// detect how many perimeters must be generated for this island
int loop_number = this->config->perimeters + surface.extra_perimeters - 1 + extra_odd_perimeter; // 0-indexed loops
@@ -303,9 +317,21 @@ void PerimeterGenerator::process()
ExPolygons last = union_ex(surface.expolygon.simplify_p(SCALED_RESOLUTION));
if (loop_number >= 0) {
+ //increase surface for milling_post-process
+ if (have_to_grow_for_miller) {
+ if (unmillable.empty())
+ last = offset_ex(last, mill_extra_size);
+ else {
+ ExPolygons growth = diff_ex(offset_ex(last, mill_extra_size), unmillable, true);
+ last.insert(last.end(), growth.begin(), growth.end());
+ last = union_ex(last);
+ }
+ }
+
+
// Add perimeters on overhangs : initialization
ExPolygons overhangs_unsupported;
- if ( (this->config->extra_perimeters_overhangs || (this->config->overhangs_reverse && this->layer_id % 2 == 1))
+ if ( (this->config->extra_perimeters_overhangs || (this->config->overhangs_reverse && this->layer->id() % 2 == 1))
&& !last.empty() && this->lower_slices != NULL && !this->lower_slices->empty()) {
//remove holes from lower layer, we only ant that for overhangs, not bridges!
ExPolygons lower_without_holes;
@@ -341,11 +367,11 @@ void PerimeterGenerator::process()
}
}
bool has_steep_overhang = false;
- if (this->layer_id % 2 == 1 && this->config->overhangs_reverse //check if my option is set and good layer
+ if (this->layer->id() % 2 == 1 && this->config->overhangs_reverse //check if my option is set and good layer
&& !last.empty() && !overhangs_unsupported.empty() //has something to work with
) {
coord_t offset = scale_(config->overhangs_reverse_threshold.get_abs_value(this->perimeter_flow.width));
- //version with °: scale_(std::tan(PI * (0.5f / 90) * config->overhangs_reverse_threshold.value ) * this->layer_height)
+ //version with °: scale_(std::tan(PI * (0.5f / 90) * config->overhangs_reverse_threshold.value ) * this->layer->height)
if (offset_ex(overhangs_unsupported, -offset / 2).size() > 0) {
//allow this loop to be printed in reverse
@@ -444,7 +470,7 @@ void PerimeterGenerator::process()
bound.remove_point_too_near((coord_t)SCALED_RESOLUTION);
// the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop (*1.2 because of circles approx. and enlrgment from 'div')
Slic3r::MedialAxis ma{ thin[0], (coord_t)((ext_perimeter_width + ext_perimeter_spacing)*1.2),
- min_width, coord_t(this->layer_height) };
+ min_width, coord_t(this->layer->height) };
ma.use_bounds(bound)
.use_min_real_width((coord_t)scale_(this->ext_perimeter_flow.nozzle_diameter))
.use_tapers(overlap)
@@ -554,7 +580,12 @@ void PerimeterGenerator::process()
offset_top_surface -= 0.9 * (config->perimeters <= 1 ? 0. : (perimeter_spacing * (config->perimeters - 1)));
else offset_top_surface = 0;
// get the real top surface
- ExPolygons top_polygons = diff_ex(last, *this->upper_slices, true);
+ ExPolygons top_polygons = (!have_to_grow_for_miller) ? diff_ex(last, *this->upper_slices, true)
+ :(unmillable.empty())?
+ diff_ex(last, offset_ex(*this->upper_slices, mill_extra_size), true)
+ :
+ diff_ex(last, diff_ex(offset_ex(*this->upper_slices, mill_extra_size), unmillable, true));
+
//get the not-top surface, from the "real top" but enlarged by external_infill_margin
ExPolygons inner_polygons = diff_ex(last, offset_ex(top_polygons, offset_top_surface), true);
// get the enlarged top surface, by using inner_polygons instead of upper_slices
@@ -651,7 +682,7 @@ void PerimeterGenerator::process()
// we continue inwards after having finished the brim
// TODO: add test for perimeter order
if (this->config->external_perimeters_first ||
- (this->layer_id == 0 && this->object_config->brim_width.value > 0)) {
+ (this->layer->id() == 0 && this->object_config->brim_width.value > 0)) {
if (this->config->external_perimeters_nothole.value) {
if (this->config->external_perimeters_hole.value) {
entities.reverse();
@@ -699,7 +730,7 @@ void PerimeterGenerator::process()
// collapse
double min = 0.2 * perimeter_width * (1 - INSET_OVERLAP_TOLERANCE);
//be sure we don't gapfill where the perimeters are already touching each other (negative spacing).
- min = std::max(min, double(Flow::new_from_spacing(EPSILON, nozzle_diameter, this->layer_height, false).scaled_width()));
+ min = std::max(min, double(Flow::new_from_spacing(EPSILON, nozzle_diameter, this->layer->height, false).scaled_width()));
double max = 2.2 * perimeter_spacing;
//remove areas that are too big (shouldn't occur...)
ExPolygons gaps_ex_to_test = diff_ex(
@@ -762,7 +793,7 @@ void PerimeterGenerator::process()
// create lines from the area
ThickPolylines polylines;
for (const ExPolygon &ex : gaps_ex) {
- MedialAxis{ ex, coord_t(max*1.1), coord_t(min), coord_t(this->layer_height) }.build(polylines);
+ MedialAxis{ ex, coord_t(max*1.1), coord_t(min), coord_t(this->layer->height) }.build(polylines);
}
// create extrusion from lines
if (!polylines.empty()) {
@@ -852,7 +883,7 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
// detect overhanging/bridging perimeters
ExtrusionPaths paths;
- if (this->config->overhangs && this->layer_id > 0
+ if (this->config->overhangs && this->layer->id() > 0
&& !(this->object_config->support_material && this->object_config->support_material_contact_distance_type.value == zdNone)) {
// get non-overhang paths by intersecting this loop with the grown lower slices
extrusion_paths_append(
@@ -861,7 +892,7 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
role,
is_external ? this->_ext_mm3_per_mm : this->_mm3_per_mm,
is_external ? this->ext_perimeter_flow.width : this->perimeter_flow.width,
- (float) this->layer_height);
+ (float) this->layer->height);
// get overhang paths by checking what parts of this loop fall
// outside the grown lower slices (thus where the distance between
@@ -882,7 +913,7 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
path.polyline = loop.polygon.split_at_first_point();
path.mm3_per_mm = is_external ? this->_ext_mm3_per_mm : this->_mm3_per_mm;
path.width = is_external ? this->ext_perimeter_flow.width : this->perimeter_flow.width;
- path.height = (float) this->layer_height;
+ path.height = (float) this->layer->height;
paths.push_back(path);
}
@@ -923,8 +954,8 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
ExtrusionLoop *eloop = static_cast<ExtrusionLoop*>(coll.entities[idx.first]);
coll.entities[idx.first] = nullptr;
if (loop.is_contour) {
- //note: this->layer_id % 2 == 1 already taken into account in the is_steep_overhang compute (to save time).
- if (loop.is_steep_overhang && this->layer_id % 2 == 1)
+ //note: this->layer->id() % 2 == 1 already taken into account in the is_steep_overhang compute (to save time).
+ if (loop.is_steep_overhang && this->layer->id() % 2 == 1)
eloop->make_clockwise();
else
eloop->make_counter_clockwise();
@@ -1071,7 +1102,7 @@ PerimeterGenerator::_extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, co
loop.is_external() ? erExternalPerimeter : erPerimeter,
(double)(loop.is_external() ? this->_ext_mm3_per_mm : this->_mm3_per_mm),
(float)(loop.is_external() ? this->ext_perimeter_flow.width : this->perimeter_flow.width),
- (float)(this->layer_height));
+ (float)(this->layer->height));
single_point.paths.back().polyline = poly_point;
return single_point;
}
@@ -1119,7 +1150,7 @@ PerimeterGenerator::_extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, co
}
// detect overhanging/bridging perimeters
- if (this->config->overhangs && this->layer_id > 0
+ if (this->config->overhangs && this->layer->id() > 0
&& !(this->object_config->support_material && this->object_config->support_material_contact_distance_type.value == zdNone)) {
ExtrusionPaths paths;
// get non-overhang paths by intersecting this loop with the grown lower slices
@@ -1129,7 +1160,7 @@ PerimeterGenerator::_extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, co
role,
is_external ? this->_ext_mm3_per_mm : this->_mm3_per_mm,
is_external ? this->ext_perimeter_flow.width : this->perimeter_flow.width,
- (float) this->layer_height);
+ (float) this->layer->height);
// get overhang paths by checking what parts of this loop fall
// outside the grown lower slices (thus where the distance between
@@ -1203,7 +1234,7 @@ PerimeterGenerator::_extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, co
if (need_to_reverse) path.polyline.reverse();
path.mm3_per_mm = is_external ? this->_ext_mm3_per_mm : this->_mm3_per_mm;
path.width = is_external ? this->ext_perimeter_flow.width : this->perimeter_flow.width;
- path.height = (float)(this->layer_height);
+ path.height = (float)(this->layer->height);
my_loop.paths.emplace_back(path);
}
diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp
index 070b03e50..8d66520b8 100644
--- a/src/libslic3r/PerimeterGenerator.hpp
+++ b/src/libslic3r/PerimeterGenerator.hpp
@@ -5,6 +5,7 @@
#include <vector>
#include "ExPolygonCollection.hpp"
#include "Flow.hpp"
+#include "Layer.hpp"
#include "Polygon.hpp"
#include "PrintConfig.hpp"
#include "SurfaceCollection.hpp"
@@ -54,8 +55,7 @@ public:
const SurfaceCollection *slices;
const ExPolygons *upper_slices;
const ExPolygons *lower_slices;
- double layer_height;
- int layer_id;
+ Layer *layer;
Flow perimeter_flow;
Flow ext_perimeter_flow;
Flow overhang_flow;
@@ -71,8 +71,7 @@ public:
PerimeterGenerator(
// Input:
- const SurfaceCollection* slices,
- double layer_height,
+ const SurfaceCollection* slices,
Flow flow,
const PrintRegionConfig* config,
const PrintObjectConfig* object_config,
@@ -84,8 +83,8 @@ public:
ExtrusionEntityCollection* gap_fill,
// Infills without the gap fills
SurfaceCollection* fill_surfaces)
- : slices(slices), lower_slices(nullptr), upper_slices(nullptr), layer_height(layer_height),
- layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow),
+ : slices(slices), lower_slices(nullptr), upper_slices(nullptr),
+ perimeter_flow(flow), ext_perimeter_flow(flow),
overhang_flow(flow), solid_infill_flow(flow),
config(config), object_config(object_config), print_config(print_config),
loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces),
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index 0da8e6fdb..4d386bd4c 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -117,6 +117,11 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
"min_print_speed",
"max_print_speed",
"max_volumetric_speed",
+ "milling_toolchange_end_gcode",
+ "milling_toolchange_start_gcode",
+ "milling_offset",
+ "milling_z_offset",
+ "milling_z_lift",
#ifdef HAS_PRESSURE_EQUALIZER
"max_volumetric_extrusion_rate_slope_positive",
"max_volumetric_extrusion_rate_slope_negative",
@@ -312,9 +317,9 @@ bool Print::is_step_done(PrintObjectStep step) const
}
// returns 0-based indices of used extruders
-std::vector<unsigned int> Print::object_extruders(const PrintObjectPtrs &objects) const
+std::vector<uint16_t> Print::object_extruders(const PrintObjectPtrs &objects) const
{
- std::vector<unsigned int> extruders;
+ std::vector<uint16_t> extruders;
extruders.reserve(m_regions.size() * 3);
std::vector<unsigned char> region_used(m_regions.size(), false);
for (const PrintObject *object : objects)
@@ -329,11 +334,11 @@ std::vector<unsigned int> Print::object_extruders(const PrintObjectPtrs &objects
}
// returns 0-based indices of used extruders
-std::vector<unsigned int> Print::support_material_extruders() const
+std::vector<uint16_t> Print::support_material_extruders() const
{
- std::vector<unsigned int> extruders;
+ std::vector<uint16_t> extruders;
bool support_uses_current_extruder = false;
- auto num_extruders = (unsigned int)m_config.nozzle_diameter.size();
+ auto num_extruders = (uint16_t)m_config.nozzle_diameter.size();
for (PrintObject *object : m_objects) {
if (object->has_support_material()) {
@@ -341,14 +346,14 @@ std::vector<unsigned int> Print::support_material_extruders() const
if (object->config().support_material_extruder == 0)
support_uses_current_extruder = true;
else {
- unsigned int i = (unsigned int)object->config().support_material_extruder - 1;
+ uint16_t i = (uint16_t)object->config().support_material_extruder - 1;
extruders.emplace_back((i >= num_extruders) ? 0 : i);
}
assert(object->config().support_material_interface_extruder >= 0);
if (object->config().support_material_interface_extruder == 0)
support_uses_current_extruder = true;
else {
- unsigned int i = (unsigned int)object->config().support_material_interface_extruder - 1;
+ uint16_t i = (uint16_t)object->config().support_material_interface_extruder - 1;
extruders.emplace_back((i >= num_extruders) ? 0 : i);
}
}
@@ -363,19 +368,19 @@ std::vector<unsigned int> Print::support_material_extruders() const
}
// returns 0-based indices of used extruders
-std::vector<unsigned int> Print::extruders() const
+std::vector<uint16_t> Print::extruders() const
{
- std::vector<unsigned int> extruders = this->object_extruders(m_objects);
+ std::vector<uint16_t> extruders = this->object_extruders(m_objects);
append(extruders, this->support_material_extruders());
sort_remove_duplicates(extruders);
return extruders;
}
-unsigned int Print::num_object_instances() const
+uint16_t Print::num_object_instances() const
{
- size_t instances = 0;
+ uint16_t instances = 0;
for (const PrintObject *print_object : m_objects)
- instances += (unsigned int)print_object->instances().size();
+ instances += (uint16_t)print_object->instances().size();
return instances;
}
@@ -1403,12 +1408,12 @@ std::string Print::validate() const
}
{
- std::vector<unsigned int> extruders = this->extruders();
+ std::vector<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();
double max_nozzle_diameter = 0;
- for (unsigned int extruder_id : extruders) {
+ for (uint16_t extruder_id : extruders) {
double dmr = m_config.nozzle_diameter.get_at(extruder_id);
min_nozzle_diameter = std::min(min_nozzle_diameter, dmr);
max_nozzle_diameter = std::max(max_nozzle_diameter, dmr);
@@ -1724,7 +1729,7 @@ void Print::process()
if (config().complete_objects) {
for (PrintObject *obj : obj_group) {
//get flow
- std::vector<unsigned int> set_extruders = this->object_extruders({ obj });
+ std::vector<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());
@@ -1749,7 +1754,7 @@ 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<unsigned int> set_extruders = this->object_extruders(m_objects);
+ std::vector<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());
@@ -1885,7 +1890,7 @@ void Print::_make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollectio
std::vector<size_t> extruders;
std::vector<double> extruders_e_per_mm;
{
- std::vector<unsigned int> set_extruders = this->object_extruders(objects);
+ std::vector<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());
diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp
index fdef40759..dda947714 100644
--- a/src/libslic3r/Print.hpp
+++ b/src/libslic3r/Print.hpp
@@ -57,7 +57,7 @@ public:
const Print* print() const { return m_print; }
const PrintRegionConfig& config() const { return m_config; }
// 1-based extruder identifier for this region and role.
- unsigned int extruder(FlowRole role) const;
+ uint16_t extruder(FlowRole role) const;
Flow flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const;
// Average diameter of nozzles participating on extruding this region.
coordf_t nozzle_dmr_avg(const PrintConfig &print_config) const;
@@ -65,8 +65,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<unsigned int> &object_extruders) const;
- static void collect_object_printing_extruders(const PrintConfig &print_config, const PrintObjectConfig &object_config, const PrintRegionConfig &region_config, std::vector<unsigned int> &object_extruders);
+ 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);
// Methods modifying the PrintRegion's state:
public:
@@ -184,7 +184,7 @@ 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<unsigned int> object_extruders() const;
+ std::vector<uint16_t> object_extruders() const;
// Called when slicing to SVG (see Print.pm sub export_svg), and used by perimeters.t
void slice();
@@ -404,9 +404,9 @@ public:
Flow brim_flow(size_t extruder_id) const;
Flow skirt_flow(size_t extruder_id) const;
- std::vector<unsigned int> object_extruders(const PrintObjectPtrs &objects) const;
- std::vector<unsigned int> support_material_extruders() const;
- std::vector<unsigned int> extruders() 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;
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!
@@ -422,7 +422,7 @@ public:
const PrintRegionPtrs& regions() const { return m_regions; }
// How many of PrintObject::copies() over all print objects are there?
// If zero, then the print is empty and the print shall not be executed.
- unsigned int num_object_instances() const;
+ uint16_t num_object_instances() const;
const ExtrusionEntityCollection& skirt() const { return m_skirt; }
const ExtrusionEntityCollection& brim() const { return m_brim; }
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index 9823006ad..a48c140d1 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -34,6 +34,8 @@ PrintConfigDef::PrintConfigDef()
assign_printer_technology_to_unknown(this->options, ptFFF);
this->init_sla_params();
assign_printer_technology_to_unknown(this->options, ptSLA);
+ this->init_milling_params();
+ assign_printer_technology_to_unknown(this->options, ptMill);
}
void PrintConfigDef::init_common_params()
@@ -1955,31 +1957,6 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionFloat(0));
#endif /* HAS_PRESSURE_EQUALIZER */
- def = this->add("milling_cutter", coInt);
- def->gui_type = "i_enum_open";
- def->label = L("Milling cutter");
- def->category = OptionCategory::extruders;
- def->tooltip = L("The milling cutter to use (unless more specific extruder settings are specified). ");
- def->min = 0; // 0 = inherit defaults
- def->enum_labels.push_back("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("milling_diameter", coFloats);
- def->label = L("Milling diameter");
- def->category = OptionCategory::extruders;
- def->tooltip = L("This is the diameter of your cutting tool.");
- def->sidetext = L("mm");
- def->mode = comAdvanced;
- def->set_default_value(new ConfigOptionFloats(2.14));
-
def = this->add("min_fan_speed", coInts);
def->label = L("Min");
def->full_label = ("Min fan speed");
@@ -3497,9 +3474,129 @@ void PrintConfigDef::init_extruder_option_keys()
"wipe_extra_perimeter"
};
assert(std::is_sorted(m_extruder_retract_keys.begin(), m_extruder_retract_keys.end()));
+}
+
+void PrintConfigDef::init_milling_params()
+{
m_milling_option_keys = {
"milling_diameter",
+ "milling_toolchange_end_gcode",
+ "milling_toolchange_start_gcode",
+ //"milling_offset",
+ //"milling_z_offset",
+ "milling_z_lift",
+
};
+
+ ConfigOptionDef* def;
+
+ // Milling Printer settings
+
+ def = this->add("milling_cutter", coInt);
+ def->gui_type = "i_enum_open";
+ def->label = L("Milling cutter");
+ def->category = OptionCategory::general;
+ def->tooltip = L("The milling cutter to use (unless more specific extruder settings are specified). ");
+ def->min = 0; // 0 = inherit defaults
+ def->enum_labels.push_back("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("milling_diameter", coFloats);
+ def->label = L("Milling diameter");
+ def->category = OptionCategory::milling_extruders;
+ def->tooltip = L("This is the diameter of your cutting tool.");
+ def->sidetext = L("mm");
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionFloats(3.14));
+
+ def = this->add("milling_offset", coPoints);
+ def->label = L("Tool offset");
+ def->category = OptionCategory::extruders;
+ def->tooltip = L("If your firmware doesn't handle the extruder displacement you need the G-code "
+ "to take it into account. This option lets you specify the displacement of each extruder "
+ "with respect to the first one. It expects positive coordinates (they will be subtracted "
+ "from the XY coordinate).");
+ def->sidetext = L("mm");
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionPoints( Vec2d(0,0) ));
+
+ def = this->add("milling_z_offset", coFloats);
+ def->label = L("Tool z offset");
+ def->category = OptionCategory::extruders;
+ def->tooltip = L(".");
+ def->sidetext = L("mm");
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionFloats(0));
+
+ def = this->add("milling_z_lift", coFloats);
+ def->label = L("Tool z lift");
+ def->category = OptionCategory::extruders;
+ def->tooltip = L("Amount of lift for travel.");
+ def->sidetext = L("mm");
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionFloats(2));
+
+ def = this->add("milling_toolchange_start_gcode", coStrings);
+ def->label = L("G-Code to switch to this toolhead");
+ def->category = OptionCategory::milling_extruders;
+ def->tooltip = L("Put here the gcode to change the toolhead (called after the g-code T[next_extruder]). You have access to [next_extruder] and [previous_extruder]."
+ " next_extruder is the 'extruder number' of the new milling tool, it's equal to the index (begining at 0) of the milling tool plus the number of extruders."
+ " 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 numbe rof extruder is available at [extruder]and the number of milling tool is available at [milling_cutter].");
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionStrings(""));
+
+ def = this->add("milling_toolchange_end_gcode", coStrings);
+ def->label = L("G-Code to switch from this toolhead");
+ def->category = OptionCategory::milling_extruders;
+ def->tooltip = L("Put here the gcode to end the toolhead action, like stopping the spindle. You have access to [next_extruder] and [previous_extruder]."
+ " previous_extruder is the 'extruder number' of the current milling tool, it's equal to the index (begining at 0) of the milling tool plus the number of extruders."
+ " 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 numbe rof extruder is available at [extruder]and the number of milling tool is available at [milling_cutter].");
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionStrings(""));
+
+ def = this->add("milling_post_process", coBool);
+ def->label = L("Milling post-processing");
+ def->category = OptionCategory::milling;
+ def->tooltip = L("If activated, at the end of each layer, the printer will switch to a milling ead and mill the external periemters."
+ "\nYou should set the 'Milling extra XY size' to a value high enough to have enough plastic to mill. Also, be sure that your piece is firmly glued to the bed.");
+ def->mode = comSimple;
+ def->set_default_value(new ConfigOptionBool(false));
+
+ def = this->add("milling_extra_size", coFloatOrPercent);
+ def->label = L("Milling extra XY size");
+ def->category = OptionCategory::milling;
+ def->tooltip = L("This increase the size of the object by a certain amount to have enough plastic to mill."
+ " You can set a number of mm or a percentage of the calculated optimal extra width (from flow calculation).");
+ def->sidetext = L("mm or %");
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionFloatOrPercent(150, true));
+
+ def = this->add("milling_after_z", coFloatOrPercent);
+ def->label = L("Milling only after");
+ def->category = OptionCategory::milling;
+ def->tooltip = L("THis setting restrict the post-process milling to a certain height, to avoid milling the bed. It can be a mm of a % of the first layer height (so it can depends of the object).");
+ def->sidetext = L("mm or %");
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionFloatOrPercent(200, true));
+
+ def = this->add("milling_speed", coFloat);
+ def->label = L("Milling Speed");
+ def->category = OptionCategory::milling;
+ def->tooltip = L("Speed for milling tool.");
+ def->sidetext = L("mm/s");
+ def->min = 0;
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionFloat(30));
}
void PrintConfigDef::init_sla_params()
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index b12545090..efc3bc653 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -282,6 +282,7 @@ private:
void init_fff_params();
void init_extruder_option_keys();
void init_sla_params();
+ void init_milling_params();
std::vector<std::string> m_extruder_option_keys;
std::vector<std::string> m_extruder_retract_keys;
@@ -642,6 +643,10 @@ public:
ConfigOptionBool infill_dense;
ConfigOptionEnum<DenseInfillAlgo> infill_dense_algo;
ConfigOptionBool infill_first;
+ ConfigOptionFloatOrPercent milling_after_z;
+ ConfigOptionFloatOrPercent milling_extra_size;
+ ConfigOptionBool milling_post_process;
+ ConfigOptionFloat milling_speed;
// Detect bridging perimeters
ConfigOptionBool overhangs;
ConfigOptionFloatOrPercent overhangs_width;
@@ -725,6 +730,10 @@ protected:
OPT_PTR(infill_not_connected);
OPT_PTR(infill_dense_algo);
OPT_PTR(infill_first);
+ OPT_PTR(milling_after_z);
+ OPT_PTR(milling_extra_size);
+ OPT_PTR(milling_post_process);
+ OPT_PTR(milling_speed);
OPT_PTR(overhangs);
OPT_PTR(overhangs_width);
OPT_PTR(overhangs_reverse);
@@ -859,6 +868,7 @@ public:
ConfigOptionString feature_gcode;
ConfigOptionFloat max_print_speed;
ConfigOptionFloat max_volumetric_speed;
+ ConfigOptionFloats milling_z_lift;
#ifdef HAS_PRESSURE_EQUALIZER
ConfigOptionFloat max_volumetric_extrusion_rate_slope_positive;
ConfigOptionFloat max_volumetric_extrusion_rate_slope_negative;
@@ -953,6 +963,7 @@ protected:
OPT_PTR(feature_gcode);
OPT_PTR(max_print_speed);
OPT_PTR(max_volumetric_speed);
+ OPT_PTR(milling_z_lift);
#ifdef HAS_PRESSURE_EQUALIZER
OPT_PTR(max_volumetric_extrusion_rate_slope_positive);
OPT_PTR(max_volumetric_extrusion_rate_slope_negative);
@@ -1038,6 +1049,10 @@ public:
ConfigOptionFloats max_layer_height;
ConfigOptionFloat max_print_height;
ConfigOptionFloats milling_diameter;
+ ConfigOptionStrings milling_toolchange_end_gcode;
+ ConfigOptionStrings milling_toolchange_start_gcode;
+ //ConfigOptionPoints milling_offset;
+ //ConfigOptionFloats milling_z_offset;
ConfigOptionInts min_fan_speed;
ConfigOptionFloats min_layer_height;
ConfigOptionFloats min_print_speed;
@@ -1120,6 +1135,10 @@ protected:
OPT_PTR(max_layer_height);
OPT_PTR(max_print_height);
OPT_PTR(milling_diameter);
+ OPT_PTR(milling_toolchange_end_gcode);
+ OPT_PTR(milling_toolchange_start_gcode);
+ //OPT_PTR(milling_offset);
+ //OPT_PTR(milling_z_offset);
OPT_PTR(min_fan_speed);
OPT_PTR(min_layer_height);
OPT_PTR(min_print_speed);
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 3e4eb9844..b8d89980a 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -353,15 +353,30 @@ void PrintObject::make_perimeters()
tbb::parallel_for(
tbb::blocked_range<size_t>(0, m_layers.size()),
[this](const tbb::blocked_range<size_t>& range) {
- for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
- m_print->throw_if_canceled();
- m_layers[layer_idx]->make_perimeters();
- }
+ for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
+ m_print->throw_if_canceled();
+ m_layers[layer_idx]->make_perimeters();
}
+ }
);
m_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - end";
+ if (print()->config().milling_diameter.size() > 0 ) {
+ BOOST_LOG_TRIVIAL(debug) << "Generating milling post-process in parallel - start";
+ tbb::parallel_for(
+ tbb::blocked_range<size_t>(0, m_layers.size()),
+ [this](const tbb::blocked_range<size_t>& range) {
+ for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
+ m_print->throw_if_canceled();
+ m_layers[layer_idx]->make_milling_post_process();
+ }
+ }
+ );
+ m_print->throw_if_canceled();
+ BOOST_LOG_TRIVIAL(debug) << "Generating milling post-process in parallel - end";
+ }
+
this->set_done(posPerimeters);
}
@@ -1991,7 +2006,7 @@ SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full
size_t num_extruders = print_config.nozzle_diameter.size();
object_config = object_config_from_model_object(object_config, model_object, num_extruders);
- std::vector<unsigned int> object_extruders;
+ std::vector<uint16_t> object_extruders;
for (const ModelVolume* model_volume : model_object.volumes)
if (model_volume->is_model_part()) {
PrintRegion::collect_object_printing_extruders(
@@ -2017,9 +2032,9 @@ SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full
}
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
-std::vector<unsigned int> PrintObject::object_extruders() const
+std::vector<uint16_t> PrintObject::object_extruders() const
{
- std::vector<unsigned int> extruders;
+ std::vector<uint16_t> extruders;
extruders.reserve(this->region_volumes.size() * 3);
for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++ idx_region)
if (! this->region_volumes[idx_region].empty())
diff --git a/src/libslic3r/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp
index 5b94b3d56..c8c1537bb 100644
--- a/src/libslic3r/PrintRegion.cpp
+++ b/src/libslic3r/PrintRegion.cpp
@@ -3,7 +3,7 @@
namespace Slic3r {
// 1-based extruder identifier for this region and role.
-unsigned int PrintRegion::extruder(FlowRole role) const
+uint16_t PrintRegion::extruder(FlowRole role) const
{
size_t extruder = 0;
if (role == frPerimeter || role == frExternalPerimeter)
@@ -65,7 +65,7 @@ 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<unsigned int> &object_extruders)
+void PrintRegion::collect_object_printing_extruders(const PrintConfig &print_config, const PrintObjectConfig &object_config, const PrintRegionConfig &region_config, std::vector<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();
@@ -81,7 +81,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<unsigned int> &object_extruders) const
+void PrintRegion::collect_object_printing_extruders(std::vector<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 a2dad7d86..1a5308f90 100644
--- a/src/libslic3r/Slicing.cpp
+++ b/src/libslic3r/Slicing.cpp
@@ -62,7 +62,7 @@ SlicingParameters SlicingParameters::create_from_config(
const PrintConfig &print_config,
const PrintObjectConfig &object_config,
coordf_t object_height,
- const std::vector<unsigned int> &object_extruders)
+ const std::vector<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.
diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp
index 2b7b7d49c..d49790e5d 100644
--- a/src/libslic3r/Slicing.hpp
+++ b/src/libslic3r/Slicing.hpp
@@ -31,7 +31,7 @@ struct SlicingParameters
const PrintConfig &print_config,
const PrintObjectConfig &object_config,
coordf_t object_height,
- const std::vector<unsigned int> &object_extruders);
+ const std::vector<uint16_t> &object_extruders);
// Has any raft layers?
bool has_raft() const { return raft_layers() > 0; }