From 7c20c21255b7bd9dcdca14931d8eb6075fcb1736 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 26 Mar 2019 18:51:27 +0100 Subject: [PATCH 01/38] 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 df9446cf52a..003ed5af4d9 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 5961d9b7892..3e42e37d8b8 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 06d5b88c6dd..05ffd99b3b2 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 ee24cf3ecf8..af3f20a594c 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 afdfab4156e..9b6c8968783 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 6c5fb6430d5a9b0811b6e9c42a3373621ec6ef07 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 27 Mar 2019 10:59:29 +0100 Subject: [PATCH 02/38] 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 ee24cf3ecf8..862913f9511 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 afdfab4156e..0909645f7a3 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 da62ddab082..eaa5f30f590 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 18324f2e8a7..8ed6ccb8049 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 0d3f453af0041dc4dad2208b33e1e1f4c3e64d82 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 27 Mar 2019 18:37:50 +0100 Subject: [PATCH 03/38] 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 995afcc76d7..462d1dd068d 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 00000000000..e9fbfbd18a3 --- /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 9f881e7e0da..2c9550cf8cd 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 b9a4eb8fab1..1e65826bd30 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 4942e35b600..54627ba86b1 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 003ed5af4d9..c0c12209a33 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 3e42e37d8b8..45c9daf3b4f 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 05ffd99b3b2..0468b664445 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 ab7feed0e65..eaa4642b0c1 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 e645a9574bf..0688307710d 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 be6348ad744c6058acbf53b49fb4df7cb1c2c6e9 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 28 Mar 2019 11:01:41 +0100 Subject: [PATCH 04/38] 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 2c9550cf8cd..d0cc4489644 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 49baa65f25f..c7b252e5d58 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 6fb717a7a68..91affe97862 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 309a5007dec..abcd861830a 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 b03534dc469..25007e580ee 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 a6988ca0072..baf1c6a105e 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 ab26a95c658ff2029d48c5b342e7cea74e9395eb Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 29 Mar 2019 13:34:22 +0100 Subject: [PATCH 05/38] 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 eaa4642b0c1..ba6e5a904a4 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 10624370e1bd7187860e4a9e7f50b12398114e64 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 29 Mar 2019 14:57:53 +0100 Subject: [PATCH 06/38] imgui: Get font size from wxWidgets, fix #2043 --- src/slic3r/GUI/GUI_App.cpp | 11 ++++++----- src/slic3r/GUI/ImGuiWrapper.cpp | 33 ++++++++++++++------------------- src/slic3r/GUI/ImGuiWrapper.hpp | 6 +++--- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index bdfd2fc264a..fdb8968d331 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -81,7 +81,7 @@ IMPLEMENT_APP(GUI_App) GUI_App::GUI_App() : wxApp() , m_em_unit(10) - , m_imgui(new ImGuiWrapper()) + , m_imgui(nullptr) {} bool GUI_App::OnInit() @@ -90,7 +90,6 @@ bool GUI_App::OnInit() const wxString resources_dir = from_u8(Slic3r::resources_dir()); wxCHECK_MSG(wxDirExists(resources_dir), false, wxString::Format("Resources path does not exist or is not a directory: %s", resources_dir)); - wxCHECK_MSG(m_imgui->init(), false, "Failed to initialize ImGui"); SetAppName("Slic3rPE-beta"); SetAppDisplayName("Slic3r Prusa Edition"); @@ -136,6 +135,11 @@ bool GUI_App::OnInit() app_config->save(); }); + // initialize label colors and fonts + init_label_colours(); + init_fonts(); + m_imgui.reset(new ImGuiWrapper(m_normal_font.GetPixelSize().y)); + load_language(); // Suppress the '- default -' presets. @@ -148,9 +152,6 @@ bool GUI_App::OnInit() // Let the libslic3r know the callback, which will translate messages on demand. Slic3r::I18N::set_translate_callback(libslic3r_translate_callback); - // initialize label colors and fonts - init_label_colours(); - init_fonts(); // application frame if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr) diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 0932c8ce93d..f626fa7f5ad 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -25,14 +25,22 @@ namespace Slic3r { namespace GUI { -ImGuiWrapper::ImGuiWrapper() +ImGuiWrapper::ImGuiWrapper(float font_size) : m_glyph_ranges(nullptr) + , m_font_size(font_size) , m_font_texture(0) , m_style_scaling(1.0) , m_mouse_buttons(0) , m_disabled(false) , m_new_frame_open(false) { + ImGui::CreateContext(); + + init_default_font(); + init_input(); + init_style(); + + ImGui::GetIO().IniFilename = nullptr; } ImGuiWrapper::~ImGuiWrapper() @@ -41,19 +49,6 @@ ImGuiWrapper::~ImGuiWrapper() ImGui::DestroyContext(); } -bool ImGuiWrapper::init() -{ - ImGui::CreateContext(); - - init_default_font(m_style_scaling); - init_input(); - init_style(); - - ImGui::GetIO().IniFilename = nullptr; - - return true; -} - void ImGuiWrapper::set_language(const std::string &language) { if (m_new_frame_open) { @@ -87,7 +82,7 @@ void ImGuiWrapper::set_language(const std::string &language) if (ranges != m_glyph_ranges) { m_glyph_ranges = ranges; - init_default_font(m_style_scaling); + init_default_font(); } } @@ -102,8 +97,8 @@ void ImGuiWrapper::set_style_scaling(float scaling) { if (!std::isnan(scaling) && !std::isinf(scaling) && scaling != m_style_scaling) { ImGui::GetStyle().ScaleAllSizes(scaling / m_style_scaling); - init_default_font(scaling); m_style_scaling = scaling; + init_default_font(); } } @@ -328,15 +323,15 @@ bool ImGuiWrapper::want_any_input() const return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput; } -void ImGuiWrapper::init_default_font(float scaling) +void ImGuiWrapper::init_default_font() { - static const float font_size = 18.0f; + const float font_size = m_font_size * m_style_scaling; destroy_fonts_texture(); ImGuiIO& io = ImGui::GetIO(); io.Fonts->Clear(); - ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), font_size * scaling, nullptr, m_glyph_ranges); + ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), font_size, nullptr, m_glyph_ranges); if (font == nullptr) { font = io.Fonts->AddFontDefault(); if (font == nullptr) { diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 35d0b5636d7..7e022532a55 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -22,6 +22,7 @@ class ImGuiWrapper FontsMap m_fonts; const ImWchar *m_glyph_ranges; + float m_font_size; unsigned m_font_texture; float m_style_scaling; unsigned m_mouse_buttons; @@ -30,10 +31,9 @@ class ImGuiWrapper std::string m_clipboard_text; public: - ImGuiWrapper(); + ImGuiWrapper(float font_size); ~ImGuiWrapper(); - bool init(); void read_glsl_version(); void set_language(const std::string &language); @@ -73,7 +73,7 @@ public: bool want_any_input() const; private: - void init_default_font(float scaling); + void init_default_font(); void create_device_objects(); void create_fonts_texture(); void init_input(); From e2334782e7da991e28f46775d6a2cd2c414d4d9b Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 29 Mar 2019 17:20:19 +0100 Subject: [PATCH 07/38] 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 5b0a911773e..04b993a529b 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 ba6e5a904a4..9e03b6f842f 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 c5e93fe2bb561f851d7fd6bf2fbe4670230a6012 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 1 Apr 2019 09:11:23 +0200 Subject: [PATCH 08/38] Fix of visual hints for rotation of full single instance selection --- src/slic3r/GUI/Selection.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index fb35b500e83..5d286846b42 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -970,7 +970,23 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field) const ::glTranslated(center(0), center(1), center(2)); if (!boost::starts_with(sidebar_field, "position")) { - Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); + Transform3d orient_matrix = Transform3d::Identity(); + if (boost::starts_with(sidebar_field, "scale")) + orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); + else if (boost::starts_with(sidebar_field, "rotation")) + { + if (boost::ends_with(sidebar_field, "x")) + orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); + else if (boost::ends_with(sidebar_field, "y")) + { + const Vec3d& rotation = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation(); + if (rotation(0) == 0.0) + orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); + else + orient_matrix.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ())); + } + } + ::glMultMatrixd(orient_matrix.data()); } } From a26faa56cf54f5b092ee0b6d45d522377786fd21 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 1 Apr 2019 11:08:26 +0200 Subject: [PATCH 09/38] Fix of No preview of position in variable layer editing UI at retina resolution #2050 --- src/slic3r/GUI/GLCanvas3D.cpp | 16 +++++++++++----- src/slic3r/GUI/GLCanvas3D.hpp | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a25b7e7c193..5fd058ff76a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -380,7 +380,7 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas) { - const Point& mouse_pos = canvas.get_local_mouse_position(); + const Vec2d mouse_pos = canvas.get_local_mouse_position(); const Rect& rect = get_bar_rect_screen(canvas); float x = (float)mouse_pos(0); float y = (float)mouse_pos(1); @@ -3915,19 +3915,25 @@ Size GLCanvas3D::get_canvas_size() const w *= factor; h *= factor; #else - const float factor = 1.0; + const float factor = 1.0f; #endif return Size(w, h, factor); } -Point GLCanvas3D::get_local_mouse_position() const +Vec2d GLCanvas3D::get_local_mouse_position() const { if (m_canvas == nullptr) - return Point(); + return Vec2d::Zero(); wxPoint mouse_pos = m_canvas->ScreenToClient(wxGetMousePosition()); - return Point(mouse_pos.x, mouse_pos.y); + const double factor = +#if ENABLE_RETINA_GL + m_retina_helper->get_scale_factor(); +#else + 1.0; +#endif + return Vec2d(factor * mouse_pos.x, factor * mouse_pos.y); } void GLCanvas3D::reset_legend_texture() diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index cc69117bfa3..2b1061c95fd 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -699,7 +699,7 @@ public: void on_paint(wxPaintEvent& evt); Size get_canvas_size() const; - Point get_local_mouse_position() const; + Vec2d get_local_mouse_position() const; void reset_legend_texture(); From e58f974cf4ed82e2c1680d64e7974e133dac224e Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 1 Apr 2019 11:37:26 +0200 Subject: [PATCH 10/38] 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 d0cc4489644..15eeb57b8ad 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 9e03b6f842f..a5aa826c98b 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 99c72bd4af33a79926e1128fc4e483257872b81b Mon Sep 17 00:00:00 2001 From: Sijmen Schoon Date: Thu, 28 Mar 2019 12:34:41 +0100 Subject: [PATCH 11/38] Clean up and fix TriangleMesh::split and relatives --- src/libslic3r/Model.cpp | 22 ++--- src/libslic3r/TriangleMesh.cpp | 142 +++++++++++++-------------------- src/libslic3r/TriangleMesh.hpp | 8 +- 3 files changed, 67 insertions(+), 105 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index f9db9fea0b1..ffb80c57320 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -61,7 +61,7 @@ Model& Model::assign_copy(Model &&rhs) this->objects = std::move(rhs.objects); for (ModelObject *model_object : this->objects) model_object->set_model(this); - rhs.objects.clear(); + rhs.objects.clear(); return *this; } @@ -651,7 +651,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs) for (ModelInstance *model_instance : this->instances) model_instance->set_model_object(this); - return *this; + return *this; } void ModelObject::assign_new_unique_ids_recursive() @@ -970,8 +970,8 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) } } } - std::sort(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) < b(0) || (a(0) == b(0) && a(1) < b(1)); }); - pts.erase(std::unique(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) == b(0) && a(1) == b(1); }), pts.end()); + std::sort(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) < b(0) || (a(0) == b(0) && a(1) < b(1)); }); + pts.erase(std::unique(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) == b(0) && a(1) == b(1); }), pts.end()); Polygon hull; int n = (int)pts.size(); @@ -1291,11 +1291,11 @@ void ModelObject::split(ModelObjectPtrs* new_objects) // XXX: this seems to be the only real usage of m_model, maybe refactor this so that it's not needed? ModelObject* new_object = m_model->add_object(); - new_object->name = this->name; - new_object->config = this->config; - new_object->instances.reserve(this->instances.size()); - for (const ModelInstance *model_instance : this->instances) - new_object->add_instance(*model_instance); + new_object->name = this->name; + new_object->config = this->config; + new_object->instances.reserve(this->instances.size()); + for (const ModelInstance *model_instance : this->instances) + new_object->add_instance(*model_instance); ModelVolume* new_vol = new_object->add_volume(*volume, std::move(*mesh)); #if !ENABLE_VOLUMES_CENTERING_FIXES new_vol->center_geometry(); @@ -1467,9 +1467,9 @@ int ModelVolume::extruder_id() const bool ModelVolume::is_splittable() const { - // the call mesh.has_multiple_patches() is expensive, so cache the value to calculate it only once + // the call mesh.is_splittable() is expensive, so cache the value to calculate it only once if (m_is_splittable == -1) - m_is_splittable = (int)mesh.has_multiple_patches(); + m_is_splittable = (int)mesh.is_splittable(); return m_is_splittable == 1; } diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index eaa11b73815..467c44a8abd 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -338,113 +338,78 @@ void TriangleMesh::rotate(double angle, Point* center) this->translate(c(0), c(1), 0); } -bool TriangleMesh::has_multiple_patches() const +/** + * Calculates whether or not the mesh is splittable. + */ +bool TriangleMesh::is_splittable() const { - // we need neighbors - if (!this->repaired) - throw std::runtime_error("split() requires repair()"); - - if (this->stl.stats.number_of_facets == 0) - return false; + std::vector visited; + find_unvisited_neighbors(visited); - std::vector facet_queue(this->stl.stats.number_of_facets, 0); - std::vector facet_visited(this->stl.stats.number_of_facets, false); - int facet_queue_cnt = 1; - facet_queue[0] = 0; - facet_visited[0] = true; - while (facet_queue_cnt > 0) { - int facet_idx = facet_queue[-- facet_queue_cnt]; - facet_visited[facet_idx] = true; - for (int j = 0; j < 3; ++ j) { - int neighbor_idx = this->stl.neighbors_start[facet_idx].neighbor[j]; - if (neighbor_idx != -1 && ! facet_visited[neighbor_idx]) - facet_queue[facet_queue_cnt ++] = neighbor_idx; - } - } - - // If any of the face was not visited at the first time, return "multiple bodies". - for (int facet_idx = 0; facet_idx < this->stl.stats.number_of_facets; ++ facet_idx) - if (! facet_visited[facet_idx]) - return true; - return false; + // Try finding an unvisited facet. If there are none, the mesh is not splittable. + auto it = std::find(visited.begin(), visited.end(), false); + return it != visited.end(); } -size_t TriangleMesh::number_of_patches() const +/** + * Visit all unvisited neighboring facets that are reachable from the first unvisited facet, + * and return them. + * + * @param facet_visited A reference to a vector of booleans. Contains whether or not a + * facet with the same index has been visited. + * @return A deque with all newly visited facets. + */ +std::deque TriangleMesh::find_unvisited_neighbors(std::vector &facet_visited) const { - // we need neighbors - if (!this->repaired) - throw std::runtime_error("split() requires repair()"); - - if (this->stl.stats.number_of_facets == 0) - return false; + // If the visited list is empty, populate it with false for every facet. + if (facet_visited.empty()) { + facet_visited = std::vector(this->stl.stats.number_of_facets, false); + } - std::vector facet_queue(this->stl.stats.number_of_facets, 0); - std::vector facet_visited(this->stl.stats.number_of_facets, false); - int facet_queue_cnt = 0; - size_t num_bodies = 0; - for (;;) { - // Find a seeding triangle for a new body. - int facet_idx = 0; - for (; facet_idx < this->stl.stats.number_of_facets; ++ facet_idx) - if (! facet_visited[facet_idx]) { - // A seed triangle was found. - facet_queue[facet_queue_cnt ++] = facet_idx; - facet_visited[facet_idx] = true; - break; - } - if (facet_idx == this->stl.stats.number_of_facets) - // No seed found. - break; - ++ num_bodies; - while (facet_queue_cnt > 0) { - int facet_idx = facet_queue[-- facet_queue_cnt]; + // Find the first unvisited facet. + std::queue facet_queue; + auto facet = std::find(facet_visited.begin(), facet_visited.end(), false); + if (facet != facet_visited.end()) + facet_queue.push(facet - facet_visited.begin()); + + // Traverse all reachable neighbors and mark them as visited. + std::deque facets; + while (!facet_queue.empty()) { + int facet_idx = facet_queue.front(); + facet_queue.pop(); + + if (facet_idx != -1 && !facet_visited[facet_idx]) { facet_visited[facet_idx] = true; - for (int j = 0; j < 3; ++ j) { - int neighbor_idx = this->stl.neighbors_start[facet_idx].neighbor[j]; - if (neighbor_idx != -1 && ! facet_visited[neighbor_idx]) - facet_queue[facet_queue_cnt ++] = neighbor_idx; - } + + facets.emplace_back(facet_idx); + for (int facet : this->stl.neighbors_start[facet_idx].neighbor) + facet_queue.push(facet); } } - return num_bodies; + return facets; } +/** + * Splits a mesh into multiple meshes when possible. + * + * @return A TriangleMeshPtrs with the newly created meshes. + */ TriangleMeshPtrs TriangleMesh::split() const { - TriangleMeshPtrs meshes; - std::vector facet_visited(this->stl.stats.number_of_facets, false); - - // we need neighbors + // Make sure we're not operating on a broken mesh. if (!this->repaired) throw std::runtime_error("split() requires repair()"); - // loop while we have remaining facets + // Loop while we have remaining facets. + std::vector facet_visited; + TriangleMeshPtrs meshes; for (;;) { - // get the first facet - std::queue facet_queue; - std::deque facets; - for (int facet_idx = 0; facet_idx < this->stl.stats.number_of_facets; ++ facet_idx) { - if (! facet_visited[facet_idx]) { - // if facet was not seen put it into queue and start searching - facet_queue.push(facet_idx); - break; - } - } - if (facet_queue.empty()) + std::deque facets = find_unvisited_neighbors(facet_visited); + if (facets.empty()) break; - while (! facet_queue.empty()) { - int facet_idx = facet_queue.front(); - facet_queue.pop(); - if (! facet_visited[facet_idx]) { - facets.emplace_back(facet_idx); - for (int j = 0; j < 3; ++ j) - facet_queue.push(this->stl.neighbors_start[facet_idx].neighbor[j]); - facet_visited[facet_idx] = true; - } - } - + // Create a new mesh for the part that was just split off. TriangleMesh* mesh = new TriangleMesh; meshes.emplace_back(mesh); mesh->stl.stats.type = inmemory; @@ -453,8 +418,9 @@ TriangleMeshPtrs TriangleMesh::split() const stl_clear_error(&mesh->stl); stl_allocate(&mesh->stl); + // Assign the facets to the new mesh. bool first = true; - for (std::deque::const_iterator facet = facets.begin(); facet != facets.end(); ++ facet) { + for (auto facet = facets.begin(); facet != facets.end(); ++ facet) { mesh->stl.facet_start[facet - facets.begin()] = this->stl.facet_start[*facet]; stl_facet_stats(&mesh->stl, this->stl.facet_start[*facet], first); } diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index a4387e5c1e5..b204a9a3ecf 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -68,12 +68,8 @@ public: size_t facets_count() const { return this->stl.stats.number_of_facets; } bool empty() const { return this->facets_count() == 0; } - // Returns true, if there are two and more connected patches in the mesh. - // Returns false, if one or zero connected patch is in the mesh. - bool has_multiple_patches() const; - - // Count disconnected triangle patches. - size_t number_of_patches() const; + bool is_splittable() const; + std::deque find_unvisited_neighbors(std::vector &facet_visited) const; stl_file stl; bool repaired; From e16ccd9a3b753178fa76d802d127afad71b21445 Mon Sep 17 00:00:00 2001 From: Sijmen Schoon Date: Thu, 28 Mar 2019 12:37:10 +0100 Subject: [PATCH 12/38] Fix a bunch of warnings --- src/libslic3r/Model.cpp | 3 ++- src/libslic3r/TriangleMesh.cpp | 25 +++++++++++-------------- src/libslic3r/Utils.hpp | 4 ++-- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index ffb80c57320..b5b9a008d01 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1609,6 +1609,7 @@ void ModelVolume::rotate(double angle, Axis axis) case X: { rotate(angle, Vec3d::UnitX()); break; } case Y: { rotate(angle, Vec3d::UnitY()); break; } case Z: { rotate(angle, Vec3d::UnitZ()); break; } + default: break; } } @@ -1625,6 +1626,7 @@ void ModelVolume::mirror(Axis axis) case X: { mirror(0) *= -1.0; break; } case Y: { mirror(1) *= -1.0; break; } case Z: { mirror(2) *= -1.0; break; } + default: break; } set_mirror(mirror); } @@ -1711,7 +1713,6 @@ bool model_object_list_extended(const Model &model_old, const Model &model_new) bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolumeType type) { - bool modifiers_differ = false; size_t i_old, i_new; for (i_old = 0, i_new = 0; i_old < model_object_old.volumes.size() && i_new < model_object_new.volumes.size();) { const ModelVolume &mv_old = *model_object_old.volumes[i_old]; diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 467c44a8abd..9a1a9def4e5 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -55,7 +55,7 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector& f stl.stats.original_num_facets = stl.stats.number_of_facets; stl_allocate(&stl); - for (int i = 0; i < stl.stats.number_of_facets; i++) { + for (uint32_t i = 0; i < stl.stats.number_of_facets; i++) { stl_facet facet; facet.vertex[0] = points[facets[i](0)].cast(); facet.vertex[1] = points[facets[i](1)].cast(); @@ -125,9 +125,9 @@ void TriangleMesh::repair() float tolerance = stl.stats.shortest_edge; float increment = stl.stats.bounding_diameter / 10000.0; int iterations = 2; - if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) { + if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) { for (int i = 0; i < iterations; i++) { - if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) { + if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) { //printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations); #ifdef SLIC3R_TRACE_REPAIR BOOST_LOG_TRIVIAL(trace) << "\tstl_check_faces_nearby"; @@ -143,7 +143,7 @@ void TriangleMesh::repair() } // remove_unconnected - if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) { + if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) { #ifdef SLIC3R_TRACE_REPAIR BOOST_LOG_TRIVIAL(trace) << "\tstl_remove_unconnected_facets"; #endif /* SLIC3R_TRACE_REPAIR */ @@ -212,9 +212,9 @@ void TriangleMesh::check_topology() float tolerance = stl.stats.shortest_edge; float increment = stl.stats.bounding_diameter / 10000.0; int iterations = 2; - if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) { + if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) { for (int i = 0; i < iterations; i++) { - if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) { + if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) { //printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations); stl_check_facets_nearby(&stl, tolerance); //printf(" Fixed %d edges.\n", stl.stats.edges_fixed - last_edges_fixed); @@ -442,7 +442,7 @@ void TriangleMesh::merge(const TriangleMesh &mesh) stl_reallocate(&this->stl); // copy facets - for (int i = 0; i < mesh.stl.stats.number_of_facets; ++ i) + for (uint32_t i = 0; i < mesh.stl.stats.number_of_facets; ++ i) this->stl.facet_start[number_of_facets + i] = mesh.stl.facet_start[i]; // update size @@ -455,7 +455,7 @@ ExPolygons TriangleMesh::horizontal_projection() const { Polygons pp; pp.reserve(this->stl.stats.number_of_facets); - for (int i = 0; i < this->stl.stats.number_of_facets; ++ i) { + for (uint32_t i = 0; i < this->stl.stats.number_of_facets; ++ i) { stl_facet* facet = &this->stl.facet_start[i]; Polygon p; p.points.resize(3); @@ -497,7 +497,7 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) c BoundingBoxf3 bbox; if (stl.v_shared == nullptr) { // Using the STL faces. - for (int i = 0; i < this->facets_count(); ++ i) { + for (size_t i = 0; i < this->facets_count(); ++ i) { const stl_facet &facet = this->stl.facet_start[i]; for (size_t j = 0; j < 3; ++ j) bbox.merge(trafo * facet.vertex[j].cast()); @@ -622,7 +622,7 @@ void TriangleMeshSlicer::init(TriangleMesh *_mesh, throw_on_cancel_callback_type }; std::vector edges_map; edges_map.assign(this->mesh->stl.stats.number_of_facets * 3, EdgeToFace()); - for (int facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) + for (uint32_t facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) for (int i = 0; i < 3; ++ i) { EdgeToFace &e2f = edges_map[facet_idx*3+i]; e2f.vertex_low = this->mesh->stl.v_indices[facet_idx].vertex[i]; @@ -871,7 +871,6 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( const stl_normal &normal = this->mesh->stl.facet_start[facet_idx].normal; // We may ignore this edge for slicing purposes, but we may still use it for object cutting. FacetSliceType result = Slicing; - const stl_neighbors &nbr = this->mesh->stl.neighbors_start[facet_idx]; if (min_z == max_z) { // All three vertices are aligned with slice_z. line_out->edge_type = feHorizontal; @@ -883,8 +882,6 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( } } else { // Two vertices are aligned with the cutting plane, the third vertex is below or above the cutting plane. - int nbr_idx = j % 3; - int nbr_face = nbr.neighbor[nbr_idx]; // Is the third vertex below the cutting plane? bool third_below = v0.z() < slice_z || v1.z() < slice_z || v2.z() < slice_z; // Two vertices on the cutting plane, the third vertex is below the plane. Consider the edge to be part of the slice @@ -1663,7 +1660,7 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - slicing object"; float scaled_z = scale_(z); - for (int facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) { + for (uint32_t facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) { stl_facet* facet = &this->mesh->stl.facet_start[facet_idx]; // find facet extents diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index c13df454623..dfd72b7a917 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -208,7 +208,7 @@ public: // Shorten the dhms time by removing the seconds, rounding the dhm to full minutes // and removing spaces. -static std::string short_time(const std::string &time) +inline std::string short_time(const std::string &time) { // Parse the dhms time format. int days = 0; @@ -247,7 +247,7 @@ static std::string short_time(const std::string &time) } // Returns the given time is seconds in format DDd HHh MMm SSs -static std::string get_time_dhms(float time_in_secs) +inline std::string get_time_dhms(float time_in_secs) { int days = (int)(time_in_secs / 86400.0f); time_in_secs -= (float)days * 86400.0f; From 7ee4009ef4d8f456c07a006671ceb28eb1a305ee Mon Sep 17 00:00:00 2001 From: Sijmen Schoon Date: Thu, 28 Mar 2019 12:39:57 +0100 Subject: [PATCH 13/38] Move repaired check to find_unvisited_neighbors --- src/libslic3r/TriangleMesh.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 9a1a9def4e5..7595688603e 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -361,6 +361,10 @@ bool TriangleMesh::is_splittable() const */ std::deque TriangleMesh::find_unvisited_neighbors(std::vector &facet_visited) const { + // Make sure we're not operating on a broken mesh. + if (!this->repaired) + throw std::runtime_error("split() requires repair()"); + // If the visited list is empty, populate it with false for every facet. if (facet_visited.empty()) { facet_visited = std::vector(this->stl.stats.number_of_facets, false); @@ -397,10 +401,6 @@ std::deque TriangleMesh::find_unvisited_neighbors(std::vector &f */ TriangleMeshPtrs TriangleMesh::split() const { - // Make sure we're not operating on a broken mesh. - if (!this->repaired) - throw std::runtime_error("split() requires repair()"); - // Loop while we have remaining facets. std::vector facet_visited; TriangleMeshPtrs meshes; @@ -417,7 +417,7 @@ TriangleMeshPtrs TriangleMesh::split() const mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets; stl_clear_error(&mesh->stl); stl_allocate(&mesh->stl); - + // Assign the facets to the new mesh. bool first = true; for (auto facet = facets.begin(); facet != facets.end(); ++ facet) { @@ -425,7 +425,7 @@ TriangleMeshPtrs TriangleMesh::split() const stl_facet_stats(&mesh->stl, this->stl.facet_start[*facet], first); } } - + return meshes; } From ab03a61901d2ef6c33cd2cf146d068e688d69dc6 Mon Sep 17 00:00:00 2001 From: Sijmen Schoon Date: Fri, 29 Mar 2019 01:27:20 +0100 Subject: [PATCH 14/38] Use number_of_parts for is_splittable It's there, why not use it --- src/libslic3r/Model.cpp | 6 +----- src/libslic3r/Model.hpp | 6 ------ src/libslic3r/TriangleMesh.cpp | 13 ------------- src/libslic3r/TriangleMesh.hpp | 1 - 4 files changed, 1 insertion(+), 25 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index b5b9a008d01..a9835eaa19b 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1467,11 +1467,7 @@ int ModelVolume::extruder_id() const bool ModelVolume::is_splittable() const { - // the call mesh.is_splittable() is expensive, so cache the value to calculate it only once - if (m_is_splittable == -1) - m_is_splittable = (int)mesh.is_splittable(); - - return m_is_splittable == 1; + return mesh.stl.stats.number_of_parts > 1; } void ModelVolume::center_geometry() diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 8a48f8ee960..919e7715c08 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -420,12 +420,6 @@ private: TriangleMesh m_convex_hull; Geometry::Transformation m_transformation; - // flag to optimize the checking if the volume is splittable - // -1 -> is unknown value (before first cheking) - // 0 -> is not splittable - // 1 -> is splittable - mutable int m_is_splittable{ -1 }; - ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(ModelVolumeType::MODEL_PART), object(object) { if (mesh.stl.stats.number_of_facets > 1) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 7595688603e..1baf3cee303 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -338,19 +338,6 @@ void TriangleMesh::rotate(double angle, Point* center) this->translate(c(0), c(1), 0); } -/** - * Calculates whether or not the mesh is splittable. - */ -bool TriangleMesh::is_splittable() const -{ - std::vector visited; - find_unvisited_neighbors(visited); - - // Try finding an unvisited facet. If there are none, the mesh is not splittable. - auto it = std::find(visited.begin(), visited.end(), false); - return it != visited.end(); -} - /** * Visit all unvisited neighboring facets that are reachable from the first unvisited facet, * and return them. diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index b204a9a3ecf..e538b76937d 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -68,7 +68,6 @@ public: size_t facets_count() const { return this->stl.stats.number_of_facets; } bool empty() const { return this->facets_count() == 0; } - bool is_splittable() const; std::deque find_unvisited_neighbors(std::vector &facet_visited) const; stl_file stl; From 493bdfe5c425501b98140188c06d18fffb76016b Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 1 Apr 2019 12:15:47 +0200 Subject: [PATCH 15/38] 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 15eeb57b8ad..232668f6106 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 ab584821feb..496a584a247 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 a5aa826c98b..4248814914b 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; From 358ea1b1dbbb1121cc06885109e7fbcf906031ce Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 1 Apr 2019 12:27:45 +0200 Subject: [PATCH 16/38] Revert "Use number_of_parts for is_splittable" It is too dangerous to rely on the admesh flag without inspecting the admesh code line by line and a through test. This reverts commit cd3cec3e45535ab42f7e36d50730299a91dada3e. --- src/libslic3r/Model.cpp | 6 +++++- src/libslic3r/Model.hpp | 6 ++++++ src/libslic3r/TriangleMesh.cpp | 13 +++++++++++++ src/libslic3r/TriangleMesh.hpp | 1 + 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index a9835eaa19b..b5b9a008d01 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1467,7 +1467,11 @@ int ModelVolume::extruder_id() const bool ModelVolume::is_splittable() const { - return mesh.stl.stats.number_of_parts > 1; + // the call mesh.is_splittable() is expensive, so cache the value to calculate it only once + if (m_is_splittable == -1) + m_is_splittable = (int)mesh.is_splittable(); + + return m_is_splittable == 1; } void ModelVolume::center_geometry() diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 919e7715c08..8a48f8ee960 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -420,6 +420,12 @@ private: TriangleMesh m_convex_hull; Geometry::Transformation m_transformation; + // flag to optimize the checking if the volume is splittable + // -1 -> is unknown value (before first cheking) + // 0 -> is not splittable + // 1 -> is splittable + mutable int m_is_splittable{ -1 }; + ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(ModelVolumeType::MODEL_PART), object(object) { if (mesh.stl.stats.number_of_facets > 1) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 1baf3cee303..7595688603e 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -338,6 +338,19 @@ void TriangleMesh::rotate(double angle, Point* center) this->translate(c(0), c(1), 0); } +/** + * Calculates whether or not the mesh is splittable. + */ +bool TriangleMesh::is_splittable() const +{ + std::vector visited; + find_unvisited_neighbors(visited); + + // Try finding an unvisited facet. If there are none, the mesh is not splittable. + auto it = std::find(visited.begin(), visited.end(), false); + return it != visited.end(); +} + /** * Visit all unvisited neighboring facets that are reachable from the first unvisited facet, * and return them. diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index e538b76937d..b204a9a3ecf 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -68,6 +68,7 @@ public: size_t facets_count() const { return this->stl.stats.number_of_facets; } bool empty() const { return this->facets_count() == 0; } + bool is_splittable() const; std::deque find_unvisited_neighbors(std::vector &facet_visited) const; stl_file stl; From 0123f90225399049775867c44ebea3e534b44873 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 1 Apr 2019 13:53:48 +0200 Subject: [PATCH 17/38] Fix dragging of mixed instances plus volumes selections --- src/slic3r/GUI/Selection.cpp | 53 ++++++++++++++++++++++++++++++------ src/slic3r/GUI/Selection.hpp | 1 + 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 5d286846b42..34b5f4067b5 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -118,17 +118,17 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection) if (needs_reset) clear(); - if (volume->is_modifier) - m_mode = Volume; - else if (!contains_volume(volume_idx)) - m_mode = Instance; - // else -> keep current mode + if (!contains_volume(volume_idx)) + m_mode = volume->is_modifier ? Volume : Instance; + else + // keep current mode + return; switch (m_mode) { case Volume: { - if (volume->volume_idx() >= 0 && (is_empty() || (volume->instance_idx() == get_instance_idx()))) + if ((volume->volume_idx() >= 0) && (is_empty() || (volume->instance_idx() == get_instance_idx()))) _add_volume(volume_idx); break; @@ -439,6 +439,8 @@ void Selection::translate(const Vec3d& displacement, bool local) if (!m_valid) return; + EMode translation_type = m_mode; + for (unsigned int i : m_list) { if ((m_mode == Volume) || (*m_volumes)[i]->is_wipe_tower) @@ -452,13 +454,22 @@ void Selection::translate(const Vec3d& displacement, bool local) } } else if (m_mode == Instance) - (*m_volumes)[i]->set_instance_offset(m_cache.volumes_data[i].get_instance_position() + displacement); + { + if (_is_from_fully_selected_instance(i)) + (*m_volumes)[i]->set_instance_offset(m_cache.volumes_data[i].get_instance_position() + displacement); + else + { + Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_instance_mirror_matrix()).inverse() * displacement; + (*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + local_displacement); + translation_type = Volume; + } + } } #if !DISABLE_INSTANCES_SYNCH - if (m_mode == Instance) + if (translation_type == Instance) _synchronize_unselected_instances(SYNC_ROTATION_NONE); - else if (m_mode == Volume) + else if (translation_type == Volume) _synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH @@ -1683,5 +1694,29 @@ void Selection::_ensure_on_bed() } } +bool Selection::_is_from_fully_selected_instance(unsigned int volume_idx) const +{ + struct SameInstance + { + int obj_idx; + int inst_idx; + GLVolumePtrs& volumes; + + SameInstance(int obj_idx, int inst_idx, GLVolumePtrs& volumes) : obj_idx(obj_idx), inst_idx(inst_idx), volumes(volumes) {} + bool operator () (unsigned int i) { return (volumes[i]->object_idx() == obj_idx) && (volumes[i]->instance_idx() == inst_idx); } + }; + + if ((unsigned int)m_volumes->size() <= volume_idx) + return false; + + GLVolume* volume = (*m_volumes)[volume_idx]; + int object_idx = volume->object_idx(); + if ((int)m_model->objects.size() <= object_idx) + return false; + + unsigned int count = (unsigned int)std::count_if(m_list.begin(), m_list.end(), SameInstance(object_idx, volume->instance_idx(), *m_volumes)); + return count == (unsigned int)m_model->objects[object_idx]->volumes.size(); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 200f239c1f1..4b2a72d7c04 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -297,6 +297,7 @@ private: void _synchronize_unselected_instances(SyncRotationType sync_rotation_type); void _synchronize_unselected_volumes(); void _ensure_on_bed(); + bool _is_from_fully_selected_instance(unsigned int volume_idx) const; }; } // namespace GUI From 65276e129eba475431bc5d6fd0b7f5886723854e Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 1 Apr 2019 13:59:39 +0200 Subject: [PATCH 18/38] Fixing negative status values in console output --- src/slic3r.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/slic3r.cpp b/src/slic3r.cpp index 5198eeaa322..958b6630590 100644 --- a/src/slic3r.cpp +++ b/src/slic3r.cpp @@ -361,6 +361,14 @@ int CLI::run(int argc, char **argv) std::string outfile = m_config.opt_string("output"); Print fff_print; SLAPrint sla_print; + + sla_print.set_status_callback( + [](const PrintBase::SlicingStatus& s) + { + if(s.percent >= 0) // FIXME: is this sufficient? + printf("%3d%s %s\n", s.percent, "% =>", s.text.c_str()); + }); + PrintBase *print = (printer_technology == ptFFF) ? static_cast(&fff_print) : static_cast(&sla_print); if (! m_config.opt_bool("dont_arrange")) { //FIXME make the min_object_distance configurable. From 98bf41f335cba767b8276198a5171eb4e7abe09f Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 1 Apr 2019 14:12:05 +0200 Subject: [PATCH 19/38] imgui: Refactor font size, font initialization --- src/slic3r/GUI/GLCanvas3D.cpp | 8 +++-- src/slic3r/GUI/GUI_App.cpp | 3 +- src/slic3r/GUI/ImGuiWrapper.cpp | 59 ++++++++++++++++++--------------- src/slic3r/GUI/ImGuiWrapper.hpp | 19 ++++++----- 4 files changed, 48 insertions(+), 41 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4178dcb431e..31c3717ff93 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4403,11 +4403,13 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) if ((m_canvas == nullptr) && (m_context == nullptr)) return; - wxGetApp().imgui()->set_display_size((float)w, (float)h); + auto *imgui = wxGetApp().imgui(); + imgui->set_display_size((float)w, (float)h); + imgui->set_font_size(m_canvas->GetFont().GetPixelSize().y); #if ENABLE_RETINA_GL - wxGetApp().imgui()->set_style_scaling(m_retina_helper->get_scale_factor()); + imgui->set_style_scaling(m_retina_helper->get_scale_factor()); #else - wxGetApp().imgui()->set_style_scaling(m_canvas->GetContentScaleFactor()); + imgui->set_style_scaling(m_canvas->GetContentScaleFactor()); #endif // ensures that this canvas is current diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index fdb8968d331..f1a7d926327 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -81,7 +81,7 @@ IMPLEMENT_APP(GUI_App) GUI_App::GUI_App() : wxApp() , m_em_unit(10) - , m_imgui(nullptr) + , m_imgui(new ImGuiWrapper()) {} bool GUI_App::OnInit() @@ -138,7 +138,6 @@ bool GUI_App::OnInit() // initialize label colors and fonts init_label_colours(); init_fonts(); - m_imgui.reset(new ImGuiWrapper(m_normal_font.GetPixelSize().y)); load_language(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index f626fa7f5ad..001e0b33f72 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -25,9 +25,9 @@ namespace Slic3r { namespace GUI { -ImGuiWrapper::ImGuiWrapper(float font_size) +ImGuiWrapper::ImGuiWrapper() : m_glyph_ranges(nullptr) - , m_font_size(font_size) + , m_font_size(18.0) , m_font_texture(0) , m_style_scaling(1.0) , m_mouse_buttons(0) @@ -36,7 +36,6 @@ ImGuiWrapper::ImGuiWrapper(float font_size) { ImGui::CreateContext(); - init_default_font(); init_input(); init_style(); @@ -45,7 +44,7 @@ ImGuiWrapper::ImGuiWrapper(float font_size) ImGuiWrapper::~ImGuiWrapper() { - destroy_device_objects(); + destroy_font(); ImGui::DestroyContext(); } @@ -82,7 +81,7 @@ void ImGuiWrapper::set_language(const std::string &language) if (ranges != m_glyph_ranges) { m_glyph_ranges = ranges; - init_default_font(); + destroy_font(); } } @@ -93,12 +92,20 @@ void ImGuiWrapper::set_display_size(float w, float h) io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f); } +void ImGuiWrapper::set_font_size(float font_size) +{ + if (m_font_size != font_size) { + m_font_size = font_size; + destroy_font(); + } +} + void ImGuiWrapper::set_style_scaling(float scaling) { if (!std::isnan(scaling) && !std::isinf(scaling) && scaling != m_style_scaling) { ImGui::GetStyle().ScaleAllSizes(scaling / m_style_scaling); m_style_scaling = scaling; - init_default_font(); + destroy_font(); } } @@ -156,12 +163,15 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt) void ImGuiWrapper::new_frame() { + printf("ImGuiWrapper: new_frame()\n"); + if (m_new_frame_open) { return; } - if (m_font_texture == 0) - create_device_objects(); + if (m_font_texture == 0) { + init_font(); + } ImGui::NewFrame(); m_new_frame_open = true; @@ -254,7 +264,8 @@ void ImGuiWrapper::text(const std::string &label) void ImGuiWrapper::text(const wxString &label) { - this->text(into_u8(label).c_str()); + auto label_utf8 = into_u8(label); + this->text(label_utf8.c_str()); } bool ImGuiWrapper::combo(const wxString& label, const std::vector& options, int& selection) @@ -282,6 +293,12 @@ bool ImGuiWrapper::combo(const wxString& label, const std::vector& return res; } +ImVec2 ImGuiWrapper::calc_text_size(const wxString &text) +{ + auto text_utf8 = into_u8(text); + return ImGui::CalcTextSize(text_utf8.c_str()); +} + void ImGuiWrapper::disabled_begin(bool disabled) { wxCHECK_RET(!m_disabled, "ImGUI: Unbalanced disabled_begin() call"); @@ -323,11 +340,13 @@ bool ImGuiWrapper::want_any_input() const return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput; } -void ImGuiWrapper::init_default_font() +void ImGuiWrapper::init_font() { + printf("ImGuiWrapper: init_font()\n"); + const float font_size = m_font_size * m_style_scaling; - destroy_fonts_texture(); + destroy_font(); ImGuiIO& io = ImGui::GetIO(); io.Fonts->Clear(); @@ -338,17 +357,8 @@ void ImGuiWrapper::init_default_font() throw std::runtime_error("ImGui: Could not load deafult font"); } } -} -void ImGuiWrapper::create_device_objects() -{ - create_fonts_texture(); -} - -void ImGuiWrapper::create_fonts_texture() -{ // Build texture atlas - ImGuiIO& io = ImGui::GetIO(); unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. @@ -554,14 +564,9 @@ bool ImGuiWrapper::display_initialized() const return io.DisplaySize.x >= 0.0f && io.DisplaySize.y >= 0.0f; } -void ImGuiWrapper::destroy_device_objects() +void ImGuiWrapper::destroy_font() { - destroy_fonts_texture(); -} - -void ImGuiWrapper::destroy_fonts_texture() -{ - if (m_font_texture) { + if (m_font_texture != 0) { ImGuiIO& io = ImGui::GetIO(); io.Fonts->TexID = 0; glDeleteTextures(1, &m_font_texture); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 7e022532a55..476379da2b5 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -18,9 +18,6 @@ namespace GUI { class ImGuiWrapper { - typedef std::map FontsMap; - - FontsMap m_fonts; const ImWchar *m_glyph_ranges; float m_font_size; unsigned m_font_texture; @@ -31,22 +28,27 @@ class ImGuiWrapper std::string m_clipboard_text; public: - ImGuiWrapper(float font_size); + ImGuiWrapper(); ~ImGuiWrapper(); void read_glsl_version(); void set_language(const std::string &language); void set_display_size(float w, float h); + void set_font_size(float font_size); void set_style_scaling(float scaling); bool update_mouse_data(wxMouseEvent &evt); bool update_key_data(wxKeyEvent &evt); + float get_font_size() const { return m_font_size; } float get_style_scaling() const { return m_style_scaling; } void new_frame(); void render(); + float scaled(float x) const { return x * m_font_size * m_style_scaling; } + ImVec2 scaled_vec(float x, float y) const { return ImVec2(x * m_font_size * m_style_scaling, y * m_font_size * m_style_scaling); } + void set_next_window_pos(float x, float y, int flag); void set_next_window_bg_alpha(float alpha); @@ -64,6 +66,8 @@ public: void text(const wxString &label); bool combo(const wxString& label, const std::vector& options, int& selection); // Use -1 to not mark any option as selected + ImVec2 calc_text_size(const wxString &text); + void disabled_begin(bool disabled); void disabled_end(); @@ -73,15 +77,12 @@ public: bool want_any_input() const; private: - void init_default_font(); - void create_device_objects(); - void create_fonts_texture(); + void init_font(); void init_input(); void init_style(); void render_draw_data(ImDrawData *draw_data); bool display_initialized() const; - void destroy_device_objects(); - void destroy_fonts_texture(); + void destroy_font(); static const char* clipboard_get(void* user_data); static void clipboard_set(void* user_data, const char* text); From 93798b9a5ed25e44a855f1ab8c5700cc1ee7ad2a Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 1 Apr 2019 14:50:40 +0200 Subject: [PATCH 20/38] Some optimizations of "Fix crash on splitting some models #2042" replaced std::vector with std::vector as std::vector is a specialized version optimized for memory, not speed (8 bools are packed into a single boolean). The triangle neighbor traversal was optimized to not push visited or non-neighbors into the queue. --- src/libslic3r/TriangleMesh.cpp | 43 +++++++++++++++++----------------- src/libslic3r/TriangleMesh.hpp | 2 +- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 7595688603e..c145380c963 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -343,7 +343,7 @@ void TriangleMesh::rotate(double angle, Point* center) */ bool TriangleMesh::is_splittable() const { - std::vector visited; + std::vector visited; find_unvisited_neighbors(visited); // Try finding an unvisited facet. If there are none, the mesh is not splittable. @@ -359,36 +359,37 @@ bool TriangleMesh::is_splittable() const * facet with the same index has been visited. * @return A deque with all newly visited facets. */ -std::deque TriangleMesh::find_unvisited_neighbors(std::vector &facet_visited) const +std::deque TriangleMesh::find_unvisited_neighbors(std::vector &facet_visited) const { // Make sure we're not operating on a broken mesh. if (!this->repaired) - throw std::runtime_error("split() requires repair()"); + throw std::runtime_error("find_unvisited_neighbors() requires repair()"); // If the visited list is empty, populate it with false for every facet. - if (facet_visited.empty()) { - facet_visited = std::vector(this->stl.stats.number_of_facets, false); - } + if (facet_visited.empty()) + facet_visited = std::vector(this->stl.stats.number_of_facets, false); // Find the first unvisited facet. - std::queue facet_queue; + std::queue facet_queue; + std::deque facets; auto facet = std::find(facet_visited.begin(), facet_visited.end(), false); - if (facet != facet_visited.end()) - facet_queue.push(facet - facet_visited.begin()); + if (facet != facet_visited.end()) { + uint32_t idx = uint32_t(facet - facet_visited.begin()); + facet_queue.push(idx); + facet_visited[idx] = true; + facets.emplace_back(idx); + } // Traverse all reachable neighbors and mark them as visited. - std::deque facets; - while (!facet_queue.empty()) { - int facet_idx = facet_queue.front(); + while (! facet_queue.empty()) { + uint32_t facet_idx = facet_queue.front(); facet_queue.pop(); - - if (facet_idx != -1 && !facet_visited[facet_idx]) { - facet_visited[facet_idx] = true; - - facets.emplace_back(facet_idx); - for (int facet : this->stl.neighbors_start[facet_idx].neighbor) - facet_queue.push(facet); - } + for (int neighbor_idx : this->stl.neighbors_start[facet_idx].neighbor) + if (neighbor_idx != -1 && ! facet_visited[neighbor_idx]) { + facet_queue.push(uint32_t(neighbor_idx)); + facet_visited[neighbor_idx] = true; + facets.emplace_back(uint32_t(neighbor_idx)); + } } return facets; @@ -402,7 +403,7 @@ std::deque TriangleMesh::find_unvisited_neighbors(std::vector &f TriangleMeshPtrs TriangleMesh::split() const { // Loop while we have remaining facets. - std::vector facet_visited; + std::vector facet_visited; TriangleMeshPtrs meshes; for (;;) { std::deque facets = find_unvisited_neighbors(facet_visited); diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index b204a9a3ecf..a65a4be75bc 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -69,13 +69,13 @@ public: bool empty() const { return this->facets_count() == 0; } bool is_splittable() const; - std::deque find_unvisited_neighbors(std::vector &facet_visited) const; stl_file stl; bool repaired; private: void require_shared_vertices(); + std::deque find_unvisited_neighbors(std::vector &facet_visited) const; friend class TriangleMeshSlicer; }; From cf36acde71e6b72d803c499a65a90c3520cbfcf1 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 1 Apr 2019 10:45:51 +0200 Subject: [PATCH 21/38] SLA gizmo dialog now respects system font settings --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index d83ef9ed837..d094225ac7b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -565,8 +565,7 @@ void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_l RENDER_AGAIN: m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); - const float scaling = m_imgui->get_style_scaling(); - const ImVec2 window_size(285.f * scaling, 300.f * scaling); + const ImVec2 window_size(m_imgui->scaled_vec(15.f, 16.5f)); ImGui::SetNextWindowPos(ImVec2(x, y - std::max(0.f, y+window_size.y-bottom_limit) )); ImGui::SetNextWindowSize(ImVec2(window_size)); From 2312a1f851b5cd9e9ed8cc76b1686ce5307e2061 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 1 Apr 2019 16:10:15 +0200 Subject: [PATCH 22/38] Fix for broken SLA status indication. --- src/libslic3r/SLAPrint.cpp | 40 +++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 4248814914b..c7bacaa31b0 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -46,13 +46,13 @@ const std::array OBJ_STEP_LEVELS = 30, // slaposSupportPoints, 25, // slaposSupportTree, 25, // slaposBasePool, - 10, // slaposSliceSupports, + 10, // slaposSliceSupports, }; const std::array OBJ_STEP_LABELS = { L("Slicing model"), // slaposObjectSlice, - L("Generating support points"), // slaposSupportPoints, + L("Generating support points"), // slaposSupportPoints, L("Generating support tree"), // slaposSupportTree, L("Generating pad"), // slaposBasePool, L("Slicing supports"), // slaposSliceSupports, @@ -61,7 +61,7 @@ const std::array OBJ_STEP_LABELS = // Should also add up to 100 (%) const std::array PRINT_STEP_LEVELS = { - 5, // slapsStats + 5, // slapsMergeSlicesAndEval 95, // slapsRasterize }; @@ -645,7 +645,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[slapsMergeSlicesAndEval]; // where the per object operations end + const unsigned max_objstatus = 50; // 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 @@ -802,13 +802,13 @@ void SLAPrint::process() init = int(init * ostepd); // scale the init portion // scaling for the sub operations - double d = *stthis / (objcount * 100.0); + double d = *stthis / 100.0; - ctl.statuscb = [this, init, d](unsigned st, const std::string& msg) + ctl.statuscb = [this, init, d, ostepd](unsigned st, const std::string& /*msg*/) { //FIXME this status line scaling does not seem to be correct. // How does it account for an increasing object index? - report_status(*this, int(init + st*d), msg); + report_status(*this, int(init + st*d*ostepd), OBJ_STEP_LABELS[slaposSupportTree]); }; ctl.stopcondition = [this](){ return canceled(); }; @@ -1252,18 +1252,29 @@ void SLAPrint::process() auto lvlcnt = unsigned(m_printer_input.size()); printer.layers(lvlcnt); - // slot is the portion of 100% that is realted to rasterization - unsigned slot = PRINT_STEP_LEVELS[slapsRasterize]; - // ist: initial state; pst: previous state - unsigned ist = max_objstatus, pst = ist; // coefficient to map the rasterization state (0-99) to the allocated // portion (slot) of the process state - double sd = (100 - ist) / 100.0; + double sd = (100 - max_objstatus) / 100.0; + + // slot is the portion of 100% that is realted to rasterization + unsigned slot = PRINT_STEP_LEVELS[slapsRasterize]; + + // ist: initial state; pst: previous state + unsigned ist = std::accumulate(PRINT_STEP_LEVELS.begin(), + PRINT_STEP_LEVELS.begin()+slapsRasterize, + 0u); + + ist = max_objstatus + unsigned(ist * sd); + unsigned pst = ist; + + double increment = (slot * sd) / m_printer_input.size(); + double dstatus = double(ist); + SpinMutex slck; // procedure to process one height level. This will run in parallel auto lvlfn = - [this, &slck, &printer, slot, sd, ist, &pst] + [this, &slck, &printer, increment, &dstatus, &pst] (unsigned level_id) { if(canceled()) return; @@ -1280,9 +1291,10 @@ void SLAPrint::process() printer.finish_layer(level_id); // Status indication guarded with the spinlock - auto st = ist + unsigned(sd*level_id*slot/m_printer_input.size()); { std::lock_guard lck(slck); + dstatus += increment; + auto st = unsigned(dstatus); if( st > pst) { report_status(*this, int(st), PRINT_STEP_LABELS[slapsRasterize]); From 3975473f4a46c77f36738fa811f18775ea4d78f8 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 1 Apr 2019 17:12:39 +0200 Subject: [PATCH 23/38] Improvement in handling of the custom bridging angle value. In case the bridge is only supported at one side, it is technically not considered to be a support, therefore the default infill angle is used. With this change, the bridging areas use the custom angle value even if not supported on both sides. --- src/libslic3r/LayerRegion.cpp | 9 +++++++-- src/libslic3r/Rasterizer/Rasterizer.hpp | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 913ba76a6d4..19fbb3bb6e0 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -258,13 +258,18 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) #ifdef SLIC3R_DEBUG printf("Processing bridge at layer " PRINTF_ZU ":\n", this->layer()->id()); #endif - if (bd.detect_angle(Geometry::deg2rad(this->region()->config().bridge_angle.value))) { + double custom_angle = Geometry::deg2rad(this->region()->config().bridge_angle.value); + if (bd.detect_angle(custom_angle)) { bridges[idx_last].bridge_angle = bd.angle; if (this->layer()->object()->config().support_material) { polygons_append(this->bridged, bd.coverage()); this->unsupported_bridge_edges.append(bd.unsupported_edges()); } - } + } else if (custom_angle > 0) { + // Bridge was not detected (likely it is only supported at one side). Still it is a surface filled in + // using a bridging flow, therefore it makes sense to respect the custom bridging direction. + bridges[idx_last].bridge_angle = custom_angle; + } // without safety offset, artifacts are generated (GH #2494) surfaces_append(bottom, union_ex(grown, true), bridges[idx_last]); } diff --git a/src/libslic3r/Rasterizer/Rasterizer.hpp b/src/libslic3r/Rasterizer/Rasterizer.hpp index a8c8e186646..671dcbb3d93 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.hpp +++ b/src/libslic3r/Rasterizer/Rasterizer.hpp @@ -6,7 +6,7 @@ #include #include -namespace ClipperLib { class Polygon; } +namespace ClipperLib { struct Polygon; } namespace Slic3r { From dd659784983d4acf63fb6fbe21c1255f550eb76f Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 2 Apr 2019 09:36:16 +0200 Subject: [PATCH 24/38] SLA gizmo uses CallAfter to trigger SLA supports calculation to prevent recursive rendering calls --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index d094225ac7b..c5d0f28edbc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -816,7 +816,7 @@ void GLGizmoSlaSupports::editing_mode_apply_changes() // Recalculate support structures once the editing mode is left. // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); - wxGetApp().plater()->reslice_SLA_supports(*m_model_object); + wxGetApp().CallAfter([this]() { wxGetApp().plater()->reslice_SLA_supports(*m_model_object); }); } m_editing_mode = false; m_unsaved_changes = false; @@ -869,7 +869,7 @@ void GLGizmoSlaSupports::auto_generate() m_model_object->sla_support_points.clear(); m_model_object->sla_points_status = sla::PointsStatus::Generating; m_editing_mode_cache.clear(); - wxGetApp().plater()->reslice_SLA_supports(*m_model_object); + wxGetApp().CallAfter([this]() { wxGetApp().plater()->reslice_SLA_supports(*m_model_object); }); } } From 4ffa47ee8787dd3811b001aedb33f59f0fe1350b Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Wed, 27 Mar 2019 16:49:44 +0100 Subject: [PATCH 25/38] Firmware updater: Support for CW1 --- src/slic3r/GUI/FirmwareDialog.cpp | 109 ++++++++++++++++++++---------- src/slic3r/Utils/HexFile.cpp | 1 + src/slic3r/Utils/HexFile.hpp | 1 + 3 files changed, 76 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/FirmwareDialog.cpp b/src/slic3r/GUI/FirmwareDialog.cpp index 1a294d2107a..5da81839569 100644 --- a/src/slic3r/GUI/FirmwareDialog.cpp +++ b/src/slic3r/GUI/FirmwareDialog.cpp @@ -59,6 +59,8 @@ enum { USB_PID_MK3 = 2, USB_PID_MMU_BOOT = 3, USB_PID_MMU_APP = 4, + USB_PID_CW1_BOOT = 7, + USB_PID_CW1_APP = 8, }; // This enum discriminates the kind of information in EVT_AVRDUDE, @@ -77,6 +79,13 @@ wxDEFINE_EVENT(EVT_AVRDUDE, wxCommandEvent); wxDECLARE_EVENT(EVT_ASYNC_DIALOG, wxCommandEvent); wxDEFINE_EVENT(EVT_ASYNC_DIALOG, wxCommandEvent); +struct Avr109Pid +{ + unsigned boot; + unsigned app; + + Avr109Pid(unsigned boot, unsigned app) : boot(boot), app(app) {} +}; // Private @@ -151,19 +160,21 @@ struct FirmwareDialog::priv bool ask_model_id_mismatch(const std::string &printer_model); bool check_model_id(); - void wait_for_mmu_bootloader(unsigned retries); - void mmu_reboot(const SerialPortInfo &port); - void lookup_port_mmu(); + void avr109_wait_for_bootloader(Avr109Pid usb_pid, unsigned retries); + void avr109_reboot(const SerialPortInfo &port); + void avr109_lookup_port(Avr109Pid usb_pid); void prepare_common(); void prepare_mk2(); void prepare_mk3(); - void prepare_mm_control(); + void prepare_avr109(Avr109Pid usb_pid); void perform_upload(); void user_cancel(); void on_avrdude(const wxCommandEvent &evt); void on_async_dialog(const wxCommandEvent &evt); void ensure_joined(); + + static const char* avr109_dev_name(Avr109Pid usb_pid); }; void FirmwareDialog::priv::find_serial_ports() @@ -259,7 +270,8 @@ void FirmwareDialog::priv::enable_port_picker(bool enable) void FirmwareDialog::priv::load_hex_file(const wxString &path) { hex_file = HexFile(path.wx_str()); - enable_port_picker(hex_file.device != HexFile::DEV_MM_CONTROL); + const bool auto_lookup = hex_file.device == HexFile::DEV_MM_CONTROL || hex_file.device == HexFile::DEV_CW1; + enable_port_picker(! auto_lookup); } void FirmwareDialog::priv::queue_status(wxString message) @@ -356,7 +368,7 @@ bool FirmwareDialog::priv::check_model_id() // return false; } -void FirmwareDialog::priv::wait_for_mmu_bootloader(unsigned retries) +void FirmwareDialog::priv::avr109_wait_for_bootloader(Avr109Pid usb_pid, unsigned retries) { enum { SLEEP_MS = 500, @@ -367,61 +379,67 @@ void FirmwareDialog::priv::wait_for_mmu_bootloader(unsigned retries) auto ports = Utils::scan_serial_ports_extended(); ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) { - return port.id_vendor != USB_VID_PRUSA || port.id_product != USB_PID_MMU_BOOT; + return port.id_vendor != USB_VID_PRUSA || port.id_product != usb_pid.boot; }), ports.end()); if (ports.size() == 1) { port = ports[0]; return; } else if (ports.size() > 1) { - BOOST_LOG_TRIVIAL(error) << "Several VID/PID 0x2c99/3 devices found"; - queue_error(_(L("Multiple Original Prusa i3 MMU 2.0 devices found. Please only connect one at a time for flashing."))); + BOOST_LOG_TRIVIAL(error) << boost::format("Several VID/PID 0x2c99/%1% devices found") % usb_pid.boot; + queue_error(wxString::Format( + _(L("Multiple %s devices found. Please only connect one at a time for flashing.")), avr109_dev_name(usb_pid))); return; } } } -void FirmwareDialog::priv::mmu_reboot(const SerialPortInfo &port) +void FirmwareDialog::priv::avr109_reboot(const SerialPortInfo &port) { asio::io_service io; Serial serial(io, port.port, 1200); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } -void FirmwareDialog::priv::lookup_port_mmu() +void FirmwareDialog::priv::avr109_lookup_port(Avr109Pid usb_pid) { - static const auto msg_not_found = - "The Multi Material Control device was not found.\n" - "If the device is connected, please press the Reset button next to the USB connector ..."; + const char *dev_name = avr109_dev_name(usb_pid); + const wxString msg_not_found = wxString::Format( + _(L("The %s device was not found.\n" + "If the device is connected, please press the Reset button next to the USB connector ...")), + dev_name); - BOOST_LOG_TRIVIAL(info) << "Flashing MMU 2.0, looking for VID/PID 0x2c99/3 or 0x2c99/4 ..."; + BOOST_LOG_TRIVIAL(info) << boost::format("Flashing %1%, looking for VID/PID 0x2c99/%2% or 0x2c99/%3% ...") + % dev_name + % usb_pid.boot + % usb_pid.app; auto ports = Utils::scan_serial_ports_extended(); ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) { return port.id_vendor != USB_VID_PRUSA || - port.id_product != USB_PID_MMU_BOOT && - port.id_product != USB_PID_MMU_APP; + port.id_product != usb_pid.boot && + port.id_product != usb_pid.app; }), ports.end()); if (ports.size() == 0) { - BOOST_LOG_TRIVIAL(info) << "MMU 2.0 device not found, asking the user to press Reset and waiting for the device to show up ..."; - queue_status(_(L(msg_not_found))); - wait_for_mmu_bootloader(30); + BOOST_LOG_TRIVIAL(info) << "Device not found, asking the user to press Reset and waiting for the device to show up ..."; + queue_status(msg_not_found); + avr109_wait_for_bootloader(usb_pid, 30); } else if (ports.size() > 1) { - BOOST_LOG_TRIVIAL(error) << "Several VID/PID 0x2c99/3 devices found"; - queue_error(_(L("Multiple Original Prusa i3 MMU 2.0 devices found. Please only connect one at a time for flashing."))); + BOOST_LOG_TRIVIAL(error) << boost::format("Several VID/PID 0x2c99/%1% devices found") % usb_pid.boot; + queue_error(wxString::Format(_(L("Multiple %s devices found. Please only connect one at a time for flashing.")), dev_name)); } else { - if (ports[0].id_product == USB_PID_MMU_APP) { + if (ports[0].id_product == usb_pid.app) { // The device needs to be rebooted into the bootloader mode - BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/4 at `%1%`, rebooting the device ...") % ports[0].port; - mmu_reboot(ports[0]); - wait_for_mmu_bootloader(10); + BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/%1% at `%2%`, rebooting the device ...") % usb_pid.app % ports[0].port; + avr109_reboot(ports[0]); + avr109_wait_for_bootloader(usb_pid, 10); if (! port) { // The device in bootloader mode was not found, inform the user and wait some more... - BOOST_LOG_TRIVIAL(info) << "MMU 2.0 bootloader device not found after reboot, asking the user to press Reset and waiting for the device to show up ..."; - queue_status(_(L(msg_not_found))); - wait_for_mmu_bootloader(30); + BOOST_LOG_TRIVIAL(info) << boost::format("%1% device not found after reboot, asking the user to press Reset and waiting for the device to show up ...") % dev_name; + queue_status(msg_not_found); + avr109_wait_for_bootloader(usb_pid, 30); } } else { port = ports[0]; @@ -498,16 +516,16 @@ void FirmwareDialog::priv::prepare_mk3() avrdude->push_args(std::move(args)); } -void FirmwareDialog::priv::prepare_mm_control() +void FirmwareDialog::priv::prepare_avr109(Avr109Pid usb_pid) { port = boost::none; - lookup_port_mmu(); + avr109_lookup_port(usb_pid); if (! port) { - queue_error(_(L("The device could not have been found"))); + queue_error(wxString::Format(_(L("The %s device could not have been found")), avr109_dev_name(usb_pid))); return; } - BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/3 at `%1%`, flashing ...") % port->port; + BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/%1% at `%2%`, flashing ...") % usb_pid.boot % port->port; queue_status(label_status_flashing); std::vector args {{ @@ -568,7 +586,11 @@ void FirmwareDialog::priv::perform_upload() break; case HexFile::DEV_MM_CONTROL: - this->prepare_mm_control(); + this->prepare_avr109(Avr109Pid(USB_PID_MMU_BOOT, USB_PID_MMU_APP)); + break; + + case HexFile::DEV_CW1: + this->prepare_avr109(Avr109Pid(USB_PID_CW1_BOOT, USB_PID_CW1_APP)); break; default: @@ -576,7 +598,11 @@ void FirmwareDialog::priv::perform_upload() break; } } catch (const std::exception &ex) { - queue_error(wxString::Format(_(L("Error accessing port at %s: %s")), port->port, ex.what())); + if (port) { + queue_error(wxString::Format(_(L("Error accessing port at %s: %s")), port->port, ex.what())); + } else { + queue_error(wxString::Format(_(L("Error: %s")), ex.what())); + } } }) .on_message(std::move([q, extra_verbose](const char *msg, unsigned /* size */) { @@ -688,6 +714,19 @@ void FirmwareDialog::priv::ensure_joined() avrdude.reset(); } +const char* FirmwareDialog::priv::avr109_dev_name(Avr109Pid usb_pid) { + switch (usb_pid.boot) { + case USB_PID_MMU_BOOT: + return "Prusa MMU 2.0 Control"; + break; + case USB_PID_CW1_BOOT: + return "Prusa CurWa"; + break; + + default: throw std::runtime_error((boost::format("Invalid avr109 device USB PID: %1%") % usb_pid.boot).str()); + } +} + // Public diff --git a/src/slic3r/Utils/HexFile.cpp b/src/slic3r/Utils/HexFile.cpp index 9e080332593..26596f629ec 100644 --- a/src/slic3r/Utils/HexFile.cpp +++ b/src/slic3r/Utils/HexFile.cpp @@ -18,6 +18,7 @@ static HexFile::DeviceKind parse_device_kind(const std::string &str) if (str == "mk2") { return HexFile::DEV_MK2; } else if (str == "mk3") { return HexFile::DEV_MK3; } else if (str == "mm-control") { return HexFile::DEV_MM_CONTROL; } + else if (str == "cw1") { return HexFile::DEV_CW1; } else { return HexFile::DEV_GENERIC; } } diff --git a/src/slic3r/Utils/HexFile.hpp b/src/slic3r/Utils/HexFile.hpp index 1201d23a465..742ae00e6a0 100644 --- a/src/slic3r/Utils/HexFile.hpp +++ b/src/slic3r/Utils/HexFile.hpp @@ -16,6 +16,7 @@ struct HexFile DEV_MK2, DEV_MK3, DEV_MM_CONTROL, + DEV_CW1, }; boost::filesystem::path path; From ae2da7d7e464b89ddd2f0dcd6893e6e07ef64761 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 29 Mar 2019 16:01:47 +0100 Subject: [PATCH 26/38] Firmware updater: Improve logging --- src/slic3r/GUI/FirmwareDialog.cpp | 61 ++++++++++++++++--------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/slic3r/GUI/FirmwareDialog.cpp b/src/slic3r/GUI/FirmwareDialog.cpp index 5da81839569..8095a3237c5 100644 --- a/src/slic3r/GUI/FirmwareDialog.cpp +++ b/src/slic3r/GUI/FirmwareDialog.cpp @@ -155,8 +155,7 @@ struct FirmwareDialog::priv void flashing_done(AvrDudeComplete complete); void enable_port_picker(bool enable); void load_hex_file(const wxString &path); - void queue_status(wxString message); - void queue_error(const wxString &message); + void queue_event(AvrdudeEvent aevt, wxString message); bool ask_model_id_mismatch(const std::string &printer_model); bool check_model_id(); @@ -174,6 +173,21 @@ struct FirmwareDialog::priv void on_async_dialog(const wxCommandEvent &evt); void ensure_joined(); + void queue_status(wxString message) { queue_event(AE_STATUS, std::move(message)); } + + template void queue_message(const wxString &format, Args... args) { + auto message = wxString::Format(format, args...); + BOOST_LOG_TRIVIAL(info) << message; + message.Append('\n'); + queue_event(AE_MESSAGE, std::move(message)); + } + + template void queue_error(const wxString &format, Args... args) { + queue_message(format, args...); + queue_event(AE_STATUS, _(L("Flashing failed: ")) + wxString::Format(format, args...)); + avrdude->cancel(); + } + static const char* avr109_dev_name(Avr109Pid usb_pid); }; @@ -274,23 +288,14 @@ void FirmwareDialog::priv::load_hex_file(const wxString &path) enable_port_picker(! auto_lookup); } -void FirmwareDialog::priv::queue_status(wxString message) +void FirmwareDialog::priv::queue_event(AvrdudeEvent aevt, wxString message) { auto evt = new wxCommandEvent(EVT_AVRDUDE, this->q->GetId()); - evt->SetExtraLong(AE_STATUS); + evt->SetExtraLong(aevt); evt->SetString(std::move(message)); wxQueueEvent(this->q, evt); } -void FirmwareDialog::priv::queue_error(const wxString &message) -{ - auto evt = new wxCommandEvent(EVT_AVRDUDE, this->q->GetId()); - evt->SetExtraLong(AE_STATUS); - evt->SetString(wxString::Format(_(L("Flashing failed: %s")), message)); - - wxQueueEvent(this->q, evt); avrdude->cancel(); -} - bool FirmwareDialog::priv::ask_model_id_mismatch(const std::string &printer_model) { // model_id in the hex file doesn't match what the printer repoted. @@ -386,9 +391,8 @@ void FirmwareDialog::priv::avr109_wait_for_bootloader(Avr109Pid usb_pid, unsigne port = ports[0]; return; } else if (ports.size() > 1) { - BOOST_LOG_TRIVIAL(error) << boost::format("Several VID/PID 0x2c99/%1% devices found") % usb_pid.boot; - queue_error(wxString::Format( - _(L("Multiple %s devices found. Please only connect one at a time for flashing.")), avr109_dev_name(usb_pid))); + queue_message("Several VID/PID 0x2c99/%u devices found", usb_pid.boot); + queue_error(_(L("Multiple %s devices found. Please only connect one at a time for flashing.")), avr109_dev_name(usb_pid)); return; } } @@ -409,10 +413,7 @@ void FirmwareDialog::priv::avr109_lookup_port(Avr109Pid usb_pid) "If the device is connected, please press the Reset button next to the USB connector ...")), dev_name); - BOOST_LOG_TRIVIAL(info) << boost::format("Flashing %1%, looking for VID/PID 0x2c99/%2% or 0x2c99/%3% ...") - % dev_name - % usb_pid.boot - % usb_pid.app; + queue_message("Flashing %s, looking for VID/PID 0x2c99/%u or 0x2c99/%u ...", dev_name, usb_pid.boot, usb_pid.app); auto ports = Utils::scan_serial_ports_extended(); ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) { @@ -422,22 +423,22 @@ void FirmwareDialog::priv::avr109_lookup_port(Avr109Pid usb_pid) }), ports.end()); if (ports.size() == 0) { - BOOST_LOG_TRIVIAL(info) << "Device not found, asking the user to press Reset and waiting for the device to show up ..."; + queue_message("The %s device was not found.", dev_name); queue_status(msg_not_found); avr109_wait_for_bootloader(usb_pid, 30); } else if (ports.size() > 1) { - BOOST_LOG_TRIVIAL(error) << boost::format("Several VID/PID 0x2c99/%1% devices found") % usb_pid.boot; - queue_error(wxString::Format(_(L("Multiple %s devices found. Please only connect one at a time for flashing.")), dev_name)); + queue_message("Several VID/PID 0x2c99/%u devices found", usb_pid.boot); + queue_error(_(L("Multiple %s devices found. Please only connect one at a time for flashing.")), dev_name); } else { if (ports[0].id_product == usb_pid.app) { // The device needs to be rebooted into the bootloader mode - BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/%1% at `%2%`, rebooting the device ...") % usb_pid.app % ports[0].port; + queue_message("Found VID/PID 0x2c99/%u at `%s`, rebooting the device ...", usb_pid.app, ports[0].port); avr109_reboot(ports[0]); avr109_wait_for_bootloader(usb_pid, 10); if (! port) { // The device in bootloader mode was not found, inform the user and wait some more... - BOOST_LOG_TRIVIAL(info) << boost::format("%1% device not found after reboot, asking the user to press Reset and waiting for the device to show up ...") % dev_name; + queue_message("%s device not found after reboot", dev_name); queue_status(msg_not_found); avr109_wait_for_bootloader(usb_pid, 30); } @@ -521,11 +522,11 @@ void FirmwareDialog::priv::prepare_avr109(Avr109Pid usb_pid) port = boost::none; avr109_lookup_port(usb_pid); if (! port) { - queue_error(wxString::Format(_(L("The %s device could not have been found")), avr109_dev_name(usb_pid))); + queue_error(_(L("The %s device could not have been found")), avr109_dev_name(usb_pid)); return; } - BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/%1% at `%2%`, flashing ...") % usb_pid.boot % port->port; + queue_message("Found VID/PID 0x2c99/%u at `%s`, flashing ...", usb_pid.boot, port->port); queue_status(label_status_flashing); std::vector args {{ @@ -599,9 +600,9 @@ void FirmwareDialog::priv::perform_upload() } } catch (const std::exception &ex) { if (port) { - queue_error(wxString::Format(_(L("Error accessing port at %s: %s")), port->port, ex.what())); + queue_error(_(L("Error accessing port at %s: %s")), port->port, ex.what()); } else { - queue_error(wxString::Format(_(L("Error: %s")), ex.what())); + queue_error(_(L("Error: %s")), ex.what()); } } }) @@ -796,7 +797,7 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : vsizer->Add(grid, 0, wxEXPAND | wxTOP | wxBOTTOM, SPACING); - p->spoiler = new wxCollapsiblePane(panel, wxID_ANY, _(L("Advanced: avrdude output log")), wxDefaultPosition, wxDefaultSize, wxCP_DEFAULT_STYLE | wxCP_NO_TLW_RESIZE); + p->spoiler = new wxCollapsiblePane(panel, wxID_ANY, _(L("Advanced: Output log")), wxDefaultPosition, wxDefaultSize, wxCP_DEFAULT_STYLE | wxCP_NO_TLW_RESIZE); auto *spoiler_pane = p->spoiler->GetPane(); auto *spoiler_sizer = new wxBoxSizer(wxVERTICAL); p->txt_stdout = new wxTextCtrl(spoiler_pane, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY); From e7f991d27b9386e0e531b6ffefaebc22d89ac3a9 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 1 Apr 2019 15:36:48 +0200 Subject: [PATCH 27/38] imgui: More refactoring, cut gizmo window positioning --- src/slic3r/GUI/GLCanvas3D.cpp | 6 ++--- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 3 +++ src/slic3r/GUI/ImGuiWrapper.cpp | 37 +++++++++++----------------- src/slic3r/GUI/ImGuiWrapper.hpp | 8 +++--- 4 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 31c3717ff93..e6365e32ade 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4405,12 +4405,12 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) auto *imgui = wxGetApp().imgui(); imgui->set_display_size((float)w, (float)h); - imgui->set_font_size(m_canvas->GetFont().GetPixelSize().y); #if ENABLE_RETINA_GL - imgui->set_style_scaling(m_retina_helper->get_scale_factor()); + const float scaling = m_retina_helper->get_scale_factor(); #else - imgui->set_style_scaling(m_canvas->GetContentScaleFactor()); + const float scaling = m_canvas->GetContentScaleFactor(); #endif + imgui->set_scaling(m_canvas->GetFont().GetPixelSize().y, scaling); // ensures that this canvas is current _set_current(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 56609050404..02d663e93b9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -185,7 +185,10 @@ void GLGizmoCut::on_render_for_picking(const Selection& selection) const void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection) { + const float approx_height = m_imgui->scaled(11.0f); + y = std::min(y, bottom_limit - approx_height); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); + m_imgui->set_next_window_bg_alpha(0.5f); m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 001e0b33f72..b008c17a742 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -92,21 +92,18 @@ void ImGuiWrapper::set_display_size(float w, float h) io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f); } -void ImGuiWrapper::set_font_size(float font_size) +void ImGuiWrapper::set_scaling(float font_size, float scaling) { - if (m_font_size != font_size) { - m_font_size = font_size; - destroy_font(); + if (m_font_size == font_size && m_style_scaling == scaling) { + return; } -} -void ImGuiWrapper::set_style_scaling(float scaling) -{ - if (!std::isnan(scaling) && !std::isinf(scaling) && scaling != m_style_scaling) { - ImGui::GetStyle().ScaleAllSizes(scaling / m_style_scaling); - m_style_scaling = scaling; - destroy_font(); - } + m_font_size = font_size; + + ImGui::GetStyle().ScaleAllSizes(scaling / m_style_scaling); + m_style_scaling = scaling; + + destroy_font(); } bool ImGuiWrapper::update_mouse_data(wxMouseEvent& evt) @@ -163,8 +160,6 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt) void ImGuiWrapper::new_frame() { - printf("ImGuiWrapper: new_frame()\n"); - if (m_new_frame_open) { return; } @@ -184,6 +179,12 @@ void ImGuiWrapper::render() m_new_frame_open = false; } +ImVec2 ImGuiWrapper::calc_text_size(const wxString &text) +{ + auto text_utf8 = into_u8(text); + return ImGui::CalcTextSize(text_utf8.c_str()); +} + void ImGuiWrapper::set_next_window_pos(float x, float y, int flag) { ImGui::SetNextWindowPos(ImVec2(x, y), (ImGuiCond)flag); @@ -293,12 +294,6 @@ bool ImGuiWrapper::combo(const wxString& label, const std::vector& return res; } -ImVec2 ImGuiWrapper::calc_text_size(const wxString &text) -{ - auto text_utf8 = into_u8(text); - return ImGui::CalcTextSize(text_utf8.c_str()); -} - void ImGuiWrapper::disabled_begin(bool disabled) { wxCHECK_RET(!m_disabled, "ImGUI: Unbalanced disabled_begin() call"); @@ -342,8 +337,6 @@ bool ImGuiWrapper::want_any_input() const void ImGuiWrapper::init_font() { - printf("ImGuiWrapper: init_font()\n"); - const float font_size = m_font_size * m_style_scaling; destroy_font(); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 476379da2b5..84a60e3d190 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -35,8 +35,7 @@ public: void set_language(const std::string &language); void set_display_size(float w, float h); - void set_font_size(float font_size); - void set_style_scaling(float scaling); + void set_scaling(float font_size, float scaling); bool update_mouse_data(wxMouseEvent &evt); bool update_key_data(wxKeyEvent &evt); @@ -47,7 +46,8 @@ public: void render(); float scaled(float x) const { return x * m_font_size * m_style_scaling; } - ImVec2 scaled_vec(float x, float y) const { return ImVec2(x * m_font_size * m_style_scaling, y * m_font_size * m_style_scaling); } + ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size * m_style_scaling, y * m_font_size * m_style_scaling); } + ImVec2 calc_text_size(const wxString &text); void set_next_window_pos(float x, float y, int flag); void set_next_window_bg_alpha(float alpha); @@ -66,8 +66,6 @@ public: void text(const wxString &label); bool combo(const wxString& label, const std::vector& options, int& selection); // Use -1 to not mark any option as selected - ImVec2 calc_text_size(const wxString &text); - void disabled_begin(bool disabled); void disabled_end(); From becf41f9626b58760d2f962150d979aac3dc2144 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 2 Apr 2019 10:54:14 +0200 Subject: [PATCH 28/38] Rethought sla status indication. --- src/libslic3r/SLA/SLAAutoSupports.cpp | 10 ++- src/libslic3r/SLA/SLAAutoSupports.hpp | 7 +- src/libslic3r/SLAPrint.cpp | 109 ++++++++++++++------------ src/libslic3r/SLAPrint.hpp | 9 +++ 4 files changed, 78 insertions(+), 57 deletions(-) diff --git a/src/libslic3r/SLA/SLAAutoSupports.cpp b/src/libslic3r/SLA/SLAAutoSupports.cpp index 9e9f07b6cbe..0a2537b919b 100644 --- a/src/libslic3r/SLA/SLAAutoSupports.cpp +++ b/src/libslic3r/SLA/SLAAutoSupports.cpp @@ -49,8 +49,8 @@ float SLAAutoSupports::distance_limit(float angle) const }*/ SLAAutoSupports::SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector& slices, const std::vector& heights, - const Config& config, std::function throw_on_cancel) -: m_config(config), m_emesh(emesh), m_throw_on_cancel(throw_on_cancel) + const Config& config, std::function throw_on_cancel, std::function statusfn) +: m_config(config), m_emesh(emesh), m_throw_on_cancel(throw_on_cancel), m_statusfn(statusfn) { process(slices, heights); project_onto_mesh(m_output); @@ -197,6 +197,9 @@ void SLAAutoSupports::process(const std::vector& slices, const std:: PointGrid3D point_grid; point_grid.cell_size = Vec3f(10.f, 10.f, 10.f); + double increment = 100.0 / layers.size(); + double status = 0; + for (unsigned int layer_id = 0; layer_id < layers.size(); ++ layer_id) { SLAAutoSupports::MyLayer *layer_top = &layers[layer_id]; SLAAutoSupports::MyLayer *layer_bottom = (layer_id > 0) ? &layers[layer_id - 1] : nullptr; @@ -252,6 +255,9 @@ void SLAAutoSupports::process(const std::vector& slices, const std:: m_throw_on_cancel(); + status += increment; + m_statusfn(int(std::round(status))); + #ifdef SLA_AUTOSUPPORTS_DEBUG /*std::string layer_num_str = std::string((i<10 ? "0" : "")) + std::string((i<100 ? "0" : "")) + std::to_string(i); output_expolygons(expolys_top, "top" + layer_num_str + ".svg"); diff --git a/src/libslic3r/SLA/SLAAutoSupports.hpp b/src/libslic3r/SLA/SLAAutoSupports.hpp index 038b505dac8..d32d182bc80 100644 --- a/src/libslic3r/SLA/SLAAutoSupports.hpp +++ b/src/libslic3r/SLA/SLAAutoSupports.hpp @@ -24,7 +24,7 @@ public: }; SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector& slices, - const std::vector& heights, const Config& config, std::function throw_on_cancel); + const std::vector& heights, const Config& config, std::function throw_on_cancel, std::function statusfn); const std::vector& output() { return m_output; } struct MyLayer; @@ -196,12 +196,13 @@ private: static void output_structures(const std::vector &structures); #endif // SLA_AUTOSUPPORTS_DEBUG - std::function m_throw_on_cancel; const sla::EigenMesh3D& m_emesh; + std::function m_throw_on_cancel; + std::function m_statusfn; }; } // namespace Slic3r -#endif // SLAAUTOSUPPORTS_HPP_ \ No newline at end of file +#endif // SLAAUTOSUPPORTS_HPP_ diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index c7bacaa31b0..454fbe78b59 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -619,14 +619,6 @@ bool SLAPrint::invalidate_step(SLAPrintStep step) return invalidated; } -template -void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) -{ - BOOST_LOG_TRIVIAL(info) << st << "% " << msg; - p.set_status(st, msg, std::forward(args)...); -} - - void SLAPrint::process() { using namespace sla; @@ -720,7 +712,7 @@ void SLAPrint::process() // In this step we check the slices, identify island and cover them with // support points. Then we sprinkle the rest of the mesh. - auto support_points = [this](SLAPrintObject& po) { + auto support_points = [this, ostepd](SLAPrintObject& po) { const ModelObject& mo = *po.m_model_object; po.m_supportdata.reset( new SLAPrintObject::SupportData(po.transformed_mesh()) ); @@ -754,6 +746,19 @@ void SLAPrint::process() config.minimal_distance = float(cfg.support_points_minimal_distance); config.head_diameter = float(cfg.support_head_front_diameter); + // scaling for the sub operations + double d = ostepd * OBJ_STEP_LEVELS[slaposSupportPoints] / 100.0; + double init = m_report_status.status(); + + auto statuscb = [this, d, init](unsigned st) + { + double current = init + st * d; + if(std::round(m_report_status.status()) < std::round(current)) + m_report_status(*this, current, + OBJ_STEP_LABELS[slaposSupportPoints]); + + }; + // Construction of this object does the calculation. this->throw_if_canceled(); SLAAutoSupports auto_supports(po.transformed_mesh(), @@ -761,7 +766,8 @@ void SLAPrint::process() po.get_model_slices(), heights, config, - [this]() { throw_if_canceled(); }); + [this]() { throw_if_canceled(); }, + statuscb); // Now let's extract the result. const std::vector& points = auto_supports.output(); @@ -772,7 +778,7 @@ void SLAPrint::process() << po.m_supportdata->support_points.size(); // Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass the update status to GLGizmoSlaSupports - report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS); + m_report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS); } else { // There are either some points on the front-end, or the user removed them on purpose. No calculation will be done. @@ -781,7 +787,8 @@ void SLAPrint::process() }; // In this step we create the supports - auto support_tree = [this, objcount, ostepd](SLAPrintObject& po) { + auto support_tree = [this, ostepd](SLAPrintObject& po) + { if(!po.m_supportdata) return; if(!po.m_config.supports_enable.getBool()) { @@ -793,22 +800,17 @@ void SLAPrint::process() sla::SupportConfig scfg = make_support_cfg(po.m_config); sla::Controller ctl; - // some magic to scale the status values coming from the support - // tree creation into the whole print process - auto stfirst = OBJ_STEP_LEVELS.begin(); - auto stthis = stfirst + slaposSupportTree; - // we need to add up the status portions until this operation - int init = std::accumulate(stfirst, stthis, 0); - init = int(init * ostepd); // scale the init portion - // scaling for the sub operations - double d = *stthis / 100.0; + double d = ostepd * OBJ_STEP_LEVELS[slaposSupportTree] / 100.0; + double init = m_report_status.status(); - ctl.statuscb = [this, init, d, ostepd](unsigned st, const std::string& /*msg*/) + ctl.statuscb = [this, d, init](unsigned st, const std::string&) { - //FIXME this status line scaling does not seem to be correct. - // How does it account for an increasing object index? - report_status(*this, int(init + st*d*ostepd), OBJ_STEP_LABELS[slaposSupportTree]); + double current = init + st * d; + if(std::round(m_report_status.status()) < std::round(current)) + m_report_status(*this, current, + OBJ_STEP_LABELS[slaposSupportTree]); + }; ctl.stopcondition = [this](){ return canceled(); }; @@ -824,7 +826,7 @@ void SLAPrint::process() auto rc = SlicingStatus::RELOAD_SCENE; // This is to prevent "Done." being displayed during merged_mesh() - report_status(*this, -1, L("Visualizing supports")); + m_report_status(*this, -1, L("Visualizing supports")); po.m_supportdata->support_tree_ptr->merged_mesh(); BOOST_LOG_TRIVIAL(debug) << "Processed support point count " @@ -834,8 +836,7 @@ void SLAPrint::process() if(po.support_mesh().empty()) BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty"; - report_status(*this, -1, L("Visualizing supports"), rc); - + m_report_status(*this, -1, L("Visualizing supports"), rc); }; // This step generates the sla base pad @@ -883,7 +884,7 @@ void SLAPrint::process() po.throw_if_canceled(); auto rc = SlicingStatus::RELOAD_SCENE; - report_status(*this, -1, L("Visualizing supports"), rc); + m_report_status(*this, -1, L("Visualizing supports"), rc); }; // Slicing the support geometries similarly to the model slicing procedure. @@ -914,7 +915,7 @@ void SLAPrint::process() } // 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); + m_report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); }; // Merging the slices from all the print objects into one slice grid and @@ -1213,7 +1214,7 @@ void SLAPrint::process() m_print_statistics.fast_layers_count = fast_layers; m_print_statistics.slow_layers_count = slow_layers; - report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); + m_report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); }; // Rasterizing the model objects, and their supports @@ -1259,16 +1260,11 @@ void SLAPrint::process() // slot is the portion of 100% that is realted to rasterization unsigned slot = PRINT_STEP_LEVELS[slapsRasterize]; - // ist: initial state; pst: previous state - unsigned ist = std::accumulate(PRINT_STEP_LEVELS.begin(), - PRINT_STEP_LEVELS.begin()+slapsRasterize, - 0u); - - ist = max_objstatus + unsigned(ist * sd); - unsigned pst = ist; + // pst: previous state + double pst = m_report_status.status(); double increment = (slot * sd) / m_printer_input.size(); - double dstatus = double(ist); + double dstatus = m_report_status.status(); SpinMutex slck; @@ -1294,10 +1290,10 @@ void SLAPrint::process() { std::lock_guard lck(slck); dstatus += increment; - auto st = unsigned(dstatus); - if( st > pst) { - report_status(*this, int(st), - PRINT_STEP_LABELS[slapsRasterize]); + double st = std::round(dstatus); + if(st > pst) { + m_report_status(*this, st, + PRINT_STEP_LABELS[slapsRasterize]); pst = st; } } @@ -1338,7 +1334,7 @@ void SLAPrint::process() rasterize }; - unsigned st = min_objstatus; + double st = min_objstatus; unsigned incr = 0; BOOST_LOG_TRIVIAL(info) << "Start slicing process."; @@ -1352,18 +1348,18 @@ void SLAPrint::process() BOOST_LOG_TRIVIAL(info) << "Slicing object " << po->model_object()->name; - for (int s = (int)step_ranges[idx_range]; s < (int)step_ranges[idx_range + 1]; ++s) { - auto currentstep = (SLAPrintObjectStep)s; + for (int s = int(step_ranges[idx_range]); s < int(step_ranges[idx_range + 1]); ++s) { + auto currentstep = static_cast(s); // Cancellation checking. Each step will check for cancellation // on its own and return earlier gracefully. Just after it returns // execution gets to this point and throws the canceled signal. throw_if_canceled(); - st += unsigned(incr * ostepd); + st += incr * ostepd; if(po->m_stepmask[currentstep] && po->set_started(currentstep)) { - report_status(*this, int(st), OBJ_STEP_LABELS[currentstep]); + m_report_status(*this, st, OBJ_STEP_LABELS[currentstep]); pobj_program[currentstep](*po); throw_if_canceled(); po->set_done(currentstep); @@ -1390,17 +1386,17 @@ void SLAPrint::process() if(m_stepmask[currentstep] && set_started(currentstep)) { - report_status(*this, int(st), PRINT_STEP_LABELS[currentstep]); + m_report_status(*this, st, PRINT_STEP_LABELS[currentstep]); print_program[currentstep](); throw_if_canceled(); set_done(currentstep); } - st += unsigned(PRINT_STEP_LEVELS[currentstep] * pstd); + st += PRINT_STEP_LEVELS[currentstep] * pstd; } // If everything vent well - report_status(*this, 100, L("Slicing done")); + m_report_status(*this, 100, L("Slicing done")); } bool SLAPrint::invalidate_state_by_config_options(const std::vector &opt_keys) @@ -1724,7 +1720,8 @@ DynamicConfig SLAPrintStatistics::placeholders() "print_time", "total_cost", "total_weight", "objects_used_material", "support_used_material" }) config.set_key_value(key, new ConfigOptionString(std::string("{") + key + "}")); - return config; + + return config; } std::string SLAPrintStatistics::finalize_output_path(const std::string &path_in) const @@ -1744,4 +1741,12 @@ std::string SLAPrintStatistics::finalize_output_path(const std::string &path_in) return final_path; } +void SLAPrint::StatusReporter::operator()( + SLAPrint &p, double st, const std::string &msg, unsigned flags) +{ + m_st = st; + BOOST_LOG_TRIVIAL(info) << st << "% " << msg; + p.set_status(int(std::round(st)), msg, flags); +} + } // namespace Slic3r diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 9cf826097ef..54128e3bf54 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -471,6 +471,15 @@ private: // Estimated print time, material consumed. SLAPrintStatistics m_print_statistics; + class StatusReporter { + double m_st = 0; + public: + void operator() (SLAPrint& p, double st, const std::string& msg, + unsigned flags = SlicingStatus::DEFAULT); + double status() const { return m_st; } + } m_report_status; + + friend SLAPrintObject; }; From f70df9e73e720d340fd42ed2408531073771b92f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 2 Apr 2019 10:55:36 +0200 Subject: [PATCH 29/38] Follow-up of d4b22cfb87f8b6bc9c8c7ec34158be2e852450e8 -> Fixed dragging of sla instances after slicing --- src/slic3r/GUI/Selection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 34b5f4067b5..7103ca12dc6 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1703,7 +1703,7 @@ bool Selection::_is_from_fully_selected_instance(unsigned int volume_idx) const GLVolumePtrs& volumes; SameInstance(int obj_idx, int inst_idx, GLVolumePtrs& volumes) : obj_idx(obj_idx), inst_idx(inst_idx), volumes(volumes) {} - bool operator () (unsigned int i) { return (volumes[i]->object_idx() == obj_idx) && (volumes[i]->instance_idx() == inst_idx); } + bool operator () (unsigned int i) { return (volumes[i]->volume_idx() >= 0) && (volumes[i]->object_idx() == obj_idx) && (volumes[i]->instance_idx() == inst_idx); } }; if ((unsigned int)m_volumes->size() <= volume_idx) From 0d6e57ed0d889ebad6efdc546e7da1f19ce02cfd Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 2 Apr 2019 10:56:08 +0200 Subject: [PATCH 30/38] Fix build --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index c5d0f28edbc..75f13cdcf0f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -565,7 +565,7 @@ void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_l RENDER_AGAIN: m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); - const ImVec2 window_size(m_imgui->scaled_vec(15.f, 16.5f)); + const ImVec2 window_size(m_imgui->scaled(15.f, 16.5f)); ImGui::SetNextWindowPos(ImVec2(x, y - std::max(0.f, y+window_size.y-bottom_limit) )); ImGui::SetNextWindowSize(ImVec2(window_size)); From 0afd7e43d27d310566abd5f18396225e2f230681 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 2 Apr 2019 11:19:52 +0200 Subject: [PATCH 31/38] More accurate status proportions for SLA steps. --- src/libslic3r/SLAPrint.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 454fbe78b59..0304363f60e 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -42,11 +42,11 @@ namespace { // should add up to 100 (%) const std::array OBJ_STEP_LEVELS = { - 10, // slaposObjectSlice, - 30, // slaposSupportPoints, - 25, // slaposSupportTree, - 25, // slaposBasePool, - 10, // slaposSliceSupports, + 30, // slaposObjectSlice, + 20, // slaposSupportPoints, + 10, // slaposSupportTree, + 10, // slaposBasePool, + 30, // slaposSliceSupports, }; const std::array OBJ_STEP_LABELS = @@ -61,8 +61,8 @@ const std::array OBJ_STEP_LABELS = // Should also add up to 100 (%) const std::array PRINT_STEP_LEVELS = { - 5, // slapsMergeSlicesAndEval - 95, // slapsRasterize + 10, // slapsMergeSlicesAndEval + 90, // slapsRasterize }; const std::array PRINT_STEP_LABELS = From 99f020757829d3a43acac371e21a6ddb9b5beef1 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 2 Apr 2019 13:47:49 +0200 Subject: [PATCH 32/38] Handling of left hand oriented coordinate systems: is_left_handed() method on transformations and volumes rendering of GLVolumes in left handed coordinate systems by glFrontFace(GL_CW); SLA slicing on left hand oriented instances by flipping the mesh for SLAPrintObject in X. rendering of the SLA cutting plane in left handed systems resetting the SLA clipping planes on 3D preview invalidation --- src/libslic3r/Geometry.hpp | 1 + src/libslic3r/Model.hpp | 1 + src/libslic3r/SLAPrint.cpp | 7 ++- src/libslic3r/SLAPrint.hpp | 7 ++- src/slic3r/GUI/3DScene.cpp | 23 ++++++++++ src/slic3r/GUI/3DScene.hpp | 1 + src/slic3r/GUI/GLCanvas3D.cpp | 81 +++++++++++++--------------------- src/slic3r/GUI/GLCanvas3D.hpp | 1 + src/slic3r/GUI/GUI_Preview.cpp | 13 ++++-- src/slic3r/GUI/GUI_Preview.hpp | 5 ++- src/slic3r/GUI/Plater.cpp | 2 +- 11 files changed, 80 insertions(+), 62 deletions(-) diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 380245b5fcf..d556f664c88 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -246,6 +246,7 @@ public: const Vec3d& get_mirror() const { return m_mirror; } double get_mirror(Axis axis) const { return m_mirror(axis); } + bool is_left_handed() const { return m_mirror.x() * m_mirror.y() * m_mirror.z() < 0.; } void set_mirror(const Vec3d& mirror); void set_mirror(Axis axis, double mirror); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 8a48f8ee960..3d476cbb072 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -394,6 +394,7 @@ public: const Vec3d& get_mirror() const { return m_transformation.get_mirror(); } double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); } + bool is_left_handed() const { return m_transformation.is_left_handed(); } void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); } void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index c7bacaa31b0..04778f58424 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -93,7 +93,10 @@ static Transform3d sla_trafo(const ModelObject &model_object) offset(0) = 0.; offset(1) = 0.; rotation(2) = 0.; - return Geometry::assemble_transform(offset, rotation, model_instance.get_scaling_factor(), model_instance.get_mirror()); + Transform3d trafo = Geometry::assemble_transform(offset, rotation, model_instance.get_scaling_factor(), model_instance.get_mirror()); + if (model_instance.is_left_handed()) + trafo = Eigen::Scaling(Vec3d(-1., 1., 1.)) * trafo; + return trafo; } // List of instances, where the ModelInstance transformation is a composite of sla_trafo and the transformation defined by SLAPrintObject::Instance. @@ -399,7 +402,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf // FIXME: this invalidates the transformed mesh in SLAPrintObject // which is expensive to calculate (especially the raw_mesh() call) - print_object->set_trafo(sla_trafo(model_object)); + print_object->set_trafo(sla_trafo(model_object), model_object.instances.front()->is_left_handed()); print_object->set_instances(new_instances); print_object->config_apply(config, true); diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 9cf826097ef..272252a2af5 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -51,6 +51,7 @@ public: const SLAPrintObjectConfig& config() const { return m_config; } const Transform3d& trafo() const { return m_trafo; } + bool is_left_handed() const { return m_left_handed; } struct Instance { Instance(ModelID instance_id, const Point &shift, float rotation) : instance_id(instance_id), shift(shift), rotation(rotation) {} @@ -241,8 +242,8 @@ protected: void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); } - void set_trafo(const Transform3d& trafo) { - m_transformed_rmesh.invalidate([this, &trafo](){ m_trafo = trafo; }); + void set_trafo(const Transform3d& trafo, bool left_handed) { + m_transformed_rmesh.invalidate([this, &trafo, left_handed](){ m_trafo = trafo; m_left_handed = left_handed; }); } void set_instances(const std::vector &instances) { m_instances = instances; } @@ -262,6 +263,8 @@ private: // Translation in Z + Rotation by Y and Z + Scaling / Mirroring. Transform3d m_trafo = Transform3d::Identity(); + // m_trafo is left handed -> 3x3 affine transformation has negative determinant. + bool m_left_handed = false; std::vector m_instances; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 58011730b60..7ba61bdb697 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -333,6 +333,13 @@ Transform3d GLVolume::world_matrix() const return m; } +bool GLVolume::is_left_handed() const +{ + const Vec3d &m1 = m_instance_transformation.get_mirror(); + const Vec3d &m2 = m_volume_transformation.get_mirror(); + return m1.x() * m1.y() * m1.z() * m2.x() * m2.y() * m2.z() < 0.; +} + const BoundingBoxf3& GLVolume::transformed_bounding_box() const { assert(bounding_box.defined || bounding_box.min(0) >= bounding_box.max(0) || bounding_box.min(1) >= bounding_box.max(1) || bounding_box.min(2) >= bounding_box.max(2)); @@ -401,6 +408,8 @@ void GLVolume::render() const if (!is_active) return; + if (this->is_left_handed()) + glFrontFace(GL_CW); glsafe(::glCullFace(GL_BACK)); glsafe(::glPushMatrix()); @@ -410,6 +419,8 @@ void GLVolume::render() const else this->indexed_vertex_array.render(); glsafe(::glPopMatrix()); + if (this->is_left_handed()) + glFrontFace(GL_CCW); } void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) const @@ -420,6 +431,9 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c if (!indexed_vertex_array.vertices_and_normals_interleaved_VBO_id) return; + if (this->is_left_handed()) + glFrontFace(GL_CW); + GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first)); GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first)); if (n_triangles + n_quads == 0) @@ -481,6 +495,9 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c } glsafe(::glPopMatrix()); + + if (this->is_left_handed()) + glFrontFace(GL_CCW); } void GLVolume::render_legacy() const @@ -489,6 +506,9 @@ void GLVolume::render_legacy() const if (!is_active) return; + if (this->is_left_handed()) + glFrontFace(GL_CW); + GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first)); GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first)); if (n_triangles + n_quads == 0) @@ -520,6 +540,9 @@ void GLVolume::render_legacy() const glsafe(::glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, indexed_vertex_array.quad_indices.data() + qverts_range.first)); glsafe(::glPopMatrix()); + + if (this->is_left_handed()) + glFrontFace(GL_CCW); } std::vector GLVolumeCollection::load_object( diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index e421997e5de..5cc301a3934 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -388,6 +388,7 @@ public: int instance_idx() const { return this->composite_id.instance_id; } Transform3d world_matrix() const; + bool is_left_handed() const; const BoundingBoxf3& transformed_bounding_box() const; const BoundingBoxf3& transformed_convex_hull_bounding_box() const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 31c3717ff93..862ce74b7c5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5010,24 +5010,12 @@ void GLCanvas3D::_render_sla_slices() const Pointf3s &top_obj_triangles = it_caps_top->second.object; Pointf3s &top_sup_triangles = it_caps_top->second.supports; - const std::vector& instances = obj->instances(); - struct InstanceTransform - { - Vec3d offset; - float rotation; - }; - - std::vector instance_transforms; - for (const SLAPrintObject::Instance& inst : instances) - { - instance_transforms.push_back({ to_3d(unscale(inst.shift), 0.), Geometry::rad2deg(inst.rotation) }); - } - if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.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; + bool left_handed = obj->is_left_handed(); coord_t key_zero = obj->get_slice_index().front().print_level(); // Slice at the center of the slab starting at clip_min_z will be rendered for the lower plane. @@ -5046,10 +5034,10 @@ void GLCanvas3D::_render_sla_slices() const const ExPolygons& sup_bottom = slice_low.get_slice(soSupport); // calculate model bottom cap if (bottom_obj_triangles.empty() && !obj_bottom.empty()) - bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, true); + bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, ! left_handed); // calculate support bottom cap if (bottom_sup_triangles.empty() && !sup_bottom.empty()) - bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, true); + bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, ! left_handed); } if (slice_high.is_valid()) { @@ -5057,49 +5045,35 @@ void GLCanvas3D::_render_sla_slices() const const ExPolygons& sup_top = slice_high.get_slice(soSupport); // calculate model top cap if (top_obj_triangles.empty() && !obj_top.empty()) - top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, false); + top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, left_handed); // calculate support top cap if (top_sup_triangles.empty() && !sup_top.empty()) - top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, false); + top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, left_handed); } } if (!bottom_obj_triangles.empty() || !top_obj_triangles.empty() || !bottom_sup_triangles.empty() || !top_sup_triangles.empty()) { - for (const InstanceTransform& inst : instance_transforms) + for (const SLAPrintObject::Instance& inst : obj->instances()) { ::glPushMatrix(); - ::glTranslated(inst.offset(0), inst.offset(1), inst.offset(2)); - ::glRotatef(inst.rotation, 0.0, 0.0, 1.0); - - ::glBegin(GL_TRIANGLES); - + ::glTranslated(unscale(inst.shift.x()), unscale(inst.shift.y()), 0); + ::glRotatef(Geometry::rad2deg(inst.rotation), 0.0, 0.0, 1.0); + if (obj->is_left_handed()) + // The polygons are mirrored by X. + ::glScalef(-1.0, 1.0, 1.0); ::glColor3f(1.0f, 0.37f, 0.0f); - - for (const Vec3d& v : bottom_obj_triangles) - { - ::glVertex3dv((GLdouble*)v.data()); - } - - for (const Vec3d& v : top_obj_triangles) - { - ::glVertex3dv((GLdouble*)v.data()); - } - - ::glColor3f(1.0f, 0.0f, 0.37f); - - for (const Vec3d& v : bottom_sup_triangles) - { - ::glVertex3dv((GLdouble*)v.data()); - } - - for (const Vec3d& v : top_sup_triangles) - { - ::glVertex3dv((GLdouble*)v.data()); - } - - ::glEnd(); - + ::glEnableClientState(GL_VERTEX_ARRAY); + ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_obj_triangles.front().data()); + ::glDrawArrays(GL_TRIANGLES, 0, bottom_obj_triangles.size()); + ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_obj_triangles.front().data()); + ::glDrawArrays(GL_TRIANGLES, 0, top_obj_triangles.size()); + ::glColor3f(1.0f, 0.0f, 0.37f); + ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_sup_triangles.front().data()); + ::glDrawArrays(GL_TRIANGLES, 0, bottom_sup_triangles.size()); + ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_sup_triangles.front().data()); + ::glDrawArrays(GL_TRIANGLES, 0, top_sup_triangles.size()); + ::glDisableClientState(GL_VERTEX_ARRAY); ::glPopMatrix(); } } @@ -6217,6 +6191,8 @@ void GLCanvas3D::_load_shells_fff() void GLCanvas3D::_load_shells_sla() { + //FIXME use reload_scene +#if 1 const SLAPrint* print = this->sla_print(); if (print->objects().empty()) // nothing to render, return @@ -6240,9 +6216,7 @@ void GLCanvas3D::_load_shells_sla() m_volumes.load_object(model_obj, obj_idx, instance_idxs, "object", m_use_VBOs && m_initialized); - const std::vector& instances = obj->instances(); - - for (const SLAPrintObject::Instance& instance : instances) + for (const SLAPrintObject::Instance& instance : obj->instances()) { Vec3d offset = unscale(instance.shift(0), instance.shift(1), 0); Vec3d rotation(0.0, 0.0, (double)instance.rotation); @@ -6265,6 +6239,7 @@ void GLCanvas3D::_load_shells_sla() v.composite_id.volume_id = -1; v.set_instance_offset(offset); v.set_instance_rotation(rotation); + v.set_instance_mirror(X, obj->is_left_handed() ? -1. : 1.); } // add pad @@ -6283,6 +6258,7 @@ void GLCanvas3D::_load_shells_sla() v.composite_id.volume_id = -1; v.set_instance_offset(offset); v.set_instance_rotation(rotation); + v.set_instance_mirror(X, obj->is_left_handed() ? -1. : 1.); } // finalize volumes and sends geometry to gpu @@ -6305,6 +6281,9 @@ void GLCanvas3D::_load_shells_sla() } update_volumes_colors_by_extruder(); +#else + this->reload_scene(true, true); +#endif } void GLCanvas3D::_update_gcode_volumes_visibility(const GCodePreviewData& preview_data) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 2b1061c95fd..7e414d52a8b 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -634,6 +634,7 @@ public: m_sla_caps[id].reset(); } } + void reset_clipping_planes_cache() { m_sla_caps[0].triangles.clear(); m_sla_caps[1].triangles.clear(); } void set_use_clipping_planes(bool use) { m_use_clipping_planes = use; } void set_color_by(const std::string& value); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 14d19e25147..438e9d236ac 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -27,7 +27,7 @@ namespace Slic3r { namespace GUI { - View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) +View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) : m_canvas_widget(nullptr) , m_canvas(nullptr) { @@ -155,7 +155,9 @@ void View3D::render() m_canvas->set_as_dirty(); } -Preview::Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function schedule_background_process_func) +Preview::Preview( + wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, + BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function schedule_background_process_func) : m_canvas_widget(nullptr) , m_canvas(nullptr) , m_double_slider_sizer(nullptr) @@ -179,14 +181,14 @@ Preview::Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_t , m_volumes_cleanup_required(false) #endif // __linux__ { - if (init(parent, bed, camera, view_toolbar)) + if (init(parent, bed, camera, view_toolbar, model)) { show_hide_ui_elements("none"); load_print(); } } -bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar) +bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model) { if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */)) return false; @@ -196,6 +198,7 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view m_canvas = _3DScene::get_canvas(this->m_canvas_widget); m_canvas->allow_multisample(GLCanvas3DManager::can_multisample()); m_canvas->set_config(m_config); + m_canvas->set_model(model); m_canvas->set_process(m_process); m_canvas->enable_legend_texture(true); m_canvas->enable_dynamic_background(true); @@ -781,6 +784,8 @@ void Preview::load_print_as_sla() } sort_remove_duplicates(zs); + m_canvas->reset_clipping_planes_cache(); + n_layers = (unsigned int)zs.size(); if (n_layers == 0) { diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 96c49e54ffa..a2929f2e6fd 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -102,7 +102,8 @@ class Preview : public wxPanel PrusaDoubleSlider* m_slider {nullptr}; public: - Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function schedule_background_process = [](){}); + Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, + BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function schedule_background_process = [](){}); virtual ~Preview(); wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } @@ -120,7 +121,7 @@ public: void refresh_print(); private: - bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar); + bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model); void bind_event_handlers(); void unbind_event_handlers(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c92c22c50c5..435d9548f8d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1350,7 +1350,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->q->Bind(EVT_SLICING_UPDATE, &priv::on_slicing_update, this); view3D = new View3D(q, bed, camera, view_toolbar, &model, config, &background_process); - preview = new Preview(q, bed, camera, view_toolbar, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); }); + preview = new Preview(q, bed, camera, view_toolbar, &model, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); }); panels.push_back(view3D); panels.push_back(preview); From f6087171b919c3882a95dba6fbe2c1f220469026 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 2 Apr 2019 13:54:23 +0200 Subject: [PATCH 33/38] Fix of the previous commmit. --- src/libslic3r/Model.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 3d476cbb072..5cf7f49cadb 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -499,6 +499,7 @@ public: const Vec3d& get_mirror() const { return m_transformation.get_mirror(); } double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); } + bool is_left_handed() const { return m_transformation.is_left_handed(); } void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); } void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); } From 53ccd309c90dbfaf151652e156f7cbd5086a18db Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 2 Apr 2019 10:25:47 +0200 Subject: [PATCH 34/38] Fixed conflicts after cherry-picking 5c89135 --- src/slic3r/GUI/GLCanvas3D.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index eb934ba7d1e..1ae4d642f55 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6207,16 +6207,25 @@ void GLCanvas3D::_load_shells_sla() unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); + // selects only instances which were sliced const ModelObject* model_obj = obj->model_object(); - std::vector instance_idxs(model_obj->instances.size()); - for (int i = 0; i < (int)model_obj->instances.size(); ++i) + const std::vector& sla_instances = obj->instances(); + std::vector instances_model_idxs(sla_instances.size()); + for (int i = 0; i < (int)sla_instances.size(); ++i) { - instance_idxs[i] = i; + instances_model_idxs[i] = (int)sla_instances[i].instance_id.id; } - m_volumes.load_object(model_obj, obj_idx, instance_idxs, "object", m_use_VBOs && m_initialized); + std::vector sliced_instance_idxs; + for (int i = 0; i < (int)model_obj->instances.size(); ++i) + { + if (std::find(instances_model_idxs.begin(), instances_model_idxs.end(), (int)model_obj->instances[i]->id().id) != instances_model_idxs.end()) + sliced_instance_idxs.push_back(i); + } - for (const SLAPrintObject::Instance& instance : obj->instances()) + m_volumes.load_object(model_obj, obj_idx, sliced_instance_idxs, "object", m_use_VBOs && m_initialized); + + for (const SLAPrintObject::Instance& instance : sla_instances) { Vec3d offset = unscale(instance.shift(0), instance.shift(1), 0); Vec3d rotation(0.0, 0.0, (double)instance.rotation); From 5cd1012dab913471cef39b122de4d86f6e325503 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 2 Apr 2019 12:13:45 +0200 Subject: [PATCH 35/38] Fixed rendering of sla cap slices after deleting object --- src/slic3r/GUI/GLCanvas3D.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1ae4d642f55..ca3f6261b5e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4987,6 +4987,9 @@ void GLCanvas3D::_render_sla_slices() const { const SLAPrintObject* obj = print_objects[i]; + if (!obj->is_step_done(slaposSliceSupports)) + continue; + SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i); SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i); { @@ -5011,7 +5014,7 @@ void GLCanvas3D::_render_sla_slices() const Pointf3s &top_sup_triangles = it_caps_top->second.supports; if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && - obj->is_step_done(slaposSliceSupports) && !obj->get_slice_index().empty()) + !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; From 79440f42a7621efbe07da7067f70869e76d9014a Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 2 Apr 2019 13:26:22 +0200 Subject: [PATCH 36/38] imgui: Fix font size and scaling on Windows --- src/slic3r/GUI/GLCanvas3D.cpp | 6 +++--- src/slic3r/GUI/ImGuiWrapper.cpp | 11 +++++++---- src/slic3r/GUI/ImGuiWrapper.hpp | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index ca3f6261b5e..a600f9ce1ea 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4405,12 +4405,12 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) auto *imgui = wxGetApp().imgui(); imgui->set_display_size((float)w, (float)h); + const float font_size = 1.5f * wxGetApp().em_unit(); #if ENABLE_RETINA_GL - const float scaling = m_retina_helper->get_scale_factor(); + imgui->set_scaling(font_size, 1.0f, m_retina_helper->get_scale_factor()); #else - const float scaling = m_canvas->GetContentScaleFactor(); + imgui->set_scaling(font_size, m_canvas->GetContentScaleFactor(), 1.0f); #endif - imgui->set_scaling(m_canvas->GetFont().GetPixelSize().y, scaling); // ensures that this canvas is current _set_current(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index b008c17a742..1b4d4edf9e2 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -92,16 +92,19 @@ void ImGuiWrapper::set_display_size(float w, float h) io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f); } -void ImGuiWrapper::set_scaling(float font_size, float scaling) +void ImGuiWrapper::set_scaling(float font_size, float scale_style, float scale_both) { - if (m_font_size == font_size && m_style_scaling == scaling) { + font_size *= scale_both; + scale_style *= scale_both; + + if (m_font_size == font_size && m_style_scaling == scale_style) { return; } m_font_size = font_size; - ImGui::GetStyle().ScaleAllSizes(scaling / m_style_scaling); - m_style_scaling = scaling; + ImGui::GetStyle().ScaleAllSizes(scale_style / m_style_scaling); + m_style_scaling = scale_style; destroy_font(); } diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 84a60e3d190..c1bf491e140 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -35,7 +35,7 @@ public: void set_language(const std::string &language); void set_display_size(float w, float h); - void set_scaling(float font_size, float scaling); + void set_scaling(float font_size, float scale_style, float scale_both); bool update_mouse_data(wxMouseEvent &evt); bool update_key_data(wxKeyEvent &evt); From 88f6aaf692025ae6103cede01376d5bc9cdaeb98 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 2 Apr 2019 17:48:50 +0200 Subject: [PATCH 37/38] Add mirror correction to rasterized polygons. --- src/libslic3r/SLAPrint.cpp | 24 ++++++++++++++++++------ src/libslic3r/SLAPrint.hpp | 3 ++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 4663fe447c1..81d01958d0e 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -105,10 +105,10 @@ static std::vector sla_instances(const ModelObject &mo std::vector instances; for (ModelInstance *model_instance : model_object.instances) if (model_instance->is_printable()) { - instances.emplace_back(SLAPrintObject::Instance( + instances.emplace_back( model_instance->id(), Point::new_scale(model_instance->get_offset(X), model_instance->get_offset(Y)), - float(model_instance->get_rotation(Z)))); + float(model_instance->get_rotation(Z))); } return instances; } @@ -404,7 +404,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf // which is expensive to calculate (especially the raw_mesh() call) print_object->set_trafo(sla_trafo(model_object), model_object.instances.front()->is_left_handed()); - print_object->set_instances(new_instances); + print_object->set_instances(std::move(new_instances)); print_object->config_apply(config, true); print_objects_new.emplace_back(print_object); new_objects = true; @@ -1025,7 +1025,8 @@ void SLAPrint::process() // get polygons for all instances in the object auto get_all_polygons = [flpXY](const ExPolygons& input_polygons, - const std::vector& instances) + const std::vector& instances, + bool is_lefthanded) { ClipperPolygons polygons; polygons.reserve(input_polygons.size() * instances.size()); @@ -1055,9 +1056,19 @@ void SLAPrint::process() auto pfirst = hole.front(); hole.emplace_back(pfirst); } + if(is_lefthanded) { + for(auto& p : poly.Contour) p.X = -p.X; + std::reverse(poly.Contour.begin(), poly.Contour.end()); + for(auto& h : poly.Holes) { + for(auto& p : h) p.X = -p.X; + std::reverse(h.begin(), h.end()); + } + } + sl::rotate(poly, 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()); @@ -1129,14 +1140,15 @@ void SLAPrint::process() const SLAPrintObject *po = record.print_obj(); const ExPolygons &modelslices = record.get_slice(soModel); + bool is_lefth = record.print_obj()->is_left_handed(); if (!modelslices.empty()) { - ClipperPolygons v = get_all_polygons(modelslices, po->instances()); + ClipperPolygons v = get_all_polygons(modelslices, po->instances(), is_lefth); 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()); + ClipperPolygons v = get_all_polygons(supportslices, po->instances(), is_lefth); for(ClipperPolygon& p_tmp : v) supports_polygons.emplace_back(std::move(p_tmp)); } } diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index c0ab616b060..a1e382acbcf 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -246,7 +246,8 @@ protected: m_transformed_rmesh.invalidate([this, &trafo, left_handed](){ m_trafo = trafo; m_left_handed = left_handed; }); } - void set_instances(const std::vector &instances) { m_instances = instances; } + template inline void set_instances(InstVec&& instances) { m_instances = std::forward(instances); } + // Invalidates the step, and its depending steps in SLAPrintObject and SLAPrint. bool invalidate_step(SLAPrintObjectStep step); bool invalidate_all_steps(); From c86433271e5c302a01a68c3dc5b82e204206d8db Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 2 Apr 2019 18:04:23 +0200 Subject: [PATCH 38/38] Fixed update of the SLAPrint back end after mirroring in a specific case of mirroring around the X axis. Fixed some asserts on visual studio due to access to empty std::vector --- src/libslic3r/SLAPrint.cpp | 9 ++++++--- src/slic3r/GUI/GLCanvas3D.cpp | 26 +++++++++++++++++--------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 81d01958d0e..7dc920517bb 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -94,7 +94,7 @@ static Transform3d sla_trafo(const ModelObject &model_object) offset(1) = 0.; rotation(2) = 0.; Transform3d trafo = Geometry::assemble_transform(offset, rotation, model_instance.get_scaling_factor(), model_instance.get_mirror()); - if (model_instance.is_left_handed()) + if (model_instance.is_left_handed()) trafo = Eigen::Scaling(Vec3d(-1., 1., 1.)) * trafo; return trafo; } @@ -317,8 +317,11 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf it_print_object_status = print_object_status.end(); // Check whether a model part volume was added or removed, their transformations or order changed. bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART); - bool sla_trafo_differs = model_object.instances.empty() != model_object_new.instances.empty() || - (! model_object.instances.empty() && ! sla_trafo(model_object).isApprox(sla_trafo(model_object_new))); + bool sla_trafo_differs = + model_object.instances.empty() != model_object_new.instances.empty() || + (! model_object.instances.empty() && + (! sla_trafo(model_object).isApprox(sla_trafo(model_object_new)) || + model_object.instances.front()->is_left_handed() != model_object_new.instances.front()->is_left_handed())); if (model_parts_differ || sla_trafo_differs) { // The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects. if (it_print_object_status != print_object_status.end()) { diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a600f9ce1ea..79a3684ef54 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5065,17 +5065,25 @@ void GLCanvas3D::_render_sla_slices() const if (obj->is_left_handed()) // The polygons are mirrored by X. ::glScalef(-1.0, 1.0, 1.0); - ::glColor3f(1.0f, 0.37f, 0.0f); ::glEnableClientState(GL_VERTEX_ARRAY); - ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_obj_triangles.front().data()); - ::glDrawArrays(GL_TRIANGLES, 0, bottom_obj_triangles.size()); - ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_obj_triangles.front().data()); - ::glDrawArrays(GL_TRIANGLES, 0, top_obj_triangles.size()); + ::glColor3f(1.0f, 0.37f, 0.0f); + if (!bottom_obj_triangles.empty()) { + ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_obj_triangles.front().data()); + ::glDrawArrays(GL_TRIANGLES, 0, bottom_obj_triangles.size()); + } + if (! top_obj_triangles.empty()) { + ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_obj_triangles.front().data()); + ::glDrawArrays(GL_TRIANGLES, 0, top_obj_triangles.size()); + } ::glColor3f(1.0f, 0.0f, 0.37f); - ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_sup_triangles.front().data()); - ::glDrawArrays(GL_TRIANGLES, 0, bottom_sup_triangles.size()); - ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_sup_triangles.front().data()); - ::glDrawArrays(GL_TRIANGLES, 0, top_sup_triangles.size()); + if (! bottom_sup_triangles.empty()) { + ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_sup_triangles.front().data()); + ::glDrawArrays(GL_TRIANGLES, 0, bottom_sup_triangles.size()); + } + if (! top_sup_triangles.empty()) { + ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_sup_triangles.front().data()); + ::glDrawArrays(GL_TRIANGLES, 0, top_sup_triangles.size()); + } ::glDisableClientState(GL_VERTEX_ARRAY); ::glPopMatrix(); }