From a05c4402632756b8401f1fe909f043349b570f02 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Tue, 17 Apr 2018 10:55:18 +0200
Subject: [PATCH 01/12] Fixed potential crashes due to the Perl worker thread
 releasing memory allocated by the GUI thread.

---
 lib/Slic3r.pm | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm
index e55e24a7a..ab06a6455 100644
--- a/lib/Slic3r.pm
+++ b/lib/Slic3r.pm
@@ -161,7 +161,12 @@ sub thread_cleanup {
     *Slic3r::Print::SupportMaterial2::DESTROY = sub {};
     *Slic3r::TriangleMesh::DESTROY          = sub {};
     *Slic3r::GUI::AppConfig::DESTROY        = sub {};
+    *Slic3r::GUI::GCodePreviewData::DESTROY = sub {};
+    *Slic3r::GUI::OctoPrint::DESTROY        = sub {};
     *Slic3r::GUI::PresetBundle::DESTROY     = sub {};
+    *Slic3r::GUI::PresetHints::DESTROY      = sub {};
+    *Slic3r::GUI::PresetUpdater::DESTROY    = sub {};
+    *Slic3r::GUI::TabIface::DESTROY         = sub {};
     return undef;  # this prevents a "Scalars leaked" warning
 }
 

From 98785e47b18c7052245e91966915c99f984aae05 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Tue, 17 Apr 2018 10:55:58 +0200
Subject: [PATCH 02/12] Removed the "The Wipe Tower currently supports only:\n"
 "- first layer height 0.2mm\n" "- layer height from 0.15mm to 0.35mm\n"
 message as the new wipe tower is more generic.

---
 xs/src/slic3r/GUI/Tab.cpp | 23 -----------------------
 1 file changed, 23 deletions(-)

diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp
index 851022489..3476a897d 100644
--- a/xs/src/slic3r/GUI/Tab.cpp
+++ b/xs/src/slic3r/GUI/Tab.cpp
@@ -1015,29 +1015,6 @@ void TabPrint::update()
 		on_value_change("fill_density", fill_density);
 	}
 
-	auto first_layer_height = m_config->option<ConfigOptionFloatOrPercent>("first_layer_height")->value;
-	auto layer_height = m_config->opt_float("layer_height");
-	if (m_config->opt_bool("wipe_tower") &&
-		(first_layer_height != 0.2 || layer_height < 0.15 || layer_height > 0.35)) {
-		wxString msg_text = _(L("The Wipe Tower currently supports only:\n"
-			"- first layer height 0.2mm\n"
-			"- layer height from 0.15mm to 0.35mm\n"
-			"\nShall I adjust those settings in order to enable the Wipe Tower?"));
-		auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO);
-		DynamicPrintConfig new_conf = *m_config;
-		if (dialog->ShowModal() == wxID_YES) {
-			const auto &val = *m_config->option<ConfigOptionFloatOrPercent>("first_layer_height");
-			auto percent = val.percent;
-			new_conf.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(0.2, percent));
-
-			if (m_config->opt_float("layer_height") < 0.15) new_conf.set_key_value("layer_height", new ConfigOptionFloat(0.15));
-			if (m_config->opt_float("layer_height") > 0.35) new_conf.set_key_value("layer_height", new ConfigOptionFloat(0.35));
-		}
-		else
-			new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false));
-		load_config(new_conf);
-	}
-
 	if (m_config->opt_bool("wipe_tower") && m_config->opt_bool("support_material") &&
 		m_config->opt_float("support_material_contact_distance") > 0. &&
 		(m_config->opt_int("support_material_extruder") != 0 || m_config->opt_int("support_material_interface_extruder") != 0)) {

From 5e6cc5ddcbc5c937e8434edb0176aceb4d98b394 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Tue, 17 Apr 2018 11:06:15 +0200
Subject: [PATCH 03/12] Updated max_print_height of PrusaResearch.ini

---
 resources/profiles/PrusaResearch.ini | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini
index 0da7f22d1..b487aae4c 100644
--- a/resources/profiles/PrusaResearch.ini
+++ b/resources/profiles/PrusaResearch.ini
@@ -69,6 +69,7 @@ infill_first = 0
 infill_only_where_needed = 0
 infill_overlap = 25%
 interface_shells = 0
+max_print_height = 200
 max_print_speed = 100
 max_volumetric_extrusion_rate_slope_negative = 0
 max_volumetric_extrusion_rate_slope_positive = 0
@@ -120,7 +121,7 @@ thin_walls = 0
 top_infill_extrusion_width = 0.45
 top_solid_infill_speed = 40
 travel_speed = 180
-wipe_tower = 0
+wipe_tower = 1
 wipe_tower_per_color_wipe = 20
 wipe_tower_width = 60
 wipe_tower_x = 180
@@ -995,6 +996,7 @@ inherits = *common*
 end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
 retract_lift_below = 209
+max_print_height = 210
 start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83  ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0  F1000.0 ; intro line\nG1 X100.0 E12.5  F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
 printer_model = MK3
 default_print_profile = 0.15mm OPTIMAL MK3
@@ -1006,6 +1008,7 @@ printer_variant = 0.25
 end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
 retract_lift_below = 209
+max_print_height = 210
 start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83  ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0  F1000.0 ; intro line\nG1 X100.0 E12.5  F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
 printer_model = MK3
 default_print_profile = 0.10mm DETAIL MK3
@@ -1017,6 +1020,7 @@ printer_variant = 0.6
 end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
 retract_lift_below = 209
+max_print_height = 210
 start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83  ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0  F1000.0 ; intro line\nG1 X100.0 E12.5  F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
 printer_model = MK3
 default_print_profile = 0.15mm OPTIMAL MK3

From 6c627be4c18cc747df9040ed3bceb2bc14823f0b Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Wed, 25 Apr 2018 10:37:31 +0200
Subject: [PATCH 04/12] New cooling logic to equalize extrusion velocity. The
 old behavior caused bad outer surface print quality on Prusa i3 MK3

---
 xs/src/libslic3r/GCode/CoolingBuffer.cpp | 479 +++++++++++++++--------
 1 file changed, 306 insertions(+), 173 deletions(-)

diff --git a/xs/src/libslic3r/GCode/CoolingBuffer.cpp b/xs/src/libslic3r/GCode/CoolingBuffer.cpp
index cd2baeffb..121cbb017 100644
--- a/xs/src/libslic3r/GCode/CoolingBuffer.cpp
+++ b/xs/src/libslic3r/GCode/CoolingBuffer.cpp
@@ -30,6 +30,174 @@ void CoolingBuffer::reset()
     m_current_pos[4] = float(m_gcodegen.config().travel_speed.value);
 }
 
+struct CoolingLine
+{
+    enum Type {
+        TYPE_SET_TOOL           = 1 << 0,
+        TYPE_EXTRUDE_END        = 1 << 1,
+        TYPE_BRIDGE_FAN_START   = 1 << 2,
+        TYPE_BRIDGE_FAN_END     = 1 << 3,
+        TYPE_G0                 = 1 << 4,
+        TYPE_G1                 = 1 << 5,
+        TYPE_ADJUSTABLE         = 1 << 6,
+        TYPE_EXTERNAL_PERIMETER = 1 << 7,
+        // The line sets a feedrate.
+        TYPE_HAS_F              = 1 << 8,
+        TYPE_WIPE               = 1 << 9,
+        TYPE_G4                 = 1 << 10,
+        TYPE_G92                = 1 << 11,
+    };
+
+    CoolingLine(unsigned int type, size_t  line_start, size_t  line_end) :
+        type(type), line_start(line_start), line_end(line_end),
+        length(0.f), time(0.f), time_max(0.f), slowdown(false) {}
+
+    bool adjustable(bool slowdown_external_perimeters) const {
+        return (this->type & TYPE_ADJUSTABLE) && 
+               (! (this->type & TYPE_EXTERNAL_PERIMETER) || slowdown_external_perimeters) &&
+               this->time < this->time_max;
+    }
+
+    bool adjustable() const {
+        return (this->type & TYPE_ADJUSTABLE) && this->time < this->time_max;
+    }
+
+    size_t  type;
+    // Start of this line at the G-code snippet.
+    size_t  line_start;
+    // End of this line at the G-code snippet.
+    size_t  line_end;
+    // XY Euclidian length of this segment.
+    float   length;
+    // Current feedrate, possibly adjusted.
+    float   feedrate;
+    // Current duration of this segment.
+    float   time;
+    // Maximum duration of this segment.
+    float   time_max;
+    // If marked with the "slowdown" flag, the line has been slowed down.
+    bool    slowdown;
+};
+
+// Calculate the required per extruder time stretches.
+struct PerExtruderAdjustments 
+{
+    // Calculate the total elapsed time per this extruder, adjusted for the slowdown.
+    float elapsed_time_total() {
+        float time_total = 0.f;
+        for (const CoolingLine &line : lines)
+            time_total += line.time;
+        return time_total;
+    }
+    // Calculate the maximum time when slowing down.
+    float maximum_time(bool slowdown_external_perimeters) {
+        float time_total = 0.f;
+        for (const CoolingLine &line : lines)
+            if (line.adjustable(slowdown_external_perimeters)) {
+                if (line.time_max == FLT_MAX)
+                    return FLT_MAX;
+                else
+                    time_total += line.time_max;
+            } else
+                time_total += line.time;
+        return time_total;
+    }
+    // Calculate the non-adjustable part of the total time.
+    float non_adjustable_time(bool slowdown_external_perimeters) {
+        float time_total = 0.f;
+        for (const CoolingLine &line : lines)
+            if (! line.adjustable(slowdown_external_perimeters))
+                time_total += line.time;
+        return time_total;
+    }
+    float slow_down_maximum(bool slowdown_external_perimeters) {
+        float time_total = 0.f;
+        for (CoolingLine &line : lines) {
+            if (line.adjustable(slowdown_external_perimeters)) {
+                assert(line.time_max >= 0.f && line.time_max < FLT_MAX);
+                line.slowdown = true;
+                line.time     = line.time_max;
+                line.feedrate = line.length / line.time;
+            }
+            time_total += line.time;
+        }
+        return time_total;
+    }
+    float slow_down_proportional(float factor, bool slowdown_external_perimeters) {
+        assert(factor >= 1.f);
+        float time_total = 0.f;
+        for (CoolingLine &line : lines) {
+            if (line.adjustable(slowdown_external_perimeters)) {
+                line.slowdown = true;
+                line.time     = std::min(line.time_max, line.time * factor);
+                line.feedrate = line.length / line.time;
+            }
+            time_total += line.time;
+        }
+        return time_total;
+    }
+
+    bool operator<(const PerExtruderAdjustments &rhs) const { return this->extruder_id < rhs.extruder_id; }
+
+    // Sort the lines, adjustable first, higher feedrate first.
+    void sort_lines_by_decreasing_feedrate() {
+        std::sort(lines.begin(), lines.end(), [](const CoolingLine &l1, const CoolingLine &l2) {
+            bool adj1 = l1.adjustable();
+            bool adj2 = l2.adjustable();
+            return (adj1 == adj2) ? l1.feedrate > l2.feedrate : adj1;
+        });
+        for (n_lines_adjustable = 0; n_lines_adjustable < lines.size(); ++ n_lines_adjustable)
+            if ((this->lines[n_lines_adjustable].type & CoolingLine::TYPE_ADJUSTABLE) == 0)
+                break;
+        time_non_adjustable = 0.f;
+        for (size_t i = n_lines_adjustable; i < lines.size(); ++ i)
+            time_non_adjustable += lines[i].time;
+    }
+
+    // Calculate the maximum time when slowing down.
+    float time_stretch_when_slowing_down_to(float min_feedrate) {
+        float time_stretch = 0.f;
+        if (this->min_print_speed < min_feedrate + EPSILON) {
+            for (size_t i = 0; i < n_lines_adjustable; ++ i) {
+                const CoolingLine &line = lines[i];
+                if (line.feedrate > min_feedrate)
+                    time_stretch += line.time * (line.feedrate / min_feedrate - 1.f);
+            }
+        }
+        return time_stretch;
+    }
+
+    void slow_down_to(float min_feedrate) {
+        if (this->min_print_speed < min_feedrate + EPSILON) {
+            for (size_t i = 0; i < n_lines_adjustable; ++ i) {
+                CoolingLine &line = lines[i];
+                if (line.feedrate > min_feedrate) {
+                    line.time *= std::max(1.f, line.feedrate / min_feedrate);
+                    line.feedrate = min_feedrate;
+                    line.slowdown = true;
+                }
+            }
+        }
+    }
+
+    // Extruder, for which the G-code will be adjusted.
+    unsigned int                extruder_id         = 0;
+    // Minimum print speed allowed for this extruder.
+    float                       min_print_speed     = 0.f;
+
+    // Parsed lines.
+    std::vector<CoolingLine>    lines;
+    // The following two values are set by sort_lines_by_decreasing_feedrate():
+    // Number of adjustable lines, at the start of lines.
+    size_t                      n_lines_adjustable  = 0;
+    // Non-adjustable time of lines starting with n_lines_adjustable. 
+    float                       time_non_adjustable = 0;
+
+    // Temporaries for processing the slow down. Both thresholds go from 0 to n_lines_adjustable.
+    size_t                      idx_line_begin      = 0;
+    size_t                      idx_line_end        = 0;
+};
+
 #define EXTRUDER_CONFIG(OPT) config.OPT.get_at(m_current_extruder)
 
 std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_id)
@@ -38,125 +206,23 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
     const std::vector<Extruder> &extruders     = m_gcodegen.writer().extruders();
     const size_t                 num_extruders = extruders.size();
 
