From 95795f249afc63da16a1cb901876e758259f4e09 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Thu, 24 May 2018 14:05:51 +0200
Subject: [PATCH] First steps in reorganizing infill order (to use infill
 instead of the wipe tower)

---
 xs/src/libslic3r/ExtrusionEntity.hpp          |  4 +++
 .../libslic3r/ExtrusionEntityCollection.cpp   |  1 +
 .../libslic3r/ExtrusionEntityCollection.hpp   | 16 +++++++++
 xs/src/libslic3r/GCode.cpp                    | 36 ++++++++++++++++---
 xs/src/libslic3r/Print.cpp                    | 20 +++++++++++
 5 files changed, 73 insertions(+), 4 deletions(-)

diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp
index 16ef51c1f..15363e8ed 100644
--- a/xs/src/libslic3r/ExtrusionEntity.hpp
+++ b/xs/src/libslic3r/ExtrusionEntity.hpp
@@ -92,6 +92,7 @@ public:
     virtual double min_mm3_per_mm() const = 0;
     virtual Polyline as_polyline() const = 0;
     virtual double length() const = 0;
+    virtual double total_volume() const = 0;
 };
 
 typedef std::vector<ExtrusionEntity*> ExtrusionEntitiesPtr;
@@ -148,6 +149,7 @@ public:
     // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
     double min_mm3_per_mm() const { return this->mm3_per_mm; }
     Polyline as_polyline() const { return this->polyline; }
+    virtual double total_volume() const { return mm3_per_mm * unscale(length()); }
 
 private:
     void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const;
@@ -194,6 +196,7 @@ public:
     // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
     double min_mm3_per_mm() const;
     Polyline as_polyline() const;
+    virtual double total_volume() const { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; }
 };
 
 // Single continuous extrusion loop, possibly with varying extrusion thickness, extrusion height or bridging / non bridging.
@@ -241,6 +244,7 @@ public:
     // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
     double min_mm3_per_mm() const;
     Polyline as_polyline() const { return this->polygon().split_at_first_point(); }
+    virtual double total_volume() const { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; }
 
 private:
     ExtrusionLoopRole m_loop_role;
diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.cpp b/xs/src/libslic3r/ExtrusionEntityCollection.cpp
index 4513139e2..7a086bcbf 100644
--- a/xs/src/libslic3r/ExtrusionEntityCollection.cpp
+++ b/xs/src/libslic3r/ExtrusionEntityCollection.cpp
@@ -125,6 +125,7 @@ void ExtrusionEntityCollection::chained_path_from(Point start_near, ExtrusionEnt
                 continue;
             }
         }
+
         ExtrusionEntity* entity = (*it)->clone();
         my_paths.push_back(entity);
         if (orig_indices != NULL) indices_map[entity] = it - this->entities.begin();
diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.hpp b/xs/src/libslic3r/ExtrusionEntityCollection.hpp
index 03bd2ba97..d292248fc 100644
--- a/xs/src/libslic3r/ExtrusionEntityCollection.hpp
+++ b/xs/src/libslic3r/ExtrusionEntityCollection.hpp
@@ -79,6 +79,7 @@ public:
     void flatten(ExtrusionEntityCollection* retval) const;
     ExtrusionEntityCollection flatten() const;
     double min_mm3_per_mm() const;
+    virtual double total_volume() const {double volume=0.; for (const auto& ent : entities) volume+=ent->total_volume(); return volume; }
 
     // Following methods shall never be called on an ExtrusionEntityCollection.
     Polyline as_polyline() const {
@@ -89,6 +90,21 @@ public:
         CONFESS("Calling length() on a ExtrusionEntityCollection");
         return 0.;        
     }
+
+    void set_extruder_override(int extruder) {
+        extruder_override = extruder;
+        for (auto& member : entities) {
+            if (member->is_collection())
+                dynamic_cast<ExtrusionEntityCollection*>(member)->set_extruder_override(extruder);
+        }
+    }
+    int get_extruder_override() const { return extruder_override; }
+    bool is_extruder_overridden() const { return extruder_override != -1; }
+
+
+private:
+    // Set this variable to explicitly state you want to use specific extruder for thie EEC (used for MM infill wiping)
+    int extruder_override = -1;
 };
 
 }
diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp
index b581b3e76..3536c0c9c 100644
--- a/xs/src/libslic3r/GCode.cpp
+++ b/xs/src/libslic3r/GCode.cpp
@@ -1249,7 +1249,7 @@ void GCode::process_layer(
                             break;
                         }
                 }
