From c8596c5c58d7331330ca6d9403ad0c68c9dee915 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Tue, 9 Dec 2014 01:08:58 +0100
Subject: [PATCH] Limit "Only retract when crossing perimeters" so that
 retraction is triggered also when crossing the boundaries of a single region.
 #2298

---
 lib/Slic3r/GCode.pm                    |  6 ++----
 xs/src/libslic3r/Layer.cpp             | 12 ++++++++++++
 xs/src/libslic3r/Layer.hpp             |  1 +
 xs/src/libslic3r/Surface.cpp           |  9 +++++++++
 xs/src/libslic3r/Surface.hpp           |  1 +
 xs/src/libslic3r/SurfaceCollection.cpp | 12 ++++++++++++
 xs/src/libslic3r/SurfaceCollection.hpp |  1 +
 xs/xsp/Layer.xsp                       |  9 +++++++++
 8 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm
index c8b72a8ad..0f322ca15 100644
--- a/lib/Slic3r/GCode.pm
+++ b/lib/Slic3r/GCode.pm
@@ -344,8 +344,7 @@ sub travel_to {
     if ($travel->length < scale $self->config->get_at('retract_before_travel', $self->writer->extruder->id)
         || ($self->config->only_retract_when_crossing_perimeters
             && $self->config->fill_density > 0
-            && $self->layer->slices->contains_line($travel)
-            && (!$self->layer->has_upper_layer || $self->layer->upper_layer->slices->contains_line($travel)))
+            && $self->layer->any_internal_region_slice_contains_line($travel))
         || (defined $role && $role == EXTR_ROLE_SUPPORTMATERIAL && $self->layer->support_islands->contains_line($travel))
         ) {
         # Just perform a straight travel move without any retraction.
@@ -608,8 +607,7 @@ sub _plan {
     # if the path is not contained in a single island we need to retract
     $gcode .= $gcodegen->retract
         if !$gcodegen->config->only_retract_when_crossing_perimeters
-        || !$gcodegen->layer->slices->contains_polyline($travel)
-        || ($gcodegen->layer->has_upper_layer && !$gcodegen->layer->upper_layer->slices->contains_polyline($travel));
+        || !$gcodegen->layer->any_internal_region_slice_contains_polyline($travel);
     
     # append the actual path and return
     # use G1 because we rely on paths being straight (G0 may make round paths)
diff --git a/xs/src/libslic3r/Layer.cpp b/xs/src/libslic3r/Layer.cpp
index 17747d06d..26e9ab7f8 100644
--- a/xs/src/libslic3r/Layer.cpp
+++ b/xs/src/libslic3r/Layer.cpp
@@ -120,6 +120,18 @@ Layer::make_slices()
     }
 }
 
+template <class T>
+bool
+Layer::any_internal_region_slice_contains(const T &item) const
+{
+    FOREACH_LAYERREGION(this, layerm) {
+        if ((*layerm)->slices.any_internal_contains(item)) return true;
+    }
+    return false;
+}
+template bool Layer::any_internal_region_slice_contains<Line>(const Line &item) const;
+template bool Layer::any_internal_region_slice_contains<Polyline>(const Polyline &item) const;
+
 
 #ifdef SLIC3RXS
 REGISTER_CLASS(Layer, "Layer");
diff --git a/xs/src/libslic3r/Layer.hpp b/xs/src/libslic3r/Layer.hpp
index cd0250089..ff8cca1d9 100644
--- a/xs/src/libslic3r/Layer.hpp
+++ b/xs/src/libslic3r/Layer.hpp
@@ -90,6 +90,7 @@ class Layer {
     LayerRegion* add_region(PrintRegion* print_region);
     
     void make_slices();
+    template <class T> bool any_internal_region_slice_contains(const T &item) const;
 
     protected:
     int _id;     // sequential number of layer, 0-based
diff --git a/xs/src/libslic3r/Surface.cpp b/xs/src/libslic3r/Surface.cpp
index 3ea6429af..e4625f799 100644
--- a/xs/src/libslic3r/Surface.cpp
+++ b/xs/src/libslic3r/Surface.cpp
@@ -26,6 +26,15 @@ Surface::is_external() const
         || this->surface_type == stBottomBridge;
 }
 
