diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index 254ebf2ef..42d222363 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -611,11 +611,11 @@ template auto call_with_bed(const Points &bed, Fn &&fn) auto parea = poly_area(bed); if ((1.0 - parea / area(bb)) < 1e-3) - return fn(bb); + return fn(RectangleBed{bb}); else if (!std::isnan(circ.radius())) return fn(circ); else - return fn(Polygon(bed)); + return fn(IrregularBed{ExPolygon(bed)}); } } @@ -631,9 +631,7 @@ void arrange(ArrangePolygons & items, const Points & bed, const ArrangeParams & params) { - call_with_bed(bed, [&](const auto &bin) { - arrange(items, excludes, bin, params); - }); + arrange(items, excludes, to_arrange_bed(bed), params); } template @@ -673,5 +671,84 @@ template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, c template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const Polygon &bed, const ArrangeParams ¶ms); template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const InfiniteBed &bed, const ArrangeParams ¶ms); +ArrangeBed to_arrange_bed(const Points &bedpts) +{ + ArrangeBed ret; + + call_with_bed(bedpts, [&](const auto &bed) { + ret = bed; + }); + + return ret; +} + +void arrange(ArrangePolygons &items, + const ArrangePolygons &excludes, + const SegmentedRectangleBed &bed, + const ArrangeParams ¶ms) +{ + arrange(items, excludes, bed.bb, params); + + if (! excludes.empty()) + return; + + auto it = std::max_element(items.begin(), items.end(), + [](auto &i1, auto &i2) { + return i1.bed_idx < i1.bed_idx; + }); + + size_t beds = 0; + if (it != items.end()) + beds = it->bed_idx + 1; + + std::vector pilebb(beds); + + for (auto &itm : items) { + if (itm.bed_idx >= 0) + pilebb[itm.bed_idx].merge(get_extents(itm.transformed_poly())); + } + + auto piecesz = unscaled(bed.bb).size(); + piecesz.x() /= bed.segments.x(); + piecesz.y() /= bed.segments.y(); + + for (size_t bedidx = 0; bedidx < beds; ++bedidx) { + BoundingBox bb; + auto pilesz = unscaled(pilebb[bedidx]).size(); + bb.max.x() = scaled(std::ceil(pilesz.x() / piecesz.x()) * piecesz.x()); + bb.max.y() = scaled(std::ceil(pilesz.y() / piecesz.y()) * piecesz.y()); + switch (params.alignment) { + case Pivots::BottomLeft: + bb.translate((bed.bb.min - bb.min)); + break; + case Pivots::TopRight: + bb.translate((bed.bb.max - bb.max)); + break; + case Pivots::BottomRight: { + Point bedref{bed.bb.max.x(), bed.bb.min.y()}; + Point bbref {bb.max.x(), bb.min.y()}; + bb.translate((bedref - bbref)); + break; + } + case Pivots::TopLeft: { + Point bedref{bed.bb.min.x(), bed.bb.max.y()}; + Point bbref {bb.min.x(), bb.max.y()}; + bb.translate((bedref - bbref)); + break; + } + case Pivots::Center: { + bb.translate(bed.bb.center() - bb.center()); + break; + } + } + + Vec2crd d = bb.center() - pilebb[bedidx].center(); + + for (auto &itm : items) + if (itm.bed_idx == bedidx) + itm.translation += d; + } +} + } // namespace arr } // namespace Slic3r diff --git a/src/libslic3r/Arrange.hpp b/src/libslic3r/Arrange.hpp index e56ecfbe2..13a8e4d60 100644 --- a/src/libslic3r/Arrange.hpp +++ b/src/libslic3r/Arrange.hpp @@ -3,12 +3,25 @@ #include "ExPolygon.hpp" +#include +#include + namespace Slic3r { class BoundingBox; namespace arrangement { +/// Representing an unbounded bed. +struct InfiniteBed { + Point center; + explicit InfiniteBed(const Point &p = {0, 0}): center{p} {} +}; + +struct RectangleBed { + BoundingBox bb; +}; + /// A geometry abstraction for a circular print bed. Similarly to BoundingBox. class CircleBed { Point center_; @@ -22,12 +35,28 @@ public: inline const Point& center() const { return center_; } }; -/// Representing an unbounded bed. -struct InfiniteBed { - Point center; - explicit InfiniteBed(const Point &p = {0, 0}): center{p} {} +struct SegmentedRectangleBed { + Vec<2, size_t> segments; + BoundingBox bb; + + SegmentedRectangleBed (const BoundingBox &bb, + size_t segments_x, + size_t segments_y) + : segments{segments_x, segments_y} + , bb{bb} + {} }; +struct IrregularBed { + ExPolygon poly; +}; + +//enum BedType { Infinite, Rectangle, Circle, SegmentedRectangle, Irregular }; + +using ArrangeBed = boost::variant; + +ArrangeBed to_arrange_bed(const Points &bedpts); + /// A logical bed representing an object not being arranged. Either the arrange /// has not yet successfully run on this ArrangePolygon or it could not fit the /// object due to overly large size or invalid geometry. @@ -134,6 +163,24 @@ extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excl extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const Polygon &bed, const ArrangeParams ¶ms); extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const InfiniteBed &bed, const ArrangeParams ¶ms); +inline void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const RectangleBed &bed, const ArrangeParams ¶ms) +{ + arrange(items, excludes, bed.bb, params); +} + +inline void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const IrregularBed &bed, const ArrangeParams ¶ms) +{ + arrange(items, excludes, bed.poly.contour, params); +} + +void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const SegmentedRectangleBed &bed, const ArrangeParams ¶ms); + +inline void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const ArrangeBed &bed, const ArrangeParams ¶ms) +{ + auto call_arrange = [&](const auto &realbed) { arrange(items, excludes, realbed, params); }; + boost::apply_visitor(call_arrange, bed); +} + inline void arrange(ArrangePolygons &items, const Points &bed, const ArrangeParams ¶ms = {}) { arrange(items, {}, bed, params); } inline void arrange(ArrangePolygons &items, const BoundingBox &bed, const ArrangeParams ¶ms = {}) { arrange(items, {}, bed, params); } inline void arrange(ArrangePolygons &items, const CircleBed &bed, const ArrangeParams ¶ms = {}) { arrange(items, {}, bed, params); } diff --git a/src/libslic3r/BoundingBox.hpp b/src/libslic3r/BoundingBox.hpp index 6b06f8bab..5c2d6763c 100644 --- a/src/libslic3r/BoundingBox.hpp +++ b/src/libslic3r/BoundingBox.hpp @@ -53,7 +53,7 @@ public: PointClass size() const; double radius() const; void translate(coordf_t x, coordf_t y) { assert(this->defined); PointClass v(x, y); this->min += v; this->max += v; } - void translate(const Vec2d &v) { this->min += v; this->max += v; } + void translate(const PointClass &v) { this->min += v; this->max += v; } void offset(coordf_t delta); BoundingBoxBase inflated(coordf_t delta) const throw() { BoundingBoxBase out(*this); out.offset(delta); return out; } PointClass center() const; @@ -221,10 +221,17 @@ inline bool empty(const BoundingBox3Base &bb) return ! bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1) || bb.min(2) >= bb.max(2); } -inline BoundingBox scaled(const BoundingBoxf &bb) { return {scaled(bb.min), scaled(bb.max)}; } -inline BoundingBox3 scaled(const BoundingBoxf3 &bb) { return {scaled(bb.min), scaled(bb.max)}; } -inline BoundingBoxf unscaled(const BoundingBox &bb) { return {unscaled(bb.min), unscaled(bb.max)}; } -inline BoundingBoxf3 unscaled(const BoundingBox3 &bb) { return {unscaled(bb.min), unscaled(bb.max)}; } +template +BoundingBoxBase> scaled(const BoundingBoxf &bb) { return {scaled(bb.min), scaled(bb.max)}; } + +template +BoundingBox3Base> scaled(const BoundingBoxf3 &bb) { return {scaled(bb.min), scaled(bb.max)}; } + +template +BoundingBoxBase> unscaled(const BoundingBox &bb) { return {unscaled(bb.min), unscaled(bb.max)}; } + +template +BoundingBox3Base> unscaled(const BoundingBox3 &bb) { return {unscaled(bb.min), unscaled(bb.max)}; } template auto cast(const BoundingBoxBase &b) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 69e221cab..64c29f2d9 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4660,6 +4660,15 @@ Points get_bed_shape(const DynamicPrintConfig &config) return to_points(bed_shape_opt->values); } +void get_bed_shape(const DynamicPrintConfig &cfg, arrangement::ArrangeBed &out) +{ + if (is_XL_printer(cfg)) { + out = arrangement::SegmentedRectangleBed{get_extents(get_bed_shape(cfg)), 4, 4}; + } else { + out = arrangement::to_arrange_bed(get_bed_shape(cfg)); + } +} + Points get_bed_shape(const PrintConfig &cfg) { return to_points(cfg.bed_shape.values); @@ -4667,6 +4676,19 @@ Points get_bed_shape(const PrintConfig &cfg) Points get_bed_shape(const SLAPrinterConfig &cfg) { return to_points(cfg.bed_shape.values); } +bool is_XL_printer(const DynamicPrintConfig &cfg) +{ + static constexpr const char *ALIGN_ONLY_FOR = "XL"; + + bool ret = false; + + auto *printer_model = cfg.opt("printer_model"); + + if (printer_model) + ret = boost::algorithm::contains(printer_model->value, ALIGN_ONLY_FOR); + + return ret; +} } // namespace Slic3r #include diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 75e0dc5ea..ea4efaf3c 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -18,6 +18,7 @@ #include "libslic3r.h" #include "Config.hpp" +#include "libslic3r/Arrange.hpp" #include #include @@ -1084,10 +1085,13 @@ private: static PrintAndCLIConfigDef s_def; }; +bool is_XL_printer(const DynamicPrintConfig &cfg); + Points get_bed_shape(const DynamicPrintConfig &cfg); Points get_bed_shape(const PrintConfig &cfg); Points get_bed_shape(const SLAPrinterConfig &cfg); +void get_bed_shape(const DynamicPrintConfig &cfg, arrangement::ArrangeBed &out); // ModelConfig is a wrapper around DynamicPrintConfig with an addition of a timestamp. // Each change of ModelConfig is tracked by assigning a new timestamp from a global counter. // The counter is used for faster synchronization of the background slicing thread diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f615a1026..242cf4fb5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -988,16 +988,7 @@ PrinterTechnology GLCanvas3D::current_printer_technology() const bool GLCanvas3D::is_arrange_alignment_enabled() const { - static constexpr const char *ALIGN_ONLY_FOR = "XL"; - - bool ret = false; - - auto *printer_model = m_config->opt("printer_model"); - - if (printer_model) - ret = boost::algorithm::contains(printer_model->value, ALIGN_ONLY_FOR); - - return ret; + return m_config ? is_XL_printer(*m_config) : false; } GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index b4c49ab01..db32fe601 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -185,7 +185,8 @@ void ArrangeJob::process() arrangement::ArrangeParams params = get_arrange_params(m_plater); auto count = unsigned(m_selected.size() + m_unprintable.size()); - Points bedpts = get_bed_shape(*m_plater->config()); + arrangement::ArrangeBed bed; + get_bed_shape(*m_plater->config(), bed); params.stopcondition = [this]() { return was_canceled(); }; @@ -194,13 +195,13 @@ void ArrangeJob::process() if (st > 0) update_status(int(count - st), arrangestr); }; - arrangement::arrange(m_selected, m_unselected, bedpts, params); + arrangement::arrange(m_selected, m_unselected, bed, params); params.progressind = [this, count](unsigned st) { if (st > 0) update_status(int(count - st), arrangestr); }; - arrangement::arrange(m_unprintable, {}, bedpts, params); + arrangement::arrange(m_unprintable, {}, bed, params); // finalize just here. update_status(int(count),