diff --git a/src/libnest2d/include/libnest2d/backends/clipper/CMakeLists.txt b/src/libnest2d/include/libnest2d/backends/clipper/CMakeLists.txt index 995afcc76..462d1dd06 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/CMakeLists.txt +++ b/src/libnest2d/include/libnest2d/backends/clipper/CMakeLists.txt @@ -64,6 +64,7 @@ endif() target_include_directories(ClipperBackend INTERFACE ${Boost_INCLUDE_DIRS} ) target_sources(ClipperBackend INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/geometries.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/clipper_polygon.hpp ${SRC_DIR}/libnest2d/utils/boost_alg.hpp ) target_compile_definitions(ClipperBackend INTERFACE LIBNEST2D_BACKEND_CLIPPER) diff --git a/src/libnest2d/include/libnest2d/backends/clipper/clipper_polygon.hpp b/src/libnest2d/include/libnest2d/backends/clipper/clipper_polygon.hpp new file mode 100644 index 000000000..e9fbfbd18 --- /dev/null +++ b/src/libnest2d/include/libnest2d/backends/clipper/clipper_polygon.hpp @@ -0,0 +1,72 @@ +#ifndef CLIPPER_POLYGON_HPP +#define CLIPPER_POLYGON_HPP + +#include + +namespace ClipperLib { + +struct Polygon { + Path Contour; + Paths Holes; + + inline Polygon() = default; + + inline explicit Polygon(const Path& cont): Contour(cont) {} + inline explicit Polygon(const Paths& holes): + Holes(holes) {} + inline Polygon(const Path& cont, const Paths& holes): + Contour(cont), Holes(holes) {} + + inline explicit Polygon(Path&& cont): Contour(std::move(cont)) {} + inline explicit Polygon(Paths&& holes): Holes(std::move(holes)) {} + inline Polygon(Path&& cont, Paths&& holes): + Contour(std::move(cont)), Holes(std::move(holes)) {} +}; + +inline IntPoint& operator +=(IntPoint& p, const IntPoint& pa ) { + // This could be done with SIMD + p.X += pa.X; + p.Y += pa.Y; + return p; +} + +inline IntPoint operator+(const IntPoint& p1, const IntPoint& p2) { + IntPoint ret = p1; + ret += p2; + return ret; +} + +inline IntPoint& operator -=(IntPoint& p, const IntPoint& pa ) { + p.X -= pa.X; + p.Y -= pa.Y; + return p; +} + +inline IntPoint operator -(IntPoint& p ) { + IntPoint ret = p; + ret.X = -ret.X; + ret.Y = -ret.Y; + return ret; +} + +inline IntPoint operator-(const IntPoint& p1, const IntPoint& p2) { + IntPoint ret = p1; + ret -= p2; + return ret; +} + +inline IntPoint& operator *=(IntPoint& p, const IntPoint& pa ) { + p.X *= pa.X; + p.Y *= pa.Y; + return p; +} + +inline IntPoint operator*(const IntPoint& p1, const IntPoint& p2) { + IntPoint ret = p1; + ret *= p2; + return ret; +} + +} + +#endif // CLIPPER_POLYGON_HPP diff --git a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp index 9f881e7e0..2c9550cf8 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp +++ b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp @@ -10,84 +10,15 @@ #include #include -#include - -namespace ClipperLib { -using PointImpl = IntPoint; -using PathImpl = Path; -using HoleStore = std::vector; - -struct PolygonImpl { - PathImpl Contour; - HoleStore Holes; - - inline PolygonImpl() = default; - - inline explicit PolygonImpl(const PathImpl& cont): Contour(cont) {} - inline explicit PolygonImpl(const HoleStore& holes): - Holes(holes) {} - inline PolygonImpl(const Path& cont, const HoleStore& holes): - Contour(cont), Holes(holes) {} - - inline explicit PolygonImpl(PathImpl&& cont): Contour(std::move(cont)) {} - inline explicit PolygonImpl(HoleStore&& holes): Holes(std::move(holes)) {} - inline PolygonImpl(Path&& cont, HoleStore&& holes): - Contour(std::move(cont)), Holes(std::move(holes)) {} -}; - -inline PointImpl& operator +=(PointImpl& p, const PointImpl& pa ) { - // This could be done with SIMD - p.X += pa.X; - p.Y += pa.Y; - return p; -} - -inline PointImpl operator+(const PointImpl& p1, const PointImpl& p2) { - PointImpl ret = p1; - ret += p2; - return ret; -} - -inline PointImpl& operator -=(PointImpl& p, const PointImpl& pa ) { - p.X -= pa.X; - p.Y -= pa.Y; - return p; -} - -inline PointImpl operator -(PointImpl& p ) { - PointImpl ret = p; - ret.X = -ret.X; - ret.Y = -ret.Y; - return ret; -} - -inline PointImpl operator-(const PointImpl& p1, const PointImpl& p2) { - PointImpl ret = p1; - ret -= p2; - return ret; -} - -inline PointImpl& operator *=(PointImpl& p, const PointImpl& pa ) { - p.X *= pa.X; - p.Y *= pa.Y; - return p; -} - -inline PointImpl operator*(const PointImpl& p1, const PointImpl& p2) { - PointImpl ret = p1; - ret *= p2; - return ret; -} - -} +#include "clipper_polygon.hpp" namespace libnest2d { // Aliases for convinience -using ClipperLib::PointImpl; -using ClipperLib::PathImpl; -using ClipperLib::PolygonImpl; -using ClipperLib::HoleStore; +using PointImpl = ClipperLib::IntPoint; +using PathImpl = ClipperLib::Path; +using HoleStore = ClipperLib::Paths; +using PolygonImpl = ClipperLib::Polygon; // Type of coordinate units used by Clipper template<> struct CoordType { @@ -158,33 +89,24 @@ template<> inline TCoord& y(PointImpl& p) #define DISABLE_BOOST_AREA namespace _smartarea { + template inline double area(const PolygonImpl& /*sh*/) { return std::nan(""); } template<> -inline double area(const PolygonImpl& sh) { - double a = 0; - - std::for_each(sh.Holes.begin(), sh.Holes.end(), [&a](const PathImpl& h) - { - a -= ClipperLib::Area(h); +inline double area(const PolygonImpl& sh) { + return std::accumulate(sh.Holes.begin(), sh.Holes.end(), + ClipperLib::Area(sh.Contour), + [](double a, const ClipperLib::Path& pt){ + return a + ClipperLib::Area(pt); }); - - return -ClipperLib::Area(sh.Contour) + a; } template<> -inline double area(const PolygonImpl& sh) { - double a = 0; - - std::for_each(sh.Holes.begin(), sh.Holes.end(), [&a](const PathImpl& h) - { - a += ClipperLib::Area(h); - }); - - return ClipperLib::Area(sh.Contour) + a; +inline double area(const PolygonImpl& sh) { + return -area(sh); } } @@ -390,11 +312,17 @@ inline void rotate(PolygonImpl& sh, const Radians& rads) } // namespace shapelike #define DISABLE_BOOST_NFP_MERGE -inline std::vector _merge(ClipperLib::Clipper& clipper) { +inline std::vector clipper_execute( + ClipperLib::Clipper& clipper, + ClipperLib::ClipType clipType, + ClipperLib::PolyFillType subjFillType = ClipperLib::pftEvenOdd, + ClipperLib::PolyFillType clipFillType = ClipperLib::pftEvenOdd) +{ shapelike::Shapes retv; ClipperLib::PolyTree result; - clipper.Execute(ClipperLib::ctUnion, result, ClipperLib::pftNegative); + clipper.Execute(clipType, result, subjFillType, clipFillType); + retv.reserve(static_cast(result.Total())); std::function processHole; @@ -437,15 +365,12 @@ merge(const std::vector& shapes) for(auto& path : shapes) { valid &= clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed); - - for(auto& hole : path.Holes) { - valid &= clipper.AddPath(hole, ClipperLib::ptSubject, closed); - } + valid &= clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed); } if(!valid) throw GeometryException(GeomErr::MERGE); - return _merge(clipper); + return clipper_execute(clipper, ClipperLib::ctUnion, ClipperLib::pftNegative); } } diff --git a/src/libnest2d/tests/printer_parts.h b/src/libnest2d/tests/printer_parts.h index b9a4eb8fa..1e65826bd 100644 --- a/src/libnest2d/tests/printer_parts.h +++ b/src/libnest2d/tests/printer_parts.h @@ -2,36 +2,10 @@ #define PRINTER_PARTS_H #include -#include - -#ifndef CLIPPER_BACKEND_HPP -namespace ClipperLib { -using PointImpl = IntPoint; -using PathImpl = Path; -using HoleStore = std::vector; - -struct PolygonImpl { - PathImpl Contour; - HoleStore Holes; - - inline PolygonImpl() {} - - inline explicit PolygonImpl(const PathImpl& cont): Contour(cont) {} - inline explicit PolygonImpl(const HoleStore& holes): - Holes(holes) {} - inline PolygonImpl(const Path& cont, const HoleStore& holes): - Contour(cont), Holes(holes) {} - - inline explicit PolygonImpl(PathImpl&& cont): Contour(std::move(cont)) {} - inline explicit PolygonImpl(HoleStore&& holes): Holes(std::move(holes)) {} - inline PolygonImpl(Path&& cont, HoleStore&& holes): - Contour(std::move(cont)), Holes(std::move(holes)) {} -}; -} -#endif +#include using TestData = std::vector; -using TestDataEx = std::vector; +using TestDataEx = std::vector; extern const TestData PRINTER_PART_POLYGONS; extern const TestData STEGOSAUR_POLYGONS; diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp index 4942e35b6..54627ba86 100644 --- a/src/libslic3r/ModelArrange.cpp +++ b/src/libslic3r/ModelArrange.cpp @@ -574,7 +574,7 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { for(ModelInstance* objinst : objptr->instances) { if(objinst) { - ClipperLib::PolygonImpl pn; + ClipperLib::Polygon pn; pn.Contour = clpath; // Efficient conversion to item. diff --git a/src/libslic3r/PrintExport.hpp b/src/libslic3r/PrintExport.hpp index 003ed5af4..c0c12209a 100644 --- a/src/libslic3r/PrintExport.hpp +++ b/src/libslic3r/PrintExport.hpp @@ -42,8 +42,9 @@ template class FilePrinter { public: - // Draw an ExPolygon which is a polygon inside a slice on the specified layer. - void draw_polygon(const Polygon& p, unsigned lyr); + // Draw a polygon which is a polygon inside a slice on the specified layer. + void draw_polygon(const ExPolygon& p, unsigned lyr); + void draw_polygon(const ClipperLib::Polygon& p, unsigned lyr); // Tell the printer how many layers should it consider. void layers(unsigned layernum); @@ -209,7 +210,12 @@ public: inline void layers(unsigned cnt) { if(cnt > 0) m_layers_rst.resize(cnt); } inline unsigned layers() const { return unsigned(m_layers_rst.size()); } - inline void draw_polygon(const Polygon& p, unsigned lyr) { + inline void draw_polygon(const ExPolygon& p, unsigned lyr) { + assert(lyr < m_layers_rst.size()); + m_layers_rst[lyr].first.draw(p); + } + + inline void draw_polygon(const ClipperLib::Polygon& p, unsigned lyr) { assert(lyr < m_layers_rst.size()); m_layers_rst[lyr].first.draw(p); } diff --git a/src/libslic3r/Rasterizer/Rasterizer.cpp b/src/libslic3r/Rasterizer/Rasterizer.cpp index 3e42e37d8..45c9daf3b 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.cpp +++ b/src/libslic3r/Rasterizer/Rasterizer.cpp @@ -1,5 +1,6 @@ #include "Rasterizer.hpp" -#include +#include +#include #include @@ -72,7 +73,7 @@ public: clear(); } - void draw(const Polygon &poly) { + template inline void draw(const Geometry &poly) { agg::rasterizer_scanline_aa<> ras; agg::scanline_p8 scanlines; @@ -104,14 +105,36 @@ private: return p(1) * SCALING_FACTOR/m_pxdim.h_mm; } - agg::path_storage to_path(const Polygon& poly) { + agg::path_storage to_path(const Polygon& poly) + { agg::path_storage path; + auto it = poly.points.begin(); path.move_to(getPx(*it), getPy(*it)); - while(++it != poly.points.end()) + while(++it != poly.points.end()) path.line_to(getPx(*it), getPy(*it)); + path.line_to(getPx(poly.points.front()), getPy(poly.points.front())); + + return path; + } + + + double getPx(const ClipperLib::IntPoint& p) { + return p.X * SCALING_FACTOR/m_pxdim.w_mm; + } + + double getPy(const ClipperLib::IntPoint& p) { + return p.Y * SCALING_FACTOR/m_pxdim.h_mm; + } + + agg::path_storage to_path(const ClipperLib::Path& poly) + { + agg::path_storage path; + auto it = poly.begin(); + path.move_to(getPx(*it), getPy(*it)); + while(++it != poly.end()) path.line_to(getPx(*it), getPy(*it)); - path.line_to(getPx(poly.points.front()), getPy(poly.points.front())); + path.line_to(getPx(poly.front()), getPy(poly.front())); return path; } @@ -163,10 +186,16 @@ void Raster::clear() m_impl->clear(); } -void Raster::draw(const Polygon &poly) +void Raster::draw(const ExPolygon &expoly) { - assert(m_impl); - m_impl->draw(poly); + m_impl->draw(expoly.contour); + for(auto& h : expoly.holes) m_impl->draw(h); +} + +void Raster::draw(const ClipperLib::Polygon &poly) +{ + m_impl->draw(poly.Contour); + for(auto& h : poly.Holes) m_impl->draw(h); } void Raster::save(std::ostream& stream, Compression comp) diff --git a/src/libslic3r/Rasterizer/Rasterizer.hpp b/src/libslic3r/Rasterizer/Rasterizer.hpp index 05ffd99b3..0468b6644 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.hpp +++ b/src/libslic3r/Rasterizer/Rasterizer.hpp @@ -4,9 +4,11 @@ #include #include +namespace ClipperLib { class Polygon; } + namespace Slic3r { -class Polygon; +class ExPolygon; /** * @brief Raster captures an anti-aliased monochrome canvas where vectorial @@ -83,7 +85,8 @@ public: void clear(); /// Draw a polygon with holes. - void draw(const Polygon& poly); + void draw(const ExPolygon& poly); + void draw(const ClipperLib::Polygon& poly); /// Save the raster on the specified stream. void save(std::ostream& stream, Compression comp = Compression::RAW); diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index ab7feed0e..eaa4642b0 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -12,6 +12,9 @@ #include #include +// For geometry algorithms with native Clipper types (no copies and conversions) +#include + //#include //#include "tbb/mutex.h" #include "I18N.hpp" @@ -958,8 +961,249 @@ void SLAPrint::process() m_print_statistics.clear(); - // Fill statistics - fill_statistics(); + using ClipperPolygon = libnest2d::PolygonImpl; + using ClipperPath = ClipperLib::Path; + using ClipperPoint = ClipperLib::IntPoint; + using ClipperPolygons = std::vector; + using libnest2d::Radians; + namespace sl = libnest2d::shapelike; + + // If the raster has vertical orientation, we will flip the coordinates + bool flpXY = m_printer_config.display_orientation.getInt() == SLADisplayOrientation::sladoPortrait; + + auto polyunion = [] (const ClipperPolygons& subjects) + { + ClipperLib::Clipper clipper; + + bool closed = true; + + for(auto& path : subjects) { + clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed); + clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed); + } + + auto mode = ClipperLib::pftPositive; + + return libnest2d::clipper_execute(clipper, ClipperLib::ctUnion, mode, mode); + }; + + auto polydiff = [](const ClipperPolygons& subjects, const ClipperPolygons& clips) + { + ClipperLib::Clipper clipper; + + bool closed = true; + + for(auto& path : subjects) { + clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed); + clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed); + } + + for(auto& path : clips) { + clipper.AddPath(path.Contour, ClipperLib::ptClip, closed); + clipper.AddPaths(path.Holes, ClipperLib::ptClip, closed); + } + + auto mode = ClipperLib::pftPositive; + + return libnest2d::clipper_execute(clipper, ClipperLib::ctDifference, mode, mode); + }; + + auto area = [](const ClipperPolygon& poly) + { + using ClipperLib::Area; + return std::accumulate( poly.Holes.begin(), poly.Holes.end(), + Area(poly.Contour), + [](double a, const ClipperPath& p) { return a + Area(p); }); + }; + + const double area_fill = m_printer_config.area_fill.getFloat()*0.01;// 0.5 (50%); + const double fast_tilt = m_printer_config.fast_tilt_time.getFloat();// 5.0; + const double slow_tilt = m_printer_config.slow_tilt_time.getFloat();// 8.0; + + const double init_exp_time = m_material_config.initial_exposure_time.getFloat(); + const double exp_time = m_material_config.exposure_time.getFloat(); + + const int fade_layers_cnt = m_default_object_config.faded_layers.getInt();// 10 // [3;20] + + const double width = m_printer_config.display_width.getFloat() / SCALING_FACTOR; + const double height = m_printer_config.display_height.getFloat() / SCALING_FACTOR; + const double display_area = width*height; + + // get polygons for all instances in the object + auto get_all_polygons = + [flpXY](const ExPolygons& input_polygons, + const std::vector& instances) + { + ClipperPolygons polygons; + polygons.reserve(input_polygons.size() * instances.size()); + + for (const ExPolygon& polygon : input_polygons) { + if(polygon.contour.empty()) continue; + + for (size_t i = 0; i < instances.size(); ++i) + { + ClipperPolygon poly; + + // should be a move + poly.Contour.reserve(polygon.contour.size() + 1); + + for(auto& p : polygon.contour.points) + poly.Contour.emplace_back(p.x(), p.y()); + + auto pfirst = poly.Contour.front(); + poly.Contour.emplace_back(pfirst); + + for(auto& h : polygon.holes) { + poly.Holes.emplace_back(); + auto& hole = poly.Holes.back(); + hole.reserve(h.points.size() + 1); + + for(auto& p : h.points) hole.emplace_back(p.x(), p.y()); + auto pfirst = hole.front(); hole.emplace_back(pfirst); + } + + sl::rotate(poly, Radians(double(instances[i].rotation))); + sl::translate(poly, ClipperPoint{instances[i].shift(X), + instances[i].shift(Y)}); + if (flpXY) { + for(auto& p : poly.Contour) std::swap(p.X, p.Y); + std::reverse(poly.Contour.begin(), poly.Contour.end()); + + for(auto& h : poly.Holes) { + for(auto& p : h) std::swap(p.X, p.Y); + std::reverse(h.begin(), h.end()); + } + } + + polygons.emplace_back(std::move(poly)); + } + } + return polygons; + }; + + double supports_volume = 0.0; + double models_volume = 0.0; + + double estim_time = 0.0; + + size_t slow_layers = 0; + size_t fast_layers = 0; + + const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1); + double fade_layer_time = init_exp_time; + + int sliced_layer_cnt = 0; + for (PrintLayer& layer : m_printer_input) + { + // vector of slice record references + auto& lyrslices = layer.slices(); + + if(lyrslices.empty()) continue; + + // Layer height should match for all object slices for a given level. + const auto l_height = double(lyrslices.front().get().layer_height()); + + // Calculation of the consumed material + + ClipperPolygons model_polygons; + ClipperPolygons supports_polygons; + + size_t c = std::accumulate(layer.slices().begin(), layer.slices().end(), 0u, [](size_t a, const SliceRecord& sr) { + return a + sr.get_slice(soModel).size(); + }); + + model_polygons.reserve(c); + + c = std::accumulate(layer.slices().begin(), layer.slices().end(), 0u, [](size_t a, const SliceRecord& sr) { + return a + sr.get_slice(soModel).size(); + }); + + supports_polygons.reserve(c); + + for(const SliceRecord& record : layer.slices()) { + const SLAPrintObject *po = record.print_obj(); + + const ExPolygons &modelslices = record.get_slice(soModel); + if (!modelslices.empty()) { + ClipperPolygons v = get_all_polygons(modelslices, po->instances()); + for(ClipperPolygon& p_tmp : v) model_polygons.emplace_back(std::move(p_tmp)); + } + + const ExPolygons &supportslices = record.get_slice(soSupport); + if (!supportslices.empty()) { + ClipperPolygons v = get_all_polygons(supportslices, po->instances()); + for(ClipperPolygon& p_tmp : v) supports_polygons.emplace_back(std::move(p_tmp)); + } + } + + model_polygons = polyunion(model_polygons); + double layer_model_area = 0; + for (const ClipperPolygon& polygon : model_polygons) + layer_model_area += area(polygon); + + if (layer_model_area < 0 || layer_model_area > 0) + models_volume += layer_model_area * l_height; + + if(!supports_polygons.empty()) { + if(model_polygons.empty()) supports_polygons = polyunion(supports_polygons); + else supports_polygons = polydiff(supports_polygons, model_polygons); + // allegedly, union of subject is done withing the diff + } + + double layer_support_area = 0; + for (const ClipperPolygon& polygon : supports_polygons) + layer_support_area += area(polygon); + + if (layer_support_area < 0 || layer_model_area > 0) + supports_volume += layer_support_area * l_height; + + // Here we can save the expensively calculated polygons for printing + ClipperPolygons trslices; + trslices.reserve(model_polygons.size() + supports_polygons.size()); + for(ClipperPolygon& poly : model_polygons) trslices.emplace_back(std::move(poly)); + for(ClipperPolygon& poly : supports_polygons) trslices.emplace_back(std::move(poly)); + + layer.transformed_slices(polyunion(trslices)); + + // Calculation of the slow and fast layers to the future controlling those values on FW + + const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill; + const double tilt_time = is_fast_layer ? fast_tilt : slow_tilt; + if (is_fast_layer) + fast_layers++; + else + slow_layers++; + + + // Calculation of the printing time + + if (sliced_layer_cnt < 3) + estim_time += init_exp_time; + else if (fade_layer_time > exp_time) + { + fade_layer_time -= delta_fade_time; + estim_time += fade_layer_time; + } + else + estim_time += exp_time; + + estim_time += tilt_time; + + sliced_layer_cnt++; + } + + m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR; + m_print_statistics.objects_used_material = models_volume * SCALING_FACTOR * SCALING_FACTOR; + + // Estimated printing time + // A layers count o the highest object + if (m_printer_input.size() == 0) + m_print_statistics.estimated_print_time = "N/A"; + else + m_print_statistics.estimated_print_time = get_time_dhms(float(estim_time)); + + m_print_statistics.fast_layers_count = fast_layers; + m_print_statistics.slow_layers_count = slow_layers; report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); }; @@ -1011,7 +1255,7 @@ void SLAPrint::process() // procedure to process one height level. This will run in parallel auto lvlfn = - [this, &slck, &printer, slot, sd, ist, &pst, flpXY] + [this, &slck, &printer, slot, sd, ist, &pst] (unsigned level_id) { if(canceled()) return; @@ -1021,31 +1265,9 @@ void SLAPrint::process() // Switch to the appropriate layer in the printer printer.begin_layer(level_id); - for(const Polygon& poly : printlayer.transformed_slices()) + for(const ClipperLib::Polygon& poly : printlayer.transformed_slices()) printer.draw_polygon(poly, level_id); - -// auto draw = -// [&printer, flpXY, level_id](Polygon& poly, const Instance& tr) -// { -// poly.rotate(double(tr.rotation)); -// poly.translate(tr.shift(X), tr.shift(Y)); -// if(flpXY) for(auto& p : poly.points) std::swap(p(X), p(Y)); -// printer.draw_polygon(poly, level_id); -// }; - -// for(const SliceRecord& sr : printlayer.slices()) { -// if(! sr.print_obj()) continue; - -// for(const Instance& inst : sr.print_obj()->instances()) { -// ExPolygons objsl = sr.get_slice(soModel); -// for(ExPolygon& poly : objsl) draw(poly, inst); - -// ExPolygons supsl = sr.get_slice(soSupport); -// for(ExPolygon& poly : supsl) draw(poly, inst); -// } -// } - // Finish the layer for later saving it. printer.finish_layer(level_id); @@ -1221,149 +1443,6 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector& instances) - { - const size_t inst_cnt = instances.size(); - - size_t polygon_cnt = 0; - for (const ExPolygon& polygon : input_polygons) - polygon_cnt += polygon.holes.size() + 1; - - Polygons polygons; - polygons.reserve(polygon_cnt * inst_cnt); - for (const ExPolygon& polygon : input_polygons) { - for (size_t i = 0; i < inst_cnt; ++i) - { - ExPolygon tmp = polygon; - tmp.rotate(double(instances[i].rotation)); - tmp.translate(instances[i].shift.x(), instances[i].shift.y()); - if(flpXY) swapXY(tmp); - polygons_append(polygons, to_polygons(std::move(tmp))); - } - } - return polygons; - }; - - double supports_volume = 0.0; - double models_volume = 0.0; - - double estim_time = 0.0; - - size_t slow_layers = 0; - size_t fast_layers = 0; - - const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1); - double fade_layer_time = init_exp_time; - - int sliced_layer_cnt = 0; - for (PrintLayer& layer : m_printer_input) - { - if(layer.slices().empty()) continue; - - // Layer height should match for all object slices for a given level. - const auto l_height = double(layer.slices().front().get().layer_height()); - - // Calculation of the consumed material - - Polygons model_polygons; - Polygons supports_polygons; - - for(const SliceRecord& record : layer.slices()) { - const SLAPrintObject *po = record.print_obj(); - - const ExPolygons &modelslices = record.get_slice(soModel); - if (!modelslices.empty()) - append(model_polygons, get_all_polygons(modelslices, po->instances())); - - const ExPolygons &supportslices = record.get_slice(soSupport); - if (!supportslices.empty()) - append(supports_polygons, get_all_polygons(supportslices, po->instances())); - } - - model_polygons = union_(model_polygons); - double layer_model_area = 0; - for (const Polygon& polygon : model_polygons) - layer_model_area += polygon.area(); - - if (layer_model_area < 0 || layer_model_area > 0) - models_volume += layer_model_area * l_height; - - if (!supports_polygons.empty() && !model_polygons.empty()) - supports_polygons = diff(supports_polygons, model_polygons); - double layer_support_area = 0; - for (const Polygon& polygon : supports_polygons) - layer_support_area += polygon.area(); - - if (layer_support_area < 0 || layer_model_area > 0) - supports_volume += layer_support_area * l_height; - - // Here we can save the expensively calculated polygons for printing - append(model_polygons, supports_polygons); - layer.transformed_slices(union_(model_polygons)); - - // Calculation of the slow and fast layers to the future controlling those values on FW - - const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill; - const double tilt_time = is_fast_layer ? fast_tilt : slow_tilt; - if (is_fast_layer) - fast_layers++; - else - slow_layers++; - - - // Calculation of the printing time - - if (sliced_layer_cnt < 3) - estim_time += init_exp_time; - else if (fade_layer_time > exp_time) - { - fade_layer_time -= delta_fade_time; - estim_time += fade_layer_time; - } - else - estim_time += exp_time; - - estim_time += tilt_time; - - sliced_layer_cnt++; - } - - m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR; - m_print_statistics.objects_used_material = models_volume * SCALING_FACTOR * SCALING_FACTOR; - - // Estimated printing time - // A layers count o the highest object - if (m_printer_input.size() == 0) - m_print_statistics.estimated_print_time = "N/A"; - else - m_print_statistics.estimated_print_time = get_time_dhms(float(estim_time)); - - m_print_statistics.fast_layers_count = fast_layers; - m_print_statistics.slow_layers_count = slow_layers; -} - // Returns true if an object step is done on all objects and there's at least one object. bool SLAPrint::is_step_done(SLAPrintObjectStep step) const { diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index e645a9574..068830771 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -6,6 +6,7 @@ #include "PrintExport.hpp" #include "Point.hpp" #include "MTUtils.hpp" +#include #include namespace Slic3r { @@ -328,46 +329,8 @@ class SLAPrint : public PrintBaseWithState private: // Prevents erroneous use by other classes. typedef PrintBaseWithState Inherited; - void fill_statistics(); public: - // An aggregation of SliceRecord-s from all the print objects for each - // occupied layer. Slice record levels dont have to match exactly. - // They are unified if the level difference is within +/- SCALED_EPSILON - class PrintLayer { - coord_t m_level; - - // The collection of slice records for the current level. - std::vector> m_slices; - - Polygons m_transformed_slices; - - template void transformed_slices(Container&& c) { - m_transformed_slices = std::forward(c); - } - - friend void SLAPrint::fill_statistics(); - - public: - - explicit PrintLayer(coord_t lvl) : m_level(lvl) {} - - // for being sorted in their container (see m_printer_input) - bool operator<(const PrintLayer& other) const { - return m_level < other.m_level; - } - - void add(const SliceRecord& sr) { m_slices.emplace_back(sr); } - - coord_t level() const { return m_level; } - - auto slices() const -> const decltype (m_slices)& { return m_slices; } - - const Polygons& transformed_slices() const { - return m_transformed_slices; - } - }; - SLAPrint(): m_stepmask(slapsCount, true) {} virtual ~SLAPrint() override { this->clear(); } @@ -401,6 +364,43 @@ public: std::string validate() const override; + // An aggregation of SliceRecord-s from all the print objects for each + // occupied layer. Slice record levels dont have to match exactly. + // They are unified if the level difference is within +/- SCALED_EPSILON + class PrintLayer { + coord_t m_level; + + // The collection of slice records for the current level. + std::vector> m_slices; + + std::vector m_transformed_slices; + + template void transformed_slices(Container&& c) { + m_transformed_slices = std::forward(c); + } + + friend void SLAPrint::process(); + + public: + + explicit PrintLayer(coord_t lvl) : m_level(lvl) {} + + // for being sorted in their container (see m_printer_input) + bool operator<(const PrintLayer& other) const { + return m_level < other.m_level; + } + + void add(const SliceRecord& sr) { m_slices.emplace_back(sr); } + + coord_t level() const { return m_level; } + + auto slices() const -> const decltype (m_slices)& { return m_slices; } + + const std::vector & transformed_slices() const { + return m_transformed_slices; + } + }; + // The aggregated and leveled print records from various objects. // TODO: use this structure for the preview in the future. const std::vector& print_layers() const { return m_printer_input; }