+bool
+Surface::is_internal() const
+{
+    return this->surface_type == stInternal
+        || this->surface_type == stInternalBridge
+        || this->surface_type == stInternalSolid
+        || this->surface_type == stInternalVoid;
+}
+
 bool
 Surface::is_bottom() const
 {
diff --git a/xs/src/libslic3r/Surface.hpp b/xs/src/libslic3r/Surface.hpp
index c98567cf0..28a90799a 100644
--- a/xs/src/libslic3r/Surface.hpp
+++ b/xs/src/libslic3r/Surface.hpp
@@ -24,6 +24,7 @@ class Surface
     double area() const;
     bool is_solid() const;
     bool is_external() const;
+    bool is_internal() const;
     bool is_bottom() const;
     bool is_bridge() const;
     
diff --git a/xs/src/libslic3r/SurfaceCollection.cpp b/xs/src/libslic3r/SurfaceCollection.cpp
index 1590e7a21..027138818 100644
--- a/xs/src/libslic3r/SurfaceCollection.cpp
+++ b/xs/src/libslic3r/SurfaceCollection.cpp
@@ -68,6 +68,18 @@ SurfaceCollection::group(std::vector<SurfacesPtr> *retval)
     }
 }
 
+template <class T>
+bool
+SurfaceCollection::any_internal_contains(const T &item) const
+{
+    for (Surfaces::const_iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
+        if (surface->is_internal() && surface->expolygon.contains(item)) return true;
+    }
+    return false;
+}
+template bool SurfaceCollection::any_internal_contains<Line>(const Line &item) const;
+template bool SurfaceCollection::any_internal_contains<Polyline>(const Polyline &item) const;
+
 #ifdef SLIC3RXS
 REGISTER_CLASS(SurfaceCollection, "Surface::Collection");
 #endif
diff --git a/xs/src/libslic3r/SurfaceCollection.hpp b/xs/src/libslic3r/SurfaceCollection.hpp
index fe3fae8c6..494bb1a21 100644
--- a/xs/src/libslic3r/SurfaceCollection.hpp
+++ b/xs/src/libslic3r/SurfaceCollection.hpp
@@ -15,6 +15,7 @@ class SurfaceCollection
     operator ExPolygons() const;
     void simplify(double tolerance);
     void group(std::vector<SurfacesPtr> *retval);
+    template <class T> bool any_internal_contains(const T &item) const;
 };
 
 }
diff --git a/xs/xsp/Layer.xsp b/xs/xsp/Layer.xsp
index e0f7e8a17..a84d4464f 100644
--- a/xs/xsp/Layer.xsp
+++ b/xs/xsp/Layer.xsp
@@ -69,6 +69,10 @@
         %code%{ RETVAL = (int)(intptr_t)THIS; %};
     
     void make_slices();
+    bool any_internal_region_slice_contains_line(Line* line)
+        %code%{ RETVAL = THIS->any_internal_region_slice_contains(*line); %};
+    bool any_internal_region_slice_contains_polyline(Polyline* polyline)
+        %code%{ RETVAL = THIS->any_internal_region_slice_contains(*polyline); %};
 };
 
 %name{Slic3r::Layer::Support} class SupportLayer {
@@ -114,4 +118,9 @@
 
     Ref<ExPolygonCollection> slices()
         %code%{ RETVAL = &THIS->slices; %};
+    
+    bool any_internal_region_slice_contains_line(Line* line)
+        %code%{ RETVAL = THIS->any_internal_region_slice_contains(*line); %};
+    bool any_internal_region_slice_contains_polyline(Polyline* polyline)
+        %code%{ RETVAL = THIS->any_internal_region_slice_contains(*polyline); %};
 };