diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
index 35e7e160d..83f7bd246 100644
--- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
+++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
@@ -167,6 +167,8 @@ struct NfpPConfig {
                        const ItemGroup&              // remaining items
                        )> before_packing;
 
+    std::function<void(const ItemGroup &, NfpPConfig &config)> on_preload;
+
     NfpPConfig(): rotations({0.0, Pi/2.0, Pi, 3*Pi/2}),
         alignment(Alignment::CENTER), starting_point(Alignment::CENTER) {}
 };
@@ -577,6 +579,12 @@ public:
         Base::clearItems();
     }
 
+    void preload(const ItemGroup& packeditems) {
+        Base::preload(packeditems);
+        if (config_.on_preload)
+            config_.on_preload(packeditems, config_);
+    }
+
 private:
 
     using Shapes = TMultiShape<RawShape>;
diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp
index 705e213e3..eaa9726dd 100644
--- a/src/libslic3r/Arrange.cpp
+++ b/src/libslic3r/Arrange.cpp
@@ -109,6 +109,7 @@ void fill_config(PConf& pcfg, const ArrangeParams &params) {
 
 // Apply penalty to object function result. This is used only when alignment
 // after arrange is explicitly disabled (PConfig::Alignment::DONT_ALIGN)
+// Also, this will only work well for Box shaped beds.
 static double fixed_overfit(const std::tuple<double, Box>& result, const Box &binbb)
 {
     double score = std::get<0>(result);
@@ -348,6 +349,17 @@ public:
         
         m_pconf.object_function = get_objfn();
 
+        m_pconf.on_preload = [this](const ItemGroup &items, PConfig &cfg) {
+            if (items.empty()) return;
+
+            cfg.alignment = PConfig::Alignment::DONT_ALIGN;
+            auto bb = sl::boundingBox(m_bin);
+            auto bbcenter = bb.center();
+            cfg.object_function = [this, bb, bbcenter](const Item &item) {
+                return fixed_overfit(objfunc(item, bbcenter), bb);
+            };
+        };
+
         auto on_packed = params.on_packed;
         
         if (progressind || on_packed)
@@ -384,13 +396,6 @@ public:
     const PConfig& config() const { return m_pconf; }
     
     inline void preload(std::vector<Item>& fixeditems) {
-        m_pconf.alignment = PConfig::Alignment::DONT_ALIGN;
-        auto bb = sl::boundingBox(m_bin);
-        auto bbcenter = bb.center();
-        m_pconf.object_function = [this, bb, bbcenter](const Item &item) {
-            return fixed_overfit(objfunc(item, bbcenter), bb);
-        };
-
         // Build the rtree for queries to work
         
         for(unsigned idx = 0; idx < fixeditems.size(); ++idx) {
@@ -398,7 +403,6 @@ public:
             itm.markAsFixedInBin(itm.binId());
         }
 
-        m_pck.configure(m_pconf);
         m_item_count += fixeditems.size();
     }
 };
diff --git a/src/libslic3r/Arrange.hpp b/src/libslic3r/Arrange.hpp
index ec46da8d3..0ff87c88d 100644
--- a/src/libslic3r/Arrange.hpp
+++ b/src/libslic3r/Arrange.hpp
@@ -62,6 +62,15 @@ struct ArrangePolygon {
 
     /// Test if arrange() was called previously and gave a successful result.
     bool is_arranged() const { return bed_idx != UNARRANGED; }
+
+    inline ExPolygon transformed_poly() const
+    {
+        ExPolygon ret = poly;
+        ret.rotate(rotation);
+        ret.translate(translation.x(), translation.y());
+
+        return ret;
+    }
 };
 
 using ArrangePolygons = std::vector<ArrangePolygon>;
diff --git a/src/libslic3r/BoundingBox.hpp b/src/libslic3r/BoundingBox.hpp
index 819162ec9..8de28af5c 100644
--- a/src/libslic3r/BoundingBox.hpp
+++ b/src/libslic3r/BoundingBox.hpp
@@ -53,6 +53,9 @@ public:
         return point(0) >= this->min(0) && point(0) <= this->max(0)
             && point(1) >= this->min(1) && point(1) <= this->max(1);
     }