-                
+
                 // process infill
                 // layerm->fills is a collection of Slic3r::ExtrusionPath::Collection objects (C++ class ExtrusionEntityCollection), 
                 // each one containing the ExtrusionPath objects of a certain infill "group" (also called "surface"
@@ -1261,6 +1261,10 @@ void GCode::process_layer(
                     if (fill->entities.empty())
                         // This shouldn't happen but first_point() would fail.
                         continue;
+
+                    if (fill->is_extruder_overridden())
+                        continue;
+
                     // init by_extruder item only if we actually use the extruder
                     int extruder_id = std::max<int>(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1);
                     // Init by_extruder item only if we actually use the extruder.
@@ -1334,15 +1338,37 @@ void GCode::process_layer(
             m_avoid_crossing_perimeters.disable_once = true;
         }
 
+        for (const auto& layer_to_print : layers) {   // iterate through all objects
+            if (layer_to_print.object_layer == nullptr)
+                continue;
+            std::vector<ObjectByExtruder::Island::Region> overridden;
+            for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) {
+                ObjectByExtruder::Island::Region new_region;
+                overridden.push_back(new_region);
+                for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->fills.entities) {
+                    auto *fill = dynamic_cast<ExtrusionEntityCollection*>(ee);
+                    if (fill->get_extruder_override() == extruder_id) {
+                        overridden.back().infills.append(*fill);
+                        fill->set_extruder_override(-1);
+                    }
+               }
+                m_config.apply((layer_to_print.object_layer)->object()->config, true);
+                Point copy = (layer_to_print.object_layer)->object()->_shifted_copies.front();
+                this->set_origin(unscale(copy.x), unscale(copy.y));
+                gcode += this->extrude_infill(print, overridden);
+            }
+        }
+
+
         auto objects_by_extruder_it = by_extruder.find(extruder_id);
         if (objects_by_extruder_it == by_extruder.end())
             continue;
         for (const ObjectByExtruder &object_by_extruder : objects_by_extruder_it->second) {
             const size_t       layer_id     = &object_by_extruder - objects_by_extruder_it->second.data();
             const PrintObject *print_object = layers[layer_id].object();
-			if (print_object == nullptr)
-				// This layer is empty for this particular object, it has neither object extrusions nor support extrusions at this print_z.
-				continue;
+            if (print_object == nullptr)
+                // This layer is empty for this particular object, it has neither object extrusions nor support extrusions at this print_z.
+                continue;
 
             m_config.apply(print_object->config, true);
             m_layer = layers[layer_id].layer();
@@ -1355,6 +1381,7 @@ void GCode::process_layer(
                 copies.push_back(print_object->_shifted_copies[single_object_idx]);
             // Sort the copies by the closest point starting with the current print position.
             
+
             for (const Point &copy : copies) {
                 // When starting a new object, use the external motion planner for the first travel move.
                 std::pair<const PrintObject*, Point> this_object_copy(print_object, copy);
@@ -2004,6 +2031,7 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector<Obje
 }
 
 // Chain the paths hierarchically by a greedy algorithm to minimize a travel distance.
+// if extruder_id is set, only entities marked with given extruder_id are extruded
 std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region)
 {
     std::string gcode;
diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp
index 643ab3f31..82f513d70 100644
--- a/xs/src/libslic3r/Print.cpp
+++ b/xs/src/libslic3r/Print.cpp
@@ -1037,6 +1037,26 @@ void Print::_make_wipe_tower()
     if (! this->has_wipe_tower())
         return;
 
+
+    int wiping_extruder = 0;
+
+    for (size_t i = 0; i < objects.size(); ++ i) {
+        for (Layer* lay : objects[i]->layers) {
+            for (LayerRegion* reg : lay->regions) {
+                ExtrusionEntityCollection& eec = reg->fills;
+                for (ExtrusionEntity* ee : eec.entities) {
+                        auto* fill = dynamic_cast<ExtrusionEntityCollection*>(ee);
+                        /*if (fill->total_volume() > 1.)*/ {
+                            fill->set_extruder_override(wiping_extruder);
+                        if (++wiping_extruder > 3)
+                            wiping_extruder = 0;
+                        }
+                }
+            }
+        }
+    }
+
+
     // Let the ToolOrdering class know there will be initial priming extrusions at the start of the print.
     m_tool_ordering = ToolOrdering(*this, (unsigned int)-1, true);
     if (! m_tool_ordering.has_wipe_tower())