From 2012c945d5b0d3f76bca0d62f4f94fba230cae34 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 1 Mar 2023 16:19:07 +0100 Subject: [PATCH] Arrange onto segmented beds for XL --- src/libslic3r/Arrange.cpp | 88 ++++++++++++++++++++++++++++-- src/libslic3r/Arrange.hpp | 55 +++++++++++++++++-- src/libslic3r/BoundingBox.hpp | 15 +++-- src/libslic3r/PrintConfig.cpp | 23 ++++++++ src/libslic3r/PrintConfig.hpp | 5 ++ src/slic3r/GUI/GLCanvas3D.cpp | 11 +--- src/slic3r/GUI/Jobs/ArrangeJob.cpp | 10 ++-- 7 files changed, 179 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index 32cfac2ea2..8f8aaea027 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -599,11 +599,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)}); } } @@ -619,9 +619,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 @@ -661,5 +659,85 @@ 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()); + coord_t offs = params.min_bed_distance; + switch (params.alignment) { + case Pivots::BottomLeft: + bb.translate((bed.bb.min - bb.min) + Point{offs, offs}); + break; + case Pivots::TopRight: + bb.translate((bed.bb.max - bb.max) - Point{offs, offs}); + 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) + Point{-offs, offs}); + 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) + Point{offs, -offs}); + 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 e8fdbdff2c..6d4001a50c 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. @@ -137,6 +166,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 6c16d08b78..47b99443aa 100644 --- a/src/libslic3r/BoundingBox.hpp +++ b/src/libslic3r/BoundingBox.hpp @@ -225,10 +225,17 @@ inline bool empty(const BoundingBox3Base &bb) return ! bb.defined || bb.min.x() >= bb.max.x() || bb.min.y() >= bb.max.y() || bb.min.z() >= bb.max.z(); } -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 878acc10ad..b3b16a44ad 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4790,6 +4790,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); @@ -4814,6 +4823,20 @@ std::string get_sla_suptree_prefix(const DynamicPrintConfig &config) return slatree; } +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 b899571490..b3eda638dc 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -19,6 +19,7 @@ #include "libslic3r.h" #include "Config.hpp" #include "SLA/SupportTreeStrategies.hpp" +#include "libslic3r/Arrange.hpp" #include #include @@ -1177,10 +1178,14 @@ 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); + std::string get_sla_suptree_prefix(const DynamicPrintConfig &config); // ModelConfig is a wrapper around DynamicPrintConfig with an addition of a timestamp. diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f114543f42..5ac26ad210 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1065,16 +1065,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 2b954108b9..4595ae2544 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -169,11 +169,11 @@ void ArrangeJob::process(Ctl &ctl) static const auto arrangestr = _u8L("Arranging"); arrangement::ArrangeParams params; - Points bedpts; - ctl.call_on_main_thread([this, ¶ms, &bedpts]{ + arrangement::ArrangeBed bed; + ctl.call_on_main_thread([this, ¶ms, &bed]{ prepare(); params = get_arrange_params(m_plater); - bedpts = get_bed_shape(*m_plater->config()); + get_bed_shape(*m_plater->config(), bed); }).wait(); auto count = unsigned(m_selected.size() + m_unprintable.size()); @@ -192,13 +192,13 @@ void ArrangeJob::process(Ctl &ctl) ctl.update_status(0, arrangestr); - arrangement::arrange(m_selected, m_unselected, bedpts, params); + arrangement::arrange(m_selected, m_unselected, bed, params); params.progressind = [this, count, &ctl](unsigned st) { if (st > 0) ctl.update_status(int(count - st) * 100 / status_range(), arrangestr); }; - arrangement::arrange(m_unprintable, {}, bedpts, params); + arrangement::arrange(m_unprintable, {}, bed, params); // finalize just here. ctl.update_status(int(count) * 100 / status_range(), ctl.was_canceled() ?