diff --git a/src/libslic3r/JumpPointSearch.cpp b/src/libslic3r/JumpPointSearch.cpp
index 59bb1165e..888db296b 100644
--- a/src/libslic3r/JumpPointSearch.cpp
+++ b/src/libslic3r/JumpPointSearch.cpp
@@ -25,6 +25,7 @@
 
 namespace Slic3r {
 
+// execute fn for each pixel on the line. If fn returns false, terminate the iteration
 template<typename PointFn> void dda(coord_t x0, coord_t y0, coord_t x1, coord_t y1, const PointFn &fn)
 {
     coord_t dx    = abs(x1 - x0);
@@ -39,7 +40,7 @@ template<typename PointFn> void dda(coord_t x0, coord_t y0, coord_t x1, coord_t
     dy *= 2;
 
     for (; n > 0; --n) {
-        fn(x, y);
+        if (!fn(x, y)) return;
 
         if (error > 0) {
             x += x_inc;
@@ -55,11 +56,11 @@ template<typename PointFn> void dda(coord_t x0, coord_t y0, coord_t x1, coord_t
 // may call the fn on the same coordiantes multiple times!
 template<typename PointFn> void double_dda_with_offset(coord_t x0, coord_t y0, coord_t x1, coord_t y1, const PointFn &fn)
 {
-    Vec2d normal = Point{y1 - y0, x1 - x0}.cast<double>().normalized();
-    normal.x() = ceil(normal.x());
-    normal.y() = ceil(normal.y());
-    Point start_offset = Point(x0,y0) + (normal).cast<coord_t>();
-    Point end_offset = Point(x1,y1) + (normal).cast<coord_t>();
+    Vec2d normal       = Point{y1 - y0, x1 - x0}.cast<double>().normalized();
+    normal.x()         = ceil(normal.x());
+    normal.y()         = ceil(normal.y());
+    Point start_offset = Point(x0, y0) + (normal).cast<coord_t>();
+    Point end_offset   = Point(x1, y1) + (normal).cast<coord_t>();
 
     dda(x0, y0, x1, y1, fn);
     dda(start_offset.x(), start_offset.y(), end_offset.x(), end_offset.y(), fn);
@@ -95,7 +96,7 @@ private:
 
     bool is_jump_point(CellPositionType pos, CellPositionType forward_dir) const
     {
-        if (abs(forward_dir.x()) + abs(forward_dir.y()) == 2) { 
+        if (abs(forward_dir.x()) + abs(forward_dir.y()) == 2) {
             // diagonal
             CellPositionType horizontal_check_dir = CellPositionType{forward_dir.x(), 0};
             CellPositionType vertical_check_dir   = CellPositionType{0, forward_dir.y()};
@@ -169,8 +170,11 @@ public:
 
     float goal_heuristic(Node n) const { return n.position == target ? -1.f : (target - n.position).template cast<double>().norm(); }
 
-    size_t unique_id(Node n) const { return (static_cast<size_t>(uint16_t(n.position.x())) << 16) + static_cast<size_t>(uint16_t(n.position.y())); }
-    
+    size_t unique_id(Node n) const
+    {
+        return (static_cast<size_t>(uint16_t(n.position.x())) << 16) + static_cast<size_t>(uint16_t(n.position.y()));
+    }
+
     const std::vector<CellPositionType> all_directions{{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}};
 };
 
@@ -189,6 +193,7 @@ void JPSPathFinder::add_obstacles(const Lines &obstacles)
         obstacle_min.x() = std::min(obstacle_min.x(), x);
         obstacle_min.y() = std::min(obstacle_min.y(), y);
         inpassable.insert(Pixel{x, y});
+        return true;
     };
 
     for (const Line &l : obstacles) {
@@ -200,36 +205,13 @@ void JPSPathFinder::add_obstacles(const Lines &obstacles)
 
 void JPSPathFinder::add_obstacles(const Layer *layer, const Point &global_origin)
 {
-    if (layer != nullptr) { this->print_z = layer->print_z; }
+    if (layer == nullptr) return;
 
-    auto  store_obstacle = [&](coord_t x, coord_t y) { 
-        obstacle_max.x() = std::max(obstacle_max.x(), x);
-        obstacle_max.y() = std::max(obstacle_max.y(), y);
-        obstacle_min.x() = std::min(obstacle_min.x(), x);
-        obstacle_min.y() = std::min(obstacle_min.y(), y);
-        inpassable.insert(Pixel{x, y}); 
-        };
+    this->print_z = layer->print_z;
     Lines obstacles;
-    for (size_t step = 0; step < 3; step++) {
-        if (layer != nullptr) {
-            obstacles.insert(obstacles.end(), layer->malformed_lines.begin(), layer->malformed_lines.end());
-            layer = layer->lower_layer;
-        } else {
-            break;
-        }
-    }
-
-    for (const Line &l : obstacles) {
-        Pixel start = pixelize(l.a + global_origin);
-        Pixel end   = pixelize(l.b + global_origin);
-        double_dda_with_offset(start.x(), start.y(), end.x(), end.y(), store_obstacle);
-    }
-#ifdef DEBUG_FILES
-    ::Slic3r::SVG svg(debug_out_path(("obstacles_jps" + std::to_string(print_z) + "_" + std::to_string(rand() % 1000)).c_str()).c_str(),
-                      get_extents(obstacles));
-    svg.draw(obstacles);
-    svg.Close();
-#endif
+    obstacles.reserve(layer->malformed_lines.size());
+    for (const Line &l : layer->malformed_lines) { obstacles.push_back(Line{l.a + global_origin, l.b + global_origin}); }
+    add_obstacles(obstacles);
 }
 
 Polyline JPSPathFinder::find_path(const Point &p0, const Point &p1)
@@ -238,21 +220,40 @@ Polyline JPSPathFinder::find_path(const Point &p0, const Point &p1)
     Pixel end   = pixelize(p1);
     if (inpassable.empty() || (start - end).cast<float>().norm() < 3.0) { return Polyline{p0, p1}; }
 
-    BoundingBox search_box({start,end,obstacle_max,obstacle_min});
-    search_box.max += Pixel(1,1);
-    search_box.min -= Pixel(1,1);
+    if (inpassable.find(start) != inpassable.end()) {
+        dda(start.x(), start.y(), end.x(), end.y(), [&](coord_t x, coord_t y) {
+            if (inpassable.find(Pixel(x, y)) == inpassable.end() || start == end) { // new start not found yet, and xy passable
+                start = Pixel(x, y);
+                return false;
+            }
+            return true;
+        });
+    }
 
+    if (inpassable.find(end) != inpassable.end()) {
+        dda(end.x(), end.y(), start.x(), start.y(), [&](coord_t x, coord_t y) {
+            if (inpassable.find(Pixel(x, y)) == inpassable.end() || start == end) { // new start not found yet, and xy passable
+                end = Pixel(x, y);
+                return false;
+            }
+            return true;
+        });
+    }
 
-    BoundingBox bounding_square(Points{start,end});
-    bounding_square.max += Pixel(5,5);
-    bounding_square.min -= Pixel(5,5);
-    coord_t bounding_square_size = 2*std::max(bounding_square.size().x(),bounding_square.size().y());
+    BoundingBox search_box({start, end, obstacle_max, obstacle_min});
+    search_box.max += Pixel(1, 1);
+    search_box.min -= Pixel(1, 1);
+
+    BoundingBox bounding_square(Points{start, end});
+    bounding_square.max += Pixel(5, 5);
+    bounding_square.min -= Pixel(5, 5);
+    coord_t bounding_square_size = 2 * std::max(bounding_square.size().x(), bounding_square.size().y());
     bounding_square.max.x() += (bounding_square_size - bounding_square.size().x()) / 2;
     bounding_square.min.x() -= (bounding_square_size - bounding_square.size().x()) / 2;
     bounding_square.max.y() += (bounding_square_size - bounding_square.size().y()) / 2;
     bounding_square.min.y() -= (bounding_square_size - bounding_square.size().y()) / 2;
 
-    // Intersection - limit the search box to a square area around the start and end, to fasten the path searching 
+    // Intersection - limit the search box to a square area around the start and end, to fasten the path searching
     search_box.max = search_box.max.cwiseMin(bounding_square.max);
     search_box.min = search_box.min.cwiseMax(bounding_square.min);
 
@@ -283,9 +284,7 @@ Polyline JPSPathFinder::find_path(const Point &p0, const Point &p1)
             closest_qnode = astar_cache[closest_qnode].parent;
         }
     } else {
-        for (const auto& node : out_nodes) {
-            out_path.push_back(node.position);
-        }
+        for (const auto &node : out_nodes) { out_path.push_back(node.position); }
         out_path.push_back(start);
     }
 
@@ -335,7 +334,11 @@ Polyline JPSPathFinder::find_path(const Point &p0, const Point &p1)
             if (i - index_of_last_stored_point < 2) continue;
             bool passable       = true;
             auto store_obstacle = [&](coord_t x, coord_t y) {
-                if (Pixel(x, y) != start && Pixel(x, y) != end && inpassable.find(Pixel(x, y)) != inpassable.end()) { passable = false; };
+                if (Pixel(x, y) != start && Pixel(x, y) != end && inpassable.find(Pixel(x, y)) != inpassable.end()) {
+                    passable = false;
+                    return false;
+                }
+                return true;
             };
             dda(tmp_path.back().x(), tmp_path.back().y(), out_path[i].x(), out_path[i].y(), store_obstacle);
             if (!passable) {
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index 2fee76828..dac4d3c6e 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -58,7 +58,6 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
     // Cache the plenty of parameters, which influence the G-code generator only,
     // or they are only notes not influencing the generated G-code.
     static std::unordered_set<std::string> steps_gcode = {
-        "avoid_curled_filament_during_travels",
         "avoid_crossing_perimeters",
         "avoid_crossing_perimeters_max_detour",
         "bed_shape",
@@ -223,6 +222,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
             osteps.emplace_back(posInfill);
             osteps.emplace_back(posSupportMaterial);
             steps.emplace_back(psSkirtBrim);
+        } else if (opt_key == "avoid_curled_filament_during_travels") {
+            osteps.emplace_back(posEstimateCurledExtrusions);
         } else {
             // for legacy, if we can't handle this option let's invalidate all steps
             //FIXME invalidate all steps of all objects as well?