From 95b0467c850f801d7de0e391f93d618843c93eb4 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 26 Mar 2019 18:51:27 +0100 Subject: [PATCH 1/8] Reusing unified polygons from statistics --- src/libslic3r/PrintExport.hpp | 4 +- src/libslic3r/Rasterizer/Rasterizer.cpp | 14 +-- src/libslic3r/Rasterizer/Rasterizer.hpp | 4 +- src/libslic3r/SLAPrint.cpp | 130 +++++++++++------------- src/libslic3r/SLAPrint.hpp | 17 +++- 5 files changed, 80 insertions(+), 89 deletions(-) diff --git a/src/libslic3r/PrintExport.hpp b/src/libslic3r/PrintExport.hpp index df9446cf5..003ed5af4 100644 --- a/src/libslic3r/PrintExport.hpp +++ b/src/libslic3r/PrintExport.hpp @@ -43,7 +43,7 @@ class FilePrinter { public: // Draw an ExPolygon which is a polygon inside a slice on the specified layer. - void draw_polygon(const ExPolygon& p, unsigned lyr); + void draw_polygon(const Polygon& p, unsigned lyr); // Tell the printer how many layers should it consider. void layers(unsigned layernum); @@ -209,7 +209,7 @@ 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 ExPolygon& p, unsigned lyr) { + inline void draw_polygon(const 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 5961d9b78..3e42e37d8 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.cpp +++ b/src/libslic3r/Rasterizer/Rasterizer.cpp @@ -1,5 +1,5 @@ #include "Rasterizer.hpp" -#include +#include #include @@ -72,22 +72,16 @@ public: clear(); } - void draw(const ExPolygon &poly) { + void draw(const Polygon &poly) { agg::rasterizer_scanline_aa<> ras; agg::scanline_p8 scanlines; - auto&& path = to_path(poly.contour); + auto&& path = to_path(poly); if(m_o == Origin::TOP_LEFT) flipy(path); ras.add_path(path); - for(auto h : poly.holes) { - auto&& holepath = to_path(h); - if(m_o == Origin::TOP_LEFT) flipy(holepath); - ras.add_path(holepath); - } - agg::render_scanlines(ras, scanlines, m_renderer); } @@ -169,7 +163,7 @@ void Raster::clear() m_impl->clear(); } -void Raster::draw(const ExPolygon &poly) +void Raster::draw(const Polygon &poly) { assert(m_impl); m_impl->draw(poly); diff --git a/src/libslic3r/Rasterizer/Rasterizer.hpp b/src/libslic3r/Rasterizer/Rasterizer.hpp index 06d5b88c6..05ffd99b3 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.hpp +++ b/src/libslic3r/Rasterizer/Rasterizer.hpp @@ -6,7 +6,7 @@ namespace Slic3r { -class ExPolygon; +class Polygon; /** * @brief Raster captures an anti-aliased monochrome canvas where vectorial @@ -83,7 +83,7 @@ public: void clear(); /// Draw a polygon with holes. - void draw(const ExPolygon& poly); + void draw(const 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 ee24cf3ec..af3f20a59 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -915,19 +915,7 @@ void SLAPrint::process() report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); }; - auto fillstats = [this]() { - - m_print_statistics.clear(); - - // Fill statistics - fill_statistics(); - - report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); - }; - - // Rasterizing the model objects, and their supports - auto rasterize = [this, max_objstatus, ilhs]() { - if(canceled()) return; + auto fillstats = [this, ilhs]() { // clear the rasterizer input m_printer_input.clear(); @@ -962,6 +950,18 @@ void SLAPrint::process() } } + m_print_statistics.clear(); + + // Fill statistics + fill_statistics(); + + report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); + }; + + // Rasterizing the model objects, and their supports + auto rasterize = [this, max_objstatus]() { + if(canceled()) return; + // collect all the keys // If the raster has vertical orientation, we will flip the coordinates @@ -1015,28 +1015,30 @@ void SLAPrint::process() // Switch to the appropriate layer in the printer printer.begin_layer(level_id); - using Instance = SLAPrintObject::Instance; - - auto draw = - [&printer, flpXY, level_id](ExPolygon& poly, const Instance& tr) - { - poly.rotate(double(tr.rotation)); - poly.translate(tr.shift(X), tr.shift(Y)); - if(flpXY) swapXY(poly); + for(const Polygon& poly : printlayer.transformed_slices()) 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); +// 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); +// }; - ExPolygons supsl = sr.get_slice(soSupport); - for(ExPolygon& poly : supsl) draw(poly, inst); - } - } +// 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); @@ -1217,9 +1219,6 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector& instances) { + auto get_all_polygons = + [flpXY](const ExPolygons& input_polygons, + const std::vector& instances) + { const size_t inst_cnt = instances.size(); size_t polygon_cnt = 0; @@ -1249,6 +1255,7 @@ void SLAPrint::fill_statistics() 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))); } } @@ -1263,55 +1270,30 @@ void SLAPrint::fill_statistics() size_t slow_layers = 0; size_t fast_layers = 0; - // find highest object - // Which is a better bet? To compare by max_z or by number of layers in the index? - // float max_z = 0.; - size_t max_layers_cnt = 0; - size_t highest_obj_idx = 0; - for (SLAPrintObject *&po : m_objects) { - auto& slice_index = po->get_slice_index(); - if (! slice_index.empty()) { - // float z = (-- slice_index.end())->slice_level(); - size_t cnt = slice_index.size(); - //if (z > max_z) { - if (cnt > max_layers_cnt) { - max_layers_cnt = cnt; - // max_z = z; - highest_obj_idx = &po - &m_objects.front(); - } - } - } - - const SLAPrintObject * highest_obj = m_objects[highest_obj_idx]; - auto& highest_obj_slice_index = highest_obj->get_slice_index(); - 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 (const SliceRecord& layer : highest_obj_slice_index) + for (PrintLayer& layer : m_printer_input) { - const auto l_height = double(layer.layer_height()); + 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 (SLAPrintObject * po : m_objects) - { - const SliceRecord *record = nullptr; - { - const SliceRecord& slr = po->closest_slice_to_slice_level(layer.slice_level(), float(EPSILON)); - if (!slr.is_valid()) continue; - record = &slr; - } + for(const SliceRecord& record : layer.slices()) { + const SLAPrintObject *po = record.print_obj(); - const ExPolygons &modelslices = record->get_slice(soModel); + 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); + const ExPolygons &supportslices = record.get_slice(soSupport); if (!supportslices.empty()) append(supports_polygons, get_all_polygons(supportslices, po->instances())); } @@ -1321,7 +1303,7 @@ void SLAPrint::fill_statistics() for (const Polygon& polygon : model_polygons) layer_model_area += polygon.area(); - if (layer_model_area != 0) + if (layer_model_area < 0 || layer_model_area > 0) models_volume += layer_model_area * l_height; if (!supports_polygons.empty() && !model_polygons.empty()) @@ -1330,9 +1312,13 @@ void SLAPrint::fill_statistics() for (const Polygon& polygon : supports_polygons) layer_support_area += polygon.area(); - if (layer_support_area != 0) + 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; @@ -1365,7 +1351,7 @@ void SLAPrint::fill_statistics() // Estimated printing time // A layers count o the highest object - if (max_layers_cnt == 0) + 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)); diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index afdfab415..9b6c89687 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -127,7 +127,7 @@ public: bool is_valid() const { return ! std::isnan(m_slice_z); } - const SLAPrintObject* print_obj() const { return m_po; } + const SLAPrintObject* print_obj() const { assert(m_po); return m_po; } // Methods for setting the indices into the slice vectors. void set_model_slice_idx(const SLAPrintObject &po, size_t id) { @@ -328,6 +328,7 @@ 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 @@ -339,6 +340,14 @@ public: // 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) {} @@ -353,6 +362,10 @@ public: 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) {} @@ -399,8 +412,6 @@ private: // Invalidate steps based on a set of parameters changed. bool invalidate_state_by_config_options(const std::vector &opt_keys); - void fill_statistics(); - SLAPrintConfig m_print_config; SLAPrinterConfig m_printer_config; SLAMaterialConfig m_material_config; From bc747615135c5c6661b530ae57fd0e370e178f94 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 27 Mar 2019 10:59:29 +0100 Subject: [PATCH 2/8] Integrating new step, removing old and unused steps. --- src/libslic3r/SLAPrint.cpp | 83 +++++++++++++++------------------- src/libslic3r/SLAPrint.hpp | 19 ++++---- src/slic3r/GUI/GLCanvas3D.cpp | 4 +- src/slic3r/GUI/GUI_Preview.cpp | 2 +- 4 files changed, 50 insertions(+), 58 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index ee24cf3ec..862913f95 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -43,8 +43,7 @@ const std::array OBJ_STEP_LEVELS = 30, // slaposSupportPoints, 25, // slaposSupportTree, 25, // slaposBasePool, - 5, // slaposSliceSupports, - 5 // slaposIndexSlices + 10, // slaposSliceSupports, }; const std::array OBJ_STEP_LABELS = @@ -54,22 +53,19 @@ const std::array OBJ_STEP_LABELS = L("Generating support tree"), // slaposSupportTree, L("Generating pad"), // slaposBasePool, L("Slicing supports"), // slaposSliceSupports, - L("Slicing supports") // slaposIndexSlices, }; // Should also add up to 100 (%) const std::array PRINT_STEP_LEVELS = { 5, // slapsStats - 94, // slapsRasterize - 1, // slapsValidate + 95, // slapsRasterize }; const std::array PRINT_STEP_LABELS = { - L("Calculating statistics"), // slapsStats + L("Merging slices and calculating statistics"), // slapsStats L("Rasterizing layers"), // slapsRasterize - L("Validating"), // slapsValidate }; } @@ -206,7 +202,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf model_object_status.emplace(model_object->id(), ModelObjectStatus::Old); } else if (model_object_list_extended(m_model, model)) { // Add new objects. Their volumes and configs will be synchronized later. - update_apply_status(this->invalidate_step(slapsRasterize)); + update_apply_status(this->invalidate_step(slapsMergeSlicesAndEval)); for (const ModelObject *model_object : m_model.objects) model_object_status.emplace(model_object->id(), ModelObjectStatus::Old); for (size_t i = m_model.objects.size(); i < model.objects.size(); ++ i) { @@ -218,7 +214,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf // Reorder the objects, add new objects. // First stop background processing before shuffling or deleting the PrintObjects in the object list. this->call_cancel_callback(); - update_apply_status(this->invalidate_step(slapsRasterize)); + update_apply_status(this->invalidate_step(slapsMergeSlicesAndEval)); // Second create a new list of objects. std::vector model_objects_old(std::move(m_model.objects)); m_model.objects.clear(); @@ -390,7 +386,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf if (new_instances != it_print_object_status->print_object->instances()) { // Instances changed. it_print_object_status->print_object->set_instances(new_instances); - update_apply_status(this->invalidate_step(slapsRasterize)); + update_apply_status(this->invalidate_step(slapsMergeSlicesAndEval)); } print_objects_new.emplace_back(it_print_object_status->print_object); const_cast(*it_print_object_status).status = PrintObjectStatus::Reused; @@ -613,6 +609,18 @@ std::string SLAPrint::validate() const return ""; } +bool SLAPrint::invalidate_step(SLAPrintStep step) +{ + bool invalidated = Inherited::invalidate_step(step); + + // propagate to dependent steps + if (step == slapsMergeSlicesAndEval) { + invalidated |= this->invalidate_all_steps(); + } + + return invalidated; +} + template void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) { @@ -639,7 +647,7 @@ void SLAPrint::process() const size_t objcount = m_objects.size(); const unsigned min_objstatus = 0; // where the per object operations start - const unsigned max_objstatus = PRINT_STEP_LEVELS[slapsRasterize]; // where the per object operations end + const unsigned max_objstatus = PRINT_STEP_LEVELS[slapsMergeSlicesAndEval]; // where the per object operations end // the coefficient that multiplies the per object status values which // are set up for <0, 100>. They need to be scaled into the whole process @@ -883,7 +891,7 @@ void SLAPrint::process() // Slicing the support geometries similarly to the model slicing procedure. // If the pad had been added previously (see step "base_pool" than it will // be part of the slices) - auto slice_supports = [](SLAPrintObject& po) { + auto slice_supports = [this](SLAPrintObject& po) { auto& sd = po.m_supportdata; if(sd) sd->support_slices.clear(); @@ -906,16 +914,14 @@ void SLAPrint::process() { po.m_slice_index[i].set_support_slice_idx(po, i); } - }; - // We have the layer polygon collection but we need to unite them into - // an index where the key is the height level in discrete levels (clipper) - auto index_slices = [this/*, ilhd*/](SLAPrintObject& /*po*/) { // Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update status to the 3D preview to load the SLA slices. report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); }; - auto fillstats = [this]() { + // Merging the slices from all the print objects into one slice grid and + // calculating print statistics from the merge result. + auto merge_slices_and_eval_stats = [this]() { m_print_statistics.clear(); @@ -1079,15 +1085,13 @@ void SLAPrint::process() support_points, support_tree, base_pool, - slice_supports, - index_slices + slice_supports }; std::array print_program = { - fillstats, - rasterize, - [](){} // validate + merge_slices_and_eval_stats, + rasterize }; unsigned st = min_objstatus; @@ -1127,7 +1131,7 @@ void SLAPrint::process() } std::array printsteps = { - slapsStats, slapsRasterize, slapsValidate + slapsMergeSlicesAndEval, slapsRasterize }; // this would disable the rasterization step @@ -1193,11 +1197,11 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vectorinvalidate_all_steps(); } else if (step == slaposSupportPoints) { - invalidated |= this->invalidate_steps({ slaposSupportTree, slaposBasePool, slaposSliceSupports, slaposIndexSlices }); - invalidated |= m_print->invalidate_step(slapsRasterize); + invalidated |= this->invalidate_steps({ slaposSupportTree, slaposBasePool, slaposSliceSupports }); + invalidated |= m_print->invalidate_step(slapsMergeSlicesAndEval); } else if (step == slaposSupportTree) { - invalidated |= this->invalidate_steps({ slaposBasePool, slaposSliceSupports, slaposIndexSlices }); - invalidated |= m_print->invalidate_step(slapsRasterize); + invalidated |= this->invalidate_steps({ slaposBasePool, slaposSliceSupports }); + invalidated |= m_print->invalidate_step(slapsMergeSlicesAndEval); } else if (step == slaposBasePool) { - invalidated |= this->invalidate_steps({slaposSliceSupports, slaposIndexSlices}); - invalidated |= m_print->invalidate_step(slapsRasterize); + invalidated |= this->invalidate_steps({slaposSliceSupports}); + invalidated |= m_print->invalidate_step(slapsMergeSlicesAndEval); } else if (step == slaposSliceSupports) { - invalidated |= this->invalidate_step(slaposIndexSlices); - invalidated |= m_print->invalidate_step(slapsRasterize); - } else if(step == slaposIndexSlices) { - invalidated |= m_print->invalidate_step(slapsRasterize); + invalidated |= m_print->invalidate_step(slapsMergeSlicesAndEval); } return invalidated; } @@ -1547,18 +1548,6 @@ const ExPolygons &SliceRecord::get_slice(SliceOrigin o) const return idx >= v.size() ? EMPTY_SLICE : v[idx]; } -const std::vector & SLAPrintObject::get_slice_index() const -{ - // assert(is_step_done(slaposIndexSlices)); - return m_slice_index; -} - -const std::vector &SLAPrintObject::get_model_slices() const -{ - // assert(is_step_done(slaposObjectSlice)); - return m_model_slices; -} - bool SLAPrintObject::has_mesh(SLAPrintObjectStep step) const { switch (step) { diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index afdfab415..0909645f7 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -11,9 +11,8 @@ namespace Slic3r { enum SLAPrintStep : unsigned int { - slapsStats, - slapsRasterize, - slapsValidate, + slapsMergeSlicesAndEval, + slapsRasterize, slapsCount }; @@ -22,8 +21,7 @@ enum SLAPrintObjectStep : unsigned int { slaposSupportPoints, slaposSupportTree, slaposBasePool, - slaposSliceSupports, - slaposIndexSlices, + slaposSliceSupports, slaposCount }; @@ -190,7 +188,7 @@ private: return it; } - const std::vector& get_model_slices() const; + const std::vector& get_model_slices() const { return m_model_slices; } const std::vector& get_support_slices() const; public: @@ -205,7 +203,9 @@ public: // ///////////////////////////////////////////////////////////////////////// // Retrieve the slice index. - const std::vector& get_slice_index() const; + const std::vector& get_slice_index() const { + return m_slice_index; + } // Search slice index for the closest slice to given print_level. // max_epsilon gives the allowable deviation of the returned slice record's @@ -370,7 +370,7 @@ public: // Returns true if an object step is done on all objects and there's at least one object. bool is_step_done(SLAPrintObjectStep step) const; // Returns true if the last step was finished with success. - bool finished() const override { return this->is_step_done(slaposIndexSlices) && this->Inherited::is_step_done(slapsRasterize); } + bool finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); } template void export_raster(const std::string& fname) { if(m_printer) m_printer->save(fname); @@ -396,6 +396,9 @@ private: using SLAPrinter = FilePrinter; using SLAPrinterPtr = std::unique_ptr; + // Implement same logic as in SLAPrintObject + bool invalidate_step(SLAPrintStep st); + // Invalidate steps based on a set of parameters changed. bool invalidate_state_by_config_options(const std::vector &opt_keys); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index da62ddab0..eaa5f30f5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5010,7 +5010,7 @@ void GLCanvas3D::_render_sla_slices() const } if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && - obj->is_step_done(slaposIndexSlices) && !obj->get_slice_index().empty()) + obj->is_step_done(slaposSliceSupports) && !obj->get_slice_index().empty()) { double layer_height = print->default_object_config().layer_height.value; double initial_layer_height = print->material_config().initial_layer_height.value; @@ -6212,7 +6212,7 @@ void GLCanvas3D::_load_shells_sla() int obj_idx = 0; for (const SLAPrintObject* obj : print->objects()) { - if (!obj->is_step_done(slaposIndexSlices)) + if (!obj->is_step_done(slaposSliceSupports)) continue; unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 18324f2e8..8ed6ccb80 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -772,7 +772,7 @@ void Preview::load_print_as_sla() std::vector zs; double initial_layer_height = print->material_config().initial_layer_height.value; for (const SLAPrintObject* obj : print->objects()) - if (obj->is_step_done(slaposIndexSlices) && !obj->get_slice_index().empty()) + if (obj->is_step_done(slaposSliceSupports) && !obj->get_slice_index().empty()) { auto low_coord = obj->get_slice_index().front().print_level(); for (auto& rec : obj->get_slice_index()) From 440e54181b48291e9eed5298c80893661afb4c4c Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 27 Mar 2019 18:37:50 +0100 Subject: [PATCH 3/8] Output raster seem ok, stats broken. --- .../libnest2d/backends/clipper/CMakeLists.txt | 1 + .../backends/clipper/clipper_polygon.hpp | 72 +++ .../libnest2d/backends/clipper/geometries.hpp | 121 +---- src/libnest2d/tests/printer_parts.h | 30 +- src/libslic3r/ModelArrange.cpp | 2 +- src/libslic3r/PrintExport.hpp | 12 +- src/libslic3r/Rasterizer/Rasterizer.cpp | 45 +- src/libslic3r/Rasterizer/Rasterizer.hpp | 7 +- src/libslic3r/SLAPrint.cpp | 417 +++++++++++------- src/libslic3r/SLAPrint.hpp | 76 ++-- 10 files changed, 436 insertions(+), 347 deletions(-) create mode 100644 src/libnest2d/include/libnest2d/backends/clipper/clipper_polygon.hpp 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; } From 50c351e0f4bf498d4890b652074103569145bddf Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 28 Mar 2019 11:01:41 +0100 Subject: [PATCH 4/8] Fix broken arrange --- .../libnest2d/backends/clipper/geometries.hpp | 24 ++++++++++++------- src/libnest2d/include/libnest2d/libnest2d.hpp | 2 +- .../include/libnest2d/placers/nfpplacer.hpp | 6 ++--- .../libnest2d/placers/placer_boilerplate.hpp | 4 ++-- .../libnest2d/selections/djd_heuristic.hpp | 2 +- .../include/libnest2d/utils/boost_alg.hpp | 2 +- 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp index 2c9550cf8..d0cc44896 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp +++ b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp @@ -150,9 +150,10 @@ template<> inline void offset(PolygonImpl& sh, TCoord distance) // but throwing would be an overkill. Instead, we should warn the // caller about the inability to create correct geometries if(!found_the_contour) { - sh.Contour = r; + sh.Contour = std::move(r); ClipperLib::ReversePath(sh.Contour); - sh.Contour.push_back(sh.Contour.front()); + auto front_p = sh.Contour.front(); + sh.Contour.emplace_back(std::move(front_p)); found_the_contour = true; } else { dout() << "Warning: offsetting result is invalid!"; @@ -162,9 +163,10 @@ template<> inline void offset(PolygonImpl& sh, TCoord distance) // TODO If there are multiple contours we can't be sure which hole // belongs to the first contour. (But in this case the situation is // bad enough to let it go...) - sh.Holes.push_back(r); + sh.Holes.emplace_back(std::move(r)); ClipperLib::ReversePath(sh.Holes.back()); - sh.Holes.back().push_back(sh.Holes.back().front()); + auto front_p = sh.Holes.back().front(); + sh.Holes.back().emplace_back(std::move(front_p)); } } } @@ -328,16 +330,18 @@ inline std::vector clipper_execute( std::function processHole; auto processPoly = [&retv, &processHole](ClipperLib::PolyNode *pptr) { - PolygonImpl poly(pptr->Contour); - poly.Contour.push_back(poly.Contour.front()); + PolygonImpl poly; + poly.Contour.swap(pptr->Contour); auto front_p = poly.Contour.front(); + poly.Contour.emplace_back(std::move(front_p)); for(auto h : pptr->Childs) { processHole(h, poly); } retv.push_back(poly); }; processHole = [&processPoly](ClipperLib::PolyNode *pptr, PolygonImpl& poly) { - poly.Holes.push_back(pptr->Contour); - poly.Holes.back().push_back(poly.Holes.back().front()); + poly.Holes.emplace_back(std::move(pptr->Contour)); + auto front_p = poly.Holes.back().front(); + poly.Holes.back().emplace_back(std::move(front_p)); for(auto c : pptr->Childs) processPoly(c); }; @@ -365,7 +369,9 @@ merge(const std::vector& shapes) for(auto& path : shapes) { valid &= clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed); - valid &= clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed); + + for(auto& h : path.Holes) + valid &= clipper.AddPath(h, ClipperLib::ptSubject, closed); } if(!valid) throw GeometryException(GeomErr::MERGE); diff --git a/src/libnest2d/include/libnest2d/libnest2d.hpp b/src/libnest2d/include/libnest2d/libnest2d.hpp index 49baa65f2..c7b252e5d 100644 --- a/src/libnest2d/include/libnest2d/libnest2d.hpp +++ b/src/libnest2d/include/libnest2d/libnest2d.hpp @@ -966,7 +966,7 @@ private: for(size_t i = 0; i < pckgrp.size(); i++) { auto items = pckgrp[i]; - pg.push_back({}); + pg.emplace_back(); pg[i].reserve(items.size()); for(Item& itemA : items) { diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp index 6fb717a7a..91affe978 100644 --- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp +++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp @@ -261,7 +261,7 @@ template class EdgeCache { while(next != endit) { contour_.emap.emplace_back(*(first++), *(next++)); contour_.full_distance += contour_.emap.back().length(); - contour_.distances.push_back(contour_.full_distance); + contour_.distances.emplace_back(contour_.full_distance); } } @@ -276,10 +276,10 @@ template class EdgeCache { while(next != endit) { hc.emap.emplace_back(*(first++), *(next++)); hc.full_distance += hc.emap.back().length(); - hc.distances.push_back(hc.full_distance); + hc.distances.emplace_back(hc.full_distance); } - holes_.push_back(hc); + holes_.emplace_back(std::move(hc)); } } diff --git a/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp b/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp index 309a5007d..abcd86183 100644 --- a/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp +++ b/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp @@ -63,7 +63,7 @@ public: bool pack(Item& item, const Range& rem = Range()) { auto&& r = static_cast(this)->trypack(item, rem); if(r) { - items_.push_back(*(r.item_ptr_)); + items_.emplace_back(*(r.item_ptr_)); farea_valid_ = false; } return r; @@ -78,7 +78,7 @@ public: if(r) { r.item_ptr_->translation(r.move_); r.item_ptr_->rotation(r.rot_); - items_.push_back(*(r.item_ptr_)); + items_.emplace_back(*(r.item_ptr_)); farea_valid_ = false; } } diff --git a/src/libnest2d/include/libnest2d/selections/djd_heuristic.hpp b/src/libnest2d/include/libnest2d/selections/djd_heuristic.hpp index b03534dc4..25007e580 100644 --- a/src/libnest2d/include/libnest2d/selections/djd_heuristic.hpp +++ b/src/libnest2d/include/libnest2d/selections/djd_heuristic.hpp @@ -667,7 +667,7 @@ public: addBin(); ItemList& not_packed = not_packeds[b]; for(unsigned idx = b; idx < store_.size(); idx+=bincount_guess) { - not_packed.push_back(store_[idx]); + not_packed.emplace_back(store_[idx]); } } diff --git a/src/libnest2d/include/libnest2d/utils/boost_alg.hpp b/src/libnest2d/include/libnest2d/utils/boost_alg.hpp index a6988ca00..baf1c6a10 100644 --- a/src/libnest2d/include/libnest2d/utils/boost_alg.hpp +++ b/src/libnest2d/include/libnest2d/utils/boost_alg.hpp @@ -463,7 +463,7 @@ template<> inline std::string serialize( auto& v = *it; hf.emplace_back(getX(v)*scale, getY(v)*scale); }; - holes.push_back(hf); + holes.emplace_back(std::move(hf)); } Polygonf poly; From b19d411738979ec9416827aec52d494489ba5363 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 29 Mar 2019 13:34:22 +0100 Subject: [PATCH 5/8] It seems that stats are not broken after all. --- src/libslic3r/SLAPrint.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index eaa4642b0..ba6e5a904 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -578,11 +578,6 @@ sla::PoolConfig make_pool_config(const SLAPrintObjectConfig& c) { return pcfg; } - -void swapXY(ExPolygon& expoly) { - for(auto& p : expoly.contour.points) std::swap(p(X), p(Y)); - for(auto& h : expoly.holes) for(auto& p : h.points) std::swap(p(X), p(Y)); -} } std::string SLAPrint::validate() const @@ -1008,13 +1003,7 @@ void SLAPrint::process() 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); }); - }; + auto area = [](const ClipperPolygon& poly) { return - sl::area(poly); }; 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; From 65934218028121fdb6f8a494122a64f17778cd66 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 29 Mar 2019 17:20:19 +0100 Subject: [PATCH 6/8] fix for statistics --- src/libslic3r/PrintExport.hpp | 2 +- src/libslic3r/SLAPrint.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/PrintExport.hpp b/src/libslic3r/PrintExport.hpp index 5b0a91177..04b993a52 100644 --- a/src/libslic3r/PrintExport.hpp +++ b/src/libslic3r/PrintExport.hpp @@ -224,7 +224,7 @@ public: inline void draw_polygon(const ClipperLib::Polygon& p, unsigned lyr) { assert(lyr < m_layers_rst.size()); - m_layers_rst[lyr].first.draw(p); + m_layers_rst[lyr].raster.draw(p); } inline void begin_layer(unsigned lyr) { diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index ba6e5a904..9e03b6f84 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1143,7 +1143,7 @@ void SLAPrint::process() for (const ClipperPolygon& polygon : supports_polygons) layer_support_area += area(polygon); - if (layer_support_area < 0 || layer_model_area > 0) + if (layer_support_area < 0 || layer_support_area > 0) supports_volume += layer_support_area * l_height; // Here we can save the expensively calculated polygons for printing From 4eb5d91a8f2209f5b5a192a80dd7f03905a3aa10 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 1 Apr 2019 11:37:26 +0200 Subject: [PATCH 7/8] Parallel loop for the statistics --- .../libnest2d/backends/clipper/geometries.hpp | 4 +- src/libslic3r/SLAPrint.cpp | 94 +++++++++++-------- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp index d0cc44896..15eeb57b8 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp +++ b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp @@ -347,9 +347,7 @@ inline std::vector clipper_execute( auto traverse = [&processPoly] (ClipperLib::PolyNode *node) { - for(auto ch : node->Childs) { - processPoly(ch); - } + for(auto ch : node->Childs) processPoly(ch); }; traverse(&result); diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 9e03b6f84..a5aa826c9 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -956,16 +956,15 @@ void SLAPrint::process() m_print_statistics.clear(); - using ClipperPolygon = libnest2d::PolygonImpl; - using ClipperPath = ClipperLib::Path; using ClipperPoint = ClipperLib::IntPoint; + using ClipperPolygon = ClipperLib::Polygon; // see clipper_polygon.hpp in libnest2d using ClipperPolygons = std::vector; - using libnest2d::Radians; - namespace sl = libnest2d::shapelike; + namespace sl = libnest2d::shapelike; // For algorithms // If the raster has vertical orientation, we will flip the coordinates bool flpXY = m_printer_config.display_orientation.getInt() == SLADisplayOrientation::sladoPortrait; + // Set up custom union and diff functions for clipper polygons auto polyunion = [] (const ClipperPolygons& subjects) { ClipperLib::Clipper clipper; @@ -1003,7 +1002,8 @@ void SLAPrint::process() return libnest2d::clipper_execute(clipper, ClipperLib::ctDifference, mode, mode); }; - auto area = [](const ClipperPolygon& poly) { return - sl::area(poly); }; + // libnest calculates positive area for clockwise polygons, Slic3r is in counter-clockwise + auto areafn = [](const ClipperPolygon& poly) { return - sl::area(poly); }; 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; @@ -1051,7 +1051,7 @@ void SLAPrint::process() auto pfirst = hole.front(); hole.emplace_back(pfirst); } - sl::rotate(poly, Radians(double(instances[i].rotation))); + sl::rotate(poly, double(instances[i].rotation)); sl::translate(poly, ClipperPoint{instances[i].shift(X), instances[i].shift(Y)}); if (flpXY) { @@ -1070,10 +1070,10 @@ void SLAPrint::process() return polygons; }; - double supports_volume = 0.0; - double models_volume = 0.0; + double supports_volume(0.0); + double models_volume(0.0); - double estim_time = 0.0; + double estim_time(0.0); size_t slow_layers = 0; size_t fast_layers = 0; @@ -1081,16 +1081,22 @@ void SLAPrint::process() 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(); + SpinMutex mutex; + using Lock = std::lock_guard; - if(lyrslices.empty()) continue; +// for (PrintLayer& layer : m_printer_input) + auto printlayerfn = [this, get_all_polygons, polyunion, polydiff, areafn, area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, delta_fade_time, + &mutex, &models_volume, &supports_volume, &estim_time, &slow_layers, &fast_layers, &fade_layer_time](size_t sliced_layer_cnt) + { + PrintLayer& layer = m_printer_input[sliced_layer_cnt]; + + // vector of slice record references + auto& slicerecord_references = layer.slices(); + + if(slicerecord_references.empty()) return; // Layer height should match for all object slices for a given level. - const auto l_height = double(lyrslices.front().get().layer_height()); + const auto l_height = double(slicerecord_references.front().get().layer_height()); // Calculation of the consumed material @@ -1128,23 +1134,25 @@ void SLAPrint::process() model_polygons = polyunion(model_polygons); double layer_model_area = 0; for (const ClipperPolygon& polygon : model_polygons) - layer_model_area += area(polygon); + layer_model_area += areafn(polygon); - if (layer_model_area < 0 || layer_model_area > 0) - models_volume += layer_model_area * l_height; + if (layer_model_area < 0 || layer_model_area > 0) { + Lock lck(mutex); 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); + /*if(model_polygons.empty()) */supports_polygons = polyunion(supports_polygons); + /*else */ if(!model_polygons.empty())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); + layer_support_area += areafn(polygon); - if (layer_support_area < 0 || layer_support_area > 0) - supports_volume += layer_support_area * l_height; + if (layer_support_area < 0 || layer_support_area > 0) { + Lock lck(mutex); supports_volume += layer_support_area * l_height; + } // Here we can save the expensively calculated polygons for printing ClipperPolygons trslices; @@ -1158,28 +1166,32 @@ void SLAPrint::process() 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++; + + { Lock lck(mutex); + if (is_fast_layer) + fast_layers++; + else + slow_layers++; - // Calculation of the printing time + // 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; + 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; } - else - estim_time += exp_time; + }; - estim_time += tilt_time; - - sliced_layer_cnt++; - } + for(size_t i = 0; i < m_printer_input.size(); ++i) printlayerfn(i); +// tbb::parallel_for(0, m_printer_input.size(), printlayerfn); m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR; m_print_statistics.objects_used_material = models_volume * SCALING_FACTOR * SCALING_FACTOR; From 2baa651f1e21b81a00bf23975fce711c5642e4ae Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 1 Apr 2019 12:15:47 +0200 Subject: [PATCH 8/8] Fixing the broken rasterizer. Paths and holes cannot be added separately. --- .../libnest2d/backends/clipper/geometries.hpp | 21 ++++++++--- src/libslic3r/Rasterizer/Rasterizer.cpp | 35 +++++++++++++++---- src/libslic3r/SLAPrint.cpp | 23 +++++++----- 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp index 15eeb57b8..232668f61 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp +++ b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp @@ -331,8 +331,15 @@ inline std::vector clipper_execute( auto processPoly = [&retv, &processHole](ClipperLib::PolyNode *pptr) { PolygonImpl poly; - poly.Contour.swap(pptr->Contour); auto front_p = poly.Contour.front(); - poly.Contour.emplace_back(std::move(front_p)); + poly.Contour.swap(pptr->Contour); + + assert(!pptr->IsHole()); + + if(pptr->IsOpen()) { + auto front_p = poly.Contour.front(); + poly.Contour.emplace_back(front_p); + } + for(auto h : pptr->Childs) { processHole(h, poly); } retv.push_back(poly); }; @@ -340,8 +347,14 @@ inline std::vector clipper_execute( processHole = [&processPoly](ClipperLib::PolyNode *pptr, PolygonImpl& poly) { poly.Holes.emplace_back(std::move(pptr->Contour)); - auto front_p = poly.Holes.back().front(); - poly.Holes.back().emplace_back(std::move(front_p)); + + assert(pptr->IsHole()); + + if(pptr->IsOpen()) { + auto front_p = poly.Holes.back().front(); + poly.Holes.back().emplace_back(front_p); + } + for(auto c : pptr->Childs) processPoly(c); }; diff --git a/src/libslic3r/Rasterizer/Rasterizer.cpp b/src/libslic3r/Rasterizer/Rasterizer.cpp index ab584821f..496a584a2 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.cpp +++ b/src/libslic3r/Rasterizer/Rasterizer.cpp @@ -71,16 +71,41 @@ public: clear(); } - template inline void draw(const Geometry &poly) { + void draw(const ExPolygon &poly) { agg::rasterizer_scanline_aa<> ras; agg::scanline_p8 scanlines; - auto&& path = to_path(poly); + auto&& path = to_path(poly.contour); if(m_o == Origin::TOP_LEFT) flipy(path); ras.add_path(path); + for(auto h : poly.holes) { + auto&& holepath = to_path(h); + if(m_o == Origin::TOP_LEFT) flipy(holepath); + ras.add_path(holepath); + } + + agg::render_scanlines(ras, scanlines, m_renderer); + } + + void draw(const ClipperLib::Polygon &poly) { + agg::rasterizer_scanline_aa<> ras; + agg::scanline_p8 scanlines; + + auto&& path = to_path(poly.Contour); + + if(m_o == Origin::TOP_LEFT) flipy(path); + + ras.add_path(path); + + for(auto h : poly.Holes) { + auto&& holepath = to_path(h); + if(m_o == Origin::TOP_LEFT) flipy(holepath); + ras.add_path(holepath); + } + agg::render_scanlines(ras, scanlines, m_renderer); } @@ -186,14 +211,12 @@ void Raster::clear() void Raster::draw(const ExPolygon &expoly) { - m_impl->draw(expoly.contour); - for(auto& h : expoly.holes) m_impl->draw(h); + m_impl->draw(expoly); } void Raster::draw(const ClipperLib::Polygon &poly) { - m_impl->draw(poly.Contour); - for(auto& h : poly.Holes) m_impl->draw(h); + m_impl->draw(poly); } void Raster::save(std::ostream& stream, Compression comp) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index a5aa826c9..424881491 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1084,9 +1084,15 @@ void SLAPrint::process() SpinMutex mutex; using Lock = std::lock_guard; -// for (PrintLayer& layer : m_printer_input) - auto printlayerfn = [this, get_all_polygons, polyunion, polydiff, areafn, area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, delta_fade_time, - &mutex, &models_volume, &supports_volume, &estim_time, &slow_layers, &fast_layers, &fade_layer_time](size_t sliced_layer_cnt) + // Going to parallel: + auto printlayerfn = [this, + // functions and read only vars + get_all_polygons, polyunion, polydiff, areafn, + area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, delta_fade_time, + + // write vars + &mutex, &models_volume, &supports_volume, &estim_time, &slow_layers, + &fast_layers, &fade_layer_time](size_t sliced_layer_cnt) { PrintLayer& layer = m_printer_input[sliced_layer_cnt]; @@ -1141,9 +1147,9 @@ void SLAPrint::process() } if(!supports_polygons.empty()) { - /*if(model_polygons.empty()) */supports_polygons = polyunion(supports_polygons); - /*else */ if(!model_polygons.empty())supports_polygons = polydiff(supports_polygons, model_polygons); - // allegedly, union of subject is done withing the diff + 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 according to the pftPositive polyFillType } double layer_support_area = 0; @@ -1190,8 +1196,9 @@ void SLAPrint::process() } }; - for(size_t i = 0; i < m_printer_input.size(); ++i) printlayerfn(i); -// tbb::parallel_for(0, m_printer_input.size(), printlayerfn); + // sequential version for debugging: + // for(size_t i = 0; i < m_printer_input.size(); ++i) printlayerfn(i); + tbb::parallel_for(0, m_printer_input.size(), printlayerfn); m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR; m_print_statistics.objects_used_material = models_volume * SCALING_FACTOR * SCALING_FACTOR;