From a6ea01a23f1f4013845fce4ec80c6511b6f40f37 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Thu, 27 Jul 2017 10:39:43 +0200
Subject: [PATCH] Moved some math macros (sqr, lerp, clamp) to libslic3r.h

Added UNUSED macro to libslic3r.h, used it to reduce some compile warnings.

Split the Int128 class from Clipper library to a separate file,
extended Int128 with intrinsic types wherever possible for performance,
added new geometric predicates.

Added a draft of new FillRectilinear3, which should reduce overfill near the perimeters in the future.
---
 xs/src/clipper.cpp                         |  129 +-
 xs/src/libslic3r/Config.hpp                |    9 +
 xs/src/libslic3r/ExtrusionSimulator.cpp    |   29 +-
 xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp  |    6 -
 xs/src/libslic3r/Fill/FillBase.hpp         |   20 +-
 xs/src/libslic3r/Fill/FillConcentric.cpp   |   10 +-
 xs/src/libslic3r/Fill/FillRectilinear2.cpp |   30 -
 xs/src/libslic3r/Fill/FillRectilinear3.cpp | 1621 ++++++++++++++++++++
 xs/src/libslic3r/Fill/FillRectilinear3.hpp |   83 +
 xs/src/libslic3r/Geometry.hpp              |    2 +-
 xs/src/libslic3r/Int128.hpp                |  300 ++++
 xs/src/libslic3r/Layer.hpp                 |   13 +-
 xs/src/libslic3r/Point.cpp                 |    6 -
 xs/src/libslic3r/Point.hpp                 |   10 +-
 xs/src/libslic3r/PolylineCollection.cpp    |   56 +-
 xs/src/libslic3r/PolylineCollection.hpp    |   30 +-
 xs/src/libslic3r/PrintConfig.hpp           |    4 +
 xs/src/libslic3r/Slicing.cpp               |   14 +-
 xs/src/libslic3r/libslic3r.h               |   23 +
 19 files changed, 2106 insertions(+), 289 deletions(-)
 create mode 100644 xs/src/libslic3r/Fill/FillRectilinear3.cpp
 create mode 100644 xs/src/libslic3r/Fill/FillRectilinear3.hpp
 create mode 100644 xs/src/libslic3r/Int128.hpp

diff --git a/xs/src/clipper.cpp b/xs/src/clipper.cpp
index 415c54bab..5c63a6afe 100644
--- a/xs/src/clipper.cpp
+++ b/xs/src/clipper.cpp
@@ -49,6 +49,7 @@
 #include <functional>
 #include <assert.h>
 #include <Shiny/Shiny.h>
+#include <libslic3r/Int128.hpp>
 
 namespace ClipperLib {
 
@@ -128,109 +129,6 @@ bool PolyNode::IsHole() const
   }
   return result;
 }  
-//------------------------------------------------------------------------------
-
-//------------------------------------------------------------------------------
-// Int128 class (enables safe math on signed 64bit integers)
-// eg Int128 val1((int64_t)9223372036854775807); //ie 2^63 -1
-//    Int128 val2((int64_t)9223372036854775807);
-//    Int128 val3 = val1 * val2;
-//    val3.AsString => "85070591730234615847396907784232501249" (8.5e+37)
-//------------------------------------------------------------------------------
-// Used by the SlopesEqual() functions.
-class Int128
-{
-  public:
-    uint64_t lo;
-    int64_t  hi;
-
-    Int128(int64_t _lo = 0) : lo((uint64_t)_lo), hi((_lo < 0) ? -1 : 0) {}
-    Int128(const Int128 &val) : lo(val.lo), hi(val.hi) {}
-    Int128(const int64_t& _hi, const uint64_t& _lo) : lo(_lo), hi(_hi) {}
-    
-    Int128& operator = (const int64_t &val)
-    {
-      lo = (uint64_t)val;
-      hi = (val < 0) ? -1 : 0;
-      return *this;
-    }
-
-    bool operator == (const Int128 &val) const { return hi == val.hi && lo == val.lo; }
-    bool operator != (const Int128 &val) const { return ! (*this == val); }
-    bool operator >  (const Int128 &val) const { return (hi == val.hi) ? lo > val.lo : hi > val.hi; }
-    bool operator <  (const Int128 &val) const { return (hi == val.hi) ? lo < val.lo : hi < val.hi; }
-    bool operator >= (const Int128 &val) const { return ! (*this < val); }
-    bool operator <= (const Int128 &val) const { return ! (*this > val); }
-
-    Int128& operator += (const Int128 &rhs)
-    {
-      hi += rhs.hi;
-      lo += rhs.lo;
-      if (lo < rhs.lo) hi++;
-      return *this;
-    }
-
-    Int128 operator + (const Int128 &rhs) const
-    {
-      Int128 result(*this);
-      result+= rhs;
-      return result;
-    }
-
-    Int128& operator -= (const Int128 &rhs)
-    {
-      *this += -rhs;
-      return *this;
-    }
-
-    Int128 operator - (const Int128 &rhs) const
-    {
-      Int128 result(*this);
-      result -= rhs;
-      return result;
-    }
-
-    Int128 operator-() const { return (lo == 0) ? Int128(-hi, 0) : Int128(~hi, ~lo + 1); }
-
-    operator double() const
-    {
-      const double shift64 = 18446744073709551616.0; //2^64
-      return (hi < 0) ?
-        ((lo == 0) ? 
-          (double)hi * shift64 :
-          -(double)(~lo + ~hi * shift64)) :
-        (double)(lo + hi * shift64);
-    }
-
-    static inline Int128 Multiply(int64_t lhs, int64_t rhs)
-    {
-      bool negate = (lhs < 0) != (rhs < 0);
-
-      if (lhs < 0) lhs = -lhs;
-      uint64_t int1Hi = uint64_t(lhs) >> 32;
-      uint64_t int1Lo = uint64_t(lhs & 0xFFFFFFFF);
-
-      if (rhs < 0) rhs = -rhs;
-      uint64_t int2Hi = uint64_t(rhs) >> 32;
-      uint64_t int2Lo = uint64_t(rhs & 0xFFFFFFFF);
-
-      //because the high (sign) bits in both int1Hi & int2Hi have been zeroed,
-      //there's no risk of 64 bit overflow in the following assignment
-      //(ie: $7FFFFFFF*$FFFFFFFF + $7FFFFFFF*$FFFFFFFF < 64bits)
-      uint64_t a = int1Hi * int2Hi;
-      uint64_t b = int1Lo * int2Lo;
-      //Result = A shl 64 + C shl 32 + B ...
-      uint64_t c = int1Hi * int2Lo + int1Lo * int2Hi;
-
-      Int128 tmp;
-      tmp.hi = int64_t(a + (c >> 32));
-      tmp.lo = int64_t(c << 32);
-      tmp.lo += int64_t(b);
-      if (tmp.lo < b) tmp.hi++;
-      if (negate) tmp = -tmp;
-      return tmp;
-    }
-};
 
 //------------------------------------------------------------------------------
 // Miscellaneous global functions
@@ -375,32 +273,11 @@ bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2)
 }
 //----------------------------------------------------------------------
 
-// Approximate calculation of SlopesEqual() for "UseFullInt64Range"
-// Returns true if the slopes are unequal for sure, 
-// otherwise returns false if the slopes may or may not be equal.
-inline bool SlopesUnequalFilter(cInt dx1, cInt dy1, cInt dx2, cInt dy2) {
-  // Round dx1, dy1, dx2, dy2 to 31 bits.
-  dx1 = (dx1 + (1 << 30)) >> 32;
-  dy1 = (dy1 + (1 << 30)) >> 32;
-  dx2 = (dx2 + (1 << 30)) >> 32;
-  dy2 = (dy2 + (1 << 30)) >> 32;
-  // Result fits 63 bits, it is an approximate of the determinant divided by 2^64.
-  cInt discr = std::abs(dy1 * dx2 - dx1 * dy2);
-  // Maximum absolute of the remainder of the exact determinant, divided by 2^64.
-  cInt error = ((std::abs(dx1) + std::abs(dy1) + std::abs(dx2) + std::abs(dy2)) >> 1) + 1;
-  return discr > error;
-}
-
 inline bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cInt dy2, bool UseFullInt64Range) {
   return (UseFullInt64Range) ?
     // |dx1| < 2^63, |dx2| < 2^63 etc,
-#if 1
-    // Instead of jumping to 128bit multiply on a 32bit or 64bit CPU,
-    // calculate an approximate value of the determinant and its error.
-    // If the determinant is above the error, the slopes are certainly not equal.
-    ! SlopesUnequalFilter(dx1, dy1, dx2, dy2) && 
-#endif
-    Int128::Multiply(dy1, dx2) == Int128::Multiply(dx1, dy2) :
+    Int128::sign_determinant_2x2_filtered(dx1, dy1, dx2, dy2) == 0 :
+//    Int128::sign_determinant_2x2(dx1, dy1, dx2, dy2) == 0 :
     // |dx1| < 2^31, |dx2| < 2^31 etc,
     // therefore the following computation could be done with 64bit arithmetics. 
     dy1 * dx2 == dx1 * dy2;
diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp
index 03a6dd859..46e47bc00 100644
--- a/xs/src/libslic3r/Config.hpp
+++ b/xs/src/libslic3r/Config.hpp
@@ -95,6 +95,7 @@ public:
     };
     
     bool deserialize(const std::string &str, bool append = false) {
+        UNUSED(append);
         std::istringstream iss(str);
         iss >> this->value;
         return !iss.fail();
@@ -155,6 +156,7 @@ public:
     };
     
     bool deserialize(const std::string &str, bool append = false) {
+        UNUSED(append);
         std::istringstream iss(str);
         iss >> this->value;
         return !iss.fail();
@@ -210,6 +212,7 @@ public:
     }
 
     bool deserialize(const std::string &str, bool append = false) {
+        UNUSED(append);
         return unescape_string_cstyle(str, this->value);
     };
 };
@@ -252,6 +255,7 @@ public:
     };
     
     bool deserialize(const std::string &str, bool append = false) {
+        UNUSED(append);
         // don't try to parse the trailing % since it's optional
         std::istringstream iss(str);
         iss >> this->value;
@@ -333,6 +337,7 @@ public:
     };
     
     bool deserialize(const std::string &str, bool append = false) {
+        UNUSED(append);
         this->percent = str.find_first_of("%") != std::string::npos;
         std::istringstream iss(str);
         iss >> this->value;
@@ -355,6 +360,7 @@ public:
     };
     
     bool deserialize(const std::string &str, bool append = false) {
+        UNUSED(append);
         std::istringstream iss(str);
         iss >> this->value.x;
         iss.ignore(std::numeric_limits<std::streamsize>::max(), ',');
@@ -422,6 +428,7 @@ public:
     };
     
     bool deserialize(const std::string &str, bool append = false) {
+        UNUSED(append);
         this->value = (str.compare("1") == 0);
         return true;
     };