+    bool contains(const BoundingBoxBase<PointClass> &other) const {
+        return contains(other.min) && contains(other.max);
+    }
     bool overlap(const BoundingBoxBase<PointClass> &other) const {
         return ! (this->max(0) < other.min(0) || this->min(0) > other.max(0) ||
                   this->max(1) < other.min(1) || this->min(1) > other.max(1));
diff --git a/src/slic3r/GUI/Jobs/FillBedJob.cpp b/src/slic3r/GUI/Jobs/FillBedJob.cpp
index 5bc9cbb36..d2ff5252a 100644
--- a/src/slic3r/GUI/Jobs/FillBedJob.cpp
+++ b/src/slic3r/GUI/Jobs/FillBedJob.cpp
@@ -29,7 +29,9 @@ void FillBedJob::prepare()
     for (ModelInstance *inst : model_object->instances)
         if (inst->printable) {
             ArrangePolygon ap = get_arrange_poly(PtrWrapper{inst}, m_plater);
-            ++ap.priority; // need to be included in the result
+            // Existing objects need to be included in the result. Only
+            // the needed amount of object will be added, no more.
+            ++ap.priority;
             m_selected.emplace_back(ap);
         }
 
@@ -38,11 +40,18 @@ void FillBedJob::prepare()
     m_bedpts = get_bed_shape(*m_plater->config());
 
     auto &objects = m_plater->model().objects;
+    BoundingBox bedbb = get_extents(m_bedpts);
+
     for (size_t idx = 0; idx < objects.size(); ++idx)
         if (int(idx) != m_object_idx)
             for (ModelInstance *mi : objects[idx]->instances) {
-                m_unselected.emplace_back(get_arrange_poly(PtrWrapper{mi}, m_plater));
-                m_unselected.back().bed_idx = 0;
+                ArrangePolygon ap = get_arrange_poly(PtrWrapper{mi}, m_plater);
+                auto ap_bb = ap.transformed_poly().contour.bounding_box();
+
+                if (ap.bed_idx == 0 && !bedbb.contains(ap_bb))
+                    ap.bed_idx = arrangement::UNARRANGED;
+
+                m_unselected.emplace_back(ap);
             }
 
     if (auto wt = get_wipe_tower_arrangepoly(*m_plater))
@@ -55,18 +64,17 @@ void FillBedJob::prepare()
     double unsel_area = std::accumulate(m_unselected.begin(),
                                         m_unselected.end(), 0.,
                                         [](double s, const auto &ap) {
-                                            return s + ap.poly.area();
+                                            return s + (ap.bed_idx == 0) * ap.poly.area();
                                         }) / sc;
 
     double fixed_area = unsel_area + m_selected.size() * poly_area;
+    double bed_area   = Polygon{m_bedpts}.area() / sc;
 
-    // This is the maximum range, the real number will always be close but less.
-    double bed_area = Polygon{m_bedpts}.area() / sc;
-
-    m_status_range = (bed_area - fixed_area) / poly_area;
+    // This is the maximum number of items, the real number will always be close but less.
+    int needed_items = (bed_area - fixed_area) / poly_area;
 
     ModelInstance *mi = model_object->instances[0];
-    for (int i = 0; i < m_status_range; ++i) {
+    for (int i = 0; i < needed_items; ++i) {
         ArrangePolygon ap;
         ap.poly = m_selected.front().poly;
         ap.bed_idx = arrangement::UNARRANGED;
@@ -77,6 +85,14 @@ void FillBedJob::prepare()
         };
         m_selected.emplace_back(ap);
     }
+
+    m_status_range = m_selected.size();
+
+    // The strides have to be removed from the fixed items. For the
+    // arrangeable (selected) items bed_idx is ignored and the
+    // translation is irrelevant.
+    double stride = bed_stride(m_plater);
+    for (auto &p : m_unselected) p.translation(X) -= p.bed_idx * stride;
 }
 
 void FillBedJob::process()