-    // Calculate the required per extruder time stretches.
-    struct Adjustment {
-        Adjustment(unsigned int extruder_id = 0) : extruder_id(extruder_id) {}
-        // Calculate the total elapsed time per this extruder, adjusted for the slowdown.
-        float elapsed_time_total() {
-            float time_total = 0.f;
-            for (const Line &line : lines)
-                time_total += line.time;
-            return time_total;
-        }
-        // Calculate the maximum time when slowing down.
-        float maximum_time(bool slowdown_external_perimeters) {
-            float time_total = 0.f;
-			for (const Line &line : lines)
-				if (line.adjustable(slowdown_external_perimeters)) {
-					if (line.time_max == FLT_MAX)
-						return FLT_MAX;
-					else
-						time_total += line.time_max;
-				} else
-					time_total += line.time;
-            return time_total;
-        }
-        // Calculate the non-adjustable part of the total time.
-        float non_adjustable_time(bool slowdown_external_perimeters) {
-            float time_total = 0.f;
-            for (const Line &line : lines)
-                if (! line.adjustable(slowdown_external_perimeters))
-                    time_total += line.time;
-            return time_total;
-        }
-        float slow_down_maximum(bool slowdown_external_perimeters) {
-            float time_total = 0.f;
-            for (Line &line : lines) {
-                if (line.adjustable(slowdown_external_perimeters)) {
-					assert(line.time_max >= 0.f && line.time_max < FLT_MAX);
-                    line.slowdown = true;
-                    line.time = line.time_max;
-                }
-                time_total += line.time;
-            }
-            return time_total;
-        }
-        float slow_down_proportional(float factor, bool slowdown_external_perimeters) {
-            assert(factor >= 1.f);
-            float time_total = 0.f;
-            for (Line &line : lines) {
-                if (line.adjustable(slowdown_external_perimeters)) {
-                    line.slowdown = true;
-                    line.time = std::min(line.time_max, line.time * factor);
-                }
-                time_total += line.time;
-            }
-            return time_total;
-        }
-
-        bool operator<(const Adjustment &rhs) const { return this->extruder_id < rhs.extruder_id; }
-
-        struct Line
-        {
-            enum Type {
-                TYPE_SET_TOOL           = 1 << 0,
-                TYPE_EXTRUDE_END        = 1 << 1,
-                TYPE_BRIDGE_FAN_START   = 1 << 2,
-                TYPE_BRIDGE_FAN_END     = 1 << 3,
-                TYPE_G0                 = 1 << 4,
-                TYPE_G1                 = 1 << 5,
-                TYPE_ADJUSTABLE         = 1 << 6,
-                TYPE_EXTERNAL_PERIMETER = 1 << 7,
-                // The line sets a feedrate.
-                TYPE_HAS_F              = 1 << 8,
-                TYPE_WIPE               = 1 << 9,
-                TYPE_G4                 = 1 << 10,
-                TYPE_G92                = 1 << 11,
-            };
-
-            Line(unsigned int type, size_t  line_start, size_t  line_end) :
-                type(type), line_start(line_start), line_end(line_end),
-                length(0.f), time(0.f), time_max(0.f), slowdown(false) {}
-
-            bool adjustable(bool slowdown_external_perimeters) const {
-                return (this->type & TYPE_ADJUSTABLE) && 
-                       (! (this->type & TYPE_EXTERNAL_PERIMETER) || slowdown_external_perimeters) &&
-                       this->time < this->time_max;
-            }
-
-            size_t  type;
-            // Start of this line at the G-code snippet.
-            size_t  line_start;
-            // End of this line at the G-code snippet.
-            size_t  line_end;
-            // XY Euclidian length of this segment.
-            float   length;
-            // Current duration of this segment.
-            float   time;
-            // Maximum duration of this segment.
-            float   time_max;
-            // If marked with the "slowdown" flag, the line has been slowed down.
-            bool    slowdown;
-        };
-
-        // Extruder, for which the G-code will be adjusted.
-        unsigned int        extruder_id;
-        // Parsed lines.
-        std::vector<Line>   lines;
-    };
-    std::vector<Adjustment> adjustments(num_extruders, Adjustment());
-    for (size_t i = 0; i < num_extruders; ++ i)
-        adjustments[i].extruder_id = extruders[i].id();
-    const std::string       toolchange_prefix = m_gcodegen.writer().toolchange_prefix();
+    std::vector<PerExtruderAdjustments> per_extruder_adjustments(num_extruders);
+    std::vector<size_t>                 map_extruder_to_per_extruder_adjustment(num_extruders, 0);
+    for (size_t i = 0; i < num_extruders; ++ i) {
+        unsigned int extruder_id = extruders[i].id();
+        per_extruder_adjustments[i].extruder_id = extruder_id;
+        per_extruder_adjustments[i].min_print_speed = config.min_print_speed.get_at(i);
+        map_extruder_to_per_extruder_adjustment[extruder_id] = i;
+    }
+    const std::string     toolchange_prefix = m_gcodegen.writer().toolchange_prefix();
     // Parse the layer G-code for the moves, which could be adjusted.
     {
-        float             min_print_speed   = float(EXTRUDER_CONFIG(min_print_speed));
-        auto              adjustment        = std::lower_bound(adjustments.begin(), adjustments.end(), Adjustment(m_current_extruder));
+        PerExtruderAdjustments *adjustment  = &per_extruder_adjustments[map_extruder_to_per_extruder_adjustment[m_current_extruder]];
         unsigned int      initial_extruder  = m_current_extruder;
 		const char       *line_start = gcode.c_str();
 		const char		 *line_end   = line_start;
         const char        extrusion_axis = config.get_extrusion_axis()[0];
-        // Index of an existing Adjustment::Line of the current adjustment, which holds the feedrate setting command
+        // Index of an existing CoolingLine of the current adjustment, which holds the feedrate setting command
         // for a sequence of extrusion moves.
         size_t            active_speed_modifier = size_t(-1);
 		for (; *line_start != 0; line_start = line_end) {
@@ -164,16 +230,16 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
                 ++ line_end;
             // sline will not contain the trailing '\n'.
             std::string sline(line_start, line_end);
-            // Adjustment::Line will contain the trailing '\n'.
+            // CoolingLine will contain the trailing '\n'.
             if (*line_end == '\n')
                 ++ line_end;
-            Adjustment::Line line(0, line_start - gcode.c_str(), line_end - gcode.c_str());
+            CoolingLine line(0, line_start - gcode.c_str(), line_end - gcode.c_str());
             if (boost::starts_with(sline, "G0 "))
-                line.type = Adjustment::Line::TYPE_G0;
+                line.type = CoolingLine::TYPE_G0;
             else if (boost::starts_with(sline, "G1 "))
-                line.type = Adjustment::Line::TYPE_G1;
+                line.type = CoolingLine::TYPE_G1;
             else if (boost::starts_with(sline, "G92 "))
-                line.type = Adjustment::Line::TYPE_G92;
+                line.type = CoolingLine::TYPE_G92;
             if (line.type) {
                 // G0, G1 or G92
                 // Parse the G-code line.
@@ -192,9 +258,9 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
 						if (axis == 4) {
 							// Convert mm/min to mm/sec.
 							new_pos[4] /= 60.f;
-                            if ((line.type & Adjustment::Line::TYPE_G92) == 0)
+                            if ((line.type & CoolingLine::TYPE_G92) == 0)
                                 // This is G0 or G1 line and it sets the feedrate. This mark is used for reducing the duplicate F calls.
-                                line.type |= Adjustment::Line::TYPE_HAS_F;
+                                line.type |= CoolingLine::TYPE_HAS_F;
                         }
 					}
                     // Skip this word.
@@ -203,14 +269,14 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
                 bool external_perimeter = boost::contains(sline, ";_EXTERNAL_PERIMETER");
                 bool wipe               = boost::contains(sline, ";_WIPE");
                 if (external_perimeter)
-                    line.type |= Adjustment::Line::TYPE_EXTERNAL_PERIMETER;
+                    line.type |= CoolingLine::TYPE_EXTERNAL_PERIMETER;
                 if (wipe)
-                    line.type |= Adjustment::Line::TYPE_WIPE;
+                    line.type |= CoolingLine::TYPE_WIPE;
                 if (boost::contains(sline, ";_EXTRUDE_SET_SPEED") && ! wipe) {
-                    line.type |= Adjustment::Line::TYPE_ADJUSTABLE;
+                    line.type |= CoolingLine::TYPE_ADJUSTABLE;
                     active_speed_modifier = adjustment->lines.size();
                 }
-                if ((line.type & Adjustment::Line::TYPE_G92) == 0) {
+                if ((line.type & CoolingLine::TYPE_G92) == 0) {
                     // G0 or G1. Calculate the duration.
                     if (config.use_relative_e_distances.value)
                         // Reset extruder accumulator.
@@ -227,15 +293,17 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
                         // Movement in the extruder axis.
                         line.length = std::abs(dif[3]);
                     }
-                    if (line.length > 0)
-                        line.time   = line.length / new_pos[4]; // current F
+                    if (line.length > 0) {
+                        line.feedrate = new_pos[4]; // current F
+                        line.time   = line.length / line.feedrate;
+                    }
                     line.time_max = line.time;
-					if ((line.type & Adjustment::Line::TYPE_ADJUSTABLE) || active_speed_modifier != size_t(-1))
-                        line.time_max = (min_print_speed == 0.f) ? FLT_MAX : std::max(line.time, line.length / min_print_speed);
-					if (active_speed_modifier < adjustment->lines.size() && (line.type & Adjustment::Line::TYPE_G1)) {
+					if ((line.type & CoolingLine::TYPE_ADJUSTABLE) || active_speed_modifier != size_t(-1))
+                        line.time_max = (adjustment->min_print_speed == 0.f) ? FLT_MAX : std::max(line.time, line.length / adjustment->min_print_speed);
+					if (active_speed_modifier < adjustment->lines.size() && (line.type & CoolingLine::TYPE_G1)) {
                         // Inside the ";_EXTRUDE_SET_SPEED" blocks, there must not be a G1 Fxx entry.
-                        assert((line.type & Adjustment::Line::TYPE_HAS_F) == 0);
-						Adjustment::Line &sm = adjustment->lines[active_speed_modifier];
+                        assert((line.type & CoolingLine::TYPE_HAS_F) == 0);
+						CoolingLine &sm = adjustment->lines[active_speed_modifier];
 						sm.length   += line.length;
 						sm.time     += line.time;
 						if (sm.time_max != FLT_MAX) {
@@ -250,24 +318,23 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
 				}
                 m_current_pos = std::move(new_pos);
             } else if (boost::starts_with(sline, ";_EXTRUDE_END")) {
-                line.type = Adjustment::Line::TYPE_EXTRUDE_END;
+                line.type = CoolingLine::TYPE_EXTRUDE_END;
                 active_speed_modifier = size_t(-1);
             } else if (boost::starts_with(sline, toolchange_prefix)) {
                 // Switch the tool.
-                line.type = Adjustment::Line::TYPE_SET_TOOL;
+                line.type = CoolingLine::TYPE_SET_TOOL;
                 unsigned int new_extruder = (unsigned int)atoi(sline.c_str() + toolchange_prefix.size());
                 if (new_extruder != m_current_extruder) {
                     m_current_extruder = new_extruder;
-                    min_print_speed    = float(EXTRUDER_CONFIG(min_print_speed));
-                    adjustment         = std::lower_bound(adjustments.begin(), adjustments.end(), Adjustment(m_current_extruder));
+                    adjustment         = &per_extruder_adjustments[map_extruder_to_per_extruder_adjustment[m_current_extruder]];
                 }
             } else if (boost::starts_with(sline, ";_BRIDGE_FAN_START")) {
-                line.type = Adjustment::Line::TYPE_BRIDGE_FAN_START;
+                line.type = CoolingLine::TYPE_BRIDGE_FAN_START;
             } else if (boost::starts_with(sline, ";_BRIDGE_FAN_END")) {
-                line.type = Adjustment::Line::TYPE_BRIDGE_FAN_END;
+                line.type = CoolingLine::TYPE_BRIDGE_FAN_END;
             } else if (boost::starts_with(sline, "G4 ")) {
                 // Parse the wait time.
-                line.type = Adjustment::Line::TYPE_G4;
+                line.type = CoolingLine::TYPE_G4;
                 size_t pos_S = sline.find('S', 3);
                 size_t pos_P = sline.find('P', 3);
                 line.time = line.time_max = float(
@@ -281,18 +348,19 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
     }
 
     // Sort the extruders by the increasing slowdown_below_layer_time.
-    std::vector<size_t> by_slowdown_layer_time;
-    by_slowdown_layer_time.reserve(num_extruders);
+    std::vector<size_t> extruder_by_slowdown_time;
+    extruder_by_slowdown_time.reserve(num_extruders);
     // Only insert entries, which are adjustable (have cooling enabled and non-zero stretchable time).
     // Collect total print time of non-adjustable extruders.
     float elapsed_time_total_non_adjustable = 0.f;
     for (size_t i = 0; i < num_extruders; ++ i) {
-        if (config.cooling.get_at(extruders[i].id()))
-            by_slowdown_layer_time.emplace_back(i);
-        else
-            elapsed_time_total_non_adjustable += adjustments[i].elapsed_time_total();
+        if (config.cooling.get_at(extruders[i].id())) {
+            extruder_by_slowdown_time.emplace_back(i);
+            per_extruder_adjustments[i].sort_lines_by_decreasing_feedrate();
+        } else
+            elapsed_time_total_non_adjustable += per_extruder_adjustments[i].elapsed_time_total();
     }
-    std::sort(by_slowdown_layer_time.begin(), by_slowdown_layer_time.end(),
+    std::sort(extruder_by_slowdown_time.begin(), extruder_by_slowdown_time.end(),
         [&config, &extruders](const size_t idx1, const size_t idx2){
             return config.slowdown_below_layer_time.get_at(extruders[idx1].id()) < 
                    config.slowdown_below_layer_time.get_at(extruders[idx2].id());
@@ -303,18 +371,18 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
     {
         // Elapsed time for the already adjusted extruders.
 		float elapsed_time_total0 = elapsed_time_total_non_adjustable;
-        for (size_t i_by_slowdown_layer_time = 0; i_by_slowdown_layer_time < by_slowdown_layer_time.size(); ++ i_by_slowdown_layer_time) {
-            // Idx in adjustments.
-            size_t idx = by_slowdown_layer_time[i_by_slowdown_layer_time];
-            // Macro to sum or adjust all sections starting with i_by_slowdown_layer_time.
+        for (size_t i_extruder_by_slowdown_time = 0; i_extruder_by_slowdown_time < extruder_by_slowdown_time.size(); ++ i_extruder_by_slowdown_time) {
+            // Idx in per_extruder_adjustments.
+            size_t idx = extruder_by_slowdown_time[i_extruder_by_slowdown_time];
+            // Macro to sum or adjust all sections starting with i_extruder_by_slowdown_time.
             #define FORALL_UNPROCESSED(ACCUMULATOR, ACTION) \
                 ACCUMULATOR = elapsed_time_total0;\
-                for (size_t j = i_by_slowdown_layer_time; j < by_slowdown_layer_time.size(); ++ j) \
-                    ACCUMULATOR += adjustments[by_slowdown_layer_time[j]].ACTION
+                for (size_t j = i_extruder_by_slowdown_time; j < extruder_by_slowdown_time.size(); ++ j) \
+                    ACCUMULATOR += per_extruder_adjustments[extruder_by_slowdown_time[j]].ACTION
             // Calculate the current adjusted elapsed_time_total over the non-finalized extruders.
             float        total;
             FORALL_UNPROCESSED(total, elapsed_time_total());
-            float        slowdown_below_layer_time = float(config.slowdown_below_layer_time.get_at(adjustments[idx].extruder_id)) * 1.001f;
+            float        slowdown_below_layer_time = float(config.slowdown_below_layer_time.get_at(per_extruder_adjustments[idx].extruder_id)) * 1.001f;
             if (total > slowdown_below_layer_time) {
                 // The current total time is above the minimum threshold of the rest of the extruders, don't adjust anything.
             } else {
@@ -323,8 +391,9 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
                 float max_time;
                 FORALL_UNPROCESSED(max_time, maximum_time(true));
                 if (max_time > slowdown_below_layer_time) {
-                    // By slowing every possible movement, the layer time could be reached. Now decide
-                    // whether the external perimeters shall be slowed down as well.
+                    // By slowing every possible movement, the layer time could be reached.
+#if 0
+                    // Now decide, whether the external perimeters shall be slowed down as well.
                     float max_time_nep;
                     FORALL_UNPROCESSED(max_time_nep, maximum_time(false));
                     if (max_time_nep > slowdown_below_layer_time) {
@@ -355,34 +424,98 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
                                 break;
                         }
                     }
+#else
+                    // Slow down. Try to equalize the feedrates.
+                    std::vector<PerExtruderAdjustments*> by_min_print_speed;
+                    by_min_print_speed.reserve(extruder_by_slowdown_time.size() - i_extruder_by_slowdown_time);
+                    for (size_t j = i_extruder_by_slowdown_time; j < extruder_by_slowdown_time.size(); ++ j)
+                        by_min_print_speed.emplace_back(&per_extruder_adjustments[extruder_by_slowdown_time[j]]);
+                    // Find the next highest adjustable feedrate among the extruders.
+                    float feedrate = 0;
+                    for (PerExtruderAdjustments *adj : by_min_print_speed)
+                        if (adj->idx_line_begin < adj->n_lines_adjustable && adj->lines[adj->idx_line_begin].feedrate > feedrate)
+                            feedrate = adj->lines[adj->idx_line_begin].feedrate;
+                    if (feedrate == 0)
+                        // No adjustable line is left.
+                        break;
+                    // Sort by min_print_speed, maximum speed first.
+                    std::sort(by_min_print_speed.begin(), by_min_print_speed.end(), 
+                        [](const PerExtruderAdjustments *p1, const PerExtruderAdjustments *p2){ return p1->min_print_speed > p2->min_print_speed; });
+                    // Slow down, fast moves first.
+                    for (;;) {
+                        // For each extruder, find the span of lines with a feedrate close to feedrate.
+                        for (PerExtruderAdjustments *adj : by_min_print_speed) {
+                            for (adj->idx_line_end = adj->idx_line_begin;
+                                adj->idx_line_end < adj->n_lines_adjustable && adj->lines[adj->idx_line_end].feedrate > feedrate - EPSILON;
+                                 ++ adj->idx_line_end) ;
+                        }
+                        // Find the next highest adjustable feedrate among the extruders.
+                        float feedrate_next = 0.f;
+                        for (PerExtruderAdjustments *adj : by_min_print_speed)
+                            if (adj->idx_line_end < adj->n_lines_adjustable && adj->lines[adj->idx_line_end].feedrate > feedrate_next)
+                                feedrate_next = adj->lines[adj->idx_line_end].feedrate;
+                        // Slow down, limited by max(feedrate_next, min_print_speed).
+                        for (auto adj = by_min_print_speed.begin(); adj != by_min_print_speed.end();) {
+                            float feedrate_limit = std::max(feedrate_next, (*adj)->min_print_speed);
+                            float time_stretch = slowdown_below_layer_time - total;
+                            float time_stretch_max = 0.f;
+                            std::pair<float, float> time_stretched(0.f, 0.f);
+                            for (auto it = adj; it != by_min_print_speed.end(); ++ it)
+                                time_stretch_max += (*it)->time_stretch_when_slowing_down_to(feedrate_limit);
+							bool done = false;
+							if (time_stretch_max > time_stretch) {
+								feedrate_limit = feedrate - (feedrate - feedrate_limit) * time_stretch / time_stretch_max;
+								done = true;
+							}
+                            for (auto it = adj; it != by_min_print_speed.end(); ++ it)
+                                (*it)->slow_down_to(feedrate_limit);
+							if (done) {
+								// Break from two levels of loops.
+								feedrate_next = 0.f;
+								break;
+							}
+                            // Skip the other extruders with nearly the same min_print_speed, as they have been processed already.
+                            auto next = adj;
+                            for (++ next; next != by_min_print_speed.end() && (*next)->min_print_speed > (*adj)->min_print_speed - EPSILON; ++ next);
+                            adj = next;
+                        }
+                        if (feedrate_next == 0.f)
+                            // There are no other extrusions available for slow down.
+                            break;
+                        for (PerExtruderAdjustments *adj : by_min_print_speed) {
+                            adj->idx_line_begin = adj->idx_line_end;
+                            feedrate = feedrate_next;
+                        }
+                    }
+#endif
                 } else {
                     // Slow down to maximum possible.
                     FORALL_UNPROCESSED(total, slow_down_maximum(true));
                 }
             }
             #undef FORALL_UNPROCESSED
-            // Sum the final elapsed time for all extruders up to i_by_slowdown_layer_time.
-            if (i_by_slowdown_layer_time + 1 == by_slowdown_layer_time.size())
+            // Sum the final elapsed time for all extruders up to i_extruder_by_slowdown_time.
+            if (i_extruder_by_slowdown_time + 1 == extruder_by_slowdown_time.size())
                 // Optimization for single extruder prints.
                 elapsed_time_total0 = total;
             else
-                elapsed_time_total0 += adjustments[idx].elapsed_time_total();
+                elapsed_time_total0 += per_extruder_adjustments[idx].elapsed_time_total();
         }
         elapsed_time_total = elapsed_time_total0;
     }
 
     // Transform the G-code.
     // First sort the adjustment lines by their position in the source G-code.
-    std::vector<const Adjustment::Line*> lines;
+    std::vector<const CoolingLine*> lines;
     {
         size_t n_lines = 0;
-        for (const Adjustment &adj : adjustments)
+        for (const PerExtruderAdjustments &adj : per_extruder_adjustments)
             n_lines += adj.lines.size();
         lines.reserve(n_lines);
-        for (const Adjustment &adj : adjustments)
-            for (const Adjustment::Line &line : adj.lines)
+        for (const PerExtruderAdjustments &adj : per_extruder_adjustments)
+            for (const CoolingLine &line : adj.lines)
                 lines.emplace_back(&line);
-        std::sort(lines.begin(), lines.end(), [](const Adjustment::Line *ln1, const Adjustment::Line *ln2) { return ln1->line_start < ln2->line_start; } );
+        std::sort(lines.begin(), lines.end(), [](const CoolingLine *ln1, const CoolingLine *ln2) { return ln1->line_start < ln2->line_start; } );
     }
     // Second generate the adjusted G-code.
     std::string new_gcode;
@@ -425,27 +558,27 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
 
     const char *pos              = gcode.c_str();
     int         current_feedrate = 0;
-    for (const Adjustment::Line *line : lines) {
+    for (const CoolingLine *line : lines) {
         const char *line_start  = gcode.c_str() + line->line_start;
         const char *line_end    = gcode.c_str() + line->line_end;
         if (line_start > pos)
             new_gcode.append(pos, line_start - pos);
-        if (line->type & Adjustment::Line::TYPE_SET_TOOL) {
+        if (line->type & CoolingLine::TYPE_SET_TOOL) {
             unsigned int new_extruder = (unsigned int)atoi(line_start + toolchange_prefix.size());
             if (new_extruder != m_current_extruder) {
                 m_current_extruder = new_extruder;
                 change_extruder_set_fan();
             }
             new_gcode.append(line_start, line_end - line_start);
-        } else if (line->type & Adjustment::Line::TYPE_BRIDGE_FAN_START) {
+        } else if (line->type & CoolingLine::TYPE_BRIDGE_FAN_START) {
             if (bridge_fan_control)
                 new_gcode += m_gcodegen.writer().set_fan(bridge_fan_speed, true);
-        } else if (line->type & Adjustment::Line::TYPE_BRIDGE_FAN_END) {
+        } else if (line->type & CoolingLine::TYPE_BRIDGE_FAN_END) {
             if (bridge_fan_control)
                 new_gcode += m_gcodegen.writer().set_fan(fan_speed, true);
-        } else if (line->type & Adjustment::Line::TYPE_EXTRUDE_END) {
+        } else if (line->type & CoolingLine::TYPE_EXTRUDE_END) {
             // Just remove this comment.
-        } else if (line->type & (Adjustment::Line::TYPE_ADJUSTABLE | Adjustment::Line::TYPE_EXTERNAL_PERIMETER | Adjustment::Line::TYPE_WIPE | Adjustment::Line::TYPE_HAS_F)) {
+        } else if (line->type & (CoolingLine::TYPE_ADJUSTABLE | CoolingLine::TYPE_EXTERNAL_PERIMETER | CoolingLine::TYPE_WIPE | CoolingLine::TYPE_HAS_F)) {
             // Find the start of a comment, or roll to the end of line.
 			const char *end = line_start;
 			for (; end < line_end && *end != ';'; ++ end);
@@ -456,14 +589,14 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
             assert(fpos != nullptr);
             if (line->slowdown) {
                 modify       = true;
-                new_feedrate = int(floor(60. * (line->length / line->time) + 0.5));
+                new_feedrate = int(floor(60. * line->feedrate + 0.5));
             } else {
                 new_feedrate = atoi(fpos);
                 if (new_feedrate != current_feedrate) {
                     // Append the line without the comment.
                     new_gcode.append(line_start, end - line_start);
                     current_feedrate = new_feedrate;
-                } else if ((line->type & (Adjustment::Line::TYPE_ADJUSTABLE | Adjustment::Line::TYPE_EXTERNAL_PERIMETER | Adjustment::Line::TYPE_WIPE)) || line->length == 0.) {
+                } else if ((line->type & (CoolingLine::TYPE_ADJUSTABLE | CoolingLine::TYPE_EXTERNAL_PERIMETER | CoolingLine::TYPE_WIPE)) || line->length == 0.) {
                     // Feedrate does not change and this line does not move the print head. Skip the complete G-code line including the G-code comment.
                     end = line_end;
                 } else {
@@ -497,13 +630,13 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
             }
             // Process the rest of the line.
             if (end < line_end) {
-                if (line->type & (Adjustment::Line::TYPE_ADJUSTABLE | Adjustment::Line::TYPE_EXTERNAL_PERIMETER | Adjustment::Line::TYPE_WIPE)) {
+                if (line->type & (CoolingLine::TYPE_ADJUSTABLE | CoolingLine::TYPE_EXTERNAL_PERIMETER | CoolingLine::TYPE_WIPE)) {
 					// Process comments, remove ";_EXTRUDE_SET_SPEED", ";_EXTERNAL_PERIMETER", ";_WIPE"
 					std::string comment(end, line_end);
 					boost::replace_all(comment, ";_EXTRUDE_SET_SPEED", "");
-                    if (line->type & Adjustment::Line::TYPE_EXTERNAL_PERIMETER)
+                    if (line->type & CoolingLine::TYPE_EXTERNAL_PERIMETER)
                         boost::replace_all(comment, ";_EXTERNAL_PERIMETER", "");
-                    if (line->type & Adjustment::Line::TYPE_WIPE)
+                    if (line->type & CoolingLine::TYPE_WIPE)
                         boost::replace_all(comment, ";_WIPE", "");
 					new_gcode += comment;
 				} else {

From 269770bbbc373f1462631f918b0bb894db7422a1 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Wed, 25 Apr 2018 22:06:44 +0200
Subject: [PATCH 05/12] Fix of a new cooling logic.

---
 t/cooling.t                              |  6 +--
 xs/src/libslic3r/GCode/CoolingBuffer.cpp | 60 ++++++++++++++++--------
 2 files changed, 44 insertions(+), 22 deletions(-)

diff --git a/t/cooling.t b/t/cooling.t
index ee4f6abea..f69b7e8a8 100644
--- a/t/cooling.t
+++ b/t/cooling.t
@@ -2,7 +2,7 @@ use Test::More;
 use strict;
 use warnings;
 
-plan tests => 15;
+plan tests => 14;
 
 BEGIN {
     use FindBin;
@@ -203,8 +203,8 @@ $config->set('disable_fan_first_layers',    [ 0 ]);
     ok $all_below, 'slowdown_below_layer_time is honored';
     
     # check that all layers have at least one unaltered external perimeter speed
-    my $external = all { $_ > 0 } values %layer_external;
-    ok $external, 'slowdown_below_layer_time does not alter external perimeters';
+#    my $external = all { $_ > 0 } values %layer_external;
+#    ok $external, 'slowdown_below_layer_time does not alter external perimeters';
 }
 
 __END__
diff --git a/xs/src/libslic3r/GCode/CoolingBuffer.cpp b/xs/src/libslic3r/GCode/CoolingBuffer.cpp
index 121cbb017..ca9fc6555 100644
--- a/xs/src/libslic3r/GCode/CoolingBuffer.cpp
+++ b/xs/src/libslic3r/GCode/CoolingBuffer.cpp
@@ -102,6 +102,13 @@ struct PerExtruderAdjustments
                 time_total += line.time;
         return time_total;
     }
+    float adjustable_time(bool slowdown_external_perimeters) {
+        float time_total = 0.f;
+        for (const CoolingLine &line : lines)
+            if (line.adjustable(slowdown_external_perimeters))
+                time_total += line.time;
+        return time_total;
+    }
     // Calculate the non-adjustable part of the total time.
     float non_adjustable_time(bool slowdown_external_perimeters) {
         float time_total = 0.f;
@@ -207,11 +214,14 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
     const size_t                 num_extruders = extruders.size();
 
     std::vector<PerExtruderAdjustments> per_extruder_adjustments(num_extruders);
-    std::vector<size_t>                 map_extruder_to_per_extruder_adjustment(num_extruders, 0);
+    unsigned int                        id_extruder_max = 0;
+    for (const Extruder &ex : extruders)
+        id_extruder_max = std::max(ex.id(), id_extruder_max);
+    std::vector<size_t>                 map_extruder_to_per_extruder_adjustment(id_extruder_max + 1, 0);
     for (size_t i = 0; i < num_extruders; ++ i) {
         unsigned int extruder_id = extruders[i].id();
         per_extruder_adjustments[i].extruder_id = extruder_id;
-        per_extruder_adjustments[i].min_print_speed = config.min_print_speed.get_at(i);
+        per_extruder_adjustments[i].min_print_speed = config.min_print_speed.get_at(extruder_id);
         map_extruder_to_per_extruder_adjustment[extruder_id] = i;
     }
     const std::string     toolchange_prefix = m_gcodegen.writer().toolchange_prefix();
@@ -442,6 +452,7 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
                     std::sort(by_min_print_speed.begin(), by_min_print_speed.end(), 
                         [](const PerExtruderAdjustments *p1, const PerExtruderAdjustments *p2){ return p1->min_print_speed > p2->min_print_speed; });
                     // Slow down, fast moves first.
+                    float time_stretch = slowdown_below_layer_time - total;
                     for (;;) {
                         // For each extruder, find the span of lines with a feedrate close to feedrate.
                         for (PerExtruderAdjustments *adj : by_min_print_speed) {
@@ -457,23 +468,34 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
                         // Slow down, limited by max(feedrate_next, min_print_speed).
                         for (auto adj = by_min_print_speed.begin(); adj != by_min_print_speed.end();) {
                             float feedrate_limit = std::max(feedrate_next, (*adj)->min_print_speed);
-                            float time_stretch = slowdown_below_layer_time - total;
-                            float time_stretch_max = 0.f;
-                            std::pair<float, float> time_stretched(0.f, 0.f);
-                            for (auto it = adj; it != by_min_print_speed.end(); ++ it)
-                                time_stretch_max += (*it)->time_stretch_when_slowing_down_to(feedrate_limit);
-							bool done = false;
-							if (time_stretch_max > time_stretch) {
-								feedrate_limit = feedrate - (feedrate - feedrate_limit) * time_stretch / time_stretch_max;
-								done = true;
-							}
-                            for (auto it = adj; it != by_min_print_speed.end(); ++ it)
-                                (*it)->slow_down_to(feedrate_limit);
-							if (done) {
-								// Break from two levels of loops.
-								feedrate_next = 0.f;
-								break;
-							}
+                            if (feedrate_limit == 0.f) {
+                                float adjustable_time = 0.f;
+                                for (auto it = adj; it != by_min_print_speed.end(); ++ it)
+                                    adjustable_time += (*it)->adjustable_time(true);
+                                float ratio = (adjustable_time + time_stretch) / adjustable_time;
+                                for (auto it = adj; it != by_min_print_speed.end(); ++ it)
+                                    (*it)->slow_down_proportional(ratio, true);
+                                // Break from two levels of loops.
+                                feedrate_next = 0.f;
+                                break;
+                            } else {
+                                float time_stretch_max = 0.f;
+                                for (auto it = adj; it != by_min_print_speed.end(); ++ it)
+                                    time_stretch_max += (*it)->time_stretch_when_slowing_down_to(feedrate_limit);
+    							bool done = false;
+    							if (time_stretch_max > time_stretch) {
+    								feedrate_limit = feedrate - (feedrate - feedrate_limit) * time_stretch / time_stretch_max;
+    								done = true;
+    							}
+                                for (auto it = adj; it != by_min_print_speed.end(); ++ it)
+                                    (*it)->slow_down_to(feedrate_limit);
+    							if (done) {
+    								// Break from two levels of loops.
+    								feedrate_next = 0.f;
+    								break;
+    							}
+                                time_stretch -= time_stretch_max;
+                            }
                             // Skip the other extruders with nearly the same min_print_speed, as they have been processed already.
                             auto next = adj;
                             for (++ next; next != by_min_print_speed.end() && (*next)->min_print_speed > (*adj)->min_print_speed - EPSILON; ++ next);

From cbaf0ccc51133db07b47e1de0177b5db4fae2a02 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Wed, 25 Apr 2018 22:54:52 +0200
Subject: [PATCH 06/12] Refactored cooling logic for readibility and
 maintainability.

---
 t/cooling.t                              |   1 +
 xs/src/libslic3r/GCode/CoolingBuffer.cpp | 753 ++++++++++++-----------
 xs/src/libslic3r/GCode/CoolingBuffer.hpp |  26 +-
 3 files changed, 430 insertions(+), 350 deletions(-)

diff --git a/t/cooling.t b/t/cooling.t
index f69b7e8a8..2f444cf9d 100644
--- a/t/cooling.t
+++ b/t/cooling.t
@@ -79,6 +79,7 @@ $config->set('disable_fan_first_layers',    [ 0 ]);
         "G1 X50 F2500\n" .
         "G1 F3000;_EXTRUDE_SET_SPEED\n" .
         "G1 X100 E1\n" .
+        ";_EXTRUDE_END\n" .
         "G1 E4 F400",
     # Print time of $gcode.
     my $print_time = 50 / (2500 / 60) + 100 / (3000 / 60) + 4 / (400 / 60);
diff --git a/xs/src/libslic3r/GCode/CoolingBuffer.cpp b/xs/src/libslic3r/GCode/CoolingBuffer.cpp
index ca9fc6555..141d197ca 100644
--- a/xs/src/libslic3r/GCode/CoolingBuffer.cpp
+++ b/xs/src/libslic3r/GCode/CoolingBuffer.cpp
@@ -89,8 +89,9 @@ struct PerExtruderAdjustments
             time_total += line.time;
         return time_total;
     }
-    // Calculate the maximum time when slowing down.
-    float maximum_time(bool slowdown_external_perimeters) {
+    // Calculate the total elapsed time when slowing down 
+    // to the minimum extrusion feed rate defined for the current material.
+    float maximum_time_after_slowdown(bool slowdown_external_perimeters) {
         float time_total = 0.f;
         for (const CoolingLine &line : lines)
             if (line.adjustable(slowdown_external_perimeters)) {
@@ -102,6 +103,7 @@ struct PerExtruderAdjustments
                 time_total += line.time;
         return time_total;
     }
+    // Calculate the adjustable part of the total time.
     float adjustable_time(bool slowdown_external_perimeters) {
         float time_total = 0.f;
         for (const CoolingLine &line : lines)
@@ -117,7 +119,9 @@ struct PerExtruderAdjustments
                 time_total += line.time;
         return time_total;
     }
-    float slow_down_maximum(bool slowdown_external_perimeters) {
+    // Slow down the adjustable extrusions to the minimum feedrate allowed for the current extruder material.
+    // Used by both proportional and non-proportional slow down.
+    float slowdown_to_minimum_feedrate(bool slowdown_external_perimeters) {
         float time_total = 0.f;
         for (CoolingLine &line : lines) {
             if (line.adjustable(slowdown_external_perimeters)) {
@@ -130,6 +134,8 @@ struct PerExtruderAdjustments
         }
         return time_total;
     }
+    // Slow down each adjustable G-code line proportionally by a factor.
+    // Used by the proportional slow down.
     float slow_down_proportional(float factor, bool slowdown_external_perimeters) {
         assert(factor >= 1.f);
         float time_total = 0.f;
@@ -144,9 +150,8 @@ struct PerExtruderAdjustments
         return time_total;
     }
 
-    bool operator<(const PerExtruderAdjustments &rhs) const { return this->extruder_id < rhs.extruder_id; }
-
     // Sort the lines, adjustable first, higher feedrate first.
+    // Used by non-proportional slow down.
     void sort_lines_by_decreasing_feedrate() {
         std::sort(lines.begin(), lines.end(), [](const CoolingLine &l1, const CoolingLine &l2) {
             bool adj1 = l1.adjustable();
@@ -161,34 +166,41 @@ struct PerExtruderAdjustments
             time_non_adjustable += lines[i].time;
     }
 
-    // Calculate the maximum time when slowing down.
-    float time_stretch_when_slowing_down_to(float min_feedrate) {
+    // Calculate the maximum time stretch when slowing down to min_feedrate.
+    // Slowdown to min_feedrate shall be allowed for this extruder's material.
+    // Used by non-proportional slow down.
+    float time_stretch_when_slowing_down_to_feedrate(float min_feedrate) {
         float time_stretch = 0.f;
-        if (this->min_print_speed < min_feedrate + EPSILON) {
-            for (size_t i = 0; i < n_lines_adjustable; ++ i) {
-                const CoolingLine &line = lines[i];
-                if (line.feedrate > min_feedrate)
-                    time_stretch += line.time * (line.feedrate / min_feedrate - 1.f);
-            }
+        assert(this->min_print_speed < min_feedrate + EPSILON);
+        for (size_t i = 0; i < n_lines_adjustable; ++ i) {
+            const CoolingLine &line = lines[i];
+            if (line.feedrate > min_feedrate)
+                time_stretch += line.time * (line.feedrate / min_feedrate - 1.f);
         }
         return time_stretch;
     }
 
-    void slow_down_to(float min_feedrate) {
-        if (this->min_print_speed < min_feedrate + EPSILON) {
-            for (size_t i = 0; i < n_lines_adjustable; ++ i) {
-                CoolingLine &line = lines[i];
-                if (line.feedrate > min_feedrate) {
-                    line.time *= std::max(1.f, line.feedrate / min_feedrate);
-                    line.feedrate = min_feedrate;
-                    line.slowdown = true;
-                }
+    // Slow down all adjustable lines down to min_feedrate.
+    // Slowdown to min_feedrate shall be allowed for this extruder's material.
+    // Used by non-proportional slow down.
+    void slow_down_to_feedrate(float min_feedrate) {
+        assert(this->min_print_speed < min_feedrate + EPSILON);
+        for (size_t i = 0; i < n_lines_adjustable; ++ i) {
+            CoolingLine &line = lines[i];
+            if (line.feedrate > min_feedrate) {
+                line.time *= std::max(1.f, line.feedrate / min_feedrate);
+                line.feedrate = min_feedrate;
+                line.slowdown = true;
             }
         }
     }
 
     // Extruder, for which the G-code will be adjusted.
     unsigned int                extruder_id         = 0;
+    // Is the cooling slow down logic enabled for this extruder's material?
+    bool                        cooling_slow_down_enabled = false;
+    // Slow down the print down to min_print_speed if the total layer time is below slowdown_below_layer_time.
+    float                       slowdown_below_layer_time = 0.f;
     // Minimum print speed allowed for this extruder.
     float                       min_print_speed     = 0.f;
 
@@ -199,335 +211,387 @@ struct PerExtruderAdjustments
     size_t                      n_lines_adjustable  = 0;
     // Non-adjustable time of lines starting with n_lines_adjustable. 
     float                       time_non_adjustable = 0;
+    // Current total time for this extruder.
+    float                       time_total          = 0;
+    // Maximum time for this extruder, when the maximum slow down is applied.
+    float                       time_maximum        = 0;
 
     // Temporaries for processing the slow down. Both thresholds go from 0 to n_lines_adjustable.
     size_t                      idx_line_begin      = 0;
     size_t                      idx_line_end        = 0;
 };
 
-#define EXTRUDER_CONFIG(OPT) config.OPT.get_at(m_current_extruder)
-
 std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_id)
+{
+    std::vector<PerExtruderAdjustments> per_extruder_adjustments = this->parse_layer_gcode(gcode, m_current_pos);
+    float layer_time_stretched = this->calculate_layer_slowdown(per_extruder_adjustments);
+    return this->apply_layer_cooldown(gcode, layer_id, layer_time_stretched, per_extruder_adjustments);
+}
+
+// Parse the layer G-code for the moves, which could be adjusted.
+// Return the list of parsed lines, bucketed by an extruder.
+std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::string &gcode, std::vector<float> &current_pos) const
 {
     const FullPrintConfig       &config        = m_gcodegen.config();
     const std::vector<Extruder> &extruders     = m_gcodegen.writer().extruders();
-    const size_t                 num_extruders = extruders.size();
-
-    std::vector<PerExtruderAdjustments> per_extruder_adjustments(num_extruders);
-    unsigned int                        id_extruder_max = 0;
+    unsigned int                 num_extruders = 0;
     for (const Extruder &ex : extruders)
-        id_extruder_max = std::max(ex.id(), id_extruder_max);
-    std::vector<size_t>                 map_extruder_to_per_extruder_adjustment(id_extruder_max + 1, 0);
-    for (size_t i = 0; i < num_extruders; ++ i) {
-        unsigned int extruder_id = extruders[i].id();
-        per_extruder_adjustments[i].extruder_id = extruder_id;
-        per_extruder_adjustments[i].min_print_speed = config.min_print_speed.get_at(extruder_id);
+        num_extruders = std::max(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();
+		adj.extruder_id				  = extruder_id;
+		adj.cooling_slow_down_enabled = config.cooling.get_at(extruder_id);
+		adj.slowdown_below_layer_time = config.slowdown_below_layer_time.get_at(extruder_id);
+		adj.min_print_speed			  = config.min_print_speed.get_at(extruder_id);
         map_extruder_to_per_extruder_adjustment[extruder_id] = i;
     }
-    const std::string     toolchange_prefix = m_gcodegen.writer().toolchange_prefix();
-    // Parse the layer G-code for the moves, which could be adjusted.
+
+    const std::string toolchange_prefix = m_gcodegen.writer().toolchange_prefix();
+    unsigned int      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;
+    const char        extrusion_axis = config.get_extrusion_axis()[0];
+    // Index of an existing CoolingLine of the current adjustment, which holds the feedrate setting command
+    // for a sequence of extrusion moves.
+    size_t            active_speed_modifier = size_t(-1);
+
+    for (; *line_start != 0; line_start = line_end) 
     {
-        PerExtruderAdjustments *adjustment  = &per_extruder_adjustments[map_extruder_to_per_extruder_adjustment[m_current_extruder]];
-        unsigned int      initial_extruder  = m_current_extruder;
-		const char       *line_start = gcode.c_str();
-		const char		 *line_end   = line_start;
-        const char        extrusion_axis = config.get_extrusion_axis()[0];
-        // Index of an existing CoolingLine of the current adjustment, which holds the feedrate setting command
-        // for a sequence of extrusion moves.
-        size_t            active_speed_modifier = size_t(-1);
-		for (; *line_start != 0; line_start = line_end) {
-            while (*line_end != '\n' && *line_end != 0)
-                ++ line_end;
-            // sline will not contain the trailing '\n'.
-            std::string sline(line_start, line_end);
-            // CoolingLine will contain the trailing '\n'.
-            if (*line_end == '\n')
-                ++ line_end;
-            CoolingLine line(0, line_start - gcode.c_str(), line_end - gcode.c_str());
-            if (boost::starts_with(sline, "G0 "))
-                line.type = CoolingLine::TYPE_G0;
-            else if (boost::starts_with(sline, "G1 "))
-                line.type = CoolingLine::TYPE_G1;
-            else if (boost::starts_with(sline, "G92 "))
-                line.type = CoolingLine::TYPE_G92;
-            if (line.type) {
-                // G0, G1 or G92
-                // Parse the G-code line.
-                std::vector<float> new_pos(m_current_pos);
-                const char *c = sline.data() + 3;
-                for (;;) {
-                    // Skip whitespaces.
-                    for (; *c == ' ' || *c == '\t'; ++ c);
-                    if (*c == 0 || *c == ';')
-                        break;
-                    // Parse the axis.
-                    size_t axis = (*c >= 'X' && *c <= 'Z') ? (*c - 'X') :
-                                  (*c == extrusion_axis) ? 3 : (*c == 'F') ? 4 : size_t(-1);
-					if (axis != size_t(-1)) {
-						new_pos[axis] = float(atof(++c));
-						if (axis == 4) {
-							// Convert mm/min to mm/sec.
-							new_pos[4] /= 60.f;
-                            if ((line.type & CoolingLine::TYPE_G92) == 0)
-                                // This is G0 or G1 line and it sets the feedrate. This mark is used for reducing the duplicate F calls.
-                                line.type |= CoolingLine::TYPE_HAS_F;
-                        }
-					}
-                    // Skip this word.
-                    for (; *c != ' ' && *c != '\t' && *c != 0; ++ c);
-                }
-                bool external_perimeter = boost::contains(sline, ";_EXTERNAL_PERIMETER");
-                bool wipe               = boost::contains(sline, ";_WIPE");
-                if (external_perimeter)
-                    line.type |= CoolingLine::TYPE_EXTERNAL_PERIMETER;
-                if (wipe)
-                    line.type |= CoolingLine::TYPE_WIPE;
-                if (boost::contains(sline, ";_EXTRUDE_SET_SPEED") && ! wipe) {
-                    line.type |= CoolingLine::TYPE_ADJUSTABLE;
-                    active_speed_modifier = adjustment->lines.size();
-                }
-                if ((line.type & CoolingLine::TYPE_G92) == 0) {
-                    // G0 or G1. Calculate the duration.
-                    if (config.use_relative_e_distances.value)
-                        // Reset extruder accumulator.
-                        m_current_pos[3] = 0.f;
-                    float dif[4];
-                    for (size_t i = 0; i < 4; ++ i)
-                        dif[i] = new_pos[i] - m_current_pos[i];
-                    float dxy2 = dif[0] * dif[0] + dif[1] * dif[1];
-                    float dxyz2 = dxy2 + dif[2] * dif[2];
-                    if (dxyz2 > 0.f) {
-                        // Movement in xyz, calculate time from the xyz Euclidian distance.
-                        line.length = sqrt(dxyz2);
-                    } else if (std::abs(dif[3]) > 0.f) {
-                        // Movement in the extruder axis.
-                        line.length = std::abs(dif[3]);
+        while (*line_end != '\n' && *line_end != 0)
+            ++ line_end;
+        // sline will not contain the trailing '\n'.
+        std::string sline(line_start, line_end);
+        // CoolingLine will contain the trailing '\n'.
+        if (*line_end == '\n')
+            ++ line_end;
+        CoolingLine line(0, line_start - gcode.c_str(), line_end - gcode.c_str());
+        if (boost::starts_with(sline, "G0 "))
+            line.type = CoolingLine::TYPE_G0;
+        else if (boost::starts_with(sline, "G1 "))
+            line.type = CoolingLine::TYPE_G1;
+        else if (boost::starts_with(sline, "G92 "))
+            line.type = CoolingLine::TYPE_G92;
+        if (line.type) {
+            // G0, G1 or G92
+            // Parse the G-code line.
+            std::vector<float> new_pos(current_pos);
+            const char *c = sline.data() + 3;
+            for (;;) {
+                // Skip whitespaces.
+                for (; *c == ' ' || *c == '\t'; ++ c);
+                if (*c == 0 || *c == ';')
+                    break;
+                // Parse the axis.
+                size_t axis = (*c >= 'X' && *c <= 'Z') ? (*c - 'X') :
+                              (*c == extrusion_axis) ? 3 : (*c == 'F') ? 4 : size_t(-1);
+                if (axis != size_t(-1)) {
+                    new_pos[axis] = float(atof(++c));
+                    if (axis == 4) {
+                        // Convert mm/min to mm/sec.
+                        new_pos[4] /= 60.f;
+                        if ((line.type & CoolingLine::TYPE_G92) == 0)
+                            // This is G0 or G1 line and it sets the feedrate. This mark is used for reducing the duplicate F calls.
+                            line.type |= CoolingLine::TYPE_HAS_F;
                     }
-                    if (line.length > 0) {
-                        line.feedrate = new_pos[4]; // current F
-                        line.time   = line.length / line.feedrate;
-                    }
-                    line.time_max = line.time;
-					if ((line.type & CoolingLine::TYPE_ADJUSTABLE) || active_speed_modifier != size_t(-1))
-                        line.time_max = (adjustment->min_print_speed == 0.f) ? FLT_MAX : std::max(line.time, line.length / adjustment->min_print_speed);
-					if (active_speed_modifier < adjustment->lines.size() && (line.type & CoolingLine::TYPE_G1)) {
-                        // Inside the ";_EXTRUDE_SET_SPEED" blocks, there must not be a G1 Fxx entry.
-                        assert((line.type & CoolingLine::TYPE_HAS_F) == 0);
-						CoolingLine &sm = adjustment->lines[active_speed_modifier];
-						sm.length   += line.length;
-						sm.time     += line.time;
-						if (sm.time_max != FLT_MAX) {
-							if (line.time_max == FLT_MAX)
-								sm.time_max = FLT_MAX;
-							else
-								sm.time_max += line.time_max;
-						}
-						// Don't store this line.
-						line.type = 0;
-					}
-				}
-                m_current_pos = std::move(new_pos);
-            } else if (boost::starts_with(sline, ";_EXTRUDE_END")) {
-                line.type = CoolingLine::TYPE_EXTRUDE_END;
-                active_speed_modifier = size_t(-1);
-            } else if (boost::starts_with(sline, toolchange_prefix)) {
-                // Switch the tool.
-                line.type = CoolingLine::TYPE_SET_TOOL;
-                unsigned int new_extruder = (unsigned int)atoi(sline.c_str() + toolchange_prefix.size());
-                if (new_extruder != m_current_extruder) {
-                    m_current_extruder = new_extruder;
-                    adjustment         = &per_extruder_adjustments[map_extruder_to_per_extruder_adjustment[m_current_extruder]];
                 }
-            } else if (boost::starts_with(sline, ";_BRIDGE_FAN_START")) {
-                line.type = CoolingLine::TYPE_BRIDGE_FAN_START;
-            } else if (boost::starts_with(sline, ";_BRIDGE_FAN_END")) {
-                line.type = CoolingLine::TYPE_BRIDGE_FAN_END;
-            } else if (boost::starts_with(sline, "G4 ")) {
-                // Parse the wait time.
-                line.type = CoolingLine::TYPE_G4;
-                size_t pos_S = sline.find('S', 3);
-                size_t pos_P = sline.find('P', 3);
-                line.time = line.time_max = float(
-                    (pos_S > 0) ? atof(sline.c_str() + pos_S + 1) :
-                    (pos_P > 0) ? atof(sline.c_str() + pos_P + 1) * 0.001 : 0.);
+                // Skip this word.
+                for (; *c != ' ' && *c != '\t' && *c != 0; ++ c);
             }
-            if (line.type != 0)
-                adjustment->lines.emplace_back(std::move(line));
-		}
-        m_current_extruder = initial_extruder;
+            bool external_perimeter = boost::contains(sline, ";_EXTERNAL_PERIMETER");
+            bool wipe               = boost::contains(sline, ";_WIPE");
+            if (external_perimeter)
+                line.type |= CoolingLine::TYPE_EXTERNAL_PERIMETER;
+            if (wipe)
+                line.type |= CoolingLine::TYPE_WIPE;
+            if (boost::contains(sline, ";_EXTRUDE_SET_SPEED") && ! wipe) {
+                line.type |= CoolingLine::TYPE_ADJUSTABLE;
+                active_speed_modifier = adjustment->lines.size();
+            }
+            if ((line.type & CoolingLine::TYPE_G92) == 0) {
+                // G0 or G1. Calculate the duration.
+                if (config.use_relative_e_distances.value)
+                    // Reset extruder accumulator.
+                    current_pos[3] = 0.f;
+                float dif[4];
+                for (size_t i = 0; i < 4; ++ i)
+                    dif[i] = new_pos[i] - current_pos[i];
+                float dxy2 = dif[0] * dif[0] + dif[1] * dif[1];
+                float dxyz2 = dxy2 + dif[2] * dif[2];
+                if (dxyz2 > 0.f) {
+                    // Movement in xyz, calculate time from the xyz Euclidian distance.
+                    line.length = sqrt(dxyz2);
+                } else if (std::abs(dif[3]) > 0.f) {
+                    // Movement in the extruder axis.
+                    line.length = std::abs(dif[3]);
+                }
+                if (line.length > 0) {
+                    line.feedrate = new_pos[4]; // current F
+                    line.time   = line.length / line.feedrate;
+                }
+                line.time_max = line.time;
+                if ((line.type & CoolingLine::TYPE_ADJUSTABLE) || active_speed_modifier != size_t(-1))
+                    line.time_max = (adjustment->min_print_speed == 0.f) ? FLT_MAX : std::max(line.time, line.length / adjustment->min_print_speed);
+                if (active_speed_modifier < adjustment->lines.size() && (line.type & CoolingLine::TYPE_G1)) {
+                    // Inside the ";_EXTRUDE_SET_SPEED" blocks, there must not be a G1 Fxx entry.
+                    assert((line.type & CoolingLine::TYPE_HAS_F) == 0);
+                    CoolingLine &sm = adjustment->lines[active_speed_modifier];
+                    sm.length   += line.length;
+                    sm.time     += line.time;
+                    if (sm.time_max != FLT_MAX) {
+                        if (line.time_max == FLT_MAX)
+                            sm.time_max = FLT_MAX;
+                        else
+                            sm.time_max += line.time_max;
+                    }
+                    // Don't store this line.
+                    line.type = 0;
+                }
+            }
+            current_pos = std::move(new_pos);
+        } else if (boost::starts_with(sline, ";_EXTRUDE_END")) {
+            line.type = CoolingLine::TYPE_EXTRUDE_END;
+            active_speed_modifier = size_t(-1);
+        } else if (boost::starts_with(sline, toolchange_prefix)) {
+            // Switch the tool.
+            line.type = CoolingLine::TYPE_SET_TOOL;
+            unsigned int new_extruder = (unsigned int)atoi(sline.c_str() + toolchange_prefix.size());
+            if (new_extruder != current_extruder) {
+                current_extruder = new_extruder;
+                adjustment         = &per_extruder_adjustments[map_extruder_to_per_extruder_adjustment[current_extruder]];
+            }
+        } else if (boost::starts_with(sline, ";_BRIDGE_FAN_START")) {
+            line.type = CoolingLine::TYPE_BRIDGE_FAN_START;
+        } else if (boost::starts_with(sline, ";_BRIDGE_FAN_END")) {
+            line.type = CoolingLine::TYPE_BRIDGE_FAN_END;
+        } else if (boost::starts_with(sline, "G4 ")) {
+            // Parse the wait time.
+            line.type = CoolingLine::TYPE_G4;
+            size_t pos_S = sline.find('S', 3);
+            size_t pos_P = sline.find('P', 3);
+            line.time = line.time_max = float(
+                (pos_S > 0) ? atof(sline.c_str() + pos_S + 1) :
+                (pos_P > 0) ? atof(sline.c_str() + pos_P + 1) * 0.001 : 0.);
+        }
+        if (line.type != 0)
+            adjustment->lines.emplace_back(std::move(line));
     }
 
-    // Sort the extruders by the increasing slowdown_below_layer_time.
-    std::vector<size_t> extruder_by_slowdown_time;
-    extruder_by_slowdown_time.reserve(num_extruders);
+    return per_extruder_adjustments;
+}
+
+// Slow down an extruder range proportionally down to slowdown_below_layer_time.
+// Return the total time for the complete layer.
+static inline float extruder_range_slow_down_proportional(
+    std::vector<PerExtruderAdjustments*>::iterator it_begin,
+    std::vector<PerExtruderAdjustments*>::iterator it_end,
+    // Elapsed time for the extruders already processed.
+    float elapsed_time_total0,
+    // Initial total elapsed time before slow down.
+    float elapsed_time_before_slowdown,
+    // Target time for the complete layer (all extruders applied).
+    float slowdown_below_layer_time)
+{
+    // Total layer time after the slow down has been applied.
+    float total_after_slowdown = elapsed_time_before_slowdown;
+    // Now decide, whether the external perimeters shall be slowed down as well.
+    float max_time_nep = elapsed_time_total0;
+    for (auto it = it_begin; it != it_end; ++ it)
+        max_time_nep += (*it)->maximum_time_after_slowdown(false);
+    if (max_time_nep > slowdown_below_layer_time) {
+        // It is sufficient to slow down the non-external perimeter moves to reach the target layer time.
+        // Slow down the non-external perimeters proportionally.
+        float non_adjustable_time = elapsed_time_total0;
+        for (auto it = it_begin; it != it_end; ++ it)
+            non_adjustable_time += (*it)->non_adjustable_time(false);
+        // The following step is a linear programming task due to the minimum movement speeds of the print moves.
+        // Run maximum 5 iterations until a good enough approximation is reached.
+        for (size_t iter = 0; iter < 5; ++ iter) {
+            float factor = (slowdown_below_layer_time - non_adjustable_time) / (total_after_slowdown - non_adjustable_time);
+            assert(factor > 1.f);
+            total_after_slowdown = elapsed_time_total0;
+            for (auto it = it_begin; it != it_end; ++ it)
+                total_after_slowdown += (*it)->slow_down_proportional(factor, false);
+            if (total_after_slowdown > 0.95f * slowdown_below_layer_time)
+                break;
+        }
+    } else {
+        // Slow down everything. First slow down the non-external perimeters to maximum.
+        for (auto it = it_begin; it != it_end; ++ it)
+            (*it)->slowdown_to_minimum_feedrate(false);
+        // Slow down the external perimeters proportionally.
+        float non_adjustable_time = elapsed_time_total0;
+        for (auto it = it_begin; it != it_end; ++ it)
+            non_adjustable_time += (*it)->non_adjustable_time(true);
+        for (size_t iter = 0; iter < 5; ++ iter) {
+            float factor = (slowdown_below_layer_time - non_adjustable_time) / (total_after_slowdown - non_adjustable_time);
+            assert(factor > 1.f);
+            total_after_slowdown = elapsed_time_total0;
+            for (auto it = it_begin; it != it_end; ++ it)
+                total_after_slowdown += (*it)->slow_down_proportional(factor, true);
+            if (total_after_slowdown > 0.95f * slowdown_below_layer_time)
+                break;
+        }
+    }
+    return total_after_slowdown;
+}
+
+// Slow down an extruder range to slowdown_below_layer_time.
+// Return the total time for the complete layer.
+static inline void extruder_range_slow_down_non_proportional(
+    std::vector<PerExtruderAdjustments*>::iterator it_begin,
+    std::vector<PerExtruderAdjustments*>::iterator it_end,
+    float time_stretch)
+{
+    // Slow down. Try to equalize the feedrates.
+    std::vector<PerExtruderAdjustments*> by_min_print_speed(it_begin, it_end);
+    // Find the next highest adjustable feedrate among the extruders.
+    float feedrate = 0;
+	for (PerExtruderAdjustments *adj : by_min_print_speed) {
+		adj->idx_line_begin = 0;
+		adj->idx_line_end   = 0;
+		assert(adj->idx_line_begin < adj->n_lines_adjustable);
+		if (adj->lines[adj->idx_line_begin].feedrate > feedrate)
+			feedrate = adj->lines[adj->idx_line_begin].feedrate;
+	}
+	assert(feedrate > 0.f);
+    // Sort by min_print_speed, maximum speed first.
+    std::sort(by_min_print_speed.begin(), by_min_print_speed.end(), 
+        [](const PerExtruderAdjustments *p1, const PerExtruderAdjustments *p2){ return p1->min_print_speed > p2->min_print_speed; });
+    // Slow down, fast moves first.
+    for (;;) {
+        // For each extruder, find the span of lines with a feedrate close to feedrate.
+        for (PerExtruderAdjustments *adj : by_min_print_speed) {
+            for (adj->idx_line_end = adj->idx_line_begin;
+                adj->idx_line_end < adj->n_lines_adjustable && adj->lines[adj->idx_line_end].feedrate > feedrate - EPSILON;
+                 ++ adj->idx_line_end) ;
+        }
+        // Find the next highest adjustable feedrate among the extruders.
+        float feedrate_next = 0.f;
+        for (PerExtruderAdjustments *adj : by_min_print_speed)
+            if (adj->idx_line_end < adj->n_lines_adjustable && adj->lines[adj->idx_line_end].feedrate > feedrate_next)
+                feedrate_next = adj->lines[adj->idx_line_end].feedrate;
+        // Slow down, limited by max(feedrate_next, min_print_speed).
+        for (auto adj = by_min_print_speed.begin(); adj != by_min_print_speed.end();) {
+            // Slow down at most by time_stretch.
+            if ((*adj)->min_print_speed == 0.f) {
+                // All the adjustable speeds are now lowered to the same speed,
+                // and the minimum speed is set to zero.
+                float time_adjustable = 0.f;
+                for (auto it = adj; it != by_min_print_speed.end(); ++ it)
+                    time_adjustable += (*it)->adjustable_time(true);
+                float rate = (time_adjustable + time_stretch) / time_adjustable;
+                for (auto it = adj; it != by_min_print_speed.end(); ++ it)
+                    (*it)->slow_down_proportional(rate, true);
+                return;
+            } else {
+                float feedrate_limit = std::max(feedrate_next, (*adj)->min_print_speed);
+                bool  done           = false;
+                float time_stretch_max = 0.f;
+                for (auto it = adj; it != by_min_print_speed.end(); ++ it)
+                    time_stretch_max += (*it)->time_stretch_when_slowing_down_to_feedrate(feedrate_limit);
+                if (time_stretch_max >= time_stretch) {
+                    feedrate_limit = feedrate - (feedrate - feedrate_limit) * time_stretch / time_stretch_max;
+                    done = true;
+                } else
+                    time_stretch -= time_stretch_max;
+                for (auto it = adj; it != by_min_print_speed.end(); ++ it)
+                    (*it)->slow_down_to_feedrate(feedrate_limit);
+                if (done)
+                    return;
+            }
+            // Skip the other extruders with nearly the same min_print_speed, as they have been processed already.
+            auto next = adj;
+            for (++ next; next != by_min_print_speed.end() && (*next)->min_print_speed > (*adj)->min_print_speed - EPSILON; ++ next);
+            adj = next;
+        }
+        if (feedrate_next == 0.f)
+            // There are no other extrusions available for slow down.
+            break;
+        for (PerExtruderAdjustments *adj : by_min_print_speed) {
+            adj->idx_line_begin = adj->idx_line_end;
+            feedrate = feedrate_next;
+        }
+    }
+}
+
+// Calculate slow down for all the extruders.
+float CoolingBuffer::calculate_layer_slowdown(std::vector<PerExtruderAdjustments> &per_extruder_adjustments)
+{
+    // Sort the extruders by an increasing slowdown_below_layer_time.
+    // The layers with a lower slowdown_below_layer_time are slowed down
+    // together with all the other layers with slowdown_below_layer_time above.
+    std::vector<PerExtruderAdjustments*> by_slowdown_time;
+    by_slowdown_time.reserve(per_extruder_adjustments.size());
     // Only insert entries, which are adjustable (have cooling enabled and non-zero stretchable time).
     // Collect total print time of non-adjustable extruders.
-    float elapsed_time_total_non_adjustable = 0.f;
-    for (size_t i = 0; i < num_extruders; ++ i) {
-        if (config.cooling.get_at(extruders[i].id())) {
-            extruder_by_slowdown_time.emplace_back(i);
-            per_extruder_adjustments[i].sort_lines_by_decreasing_feedrate();
+    float elapsed_time_total0 = 0.f;
+    for (PerExtruderAdjustments &adj : per_extruder_adjustments) {
+        // Curren total time for this extruder.
+        adj.time_total  = adj.elapsed_time_total();
+        // Maximum time for this extruder, when all extrusion moves are slowed down to min_extrusion_speed.
+        adj.time_maximum = adj.maximum_time_after_slowdown(true);
+        if (adj.cooling_slow_down_enabled) {
+            by_slowdown_time.emplace_back(&adj);
+            if (! m_cooling_logic_proportional)
+                // sorts the lines, also sets adj.time_non_adjustable
+                adj.sort_lines_by_decreasing_feedrate();
         } else
-            elapsed_time_total_non_adjustable += per_extruder_adjustments[i].elapsed_time_total();
+            elapsed_time_total0 += adj.elapsed_time_total();
     }
-    std::sort(extruder_by_slowdown_time.begin(), extruder_by_slowdown_time.end(),
-        [&config, &extruders](const size_t idx1, const size_t idx2){
-            return config.slowdown_below_layer_time.get_at(extruders[idx1].id()) < 
-                   config.slowdown_below_layer_time.get_at(extruders[idx2].id());
-        });
+    std::sort(by_slowdown_time.begin(), by_slowdown_time.end(),
+        [](const PerExtruderAdjustments *adj1, const PerExtruderAdjustments *adj2)
+            { return adj1->slowdown_below_layer_time < adj2->slowdown_below_layer_time; });
 
-    // Elapsed time after adjustment.
-    float elapsed_time_total = 0.f;
-    {
-        // Elapsed time for the already adjusted extruders.
-		float elapsed_time_total0 = elapsed_time_total_non_adjustable;
-        for (size_t i_extruder_by_slowdown_time = 0; i_extruder_by_slowdown_time < extruder_by_slowdown_time.size(); ++ i_extruder_by_slowdown_time) {
-            // Idx in per_extruder_adjustments.
-            size_t idx = extruder_by_slowdown_time[i_extruder_by_slowdown_time];
-            // Macro to sum or adjust all sections starting with i_extruder_by_slowdown_time.
-            #define FORALL_UNPROCESSED(ACCUMULATOR, ACTION) \
-                ACCUMULATOR = elapsed_time_total0;\
-                for (size_t j = i_extruder_by_slowdown_time; j < extruder_by_slowdown_time.size(); ++ j) \
-                    ACCUMULATOR += per_extruder_adjustments[extruder_by_slowdown_time[j]].ACTION
-            // Calculate the current adjusted elapsed_time_total over the non-finalized extruders.
-            float        total;
-            FORALL_UNPROCESSED(total, elapsed_time_total());
-            float        slowdown_below_layer_time = float(config.slowdown_below_layer_time.get_at(per_extruder_adjustments[idx].extruder_id)) * 1.001f;
-            if (total > slowdown_below_layer_time) {
-                // The current total time is above the minimum threshold of the rest of the extruders, don't adjust anything.
+    for (auto cur_begin = by_slowdown_time.begin(); cur_begin != by_slowdown_time.end(); ++ cur_begin) {
+        PerExtruderAdjustments &adj = *(*cur_begin);
+        // Calculate the current adjusted elapsed_time_total over the non-finalized extruders.
+        float total = elapsed_time_total0;
+        for (auto it = cur_begin; it != by_slowdown_time.end(); ++ it)
+            total += (*it)->time_total;
+        float slowdown_below_layer_time = adj.slowdown_below_layer_time * 1.001f;
+        if (total > slowdown_below_layer_time) {
+            // The current total time is above the minimum threshold of the rest of the extruders, don't adjust anything.
+        } else {
+            // Adjust this and all the following (higher config.slowdown_below_layer_time) extruders.
+            // Sum maximum slow down time as if everything was slowed down including the external perimeters.
+            float max_time = elapsed_time_total0;
+            for (auto it = cur_begin; it != by_slowdown_time.end(); ++ it)
+                max_time += (*it)->time_maximum;
+            if (max_time > slowdown_below_layer_time) {
+                if (m_cooling_logic_proportional)
+                    extruder_range_slow_down_proportional(cur_begin, by_slowdown_time.end(), elapsed_time_total0, total, slowdown_below_layer_time);
+                else
+                    extruder_range_slow_down_non_proportional(cur_begin, by_slowdown_time.end(), slowdown_below_layer_time - total);
             } else {
-                // Adjust this and all the following (higher config.slowdown_below_layer_time) extruders.
-                // Sum maximum slow down time as if everything was slowed down including the external perimeters.
-                float max_time;
-                FORALL_UNPROCESSED(max_time, maximum_time(true));
-                if (max_time > slowdown_below_layer_time) {
-                    // By slowing every possible movement, the layer time could be reached.
-#if 0
-                    // Now decide, whether the external perimeters shall be slowed down as well.
-                    float max_time_nep;
-                    FORALL_UNPROCESSED(max_time_nep, maximum_time(false));
-                    if (max_time_nep > slowdown_below_layer_time) {
-                        // It is sufficient to slow down the non-external perimeter moves to reach the target layer time.
-                        // Slow down the non-external perimeters proportionally.
-                        float non_adjustable_time;
-                        FORALL_UNPROCESSED(non_adjustable_time, non_adjustable_time(false));
-                        // The following step is a linear programming task due to the minimum movement speeds of the print moves.
-                        // Run maximum 5 iterations until a good enough approximation is reached.
-                        for (size_t iter = 0; iter < 5; ++ iter) {
-							float factor = (slowdown_below_layer_time - non_adjustable_time) / (total - non_adjustable_time);
-                            assert(factor > 1.f);
-                            FORALL_UNPROCESSED(total, slow_down_proportional(factor, false));
-                            if (total > 0.95f * slowdown_below_layer_time)
-                                break;
-                        }
-                    } else {
-                        // Slow down everything. First slow down the non-external perimeters to maximum.
-                        FORALL_UNPROCESSED(total, slow_down_maximum(false));
-                        // Slow down the external perimeters proportionally.
-                        float non_adjustable_time;
-                        FORALL_UNPROCESSED(non_adjustable_time, non_adjustable_time(true));
-                        for (size_t iter = 0; iter < 5; ++ iter) {
-							float factor = (slowdown_below_layer_time - non_adjustable_time) / (total - non_adjustable_time);
-                            assert(factor > 1.f);
-                            FORALL_UNPROCESSED(total, slow_down_proportional(factor, true));
-                            if (total > 0.95f * slowdown_below_layer_time)
-                                break;
-                        }
-                    }
-#else
-                    // Slow down. Try to equalize the feedrates.
-                    std::vector<PerExtruderAdjustments*> by_min_print_speed;
-                    by_min_print_speed.reserve(extruder_by_slowdown_time.size() - i_extruder_by_slowdown_time);
-                    for (size_t j = i_extruder_by_slowdown_time; j < extruder_by_slowdown_time.size(); ++ j)
-                        by_min_print_speed.emplace_back(&per_extruder_adjustments[extruder_by_slowdown_time[j]]);
-                    // Find the next highest adjustable feedrate among the extruders.
-                    float feedrate = 0;
-                    for (PerExtruderAdjustments *adj : by_min_print_speed)
-                        if (adj->idx_line_begin < adj->n_lines_adjustable && adj->lines[adj->idx_line_begin].feedrate > feedrate)
-                            feedrate = adj->lines[adj->idx_line_begin].feedrate;
-                    if (feedrate == 0)
-                        // No adjustable line is left.
-                        break;
-                    // Sort by min_print_speed, maximum speed first.
-                    std::sort(by_min_print_speed.begin(), by_min_print_speed.end(), 
-                        [](const PerExtruderAdjustments *p1, const PerExtruderAdjustments *p2){ return p1->min_print_speed > p2->min_print_speed; });
-                    // Slow down, fast moves first.
-                    float time_stretch = slowdown_below_layer_time - total;
-                    for (;;) {
-                        // For each extruder, find the span of lines with a feedrate close to feedrate.
-                        for (PerExtruderAdjustments *adj : by_min_print_speed) {
-                            for (adj->idx_line_end = adj->idx_line_begin;
-                                adj->idx_line_end < adj->n_lines_adjustable && adj->lines[adj->idx_line_end].feedrate > feedrate - EPSILON;
-                                 ++ adj->idx_line_end) ;
-                        }
-                        // Find the next highest adjustable feedrate among the extruders.
-                        float feedrate_next = 0.f;
-                        for (PerExtruderAdjustments *adj : by_min_print_speed)
-                            if (adj->idx_line_end < adj->n_lines_adjustable && adj->lines[adj->idx_line_end].feedrate > feedrate_next)
-                                feedrate_next = adj->lines[adj->idx_line_end].feedrate;
-                        // Slow down, limited by max(feedrate_next, min_print_speed).
-                        for (auto adj = by_min_print_speed.begin(); adj != by_min_print_speed.end();) {
-                            float feedrate_limit = std::max(feedrate_next, (*adj)->min_print_speed);
-                            if (feedrate_limit == 0.f) {
-                                float adjustable_time = 0.f;
-                                for (auto it = adj; it != by_min_print_speed.end(); ++ it)
-                                    adjustable_time += (*it)->adjustable_time(true);
-                                float ratio = (adjustable_time + time_stretch) / adjustable_time;
-                                for (auto it = adj; it != by_min_print_speed.end(); ++ it)
-                                    (*it)->slow_down_proportional(ratio, true);
-                                // Break from two levels of loops.
-                                feedrate_next = 0.f;
-                                break;
-                            } else {
-                                float time_stretch_max = 0.f;
-                                for (auto it = adj; it != by_min_print_speed.end(); ++ it)
-                                    time_stretch_max += (*it)->time_stretch_when_slowing_down_to(feedrate_limit);
-    							bool done = false;
-    							if (time_stretch_max > time_stretch) {
-    								feedrate_limit = feedrate - (feedrate - feedrate_limit) * time_stretch / time_stretch_max;
-    								done = true;
-    							}
-                                for (auto it = adj; it != by_min_print_speed.end(); ++ it)
-                                    (*it)->slow_down_to(feedrate_limit);
-    							if (done) {
-    								// Break from two levels of loops.
-    								feedrate_next = 0.f;
-    								break;
-    							}
-                                time_stretch -= time_stretch_max;
-                            }
-                            // Skip the other extruders with nearly the same min_print_speed, as they have been processed already.
-                            auto next = adj;
-                            for (++ next; next != by_min_print_speed.end() && (*next)->min_print_speed > (*adj)->min_print_speed - EPSILON; ++ next);
-                            adj = next;
-                        }
-                        if (feedrate_next == 0.f)
-                            // There are no other extrusions available for slow down.
-                            break;
-                        for (PerExtruderAdjustments *adj : by_min_print_speed) {
-                            adj->idx_line_begin = adj->idx_line_end;
-                            feedrate = feedrate_next;
-                        }
-                    }
-#endif
-                } else {
-                    // Slow down to maximum possible.
-                    FORALL_UNPROCESSED(total, slow_down_maximum(true));
-                }
+                // Slow down to maximum possible.
+                for (auto it = cur_begin; it != by_slowdown_time.end(); ++ it)
+                    (*it)->slowdown_to_minimum_feedrate(true);
             }
-            #undef FORALL_UNPROCESSED
-            // Sum the final elapsed time for all extruders up to i_extruder_by_slowdown_time.
-            if (i_extruder_by_slowdown_time + 1 == extruder_by_slowdown_time.size())
-                // Optimization for single extruder prints.
-                elapsed_time_total0 = total;
-            else
-                elapsed_time_total0 += per_extruder_adjustments[idx].elapsed_time_total();
         }
-        elapsed_time_total = elapsed_time_total0;
+        elapsed_time_total0 += adj.elapsed_time_total();
     }
 
-    // Transform the G-code.
-    // First sort the adjustment lines by their position in the source G-code.
+    return elapsed_time_total0;
+}
+
+// Apply slow down over G-code lines stored in per_extruder_adjustments, enable fan if needed.
+// Returns the adjusted G-code.
+std::string CoolingBuffer::apply_layer_cooldown(
+    // Source G-code for the current layer.
+    const std::string                      &gcode,
+    // ID of the current layer, used to disable fan for the first n layers.
+    size_t                                  layer_id, 
+    // Total time of this layer after slow down, used to control the fan.
+    float                                   layer_time,
+    // Per extruder list of G-code lines and their cool down attributes.
+    std::vector<PerExtruderAdjustments>    &per_extruder_adjustments)
+{
+    // First sort the adjustment lines by of multiple extruders by their position in the source G-code.
     std::vector<const CoolingLine*> lines;
     {
         size_t n_lines = 0;
@@ -545,8 +609,9 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
     int  fan_speed          = -1;
     bool bridge_fan_control = false;
     int  bridge_fan_speed   = 0;
-    auto change_extruder_set_fan = [ this, layer_id, elapsed_time_total, &new_gcode, &fan_speed, &bridge_fan_control, &bridge_fan_speed ]() {
+    auto change_extruder_set_fan = [ this, layer_id, layer_time, &new_gcode, &fan_speed, &bridge_fan_control, &bridge_fan_speed ]() {
         const FullPrintConfig &config = m_gcodegen.config();
+#define EXTRUDER_CONFIG(OPT) config.OPT.get_at(m_current_extruder)
         int min_fan_speed = EXTRUDER_CONFIG(min_fan_speed);
         int fan_speed_new = EXTRUDER_CONFIG(fan_always_on) ? min_fan_speed : 0;
         if (layer_id >= EXTRUDER_CONFIG(disable_fan_first_layers)) {
@@ -554,17 +619,18 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
             float slowdown_below_layer_time = float(EXTRUDER_CONFIG(slowdown_below_layer_time));
             float fan_below_layer_time      = float(EXTRUDER_CONFIG(fan_below_layer_time));
             if (EXTRUDER_CONFIG(cooling)) {
-                if (elapsed_time_total < slowdown_below_layer_time) {
+                if (layer_time < slowdown_below_layer_time) {
                     // Layer time very short. Enable the fan to a full throttle.
                     fan_speed_new = max_fan_speed;
-                } else if (elapsed_time_total < fan_below_layer_time) {
+                } else if (layer_time < fan_below_layer_time) {
                     // Layer time quite short. Enable the fan proportionally according to the current layer time.
-                    assert(elapsed_time_total >= slowdown_below_layer_time);
-                    double t = (elapsed_time_total - slowdown_below_layer_time) / (fan_below_layer_time - slowdown_below_layer_time);
+                    assert(layer_time >= slowdown_below_layer_time);
+                    double t = (layer_time - slowdown_below_layer_time) / (fan_below_layer_time - slowdown_below_layer_time);
                     fan_speed_new = int(floor(t * min_fan_speed + (1. - t) * max_fan_speed) + 0.5);
                 }
             }
             bridge_fan_speed   = EXTRUDER_CONFIG(bridge_fan_speed);
+#undef EXTRUDER_CONFIG
             bridge_fan_control = bridge_fan_speed > fan_speed_new;
         } else {
             bridge_fan_control = false;
@@ -576,10 +642,11 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
             new_gcode += m_gcodegen.writer().set_fan(fan_speed);
         }
     };
-	change_extruder_set_fan();
 
-    const char *pos              = gcode.c_str();
-    int         current_feedrate = 0;
+    const char         *pos               = gcode.c_str();
+    int                 current_feedrate  = 0;
+    const std::string   toolchange_prefix = m_gcodegen.writer().toolchange_prefix();
+    change_extruder_set_fan();
     for (const CoolingLine *line : lines) {
         const char *line_start  = gcode.c_str() + line->line_start;
         const char *line_end    = gcode.c_str() + line->line_end;
@@ -602,9 +669,9 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
             // Just remove this comment.
         } else if (line->type & (CoolingLine::TYPE_ADJUSTABLE | CoolingLine::TYPE_EXTERNAL_PERIMETER | CoolingLine::TYPE_WIPE | CoolingLine::TYPE_HAS_F)) {
             // Find the start of a comment, or roll to the end of line.
-			const char *end = line_start;
-			for (; end < line_end && *end != ';'; ++ end);
-			// Find the 'F' word.
+            const char *end = line_start;
+            for (; end < line_end && *end != ';'; ++ end);
+            // Find the 'F' word.
             const char *fpos            = strstr(line_start + 2, " F") + 2;
             int         new_feedrate    = current_feedrate;
             bool        modify          = false;
@@ -643,7 +710,7 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
                     new_gcode.append(line_start, f - line_start + 1);
                 }
                 // Skip the non-whitespaces of the F parameter up the comment or end of line.
-				for (; fpos != end && *fpos != ' ' && *fpos != ';' && *fpos != '\n'; ++fpos);
+                for (; fpos != end && *fpos != ' ' && *fpos != ';' && *fpos != '\n'; ++fpos);
                 // Append the rest of the line without the comment.
                 if (fpos < end)
                     new_gcode.append(fpos, end - fpos);
@@ -653,21 +720,21 @@ std::string CoolingBuffer::process_layer(const std::string &gcode, size_t layer_
             // Process the rest of the line.
             if (end < line_end) {
                 if (line->type & (CoolingLine::TYPE_ADJUSTABLE | CoolingLine::TYPE_EXTERNAL_PERIMETER | CoolingLine::TYPE_WIPE)) {
-					// Process comments, remove ";_EXTRUDE_SET_SPEED", ";_EXTERNAL_PERIMETER", ";_WIPE"
-					std::string comment(end, line_end);
-					boost::replace_all(comment, ";_EXTRUDE_SET_SPEED", "");
+                    // Process comments, remove ";_EXTRUDE_SET_SPEED", ";_EXTERNAL_PERIMETER", ";_WIPE"
+                    std::string comment(end, line_end);
+                    boost::replace_all(comment, ";_EXTRUDE_SET_SPEED", "");
                     if (line->type & CoolingLine::TYPE_EXTERNAL_PERIMETER)
                         boost::replace_all(comment, ";_EXTERNAL_PERIMETER", "");
                     if (line->type & CoolingLine::TYPE_WIPE)
                         boost::replace_all(comment, ";_WIPE", "");
-					new_gcode += comment;
-				} else {
-					// Just attach the rest of the source line.
-					new_gcode.append(end, line_end - end);
-				}
+                    new_gcode += comment;
+                } else {
+                    // Just attach the rest of the source line.
+                    new_gcode.append(end, line_end - end);
+                }
             }
         } else {
-			new_gcode.append(line_start, line_end - line_start);
+            new_gcode.append(line_start, line_end - line_start);
         }
         pos = line_end;
     }
diff --git a/xs/src/libslic3r/GCode/CoolingBuffer.hpp b/xs/src/libslic3r/GCode/CoolingBuffer.hpp
index f85c470b3..bf4b082e2 100644
--- a/xs/src/libslic3r/GCode/CoolingBuffer.hpp
+++ b/xs/src/libslic3r/GCode/CoolingBuffer.hpp
@@ -9,13 +9,17 @@ namespace Slic3r {
 
 class GCode;
 class Layer;
+class PerExtruderAdjustments;
 
-/*
-A standalone G-code filter, to control cooling of the print.
-The G-code is processed per layer. Once a layer is collected, fan start / stop commands are edited
-and the print is modified to stretch over a minimum layer time.
-*/
-
+// A standalone G-code filter, to control cooling of the print.
+// The G-code is processed per layer. Once a layer is collected, fan start / stop commands are edited
+// and the print is modified to stretch over a minimum layer time.
+//
+// The simple it sounds, the actual implementation is significantly more complex.
+// Namely, for a multi-extruder print, each material may require a different cooling logic.
+// For example, some materials may not like to print too slowly, while with some materials 
+// we may slow down significantly.
+//
 class CoolingBuffer {
 public:
     CoolingBuffer(GCode &gcodegen);
@@ -25,7 +29,12 @@ public:
     GCode* 	    gcodegen() { return &m_gcodegen; }
 
 private:
-	CoolingBuffer& operator=(const CoolingBuffer&);
+	CoolingBuffer& operator=(const CoolingBuffer&) = delete;
+    std::vector<PerExtruderAdjustments> parse_layer_gcode(const std::string &gcode, std::vector<float> &current_pos) const;
+    float       calculate_layer_slowdown(std::vector<PerExtruderAdjustments> &per_extruder_adjustments);
+    // Apply slow down over G-code lines stored in per_extruder_adjustments, enable fan if needed.
+    // Returns the adjusted G-code.
+    std::string apply_layer_cooldown(const std::string &gcode, size_t layer_id, float layer_time, std::vector<PerExtruderAdjustments> &per_extruder_adjustments);
 
     GCode&              m_gcodegen;
     std::string         m_gcode;
@@ -34,6 +43,9 @@ private:
     std::vector<char>   m_axis;
     std::vector<float>  m_current_pos;
     unsigned int        m_current_extruder;
+
+    // Old logic: proportional.
+    bool                m_cooling_logic_proportional = false;
 };
 
 }

From 25d47c1da8bac02d5b1408d9a39ba7356b14fc56 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Thu, 26 Apr 2018 18:56:16 +0200
Subject: [PATCH 07/12] Fix of the new cooling logic.

---
 xs/src/libslic3r/GCode/CoolingBuffer.cpp | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/xs/src/libslic3r/GCode/CoolingBuffer.cpp b/xs/src/libslic3r/GCode/CoolingBuffer.cpp
index 141d197ca..b786f9bce 100644
--- a/xs/src/libslic3r/GCode/CoolingBuffer.cpp
+++ b/xs/src/libslic3r/GCode/CoolingBuffer.cpp
@@ -50,7 +50,7 @@ struct CoolingLine
 
     CoolingLine(unsigned int type, size_t  line_start, size_t  line_end) :
         type(type), line_start(line_start), line_end(line_end),
-        length(0.f), time(0.f), time_max(0.f), slowdown(false) {}
+        length(0.f), feedrate(0.f), time(0.f), time_max(0.f), slowdown(false) {}
 
     bool adjustable(bool slowdown_external_perimeters) const {
         return (this->type & TYPE_ADJUSTABLE) && 
@@ -158,9 +158,9 @@ struct PerExtruderAdjustments
             bool adj2 = l2.adjustable();
             return (adj1 == adj2) ? l1.feedrate > l2.feedrate : adj1;
         });
-        for (n_lines_adjustable = 0; n_lines_adjustable < lines.size(); ++ n_lines_adjustable)
-            if ((this->lines[n_lines_adjustable].type & CoolingLine::TYPE_ADJUSTABLE) == 0)
-                break;
+        for (n_lines_adjustable = 0; 
+            n_lines_adjustable < lines.size() && this->lines[n_lines_adjustable].adjustable();
+            ++ n_lines_adjustable);
         time_non_adjustable = 0.f;
         for (size_t i = n_lines_adjustable; i < lines.size(); ++ i)
             time_non_adjustable += lines[i].time;
@@ -329,10 +329,10 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
                     // Movement in the extruder axis.
                     line.length = std::abs(dif[3]);
                 }
-                if (line.length > 0) {
-                    line.feedrate = new_pos[4]; // current F
-                    line.time   = line.length / line.feedrate;
-                }
+                line.feedrate = new_pos[4];
+                assert((line.type & CoolingLine::TYPE_ADJUSTABLE) == 0 || line.feedrate > 0.f);
+                if (line.length > 0)
+                    line.time = line.length / line.feedrate;
                 line.time_max = line.time;
                 if ((line.type & CoolingLine::TYPE_ADJUSTABLE) || active_speed_modifier != size_t(-1))
                     line.time_max = (adjustment->min_print_speed == 0.f) ? FLT_MAX : std::max(line.time, line.length / adjustment->min_print_speed);
@@ -340,6 +340,7 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
                     // Inside the ";_EXTRUDE_SET_SPEED" blocks, there must not be a G1 Fxx entry.
                     assert((line.type & CoolingLine::TYPE_HAS_F) == 0);
                     CoolingLine &sm = adjustment->lines[active_speed_modifier];
+                    assert(sm.feedrate > 0.f);
                     sm.length   += line.length;
                     sm.time     += line.time;
                     if (sm.time_max != FLT_MAX) {

From 4811abfa99a6286c2dbedc41bc7801fffd21af7f Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Fri, 27 Apr 2018 09:54:21 +0200
Subject: [PATCH 08/12] Apply gradient to colors in GCode Preview

---
 xs/src/libslic3r/GCode/PreviewData.cpp | 40 +++++++++++++++++---------
 xs/src/libslic3r/GCode/PreviewData.hpp | 11 ++++---
 2 files changed, 32 insertions(+), 19 deletions(-)

diff --git a/xs/src/libslic3r/GCode/PreviewData.cpp b/xs/src/libslic3r/GCode/PreviewData.cpp
index c66de08ed..d431708c1 100644
--- a/xs/src/libslic3r/GCode/PreviewData.cpp
+++ b/xs/src/libslic3r/GCode/PreviewData.cpp
@@ -99,17 +99,31 @@ void GCodePreviewData::Range::set_from(const Range& other)
 
 float GCodePreviewData::Range::step_size() const
 {
-    return (max - min) / (float)Colors_Count;
+    return (max - min) / (float)(Colors_Count - 1);
 }
 
-const GCodePreviewData::Color& GCodePreviewData::Range::get_color_at_max() const
+GCodePreviewData::Color GCodePreviewData::Range::get_color_at(float value) const
 {
-    return colors[Colors_Count - 1];
-}
+    if (empty())
+        return Color::Dummy;
 
-const GCodePreviewData::Color& GCodePreviewData::Range::get_color_at(float value) const
-{
-    return empty() ? get_color_at_max() : colors[clamp((unsigned int)0, Colors_Count - 1, (unsigned int)((value - min) / step_size()))];
+    float global_t = (value - min) / step_size();
+
+    unsigned int low = (unsigned int)global_t;
+    unsigned int high = clamp((unsigned int)0, Colors_Count - 1, low + 1);
+
+    Color color_low = colors[low];
+    Color color_high = colors[high];
+
+    float local_t = global_t - (float)low;
+
+    // interpolate in RGB space
+    Color ret;
+    for (unsigned int i = 0; i < 4; ++i)
+    {
+        ret.rgba[i] = lerp(color_low.rgba[i], color_high.rgba[i], local_t);
+    }
+    return ret;
 }
 
 GCodePreviewData::LegendItem::LegendItem(const std::string& text, const GCodePreviewData::Color& color)
@@ -266,22 +280,22 @@ const GCodePreviewData::Color& GCodePreviewData::get_extrusion_role_color(Extrus
     return extrusion.role_colors[role];
 }
 
-const GCodePreviewData::Color& GCodePreviewData::get_height_color(float height) const
+GCodePreviewData::Color GCodePreviewData::get_height_color(float height) const
 {
     return ranges.height.get_color_at(height);
 }
 
-const GCodePreviewData::Color& GCodePreviewData::get_width_color(float width) const
+GCodePreviewData::Color GCodePreviewData::get_width_color(float width) const
 {
     return ranges.width.get_color_at(width);
 }
 
-const GCodePreviewData::Color& GCodePreviewData::get_feedrate_color(float feedrate) const
+GCodePreviewData::Color GCodePreviewData::get_feedrate_color(float feedrate) const
 {
     return ranges.feedrate.get_color_at(feedrate);
 }
 
-const GCodePreviewData::Color& GCodePreviewData::get_volumetric_rate_color(float rate) const
+GCodePreviewData::Color GCodePreviewData::get_volumetric_rate_color(float rate) const
 {
     return ranges.volumetric_rate.get_color_at(rate);
 }
@@ -373,7 +387,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
             for (int i = Range::Colors_Count - 1; i >= 0; --i)
             {
                 char buf[1024];
-                sprintf(buf, "%.*f/%.*f", decimals, scale_factor * (range.min + (float)i * step), decimals, scale_factor * (range.min + (float)(i + 1) * step));
+                sprintf(buf, "%.*f", decimals, scale_factor * (range.min + (float)i * step));
                 list.emplace_back(buf, range.colors[i]);
             }
         }
@@ -408,7 +422,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
         }
     case Extrusion::Feedrate:
         {
-            Helper::FillListFromRange(items, ranges.feedrate, 0, 1.0f);
+            Helper::FillListFromRange(items, ranges.feedrate, 1, 1.0f);
             break;
         }
     case Extrusion::VolumetricRate:
diff --git a/xs/src/libslic3r/GCode/PreviewData.hpp b/xs/src/libslic3r/GCode/PreviewData.hpp
index e9c5f7515..a7d77e0b9 100644
--- a/xs/src/libslic3r/GCode/PreviewData.hpp
+++ b/xs/src/libslic3r/GCode/PreviewData.hpp
@@ -41,8 +41,7 @@ public:
         void set_from(const Range& other);
         float step_size() const;
 
-        const Color& get_color_at(float value) const;
-        const Color& get_color_at_max() const;
+        Color get_color_at(float value) const;
     };
 
     struct Ranges
@@ -189,10 +188,10 @@ public:
     bool empty() const;
 
     const Color& get_extrusion_role_color(ExtrusionRole role) const;
-    const Color& get_height_color(float height) const;
-    const Color& get_width_color(float width) const;
-    const Color& get_feedrate_color(float feedrate) const;
-    const Color& get_volumetric_rate_color(float rate) const;
+    Color get_height_color(float height) const;
+    Color get_width_color(float width) const;
+    Color get_feedrate_color(float feedrate) const;
+    Color get_volumetric_rate_color(float rate) const;
 
     void set_extrusion_role_color(const std::string& role_name, float red, float green, float blue, float alpha);
     void set_extrusion_paths_colors(const std::vector<std::string>& colors);

From 6d38943222d45415316e102c14119c837bef499c Mon Sep 17 00:00:00 2001
From: Vojtech Kral <vojtech@kral.hk>
Date: Fri, 27 Apr 2018 12:29:18 +0200
Subject: [PATCH 09/12] Fix & refactor legacy datadir dialog

---
 xs/src/slic3r/GUI/GUI.cpp           | 21 +++----------------
 xs/src/slic3r/GUI/UpdateDialogs.cpp | 32 +++++++++++++++++++++++++++++
 xs/src/slic3r/GUI/UpdateDialogs.hpp | 12 +++++++++++
 3 files changed, 47 insertions(+), 18 deletions(-)

diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp
index 42a931033..6bac39bd7 100644
--- a/xs/src/slic3r/GUI/GUI.cpp
+++ b/xs/src/slic3r/GUI/GUI.cpp
@@ -53,6 +53,7 @@
 #include "ConfigWizard.hpp"
 #include "Preferences.hpp"
 #include "PresetBundle.hpp"
+#include "UpdateDialogs.hpp"
 
 #include "../Utils/PresetUpdater.hpp"
 #include "../Config/Snapshot.hpp"
@@ -480,24 +481,8 @@ bool config_wizard_startup(bool app_config_exists)
 		// Looks like user has legacy pre-vendorbundle data directory,
 		// explain what this is and run the wizard
 
-		const auto msg = _(L("Configuration update"));
-		const auto ext_msg = wxString::Format(
-			_(L(
-				"Slic3r PE now uses an updated configuration structure.\n\n"
-
-				"So called 'System presets' have been introduced, which hold the built-in default settings for various "
-				"printers. These System presets cannot be modified, instead, users now may create their"
-				"own presets inheriting settings from one of the System presets.\n"
-				"An inheriting preset may either inherit a particular value from its parent or override it with a customized value.\n\n"
-
-				"Please proceed with the %s that follows to set up the new presets "
-				"and to choose whether to enable automatic preset updates."
-			)),
-			ConfigWizard::name()
-		);
-		wxMessageDialog dlg(NULL, msg, _(L("Configuration update")), wxOK|wxCENTRE);
-		dlg.SetExtendedMessage(ext_msg);
-		const auto res = dlg.ShowModal();
+		MsgDataLegacy dlg;
+		dlg.ShowModal();
 
 		config_wizard(ConfigWizard::RR_DATA_LEGACY);
 		return true;
diff --git a/xs/src/slic3r/GUI/UpdateDialogs.cpp b/xs/src/slic3r/GUI/UpdateDialogs.cpp
index e11ecdf5e..62534e598 100644
--- a/xs/src/slic3r/GUI/UpdateDialogs.cpp
+++ b/xs/src/slic3r/GUI/UpdateDialogs.cpp
@@ -12,6 +12,7 @@
 #include "libslic3r/libslic3r.h"
 #include "libslic3r/Utils.hpp"
 #include "GUI.hpp"
+#include "ConfigWizard.hpp"
 
 namespace Slic3r {
 namespace GUI {
@@ -201,5 +202,36 @@ MsgDataIncompatible::MsgDataIncompatible(const std::unordered_map<std::string, w
 MsgDataIncompatible::~MsgDataIncompatible() {}
 
 
+// MsgDataLegacy
+
+MsgDataLegacy::MsgDataLegacy() :
+	MsgDialog(_(L("Configuration update")), _(L("Configuration update")))
+{
+	auto *text = new wxStaticText(this, wxID_ANY, wxString::Format(
+		_(L(
+			"Slic3r PE now uses an updated configuration structure.\n\n"
+
+			"So called 'System presets' have been introduced, which hold the built-in default settings for various "
+			"printers. These System presets cannot be modified, instead, users now may create their "
+			"own presets inheriting settings from one of the System presets.\n"
+			"An inheriting preset may either inherit a particular value from its parent or override it with a customized value.\n\n"
+
+			"Please proceed with the %s that follows to set up the new presets "
+			"and to choose whether to enable automatic preset updates."
+		)),
+		ConfigWizard::name()
+	));
+	text->Wrap(CONTENT_WIDTH);
+	content_sizer->Add(text);
+	content_sizer->AddSpacer(VERT_SPACING);
+
+	// TODO: Add link to wiki?
+
+	Fit();
+}
+
+MsgDataLegacy::~MsgDataLegacy() {}
+
+
 }
 }
diff --git a/xs/src/slic3r/GUI/UpdateDialogs.hpp b/xs/src/slic3r/GUI/UpdateDialogs.hpp
index f12fd3333..e339fbe0d 100644
--- a/xs/src/slic3r/GUI/UpdateDialogs.hpp
+++ b/xs/src/slic3r/GUI/UpdateDialogs.hpp
@@ -85,6 +85,18 @@ public:
 	~MsgDataIncompatible();
 };
 
+// Informs about a legacy data directory - an update from Slic3r PE < 1.40
+class MsgDataLegacy : public MsgDialog
+{
+public:
+	MsgDataLegacy();
+	MsgDataLegacy(MsgDataLegacy &&) = delete;
+	MsgDataLegacy(const MsgDataLegacy &) = delete;
+	MsgDataLegacy &operator=(MsgDataLegacy &&) = delete;
+	MsgDataLegacy &operator=(const MsgDataLegacy &) = delete;
+	~MsgDataLegacy();
+};
+
 
 }
 }

From ad54210c3ee75f148bd98d1f8f773a3986dff008 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Fri, 27 Apr 2018 12:56:35 +0200
Subject: [PATCH 10/12] 3mf I/O - Added import/export of layer heights profile

---
 xs/src/libslic3r/Format/3mf.cpp | 166 ++++++++++++++++++++++++++++----
 1 file changed, 146 insertions(+), 20 deletions(-)

diff --git a/xs/src/libslic3r/Format/3mf.cpp b/xs/src/libslic3r/Format/3mf.cpp
index 7b5bf7e8a..dde64a28f 100644
--- a/xs/src/libslic3r/Format/3mf.cpp
+++ b/xs/src/libslic3r/Format/3mf.cpp
@@ -23,6 +23,7 @@ const std::string CONTENT_TYPES_FILE = "[Content_Types].xml";
 const std::string RELATIONSHIPS_FILE = "_rels/.rels";
 const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config";
 const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config";
+const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt";
 
 const char* MODEL_TAG = "model";
 const char* RESOURCES_TAG = "resources";
@@ -315,6 +316,7 @@ namespace Slic3r {
         typedef std::vector<Instance> InstancesList;
         typedef std::map<int, ObjectMetadata> IdToMetadataMap;
         typedef std::map<int, Geometry> IdToGeometryMap;
+        typedef std::map<int, std::vector<coordf_t>> IdToLayerHeightsProfileMap;
 
         XML_Parser m_xml_parser;
         Model* m_model;
@@ -326,6 +328,7 @@ namespace Slic3r {
         IdToGeometryMap m_geometries;
         CurrentConfig m_curr_config;
         IdToMetadataMap m_objects_metadata;
+        IdToLayerHeightsProfileMap m_layer_heights_profiles;
 
     public:
         _3MF_Importer();
@@ -339,7 +342,8 @@ namespace Slic3r {
 
         bool _load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle);
         bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
-        bool _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, PresetBundle& bundle, const std::string& archive_filename);
+        void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
+        void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, PresetBundle& bundle, const std::string& archive_filename);
         bool _extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model);
 
         // handlers to parse the .model file
@@ -437,6 +441,7 @@ namespace Slic3r {
         m_curr_config.object_id = -1;
         m_curr_config.volume_id = -1;
         m_objects_metadata.clear();
+        m_layer_heights_profiles.clear();
         clear_errors();
 
         return _load_model_from_file(filename, model, bundle);
@@ -489,15 +494,15 @@ namespace Slic3r {
                         return false;
                     }
                 }
+                else if (boost::algorithm::iequals(name, LAYER_HEIGHTS_PROFILE_FILE))
+                {
+                    // extract slic3r lazer heights profile file
+                    _extract_layer_heights_profile_config_from_archive(archive, stat);
+                }
                 else if (boost::algorithm::iequals(name, PRINT_CONFIG_FILE))
                 {
                     // extract slic3r print config file
-                    if (!_extract_print_config_from_archive(archive, stat, bundle, filename))
-                    {
-                        mz_zip_reader_end(&archive);
-                        add_error("Archive does not contain a valid print config");
-                        return false;
-                    }
+                    _extract_print_config_from_archive(archive, stat, bundle, filename);
                 }
                 else if (boost::algorithm::iequals(name, MODEL_CONFIG_FILE))
                 {
@@ -526,6 +531,13 @@ namespace Slic3r {
                 return false;
             }
 
+            IdToLayerHeightsProfileMap::iterator obj_layer_heights_profile = m_layer_heights_profiles.find(object.first);
+            if (obj_layer_heights_profile != m_layer_heights_profiles.end())
+            {
+                object.second->layer_height_profile = obj_layer_heights_profile->second;
+                object.second->layer_height_profile_valid = true;
+            }
+
             IdToMetadataMap::iterator obj_metadata = m_objects_metadata.find(object.first);
             if (obj_metadata != m_objects_metadata.end())
             {
@@ -609,23 +621,90 @@ namespace Slic3r {
         return true;
     }
 
-    bool _3MF_Importer::_extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, PresetBundle& bundle, const std::string& archive_filename)
+    void _3MF_Importer::_extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, PresetBundle& bundle, const std::string& archive_filename)
     {
         if (stat.m_uncomp_size > 0)
         {
-            std::vector<char> buffer((size_t)stat.m_uncomp_size + 1, 0);
+            std::string buffer((size_t)stat.m_uncomp_size, 0);
             mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
             if (res == 0)
             {
                 add_error("Error while reading config data to buffer");
-                return false;
+                return;
             }
-
-            buffer.back() = '\0';
             bundle.load_config_string(buffer.data(), archive_filename.c_str());
         }
+    }
 
-        return true;
+    void _3MF_Importer::_extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
+    {
+        if (stat.m_uncomp_size > 0)
+        {
+            std::string buffer((size_t)stat.m_uncomp_size, 0);
+            mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
+            if (res == 0)
+            {
+                add_error("Error while reading layer heights profile data to buffer");
+                return;
+            }
+
+            if (buffer.back() == '\n')
+                buffer.pop_back();
+
+            std::vector<std::string> objects;
+            boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off);
+
+            for (const std::string& object : objects)
+            {
+                std::vector<std::string> object_data;
+                boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off);
+                if (object_data.size() != 2)
+                {
+                    add_error("Error while reading object data");
+                    continue;
+                }
+
+                std::vector<std::string> object_data_id;
+                boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off);
+                if (object_data_id.size() != 2)
+                {
+                    add_error("Error while reading object id");
+                    continue;
+                }
+
+                int object_id = std::atoi(object_data_id[1].c_str());
+                if (object_id == 0)
+                {
+                    add_error("Found invalid object id");
+                    continue;
+                }
+
+                IdToLayerHeightsProfileMap::iterator object_item = m_layer_heights_profiles.find(object_id);
+                if (object_item != m_layer_heights_profiles.end())
+                {
+                    add_error("Found duplicated layer heights profile");
+                    continue;
+                }
+
+                std::vector<std::string> object_data_profile;
+                boost::split(object_data_profile, object_data[1], boost::is_any_of(";"), boost::token_compress_off);
+                if ((object_data_profile.size() <= 4) || (object_data_profile.size() % 2 != 0))
+                {
+                    add_error("Found invalid layer heights profile");
+                    continue;
+                }
+
+                std::vector<coordf_t> profile;
+                profile.reserve(object_data_profile.size());
+
+                for (const std::string& value : object_data_profile)
+                {
+                    profile.push_back((coordf_t)std::atof(value.c_str()));
+                }
+
+                m_layer_heights_profiles.insert(IdToLayerHeightsProfileMap::value_type(object_id, profile));
+            }
+        }
     }
 
     bool _3MF_Importer::_extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model)
@@ -1429,6 +1508,7 @@ namespace Slic3r {
         bool _add_object_to_model_stream(std::stringstream& stream, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items, VolumeToOffsetsMap& volumes_offsets);
         bool _add_mesh_to_object_stream(std::stringstream& stream, ModelObject& object, VolumeToOffsetsMap& volumes_offsets);
         bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items);
+        bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model);
         bool _add_print_config_file_to_archive(mz_zip_archive& archive, const Print& print);
         bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model);
     };
@@ -1477,6 +1557,14 @@ namespace Slic3r {
             return false;
         }
 
+        // adds layer height profile file
+        if (!_add_layer_height_profile_file_to_archive(archive, model))
+        {
+            mz_zip_writer_end(&archive);
+            boost::filesystem::remove(filename);
+            return false;
+        }
+
         // adds slic3r print config file
         if (export_print_config)
         {
@@ -1736,6 +1824,44 @@ namespace Slic3r {
         return true;
     }
 
+    bool _3MF_Exporter::_add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model)
+    {
+        std::string out = "";
+        char buffer[1024];
+
+        unsigned int count = 0;
+        for (const ModelObject* object : model.objects)
+        {
+            ++count;
+            std::vector<double> layer_height_profile = object->layer_height_profile_valid ? object->layer_height_profile : std::vector<double>();
+            if ((layer_height_profile.size() >= 4) && ((layer_height_profile.size() % 2) == 0))
+            {
+                sprintf(buffer, "object_id=%d|", count);
+                out += buffer;
+
+                // Store the layer height profile as a single semicolon separated list.
+                for (size_t i = 0; i < layer_height_profile.size(); ++i)
+                {
+                    sprintf(buffer, (i == 0) ? "%f" : ";%f", layer_height_profile[i]);
+                    out += buffer;
+                }
+                
+                out += "\n";
+            }
+        }
+
+        if (!out.empty())
+        {
+            if (!mz_zip_writer_add_mem(&archive, LAYER_HEIGHTS_PROFILE_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
+            {
+                add_error("Unable to add layer heights profile file to archive");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     bool _3MF_Exporter::_add_print_config_file_to_archive(mz_zip_archive& archive, const Print& print)
     {
         char buffer[1024];
@@ -1744,10 +1870,13 @@ namespace Slic3r {
 
         GCode::append_full_config(print, out);
 
-        if (!mz_zip_writer_add_mem(&archive, PRINT_CONFIG_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
+        if (!out.empty())
         {
-            add_error("Unable to add print config file to archive");
-            return false;
+            if (!mz_zip_writer_add_mem(&archive, PRINT_CONFIG_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
+            {
+                add_error("Unable to add print config file to archive");
+                return false;
+            }
         }
 
         return true;
@@ -1832,10 +1961,7 @@ namespace Slic3r {
 
         _3MF_Importer importer;
         bool res = importer.load_model_from_file(path, *model, *bundle);
-
-        if (!res)
-            importer.log_errors();
-
+        importer.log_errors();
         return res;
     }
 

From b67064ef81334eec4769d35da4285af97b2fe07a Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Fri, 27 Apr 2018 14:08:22 +0200
Subject: [PATCH 11/12] Keyboard capture by 3D view on Linux

---
 lib/Slic3r/GUI/3DScene.pm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm
index 190e96052..17fcd4624 100644
--- a/lib/Slic3r/GUI/3DScene.pm
+++ b/lib/Slic3r/GUI/3DScene.pm
@@ -389,7 +389,7 @@ sub mouse_event {
 
     $self->_mouse_dragging($e->Dragging);
     
-    if ($e->Entering && &Wx::wxMSW) {
+    if ($e->Entering && (&Wx::wxMSW || $^O eq 'linux')) {
         # wxMSW needs focus in order to catch mouse wheel events
         $self->SetFocus;
         $self->_drag_start_xy(undef);        

From 285ded8bbbb2be86d1be57cff948f56597672aa6 Mon Sep 17 00:00:00 2001
From: Vojtech Kral <vojtech@kral.hk>
Date: Fri, 27 Apr 2018 15:19:07 +0200
Subject: [PATCH 12/12] Add documentation for system profiles, snapshots &
 updating

---
 doc/updating/Updatig.md           |  52 ++++++++++++++++++++++++++++++
 doc/updating/setting_mod.png      | Bin 0 -> 4050 bytes
 doc/updating/setting_sys.png      | Bin 0 -> 3863 bytes
 doc/updating/setting_user.png     | Bin 0 -> 3957 bytes
 doc/updating/snapshots_dialog.png | Bin 0 -> 78805 bytes
 5 files changed, 52 insertions(+)
 create mode 100644 doc/updating/Updatig.md
 create mode 100644 doc/updating/setting_mod.png
 create mode 100644 doc/updating/setting_sys.png
 create mode 100644 doc/updating/setting_user.png
 create mode 100644 doc/updating/snapshots_dialog.png

diff --git a/doc/updating/Updatig.md b/doc/updating/Updatig.md
new file mode 100644
index 000000000..3ce1f109c
--- /dev/null
+++ b/doc/updating/Updatig.md
@@ -0,0 +1,52 @@
+# Slic3r PE 1.40 configuration update
+
+Slic3r PE 1.40.0 comes with a major re-work of the way configuration presets work.
+There are three new features:
+
++ A two-tier system of presets being divided into _System_ and _User_ groups
++ Configuration snapshots
++ Configuration updating from the internet
+
+## System and User presets
+
+- _System preset_: These are the presets that come with Slic3r PE installation. They come from a vendor configuration bundle (not individual files like before). They are **read-only** – a user cannot modify them, but may instead create a derived User preset based on a System preset
+- _User preset_: These are regular presets stored in files just like before. Additionally, they may be derived (inherited) from one of the System presets
+
+A derived User preset keeps track of wich settings are inherited from the parent System preset and which are modified by the user. When a system preset is updated (either via installation of a new Slic3r or automatically from the internet), in a User preset the settings that are modified by the user will stay that way, while the ones that are inherited reflect the updated System preset.
+
+This system ensures that we don't overwrite user's settings when there is an update to the built in presets.
+
+Slic3r GUI now displays accurately which settings are inherited and which are modified.
+A setting derived from a System preset is represeted by green label and a locked lock icon:
+
+![a system setting](setting_sys.png)
+
+A settings modified in a User preset has an open lock icon:
+
+![a user setting](setting_user.png)
+
+Clickign the open lock icon restored the system setting.
+
+Additionaly, any setting that is modified but not yet saved onto disk is represented by orange label and a back-arrow:
+
+![a modified setting](setting_mod.png)
+
+Clicking the back-arrow restores the value that was previously saved in this Preset.
+
+## Configuration snapshots
+
+Configuration snapshots can now be taken via the _Configuration_ menu.
+A snapshot contains complete configuration from the point when the snapshot was taken.
+Users may move back and forth between snapshots at will using a dialog:
+
+![snapshots dialog](snapshots_dialog.png)
+
+
+# Updating from the internet
+
+Slic3r PE 1.40.0 checks for updates of the built-in System presets and downloads them.
+The first-time configuration assistant will ask you if you want to enable this feature - it is **not** mandatory.
+
+Updates are checked for and downloaded in the background. If there's is an update, Slic3r will prompt about it 
+next time it is launched, never during normal program operation. An update may be either accepted or refused.
+Before any update is applied a configuration snapshot (as described above) is taken.
diff --git a/doc/updating/setting_mod.png b/doc/updating/setting_mod.png
new file mode 100644
index 0000000000000000000000000000000000000000..e4d3b7e7bd40138e235882b131e1a9b1b7f46c97
GIT binary patch
literal 4050
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

literal 0
HcmV?d00001

diff --git a/doc/updating/setting_sys.png b/doc/updating/setting_sys.png
new file mode 100644
index 0000000000000000000000000000000000000000..842a8bf736350d3934fa7998ac552d6ab898c330
GIT binary patch
literal 3863
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
V=N@Fvgr0G)F2qp#hvxG){{!@3fLQ<l

literal 0
HcmV?d00001

diff --git a/doc/updating/setting_user.png b/doc/updating/setting_user.png
new file mode 100644
index 0000000000000000000000000000000000000000..ffec5e0f3e27120225de03786328b36fd462d459
GIT binary patch
literal 3957
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
HeI5QkK~k^x

literal 0
HcmV?d00001

diff --git a/doc/updating/snapshots_dialog.png b/doc/updating/snapshots_dialog.png
new file mode 100644
index 0000000000000000000000000000000000000000..d4d28955057976f1310021e79600df0ed4681bb6
GIT binary patch
literal 78805
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
F{ul1$0T2KH

literal 0
HcmV?d00001