@@ -481,6 +488,7 @@ public:
     };
 
     bool deserialize(const std::string &str, bool append = false) {
+        UNUSED(append);
         t_config_enum_values enum_keys_map = ConfigOptionEnum<T>::get_enum_values();
         if (enum_keys_map.count(str) == 0) return false;
         this->value = static_cast<T>(enum_keys_map[str]);
@@ -508,6 +516,7 @@ public:
     };
 
     bool deserialize(const std::string &str, bool append = false) {
+        UNUSED(append);
         if (this->keys_map->count(str) == 0) return false;
         this->value = (*const_cast<t_config_enum_values*>(this->keys_map))[str];
         return true;
diff --git a/xs/src/libslic3r/ExtrusionSimulator.cpp b/xs/src/libslic3r/ExtrusionSimulator.cpp
index 3752caed4..daecbc0d1 100644
--- a/xs/src/libslic3r/ExtrusionSimulator.cpp
+++ b/xs/src/libslic3r/ExtrusionSimulator.cpp
@@ -13,12 +13,15 @@
 
 #include <boost/multi_array.hpp>
 
+#include "libslic3r.h"
 #include "ExtrusionSimulator.hpp"
 
 #ifndef M_PI
 #define M_PI 3.1415926535897932384626433832795
 #endif
 
+namespace Slic3r {
+
 // Replacement for a template alias.
 // Shorthand for the point_xy.
 template<typename T>
@@ -172,24 +175,6 @@ inline T mag(const boost::geometry::model::d2::point_xy<T> &v)
 	return l2(v);
 }
 
-template<typename T>
-inline T lerp(T start, T end, T alpha)
-{
-	return start * (T(1.) - alpha) + end * alpha;
-}
-
-template<typename T>
-inline T clamp(T low, T high, T x)
-{
-	return std::max<T>(low, std::min<T>(high, x));
-}
-
-template<typename T>
-inline T sqr(T x)
-{
-	return x * x;
-}
-
 template<typename T>
 inline T dist2_to_line(
 	const boost::geometry::model::d2::point_xy<T> &p0,
@@ -657,7 +642,7 @@ void gcode_spread_points(
 	A2f 					&acc,
 	const A2f				&mask,
 	const ExtrusionPoints   &points, 
-	Slic3r::ExtrusionSimulationType simulationType)
+	ExtrusionSimulationType simulationType)
 {
 	int nc = acc.shape()[1];
 	int nr = acc.shape()[0];
@@ -796,14 +781,14 @@ void gcode_spread_points(
 //		if (true) {
 //		printf("volume_total: %f, volume_full: %f, fill factor: %f\n", volume_total, volume_full, 100.f - 100.f * volume_total / volume_full);
 //		printf("volume_full: %f, volume_excess+deficit: %f, volume_excess: %f, volume_deficit: %f\n", volume_full, volume_excess+volume_deficit, volume_excess, volume_deficit);
-		if (simulationType == Slic3r::ExtrusionSimulationSpreadFull || volume_total <= volume_full) {
+		if (simulationType == ExtrusionSimulationSpreadFull || volume_total <= volume_full) {
 			// The volume under the circle is spreaded fully.
 			float height_avg = volume_total / area_total;
 			for (size_t i = 0; i < n_cells; ++ i) {
 				const Cell &cell = cells[i];
 				acc[cell.idx.y()][cell.idx.x()] = (1.f - cell.fraction_covered) * cell.volume + cell.fraction_covered * cell.area * height_avg;
 			}
-		} else if (simulationType == Slic3r::ExtrusionSimulationSpreadExcess) {
+		} else if (simulationType == ExtrusionSimulationSpreadExcess) {
 			// The volume under the circle does not fit.
 			// 1) Fill the underfilled cells and remove them from the list.
 			float volume_borrowed_total = 0.;
@@ -881,8 +866,6 @@ inline std::vector<V3uc> CreatePowerColorGradient24bit()
 	return out;
 }
 
-namespace Slic3r {
-
 class ExtrusionSimulatorImpl {
 public:
 	std::vector<unsigned char>  image_data;
diff --git a/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp b/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp
index c763952d6..d03c1f208 100644
--- a/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp
+++ b/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp
@@ -50,12 +50,6 @@ static std::vector<coordf_t> perpendPoints(const coordf_t offset, const size_t b
     return points;
 }
 
-template<typename T>
-static inline T clamp(T low, T high, T x)
-{
-    return std::max<T>(low, std::min<T>(high, x));
-}
-
 // Trims an array of points to specified rectangular limits. Point
 // components that are outside these limits are set to the limits.
 static inline void trim(Pointfs &pts, coordf_t minX, coordf_t minY, coordf_t maxX, coordf_t maxY)
diff --git a/xs/src/libslic3r/Fill/FillBase.hpp b/xs/src/libslic3r/Fill/FillBase.hpp
index 594c498dd..62d18e518 100644
--- a/xs/src/libslic3r/Fill/FillBase.hpp
+++ b/xs/src/libslic3r/Fill/FillBase.hpp
@@ -95,21 +95,19 @@ protected:
 
     // The expolygon may be modified by the method to avoid a copy.
     virtual void    _fill_surface_single(
-        const FillParams                &params, 
-        unsigned int                     thickness_layers,
-        const std::pair<float, Point>   &direction, 
-        ExPolygon                       &expolygon, 
-        Polylines                       &polylines_out) {}
+        const FillParams                & /* params */, 
+        unsigned int                      /* thickness_layers */,
+        const std::pair<float, Point>   & /* direction */, 
+        ExPolygon                       & /* expolygon */, 
+        Polylines                       & /* polylines_out */) {};
 
-    static coord_t  _adjust_solid_spacing(const coord_t width, const coord_t distance);
-
-    virtual float _layer_angle(size_t idx) const { 
-        bool odd = idx & 1;
-        return (idx & 1) ? float(M_PI/2.) : 0;
-    }
+    virtual float _layer_angle(size_t idx) const { return (idx & 1) ? float(M_PI/2.) : 0; }
 
     virtual std::pair<float, Point> _infill_direction(const Surface *surface) const;
 
+public:
+    static coord_t  _adjust_solid_spacing(const coord_t width, const coord_t distance);
+
     // Align a coordinate to a grid. The coordinate may be negative,
     // the aligned value will never be bigger than the original one.
     static coord_t _align_to_grid(const coord_t coord, const coord_t spacing) {
diff --git a/xs/src/libslic3r/Fill/FillConcentric.cpp b/xs/src/libslic3r/Fill/FillConcentric.cpp
index 156e3478a..b21ad2799 100644
--- a/xs/src/libslic3r/Fill/FillConcentric.cpp
+++ b/xs/src/libslic3r/Fill/FillConcentric.cpp
@@ -38,8 +38,8 @@ void FillConcentric::_fill_surface_single(
     // split paths using a nearest neighbor search
     size_t iPathFirst = polylines_out.size();
     Point last_pos(0, 0);
-    for (Polygons::const_iterator it_loop = loops.begin(); it_loop != loops.end(); ++ it_loop) {
-        polylines_out.push_back(it_loop->split_at_index(last_pos.nearest_point_index(*it_loop)));
+    for (const Polygon &loop : loops) {
+        polylines_out.push_back(loop.split_at_index(last_pos.nearest_point_index(loop)));
         last_pos = polylines_out.back().last_point();
     }
 
@@ -50,13 +50,15 @@ void FillConcentric::_fill_surface_single(
         polylines_out[i].clip_end(this->loop_clipping);
         if (polylines_out[i].is_valid()) {
             if (j < i)
-                std::swap(polylines_out[j], polylines_out[i]);
+                polylines_out[j] = std::move(polylines_out[i]);
             ++ j;
         }
     }
     if (j < polylines_out.size())
         polylines_out.erase(polylines_out.begin() + j, polylines_out.end());
-    // TODO: return ExtrusionLoop objects to get better chained paths
+    //TODO: return ExtrusionLoop objects to get better chained paths,
+    // otherwise the outermost loop starts at the closest point to (0, 0).
+    // We want the loops to be split inside the G-code generator to get optimum path planning.
 }
 
 } // namespace Slic3r
diff --git a/xs/src/libslic3r/Fill/FillRectilinear2.cpp b/xs/src/libslic3r/Fill/FillRectilinear2.cpp
index 7af92a6ac..ca650faf8 100644
--- a/xs/src/libslic3r/Fill/FillRectilinear2.cpp
+++ b/xs/src/libslic3r/Fill/FillRectilinear2.cpp
@@ -33,36 +33,6 @@
 
 namespace Slic3r {
 
-#ifndef clamp
-template<typename T>
-static inline T clamp(T low, T high, T x)
-{
-    return std::max<T>(low, std::min<T>(high, x));
-}
-#endif /* clamp */
-
-#ifndef sqr
-template<typename T>
-static inline T sqr(T x)
-{
-    return x * x;
-}
-#endif /* sqr */
-
-#ifndef mag2
-static inline coordf_t mag2(const Point &p)
-{
-    return sqr(coordf_t(p.x)) + sqr(coordf_t(p.y));
-}
-#endif /* mag2 */
-
-#ifndef mag
-static inline coordf_t mag(const Point &p)
-{
-    return std::sqrt(mag2(p));
-}
-#endif /* mag */
-
 // Having a segment of a closed polygon, calculate its Euclidian length.
 // The segment indices seg1 and seg2 signify an end point of an edge in the forward direction of the loop,
 // therefore the point p1 lies on poly.points[seg1-1], poly.points[seg1] etc.
diff --git a/xs/src/libslic3r/Fill/FillRectilinear3.cpp b/xs/src/libslic3r/Fill/FillRectilinear3.cpp
new file mode 100644
index 000000000..b8b1c0b29
--- /dev/null
+++ b/xs/src/libslic3r/Fill/FillRectilinear3.cpp
@@ -0,0 +1,1621 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
+#include <boost/static_assert.hpp>
+
+#include "../ClipperUtils.hpp"
+#include "../ExPolygon.hpp"
+#include "../Geometry.hpp"
+#include "../Surface.hpp"
+#include "../Int128.hpp"
+
+#include "FillRectilinear3.hpp"
+
+// #define SLIC3R_DEBUG
+
+// Make assert active if SLIC3R_DEBUG
+#ifdef SLIC3R_DEBUG
+    #undef NDEBUG
+    #include "SVG.hpp"
+#endif
+
+#include <cassert>
+
+// We want our version of assert.
+#include "../libslic3r.h"
+
+#ifndef myassert
+#define myassert assert
+#endif
+
+namespace Slic3r {
+
+namespace FillRectilinear3_Internal {
+
+// A container maintaining the source expolygon with its inner offsetted polygon.
+// The source expolygon is offsetted twice: 
+// 1) A tiny offset is used to get a contour, to which the open hatching lines will be extended.
+// 2) A larger offset is used to get a contor, along which the individual hatching lines will be connected.
+struct ExPolygonWithOffset
+{
+public:
+    ExPolygonWithOffset(
+        const ExPolygon &expolygon,
+        float aoffset1,
+        float aoffset2)
+    {
+        // Copy and rotate the source polygons.
+        polygons_src = expolygon;
+
+        double mitterLimit = 3.;
+        // for the infill pattern, don't cut the corners.
+        // default miterLimt = 3
+        //double mitterLimit = 10.;
+        myassert(aoffset1 < 0);
+        myassert(aoffset2 < 0);
+        myassert(aoffset2 < aoffset1);
+//        bool sticks_removed = remove_sticks(polygons_src);
+//        if (sticks_removed) printf("Sticks removed!\n");
+        polygons_outer = offset(polygons_src, aoffset1,
+            ClipperLib::jtMiter,
+            mitterLimit);
+        polygons_inner = offset(polygons_outer, aoffset2 - aoffset1,
+            ClipperLib::jtMiter,
+            mitterLimit);
+        // Filter out contours with zero area or small area, contours with 2 points only.
+        const double min_area_threshold = 0.01 * aoffset2 * aoffset2;
+        remove_small(polygons_outer, min_area_threshold);
+        remove_small(polygons_inner, min_area_threshold);
+        remove_sticks(polygons_outer);
+        remove_sticks(polygons_inner);
+        n_contours_outer = polygons_outer.size();
+        n_contours_inner = polygons_inner.size();
+        n_contours = n_contours_outer + n_contours_inner;
+        polygons_ccw.assign(n_contours, false);
+        for (size_t i = 0; i < n_contours; ++ i) {
+            contour(i).remove_duplicate_points();
+            myassert(! contour(i).has_duplicate_points());
+            polygons_ccw[i] = Slic3r::Geometry::is_ccw(contour(i));
+        }
+    }
+
+    // Any contour with offset1
+    bool             is_contour_outer(size_t idx) const { return idx < n_contours_outer; }
+    // Any contour with offset2
+    bool             is_contour_inner(size_t idx) const { return idx >= n_contours_outer; }
+
+    const Polygon&   contour(size_t idx) const 
+        { return is_contour_outer(idx) ? polygons_outer[idx] : polygons_inner[idx - n_contours_outer]; }
+
+    Polygon&         contour(size_t idx)
+        { return is_contour_outer(idx) ? polygons_outer[idx] : polygons_inner[idx - n_contours_outer]; }
+
+    bool             is_contour_ccw(size_t idx) const { return polygons_ccw[idx] != 0; }
+
+    BoundingBox      bounding_box_src() const 
+        { return get_extents(polygons_src); }
+    BoundingBox      bounding_box_outer() const 
+        { return get_extents(polygons_outer); }
+    BoundingBox      bounding_box_inner() const 
+        { return get_extents(polygons_inner); }
+
+#ifdef SLIC3R_DEBUG
+    void export_to_svg(Slic3r::SVG &svg) const {
+        svg.draw_outline(polygons_src,   "black");
+        svg.draw_outline(polygons_outer, "green");
+        svg.draw_outline(polygons_inner, "brown");
+    }
+#endif /* SLIC3R_DEBUG */
+
+    ExPolygon        polygons_src;
+    Polygons         polygons_outer;
+    Polygons         polygons_inner;
+
+    size_t           n_contours_outer;
+    size_t           n_contours_inner;
+    size_t           n_contours;
+
+protected:
+    // For each polygon of polygons_inner, remember its orientation.
+    std::vector<unsigned char> polygons_ccw;
+};
+
+class SegmentedIntersectionLine;
+
+// Intersection point of a vertical line with a polygon segment.
+class SegmentIntersection
+{
+public:
+    SegmentIntersection() :
+        line(nullptr),
+        expoly_with_offset(nullptr),
+        iContour(0),
+        iSegment(0),
+        type(UNKNOWN),
+        consumed_vertical_up(false),
+        consumed_perimeter_right(false)
+        {}
+
+    // Parent object owning this intersection point.
+    const SegmentedIntersectionLine *line;
+    // Container with the source expolygon and its shrank copies, to be intersected by the line.
+    const ExPolygonWithOffset       *expoly_with_offset;
+
+    // Index of a contour in ExPolygonWithOffset, with which this vertical line intersects.
+    size_t                           iContour;
+    // Index of a segment in iContour, with which this vertical line intersects.
+    size_t                           iSegment;
+
+    // Kind of intersection. With the original contour, or with the inner offestted contour?
+    // A vertical segment will be at least intersected by OUTER_LOW, OUTER_HIGH,
+    // but it could be intersected with OUTER_LOW, INNER_LOW, INNER_HIGH, OUTER_HIGH,
+    // and there may be more than one pair of INNER_LOW, INNER_HIGH between OUTER_LOW, OUTER_HIGH.
+    enum SegmentIntersectionType {
+        OUTER_LOW   = 0,
+        OUTER_HIGH  = 1,
+        INNER_LOW   = 2,
+        INNER_HIGH  = 3,
+        UNKNOWN     = -1
+    };
+    SegmentIntersectionType    type;
+
+    // For the INNER_LOW type, this point may be connected to another INNER_LOW point following a perimeter contour.
+    // For the INNER_HIGH type, this point may be connected to another INNER_HIGH point following a perimeter contour.
+    // If INNER_LOW is connected to INNER_HIGH or vice versa,
+    // one has to make sure the vertical infill line does not overlap with the connecting perimeter line.
+    bool is_inner() const { return type == INNER_LOW  || type == INNER_HIGH; }
+    bool is_outer() const { return type == OUTER_LOW  || type == OUTER_HIGH; }
+    bool is_low  () const { return type == INNER_LOW  || type == OUTER_LOW; }
+    bool is_high () const { return type == INNER_HIGH || type == OUTER_HIGH; }
+
+    // Calculate a position of this intersection point. The position does not need to be necessary exact.
+    Point       pos() const;
+
+    // Returns 0, if this and other segments intersect at the hatching line.
+    // Returns -1, if this intersection is below the other intersection on the hatching line.
+    // Returns +1 otherwise. 
+    int         ordering_along_line(const SegmentIntersection &other) const;
+
+    // Compare two y intersection points given by rational numbers.
+    bool        operator< (const SegmentIntersection &other) const { return this->ordering_along_line(other) == -1; }
+    bool        operator==(const SegmentIntersection &other) const { return this->ordering_along_line(other) == 0; }
+
+    //FIXME legacy code, suporting the old graph traversal algorithm. Please remove.
+    // Was this segment along the y axis consumed?
+    // Up means up along the vertical segment.
+    bool consumed_vertical_up;
+    // Was a segment of the inner perimeter contour consumed?
+    // Right means right from the vertical segment.
+    bool consumed_perimeter_right;
+};
+
+// A single hathing line intersecting the ExPolygonWithOffset.
+class SegmentedIntersectionLine
+{
+public:
+    // Index of this vertical intersection line.
+    size_t                              idx;
+    // Position of the line along the X axis of the oriented bounding box.
+    coord_t                             x;
+    // Position of this vertical intersection line, rotated to the world coordinate system.
+    Point                               pos;
+    // Direction of this vertical intersection line, rotated to the world coordinate system. The direction is not normalized to maintain a sufficient accuracy!
+    Vector                              dir;
+    // List of intersection points with polygons, sorted increasingly by the y axis.
+    // The SegmentIntersection keeps a pointer to this object to access the start and direction of this line.
+    std::vector<SegmentIntersection>    intersections;
+};
+
+// Return an intersection point of the parent SegmentedIntersectionLine with the segment of a parent ExPolygonWithOffset.
+// The intersected segment of the ExPolygonWithOffset is addressed with (iContour, iSegment).
+// When calling this method, the SegmentedIntersectionLine must not be parallel with the segment.
+Point SegmentIntersection::pos() const
+{
+    // Get the two rays to be intersected.
+    const Polygon &poly = this->expoly_with_offset->contour(this->iContour);
+    // 30 bits + 1 signum bit.
+    const Point   &seg_start = poly.points[this->iSegment];
+    const Point   &seg_end   = poly.points[(this->iSegment + 1) % poly.points.size()];
+    // Point, vector of the segment.
+    const Pointf   p1  = convert_to<Pointf>(seg_start);
+    const Pointf   v1  = convert_to<Pointf>(seg_end - seg_start);
+    // Point, vector of this hatching line.
+    const Pointf   p2  = convert_to<Pointf>(line->pos);
+    const Pointf   v2  = convert_to<Pointf>(line->dir);
+    // Intersect the two rays.
+    double denom = v1.x * v2.y - v2.x * v1.y;
+    Point out;
+    if (denom == 0.) {
+        // Lines are collinear. As the pos() method is not supposed to be called on collinear vectors,
+        // the source vectors are not quite collinear. Return the center of the contour segment.
+        out = seg_start + seg_end;
+        out.x >>= 1;
+        out.y >>= 1;
+    } else {
+        // Find the intersection point.
+        double t = (v2.x * (p1.y - p2.y) - v2.y * (p1.x - p2.x)) / denom;
+        if (t < 0.)
+            out = seg_start;
+        else if (t > 1.)
+            out = seg_end;
+        else {
+            out.x = coord_t(floor(p1.x + t * v1.x + 0.5));
+            out.y = coord_t(floor(p1.y + t * v1.y + 0.5));
+        }
+    }
+    return out;
+}
+
+static inline int signum(int64_t v) { return (v > 0) - (v < 0); }
+
+// Returns 0, if this and other segments intersect at the hatching line.
+// Returns -1, if this intersection is below the other intersection on the hatching line.
+// Returns +1 otherwise. 
+int SegmentIntersection::ordering_along_line(const SegmentIntersection &other) const
+{
+    assert(this->line == other.line);
+    assert(this->expoly_with_offset == other.expoly_with_offset);
+
+    if (this->iContour == other.iContour && this->iSegment == other.iSegment)
+        return true;
+
+    // Segment of this
+    const Polygon &poly_a      = this->expoly_with_offset->contour(this->iContour);
+    // 30 bits + 1 signum bit.
+    const Point   &seg_start_a = poly_a.points[this->iSegment];
+    const Point   &seg_end_a   = poly_a.points[(this->iSegment + 1) % poly_a.points.size()];
+    const Point    vec_a       = seg_end_a - seg_start_a;
+
+    // Segment of other
+    const Polygon &poly_b      = this->expoly_with_offset->contour(other.iContour);
+    // 30 bits + 1 signum bit.
+    const Point   &seg_start_b = poly_b.points[other.iSegment];
+    const Point   &seg_end_b   = poly_b.points[(other.iSegment + 1) % poly_b.points.size()];
+    const Point    vec_b       = seg_end_b - seg_start_b;
+
+    if (this->iContour == other.iContour) {
+        if ((this->iSegment + 1) % poly_a.points.size() == other.iSegment) {
+            // other.iSegment succeeds this->iSegment
+        } else if ((other.iSegment + 1) % poly_a.points.size() == this->iSegment) {
+            // this->iSegment succeeds other.iSegment
+        } else {
+            // General case.
+        }
+    }
+
+    // First test, whether both points of one segment are completely in one half-plane of the other line.
+    int side_start = signum(cross(vec_b, seg_start_a - seg_start_b));
+    int side_end   = signum(cross(vec_b, seg_end_a   - seg_start_b));
+    int side       = side_start * side_end;
+    if (side > 0)
+        // This segment is completely inside one half-plane of the other line, therefore the ordering is trivial.
+        return signum(cross(vec_b, this->line->dir)) * side_start;
+
+    int side_start2 = signum(cross(vec_a, seg_start_b - seg_start_a));
+    int side_end2   = signum(cross(vec_a, seg_end_b   - seg_start_a));
+    int side2       = side_start2 * side_end2;
+    if (side2 > 0)
+        // This segment is completely inside one half-plane of the other line, therefore the ordering is trivial.
+        return signum(cross(vec_a, this->line->dir)) * side_start2;
+
+    if (side == 0 && side2 == 0)
+        // The segments share one of their end points.
+        return 0;
+
+    // The two segments intersect and they are not sucessive segments of the same contour.
+    // Ordering of the points depends on the position of the segment intersection (left / right from this->line),
+    // therefore a simple test over the input segment end points is not sufficient.
+
+    // Find the parameters of intersection of the two segmetns with this->line.
+    int64_t denom1 = cross(vec_a, this->line->dir);
+    int64_t denom2 = cross(vec_b, this->line->dir);
+    int64_t t1_times_denom1 = int64_t(this->line->dir.x) * int64_t(seg_start_a.y - this->line->pos.y) - int64_t(this->line->dir.y) * int64_t(seg_start_a.x - this->line->pos.x);
+    int64_t t2_times_denom2 = int64_t(this->line->dir.x) * int64_t(seg_start_b.y - this->line->pos.y) - int64_t(this->line->dir.y) * int64_t(seg_start_b.x - this->line->pos.x);
+    assert(denom1 != 0);
+    assert(denom2 != 0);
+    return Int128::compare_rationals_filtered(t1_times_denom1, denom1, t2_times_denom2, denom2);
+}
+
+// When doing a rectilinear / grid / triangle / stars / cubic infill,
+// the following class holds the hatching lines of each of the hatching directions.
+class InfillHatchingSingleDirection
+{
+public:
+    // Hatching angle, CCW from the X axis.
+    double                                  angle;
+    // Starting point of the 1st hatching line.
+    Point                                   start_point;
+    // Direction vector, its size is not normalized to maintain a sufficient accuracy!
+    Vector                                  direction;
+    // Spacing of the hatching lines, perpendicular to the direction vector.
+    coord_t                                 line_spacing;
+    // Infill segments oriented at angle.
+    std::vector<SegmentedIntersectionLine>  segs;
+};
+
+// For the rectilinear, grid, triangles, stars and cubic pattern fill one InfillHatchingSingleDirection structure
+// for each infill direction. The segments stored in InfillHatchingSingleDirection will then form a graph of candidate
+// paths to be extruded.
+static bool prepare_infill_hatching_segments(
+    // Input geometry to be hatch, containing two concentric contours for each input contour.
+    const ExPolygonWithOffset      &poly_with_offset,
+    // fill density, dont_adjust
+    const FillParams               &params,
+    // angle, pattern_shift, spacing
+    FillRectilinear3::FillDirParams &fill_dir_params,
+    // Reference point of the pattern, to which the infill lines will be alligned, and the base angle.
+    const std::pair<float, Point>  &rotate_vector,
+    // Resulting straight segments of the infill graph.
+    InfillHatchingSingleDirection  &out)
+{
+    out.angle = rotate_vector.first + fill_dir_params.angle;
+    out.direction = Point(1000, 0);
+    // Hatch along the Y axis of the rotated coordinate system.
+    out.direction.rotate(out.angle + 0.5 * M_PI);
+    out.segs.clear();
+
+    myassert(params.density > 0.0001f && params.density <= 1.f);
+    coord_t line_spacing = coord_t(scale_(fill_dir_params.spacing) / params.density);
+
+    // Bounding box around the source contour, aligned with out.angle.
+    BoundingBox bounding_box = get_extents_rotated(poly_with_offset.polygons_src.contour, - out.angle);
+
+    // Define the flow spacing according to requested density.
+    if (params.full_infill() && ! params.dont_adjust) {
+        // Full infill, adjust the line spacing to fit an integer number of lines.
+        out.line_spacing = Fill::_adjust_solid_spacing(bounding_box.size().x, line_spacing);
+        // Report back the adjusted line spacing.
+        fill_dir_params.spacing = float(unscale(line_spacing));
+    } else {
+        // Extend bounding box so that our pattern will be aligned with the other layers.
+        // Transform the reference point to the rotated coordinate system.
+        Point refpt = rotate_vector.second.rotated(- out.angle);
+        // _align_to_grid will not work correctly with positive pattern_shift.
+        coord_t pattern_shift_scaled = coord_t(scale_(fill_dir_params.pattern_shift)) % line_spacing;
+        refpt.x -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled);
+        bounding_box.merge(Fill::_align_to_grid(
+            bounding_box.min, 
+            Point(line_spacing, line_spacing), 
+            refpt));
+    }
+
+    // Intersect a set of euqally spaced vertical lines wiht expolygon.
+    // n_vlines = ceil(bbox_width / line_spacing)
+    size_t  n_vlines = (bounding_box.max.x - bounding_box.min.x + line_spacing - 1) / line_spacing;
+    coord_t x0 = bounding_box.min.x;
+    if (params.full_infill())
+        x0 += coord_t((line_spacing + SCALED_EPSILON) / 2);
+
+    out.line_spacing = line_spacing;
+    out.start_point = Point(x0, bounding_box.min.y);
+    out.start_point.rotate(out.angle);
+
+#ifdef SLIC3R_DEBUG
+    static int iRun = 0;
+    BoundingBox bbox_svg = poly_with_offset.bounding_box_outer();
+    ::Slic3r::SVG svg(debug_out_path("FillRectilinear2-%d.svg", iRun), bbox_svg); // , scale_(1.));
+    poly_with_offset.export_to_svg(svg);
+    {
+        ::Slic3r::SVG svg(debug_out_path("FillRectilinear2-initial-%d.svg", iRun), bbox_svg); // , scale_(1.));
+        poly_with_offset.export_to_svg(svg);
+    }
+    iRun ++;
+#endif /* SLIC3R_DEBUG */
+
+    // For each contour
+    // Allocate storage for the segments.
+    out.segs.assign(n_vlines, SegmentedIntersectionLine());
+    for (size_t i = 0; i < n_vlines; ++ i) {
+        auto &seg = out.segs[i];
+        seg.idx = i;
+        seg.x   = x0 + coord_t(i) * line_spacing;
+        seg.pos = Point(seg.x, bounding_box.min.y);
+        seg.pos.rotate(out.angle);
+        seg.dir = out.direction;
+    }
+
+    #if 1
+    double cos_a = cos(- out.angle);
+    double sin_a = sin(- out.angle);
+    for (size_t iContour = 0; iContour < poly_with_offset.n_contours; ++ iContour) {
+        const Points &contour = poly_with_offset.contour(iContour).points;
+        if (contour.size() < 2)
+            continue;
+        // For each segment
+        for (size_t iSegment = 0; iSegment < contour.size(); ++ iSegment) {
+            size_t iPrev = ((iSegment == 0) ? contour.size() : iSegment) - 1;
+            const Point *pl = &contour[iPrev];
+            const Point *pr = &contour[iSegment];
+            // Orient the segment to the direction vector.
+            const Point  v  = *pr - *pl;
+            int   orientation = Int128::sign_determinant_2x2_filtered(v.x, v.y, out.direction.x, out.direction.y);
+            if (orientation == 0)
+                // Ignore strictly vertical segments.
+                continue;
+            if (orientation < 0)
+                // Always orient the input segment consistently towards the hatching direction.
+                std::swap(pl, pr);
+            // Which of the equally spaced vertical lines is intersected by this segment?
+            coord_t l = (coord_t)floor(cos_a * pl->x - sin_a * pl->y - EPSILON);
+            coord_t r = (coord_t)ceil (cos_a * pr->x - sin_a * pr->y + EPSILON);
+            // il, ir are the left / right indices of vertical lines intersecting a segment
+            int il = (l - x0) / line_spacing;
+            il = std::max(int(0), il);
+            while (il * line_spacing + x0 < l)
+                ++ il;
+            int ir = (r - x0 + line_spacing) / line_spacing;
+            while (ir * line_spacing + x0 > r)
+                -- ir;
+            ir = std::min(int(out.segs.size()) - 1, ir);
+            if (il > ir)
+                // No vertical line intersects this segment.
+                continue;
+            // The previous tests were done with floating point arithmetics over an epsilon-extended interval.
+            // Now do the same tests with exact arithmetics over the exact interval.
+            while (il <= ir && Int128::orient(out.segs[il].pos, out.segs[il].pos + out.direction, *pl) < 0)
+                ++ il;
+            while (il <= ir && Int128::orient(out.segs[ir].pos, out.segs[ir].pos + out.direction, *pr) > 0)
+                -- ir;
+            if (il > ir)
+                // No vertical line intersects this segment.
+                continue;
+            // Here it is ensured, that
+            // 1) out.seg is not parallel to (pl, pr)
+            // 2) all lines from il to ir intersect <pl, pr>.
+            myassert(il >= 0 && il < out.segs.size());
+            myassert(ir >= 0 && ir < out.segs.size());
+            for (int i = il; i <= ir; ++ i) {
+                myassert(out.segs[i].x == i * line_spacing + x0);
+                myassert(l <= out.segs[i].x);
+                myassert(r >= out.segs[i].x);
+                SegmentIntersection is;
+                is.line     = &out.segs[i];
+                is.expoly_with_offset = &poly_with_offset;
+                is.iContour = iContour;
+                is.iSegment = iSegment;
+                // Test whether the calculated intersection point falls into the bounding box of the input segment.
+                // +-1 to take rounding into account.
+                myassert(is.pos().x + 1 >= std::min(pl->x, pr->x));
+                myassert(is.pos().y + 1 >= std::min(pl->y, pr->y));
+                myassert(is.pos().x     <= std::max(pl->x, pr->x) + 1);
+                myassert(is.pos().y     <= std::max(pl->y, pr->y) + 1);
+                out.segs[i].intersections.push_back(is);
+            }
+        }
+    }
+    #endif
+
+    // Sort the intersections along their segments, specify the intersection types.
+    for (size_t i_seg = 0; i_seg < out.segs.size(); ++ i_seg) {
+        SegmentedIntersectionLine &sil = out.segs[i_seg];
+        // Sort the intersection points using exact rational arithmetic.
+        std::sort(sil.intersections.begin(), sil.intersections.end());
+        // Assign the intersection types, remove duplicate or overlapping intersection points.
+        // When a loop vertex touches a vertical line, intersection point is generated for both segments.
+        // If such two segments are oriented equally, then one of them is removed.
+        // Otherwise the vertex is tangential to the vertical line and both segments are removed.
+        // The same rule applies, if the loop is pinched into a single point and this point touches the vertical line:
+        // The loop has a zero vertical size at the vertical line, therefore the intersection point is removed.
+        size_t j = 0;
+        for (size_t i = 0; i < sil.intersections.size(); ++ i) {
+            // What is the orientation of the segment at the intersection point?
+            size_t iContour = sil.intersections[i].iContour;
+            const Points &contour = poly_with_offset.contour(iContour).points;
+            size_t iSegment = sil.intersections[i].iSegment;
+            size_t iPrev    = ((iSegment == 0) ? contour.size() : iSegment) - 1;
+            coord_t dir = contour[iSegment].x - contour[iPrev].x;
+            bool low = dir > 0;
+            sil.intersections[i].type = poly_with_offset.is_contour_outer(iContour) ? 
+                (low ? SegmentIntersection::OUTER_LOW : SegmentIntersection::OUTER_HIGH) :
+                (low ? SegmentIntersection::INNER_LOW : SegmentIntersection::INNER_HIGH);
+            if (j > 0 && sil.intersections[i].iContour == sil.intersections[j-1].iContour) {
+                // Two successive intersection points on a vertical line with the same contour. This may be a special case.
+                if (sil.intersections[i] == sil.intersections[j-1]) {
+                    // Two successive segments meet exactly at the vertical line.
+        #ifdef SLIC3R_DEBUG
+                    // Verify that the segments of sil.intersections[i] and sil.intersections[j-1] are adjoint.
+                    size_t iSegment2 = sil.intersections[j-1].iSegment;
+                    size_t iPrev2    = ((iSegment2 == 0) ? contour.size() : iSegment2) - 1;
+                    myassert(iSegment == iPrev2 || iSegment2 == iPrev);
+        #endif /* SLIC3R_DEBUG */
+                    if (sil.intersections[i].type == sil.intersections[j-1].type) {
+                        // Two successive segments of the same direction (both to the right or both to the left)
+                        // meet exactly at the vertical line.
+                        // Remove the second intersection point.
+                    } else {
+                        // This is a loop returning to the same point.
+                        // It may as well be a vertex of a loop touching this vertical line.
+                        // Remove both the lines.
+                        -- j;
+                    }
+                } else if (sil.intersections[i].type == sil.intersections[j-1].type) {
+                    // Two non successive segments of the same direction (both to the right or both to the left)
+                    // meet exactly at the vertical line. That means there is a Z shaped path, where the center segment
+                    // of the Z shaped path is aligned with this vertical line.
+                    // Remove one of the intersection points while maximizing the vertical segment length.
+                    if (low) {
+                        // Remove the second intersection point, keep the first intersection point.
+                    } else {
+                        // Remove the first intersection point, keep the second intersection point.
+                        sil.intersections[j-1] = sil.intersections[i];
+                    }
+                } else {
+                    // Vertical line intersects a contour segment at a general position (not at one of its end points).
+                    // or the contour just touches this vertical line with a vertical segment or a sequence of vertical segments.
+                    // Keep both intersection points.
+                    if (j < i)
+                        sil.intersections[j] = sil.intersections[i];
+                    ++ j;
+                }
+            } else {
+                // Vertical line intersects a contour segment at a general position (not at one of its end points).
+                if (j < i)
+                    sil.intersections[j] = sil.intersections[i];
+                ++ j;
+            }
+        }
+        // Shrink the list of intersections, if any of the intersection was removed during the classification.
+        if (j < sil.intersections.size())
+            sil.intersections.erase(sil.intersections.begin() + j, sil.intersections.end());
+    }
+
+    // Verify the segments. If something is wrong, give up.
+#define ASSERT_OR_RETURN(CONDITION) do { assert(CONDITION); if (! (CONDITION)) return false; } while (0)
+#ifdef _MSC_VER
+    #pragma warning(push)
+    #pragma warning(disable: 4127)
+#endif
+    for (size_t i_seg = 0; i_seg < out.segs.size(); ++ i_seg) {
+        SegmentedIntersectionLine &sil = out.segs[i_seg];
+        // The intersection points have to be even.
+        ASSERT_OR_RETURN((sil.intersections.size() & 1) == 0);
+        for (size_t i = 0; i < sil.intersections.size();) {
+            // An intersection segment crossing the bigger contour may cross the inner offsetted contour even number of times.
+            ASSERT_OR_RETURN(sil.intersections[i].type == SegmentIntersection::OUTER_LOW);
+            size_t j = i + 1;
+            ASSERT_OR_RETURN(j < sil.intersections.size());
+            ASSERT_OR_RETURN(sil.intersections[j].type == SegmentIntersection::INNER_LOW || sil.intersections[j].type == SegmentIntersection::OUTER_HIGH);
+            for (; j < sil.intersections.size() && sil.intersections[j].is_inner(); ++ j) ;
+            ASSERT_OR_RETURN(j < sil.intersections.size());
+            ASSERT_OR_RETURN((j & 1) == 1);
+            ASSERT_OR_RETURN(sil.intersections[j].type == SegmentIntersection::OUTER_HIGH);
+            ASSERT_OR_RETURN(i + 1 == j || sil.intersections[j - 1].type == SegmentIntersection::INNER_HIGH);
+            i = j + 1;
+        }
+    }
+#undef ASSERT_OR_RETURN
+#ifdef _MSC_VER
+    #pragma warning(push)
+#endif _MSC_VER
+
+#ifdef SLIC3R_DEBUG
+    // Paint the segments and finalize the SVG file.
+    for (size_t i_seg = 0; i_seg < out.segs.size(); ++ i_seg) {
+        SegmentedIntersectionLine &sil = out.segs[i_seg];
+        for (size_t i = 0; i < sil.intersections.size();) {
+            size_t j = i + 1;
+            for (; j < sil.intersections.size() && sil.intersections[j].is_inner(); ++ j) ;
+            if (i + 1 == j) {
+                svg.draw(Line(sil.intersections[i  ].pos(), sil.intersections[j  ].pos()), "blue");
+            } else {
+                svg.draw(Line(sil.intersections[i  ].pos(), sil.intersections[i+1].pos()), "green");
+                svg.draw(Line(sil.intersections[i+1].pos(), sil.intersections[j-1].pos()), (j - i + 1 > 4) ? "yellow" : "magenta");
+                svg.draw(Line(sil.intersections[j-1].pos(), sil.intersections[j  ].pos()), "green");
+            }
+            i = j + 1;
+        }
+    }
+    svg.Close();
+#endif /* SLIC3R_DEBUG */
+
+
+    return true;
+}
+
+
+
+
+
+
+
+
+/****************************************************************** Legacy code, to be replaced by a graph algorithm ******************************************************************/
+
+
+// Having a segment of a closed polygon, calculate its Euclidian length.
+// The segment indices seg1 and seg2 signify an end point of an edge in the forward direction of the loop,
+// therefore the point p1 lies on poly.points[seg1-1], poly.points[seg1] etc.
+static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Point &p1, size_t seg2, const Point &p2)
+{
+#ifdef SLIC3R_DEBUG
+    // Verify that p1 lies on seg1. This is difficult to verify precisely,
+    // but at least verify, that p1 lies in the bounding box of seg1.
+    for (size_t i = 0; i < 2; ++ i) {
+        size_t seg = (i == 0) ? seg1 : seg2;
+        Point  px  = (i == 0) ? p1   : p2;
+        Point  pa  = poly.points[((seg == 0) ? poly.points.size() : seg) - 1];
+        Point  pb  = poly.points[seg];
+        if (pa.x > pb.x)
+            std::swap(pa.x, pb.x);
+        if (pa.y > pb.y)
+            std::swap(pa.y, pb.y);
+        myassert(px.x >= pa.x && px.x <= pb.x);
+        myassert(px.y >= pa.y && px.y <= pb.y);
+    }
+#endif /* SLIC3R_DEBUG */
+    const Point *pPrev = &p1;
+    const Point *pThis = NULL;
+    coordf_t len = 0;
+    if (seg1 <= seg2) {
+        for (size_t i = seg1; i < seg2; ++ i, pPrev = pThis)
+           len += pPrev->distance_to(*(pThis = &poly.points[i]));
+    } else {
+        for (size_t i = seg1; i < poly.points.size(); ++ i, pPrev = pThis)
+           len += pPrev->distance_to(*(pThis = &poly.points[i]));
+        for (size_t i = 0; i < seg2; ++ i, pPrev = pThis)
+           len += pPrev->distance_to(*(pThis = &poly.points[i]));
+    }
+    len += pPrev->distance_to(p2);
+    return len;
+}
+
+// Append a segment of a closed polygon to a polyline.
+// The segment indices seg1 and seg2 signify an end point of an edge in the forward direction of the loop.
+// Only insert intermediate points between seg1 and seg2.
+static inline void polygon_segment_append(Points &out, const Polygon &polygon, size_t seg1, size_t seg2)
+{
+    if (seg1 == seg2) {
+        // Nothing to append from this segment.
+    } else if (seg1 < seg2) {
+        // Do not append a point pointed to by seg2.
+        out.insert(out.end(), polygon.points.begin() + seg1, polygon.points.begin() + seg2);
+    } else {
+        out.reserve(out.size() + seg2 + polygon.points.size() - seg1);
+        out.insert(out.end(), polygon.points.begin() + seg1, polygon.points.end());
+        // Do not append a point pointed to by seg2.
+        out.insert(out.end(), polygon.points.begin(), polygon.points.begin() + seg2);
+    }
+}
+
+// Append a segment of a closed polygon to a polyline.
+// The segment indices seg1 and seg2 signify an end point of an edge in the forward direction of the loop,
+// but this time the segment is traversed backward.
+// Only insert intermediate points between seg1 and seg2.
+static inline void polygon_segment_append_reversed(Points &out, const Polygon &polygon, size_t seg1, size_t seg2)
+{
+    if (seg1 >= seg2) {
+        out.reserve(seg1 - seg2);
+        for (size_t i = seg1; i > seg2; -- i)
+            out.push_back(polygon.points[i - 1]);
+    } else {
+        // it could be, that seg1 == seg2. In that case, append the complete loop.
+        out.reserve(out.size() + seg2 + polygon.points.size() - seg1);
+        for (size_t i = seg1; i > 0; -- i)
+            out.push_back(polygon.points[i - 1]);
+        for (size_t i = polygon.points.size(); i > seg2; -- i)
+            out.push_back(polygon.points[i - 1]);
+    }
+}
+
+static inline int distance_of_segmens(const Polygon &poly, size_t seg1, size_t seg2, bool forward)
+{
+    int d = int(seg2) - int(seg1);
+    if (! forward)
+        d = - d;
+    if (d < 0)
+        d += int(poly.points.size());
+    return d;
+}
+
+// For a vertical line, an inner contour and an intersection point,
+// find an intersection point on the previous resp. next vertical line.
+// The intersection point is connected with the prev resp. next intersection point with iInnerContour.
+// Return -1 if there is no such point on the previous resp. next vertical line.
+static inline int intersection_on_prev_next_vertical_line(
+    const ExPolygonWithOffset                     &poly_with_offset,
+    const std::vector<SegmentedIntersectionLine>  &segs,
+    size_t                                         iVerticalLine,
+    size_t                                         iInnerContour,
+    size_t                                         iIntersection,
+    bool                                           dir_is_next)
+{
+    size_t iVerticalLineOther = iVerticalLine;
+    if (dir_is_next) {
+        if (++ iVerticalLineOther == segs.size())
+            // No successive vertical line.
+            return -1;
+    } else if (iVerticalLineOther -- == 0) {
+        // No preceding vertical line.
+        return -1;
+    }
+
+    const SegmentedIntersectionLine &il    = segs[iVerticalLine];
+    const SegmentIntersection       &itsct = il.intersections[iIntersection];
+    const SegmentedIntersectionLine &il2   = segs[iVerticalLineOther];
+    const Polygon                   &poly  = poly_with_offset.contour(iInnerContour);
+//    const bool                       ccw   = poly_with_offset.is_contour_ccw(iInnerContour);
+    const bool                       forward = itsct.is_low() == dir_is_next;
+    // Resulting index of an intersection point on il2.
+    int                              out   = -1;
+    // Find an intersection point on iVerticalLineOther, intersecting iInnerContour
+    // at the same orientation as iIntersection, and being closest to iIntersection
+    // in the number of contour segments, when following the direction of the contour.
+    int                              dmin  = std::numeric_limits<int>::max();
+    for (size_t i = 0; i < il2.intersections.size(); ++ i) {
+        const SegmentIntersection &itsct2 = il2.intersections[i];
+        if (itsct.iContour == itsct2.iContour && itsct.type == itsct2.type) {
+            /*
+            if (itsct.is_low()) {
+                myassert(itsct.type == SegmentIntersection::INNER_LOW);
+                myassert(iIntersection > 0);
+                myassert(il.intersections[iIntersection-1].type == SegmentIntersection::OUTER_LOW);                
+                myassert(i > 0);
+                if (il2.intersections[i-1].is_inner())
+                    // Take only the lowest inner intersection point.
+                    continue;
+                myassert(il2.intersections[i-1].type == SegmentIntersection::OUTER_LOW);
+            } else {
+                myassert(itsct.type == SegmentIntersection::INNER_HIGH);
+                myassert(iIntersection+1 < il.intersections.size());
+                myassert(il.intersections[iIntersection+1].type == SegmentIntersection::OUTER_HIGH);
+                myassert(i+1 < il2.intersections.size());
+                if (il2.intersections[i+1].is_inner())
+                    // Take only the highest inner intersection point.
+                    continue;
+                myassert(il2.intersections[i+1].type == SegmentIntersection::OUTER_HIGH);
+            }
+            */
+            // The intersection points lie on the same contour and have the same orientation.
+            // Find the intersection point with a shortest path in the direction of the contour.
+            int d = distance_of_segmens(poly, itsct.iSegment, itsct2.iSegment, forward);
+            if (d < dmin) {
+                out = i;
+                dmin = d;
+            }
+        }
+    }
+    //FIXME this routine is not asymptotic optimal, it will be slow if there are many intersection points along the line.
+    return out;
+}
+
+static inline int intersection_on_prev_vertical_line(
+    const ExPolygonWithOffset                     &poly_with_offset, 
+    const std::vector<SegmentedIntersectionLine>  &segs,
+    size_t                                         iVerticalLine,
+    size_t                                         iInnerContour,
+    size_t                                         iIntersection)
+{
+    return intersection_on_prev_next_vertical_line(poly_with_offset, segs, iVerticalLine, iInnerContour, iIntersection, false);
+}
+
+static inline int intersection_on_next_vertical_line(
+    const ExPolygonWithOffset                     &poly_with_offset, 
+    const std::vector<SegmentedIntersectionLine>  &segs, 
+    size_t                                         iVerticalLine, 
+    size_t                                         iInnerContour, 
+    size_t                                         iIntersection)
+{
+    return intersection_on_prev_next_vertical_line(poly_with_offset, segs, iVerticalLine, iInnerContour, iIntersection, true);
+}
+
+enum IntersectionTypeOtherVLine {
+    // There is no connection point on the other vertical line.
+    INTERSECTION_TYPE_OTHER_VLINE_UNDEFINED = -1,
+    // Connection point on the other vertical segment was found
+    // and it could be followed.
+    INTERSECTION_TYPE_OTHER_VLINE_OK = 0,
+    // The connection segment connects to a middle of a vertical segment.
+    // Cannot follow.
+    INTERSECTION_TYPE_OTHER_VLINE_INNER,
+    // Cannot extend the contor to this intersection point as either the connection segment
+    // or the succeeding vertical segment were already consumed.
+    INTERSECTION_TYPE_OTHER_VLINE_CONSUMED,
+    // Not the first intersection along the contor. This intersection point
+    // has been preceded by an intersection point along the vertical line.
+    INTERSECTION_TYPE_OTHER_VLINE_NOT_FIRST,
+};
+
+// Find an intersection on a previous line, but return -1, if the connecting segment of a perimeter was already extruded.
+static inline IntersectionTypeOtherVLine intersection_type_on_prev_next_vertical_line(
+    const std::vector<SegmentedIntersectionLine>  &segs,
+    size_t                                         iVerticalLine,
+    size_t                                         iIntersection,
+    size_t                                         iIntersectionOther,
+    bool                                           dir_is_next)
+{
+    // This routine will propose a connecting line even if the connecting perimeter segment intersects 
+    // iVertical line multiple times before reaching iIntersectionOther.
+    if (iIntersectionOther == -1)
+        return INTERSECTION_TYPE_OTHER_VLINE_UNDEFINED;
+    myassert(dir_is_next ? (iVerticalLine + 1 < segs.size()) : (iVerticalLine > 0));
+    const SegmentedIntersectionLine &il_this      = segs[iVerticalLine];
+    const SegmentIntersection       &itsct_this   = il_this.intersections[iIntersection];
+    const SegmentedIntersectionLine &il_other     = segs[dir_is_next ? (iVerticalLine+1) : (iVerticalLine-1)];
+    const SegmentIntersection       &itsct_other  = il_other.intersections[iIntersectionOther];
+    myassert(itsct_other.is_inner());
+    myassert(iIntersectionOther > 0);
+    myassert(iIntersectionOther + 1 < il_other.intersections.size());
+    // Is iIntersectionOther at the boundary of a vertical segment?
+    const SegmentIntersection       &itsct_other2 = il_other.intersections[itsct_other.is_low() ? iIntersectionOther - 1 : iIntersectionOther + 1];
+    if (itsct_other2.is_inner())
+        // Cannot follow a perimeter segment into the middle of another vertical segment.
+        // Only perimeter segments connecting to the end of a vertical segment are followed.
+        return INTERSECTION_TYPE_OTHER_VLINE_INNER;
+    myassert(itsct_other.is_low() == itsct_other2.is_low());
+    if (dir_is_next ? itsct_this.consumed_perimeter_right : itsct_other.consumed_perimeter_right)
+        // This perimeter segment was already consumed.
+        return INTERSECTION_TYPE_OTHER_VLINE_CONSUMED;
+    if (itsct_other.is_low() ? itsct_other.consumed_vertical_up : il_other.intersections[iIntersectionOther-1].consumed_vertical_up)
+        // This vertical segment was already consumed.
+        return INTERSECTION_TYPE_OTHER_VLINE_CONSUMED;
+    return INTERSECTION_TYPE_OTHER_VLINE_OK;
+}
+
+static inline IntersectionTypeOtherVLine intersection_type_on_prev_vertical_line(
+    const std::vector<SegmentedIntersectionLine>  &segs, 
+    size_t                                         iVerticalLine, 
+    size_t                                         iIntersection,
+    size_t                                         iIntersectionPrev)
+{
+    return intersection_type_on_prev_next_vertical_line(segs, iVerticalLine, iIntersection, iIntersectionPrev, false);
+}
+
+static inline IntersectionTypeOtherVLine intersection_type_on_next_vertical_line(
+    const std::vector<SegmentedIntersectionLine>  &segs, 
+    size_t                                         iVerticalLine, 
+    size_t                                         iIntersection,
+    size_t                                         iIntersectionNext)
+{
+    return intersection_type_on_prev_next_vertical_line(segs, iVerticalLine, iIntersection, iIntersectionNext, true);
+}
+
+// Measure an Euclidian length of a perimeter segment when going from iIntersection to iIntersection2.
+static inline coordf_t measure_perimeter_prev_next_segment_length(
+    const ExPolygonWithOffset                     &poly_with_offset, 
+    const std::vector<SegmentedIntersectionLine>  &segs,
+    size_t                                         iVerticalLine,
+    size_t                                         iInnerContour,
+    size_t                                         iIntersection,
+    size_t                                         iIntersection2,
+    bool                                           dir_is_next)
+{
+    size_t iVerticalLineOther = iVerticalLine;
+    if (dir_is_next) {
+        if (++ iVerticalLineOther == segs.size())
+            // No successive vertical line.
+            return coordf_t(-1);
+    } else if (iVerticalLineOther -- == 0) {
+        // No preceding vertical line.
+        return coordf_t(-1);
+    }
+
+    const SegmentedIntersectionLine &il     = segs[iVerticalLine];
+    const SegmentIntersection       &itsct  = il.intersections[iIntersection];
+    const SegmentedIntersectionLine &il2    = segs[iVerticalLineOther];
+    const SegmentIntersection       &itsct2 = il2.intersections[iIntersection2];
+    const Polygon                   &poly   = poly_with_offset.contour(iInnerContour);
+//    const bool                       ccw    = poly_with_offset.is_contour_ccw(iInnerContour);
+    myassert(itsct.type == itsct2.type);
+    myassert(itsct.iContour == itsct2.iContour);
+    myassert(itsct.is_inner());
+    const bool                       forward = itsct.is_low() == dir_is_next;
+
+    Point p1 = itsct.pos();
+    Point p2 = itsct2.pos();
+    return forward ?
+        segment_length(poly, itsct .iSegment, p1, itsct2.iSegment, p2) :
+        segment_length(poly, itsct2.iSegment, p2, itsct .iSegment, p1);
+}
+
+static inline coordf_t measure_perimeter_prev_segment_length(
+    const ExPolygonWithOffset                     &poly_with_offset,
+    const std::vector<SegmentedIntersectionLine>  &segs,
+    size_t                                         iVerticalLine,
+    size_t                                         iInnerContour,
+    size_t                                         iIntersection,
+    size_t                                         iIntersection2)
+{
+    return measure_perimeter_prev_next_segment_length(poly_with_offset, segs, iVerticalLine, iInnerContour, iIntersection, iIntersection2, false);
+}
+
+static inline coordf_t measure_perimeter_next_segment_length(
+    const ExPolygonWithOffset                     &poly_with_offset,
+    const std::vector<SegmentedIntersectionLine>  &segs,
+    size_t                                         iVerticalLine,
+    size_t                                         iInnerContour,
+    size_t                                         iIntersection,
+    size_t                                         iIntersection2)
+{
+    return measure_perimeter_prev_next_segment_length(poly_with_offset, segs, iVerticalLine, iInnerContour, iIntersection, iIntersection2, true);
+}
+
+// Append the points of a perimeter segment when going from iIntersection to iIntersection2.
+// The first point (the point of iIntersection) will not be inserted,
+// the last point will be inserted.
+static inline void emit_perimeter_prev_next_segment(
+    const ExPolygonWithOffset                     &poly_with_offset,
+    const std::vector<SegmentedIntersectionLine>  &segs,
+    size_t                                         iVerticalLine,
+    size_t                                         iInnerContour,
+    size_t                                         iIntersection,
+    size_t                                         iIntersection2,
+    Polyline                                      &out,
+    bool                                           dir_is_next)
+{
+    size_t iVerticalLineOther = iVerticalLine;
+    if (dir_is_next) {
+        ++ iVerticalLineOther;
+        myassert(iVerticalLineOther < segs.size());
+    } else {
+        myassert(iVerticalLineOther > 0);
+        -- iVerticalLineOther;
+    }
+
+    const SegmentedIntersectionLine &il     = segs[iVerticalLine];
+    const SegmentIntersection       &itsct  = il.intersections[iIntersection];
+    const SegmentedIntersectionLine &il2    = segs[iVerticalLineOther];
+    const SegmentIntersection       &itsct2 = il2.intersections[iIntersection2];
+    const Polygon                   &poly   = poly_with_offset.contour(iInnerContour);
+//    const bool                       ccw    = poly_with_offset.is_contour_ccw(iInnerContour);
+    myassert(itsct.type == itsct2.type);
+    myassert(itsct.iContour == itsct2.iContour);
+    myassert(itsct.is_inner());
+    const bool                       forward = itsct.is_low() == dir_is_next;
+    // Do not append the first point.
+    // out.points.push_back(Point(il.pos, itsct.pos));
+    if (forward)
+        polygon_segment_append(out.points, poly, itsct.iSegment, itsct2.iSegment);
+    else
+        polygon_segment_append_reversed(out.points, poly, itsct.iSegment, itsct2.iSegment);
+    // Append the last point.
+    out.points.push_back(itsct2.pos());
+}
+
+static inline coordf_t measure_perimeter_segment_on_vertical_line_length(
+    const ExPolygonWithOffset                     &poly_with_offset,
+    const std::vector<SegmentedIntersectionLine>  &segs,
+    size_t                                         iVerticalLine,
+    size_t                                         iInnerContour,
+    size_t                                         iIntersection,
+    size_t                                         iIntersection2,
+    bool                                           forward)
+{
+    const SegmentedIntersectionLine &il = segs[iVerticalLine];
+    const SegmentIntersection       &itsct = il.intersections[iIntersection];
+    const SegmentIntersection       &itsct2 = il.intersections[iIntersection2];
+    const Polygon                   &poly = poly_with_offset.contour(iInnerContour);
+    myassert(itsct.is_inner());
+    myassert(itsct2.is_inner());
+    myassert(itsct.type != itsct2.type);
+    myassert(itsct.iContour == iInnerContour);
+    myassert(itsct.iContour == itsct2.iContour);
+    return forward ?
+        segment_length(poly, itsct .iSegment, itsct.pos(),  itsct2.iSegment, itsct2.pos()) :
+        segment_length(poly, itsct2.iSegment, itsct2.pos(), itsct .iSegment, itsct.pos());
+}
+
+// Append the points of a perimeter segment when going from iIntersection to iIntersection2.
+// The first point (the point of iIntersection) will not be inserted,
+// the last point will be inserted.
+static inline void emit_perimeter_segment_on_vertical_line(
+    const ExPolygonWithOffset                     &poly_with_offset,
+    const std::vector<SegmentedIntersectionLine>  &segs,
+    size_t                                         iVerticalLine,
+    size_t                                         iInnerContour,
+    size_t                                         iIntersection,
+    size_t                                         iIntersection2,
+    Polyline                                      &out,
+    bool                                           forward)
+{
+    const SegmentedIntersectionLine &il = segs[iVerticalLine];
+    const SegmentIntersection       &itsct = il.intersections[iIntersection];
+    const SegmentIntersection       &itsct2 = il.intersections[iIntersection2];
+    const Polygon                   &poly = poly_with_offset.contour(iInnerContour);
+    myassert(itsct.is_inner());
+    myassert(itsct2.is_inner());
+    myassert(itsct.type != itsct2.type);
+    myassert(itsct.iContour == iInnerContour);
+    myassert(itsct.iContour == itsct2.iContour);
+    // Do not append the first point.
+    // out.points.push_back(Point(il.pos, itsct.pos));
+    if (forward)
+        polygon_segment_append(out.points, poly, itsct.iSegment, itsct2.iSegment);
+    else
+        polygon_segment_append_reversed(out.points, poly, itsct.iSegment, itsct2.iSegment);
+    // Append the last point.
+    out.points.push_back(itsct2.pos());
+}
+
+//TBD: For precise infill, measure the area of a slab spanned by an infill line.
+/*
+static inline float measure_outer_contour_slab(
+    const ExPolygonWithOffset                     &poly_with_offset,
+    const std::vector<SegmentedIntersectionLine>  &segs,
+    size_t                                         i_vline,
+    size_t                                         iIntersection)
+{
+    const SegmentedIntersectionLine &il     = segs[i_vline];
+    const SegmentIntersection       &itsct  = il.intersections[i_vline];
+    const SegmentIntersection       &itsct2 = il.intersections[iIntersection2];
+    const Polygon                   &poly   = poly_with_offset.contour((itsct.iContour);
+    myassert(itsct.is_outer());
+    myassert(itsct2.is_outer());
+    myassert(itsct.type != itsct2.type);
+    myassert(itsct.iContour == itsct2.iContour);
+    if (! itsct.is_outer() || ! itsct2.is_outer() || itsct.type == itsct2.type || itsct.iContour != itsct2.iContour)
+        // Error, return zero area.
+        return 0.f;
+
+    // Find possible connection points on the previous / next vertical line.
+    int iPrev = intersection_on_prev_vertical_line(poly_with_offset, segs, i_vline, itsct.iContour, i_intersection);
+    int iNext = intersection_on_next_vertical_line(poly_with_offset, segs, i_vline, itsct.iContour, i_intersection);
+    // Find possible connection points on the same vertical line.
+    int iAbove = iBelow = -1;
+    // Does the perimeter intersect the current vertical line above intrsctn?
+    for (size_t i = i_intersection + 1; i + 1 < seg.intersections.size(); ++ i)
+        if (seg.intersections[i].iContour == itsct.iContour)
+            { iAbove = i; break; }
+    // Does the perimeter intersect the current vertical line below intrsctn?
+    for (int i = int(i_intersection) - 1; i > 0; -- i)
+        if (seg.intersections[i].iContour == itsct.iContour)
+            { iBelow = i; break; }
+
+    if (iSegAbove != -1 && seg.intersections[iAbove].type == SegmentIntersection::OUTER_HIGH) {
+        // Invalidate iPrev resp. iNext, if the perimeter crosses the current vertical line earlier than iPrev resp. iNext.
+        // The perimeter contour orientation.
+        const Polygon &poly = poly_with_offset.contour(itsct.iContour);
+        {
+            int d_horiz = (iPrev  == -1) ? std::numeric_limits<int>::max() :
+                distance_of_segmens(poly, segs[i_vline-1].intersections[iPrev].iSegment, itsct.iSegment, true);
+            int d_down  = (iBelow == -1) ? std::numeric_limits<int>::max() :
+                distance_of_segmens(poly, iSegBelow, itsct.iSegment, true);
+            int d_up    = (iAbove == -1) ? std::numeric_limits<int>::max() :
+                distance_of_segmens(poly, iSegAbove, itsct.iSegment, true);
+            if (intrsctn_type_prev == INTERSECTION_TYPE_OTHER_VLINE_OK && d_horiz > std::min(d_down, d_up))
+                // The vertical crossing comes eralier than the prev crossing.
+                // Disable the perimeter going back.
+                intrsctn_type_prev = INTERSECTION_TYPE_OTHER_VLINE_NOT_FIRST;
+            if (d_up > std::min(d_horiz, d_down))
+                // The horizontal crossing comes earlier than the vertical crossing.
+                vert_seg_dir_valid_mask &= ~DIR_BACKWARD;
+        }
+        {
+            int d_horiz = (iNext     == -1) ? std::numeric_limits<int>::max() :
+                distance_of_segmens(poly, itsct.iSegment, segs[i_vline+1].intersections[iNext].iSegment, true);
+            int d_down  = (iSegBelow == -1) ? std::numeric_limits<int>::max() :
+                distance_of_segmens(poly, itsct.iSegment, iSegBelow, true);
+            int d_up    = (iSegAbove == -1) ? std::numeric_limits<int>::max() :
+                distance_of_segmens(poly, itsct.iSegment, iSegAbove, true);
+            if (d_up > std::min(d_horiz, d_down))
+                // The horizontal crossing comes earlier than the vertical crossing.
+                vert_seg_dir_valid_mask &= ~DIR_FORWARD;
+        }
+    }
+}
+*/
+
+enum DirectionMask
+{
+    DIR_FORWARD  = 1,
+    DIR_BACKWARD = 2
+};
+
+// For the rectilinear, grid, triangles, stars and cubic pattern fill one InfillHatchingSingleDirection structure
+// for each infill direction. The segments stored in InfillHatchingSingleDirection will then form a graph of candidate
+// paths to be extruded.
+static bool fill_hatching_segments_legacy(
+    // Input geometry to be hatch, containing two concentric contours for each input contour.
+    const ExPolygonWithOffset      &poly_with_offset,
+    // fill density, dont_adjust
+    const FillParams               &params,
+    const coord_t                   link_max_length,
+    // Resulting straight segments of the infill graph.
+    InfillHatchingSingleDirection  &hatching,
+    Polylines                      &polylines_out)
+{
+    // At the end, only the new polylines will be rotated back.
+    size_t n_polylines_out_initial = polylines_out.size();
+
+    std::vector<SegmentedIntersectionLine> &segs = hatching.segs;
+
+    // For each outer only chords, measure their maximum distance to the bow of the outer contour.
+    // Mark an outer only chord as consumed, if the distance is low.
+    for (size_t i_vline = 0; i_vline < segs.size(); ++ i_vline) {
+        SegmentedIntersectionLine &seg = segs[i_vline];
+        for (size_t i_intersection = 0; i_intersection + 1 < seg.intersections.size(); ++ i_intersection) {
+            if (seg.intersections[i_intersection].type == SegmentIntersection::OUTER_LOW &&
+                seg.intersections[i_intersection+1].type == SegmentIntersection::OUTER_HIGH) {
+                bool consumed = false;
+//                if (params.full_infill()) {
+//                        measure_outer_contour_slab(poly_with_offset, segs, i_vline, i_ntersection);
+//                } else
+                    consumed = true;
+                seg.intersections[i_intersection].consumed_vertical_up = consumed;
+            }
+        }
+    }
+
+    // Now construct a graph.
+    // Find the first point.
+    // Naively one would expect to achieve best results by chaining the paths by the shortest distance,
+    // but that procedure does not create the longest continuous paths.
+    // A simple "sweep left to right" procedure achieves better results.
+    size_t    i_vline = 0;
+    size_t    i_intersection = size_t(-1);
+    // Follow the line, connect the lines into a graph.
+    // Until no new line could be added to the output path:
+    Point     pointLast;
+    Polyline *polyline_current = NULL;
+    if (! polylines_out.empty())
+        pointLast = polylines_out.back().points.back();
+    for (;;) {
+        if (i_intersection == size_t(-1)) {
+            // The path has been interrupted. Find a next starting point, closest to the previous extruder position.
+            coordf_t dist2min = std::numeric_limits<coordf_t>().max();
+            for (size_t i_vline2 = 0; i_vline2 < segs.size(); ++ i_vline2) {
+                const SegmentedIntersectionLine &seg = segs[i_vline2];
+                if (! seg.intersections.empty()) {
+                    myassert(seg.intersections.size() > 1);
+                    // Even number of intersections with the loops.
+                    myassert((seg.intersections.size() & 1) == 0);
+                    myassert(seg.intersections.front().type == SegmentIntersection::OUTER_LOW);
+                    for (size_t i = 0; i < seg.intersections.size(); ++ i) {
+                        const SegmentIntersection &intrsctn = seg.intersections[i];
+                        if (intrsctn.is_outer()) {
+                            myassert(intrsctn.is_low() || i > 0);
+                            bool consumed = intrsctn.is_low() ? 
+                                intrsctn.consumed_vertical_up : 
+                                seg.intersections[i-1].consumed_vertical_up;
+                            if (! consumed) {
+                                coordf_t dist2 = pointLast.distance_to(intrsctn.pos());
+                                if (dist2 < dist2min) {
+                                    dist2min = dist2;
+                                    i_vline = i_vline2;
+                                    i_intersection = i;
+                                    //FIXME We are taking the first left point always. Verify, that the caller chains the paths
+                                    // by a shortest distance, while reversing the paths if needed.
+                                    //if (polylines_out.empty())
+                                        // Initial state, take the first line, which is the first from the left.
+                                        goto found;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if (i_intersection == size_t(-1))
+                // We are finished.
+                break;
+        found:
+            // Start a new path.
+            polylines_out.push_back(Polyline());
+            polyline_current = &polylines_out.back();
+            // Emit the first point of a path.
+            pointLast = segs[i_vline].intersections[i_intersection].pos();
+            polyline_current->points.push_back(pointLast);
+        }
+
+        // From the initial point (i_vline, i_intersection), follow a path.
+        SegmentedIntersectionLine &seg      = segs[i_vline];
+        SegmentIntersection       *intrsctn = &seg.intersections[i_intersection];
+        bool going_up = intrsctn->is_low();
+        bool try_connect = false;
+        if (going_up) {
+            myassert(! intrsctn->consumed_vertical_up);
+            myassert(i_intersection + 1 < seg.intersections.size());
+            // Step back to the beginning of the vertical segment to mark it as consumed.
+            if (intrsctn->is_inner()) {
+                myassert(i_intersection > 0);
+                -- intrsctn;
+                -- i_intersection;
+            }
+            // Consume the complete vertical segment up to the outer contour.
+            do {
+                intrsctn->consumed_vertical_up = true;
+                ++ intrsctn;
+                ++ i_intersection;
+                myassert(i_intersection < seg.intersections.size());
+            } while (intrsctn->type != SegmentIntersection::OUTER_HIGH);
+            if ((intrsctn - 1)->is_inner()) {
+                // Step back.
+                -- intrsctn;
+                -- i_intersection;
+                myassert(intrsctn->type == SegmentIntersection::INNER_HIGH);
+                try_connect = true;
+            }
+        } else {
+            // Going down.
+            myassert(intrsctn->is_high());
+            myassert(i_intersection > 0);
+            myassert(! (intrsctn - 1)->consumed_vertical_up);
+            // Consume the complete vertical segment up to the outer contour.
+            if (intrsctn->is_inner())
+                intrsctn->consumed_vertical_up = true;
+            do {
+                myassert(i_intersection > 0);
+                -- intrsctn;
+                -- i_intersection;
+                intrsctn->consumed_vertical_up = true;
+            } while (intrsctn->type != SegmentIntersection::OUTER_LOW);
+            if ((intrsctn + 1)->is_inner()) {
+                // Step back.
+                ++ intrsctn;
+                ++ i_intersection;
+                myassert(intrsctn->type == SegmentIntersection::INNER_LOW);
+                try_connect = true;
+            }
+        }
+        if (try_connect) {
+            // Decide, whether to finish the segment, or whether to follow the perimeter.
+
+            // 1) Find possible connection points on the previous / next vertical line.
+            int iPrev = intersection_on_prev_vertical_line(poly_with_offset, segs, i_vline, intrsctn->iContour, i_intersection);
+            int iNext = intersection_on_next_vertical_line(poly_with_offset, segs, i_vline, intrsctn->iContour, i_intersection);
+            IntersectionTypeOtherVLine intrsctn_type_prev = intersection_type_on_prev_vertical_line(segs, i_vline, i_intersection, iPrev);
+            IntersectionTypeOtherVLine intrsctn_type_next = intersection_type_on_next_vertical_line(segs, i_vline, i_intersection, iNext);
+
+            // 2) Find possible connection points on the same vertical line.
+            int iAbove = -1;
+            int iBelow = -1;
+            int iSegAbove = -1;
+            int iSegBelow = -1;
+            {
+                SegmentIntersection::SegmentIntersectionType type_crossing = (intrsctn->type == SegmentIntersection::INNER_LOW) ?
+                    SegmentIntersection::INNER_HIGH : SegmentIntersection::INNER_LOW;
+                // Does the perimeter intersect the current vertical line above intrsctn?
+                for (size_t i = i_intersection + 1; i + 1 < seg.intersections.size(); ++ i)
+//                    if (seg.intersections[i].iContour == intrsctn->iContour && seg.intersections[i].type == type_crossing) {
+                    if (seg.intersections[i].iContour == intrsctn->iContour) {
+                        iAbove = i;
+                        iSegAbove = seg.intersections[i].iSegment;
+                        break;
+                    }
+                // Does the perimeter intersect the current vertical line below intrsctn?
+                for (size_t i = i_intersection - 1; i > 0; -- i)
+//                    if (seg.intersections[i].iContour == intrsctn->iContour && seg.intersections[i].type == type_crossing) {
+                    if (seg.intersections[i].iContour == intrsctn->iContour) {
+                        iBelow = i;
+                        iSegBelow = seg.intersections[i].iSegment;
+                        break;
+                    }
+            }
+
+            // 3) Sort the intersection points, clear iPrev / iNext / iSegBelow / iSegAbove,
+            // if it is preceded by any other intersection point along the contour.
+            unsigned int vert_seg_dir_valid_mask = 
+                (going_up ? 
+                    (iSegAbove != -1 && seg.intersections[iAbove].type == SegmentIntersection::INNER_LOW) :
+                    (iSegBelow != -1 && seg.intersections[iBelow].type == SegmentIntersection::INNER_HIGH)) ?
+                (DIR_FORWARD | DIR_BACKWARD) :
+                0;
+            {
+                // Invalidate iPrev resp. iNext, if the perimeter crosses the current vertical line earlier than iPrev resp. iNext.
+                // The perimeter contour orientation.
+                const bool forward = intrsctn->is_low(); // == poly_with_offset.is_contour_ccw(intrsctn->iContour);
+                const Polygon &poly = poly_with_offset.contour(intrsctn->iContour);
+                {
+                    int d_horiz = (iPrev     == -1) ? std::numeric_limits<int>::max() :
+                        distance_of_segmens(poly, segs[i_vline-1].intersections[iPrev].iSegment, intrsctn->iSegment, forward);
+                    int d_down  = (iSegBelow == -1) ? std::numeric_limits<int>::max() :
+                        distance_of_segmens(poly, iSegBelow, intrsctn->iSegment, forward);
+                    int d_up    = (iSegAbove == -1) ? std::numeric_limits<int>::max() :
+                        distance_of_segmens(poly, iSegAbove, intrsctn->iSegment, forward);
+                    if (intrsctn_type_prev == INTERSECTION_TYPE_OTHER_VLINE_OK && d_horiz > std::min(d_down, d_up))
+                        // The vertical crossing comes eralier than the prev crossing.
+                        // Disable the perimeter going back.
+                        intrsctn_type_prev = INTERSECTION_TYPE_OTHER_VLINE_NOT_FIRST;
+                    if (going_up ? (d_up > std::min(d_horiz, d_down)) : (d_down > std::min(d_horiz, d_up)))
+                        // The horizontal crossing comes earlier than the vertical crossing.
+                        vert_seg_dir_valid_mask &= ~(forward ? DIR_BACKWARD : DIR_FORWARD);
+                }
+                {
+                    int d_horiz = (iNext     == -1) ? std::numeric_limits<int>::max() :
+                        distance_of_segmens(poly, intrsctn->iSegment, segs[i_vline+1].intersections[iNext].iSegment, forward);
+                    int d_down  = (iSegBelow == -1) ? std::numeric_limits<int>::max() :
+                        distance_of_segmens(poly, intrsctn->iSegment, iSegBelow, forward);
+                    int d_up    = (iSegAbove == -1) ? std::numeric_limits<int>::max() :
+                        distance_of_segmens(poly, intrsctn->iSegment, iSegAbove, forward);
+                    if (intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK && d_horiz > std::min(d_down, d_up))
+                        // The vertical crossing comes eralier than the prev crossing.
+                        // Disable the perimeter going forward.
+                        intrsctn_type_next = INTERSECTION_TYPE_OTHER_VLINE_NOT_FIRST;
+                    if (going_up ? (d_up > std::min(d_horiz, d_down)) : (d_down > std::min(d_horiz, d_up)))
+                        // The horizontal crossing comes earlier than the vertical crossing.
+                        vert_seg_dir_valid_mask &= ~(forward ? DIR_FORWARD : DIR_BACKWARD);
+                }
+            }
+
+            // 4) Try to connect to a previous or next vertical line, making a zig-zag pattern.
+            if (intrsctn_type_prev == INTERSECTION_TYPE_OTHER_VLINE_OK || intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK) {
+                coordf_t distPrev = (intrsctn_type_prev != INTERSECTION_TYPE_OTHER_VLINE_OK) ? std::numeric_limits<coord_t>::max() :
+                    measure_perimeter_prev_segment_length(poly_with_offset, segs, i_vline, intrsctn->iContour, i_intersection, iPrev);
+                coordf_t distNext = (intrsctn_type_next != INTERSECTION_TYPE_OTHER_VLINE_OK) ? std::numeric_limits<coord_t>::max() :
+                    measure_perimeter_next_segment_length(poly_with_offset, segs, i_vline, intrsctn->iContour, i_intersection, iNext);
+                // Take the shorter path.
+                //FIXME this may not be always the best strategy to take the shortest connection line now.
+                bool take_next = (intrsctn_type_prev == INTERSECTION_TYPE_OTHER_VLINE_OK && intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK) ?
+                    (distNext < distPrev) : 
+                    intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK;
+                myassert(intrsctn->is_inner());
+                bool skip = params.dont_connect || (link_max_length > 0 && (take_next ? distNext : distPrev) > link_max_length);
+                if (skip) {
+                    // Just skip the connecting contour and start a new path.
+                    goto dont_connect;
+                    polyline_current->points.push_back(intrsctn->pos());
+                    polylines_out.push_back(Polyline()); 
+                    polyline_current = &polylines_out.back(); 
+                    const SegmentedIntersectionLine &il2 = segs[take_next ? (i_vline + 1) : (i_vline - 1)];
+                    polyline_current->points.push_back(il2.intersections[take_next ? iNext : iPrev].pos());
+                } else {
+                    polyline_current->points.push_back(intrsctn->pos());
+                    emit_perimeter_prev_next_segment(poly_with_offset, segs, i_vline, intrsctn->iContour, i_intersection, take_next ? iNext : iPrev, *polyline_current, take_next);
+                }
+                // Mark both the left and right connecting segment as consumed, because one cannot go to this intersection point as it has been consumed.
+                if (iPrev != -1)
+                    segs[i_vline-1].intersections[iPrev].consumed_perimeter_right = true;
+                if (iNext != -1)
+                    intrsctn->consumed_perimeter_right = true;
+                //FIXME consume the left / right connecting segments at the other end of this line? Currently it is not critical because a perimeter segment is not followed if the vertical segment at the other side has already been consumed.
+                // Advance to the neighbor line.
+                if (take_next) {
+                    ++ i_vline;
+                    i_intersection = iNext;
+                } else {
+                    -- i_vline;
+                    i_intersection = iPrev;
+                }
+                continue;
+            } 
+
+            // 5) Try to connect to a previous or next point on the same vertical line.
+            if (vert_seg_dir_valid_mask) {
+                bool valid = true;
+                // Verify, that there is no intersection with the inner contour up to the end of the contour segment.
+                // Verify, that the successive segment has not been consumed yet.
+                if (going_up) {
+                    if (seg.intersections[iAbove].consumed_vertical_up) {
+                        valid = false;
+                    } else {
+                        for (int i = (int)i_intersection + 1; i < iAbove && valid; ++i)
+                            if (seg.intersections[i].is_inner()) 
+                                valid = false;
+                    }
+                } else {
+                    if (seg.intersections[iBelow-1].consumed_vertical_up) {
+                        valid = false;
+                    } else {
+                        for (int i = iBelow + 1; i < (int)i_intersection && valid; ++i)
+                            if (seg.intersections[i].is_inner()) 
+                                valid = false;
+                    }
+                }
+                if (valid) {
+                    const Polygon &poly = poly_with_offset.contour(intrsctn->iContour);
+                    int iNext    = going_up ? iAbove : iBelow;
+                    int iSegNext = going_up ? iSegAbove : iSegBelow;
+                    bool dir_forward = (vert_seg_dir_valid_mask == (DIR_FORWARD | DIR_BACKWARD)) ?
+                        // Take the shorter length between the current and the next intersection point.
+                        (distance_of_segmens(poly, intrsctn->iSegment, iSegNext, true) <
+                         distance_of_segmens(poly, intrsctn->iSegment, iSegNext, false)) :
+                        (vert_seg_dir_valid_mask == DIR_FORWARD);
+                    // Skip this perimeter line?
+                    bool skip = params.dont_connect;
+                    if (! skip && link_max_length > 0) {
+                        coordf_t link_length = measure_perimeter_segment_on_vertical_line_length(
+                            poly_with_offset, segs, i_vline, intrsctn->iContour, i_intersection, iNext, dir_forward);
+                        skip = link_length > link_max_length;
+                    }
+                    polyline_current->points.push_back(intrsctn->pos());
+                    if (skip) {
+                        // Just skip the connecting contour and start a new path.
+                        polylines_out.push_back(Polyline()); 
+                        polyline_current = &polylines_out.back();
+                        polyline_current->points.push_back(seg.intersections[iNext].pos());
+                    } else {
+                        // Consume the connecting contour and the next segment.
+                        emit_perimeter_segment_on_vertical_line(poly_with_offset, segs, i_vline, intrsctn->iContour, i_intersection, iNext, *polyline_current, dir_forward);
+                    }
+                    // Mark both the left and right connecting segment as consumed, because one cannot go to this intersection point as it has been consumed.
+                    // If there are any outer intersection points skipped (bypassed) by the contour,
+                    // mark them as processed.
+                    if (going_up) {
+                        for (int i = (int)i_intersection; i < iAbove; ++ i)
+                            seg.intersections[i].consumed_vertical_up = true;
+                    } else {
+                        for (int i = iBelow; i < (int)i_intersection; ++ i)
+                            seg.intersections[i].consumed_vertical_up = true;
+                    }
+//                    seg.intersections[going_up ? i_intersection : i_intersection - 1].consumed_vertical_up = true;
+                    intrsctn->consumed_perimeter_right = true;
+                    i_intersection = iNext;
+                    if (going_up)
+                        ++ intrsctn;
+                    else
+                        -- intrsctn;
+                    intrsctn->consumed_perimeter_right = true;
+                    continue;
+                }
+            }
+        dont_connect: 
+            // No way to continue the current polyline. Take the rest of the line up to the outer contour.
+            // This will finish the polyline, starting another polyline at a new point.
+            if (going_up)
+                ++ intrsctn;
+            else
+                -- intrsctn;
+        }
+
+        // Finish the current vertical line,
+        // reset the current vertical line to pick a new starting point in the next round.
+        myassert(intrsctn->is_outer());
+        myassert(intrsctn->is_high() == going_up);
+        pointLast = intrsctn->pos();
+        polyline_current->points.push_back(pointLast);
+        // Handle duplicate points and zero length segments.
+        polyline_current->remove_duplicate_points();
+        myassert(! polyline_current->has_duplicate_points());
+        // Handle nearly zero length edges.
+        if (polyline_current->points.size() <= 1 ||
+            (polyline_current->points.size() == 2 &&
+                std::abs(polyline_current->points.front().x - polyline_current->points.back().x) < SCALED_EPSILON &&
+                std::abs(polyline_current->points.front().y - polyline_current->points.back().y) < SCALED_EPSILON))
+            polylines_out.pop_back();
+        intrsctn = NULL;
+        i_intersection = -1;
+        polyline_current = NULL;
+    }
+
+#ifdef SLIC3R_DEBUG
+    {
+        static int iRun = 0;
+        BoundingBox bbox_svg = poly_with_offset.bounding_box_outer();
+        {
+            ::Slic3r::SVG svg(debug_out_path("FillRectilinear2-final-%03d.svg", iRun), bbox_svg); // , scale_(1.));
+            poly_with_offset.export_to_svg(svg);
+            for (size_t i = n_polylines_out_initial; i < polylines_out.size(); ++ i)
+                svg.draw(polylines_out[i].lines(), "black");
+        }
+        // Paint a picture per polyline. This makes it easier to discover the order of the polylines and their overlap.
+        for (size_t i_polyline = n_polylines_out_initial; i_polyline < polylines_out.size(); ++ i_polyline) {
+            ::Slic3r::SVG svg(debug_out_path("FillRectilinear2-final-%03d-%03d.svg", iRun, i_polyline), bbox_svg); // , scale_(1.));
+            svg.draw(polylines_out[i_polyline].lines(), "black");
+        }
+    }
+#endif /* SLIC3R_DEBUG */
+
+    // paths must be rotated back
+    for (Polylines::iterator it = polylines_out.begin() + n_polylines_out_initial; it != polylines_out.end(); ++ it) {
+        // No need to translate, the absolute position is irrelevant.
+        // it->translate(- rotate_vector.second.x, - rotate_vector.second.y);
+        myassert(! it->has_duplicate_points());
+        //it->rotate(rotate_vector.first);
+        //FIXME rather simplify the paths to avoid very short edges?
+        //myassert(! it->has_duplicate_points());
+        it->remove_duplicate_points();
+    }
+
+#ifdef SLIC3R_DEBUG
+    // Verify, that there are no duplicate points in the sequence.
+    for (Polyline &polyline : polylines_out)
+        myassert(! polyline.has_duplicate_points());
+#endif /* SLIC3R_DEBUG */
+
+    return true;
+}
+
+}; // namespace FillRectilinear3_Internal
+
+bool FillRectilinear3::fill_surface_by_lines(const Surface *surface, const FillParams &params, std::vector<FillDirParams> &fill_dir_params, Polylines &polylines_out)
+{
+    myassert(params.density > 0.0001f && params.density <= 1.f);
+
+    const float INFILL_OVERLAP_OVER_SPACING = 0.45f;
+    myassert(INFILL_OVERLAP_OVER_SPACING > 0 && INFILL_OVERLAP_OVER_SPACING < 0.5f);
+
+    // On the polygons of poly_with_offset, the infill lines will be connected.
+    FillRectilinear3_Internal::ExPolygonWithOffset poly_with_offset(
+        surface->expolygon,
+        float(scale_(- (0.5 - INFILL_OVERLAP_OVER_SPACING) * this->spacing)),
+        float(scale_(- 0.5 * this->spacing)));
+    if (poly_with_offset.n_contours_inner == 0) {
+        // Not a single infill line fits.
+        //FIXME maybe one shall trigger the gap fill here?
+        return true;
+    }
+
+    // Rotate polygons so that we can work with vertical lines here
+    std::pair<float, Point> rotate_vector = this->_infill_direction(surface);
+    std::vector<FillRectilinear3_Internal::InfillHatchingSingleDirection> hatching(fill_dir_params.size(), FillRectilinear3_Internal::InfillHatchingSingleDirection());
+    for (size_t i = 0; i < hatching.size(); ++ i)
+        if (! FillRectilinear3_Internal::prepare_infill_hatching_segments(poly_with_offset, params, fill_dir_params[i], rotate_vector, hatching[i]))
+            return false;
+
+    for (size_t i = 0; i < hatching.size(); ++ i)
+        if (! FillRectilinear3_Internal::fill_hatching_segments_legacy(
+                poly_with_offset,
+                params,
+                this->link_max_length,
+                hatching[i],
+                polylines_out))
+            return false;
+
+    return true;
+}
+
+Polylines FillRectilinear3::fill_surface(const Surface *surface, const FillParams &params)
+{
+    Polylines polylines_out;
+    std::vector<FillDirParams> fill_dir_params;
+    fill_dir_params.emplace_back(FillDirParams(this->spacing, 0.f));
+    if (! fill_surface_by_lines(surface, params, fill_dir_params, polylines_out))
+        printf("FillRectilinear3::fill_surface() failed to fill a region.\n");
+    if (params.full_infill() && ! params.dont_adjust)
+        // Return back the adjusted spacing.
+        this->spacing = fill_dir_params.front().spacing;
+    return polylines_out;
+}
+
+Polylines FillGrid3::fill_surface(const Surface *surface, const FillParams &params)
+{
+    // Each linear fill covers half of the target coverage.
+    FillParams params2 = params;
+    params2.density *= 0.5f;
+    Polylines polylines_out;
+    std::vector<FillDirParams> fill_dir_params;
+    fill_dir_params.emplace_back(FillDirParams(this->spacing, 0.f));
+    fill_dir_params.emplace_back(FillDirParams(this->spacing, float(M_PI / 2.)));
+    if (! fill_surface_by_lines(surface, params2, fill_dir_params, polylines_out))
+        printf("FillGrid3::fill_surface() failed to fill a region.\n");
+    return polylines_out;
+}
+
+Polylines FillTriangles3::fill_surface(const Surface *surface, const FillParams &params)
+{
+    // Each linear fill covers 1/3 of the target coverage.
+    FillParams params2 = params;
+    params2.density *= 0.333333333f;
+    Polylines polylines_out;
+    std::vector<FillDirParams> fill_dir_params;
+    fill_dir_params.emplace_back(FillDirParams(this->spacing, 0.));
+    fill_dir_params.emplace_back(FillDirParams(this->spacing, M_PI / 3.));
+    fill_dir_params.emplace_back(FillDirParams(this->spacing, 2. * M_PI / 3.));
+    if (! fill_surface_by_lines(surface, params2, fill_dir_params, polylines_out))
+        printf("FillTriangles3::fill_surface() failed to fill a region.\n");
+    return polylines_out;
+}
+
+Polylines FillStars3::fill_surface(const Surface *surface, const FillParams &params)
+{
+    // Each linear fill covers 1/3 of the target coverage.
+    FillParams params2 = params;
+    params2.density *= 0.333333333f;
+    Polylines polylines_out;
+    std::vector<FillDirParams> fill_dir_params;
+    fill_dir_params.emplace_back(FillDirParams(this->spacing, 0.));
+    fill_dir_params.emplace_back(FillDirParams(this->spacing, M_PI / 3.));
+    fill_dir_params.emplace_back(FillDirParams(this->spacing, 2. * M_PI / 3., 0.5 * this->spacing / params2.density));
+    if (! fill_surface_by_lines(surface, params2, fill_dir_params, polylines_out))
+        printf("FillStars3::fill_surface() failed to fill a region.\n");
+    return polylines_out;
+}
+
+Polylines FillCubic3::fill_surface(const Surface *surface, const FillParams &params)
+{
+    // Each linear fill covers 1/3 of the target coverage.
+    FillParams params2 = params;
+    params2.density *= 0.333333333f;
+    Polylines polylines_out;
+    std::vector<FillDirParams> fill_dir_params;
+    fill_dir_params.emplace_back(FillDirParams(this->spacing, 0.,             z));
+    fill_dir_params.emplace_back(FillDirParams(this->spacing, M_PI / 3.,     -z));
+    fill_dir_params.emplace_back(FillDirParams(this->spacing, 2. * M_PI / 3., z));
+    if (! fill_surface_by_lines(surface, params2, fill_dir_params, polylines_out))
+        printf("FillCubic3::fill_surface() failed to fill a region.\n");
+    return polylines_out;
+}
+
+} // namespace Slic3r
diff --git a/xs/src/libslic3r/Fill/FillRectilinear3.hpp b/xs/src/libslic3r/Fill/FillRectilinear3.hpp
new file mode 100644
index 000000000..5434c1ff6
--- /dev/null
+++ b/xs/src/libslic3r/Fill/FillRectilinear3.hpp
@@ -0,0 +1,83 @@
+#ifndef slic3r_FillRectilinear2_hpp_
+#define slic3r_FillRectilinear2_hpp_
+
+#include "../libslic3r.h"
+
+#include "FillBase.hpp"
+
+namespace Slic3r {
+
+class Surface;
+
+class FillRectilinear3 : public Fill
+{
+public:
+    virtual Fill* clone() const { return new FillRectilinear3(*this); };
+    virtual ~FillRectilinear3() {}
+    virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
+
+    struct FillDirParams
+    {
+        FillDirParams(coordf_t spacing, double angle, coordf_t pattern_shift = 0.f) : 
+            spacing(spacing), angle(angle), pattern_shift(pattern_shift) {}
+        coordf_t    spacing;
+        double      angle;
+        coordf_t    pattern_shift;
+    };
+
+protected:
+	bool fill_surface_by_lines(const Surface *surface, const FillParams &params, std::vector<FillDirParams> &fill_dir_params, Polylines &polylines_out);
+};
+
+class FillGrid3 : public FillRectilinear3
+{
+public:
+    virtual Fill* clone() const { return new FillGrid3(*this); };
+    virtual ~FillGrid3() {}
+    virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
+
+protected:
+	// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
+    virtual float _layer_angle(size_t /* idx */) const { return 0.f; }
+};
+
+class FillTriangles3 : public FillRectilinear3
+{
+public:
+    virtual Fill* clone() const { return new FillTriangles3(*this); };
+    virtual ~FillTriangles3() {}
+    virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
+
+protected:
+	// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
+    virtual float _layer_angle(size_t /* idx */) const { return 0.f; }
+};
+
+class FillStars3 : public FillRectilinear3
+{
+public:
+    virtual Fill* clone() const { return new FillStars3(*this); };
+    virtual ~FillStars3() {}
+    virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
+
+protected:
+    // The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
+    virtual float _layer_angle(size_t /* idx */) const { return 0.f; }
+};
+
+class FillCubic3 : public FillRectilinear3
+{
+public:
+    virtual Fill* clone() const { return new FillCubic3(*this); };
+    virtual ~FillCubic3() {}
+    virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
+
+protected:
+	// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
+    virtual float _layer_angle(size_t /* idx */) const { return 0.f; }
+};
+
+
+}; // namespace Slic3r
+
+#endif // slic3r_FillRectilinear2_hpp_
diff --git a/xs/src/libslic3r/Geometry.hpp b/xs/src/libslic3r/Geometry.hpp
index 8e7fb5c8c..bb3fa1e75 100644
--- a/xs/src/libslic3r/Geometry.hpp
+++ b/xs/src/libslic3r/Geometry.hpp
@@ -49,7 +49,7 @@ static inline bool is_ccw(const Polygon &poly)
 
     // 1) Find the lowest lexicographical point.
     int     imin = 0;
-    for (size_t i = 1; i < poly.points.size(); ++ i) {
+    for (int i = 1; i < poly.points.size(); ++ i) {
         const Point &pmin = poly.points[imin];
         const Point &p    = poly.points[i];
         if (p.x < pmin.x || (p.x == pmin.x && p.y < pmin.y))
diff --git a/xs/src/libslic3r/Int128.hpp b/xs/src/libslic3r/Int128.hpp
new file mode 100644
index 000000000..7dcfed70d
--- /dev/null
+++ b/xs/src/libslic3r/Int128.hpp
@@ -0,0 +1,300 @@
+// This is an excerpt of from the Clipper library by Angus Johnson, see the license below,
+// implementing a 64 x 64 -> 128bit multiply, and 128bit addition, subtraction and compare
+// operations, to be used with exact geometric predicates.
+// The code has been extended by Vojtech Bubnik to use 128 bit intrinsic types
+// and/or 64x64->128 intrinsic functions where possible.
+
+/*******************************************************************************
+*                                                                              *
+* Author    :  Angus Johnson                                                   *
+* Version   :  6.2.9                                                           *
+* Date      :  16 February 2015                                                *
+* Website   :  http://www.angusj.com                                           *
+* Copyright :  Angus Johnson 2010-2015                                         *
+*                                                                              *
+* License:                                                                     *
+* Use, modification & distribution is subject to Boost Software License Ver 1. *
+* http://www.boost.org/LICENSE_1_0.txt                                         *
+*                                                                              *
+* Attributions:                                                                *
+* The code in this library is an extension of Bala Vatti's clipping algorithm: *
+* "A generic solution to polygon clipping"                                     *
+* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63.             *
+* http://portal.acm.org/citation.cfm?id=129906                                 *
+*                                                                              *
+* Computer graphics and geometric modeling: implementation and algorithms      *
+* By Max K. Agoston                                                            *
+* Springer; 1 edition (January 4, 2005)                                        *
+* http://books.google.com/books?q=vatti+clipping+agoston                       *
+*                                                                              *
+* See also:                                                                    *
+* "Polygon Offsetting by Computing Winding Numbers"                            *
+* Paper no. DETC2005-85513 pp. 565-575                                         *
+* ASME 2005 International Design Engineering Technical Conferences             *
+* and Computers and Information in Engineering Conference (IDETC/CIE2005)      *
+* September 24-28, 2005 , Long Beach, California, USA                          *
+* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf              *
+*                                                                              *
+*******************************************************************************/
+
+ #define SLIC3R_DEBUG
+
+// Make assert active if SLIC3R_DEBUG
+#ifdef SLIC3R_DEBUG
+    #undef NDEBUG
+    #define DEBUG
+    #define _DEBUG
+    #undef assert 
+#endif
+
+#include <cassert>
+#include "Point.hpp"
+
+#ifndef _MSC_VER
+	#define HAS_INTRINSIC_128_TYPE
+#endif
+
+//------------------------------------------------------------------------------
+// Int128 class (enables safe math on signed 64bit integers)
+// eg Int128 val1((int64_t)9223372036854775807); //ie 2^63 -1
+//    Int128 val2((int64_t)9223372036854775807);
+//    Int128 val3 = val1 * val2;
+//------------------------------------------------------------------------------
+
+class Int128
+{
+
+#ifdef HAS_INTRINSIC_128_TYPE
+
+/******************************************** Using the intrinsic 128bit x 128bit multiply ************************************************/
+
+public:
+	__int128 value;
+
+	Int128(int64_t lo = 0) : value(lo) {}
+	Int128(const Int128 &v) : value(v.value) {}
+
+	Int128& operator=(const int64_t &rhs) { value = rhs; return *this; }
+
+	uint64_t lo()   const { return uint64_t(value); }
+	int64_t  hi()   const { return int64_t(value >> 64); }
+	int      sign() const { return (value > 0) - (value < 0); }
+
+	bool operator==(const Int128 &rhs) const { return value == rhs.value; }
+	bool operator!=(const Int128 &rhs) const { return value != rhs.value; }
+	bool operator> (const Int128 &rhs) const { return value >  rhs.value; }
+	bool operator< (const Int128 &rhs) const { return value <  rhs.value; }
+	bool operator>=(const Int128 &rhs) const { return value >= rhs.value; }
+	bool operator<=(const Int128 &rhs) const { return value <= rhs.value; }
+
+	Int128& operator+=(const Int128 &rhs) 		{ value += rhs.value; return *this; }
+	Int128  operator+ (const Int128 &rhs) const { return Int128(value + rhs.value); }
+	Int128& operator-=(const Int128 &rhs)		{ value -= rhs.value; return *this; }
+	Int128  operator -(const Int128 &rhs) const { return Int128(value - rhs.value); }
+	Int128  operator -()                  const { return Int128(- value); }
+
+	operator double() 				      const { return double(value); }
+
+	static inline Int128 multiply(int64_t lhs, int64_t rhs) { return Int128(__int128(lhs) * __int128(rhs)); }
+
+	// Evaluate signum of a 2x2 determinant.
+	static int sign_determinant_2x2(int64_t a11, int64_t a12, int64_t a21, int64_t a22)
+	{
+		__int128 det = __int128(a11) * __int128(a22) - __int128(a12) * __int128(a21);
+		return (det > 0) - (det < 0);
+	}
+
+	// Compare two rational numbers.
+	static int compare_rationals(int64_t p1, int64_t q1, int64_t p2, int64_t q2)
+	{
+		int invert = ((q1 < 0) == (q2 < 0)) ? 1 : -1;
+		__int128 det = __int128(p1) * __int128(q2) - __int128(p2) * __int128(q1);
+		return ((det > 0) - (det < 0)) * invert;
+	}
+
+#else /* HAS_INTRINSIC_128_TYPE */
+
+/******************************************** Splitting the 128bit number into two 64bit words *********************************************/
+
+	Int128(int64_t lo = 0) : m_lo((uint64_t)lo), m_hi((lo < 0) ? -1 : 0) {}
+	Int128(const Int128 &val) : m_lo(val.m_lo), m_hi(val.m_hi) {}
+	Int128(const int64_t& hi, const uint64_t& lo) : m_lo(lo), m_hi(hi) {}
+
+	Int128& operator = (const int64_t &val)
+	{
+		m_lo = (uint64_t)val;
+		m_hi = (val < 0) ? -1 : 0;
+		return *this;
+	}
+
+	uint64_t lo()   const { return m_lo; }
+	int64_t  hi()   const { return m_hi; }
+	int      sign() const { return (m_hi == 0) ? (m_lo > 0) : (m_hi > 0) - (m_hi < 0); }
+
+	bool operator == (const Int128 &val) const { return m_hi == val.m_hi && m_lo == val.m_lo; }
+	bool operator != (const Int128 &val) const { return ! (*this == val); }
+	bool operator >  (const Int128 &val) const { return (m_hi == val.m_hi) ? m_lo > val.m_lo : m_hi > val.m_hi; }
+	bool operator <  (const Int128 &val) const { return (m_hi == val.m_hi) ? m_lo < val.m_lo : m_hi < val.m_hi; }
+	bool operator >= (const Int128 &val) const { return ! (*this < val); }
+	bool operator <= (const Int128 &val) const { return ! (*this > val); }
+
+	Int128& operator += (const Int128 &rhs)
+	{
+		m_hi += rhs.m_hi;
+		m_lo += rhs.m_lo;
+		if (m_lo < rhs.m_lo) m_hi++;
+		return *this;
+	}
+
+	Int128 operator + (const Int128 &rhs) const
+	{
+		Int128 result(*this);
+		result+= rhs;
+		return result;
+	}
+
+	Int128& operator -= (const Int128 &rhs)
+	{
+		*this += -rhs;
+		return *this;
+	}
+
+	Int128 operator - (const Int128 &rhs) const
+	{
+		Int128 result(*this);
+		result -= rhs;
+		return result;
+	}
+
+	Int128 operator-() const { return (m_lo == 0) ? Int128(-m_hi, 0) : Int128(~m_hi, ~m_lo + 1); }
+
+	operator double() const
+	{
+		const double shift64 = 18446744073709551616.0; //2^64
+		return (m_hi < 0) ?
+		((m_lo == 0) ? 
+		(double)m_hi * shift64 :
+		-(double)(~m_lo + ~m_hi * shift64)) :
+		(double)(m_lo + m_hi * shift64);
+	}
+
+	static inline Int128 multiply(int64_t lhs, int64_t rhs)
+	{
+#if defined(_MSC_VER) && defined(_WIN64)
+		// On Visual Studio 64bit, use the _mul128() intrinsic function.
+		Int128 result;
+	    result.m_lo = (uint64_t)_mul128(lhs, rhs, &result.m_hi);
+	    return result;
+#else
+	    // This branch should only be executed in case there is neither __int16 type nor _mul128 intrinsic
+	    // function available. This is mostly on 32bit operating systems.
+	    // Use a pure C implementation of _mul128().
+
+		int negate = (lhs < 0) != (rhs < 0);
+
+		if (lhs < 0)
+			lhs = -lhs;
+		uint64_t int1Hi = uint64_t(lhs) >> 32;
+		uint64_t int1Lo = uint64_t(lhs & 0xFFFFFFFF);
+
+		if (rhs < 0)
+			rhs = -rhs;
+		uint64_t int2Hi = uint64_t(rhs) >> 32;
+		uint64_t int2Lo = uint64_t(rhs & 0xFFFFFFFF);
+
+		//because the high (sign) bits in both int1Hi & int2Hi have been zeroed,
+		//there's no risk of 64 bit overflow in the following assignment
+		//(ie: $7FFFFFFF*$FFFFFFFF + $7FFFFFFF*$FFFFFFFF < 64bits)
+		uint64_t a = int1Hi * int2Hi;
+		uint64_t b = int1Lo * int2Lo;
+		//Result = A shl 64 + C shl 32 + B ...
+		uint64_t c = int1Hi * int2Lo + int1Lo * int2Hi;
+
+		Int128 tmp;
+		tmp.m_hi = int64_t(a + (c >> 32));
+		tmp.m_lo = int64_t(c << 32);
+		tmp.m_lo += int64_t(b);
+		if (tmp.m_lo < b) 
+			++ tmp.m_hi;
+		if (negate) 
+			tmp = - tmp;
+		return tmp;
+#endif
+	}
+
+	// Evaluate signum of a 2x2 determinant.
+	static int sign_determinant_2x2(int64_t a11, int64_t a12, int64_t a21, int64_t a22)
+	{
+		return (Int128::multiply(a11, a22) - Int128::multiply(a12, a21)).sign();
+	}
+
+	// Compare two rational numbers.
+	static int compare_rationals(int64_t p1, int64_t q1, int64_t p2, int64_t q2)
+	{
+		int invert = ((q1 < 0) == (q2 < 0)) ? 1 : -1;
+		Int128 det = Int128::multiply(p1, q2) - Int128::multiply(p2, q1);
+		return det.sign() * invert;
+	}
+
+private:
+	uint64_t m_lo;
+	int64_t  m_hi;
+
+
+#endif /* HAS_INTRINSIC_128_TYPE */
+
+
+/******************************************** Common methods ************************************************/
+
+public:
+
+	// Evaluate signum of a 2x2 determinant, use a numeric filter to avoid 128 bit multiply if possible.
+	static int sign_determinant_2x2_filtered(int64_t a11, int64_t a12, int64_t a21, int64_t a22)
+	{
+		// First try to calculate the determinant over the upper 31 bits.
+		// Round p1, p2, q1, q2 to 31 bits.
+		int64_t a11s = (a11 + (1 << 31)) >> 32;
+		int64_t a12s = (a12 + (1 << 31)) >> 32;
+		int64_t a21s = (a21 + (1 << 31)) >> 32;
+		int64_t a22s = (a22 + (1 << 31)) >> 32;
+		// Result fits 63 bits, it is an approximate of the determinant divided by 2^64.
+		int64_t det  = a11s * a22s - a12s * a21s;
+		// Maximum absolute of the remainder of the exact determinant, divided by 2^64.
+		int64_t err  = ((std::abs(a11s) + std::abs(a12s) + std::abs(a21s) + std::abs(a22s)) << 1) + 1;
+		assert(std::abs(det) <= err || ((det > 0) ? 1 : -1) == sign_determinant_2x2(a11, a12, a21, a22));
+		return (std::abs(det) > err) ?
+			((det > 0) ? 1 : -1) :
+			sign_determinant_2x2(a11, a12, a21, a22);
+	}
+
+	// Compare two rational numbers, use a numeric filter to avoid 128 bit multiply if possible.
+	static int compare_rationals_filtered(int64_t p1, int64_t q1, int64_t p2, int64_t q2)
+	{
+		// First try to calculate the determinant over the upper 31 bits.
+		// Round p1, p2, q1, q2 to 31 bits.
+		int     invert = ((q1 < 0) == (q2 < 0)) ? 1 : -1;
+		int64_t q1s = (q1 + (1 << 31)) >> 32;
+		int64_t q2s = (q2 + (1 << 31)) >> 32;
+		if (q1s != 0 && q2s != 0) {
+			int64_t p1s = (p1 + (1 << 31)) >> 32;
+			int64_t p2s = (p2 + (1 << 31)) >> 32;
+			// Result fits 63 bits, it is an approximate of the determinant divided by 2^64.
+			int64_t det = p1s * q2s - p2s * q1s;
+			// Maximum absolute of the remainder of the exact determinant, divided by 2^64.
+			int64_t err = ((std::abs(p1s) + std::abs(q1s) + std::abs(p2s) + std::abs(q2s)) << 1) + 1;
+			assert(std::abs(det) <= err || ((det > 0) ? 1 : -1) * invert == compare_rationals(p1, q1, p2, q2));
+			if (std::abs(det) > err)
+				return ((det > 0) ? 1 : -1) * invert;
+		}
+		return sign_determinant_2x2(p1, q1, p2, q2);
+	}
+
+	// Exact orientation predicate,
+	// returns +1: CCW, 0: collinear, -1: CW.
+	static int orient(const Slic3r::Point &p1, const Slic3r::Point &p2, const Slic3r::Point &p3)
+	{
+		Slic3r::Vector v1(p2 - p1);
+		Slic3r::Vector v2(p3 - p1);
+		return sign_determinant_2x2_filtered(v1.x, v1.y, v2.x, v2.y);
+	}
+};
diff --git a/xs/src/libslic3r/Layer.hpp b/xs/src/libslic3r/Layer.hpp
index 0bb76fe13..333b02831 100644
--- a/xs/src/libslic3r/Layer.hpp
+++ b/xs/src/libslic3r/Layer.hpp
@@ -74,7 +74,10 @@ public:
     void export_region_slices_to_svg_debug(const char *name);
     void export_region_fill_surfaces_to_svg_debug(const char *name);
 
-    private:
+    // Is there any valid extrusion assigned to this LayerRegion?
+    bool has_extrusions() const { return ! this->perimeters.entities.empty() || ! this->fills.entities.empty(); }
+
+private:
     Layer *_layer;
     PrintRegion *_region;
 
@@ -131,7 +134,10 @@ public:
     // Export to "out/LayerRegion-name-%d.svg" with an increasing index with every export.
     void export_region_slices_to_svg_debug(const char *name);
     void export_region_fill_surfaces_to_svg_debug(const char *name);
-    
+
+    // Is there any valid extrusion assigned to this LayerRegion?
+    virtual bool has_extrusions() const { for (auto layerm : this->regions) if (layerm->has_extrusions()) return true; return false; }
+
 protected:
     size_t _id;     // sequential number of layer, 0-based
     PrintObject *_object;
@@ -152,6 +158,9 @@ public:
     // Extrusion paths for the support base and for the support interface and contacts.
     ExtrusionEntityCollection support_fills;
 
+    // Is there any valid extrusion assigned to this LayerRegion?
+    virtual bool has_extrusions() const { return ! support_fills.empty(); }
+
 protected:
     SupportLayer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z, coordf_t slice_z) :
         Layer(id, object, height, print_z, slice_z) {}
diff --git a/xs/src/libslic3r/Point.cpp b/xs/src/libslic3r/Point.cpp
index ad25ba91a..7c1dc91f5 100644
--- a/xs/src/libslic3r/Point.cpp
+++ b/xs/src/libslic3r/Point.cpp
@@ -88,12 +88,6 @@ Point::nearest_point_index(const Points &points) const
     return this->nearest_point_index(p);
 }
 
-template<typename T>
-inline T sqr(const T x)
-{
-    return x * x;
-}
-
 int Point::nearest_point_index(const PointConstPtrs &points) const
 {
     int idx = -1;
diff --git a/xs/src/libslic3r/Point.hpp b/xs/src/libslic3r/Point.hpp
index 8f11bd50a..9fd4f13ae 100644
--- a/xs/src/libslic3r/Point.hpp
+++ b/xs/src/libslic3r/Point.hpp
@@ -27,7 +27,8 @@ typedef std::vector<Pointf3> Pointf3s;
 
 class Point
 {
-    public:
+public:
+    typedef coord_t coord_type;
     coord_t x;
     coord_t y;
     Point(coord_t _x = 0, coord_t _y = 0): x(_x), y(_y) {};
@@ -77,6 +78,7 @@ class Point
 inline Point operator+(const Point& point1, const Point& point2) { return Point(point1.x + point2.x, point1.y + point2.y); }
 inline Point operator-(const Point& point1, const Point& point2) { return Point(point1.x - point2.x, point1.y - point2.y); }
 inline Point operator*(double scalar, const Point& point2) { return Point(scalar * point2.x, scalar * point2.y); }
+inline int64_t cross(const Point &v1, const Point &v2) { return int64_t(v1.x) * int64_t(v2.y) - int64_t(v1.y) * int64_t(v2.x); }
 
 // To be used by std::unordered_map, std::unordered_multimap and friends.
 struct PointHash {
@@ -189,6 +191,7 @@ std::ostream& operator<<(std::ostream &stm, const Pointf &pointf);
 class Pointf
 {
 public:
+    typedef coordf_t coord_type;
     coordf_t x;
     coordf_t y;
     explicit Pointf(coordf_t _x = 0, coordf_t _y = 0): x(_x), y(_y) {};
@@ -239,6 +242,11 @@ class Pointf3 : public Pointf
     Vectorf3 vector_to(const Pointf3 &point) const;
 };
 
+template<typename TO> inline TO convert_to(const Point &src) { return TO(TO::coord_type(src.x), TO::coord_type(src.y)); }
+template<typename TO> inline TO convert_to(const Pointf &src) { return TO(TO::coord_type(src.x), TO::coord_type(src.y)); }
+template<typename TO> inline TO convert_to(const Point3 &src) { return TO(TO::coord_type(src.x), TO::coord_type(src.y), TO::coord_type(src.z)); }
+template<typename TO> inline TO convert_to(const Pointf3 &src) { return TO(TO::coord_type(src.x), TO::coord_type(src.y), TO::coord_type(src.z)); }
+
 } // namespace Slic3r
 
 // start Boost
diff --git a/xs/src/libslic3r/PolylineCollection.cpp b/xs/src/libslic3r/PolylineCollection.cpp
index ca46930c5..ca9c64d23 100644
--- a/xs/src/libslic3r/PolylineCollection.cpp
+++ b/xs/src/libslic3r/PolylineCollection.cpp
@@ -9,11 +9,6 @@ struct Chaining
     size_t idx;
 };
 
-#ifndef sqr
-template<typename T>
-inline T sqr(T x) { return x * x; }
-#endif /* sqr */
-
 template<typename T>
 inline int nearest_point_index(const std::vector<Chaining> &pairs, const Point &start_near, bool no_reverse)
 {
@@ -49,11 +44,8 @@ inline int nearest_point_index(const std::vector<Chaining> &pairs, const Point &
 Polylines PolylineCollection::_chained_path_from(
     const Polylines &src,
     Point start_near,
-    bool  no_reverse
-#if SLIC3R_CPPVER >= 11
-    , bool  move_from_src
-#endif
-    )
+    bool  no_reverse, 
+    bool  move_from_src)
 {
     std::vector<Chaining> endpoints;
     endpoints.reserve(src.size());
@@ -70,15 +62,11 @@ Polylines PolylineCollection::_chained_path_from(
         // find nearest point
         int endpoint_index = nearest_point_index<double>(endpoints, start_near, no_reverse);
         assert(endpoint_index >= 0 && endpoint_index < endpoints.size() * 2);
-#if SLIC3R_CPPVER > 11
         if (move_from_src) {
             retval.push_back(std::move(src[endpoints[endpoint_index/2].idx]));
         } else {
             retval.push_back(src[endpoints[endpoint_index/2].idx]);
         }
-#else
-        retval.push_back(src[endpoints[endpoint_index/2].idx]);
-#endif
         if (endpoint_index & 1)
             retval.back().reverse();
         endpoints.erase(endpoints.begin() + endpoint_index/2);
@@ -87,40 +75,6 @@ Polylines PolylineCollection::_chained_path_from(
     return retval;
 }
 
-#if SLIC3R_CPPVER >= 11
-Polylines PolylineCollection::chained_path(Polylines &&src, bool no_reverse)
-{
-    return (src.empty() || src.front().points.empty()) ?
-        Polylines() :
-        _chained_path_from(src, src.front().first_point(), no_reverse, true);
-}
-
-Polylines PolylineCollection::chained_path_from(Polylines &&src, Point start_near, bool no_reverse)
-{
-    return _chained_path_from(src, start_near, no_reverse, true);
-}
-#endif
-
-Polylines PolylineCollection::chained_path(const Polylines &src, bool no_reverse)
-{
-    return (src.empty() || src.front().points.empty()) ?
-        Polylines() :
-        _chained_path_from(src, src.front().first_point(), no_reverse
-#if SLIC3R_CPPVER >= 11
-        , false
-#endif
-    );
-}
-
-Polylines PolylineCollection::chained_path_from(const Polylines &src, Point start_near, bool no_reverse)
-{
-    return _chained_path_from(src, start_near, no_reverse
-#if SLIC3R_CPPVER >= 11
-        , false
-#endif
-    );
-}
-
 Point PolylineCollection::leftmost_point(const Polylines &polylines)
 {
     if (polylines.empty()) CONFESS("leftmost_point() called on empty PolylineCollection");
@@ -134,10 +88,4 @@ Point PolylineCollection::leftmost_point(const Polylines &polylines)
     return p;
 }
 
-void
-PolylineCollection::append(const Polylines &pp)
-{
-    this->polylines.insert(this->polylines.end(), pp.begin(), pp.end());
-}
-
 } // namespace Slic3r
diff --git a/xs/src/libslic3r/PolylineCollection.hpp b/xs/src/libslic3r/PolylineCollection.hpp
index 80d609410..87fc1985b 100644
--- a/xs/src/libslic3r/PolylineCollection.hpp
+++ b/xs/src/libslic3r/PolylineCollection.hpp
@@ -11,11 +11,8 @@ class PolylineCollection
     static Polylines _chained_path_from(
         const Polylines &src,
         Point start_near,
-        bool no_reverse
-#if SLIC3R_CPPVER >= 11
-        , bool move_from_src
-#endif
-    );
+        bool no_reverse, 
+        bool move_from_src);
 
 public:
     Polylines polylines;
@@ -25,15 +22,24 @@ public:
     	{ retval->polylines = chained_path_from(this->polylines, start_near, no_reverse); }
     Point leftmost_point() const
     	{ return leftmost_point(polylines); }
-    void append(const Polylines &polylines);
+    void append(const Polylines &polylines)
+        { this->polylines.insert(this->polylines.end(), polylines.begin(), polylines.end()); }
 
 	static Point     leftmost_point(const Polylines &polylines);
-#if SLIC3R_CPPVER >= 11
-	static Polylines chained_path(Polylines &&src, bool no_reverse = false);
-	static Polylines chained_path_from(Polylines &&src, Point start_near, bool no_reverse = false);
-#endif
-    static Polylines chained_path(const Polylines &src, bool no_reverse = false);
-    static Polylines chained_path_from(const Polylines &src, Point start_near, bool no_reverse = false);
+	static Polylines chained_path(Polylines &&src, bool no_reverse = false) {
+        return (src.empty() || src.front().points.empty()) ?
+            Polylines() :
+            _chained_path_from(src, src.front().first_point(), no_reverse, true);
+    }
+	static Polylines chained_path_from(Polylines &&src, Point start_near, bool no_reverse = false)
+        { return _chained_path_from(src, start_near, no_reverse, true); }
+    static Polylines chained_path(const Polylines &src, bool no_reverse = false) {
+        return (src.empty() || src.front().points.empty()) ?
+            Polylines() :
+            _chained_path_from(src, src.front().first_point(), no_reverse, false);
+    }
+    static Polylines chained_path_from(const Polylines &src, Point start_near, bool no_reverse = false)
+        { return _chained_path_from(src, start_near, no_reverse, false); }
 };
 
 }
diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp
index 5620a2f42..c292f03c0 100644
--- a/xs/src/libslic3r/PrintConfig.hpp
+++ b/xs/src/libslic3r/PrintConfig.hpp
@@ -202,6 +202,7 @@ public:
     }
 
     virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
+        UNUSED(create);
         OPT_PTR(clip_multipart_objects);
         OPT_PTR(dont_support_bridges);
         OPT_PTR(elefant_foot_compensation);
@@ -283,6 +284,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
     }
 
     virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
+        UNUSED(create);
         OPT_PTR(bottom_solid_layers);
         OPT_PTR(bridge_flow_ratio);
         OPT_PTR(bridge_speed);
@@ -369,6 +371,7 @@ public:
     }
     
     virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
+        UNUSED(create);
         OPT_PTR(before_layer_gcode);
         OPT_PTR(deretract_speed);
         OPT_PTR(end_gcode);
@@ -571,6 +574,7 @@ public:
     }
 
     virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
+        UNUSED(create);
         OPT_PTR(octoprint_host);
         OPT_PTR(octoprint_apikey);
         OPT_PTR(serial_port);
diff --git a/xs/src/libslic3r/Slicing.cpp b/xs/src/libslic3r/Slicing.cpp
index 27cebdd46..e9295d1e3 100644
--- a/xs/src/libslic3r/Slicing.cpp
+++ b/xs/src/libslic3r/Slicing.cpp
@@ -1,5 +1,6 @@
 #include <limits>
 
+#include "libslic3r.h"
 #include "Slicing.hpp"
 #include "SlicingAdaptive.hpp"
 #include "PrintConfig.hpp"
@@ -308,19 +309,6 @@ std::vector<coordf_t> layer_height_profile_adaptive(
     return layer_height_profile;
 }
 
-template <typename T>
-static inline T clamp(const T low, const T high, const T value)
-{
-    return std::max(low, std::min(high, value));
-}
-
-template <typename T>
-static inline T lerp(const T a, const T b, const T t)
-{
-    assert(t >= T(-EPSILON) && t <= T(1.+EPSILON));
-    return (1. - t) * a + t * b;
-}
-
 void adjust_layer_height_profile(
     const SlicingParameters     &slicing_params,
     std::vector<coordf_t> 		&layer_height_profile,
diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h
index b69d9c564..4a68b030d 100644
--- a/xs/src/libslic3r/libslic3r.h
+++ b/xs/src/libslic3r/libslic3r.h
@@ -88,6 +88,10 @@ inline std::string debug_out_path(const char *name, ...)
 	#define PRINTF_ZU "%zu"
 #endif
 
+#ifndef UNUSED
+#define UNUSED(x) (void)(x)
+#endif /* UNUSED */
+
 // Write slices as SVG images into out directory during the 2D processing of the slices.
 // #define SLIC3R_DEBUG_SLICE_PROCESSING
 
@@ -142,6 +146,25 @@ inline std::unique_ptr<T> make_unique(Args&&... args) {
     return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
 }
 
+template<typename T>
+static inline T sqr(T x)
+{
+    return x * x;
+}
+
+template <typename T>
+static inline T clamp(const T low, const T high, const T value)
+{
+    return std::max(low, std::min(high, value));
+}
+
+template <typename T>
+static inline T lerp(const T a, const T b, const T t)
+{
+    assert(t >= T(-EPSILON) && t <= T(1.+EPSILON));
+    return (1. - t) * a + t * b;
+}
+
 } // namespace Slic3r
 
 #endif