diff --git a/src/libslic3r/EdgeGrid.hpp b/src/libslic3r/EdgeGrid.hpp
index 6a9f482a1..bff56523b 100644
--- a/src/libslic3r/EdgeGrid.hpp
+++ b/src/libslic3r/EdgeGrid.hpp
@@ -238,7 +238,14 @@ public:
 	{
 		const Slic3r::Points &ipts = *m_contours[contour_and_segment_idx.first];
 		size_t ipt = contour_and_segment_idx.second;
-		return std::pair<const Slic3r::Point&, const Slic3r::Point&>(ipts[ipt], ipts[(ipt + 1 == ipts.size()) ? 0 : ipt + 1]);
+		return std::pair<const Slic3r::Point&, const Slic3r::Point&>(ipts[ipt], ipts[ipt + 1 == ipts.size() ? 0 : ipt + 1]);
+	}
+
+	Line line(const std::pair<size_t, size_t> &contour_and_segment_idx) const
+	{
+		const Slic3r::Points &ipts = *m_contours[contour_and_segment_idx.first];
+		size_t ipt = contour_and_segment_idx.second;
+		return Line(ipts[ipt], ipts[ipt + 1 == ipts.size() ? 0 : ipt + 1]);
 	}
 
 protected:
diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp
index 5bdd5055e..f6e03dd1c 100644
--- a/src/libslic3r/ExPolygon.cpp
+++ b/src/libslic3r/ExPolygon.cpp
@@ -42,11 +42,11 @@ void ExPolygon::scale(double factor)
         hole.scale(factor);
 }
 
-void ExPolygon::translate(double x, double y)
+void ExPolygon::translate(const Point &p)
 {
-    contour.translate(x, y);
+    contour.translate(p);
     for (Polygon &hole : holes)
-        hole.translate(x, y);
+        hole.translate(p);
 }
 
 void ExPolygon::rotate(double angle)
diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp
index 373853f97..0c8c42368 100644
--- a/src/libslic3r/ExPolygon.hpp
+++ b/src/libslic3r/ExPolygon.hpp
@@ -42,7 +42,8 @@ public:
     operator Polylines() const;
     void clear() { contour.points.clear(); holes.clear(); }
     void scale(double factor);
-    void translate(double x, double y);
+    void translate(double x, double y) { this->translate(Point(coord_t(x), coord_t(y))); }
+    void translate(const Point &vector);
     void rotate(double angle);
     void rotate(double angle, const Point &center);
     double area() const;
diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp
index 7c0213556..f577c42a5 100644
--- a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp
+++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp
@@ -4,6 +4,7 @@
 #include "../Print.hpp"
 #include "../Polygon.hpp"
 #include "../ExPolygon.hpp"
+#include "../Geometry.hpp"
 #include "../ClipperUtils.hpp"
 #include "../SVG.hpp"
 #include "AvoidCrossingPerimeters.hpp"
@@ -16,7 +17,7 @@ namespace Slic3r {
 struct TravelPoint
 {
     Point point;
-    // Index of the polygon containing this point. A negative value indicates that the point is not on any border
+    // Index of the polygon containing this point. A negative value indicates that the point is not on any border.
     int   border_idx;
 };
 
@@ -26,17 +27,11 @@ struct Intersection
     size_t border_idx;
     // Index of the line on the polygon containing this point of intersection.
     size_t line_idx;
-    // Point of intersection projected on the travel path.
-    Point  point_transformed;
     // Point of intersection.
     Point  point;
-
-    Intersection(size_t border_idx, size_t line_idx, const Point &point_transformed, const Point &point)
-        : border_idx(border_idx), line_idx(line_idx), point_transformed(point_transformed), point(point){};
-
-    inline bool operator<(const Intersection &other) const { return this->point_transformed.x() < other.point_transformed.x(); }
 };
 
