diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 9fbbe378a1..f5712c3de6 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -565,6 +565,11 @@ public: SpanOfConstPtrs objects() const { return SpanOfConstPtrs(const_cast(m_objects.data()), m_objects.size()); } PrintObject* get_object(size_t idx) { return const_cast(m_objects[idx]); } const PrintObject* get_object(size_t idx) const { return m_objects[idx]; } + const PrintObject* get_print_object_by_model_object_id(ObjectID object_id) const { + auto it = std::find_if(m_objects.begin(), m_objects.end(), + [object_id](const PrintObject* obj) { return obj->model_object()->id() == object_id; }); + return (it == m_objects.end()) ? nullptr : *it; + } // PrintObject by its ObjectID, to be used to uniquely bind slicing warnings to their source PrintObjects // in the notification center. const PrintObject* get_object(ObjectID object_id) const { diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index 72a938ab33..67c6298f89 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -2,6 +2,7 @@ #include "libslic3r/BuildVolume.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/Print.hpp" #include "libslic3r/SLAPrint.hpp" #include "libslic3r/Geometry/ConvexHull.hpp" @@ -79,7 +80,6 @@ void ArrangeJob::clear_input() m_selected.reserve(count + 1 /* for optional wti */); m_unselected.reserve(count + 1 /* for optional wti */); m_unprintable.reserve(cunprint /* for optional wti */); - m_min_inflation = 0; } void ArrangeJob::prepare_all() { @@ -151,8 +151,7 @@ void ArrangeJob::prepare_selected() { static void update_arrangepoly_slaprint(arrangement::ArrangePolygon &ret, const SLAPrintObject &po, - const ModelInstance &inst, - coord_t min_infl) + const ModelInstance &inst) { auto laststep = po.last_completed_step(); @@ -189,10 +188,22 @@ static void update_arrangepoly_slaprint(arrangement::ArrangePolygon &ret, po.config().pad_around_object.getBool() * po.config().pad_object_gap.getFloat()); - ret.inflation = std::max(infl, min_infl); + ret.inflation = infl; } } +static coord_t brim_offset(const PrintObject &po, const ModelInstance &inst) +{ + const BrimType brim_type = po.config().brim_type.value; + const float brim_separation = po.config().brim_separation.getFloat(); + const float brim_width = po.config().brim_width.getFloat(); + const bool has_outer_brim = brim_type == BrimType::btOuterOnly || + brim_type == BrimType::btOuterAndInner; + + // How wide is the brim? (in scaled units) + return has_outer_brim ? scaled(brim_width + brim_separation) : 0; +} + arrangement::ArrangePolygon ArrangeJob::get_arrange_poly_(ModelInstance *mi) { arrangement::ArrangePolygon ap = get_arrange_poly(mi, m_plater); @@ -204,27 +215,40 @@ arrangement::ArrangePolygon ArrangeJob::get_arrange_poly_(ModelInstance *mi) m_unarranged.emplace_back(mi); }; - if (m_plater->printer_technology() == ptSLA) { - auto obj_id = mi->get_object()->id(); - const SLAPrintObject *po = - m_plater->sla_print().get_print_object_by_model_object_id(obj_id); + return ap; +} - if (po) { - update_arrangepoly_slaprint(ap, *po, *mi, m_min_inflation); - m_min_inflation = std::max(m_min_inflation, ap.inflation); - } - } else { - // TODO: get fff supports outline +coord_t get_skirt_offset(const Plater* plater) { + float skirt_inset = 0.f; + // Try to subtract the skirt from the bed shape so we don't arrange outside of it. + if (plater->printer_technology() == ptFFF && plater->fff_print().has_skirt()) { + const auto& print = plater->fff_print(); + skirt_inset = print.config().skirts.value * print.skirt_flow().width() + + print.config().skirt_distance.value; } - return ap; + return scaled(skirt_inset); } void ArrangeJob::prepare() { wxGetKeyState(WXK_SHIFT) ? prepare_selected() : prepare_all(); + + coord_t min_offset = 0; for (auto &ap : m_selected) { - ap.inflation = m_min_inflation; + min_offset = std::max(ap.inflation, min_offset); + } + + if (m_plater->printer_technology() == ptSLA) { + // Apply the max offset for all the objects + for (auto &ap : m_selected) { + ap.inflation = min_offset; + } + } else { // it's fff, brims only need to be minded from bed edges + for (auto &ap : m_selected) { + ap.inflation = 0; + } + m_min_bed_inset = min_offset; } } @@ -238,6 +262,8 @@ void ArrangeJob::process(Ctl &ctl) prepare(); params = get_arrange_params(m_plater); get_bed_shape(*m_plater->config(), bed); + coord_t min_inset = get_skirt_offset(m_plater) + m_min_bed_inset; + params.min_bed_distance = std::max(params.min_bed_distance, min_inset); }).wait(); auto count = unsigned(m_selected.size() + m_unprintable.size()); @@ -352,6 +378,23 @@ arrangement::ArrangePolygon get_arrange_poly(ModelInstance *inst, { auto ap = get_arrange_poly(PtrWrapper{inst}, plater); + auto obj_id = inst->get_object()->id(); + if (plater->printer_technology() == ptSLA) { + const SLAPrintObject *po = + plater->sla_print().get_print_object_by_model_object_id(obj_id); + + if (po) { + update_arrangepoly_slaprint(ap, *po, *inst); + } + } else { + const PrintObject *po = + plater->fff_print().get_print_object_by_model_object_id(obj_id); + + if (po) { + ap.inflation = brim_offset(*po, *inst); + } + } + return ap; } diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.hpp b/src/slic3r/GUI/Jobs/ArrangeJob.hpp index 4b75868a03..a422d44070 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.hpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.hpp @@ -21,7 +21,7 @@ class ArrangeJob : public Job ArrangePolygons m_selected, m_unselected, m_unprintable; std::vector m_unarranged; - coord_t m_min_inflation = 0; + coord_t m_min_bed_inset = 0.; Plater *m_plater; @@ -104,6 +104,8 @@ arrangement::ArrangePolygon get_arrange_poly(ModelInstance *inst, arrangement::ArrangeParams get_arrange_params(Plater *p); +coord_t get_skirt_offset(const Plater* plater); + }} // namespace Slic3r::GUI #endif // ARRANGEJOB_HPP diff --git a/src/slic3r/GUI/Jobs/FillBedJob.cpp b/src/slic3r/GUI/Jobs/FillBedJob.cpp index 6a173683f6..b8a579ed5d 100644 --- a/src/slic3r/GUI/Jobs/FillBedJob.cpp +++ b/src/slic3r/GUI/Jobs/FillBedJob.cpp @@ -18,6 +18,7 @@ void FillBedJob::prepare() m_selected.clear(); m_unselected.clear(); m_bedpts.clear(); + m_min_bed_inset = 0.; m_object_idx = m_plater->get_selected_object_idx(); if (m_object_idx == -1) @@ -29,7 +30,7 @@ void FillBedJob::prepare() m_selected.reserve(model_object->instances.size()); for (ModelInstance *inst : model_object->instances) if (inst->printable) { - ArrangePolygon ap = get_arrange_poly(PtrWrapper{inst}, m_plater); + ArrangePolygon ap = get_arrange_poly(inst, m_plater); // Existing objects need to be included in the result. Only // the needed amount of object will be added, no more. ++ap.priority; @@ -101,6 +102,23 @@ void FillBedJob::prepare() for (auto &p : m_unselected) if (p.bed_idx > 0) p.translation(X) -= p.bed_idx * stride; + + coord_t min_offset = 0; + for (auto &ap : m_selected) { + min_offset = std::max(ap.inflation, min_offset); + } + + if (m_plater->printer_technology() == ptSLA) { + // Apply the max offset for all the objects + for (auto &ap : m_selected) { + ap.inflation = min_offset; + } + } else { // it's fff, brims only need to be minded from bed edges + for (auto &ap : m_selected) { + ap.inflation = 0; + } + m_min_bed_inset = min_offset; + } } void FillBedJob::process(Ctl &ctl) @@ -110,6 +128,8 @@ void FillBedJob::process(Ctl &ctl) ctl.call_on_main_thread([this, ¶ms] { prepare(); params = get_arrange_params(m_plater); + coord_t min_inset = get_skirt_offset(m_plater) + m_min_bed_inset; + params.min_bed_distance = std::max(params.min_bed_distance, min_inset); }).wait(); ctl.update_status(0, statustxt); diff --git a/src/slic3r/GUI/Jobs/FillBedJob.hpp b/src/slic3r/GUI/Jobs/FillBedJob.hpp index b1417bbbd4..b953e0e981 100644 --- a/src/slic3r/GUI/Jobs/FillBedJob.hpp +++ b/src/slic3r/GUI/Jobs/FillBedJob.hpp @@ -16,6 +16,7 @@ class FillBedJob : public Job ArrangePolygons m_selected; ArrangePolygons m_unselected; + coord_t m_min_bed_inset = 0.; Points m_bedpts;