+// Finding all intersections of a set of contours with a line segment.
 struct AllIntersectionsVisitor
 {
     AllIntersectionsVisitor(const EdgeGrid::Grid &grid, std::vector<Intersection> &intersections)
@@ -45,9 +40,8 @@ struct AllIntersectionsVisitor
 
     AllIntersectionsVisitor(const EdgeGrid::Grid      &grid,
                             std::vector<Intersection> &intersections,
-                            const Matrix2d            &transform_to_x_axis,
                             const Line                &travel_line)
-        : grid(grid), intersections(intersections), transform_to_x_axis(transform_to_x_axis), travel_line(travel_line)
+        : grid(grid), intersections(intersections), travel_line(travel_line)
     {}
 
     void reset() {
@@ -58,16 +52,11 @@ struct AllIntersectionsVisitor
     {
         // Called with a row and colum of the grid cell, which is intersected by a line.
         auto cell_data_range = grid.cell_data_range(iy, ix);
-        for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second;
-             ++it_contour_and_segment) {
-            // End points of the line segment and their vector.
-            auto segment = grid.segment(*it_contour_and_segment);
-
+        for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++it_contour_and_segment) {
             Point intersection_point;
-            if (travel_line.intersection(Line(segment.first, segment.second), &intersection_point) &&
+            if (travel_line.intersection(grid.line(*it_contour_and_segment), &intersection_point) &&
                 intersection_set.find(*it_contour_and_segment) == intersection_set.end()) {
-                intersections.emplace_back(it_contour_and_segment->first, it_contour_and_segment->second,
-                                           (transform_to_x_axis * intersection_point.cast<double>()).cast<coord_t>(), intersection_point);
+                intersections.push_back({ it_contour_and_segment->first, it_contour_and_segment->second, intersection_point });
                 intersection_set.insert(*it_contour_and_segment);
             }
         }
@@ -77,57 +66,42 @@ struct AllIntersectionsVisitor
 
     const EdgeGrid::Grid                                                                 &grid;
     std::vector<Intersection>                                                            &intersections;
-    Matrix2d                                                                              transform_to_x_axis;
     Line                                                                                  travel_line;
     std::unordered_set<std::pair<size_t, size_t>, boost::hash<std::pair<size_t, size_t>>> intersection_set;
 };
 
-// Create a rotation matrix for projection on the given vector
-static Matrix2d rotation_by_direction(const Point &direction)
-{
-    Matrix2d rotation;
-    rotation.block<1, 2>(0, 0) = direction.cast<double>() / direction.cast<double>().norm();
-    rotation(1, 0)             = -rotation(0, 1);
-    rotation(1, 1)             = rotation(0, 0);
-
-    return rotation;
-}
-
-static Point find_first_different_vertex(const Polygon &polygon, const size_t point_idx, const Point &point, bool forward)
+template<bool forward>
+static Point find_first_different_vertex(const Polygon &polygon, const size_t point_idx, const Point &point)
 {
     assert(point_idx < polygon.size());
-    if (point != polygon.points[point_idx])
-        return polygon.points[point_idx];
-
-    int line_idx = int(point_idx);
-    if (forward)
-        for (; point == polygon.points[line_idx]; line_idx = (((line_idx + 1) < int(polygon.points.size())) ? (line_idx + 1) : 0));
+    auto line_idx = int(point_idx);
+    //FIXME endless loop if all points are equal to point?
+    if constexpr (forward)
+        for (; point == polygon.points[line_idx]; line_idx = line_idx + 1 < int(polygon.points.size()) ? line_idx + 1 : 0);
     else
-        for (; point == polygon.points[line_idx]; line_idx = (((line_idx - 1) >= 0) ? (line_idx - 1) : (int(polygon.points.size()) - 1)));
+        for (; point == polygon.points[line_idx]; line_idx = line_idx - 1 >= 0 ? line_idx - 1 : int(polygon.points.size()) - 1);
     return polygon.points[line_idx];
 }
 
+//FIXME will be in Point.h in the master
+template<typename T, int Options>
+inline Eigen::Matrix<T, 2, 1, Eigen::DontAlign> perp(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>>& v) { return Eigen::Matrix<T, 2, 1, Eigen::DontAlign>(-v.y(), v.x()); }
+
 static Vec2d three_points_inward_normal(const Point &left, const Point &middle, const Point &right)
 {
     assert(left != middle);
     assert(middle != right);
-
-    Vec2d normal_1(-1 * (middle.y() - left.y()), middle.x() - left.x());
-    Vec2d normal_2(-1 * (right.y() - middle.y()), right.x() - middle.x());
-    normal_1.normalize();
-    normal_2.normalize();
-
-    return (normal_1 + normal_2).normalized();
+    return (perp(Point(middle - left)).cast<double>().normalized() + perp(Point(right - middle)).cast<double>().normalized()).normalized();
 }
 
 // Compute normal of the polygon's vertex in an inward direction
 static Vec2d get_polygon_vertex_inward_normal(const Polygon &polygon, const size_t point_idx)
 {
-    const size_t left_idx  = (point_idx <= 0) ? (polygon.size() - 1) : (point_idx - 1);
-    const size_t right_idx = (point_idx >= (polygon.size() - 1)) ? 0 : (point_idx + 1);
+    const size_t left_idx  = point_idx == 0 ? polygon.size() - 1 : point_idx - 1;
+    const size_t right_idx = point_idx + 1 == polygon.size() ? 0 : point_idx + 1;
     const Point &middle    = polygon.points[point_idx];
-    const Point &left      = find_first_different_vertex(polygon, left_idx, middle, false);
-    const Point &right     = find_first_different_vertex(polygon, right_idx, middle, true);
+    const Point &left      = find_first_different_vertex<false>(polygon, left_idx, middle);
+    const Point &right     = find_first_different_vertex<true>(polygon, right_idx, middle);
     return three_points_inward_normal(left, middle, right);
 }
 
@@ -140,114 +114,11 @@ static Point get_polygon_vertex_offset(const Polygon &polygon, const size_t poin
 // Compute offset (in the direction of inward normal) of the point(passed on "middle") based on the nearest points laying on the polygon (left_idx and right_idx).
 static Point get_middle_point_offset(const Polygon &polygon, const size_t left_idx, const size_t right_idx, const Point &middle, const coord_t offset)
 {
-    const Point &left  = find_first_different_vertex(polygon, left_idx, middle, false);
-    const Point &right = find_first_different_vertex(polygon, right_idx, middle, true);
+    const Point &left  = find_first_different_vertex<false>(polygon, left_idx, middle);
+    const Point &right = find_first_different_vertex<true>(polygon, right_idx, middle);
     return middle + (three_points_inward_normal(left, middle, right) * double(offset)).cast<coord_t>();
 }
 
-static bool check_if_could_cross_perimeters(const BoundingBox &bbox, const Point &start, const Point &end)
-{
-    bool start_out_of_bound = !bbox.contains(start), end_out_of_bound = !bbox.contains(end);
-    // When both endpoints are out of the bounding box, it needs to check in more detail.
-    if (start_out_of_bound && end_out_of_bound) {
-        Point intersection;
-        return bbox.polygon().intersection(Line(start, end), &intersection);
-    }
-    return true;
-}
-
-static std::pair<Point, Point> clamp_endpoints_by_bounding_box(const BoundingBox &bbox, const Point &start, const Point &end)
-{
-    bool   start_out_of_bound = !bbox.contains(start), end_out_of_bound = !bbox.contains(end);
-    Point  start_clamped = start, end_clamped = end;
-    Points intersections;
-    if (start_out_of_bound || end_out_of_bound) {
-        bbox.polygon().intersections(Line(start, end), &intersections);
-        assert(intersections.size() <= 2);
-    }
-
-    if (start_out_of_bound && !end_out_of_bound && intersections.size() == 1) {
-        start_clamped = intersections[0];
-    } else if (!start_out_of_bound && end_out_of_bound && intersections.size() == 1) {
-        end_clamped = intersections[0];
-    } else if (start_out_of_bound && end_out_of_bound && intersections.size() == 2) {
-        if ((intersections[0] - start).cast<double>().norm() < (intersections[1] - start).cast<double>().norm()) {
-            start_clamped = intersections[0];
-            end_clamped   = intersections[1];
-        } else {
-            start_clamped = intersections[1];
-            end_clamped   = intersections[0];
-        }
-    }
-
-    return std::make_pair(start_clamped, end_clamped);
-}
-
-static inline float get_default_perimeter_spacing(const Print &print)
-{
-    const std::vector<double> &nozzle_diameters = print.config().nozzle_diameter.values;
-    return float(scale_(*std::max_element(nozzle_diameters.begin(), nozzle_diameters.end())));
-}
-
-static float get_perimeter_spacing(const Layer &layer)
-{
-    size_t regions_count     = 0;
-    float  perimeter_spacing = 0.f;
-    for (const LayerRegion *layer_region : layer.regions()) {
-        perimeter_spacing += layer_region->flow(frPerimeter).scaled_spacing();
-        ++regions_count;
-    }
-
-    assert(perimeter_spacing >= 0.f);
-    if (regions_count != 0)
-        perimeter_spacing /= float(regions_count);
-    else
-        perimeter_spacing = get_default_perimeter_spacing(*layer.object()->print());
-    return perimeter_spacing;
-}
-
-static float get_perimeter_spacing_external(const Layer &layer)
-{
-    size_t regions_count     = 0;
-    float  perimeter_spacing = 0.f;
-    for (const PrintObject *object : layer.object()->print()->objects())
-        for (Layer *l : object->layers())
-            if ((layer.print_z - EPSILON) <= l->print_z && l->print_z <= (layer.print_z + EPSILON))
-                for (const LayerRegion *layer_region : l->regions()) {
-                    perimeter_spacing += layer_region->flow(frPerimeter).scaled_spacing();
-                    ++regions_count;
-                }
-
-    assert(perimeter_spacing >= 0.f);
-    if (regions_count != 0)
-        perimeter_spacing /= float(regions_count);
-    else
-        perimeter_spacing = get_default_perimeter_spacing(*layer.object()->print());
-    return perimeter_spacing;
-}
-
-// Check if anyone of ExPolygons contains whole travel.
-template<class T> static bool any_expolygon_contains(const ExPolygons &ex_polygons, const T &travel)
-{
-    for (const ExPolygon &ex_polygon : ex_polygons)
-        if (ex_polygon.contains(travel)) return true;
-
-    return false;
-}
-
-static std::pair<Polygons, Polygons> split_expolygon(const ExPolygons &ex_polygons)
-{
-    Polygons contours, holes;
-    contours.reserve(ex_polygons.size());
-    holes.reserve(std::accumulate(ex_polygons.begin(), ex_polygons.end(), size_t(0),
-                                  [](size_t sum, const ExPolygon &ex_poly) { return sum + ex_poly.holes.size(); }));
-    for (const ExPolygon &ex_poly : ex_polygons) {
-        contours.emplace_back(ex_poly.contour);
-        append(holes, ex_poly.holes);
-    }
-    return std::make_pair(std::move(contours), std::move(holes));
-}
-
 static Polyline to_polyline(const std::vector<TravelPoint> &travel)
 {
     Polyline result;
@@ -265,6 +136,8 @@ static double travel_length(const std::vector<TravelPoint> &travel) {
     return total_length;
 }
 
+// #define AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT
+
 #ifdef AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT
 static void export_travel_to_svg(const Polygons                  &boundary,
                                  const Line                      &original_travel,
@@ -294,102 +167,6 @@ static void export_travel_to_svg(const Polygons                  &boundary,
 }
 #endif /* AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT */
 
-static ExPolygons get_boundary(const Layer &layer)
-{
-    const float perimeter_spacing = get_perimeter_spacing(layer);
-    const float perimeter_offset  = perimeter_spacing / 2.f;
-    size_t      polygons_count    = 0;
-    for (const LayerRegion *layer_region : layer.regions())
-        polygons_count += layer_region->slices.surfaces.size();
-
-    ExPolygons boundary;
-    boundary.reserve(polygons_count);
-    for (const LayerRegion *layer_region : layer.regions())
-        for (const Surface &surface : layer_region->slices.surfaces) boundary.emplace_back(surface.expolygon);
-
-    boundary                      = union_ex(boundary);
-    ExPolygons perimeter_boundary = offset_ex(boundary, -perimeter_offset);
-    ExPolygons result_boundary;
-    if (perimeter_boundary.size() != boundary.size()) {
-        // If any part of the polygon is missing after shrinking, then for misisng parts are is used the boundary of the slice.
-        ExPolygons missing_perimeter_boundary = offset_ex(diff_ex(boundary,
-                                                                  offset_ex(perimeter_boundary, perimeter_offset + float(SCALED_EPSILON) / 2.f)),
-                                                          perimeter_offset + float(SCALED_EPSILON));
-        perimeter_boundary                    = offset_ex(perimeter_boundary, perimeter_offset);
-        perimeter_boundary.reserve(perimeter_boundary.size() + missing_perimeter_boundary.size());
-        perimeter_boundary.insert(perimeter_boundary.end(), missing_perimeter_boundary.begin(), missing_perimeter_boundary.end());
-        // By calling intersection_ex some artifacts arose by previous operations are removed.
-        result_boundary = union_ex(intersection_ex(offset_ex(perimeter_boundary, -perimeter_offset), boundary));
-    } else {
-        result_boundary = std::move(perimeter_boundary);
-    }
-
-    auto [contours, holes] = split_expolygon(boundary);
-    // Add an outer boundary to avoid crossing perimeters from supports
-    ExPolygons outer_boundary = union_ex(
-        diff(static_cast<Polygons>(Geometry::convex_hull(offset(contours, 2.f * perimeter_spacing))),
-             offset(contours, perimeter_spacing + perimeter_offset)));
-    result_boundary.insert(result_boundary.end(), outer_boundary.begin(), outer_boundary.end());
-    ExPolygons holes_boundary = offset_ex(holes, -perimeter_spacing);
-    result_boundary.insert(result_boundary.end(), holes_boundary.begin(), holes_boundary.end());
-    result_boundary = union_ex(result_boundary);
-
-    // Collect all top layers that will not be crossed.
-    polygons_count = 0;
-    for (const LayerRegion *layer_region : layer.regions())
-        for (const Surface &surface : layer_region->fill_surfaces.surfaces)
-            if (surface.is_top()) ++polygons_count;
-
-    if (polygons_count > 0) {
-        ExPolygons top_layer_polygons;
-        top_layer_polygons.reserve(polygons_count);
-        for (const LayerRegion *layer_region : layer.regions())
-            for (const Surface &surface : layer_region->fill_surfaces.surfaces)
-                if (surface.is_top()) top_layer_polygons.emplace_back(surface.expolygon);
-
-        top_layer_polygons = union_ex(top_layer_polygons);
-        return diff_ex(result_boundary, offset_ex(top_layer_polygons, -perimeter_offset));
-    }
-
-    return result_boundary;
-}
-
-static ExPolygons get_boundary_external(const Layer &layer)
-{
-    const float perimeter_spacing = get_perimeter_spacing_external(layer);
-    const float perimeter_offset  = perimeter_spacing / 2.f;
-    ExPolygons  boundary;
-    // Collect all polygons for all printed objects and their instances, which will be printed at the same time as passed "layer".
-    for (const PrintObject *object : layer.object()->print()->objects()) {
-        ExPolygons polygons_per_obj;
-        for (Layer *l : object->layers())
-            if ((layer.print_z - EPSILON) <= l->print_z && l->print_z <= (layer.print_z + EPSILON))
-                for (const LayerRegion *layer_region : l->regions())
-                    for (const Surface &surface : layer_region->slices.surfaces)
-                        polygons_per_obj.emplace_back(surface.expolygon);
-
-        for (const PrintInstance &instance : object->instances()) {
-            size_t boundary_idx = boundary.size();
-            boundary.reserve(boundary.size() + polygons_per_obj.size());
-            boundary.insert(boundary.end(), polygons_per_obj.begin(), polygons_per_obj.end());
-            for (; boundary_idx < boundary.size(); ++boundary_idx) boundary[boundary_idx].translate(instance.shift.x(), instance.shift.y());
-        }
-    }
-    boundary               = union_ex(boundary);
-    auto [contours, holes] = split_expolygon(boundary);
-    // Polygons in which is possible traveling without crossing perimeters of another object.
-    // A convex hull allows removing unnecessary detour caused by following the boundary of the object.
-    ExPolygons result_boundary = union_ex(
-        diff(static_cast<Polygons>(Geometry::convex_hull(offset(contours, 2.f * perimeter_spacing))),
-             offset(contours,  perimeter_spacing + perimeter_offset)));
-    // All holes are extended for forcing travel around the outer perimeter of a hole when a hole is crossed.
-    ExPolygons holes_boundary = union_ex(diff(offset(holes, perimeter_spacing), offset(holes, perimeter_offset)));
-    result_boundary.reserve(result_boundary.size() + holes_boundary.size());
-    result_boundary.insert(result_boundary.end(), holes_boundary.begin(), holes_boundary.end());
-    result_boundary = union_ex(result_boundary);
-    return result_boundary;
-}
-
 // Returns a direction of the shortest path along the polygon boundary
 enum class Direction { Forward, Backward };
 static Direction get_shortest_direction(const Lines &lines,
@@ -422,29 +199,89 @@ static Direction get_shortest_direction(const Lines &lines,
     return (total_length_forward < total_length_backward) ? Direction::Forward : Direction::Backward;
 }
 
-static std::vector<TravelPoint> simplify_travel(const EdgeGrid::Grid& edge_grid, const std::vector<TravelPoint>& travel, const Polygons& boundaries, const bool use_heuristics);
-
-static size_t avoid_perimeters(const Polygons           &boundaries,
-                               const EdgeGrid::Grid     &edge_grid,
-                               const Point              &start,
-                               const Point              &end,
-                               const bool                use_heuristics,
-                               std::vector<TravelPoint> *result_out)
+// Straighten the travel path as long as it does not collide with the contours stored in edge_grid.
+static std::vector<TravelPoint> simplify_travel(const EdgeGrid::Grid &edge_grid, const std::vector<TravelPoint> &travel)
 {
-    const Point direction           = end - start;
-    Matrix2d    transform_to_x_axis = rotation_by_direction(direction);
-
-    const Line travel_line_orig(start, end);
-    const Line travel_line((transform_to_x_axis * start.cast<double>()).cast<coord_t>(),
-                           (transform_to_x_axis * end.cast<double>()).cast<coord_t>());
-
-    std::vector<Intersection> intersections;
+    // Visitor to check for a collision of a line segment with any contour stored inside the edge_grid.
+    struct Visitor
     {
-        AllIntersectionsVisitor visitor(edge_grid, intersections, transform_to_x_axis, travel_line_orig);
-        edge_grid.visit_cells_intersecting_line(start, end, visitor);
+        Visitor(const EdgeGrid::Grid &grid) : grid(grid) {}
+
+        bool operator()(coord_t iy, coord_t ix)
+        {
+            assert(pt_current != nullptr);
+            assert(pt_next != nullptr);
+            // Called with a row and colum of the grid cell, which is intersected by a line.
+            auto cell_data_range = grid.cell_data_range(iy, ix);
+            this->intersect      = false;
+            for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++it_contour_and_segment) {
+                // End points of the line segment and their vector.
+                auto segment = grid.segment(*it_contour_and_segment);
+                if (Geometry::segments_intersect(segment.first, segment.second, *pt_current, *pt_next)) {
+                    this->intersect = true;
+                    return false;
+                }
+            }
+            // Continue traversing the grid along the edge.
+            return true;
+        }
+
+        const EdgeGrid::Grid &grid;
+        const Slic3r::Point  *pt_current = nullptr;
+        const Slic3r::Point  *pt_next    = nullptr;
+        bool                  intersect  = false;
+    } visitor(edge_grid);
+
+    std::vector<TravelPoint> simplified_path;
+    simplified_path.reserve(travel.size());
+    simplified_path.emplace_back(travel.front());
+
+    // Try to skip some points in the path.
+    //FIXME maybe use a binary search to trim the line?
+    //FIXME how about searching tangent point at long segments? 
+    for (size_t point_idx = 1; point_idx < travel.size(); ++point_idx) {
+        const Point &current_point = travel[point_idx - 1].point;
+        TravelPoint  next          = travel[point_idx];
+
+        visitor.pt_current = &current_point;
+
+        for (size_t point_idx_2 = point_idx + 1; point_idx_2 < travel.size(); ++point_idx_2) {
+            if (travel[point_idx_2].point == current_point) {
+                next      = travel[point_idx_2];
+                point_idx = point_idx_2;
+                continue;
+            }
+
+            visitor.pt_next = &travel[point_idx_2].point;
+            edge_grid.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor);
+            // Check if deleting point causes crossing a boundary
+            if (!visitor.intersect) {
+                next      = travel[point_idx_2];
+                point_idx = point_idx_2;
+            }
+        }
+
+        simplified_path.emplace_back(next);
     }
 
-    std::sort(intersections.begin(), intersections.end());
+    return simplified_path;
+}
+
+// Called by avoid_perimeters() and by simplify_travel_heuristics().
+static size_t avoid_perimeters_inner(const Polygons           &boundaries,
+                                     const EdgeGrid::Grid     &edge_grid,
+                                     const Point              &start,
+                                     const Point              &end,
+                                     std::vector<TravelPoint> &result_out)
+{
+    // Find all intersections between boundaries and the line segment, sort them along the line segment.
+    std::vector<Intersection> intersections;
+    {
+        AllIntersectionsVisitor visitor(edge_grid, intersections, Line(start, end));
+        edge_grid.visit_cells_intersecting_line(start, end, visitor);
+        Vec2d dir = (end - start).cast<double>();
+        std::sort(intersections.begin(), intersections.end(), [dir](const auto &l, const auto &r) { return (r.point - l.point).cast<double>().dot(dir) > 0.; });
+    }
 
     std::vector<TravelPoint> result;
     result.push_back({start, -1});
@@ -500,24 +337,23 @@ static size_t avoid_perimeters(const Polygons           &boundaries,
 #ifdef AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT
     {
         static int iRun = 0;
-        export_travel_to_svg(boundaries, travel_line_orig, result, intersections,
-                             debug_out_path("AvoidCrossingPerimeters-initial-%d.svg", iRun++));
+        export_travel_to_svg(boundaries, Line(start, end), result, intersections,
+                             debug_out_path("AvoidCrossingPerimetersInner-initial-%d.svg", iRun++));
     }
 #endif /* AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT */
 
-    if(!intersections.empty())
-        result = simplify_travel(edge_grid, result, boundaries, use_heuristics);
+    if (! intersections.empty())
+        result = simplify_travel(edge_grid, result);
 
 #ifdef AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT
     {
         static int iRun = 0;
-        export_travel_to_svg(boundaries, travel_line_orig, result, intersections,
-                             debug_out_path("AvoidCrossingPerimeters-final-%d.svg", iRun++));
+        export_travel_to_svg(boundaries, Line(start, end), result, intersections,
+                             debug_out_path("AvoidCrossingPerimetersInner-final-%d.svg", iRun++));
     }
 #endif /* AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT */
 
-    result_out->reserve(result_out->size() + result.size());
-    result_out->insert(result_out->end(), result.begin(), result.end());
+    append(result_out, std::move(result));
     return intersections.size();
 }
 
@@ -563,10 +399,10 @@ static std::vector<TravelPoint> simplify_travel_heuristics(const EdgeGrid::Grid
                 visitor.reset();
                 visitor.travel_line.a       = current.point;
                 visitor.travel_line.b       = possible_new_next.point;
-                visitor.transform_to_x_axis = rotation_by_direction(visitor.travel_line.vector());
                 edge_grid.visit_cells_intersecting_line(visitor.travel_line.a, visitor.travel_line.b, visitor);
                 if (!intersections.empty()) {
-                    std::sort(intersections.begin(), intersections.end());
+                    Vec2d dir = (visitor.travel_line.b - visitor.travel_line.a).cast<double>();
+                    std::sort(intersections.begin(), intersections.end(), [dir](const auto &l, const auto &r) { return (r.point - l.point).cast<double>().dot(dir) > 0.; });
                     size_t last_border_idx_count = 0;
                     for (const Intersection &intersection : intersections)
                         if (int(intersection.border_idx) == possible_new_next.border_idx)
@@ -576,9 +412,9 @@ static std::vector<TravelPoint> simplify_travel_heuristics(const EdgeGrid::Grid
                         continue;
 
                     std::vector<TravelPoint> possible_shortcut;
-                    avoid_perimeters(boundaries, edge_grid, current.point, possible_new_next.point, false, &possible_shortcut);
+                    avoid_perimeters_inner(boundaries, edge_grid, current.point, possible_new_next.point, possible_shortcut);
                     double shortcut_travel = travel_length(possible_shortcut);
-                    if (path_length > shortcut_travel && (path_length - shortcut_travel) > new_path_shorter_by) {
+                    if (path_length > shortcut_travel && path_length - shortcut_travel > new_path_shorter_by) {
                         new_path_shorter_by = path_length - shortcut_travel;
                         shortcut            = possible_shortcut;
                         new_next            = possible_new_next;
@@ -600,78 +436,44 @@ static std::vector<TravelPoint> simplify_travel_heuristics(const EdgeGrid::Grid
     return simplified_path;
 }
 
-static std::vector<TravelPoint> simplify_travel(const EdgeGrid::Grid           &edge_grid,
-                                                const std::vector<TravelPoint> &travel,
-                                                const Polygons                 &boundaries,
-                                                const bool                      use_heuristics)
+// Called by AvoidCrossingPerimeters::travel_to()
+static size_t avoid_perimeters(const Polygons           &boundaries,
+                               const EdgeGrid::Grid     &edge_grid,
+                               const Point              &start,
+                               const Point              &end,
+                               Polyline                 &result_out)
 {
-    struct Visitor
+    // Travel line is completely or partially inside the bounding box.
+    std::vector<TravelPoint> path;
+    size_t num_intersections = avoid_perimeters_inner(boundaries, edge_grid, start, end, path);
+    if (num_intersections) {
+        path = simplify_travel_heuristics(edge_grid, path, boundaries);
+        std::reverse(path.begin(), path.end());
+        path = simplify_travel_heuristics(edge_grid, path, boundaries);
+        std::reverse(path.begin(), path.end());
+    }
+
+    result_out = to_polyline(path);
+
+#ifdef AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT
     {
-        Visitor(const EdgeGrid::Grid &grid) : grid(grid) {}
+        static int iRun = 0;
+        export_travel_to_svg(boundaries, Line(start, end), path, {}, debug_out_path("AvoidCrossingPerimeters-final-%d.svg", iRun ++));
+    }
+#endif /* AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT */
 
-        bool operator()(coord_t iy, coord_t ix)
-        {
-            assert(pt_current != nullptr);
-            assert(pt_next != nullptr);
-            // Called with a row and colum of the grid cell, which is intersected by a line.
-            auto cell_data_range = grid.cell_data_range(iy, ix);
-            this->intersect      = false;
-            for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++it_contour_and_segment) {
-                // End points of the line segment and their vector.
-                auto segment = grid.segment(*it_contour_and_segment);
-                if (Geometry::segments_intersect(segment.first, segment.second, *pt_current, *pt_next)) {
-                    this->intersect = true;
-                    return false;
-                }
-            }
-            // Continue traversing the grid along the edge.
+    return num_intersections;
+}
+
+// Check if anyone of ExPolygons contains whole travel.
+// called by need_wipe()
+template<class T> static bool any_expolygon_contains(const ExPolygons &ex_polygons, const T &travel)
+{
+    //FIXME filter by bounding boxes!
+    for (const ExPolygon &ex_polygon : ex_polygons)
+        if (ex_polygon.contains(travel))
             return true;
-        }
-
-        const EdgeGrid::Grid &grid;
-        const Slic3r::Point  *pt_current = nullptr;
-        const Slic3r::Point  *pt_next    = nullptr;
-        bool                  intersect  = false;
-    } visitor(edge_grid);
-
-    std::vector<TravelPoint> simplified_path;
-    simplified_path.reserve(travel.size());
-    simplified_path.emplace_back(travel.front());
-
-    // Try to skip some points in the path.
-    for (size_t point_idx = 1; point_idx < travel.size(); ++point_idx) {
-        const Point &current_point = travel[point_idx - 1].point;
-        TravelPoint  next          = travel[point_idx];
-
-        visitor.pt_current = &current_point;
-
-        for (size_t point_idx_2 = point_idx + 1; point_idx_2 < travel.size(); ++point_idx_2) {
-            if (travel[point_idx_2].point == current_point) {
-                next      = travel[point_idx_2];
-                point_idx = point_idx_2;
-                continue;
-            }
-
-            visitor.pt_next = &travel[point_idx_2].point;
-            edge_grid.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor);
-            // Check if deleting point causes crossing a boundary
-            if (!visitor.intersect) {
-                next      = travel[point_idx_2];
-                point_idx = point_idx_2;
-            }
-        }
-
-        simplified_path.emplace_back(next);
-    }
-
-    if(use_heuristics) {
-        simplified_path = simplify_travel_heuristics(edge_grid, simplified_path, boundaries);
-        std::reverse(simplified_path.begin(),simplified_path.end());
-        simplified_path = simplify_travel_heuristics(edge_grid, simplified_path, boundaries);
-        std::reverse(simplified_path.begin(),simplified_path.end());
-    }
-
-    return simplified_path;
+    return false;
 }
 
 static bool need_wipe(const GCode      &gcodegen,
@@ -692,11 +494,8 @@ static bool need_wipe(const GCode      &gcodegen,
             if (any_expolygon_contains(slice, original_travel)) {
                 // Check if original_travel and result_travel are not same.
                 // If both are the same, then it is possible to skip testing of result_travel
-                if (result_travel.size() == 2 && result_travel.first_point() == original_travel.a && result_travel.last_point() == original_travel.b) {
-                    wipe_needed = false;
-                } else {
-                    wipe_needed = !any_expolygon_contains(slice, result_travel);
-                }
+                wipe_needed = !(result_travel.size() > 2 && result_travel.first_point() == original_travel.a && result_travel.last_point() == original_travel.b) &&
+                              !any_expolygon_contains(slice, result_travel);
             } else {
                 wipe_needed = true;
             }
@@ -719,28 +518,27 @@ Polyline AvoidCrossingPerimeters::travel_to(const GCode &gcodegen, const Point &
     Point    end           = point + scaled_origin;
     Polyline result_pl;
     size_t   travel_intersection_count = 0;
-    if (!check_if_could_cross_perimeters(use_external ? m_bbox_external : m_bbox, start, end)) {
-        result_pl                    = Polyline({start, end});
-        travel_intersection_count = 0;
+    Vec2d startf = start.cast<double>();
+    Vec2d endf   = end  .cast<double>();
+    // Trim the travel line by the bounding box.
+    if (Geometry::liang_barsky_line_clipping(startf, endf, use_external ? m_bbox_external : m_bbox)) {
+        // Travel line is completely or partially inside the bounding box.
+        travel_intersection_count = use_external ? 
+            avoid_perimeters(m_boundaries_external, m_grid_external, startf.cast<coord_t>(), endf.cast<coord_t>(), result_pl) :
+            avoid_perimeters(m_boundaries,          m_grid,          startf.cast<coord_t>(), endf.cast<coord_t>(), result_pl);
+        result_pl.points.front() = start;
+        result_pl.points.back()  = end;
     } else {
-        std::vector<TravelPoint> result;
-        auto [start_clamped, end_clamped] = clamp_endpoints_by_bounding_box(use_external ? m_bbox_external : m_bbox, start, end);
-        if (use_external)
-            travel_intersection_count = avoid_perimeters(m_boundaries_external, m_grid_external, start_clamped, end_clamped, true, &result);
-        else
-            travel_intersection_count = avoid_perimeters(m_boundaries, m_grid, start_clamped, end_clamped, true, &result);
-
-        result_pl = to_polyline(result);
+        // Travel line is completely outside the bounding box.
+        result_pl                 = {start, end};
+        travel_intersection_count = 0;
     }
 
-    result_pl.points.front() = start;
-    result_pl.points.back()  = end;
-
     Line travel(start, end);
     double max_detour_length scale_(gcodegen.config().avoid_crossing_perimeters_max_detour);
-    if ((max_detour_length > 0) && ((result_pl.length() - travel.length()) > max_detour_length)) {
-        result_pl = Polyline({start, end});
-    }
+    if (max_detour_length > 0 && (result_pl.length() - travel.length()) > max_detour_length)
+        result_pl = {start, end};
+
     if (use_external) {
         result_pl.translate(-scaled_origin);
         *could_be_wipe_disabled = false;
@@ -750,6 +548,172 @@ Polyline AvoidCrossingPerimeters::travel_to(const GCode &gcodegen, const Point &
     return result_pl;
 }
 
+// ************************************* AvoidCrossingPerimeters::init_layer() *****************************************
+
+// called by get_perimeter_spacing() / get_perimeter_spacing_external()
+static inline float get_default_perimeter_spacing(const Print &print)
+{
+    //FIXME better use extruders printing this PrintObject or this Print?
+    //FIXME maybe better use an average of printing extruders?
+    const std::vector<double> &nozzle_diameters = print.config().nozzle_diameter.values;
+    return float(scale_(*std::max_element(nozzle_diameters.begin(), nozzle_diameters.end())));
+}
+
+// called by get_boundary()
+static float get_perimeter_spacing(const Layer &layer)
+{
+    size_t regions_count     = 0;
+    float  perimeter_spacing = 0.f;
+    //FIXME not all regions are printing. Collect only non-empty regions?
+    for (const LayerRegion *layer_region : layer.regions()) {
+        perimeter_spacing += layer_region->flow(frPerimeter).scaled_spacing();
+        ++ regions_count;
+    }
+
+    assert(perimeter_spacing >= 0.f);
+    if (regions_count != 0)
+        perimeter_spacing /= float(regions_count);
+    else
+        perimeter_spacing = get_default_perimeter_spacing(*layer.object()->print());
+    return perimeter_spacing;
+}
+
+// called by get_boundary_external()
+static float get_perimeter_spacing_external(const Layer &layer)
+{
+    size_t regions_count     = 0;
+    float  perimeter_spacing = 0.f;
+    for (const PrintObject *object : layer.object()->print()->objects())
+        //FIXME with different layering, layers on other objects will not be found at this object's print_z.
+        // Search an overlap of layers?
+        if (const Layer *l = object->get_layer_at_printz(layer.print_z, EPSILON); l) 
+            //FIXME not all regions are printing. Collect only non-empty regions?
+            for (const LayerRegion *layer_region : l->regions()) {
+                perimeter_spacing += layer_region->flow(frPerimeter).scaled_spacing();
+                ++ regions_count;
+            }
+
+    assert(perimeter_spacing >= 0.f);
+    if (regions_count != 0)
+        perimeter_spacing /= float(regions_count);
+    else
+        perimeter_spacing = get_default_perimeter_spacing(*layer.object()->print());
+    return perimeter_spacing;
+}
+
+// called by AvoidCrossingPerimeters::init_layer()->get_boundary()/get_boundary_external()
+static std::pair<Polygons, Polygons> split_expolygon(const ExPolygons &ex_polygons)
+{
+    Polygons contours, holes;
+    contours.reserve(ex_polygons.size());
+    holes.reserve(std::accumulate(ex_polygons.begin(), ex_polygons.end(), size_t(0),
+                                  [](size_t sum, const ExPolygon &ex_poly) { return sum + ex_poly.holes.size(); }));
+    for (const ExPolygon &ex_poly : ex_polygons) {
+        contours.emplace_back(ex_poly.contour);
+        append(holes, ex_poly.holes);
+    }
+    return std::make_pair(std::move(contours), std::move(holes));
+}
+
+// called by AvoidCrossingPerimeters::init_layer()
+static ExPolygons get_boundary(const Layer &layer)
+{
+    const float perimeter_spacing = get_perimeter_spacing(layer);
+    const float perimeter_offset  = perimeter_spacing / 2.f;
+    size_t      polygons_count    = 0;
+    for (const LayerRegion *layer_region : layer.regions())
+        polygons_count += layer_region->slices.surfaces.size();
+
+    ExPolygons boundary;
+    boundary.reserve(polygons_count);
+    for (const LayerRegion *layer_region : layer.regions())
+        for (const Surface &surface : layer_region->slices.surfaces)
+            boundary.emplace_back(surface.expolygon);
+
+    boundary                      = union_ex(boundary);
+    ExPolygons perimeter_boundary = offset_ex(boundary, -perimeter_offset);
+    ExPolygons result_boundary;
+    if (perimeter_boundary.size() != boundary.size()) {
+        //FIXME ???
+        // If any part of the polygon is missing after shrinking, then for misisng parts are is used the boundary of the slice.
+        ExPolygons missing_perimeter_boundary = offset_ex(diff_ex(boundary,
+                                                                  offset_ex(perimeter_boundary, perimeter_offset + float(SCALED_EPSILON) / 2.f)),
+                                                          perimeter_offset + float(SCALED_EPSILON));
+        perimeter_boundary                    = offset_ex(perimeter_boundary, perimeter_offset);
+        append(perimeter_boundary, std::move(missing_perimeter_boundary));
+        // By calling intersection_ex some artifacts arose by previous operations are removed.
+        result_boundary = intersection_ex(offset_ex(perimeter_boundary, -perimeter_offset), boundary);
+    } else {
+        result_boundary = std::move(perimeter_boundary);
+    }
+
+    auto [contours, holes] = split_expolygon(boundary);
+    // Add an outer boundary to avoid crossing perimeters from supports
+    ExPolygons outer_boundary = union_ex(
+        //FIXME flip order of offset and convex_hull
+        diff(static_cast<Polygons>(Geometry::convex_hull(offset(contours, 2.f * perimeter_spacing))),
+             offset(contours, perimeter_spacing + perimeter_offset)));
+    result_boundary.insert(result_boundary.end(), outer_boundary.begin(), outer_boundary.end());
+    ExPolygons holes_boundary = offset_ex(holes, -perimeter_spacing);
+    result_boundary.insert(result_boundary.end(), holes_boundary.begin(), holes_boundary.end());
+    result_boundary = union_ex(result_boundary);
+
+    // Collect all top layers that will not be crossed.
+    polygons_count = 0;
+    for (const LayerRegion *layer_region : layer.regions())
+        for (const Surface &surface : layer_region->fill_surfaces.surfaces)
+            if (surface.is_top()) ++polygons_count;
+
+    if (polygons_count > 0) {
+        ExPolygons top_layer_polygons;
+        top_layer_polygons.reserve(polygons_count);
+        for (const LayerRegion *layer_region : layer.regions())
+            for (const Surface &surface : layer_region->fill_surfaces.surfaces)
+                if (surface.is_top()) top_layer_polygons.emplace_back(surface.expolygon);
+
+        top_layer_polygons = union_ex(top_layer_polygons);
+        return diff_ex(result_boundary, offset_ex(top_layer_polygons, -perimeter_offset));
+    }
+
+    return result_boundary;
+}
+
+// called by AvoidCrossingPerimeters::init_layer()
+static ExPolygons get_boundary_external(const Layer &layer)
+{
+    const float perimeter_spacing = get_perimeter_spacing_external(layer);
+    const float perimeter_offset  = perimeter_spacing / 2.f;
+    ExPolygons  boundary;
+    // Collect all polygons for all printed objects and their instances, which will be printed at the same time as passed "layer".
+    for (const PrintObject *object : layer.object()->print()->objects()) {
+        ExPolygons polygons_per_obj;
+        //FIXME with different layering, layers on other objects will not be found at this object's print_z.
+        // Search an overlap of layers?
+        if (const Layer* l = object->get_layer_at_printz(layer.print_z, EPSILON); l) 
+            for (const LayerRegion *layer_region : l->regions())
+                for (const Surface &surface : layer_region->slices.surfaces)
+                    polygons_per_obj.emplace_back(surface.expolygon);
+
+        for (const PrintInstance &instance : object->instances()) {
+            size_t boundary_idx = boundary.size();
+            boundary.insert(boundary.end(), polygons_per_obj.begin(), polygons_per_obj.end());
+            for (; boundary_idx < boundary.size(); ++boundary_idx)
+                boundary[boundary_idx].translate(instance.shift);
+        }
+    }
+    boundary               = union_ex(boundary);
+    auto [contours, holes] = split_expolygon(boundary);
+    // Polygons in which is possible traveling without crossing perimeters of another object.
+    // A convex hull allows removing unnecessary detour caused by following the boundary of the object.
+    ExPolygons result_boundary = union_ex(
+        //FIXME flip order of offset and convex_hull
+        diff(static_cast<Polygons>(Geometry::convex_hull(offset(contours, 2.f * perimeter_spacing))),
+             offset(contours,  perimeter_spacing + perimeter_offset)));
+    // All holes are extended for forcing travel around the outer perimeter of a hole when a hole is crossed.
+    append(result_boundary, union_ex(diff(offset(holes, perimeter_spacing), offset(holes, perimeter_offset))));
+    return union_ex(result_boundary);
+}
+
 void AvoidCrossingPerimeters::init_layer(const Layer &layer)
 {
     m_slice.clear();
@@ -757,19 +721,25 @@ void AvoidCrossingPerimeters::init_layer(const Layer &layer)
     m_boundaries_external.clear();
 
     for (const LayerRegion *layer_region : layer.regions())
+        //FIXME making copies?
         append(m_slice, (ExPolygons) layer_region->slices);
 
     m_boundaries = to_polygons(get_boundary(layer));
     m_boundaries_external = to_polygons(get_boundary_external(layer));
 
-    m_bbox = get_extents(m_boundaries);
-    m_bbox.offset(SCALED_EPSILON);
-    m_bbox_external = get_extents(m_boundaries_external);
-    m_bbox_external.offset(SCALED_EPSILON);
+    BoundingBox bbox(get_extents(m_boundaries));
+    bbox.offset(SCALED_EPSILON);
+    BoundingBox bbox_external = get_extents(m_boundaries_external);
+    bbox_external.offset(SCALED_EPSILON);
 
-    m_grid.set_bbox(m_bbox);
+    m_bbox = BoundingBoxf(bbox.min.cast<double>(), bbox.max.cast<double>());
+    m_bbox_external = BoundingBoxf(bbox_external.min.cast<double>(), bbox_external.max.cast<double>());
+
+    m_grid.set_bbox(bbox);
+    //FIXME 1mm grid?
     m_grid.create(m_boundaries, coord_t(scale_(1.)));
-    m_grid_external.set_bbox(m_bbox_external);
+    m_grid_external.set_bbox(bbox_external);
+    //FIXME 1mm grid?
     m_grid_external.create(m_boundaries_external, coord_t(scale_(1.)));
 }
 
diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp
index d33311a90..bdae775a1 100644
--- a/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp
+++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp
@@ -47,9 +47,9 @@ private:
     // Collection of boundaries used for detection of crossing perimetrs for travels outside object
     Polygons       m_boundaries_external;
     // Bounding box of m_boundaries
-    BoundingBox    m_bbox;
+    BoundingBoxf   m_bbox;
     // Bounding box of m_boundaries_external
-    BoundingBox    m_bbox_external;
+    BoundingBoxf   m_bbox_external;
     EdgeGrid::Grid m_grid;
     EdgeGrid::Grid m_grid_external;
 };
diff --git a/src/libslic3r/MultiPoint.cpp b/src/libslic3r/MultiPoint.cpp
index a00dd802b..03f7ff59c 100644
--- a/src/libslic3r/MultiPoint.cpp
+++ b/src/libslic3r/MultiPoint.cpp
@@ -18,13 +18,6 @@ void MultiPoint::scale(double factor_x, double factor_y)
     }
 }
 
-void MultiPoint::translate(double x, double y)
-{
-    Vector v(x, y);
-    for (Point &pt : points)
-        pt += v;
-}
-
 void MultiPoint::translate(const Point &v)
 {
     for (Point &pt : points)
diff --git a/src/libslic3r/MultiPoint.hpp b/src/libslic3r/MultiPoint.hpp
index 653e59cd8..b7a5ab684 100644
--- a/src/libslic3r/MultiPoint.hpp
+++ b/src/libslic3r/MultiPoint.hpp
@@ -28,7 +28,7 @@ public:
     MultiPoint& operator=(MultiPoint &&other) { points = std::move(other.points); return *this; }
     void scale(double factor);
     void scale(double factor_x, double factor_y);
-    void translate(double x, double y);
+    void translate(double x, double y) { this->translate(Point(coord_t(x), coord_t(y))); }
     void translate(const Point &vector);
     void rotate(double angle) { this->rotate(cos(angle), sin(angle)); }
     void rotate(double cos_angle, double sin_angle);
diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt
index 75d236a54..962e2e04d 100644
--- a/xs/CMakeLists.txt
+++ b/xs/CMakeLists.txt
@@ -62,7 +62,6 @@ set(XS_XSP_FILES
     ${XSP_DIR}/Layer.xsp
     ${XSP_DIR}/Line.xsp
     ${XSP_DIR}/Model.xsp
-    ${XSP_DIR}/MotionPlanner.xsp
     ${XSP_DIR}/PerimeterGenerator.xsp
     ${XSP_DIR}/PlaceholderParser.xsp
     ${XSP_DIR}/Point.xsp