From 95b0467c850f801d7de0e391f93d618843c93eb4 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 df9446cf5..003ed5af4 100644 --- a/src/libslic3r/PrintExport.hpp +++ b/src/libslic3r/PrintExport.hpp @@ -43,7 +43,7 @@ class FilePrinter { public: // Draw an ExPolygon which is a polygon inside a slice on the specified layer. - void draw_polygon(const ExPolygon& p, unsigned lyr); + void draw_polygon(const Polygon& p, unsigned lyr); // Tell the printer how many layers should it consider. void layers(unsigned layernum); @@ -209,7 +209,7 @@ public: inline void layers(unsigned cnt) { if(cnt > 0) m_layers_rst.resize(cnt); } inline unsigned layers() const { return unsigned(m_layers_rst.size()); } - inline void draw_polygon(const ExPolygon& p, unsigned lyr) { + inline void draw_polygon(const Polygon& p, unsigned lyr) { assert(lyr < m_layers_rst.size()); m_layers_rst[lyr].first.draw(p); } diff --git a/src/libslic3r/Rasterizer/Rasterizer.cpp b/src/libslic3r/Rasterizer/Rasterizer.cpp index 5961d9b78..3e42e37d8 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.cpp +++ b/src/libslic3r/Rasterizer/Rasterizer.cpp @@ -1,5 +1,5 @@ #include "Rasterizer.hpp" -#include +#include #include @@ -72,22 +72,16 @@ public: clear(); } - void draw(const ExPolygon &poly) { + void draw(const Polygon &poly) { agg::rasterizer_scanline_aa<> ras; agg::scanline_p8 scanlines; - auto&& path = to_path(poly.contour); + auto&& path = to_path(poly); if(m_o == Origin::TOP_LEFT) flipy(path); ras.add_path(path); - for(auto h : poly.holes) { - auto&& holepath = to_path(h); - if(m_o == Origin::TOP_LEFT) flipy(holepath); - ras.add_path(holepath); - } - agg::render_scanlines(ras, scanlines, m_renderer); } @@ -169,7 +163,7 @@ void Raster::clear() m_impl->clear(); } -void Raster::draw(const ExPolygon &poly) +void Raster::draw(const Polygon &poly) { assert(m_impl); m_impl->draw(poly); diff --git a/src/libslic3r/Rasterizer/Rasterizer.hpp b/src/libslic3r/Rasterizer/Rasterizer.hpp index 06d5b88c6..05ffd99b3 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.hpp +++ b/src/libslic3r/Rasterizer/Rasterizer.hpp @@ -6,7 +6,7 @@ namespace Slic3r { -class ExPolygon; +class Polygon; /** * @brief Raster captures an anti-aliased monochrome canvas where vectorial @@ -83,7 +83,7 @@ public: void clear(); /// Draw a polygon with holes. - void draw(const ExPolygon& poly); + void draw(const Polygon& poly); /// Save the raster on the specified stream. void save(std::ostream& stream, Compression comp = Compression::RAW); diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index ee24cf3ec..af3f20a59 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -915,19 +915,7 @@ void SLAPrint::process() report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); }; - auto fillstats = [this]() { - - m_print_statistics.clear(); - - // Fill statistics - fill_statistics(); - - report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); - }; - - // Rasterizing the model objects, and their supports - auto rasterize = [this, max_objstatus, ilhs]() { - if(canceled()) return; + auto fillstats = [this, ilhs]() { // clear the rasterizer input m_printer_input.clear(); @@ -962,6 +950,18 @@ void SLAPrint::process() } } + m_print_statistics.clear(); + + // Fill statistics + fill_statistics(); + + report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); + }; + + // Rasterizing the model objects, and their supports + auto rasterize = [this, max_objstatus]() { + if(canceled()) return; + // collect all the keys // If the raster has vertical orientation, we will flip the coordinates @@ -1015,28 +1015,30 @@ void SLAPrint::process() // Switch to the appropriate layer in the printer printer.begin_layer(level_id); - using Instance = SLAPrintObject::Instance; - - auto draw = - [&printer, flpXY, level_id](ExPolygon& poly, const Instance& tr) - { - poly.rotate(double(tr.rotation)); - poly.translate(tr.shift(X), tr.shift(Y)); - if(flpXY) swapXY(poly); + for(const Polygon& poly : printlayer.transformed_slices()) printer.draw_polygon(poly, level_id); - }; - for(const SliceRecord& sr : printlayer.slices()) { - if(! sr.print_obj()) continue; - for(const Instance& inst : sr.print_obj()->instances()) { - ExPolygons objsl = sr.get_slice(soModel); - for(ExPolygon& poly : objsl) draw(poly, inst); +// auto draw = +// [&printer, flpXY, level_id](Polygon& poly, const Instance& tr) +// { +// poly.rotate(double(tr.rotation)); +// poly.translate(tr.shift(X), tr.shift(Y)); +// if(flpXY) for(auto& p : poly.points) std::swap(p(X), p(Y)); +// printer.draw_polygon(poly, level_id); +// }; - ExPolygons supsl = sr.get_slice(soSupport); - for(ExPolygon& poly : supsl) draw(poly, inst); - } - } +// for(const SliceRecord& sr : printlayer.slices()) { +// if(! sr.print_obj()) continue; + +// for(const Instance& inst : sr.print_obj()->instances()) { +// ExPolygons objsl = sr.get_slice(soModel); +// for(ExPolygon& poly : objsl) draw(poly, inst); + +// ExPolygons supsl = sr.get_slice(soSupport); +// for(ExPolygon& poly : supsl) draw(poly, inst); +// } +// } // Finish the layer for later saving it. printer.finish_layer(level_id); @@ -1217,9 +1219,6 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector& instances) { + auto get_all_polygons = + [flpXY](const ExPolygons& input_polygons, + const std::vector& instances) + { const size_t inst_cnt = instances.size(); size_t polygon_cnt = 0; @@ -1249,6 +1255,7 @@ void SLAPrint::fill_statistics() ExPolygon tmp = polygon; tmp.rotate(double(instances[i].rotation)); tmp.translate(instances[i].shift.x(), instances[i].shift.y()); + if(flpXY) swapXY(tmp); polygons_append(polygons, to_polygons(std::move(tmp))); } } @@ -1263,55 +1270,30 @@ void SLAPrint::fill_statistics() size_t slow_layers = 0; size_t fast_layers = 0; - // find highest object - // Which is a better bet? To compare by max_z or by number of layers in the index? - // float max_z = 0.; - size_t max_layers_cnt = 0; - size_t highest_obj_idx = 0; - for (SLAPrintObject *&po : m_objects) { - auto& slice_index = po->get_slice_index(); - if (! slice_index.empty()) { - // float z = (-- slice_index.end())->slice_level(); - size_t cnt = slice_index.size(); - //if (z > max_z) { - if (cnt > max_layers_cnt) { - max_layers_cnt = cnt; - // max_z = z; - highest_obj_idx = &po - &m_objects.front(); - } - } - } - - const SLAPrintObject * highest_obj = m_objects[highest_obj_idx]; - auto& highest_obj_slice_index = highest_obj->get_slice_index(); - const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1); double fade_layer_time = init_exp_time; int sliced_layer_cnt = 0; - for (const SliceRecord& layer : highest_obj_slice_index) + for (PrintLayer& layer : m_printer_input) { - const auto l_height = double(layer.layer_height()); + if(layer.slices().empty()) continue; + + // Layer height should match for all object slices for a given level. + const auto l_height = double(layer.slices().front().get().layer_height()); // Calculation of the consumed material Polygons model_polygons; Polygons supports_polygons; - for (SLAPrintObject * po : m_objects) - { - const SliceRecord *record = nullptr; - { - const SliceRecord& slr = po->closest_slice_to_slice_level(layer.slice_level(), float(EPSILON)); - if (!slr.is_valid()) continue; - record = &slr; - } + for(const SliceRecord& record : layer.slices()) { + const SLAPrintObject *po = record.print_obj(); - const ExPolygons &modelslices = record->get_slice(soModel); + const ExPolygons &modelslices = record.get_slice(soModel); if (!modelslices.empty()) append(model_polygons, get_all_polygons(modelslices, po->instances())); - const ExPolygons &supportslices = record->get_slice(soSupport); + const ExPolygons &supportslices = record.get_slice(soSupport); if (!supportslices.empty()) append(supports_polygons, get_all_polygons(supportslices, po->instances())); } @@ -1321,7 +1303,7 @@ void SLAPrint::fill_statistics() for (const Polygon& polygon : model_polygons) layer_model_area += polygon.area(); - if (layer_model_area != 0) + if (layer_model_area < 0 || layer_model_area > 0) models_volume += layer_model_area * l_height; if (!supports_polygons.empty() && !model_polygons.empty()) @@ -1330,9 +1312,13 @@ void SLAPrint::fill_statistics() for (const Polygon& polygon : supports_polygons) layer_support_area += polygon.area(); - if (layer_support_area != 0) + if (layer_support_area < 0 || layer_model_area > 0) supports_volume += layer_support_area * l_height; + // Here we can save the expensively calculated polygons for printing + append(model_polygons, supports_polygons); + layer.transformed_slices(union_(model_polygons)); + // Calculation of the slow and fast layers to the future controlling those values on FW const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill; @@ -1365,7 +1351,7 @@ void SLAPrint::fill_statistics() // Estimated printing time // A layers count o the highest object - if (max_layers_cnt == 0) + if (m_printer_input.size() == 0) m_print_statistics.estimated_print_time = "N/A"; else m_print_statistics.estimated_print_time = get_time_dhms(float(estim_time)); diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index afdfab415..9b6c89687 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -127,7 +127,7 @@ public: bool is_valid() const { return ! std::isnan(m_slice_z); } - const SLAPrintObject* print_obj() const { return m_po; } + const SLAPrintObject* print_obj() const { assert(m_po); return m_po; } // Methods for setting the indices into the slice vectors. void set_model_slice_idx(const SLAPrintObject &po, size_t id) { @@ -328,6 +328,7 @@ class SLAPrint : public PrintBaseWithState private: // Prevents erroneous use by other classes. typedef PrintBaseWithState Inherited; + void fill_statistics(); public: // An aggregation of SliceRecord-s from all the print objects for each @@ -339,6 +340,14 @@ public: // The collection of slice records for the current level. std::vector> m_slices; + Polygons m_transformed_slices; + + template void transformed_slices(Container&& c) { + m_transformed_slices = std::forward(c); + } + + friend void SLAPrint::fill_statistics(); + public: explicit PrintLayer(coord_t lvl) : m_level(lvl) {} @@ -353,6 +362,10 @@ public: coord_t level() const { return m_level; } auto slices() const -> const decltype (m_slices)& { return m_slices; } + + const Polygons& transformed_slices() const { + return m_transformed_slices; + } }; SLAPrint(): m_stepmask(slapsCount, true) {} @@ -399,8 +412,6 @@ private: // Invalidate steps based on a set of parameters changed. bool invalidate_state_by_config_options(const std::vector &opt_keys); - void fill_statistics(); - SLAPrintConfig m_print_config; SLAPrinterConfig m_printer_config; SLAMaterialConfig m_material_config; From bc747615135c5c6661b530ae57fd0e370e178f94 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 27 Mar 2019 10:59:29 +0100 Subject: [PATCH 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 ee24cf3ec..862913f95 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -43,8 +43,7 @@ const std::array OBJ_STEP_LEVELS = 30, // slaposSupportPoints, 25, // slaposSupportTree, 25, // slaposBasePool, - 5, // slaposSliceSupports, - 5 // slaposIndexSlices + 10, // slaposSliceSupports, }; const std::array OBJ_STEP_LABELS = @@ -54,22 +53,19 @@ const std::array OBJ_STEP_LABELS = L("Generating support tree"), // slaposSupportTree, L("Generating pad"), // slaposBasePool, L("Slicing supports"), // slaposSliceSupports, - L("Slicing supports") // slaposIndexSlices, }; // Should also add up to 100 (%) const std::array PRINT_STEP_LEVELS = { 5, // slapsStats - 94, // slapsRasterize - 1, // slapsValidate + 95, // slapsRasterize }; const std::array PRINT_STEP_LABELS = { - L("Calculating statistics"), // slapsStats + L("Merging slices and calculating statistics"), // slapsStats L("Rasterizing layers"), // slapsRasterize - L("Validating"), // slapsValidate }; } @@ -206,7 +202,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf model_object_status.emplace(model_object->id(), ModelObjectStatus::Old); } else if (model_object_list_extended(m_model, model)) { // Add new objects. Their volumes and configs will be synchronized later. - update_apply_status(this->invalidate_step(slapsRasterize)); + update_apply_status(this->invalidate_step(slapsMergeSlicesAndEval)); for (const ModelObject *model_object : m_model.objects) model_object_status.emplace(model_object->id(), ModelObjectStatus::Old); for (size_t i = m_model.objects.size(); i < model.objects.size(); ++ i) { @@ -218,7 +214,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf // Reorder the objects, add new objects. // First stop background processing before shuffling or deleting the PrintObjects in the object list. this->call_cancel_callback(); - update_apply_status(this->invalidate_step(slapsRasterize)); + update_apply_status(this->invalidate_step(slapsMergeSlicesAndEval)); // Second create a new list of objects. std::vector model_objects_old(std::move(m_model.objects)); m_model.objects.clear(); @@ -390,7 +386,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf if (new_instances != it_print_object_status->print_object->instances()) { // Instances changed. it_print_object_status->print_object->set_instances(new_instances); - update_apply_status(this->invalidate_step(slapsRasterize)); + update_apply_status(this->invalidate_step(slapsMergeSlicesAndEval)); } print_objects_new.emplace_back(it_print_object_status->print_object); const_cast(*it_print_object_status).status = PrintObjectStatus::Reused; @@ -613,6 +609,18 @@ std::string SLAPrint::validate() const return ""; } +bool SLAPrint::invalidate_step(SLAPrintStep step) +{ + bool invalidated = Inherited::invalidate_step(step); + + // propagate to dependent steps + if (step == slapsMergeSlicesAndEval) { + invalidated |= this->invalidate_all_steps(); + } + + return invalidated; +} + template void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) { @@ -639,7 +647,7 @@ void SLAPrint::process() const size_t objcount = m_objects.size(); const unsigned min_objstatus = 0; // where the per object operations start - const unsigned max_objstatus = PRINT_STEP_LEVELS[slapsRasterize]; // where the per object operations end + const unsigned max_objstatus = PRINT_STEP_LEVELS[slapsMergeSlicesAndEval]; // where the per object operations end // the coefficient that multiplies the per object status values which // are set up for <0, 100>. They need to be scaled into the whole process @@ -883,7 +891,7 @@ void SLAPrint::process() // Slicing the support geometries similarly to the model slicing procedure. // If the pad had been added previously (see step "base_pool" than it will // be part of the slices) - auto slice_supports = [](SLAPrintObject& po) { + auto slice_supports = [this](SLAPrintObject& po) { auto& sd = po.m_supportdata; if(sd) sd->support_slices.clear(); @@ -906,16 +914,14 @@ void SLAPrint::process() { po.m_slice_index[i].set_support_slice_idx(po, i); } - }; - // We have the layer polygon collection but we need to unite them into - // an index where the key is the height level in discrete levels (clipper) - auto index_slices = [this/*, ilhd*/](SLAPrintObject& /*po*/) { // Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update status to the 3D preview to load the SLA slices. report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); }; - auto fillstats = [this]() { + // Merging the slices from all the print objects into one slice grid and + // calculating print statistics from the merge result. + auto merge_slices_and_eval_stats = [this]() { m_print_statistics.clear(); @@ -1079,15 +1085,13 @@ void SLAPrint::process() support_points, support_tree, base_pool, - slice_supports, - index_slices + slice_supports }; std::array print_program = { - fillstats, - rasterize, - [](){} // validate + merge_slices_and_eval_stats, + rasterize }; unsigned st = min_objstatus; @@ -1127,7 +1131,7 @@ void SLAPrint::process() } std::array printsteps = { - slapsStats, slapsRasterize, slapsValidate + slapsMergeSlicesAndEval, slapsRasterize }; // this would disable the rasterization step @@ -1193,11 +1197,11 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vectorinvalidate_all_steps(); } else if (step == slaposSupportPoints) { - invalidated |= this->invalidate_steps({ slaposSupportTree, slaposBasePool, slaposSliceSupports, slaposIndexSlices }); - invalidated |= m_print->invalidate_step(slapsRasterize); + invalidated |= this->invalidate_steps({ slaposSupportTree, slaposBasePool, slaposSliceSupports }); + invalidated |= m_print->invalidate_step(slapsMergeSlicesAndEval); } else if (step == slaposSupportTree) { - invalidated |= this->invalidate_steps({ slaposBasePool, slaposSliceSupports, slaposIndexSlices }); - invalidated |= m_print->invalidate_step(slapsRasterize); + invalidated |= this->invalidate_steps({ slaposBasePool, slaposSliceSupports }); + invalidated |= m_print->invalidate_step(slapsMergeSlicesAndEval); } else if (step == slaposBasePool) { - invalidated |= this->invalidate_steps({slaposSliceSupports, slaposIndexSlices}); - invalidated |= m_print->invalidate_step(slapsRasterize); + invalidated |= this->invalidate_steps({slaposSliceSupports}); + invalidated |= m_print->invalidate_step(slapsMergeSlicesAndEval); } else if (step == slaposSliceSupports) { - invalidated |= this->invalidate_step(slaposIndexSlices); - invalidated |= m_print->invalidate_step(slapsRasterize); - } else if(step == slaposIndexSlices) { - invalidated |= m_print->invalidate_step(slapsRasterize); + invalidated |= m_print->invalidate_step(slapsMergeSlicesAndEval); } return invalidated; } @@ -1547,18 +1548,6 @@ const ExPolygons &SliceRecord::get_slice(SliceOrigin o) const return idx >= v.size() ? EMPTY_SLICE : v[idx]; } -const std::vector & SLAPrintObject::get_slice_index() const -{ - // assert(is_step_done(slaposIndexSlices)); - return m_slice_index; -} - -const std::vector &SLAPrintObject::get_model_slices() const -{ - // assert(is_step_done(slaposObjectSlice)); - return m_model_slices; -} - bool SLAPrintObject::has_mesh(SLAPrintObjectStep step) const { switch (step) { diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index afdfab415..0909645f7 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -11,9 +11,8 @@ namespace Slic3r { enum SLAPrintStep : unsigned int { - slapsStats, - slapsRasterize, - slapsValidate, + slapsMergeSlicesAndEval, + slapsRasterize, slapsCount }; @@ -22,8 +21,7 @@ enum SLAPrintObjectStep : unsigned int { slaposSupportPoints, slaposSupportTree, slaposBasePool, - slaposSliceSupports, - slaposIndexSlices, + slaposSliceSupports, slaposCount }; @@ -190,7 +188,7 @@ private: return it; } - const std::vector& get_model_slices() const; + const std::vector& get_model_slices() const { return m_model_slices; } const std::vector& get_support_slices() const; public: @@ -205,7 +203,9 @@ public: // ///////////////////////////////////////////////////////////////////////// // Retrieve the slice index. - const std::vector& get_slice_index() const; + const std::vector& get_slice_index() const { + return m_slice_index; + } // Search slice index for the closest slice to given print_level. // max_epsilon gives the allowable deviation of the returned slice record's @@ -370,7 +370,7 @@ public: // Returns true if an object step is done on all objects and there's at least one object. bool is_step_done(SLAPrintObjectStep step) const; // Returns true if the last step was finished with success. - bool finished() const override { return this->is_step_done(slaposIndexSlices) && this->Inherited::is_step_done(slapsRasterize); } + bool finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); } template void export_raster(const std::string& fname) { if(m_printer) m_printer->save(fname); @@ -396,6 +396,9 @@ private: using SLAPrinter = FilePrinter; using SLAPrinterPtr = std::unique_ptr; + // Implement same logic as in SLAPrintObject + bool invalidate_step(SLAPrintStep st); + // Invalidate steps based on a set of parameters changed. bool invalidate_state_by_config_options(const std::vector &opt_keys); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index da62ddab0..eaa5f30f5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5010,7 +5010,7 @@ void GLCanvas3D::_render_sla_slices() const } if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && - obj->is_step_done(slaposIndexSlices) && !obj->get_slice_index().empty()) + obj->is_step_done(slaposSliceSupports) && !obj->get_slice_index().empty()) { double layer_height = print->default_object_config().layer_height.value; double initial_layer_height = print->material_config().initial_layer_height.value; @@ -6212,7 +6212,7 @@ void GLCanvas3D::_load_shells_sla() int obj_idx = 0; for (const SLAPrintObject* obj : print->objects()) { - if (!obj->is_step_done(slaposIndexSlices)) + if (!obj->is_step_done(slaposSliceSupports)) continue; unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 18324f2e8..8ed6ccb80 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -772,7 +772,7 @@ void Preview::load_print_as_sla() std::vector zs; double initial_layer_height = print->material_config().initial_layer_height.value; for (const SLAPrintObject* obj : print->objects()) - if (obj->is_step_done(slaposIndexSlices) && !obj->get_slice_index().empty()) + if (obj->is_step_done(slaposSliceSupports) && !obj->get_slice_index().empty()) { auto low_coord = obj->get_slice_index().front().print_level(); for (auto& rec : obj->get_slice_index()) From 440e54181b48291e9eed5298c80893661afb4c4c Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 27 Mar 2019 18:37:50 +0100 Subject: [PATCH 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 995afcc76..462d1dd06 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/CMakeLists.txt +++ b/src/libnest2d/include/libnest2d/backends/clipper/CMakeLists.txt @@ -64,6 +64,7 @@ endif() target_include_directories(ClipperBackend INTERFACE ${Boost_INCLUDE_DIRS} ) target_sources(ClipperBackend INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/geometries.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/clipper_polygon.hpp ${SRC_DIR}/libnest2d/utils/boost_alg.hpp ) target_compile_definitions(ClipperBackend INTERFACE LIBNEST2D_BACKEND_CLIPPER) diff --git a/src/libnest2d/include/libnest2d/backends/clipper/clipper_polygon.hpp b/src/libnest2d/include/libnest2d/backends/clipper/clipper_polygon.hpp new file mode 100644 index 000000000..e9fbfbd18 --- /dev/null +++ b/src/libnest2d/include/libnest2d/backends/clipper/clipper_polygon.hpp @@ -0,0 +1,72 @@ +#ifndef CLIPPER_POLYGON_HPP +#define CLIPPER_POLYGON_HPP + +#include + +namespace ClipperLib { + +struct Polygon { + Path Contour; + Paths Holes; + + inline Polygon() = default; + + inline explicit Polygon(const Path& cont): Contour(cont) {} + inline explicit Polygon(const Paths& holes): + Holes(holes) {} + inline Polygon(const Path& cont, const Paths& holes): + Contour(cont), Holes(holes) {} + + inline explicit Polygon(Path&& cont): Contour(std::move(cont)) {} + inline explicit Polygon(Paths&& holes): Holes(std::move(holes)) {} + inline Polygon(Path&& cont, Paths&& holes): + Contour(std::move(cont)), Holes(std::move(holes)) {} +}; + +inline IntPoint& operator +=(IntPoint& p, const IntPoint& pa ) { + // This could be done with SIMD + p.X += pa.X; + p.Y += pa.Y; + return p; +} + +inline IntPoint operator+(const IntPoint& p1, const IntPoint& p2) { + IntPoint ret = p1; + ret += p2; + return ret; +} + +inline IntPoint& operator -=(IntPoint& p, const IntPoint& pa ) { + p.X -= pa.X; + p.Y -= pa.Y; + return p; +} + +inline IntPoint operator -(IntPoint& p ) { + IntPoint ret = p; + ret.X = -ret.X; + ret.Y = -ret.Y; + return ret; +} + +inline IntPoint operator-(const IntPoint& p1, const IntPoint& p2) { + IntPoint ret = p1; + ret -= p2; + return ret; +} + +inline IntPoint& operator *=(IntPoint& p, const IntPoint& pa ) { + p.X *= pa.X; + p.Y *= pa.Y; + return p; +} + +inline IntPoint operator*(const IntPoint& p1, const IntPoint& p2) { + IntPoint ret = p1; + ret *= p2; + return ret; +} + +} + +#endif // CLIPPER_POLYGON_HPP diff --git a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp index 9f881e7e0..2c9550cf8 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp +++ b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp @@ -10,84 +10,15 @@ #include #include -#include - -namespace ClipperLib { -using PointImpl = IntPoint; -using PathImpl = Path; -using HoleStore = std::vector; - -struct PolygonImpl { - PathImpl Contour; - HoleStore Holes; - - inline PolygonImpl() = default; - - inline explicit PolygonImpl(const PathImpl& cont): Contour(cont) {} - inline explicit PolygonImpl(const HoleStore& holes): - Holes(holes) {} - inline PolygonImpl(const Path& cont, const HoleStore& holes): - Contour(cont), Holes(holes) {} - - inline explicit PolygonImpl(PathImpl&& cont): Contour(std::move(cont)) {} - inline explicit PolygonImpl(HoleStore&& holes): Holes(std::move(holes)) {} - inline PolygonImpl(Path&& cont, HoleStore&& holes): - Contour(std::move(cont)), Holes(std::move(holes)) {} -}; - -inline PointImpl& operator +=(PointImpl& p, const PointImpl& pa ) { - // This could be done with SIMD - p.X += pa.X; - p.Y += pa.Y; - return p; -} - -inline PointImpl operator+(const PointImpl& p1, const PointImpl& p2) { - PointImpl ret = p1; - ret += p2; - return ret; -} - -inline PointImpl& operator -=(PointImpl& p, const PointImpl& pa ) { - p.X -= pa.X; - p.Y -= pa.Y; - return p; -} - -inline PointImpl operator -(PointImpl& p ) { - PointImpl ret = p; - ret.X = -ret.X; - ret.Y = -ret.Y; - return ret; -} - -inline PointImpl operator-(const PointImpl& p1, const PointImpl& p2) { - PointImpl ret = p1; - ret -= p2; - return ret; -} - -inline PointImpl& operator *=(PointImpl& p, const PointImpl& pa ) { - p.X *= pa.X; - p.Y *= pa.Y; - return p; -} - -inline PointImpl operator*(const PointImpl& p1, const PointImpl& p2) { - PointImpl ret = p1; - ret *= p2; - return ret; -} - -} +#include "clipper_polygon.hpp" namespace libnest2d { // Aliases for convinience -using ClipperLib::PointImpl; -using ClipperLib::PathImpl; -using ClipperLib::PolygonImpl; -using ClipperLib::HoleStore; +using PointImpl = ClipperLib::IntPoint; +using PathImpl = ClipperLib::Path; +using HoleStore = ClipperLib::Paths; +using PolygonImpl = ClipperLib::Polygon; // Type of coordinate units used by Clipper template<> struct CoordType { @@ -158,33 +89,24 @@ template<> inline TCoord& y(PointImpl& p) #define DISABLE_BOOST_AREA namespace _smartarea { + template inline double area(const PolygonImpl& /*sh*/) { return std::nan(""); } template<> -inline double area(const PolygonImpl& sh) { - double a = 0; - - std::for_each(sh.Holes.begin(), sh.Holes.end(), [&a](const PathImpl& h) - { - a -= ClipperLib::Area(h); +inline double area(const PolygonImpl& sh) { + return std::accumulate(sh.Holes.begin(), sh.Holes.end(), + ClipperLib::Area(sh.Contour), + [](double a, const ClipperLib::Path& pt){ + return a + ClipperLib::Area(pt); }); - - return -ClipperLib::Area(sh.Contour) + a; } template<> -inline double area(const PolygonImpl& sh) { - double a = 0; - - std::for_each(sh.Holes.begin(), sh.Holes.end(), [&a](const PathImpl& h) - { - a += ClipperLib::Area(h); - }); - - return ClipperLib::Area(sh.Contour) + a; +inline double area(const PolygonImpl& sh) { + return -area(sh); } } @@ -390,11 +312,17 @@ inline void rotate(PolygonImpl& sh, const Radians& rads) } // namespace shapelike #define DISABLE_BOOST_NFP_MERGE -inline std::vector _merge(ClipperLib::Clipper& clipper) { +inline std::vector clipper_execute( + ClipperLib::Clipper& clipper, + ClipperLib::ClipType clipType, + ClipperLib::PolyFillType subjFillType = ClipperLib::pftEvenOdd, + ClipperLib::PolyFillType clipFillType = ClipperLib::pftEvenOdd) +{ shapelike::Shapes retv; ClipperLib::PolyTree result; - clipper.Execute(ClipperLib::ctUnion, result, ClipperLib::pftNegative); + clipper.Execute(clipType, result, subjFillType, clipFillType); + retv.reserve(static_cast(result.Total())); std::function processHole; @@ -437,15 +365,12 @@ merge(const std::vector& shapes) for(auto& path : shapes) { valid &= clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed); - - for(auto& hole : path.Holes) { - valid &= clipper.AddPath(hole, ClipperLib::ptSubject, closed); - } + valid &= clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed); } if(!valid) throw GeometryException(GeomErr::MERGE); - return _merge(clipper); + return clipper_execute(clipper, ClipperLib::ctUnion, ClipperLib::pftNegative); } } diff --git a/src/libnest2d/tests/printer_parts.h b/src/libnest2d/tests/printer_parts.h index b9a4eb8fa..1e65826bd 100644 --- a/src/libnest2d/tests/printer_parts.h +++ b/src/libnest2d/tests/printer_parts.h @@ -2,36 +2,10 @@ #define PRINTER_PARTS_H #include -#include - -#ifndef CLIPPER_BACKEND_HPP -namespace ClipperLib { -using PointImpl = IntPoint; -using PathImpl = Path; -using HoleStore = std::vector; - -struct PolygonImpl { - PathImpl Contour; - HoleStore Holes; - - inline PolygonImpl() {} - - inline explicit PolygonImpl(const PathImpl& cont): Contour(cont) {} - inline explicit PolygonImpl(const HoleStore& holes): - Holes(holes) {} - inline PolygonImpl(const Path& cont, const HoleStore& holes): - Contour(cont), Holes(holes) {} - - inline explicit PolygonImpl(PathImpl&& cont): Contour(std::move(cont)) {} - inline explicit PolygonImpl(HoleStore&& holes): Holes(std::move(holes)) {} - inline PolygonImpl(Path&& cont, HoleStore&& holes): - Contour(std::move(cont)), Holes(std::move(holes)) {} -}; -} -#endif +#include using TestData = std::vector; -using TestDataEx = std::vector; +using TestDataEx = std::vector; extern const TestData PRINTER_PART_POLYGONS; extern const TestData STEGOSAUR_POLYGONS; diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp index 4942e35b6..54627ba86 100644 --- a/src/libslic3r/ModelArrange.cpp +++ b/src/libslic3r/ModelArrange.cpp @@ -574,7 +574,7 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { for(ModelInstance* objinst : objptr->instances) { if(objinst) { - ClipperLib::PolygonImpl pn; + ClipperLib::Polygon pn; pn.Contour = clpath; // Efficient conversion to item. diff --git a/src/libslic3r/PrintExport.hpp b/src/libslic3r/PrintExport.hpp index 003ed5af4..c0c12209a 100644 --- a/src/libslic3r/PrintExport.hpp +++ b/src/libslic3r/PrintExport.hpp @@ -42,8 +42,9 @@ template class FilePrinter { public: - // Draw an ExPolygon which is a polygon inside a slice on the specified layer. - void draw_polygon(const Polygon& p, unsigned lyr); + // Draw a polygon which is a polygon inside a slice on the specified layer. + void draw_polygon(const ExPolygon& p, unsigned lyr); + void draw_polygon(const ClipperLib::Polygon& p, unsigned lyr); // Tell the printer how many layers should it consider. void layers(unsigned layernum); @@ -209,7 +210,12 @@ public: inline void layers(unsigned cnt) { if(cnt > 0) m_layers_rst.resize(cnt); } inline unsigned layers() const { return unsigned(m_layers_rst.size()); } - inline void draw_polygon(const Polygon& p, unsigned lyr) { + inline void draw_polygon(const ExPolygon& p, unsigned lyr) { + assert(lyr < m_layers_rst.size()); + m_layers_rst[lyr].first.draw(p); + } + + inline void draw_polygon(const ClipperLib::Polygon& p, unsigned lyr) { assert(lyr < m_layers_rst.size()); m_layers_rst[lyr].first.draw(p); } diff --git a/src/libslic3r/Rasterizer/Rasterizer.cpp b/src/libslic3r/Rasterizer/Rasterizer.cpp index 3e42e37d8..45c9daf3b 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.cpp +++ b/src/libslic3r/Rasterizer/Rasterizer.cpp @@ -1,5 +1,6 @@ #include "Rasterizer.hpp" -#include +#include +#include #include @@ -72,7 +73,7 @@ public: clear(); } - void draw(const Polygon &poly) { + template inline void draw(const Geometry &poly) { agg::rasterizer_scanline_aa<> ras; agg::scanline_p8 scanlines; @@ -104,14 +105,36 @@ private: return p(1) * SCALING_FACTOR/m_pxdim.h_mm; } - agg::path_storage to_path(const Polygon& poly) { + agg::path_storage to_path(const Polygon& poly) + { agg::path_storage path; + auto it = poly.points.begin(); path.move_to(getPx(*it), getPy(*it)); - while(++it != poly.points.end()) + while(++it != poly.points.end()) path.line_to(getPx(*it), getPy(*it)); + path.line_to(getPx(poly.points.front()), getPy(poly.points.front())); + + return path; + } + + + double getPx(const ClipperLib::IntPoint& p) { + return p.X * SCALING_FACTOR/m_pxdim.w_mm; + } + + double getPy(const ClipperLib::IntPoint& p) { + return p.Y * SCALING_FACTOR/m_pxdim.h_mm; + } + + agg::path_storage to_path(const ClipperLib::Path& poly) + { + agg::path_storage path; + auto it = poly.begin(); + path.move_to(getPx(*it), getPy(*it)); + while(++it != poly.end()) path.line_to(getPx(*it), getPy(*it)); - path.line_to(getPx(poly.points.front()), getPy(poly.points.front())); + path.line_to(getPx(poly.front()), getPy(poly.front())); return path; } @@ -163,10 +186,16 @@ void Raster::clear() m_impl->clear(); } -void Raster::draw(const Polygon &poly) +void Raster::draw(const ExPolygon &expoly) { - assert(m_impl); - m_impl->draw(poly); + m_impl->draw(expoly.contour); + for(auto& h : expoly.holes) m_impl->draw(h); +} + +void Raster::draw(const ClipperLib::Polygon &poly) +{ + m_impl->draw(poly.Contour); + for(auto& h : poly.Holes) m_impl->draw(h); } void Raster::save(std::ostream& stream, Compression comp) diff --git a/src/libslic3r/Rasterizer/Rasterizer.hpp b/src/libslic3r/Rasterizer/Rasterizer.hpp index 05ffd99b3..0468b6644 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.hpp +++ b/src/libslic3r/Rasterizer/Rasterizer.hpp @@ -4,9 +4,11 @@ #include #include +namespace ClipperLib { class Polygon; } + namespace Slic3r { -class Polygon; +class ExPolygon; /** * @brief Raster captures an anti-aliased monochrome canvas where vectorial @@ -83,7 +85,8 @@ public: void clear(); /// Draw a polygon with holes. - void draw(const Polygon& poly); + void draw(const ExPolygon& poly); + void draw(const ClipperLib::Polygon& poly); /// Save the raster on the specified stream. void save(std::ostream& stream, Compression comp = Compression::RAW); diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index ab7feed0e..eaa4642b0 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -12,6 +12,9 @@ #include #include +// For geometry algorithms with native Clipper types (no copies and conversions) +#include + //#include //#include "tbb/mutex.h" #include "I18N.hpp" @@ -958,8 +961,249 @@ void SLAPrint::process() m_print_statistics.clear(); - // Fill statistics - fill_statistics(); + using ClipperPolygon = libnest2d::PolygonImpl; + using ClipperPath = ClipperLib::Path; + using ClipperPoint = ClipperLib::IntPoint; + using ClipperPolygons = std::vector; + using libnest2d::Radians; + namespace sl = libnest2d::shapelike; + + // If the raster has vertical orientation, we will flip the coordinates + bool flpXY = m_printer_config.display_orientation.getInt() == SLADisplayOrientation::sladoPortrait; + + auto polyunion = [] (const ClipperPolygons& subjects) + { + ClipperLib::Clipper clipper; + + bool closed = true; + + for(auto& path : subjects) { + clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed); + clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed); + } + + auto mode = ClipperLib::pftPositive; + + return libnest2d::clipper_execute(clipper, ClipperLib::ctUnion, mode, mode); + }; + + auto polydiff = [](const ClipperPolygons& subjects, const ClipperPolygons& clips) + { + ClipperLib::Clipper clipper; + + bool closed = true; + + for(auto& path : subjects) { + clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed); + clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed); + } + + for(auto& path : clips) { + clipper.AddPath(path.Contour, ClipperLib::ptClip, closed); + clipper.AddPaths(path.Holes, ClipperLib::ptClip, closed); + } + + auto mode = ClipperLib::pftPositive; + + return libnest2d::clipper_execute(clipper, ClipperLib::ctDifference, mode, mode); + }; + + auto area = [](const ClipperPolygon& poly) + { + using ClipperLib::Area; + return std::accumulate( poly.Holes.begin(), poly.Holes.end(), + Area(poly.Contour), + [](double a, const ClipperPath& p) { return a + Area(p); }); + }; + + const double area_fill = m_printer_config.area_fill.getFloat()*0.01;// 0.5 (50%); + const double fast_tilt = m_printer_config.fast_tilt_time.getFloat();// 5.0; + const double slow_tilt = m_printer_config.slow_tilt_time.getFloat();// 8.0; + + const double init_exp_time = m_material_config.initial_exposure_time.getFloat(); + const double exp_time = m_material_config.exposure_time.getFloat(); + + const int fade_layers_cnt = m_default_object_config.faded_layers.getInt();// 10 // [3;20] + + const double width = m_printer_config.display_width.getFloat() / SCALING_FACTOR; + const double height = m_printer_config.display_height.getFloat() / SCALING_FACTOR; + const double display_area = width*height; + + // get polygons for all instances in the object + auto get_all_polygons = + [flpXY](const ExPolygons& input_polygons, + const std::vector& instances) + { + ClipperPolygons polygons; + polygons.reserve(input_polygons.size() * instances.size()); + + for (const ExPolygon& polygon : input_polygons) { + if(polygon.contour.empty()) continue; + + for (size_t i = 0; i < instances.size(); ++i) + { + ClipperPolygon poly; + + // should be a move + poly.Contour.reserve(polygon.contour.size() + 1); + + for(auto& p : polygon.contour.points) + poly.Contour.emplace_back(p.x(), p.y()); + + auto pfirst = poly.Contour.front(); + poly.Contour.emplace_back(pfirst); + + for(auto& h : polygon.holes) { + poly.Holes.emplace_back(); + auto& hole = poly.Holes.back(); + hole.reserve(h.points.size() + 1); + + for(auto& p : h.points) hole.emplace_back(p.x(), p.y()); + auto pfirst = hole.front(); hole.emplace_back(pfirst); + } + + sl::rotate(poly, Radians(double(instances[i].rotation))); + sl::translate(poly, ClipperPoint{instances[i].shift(X), + instances[i].shift(Y)}); + if (flpXY) { + for(auto& p : poly.Contour) std::swap(p.X, p.Y); + std::reverse(poly.Contour.begin(), poly.Contour.end()); + + for(auto& h : poly.Holes) { + for(auto& p : h) std::swap(p.X, p.Y); + std::reverse(h.begin(), h.end()); + } + } + + polygons.emplace_back(std::move(poly)); + } + } + return polygons; + }; + + double supports_volume = 0.0; + double models_volume = 0.0; + + double estim_time = 0.0; + + size_t slow_layers = 0; + size_t fast_layers = 0; + + const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1); + double fade_layer_time = init_exp_time; + + int sliced_layer_cnt = 0; + for (PrintLayer& layer : m_printer_input) + { + // vector of slice record references + auto& lyrslices = layer.slices(); + + if(lyrslices.empty()) continue; + + // Layer height should match for all object slices for a given level. + const auto l_height = double(lyrslices.front().get().layer_height()); + + // Calculation of the consumed material + + ClipperPolygons model_polygons; + ClipperPolygons supports_polygons; + + size_t c = std::accumulate(layer.slices().begin(), layer.slices().end(), 0u, [](size_t a, const SliceRecord& sr) { + return a + sr.get_slice(soModel).size(); + }); + + model_polygons.reserve(c); + + c = std::accumulate(layer.slices().begin(), layer.slices().end(), 0u, [](size_t a, const SliceRecord& sr) { + return a + sr.get_slice(soModel).size(); + }); + + supports_polygons.reserve(c); + + for(const SliceRecord& record : layer.slices()) { + const SLAPrintObject *po = record.print_obj(); + + const ExPolygons &modelslices = record.get_slice(soModel); + if (!modelslices.empty()) { + ClipperPolygons v = get_all_polygons(modelslices, po->instances()); + for(ClipperPolygon& p_tmp : v) model_polygons.emplace_back(std::move(p_tmp)); + } + + const ExPolygons &supportslices = record.get_slice(soSupport); + if (!supportslices.empty()) { + ClipperPolygons v = get_all_polygons(supportslices, po->instances()); + for(ClipperPolygon& p_tmp : v) supports_polygons.emplace_back(std::move(p_tmp)); + } + } + + model_polygons = polyunion(model_polygons); + double layer_model_area = 0; + for (const ClipperPolygon& polygon : model_polygons) + layer_model_area += area(polygon); + + if (layer_model_area < 0 || layer_model_area > 0) + models_volume += layer_model_area * l_height; + + if(!supports_polygons.empty()) { + if(model_polygons.empty()) supports_polygons = polyunion(supports_polygons); + else supports_polygons = polydiff(supports_polygons, model_polygons); + // allegedly, union of subject is done withing the diff + } + + double layer_support_area = 0; + for (const ClipperPolygon& polygon : supports_polygons) + layer_support_area += area(polygon); + + if (layer_support_area < 0 || layer_model_area > 0) + supports_volume += layer_support_area * l_height; + + // Here we can save the expensively calculated polygons for printing + ClipperPolygons trslices; + trslices.reserve(model_polygons.size() + supports_polygons.size()); + for(ClipperPolygon& poly : model_polygons) trslices.emplace_back(std::move(poly)); + for(ClipperPolygon& poly : supports_polygons) trslices.emplace_back(std::move(poly)); + + layer.transformed_slices(polyunion(trslices)); + + // Calculation of the slow and fast layers to the future controlling those values on FW + + const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill; + const double tilt_time = is_fast_layer ? fast_tilt : slow_tilt; + if (is_fast_layer) + fast_layers++; + else + slow_layers++; + + + // Calculation of the printing time + + if (sliced_layer_cnt < 3) + estim_time += init_exp_time; + else if (fade_layer_time > exp_time) + { + fade_layer_time -= delta_fade_time; + estim_time += fade_layer_time; + } + else + estim_time += exp_time; + + estim_time += tilt_time; + + sliced_layer_cnt++; + } + + m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR; + m_print_statistics.objects_used_material = models_volume * SCALING_FACTOR * SCALING_FACTOR; + + // Estimated printing time + // A layers count o the highest object + if (m_printer_input.size() == 0) + m_print_statistics.estimated_print_time = "N/A"; + else + m_print_statistics.estimated_print_time = get_time_dhms(float(estim_time)); + + m_print_statistics.fast_layers_count = fast_layers; + m_print_statistics.slow_layers_count = slow_layers; report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); }; @@ -1011,7 +1255,7 @@ void SLAPrint::process() // procedure to process one height level. This will run in parallel auto lvlfn = - [this, &slck, &printer, slot, sd, ist, &pst, flpXY] + [this, &slck, &printer, slot, sd, ist, &pst] (unsigned level_id) { if(canceled()) return; @@ -1021,31 +1265,9 @@ void SLAPrint::process() // Switch to the appropriate layer in the printer printer.begin_layer(level_id); - for(const Polygon& poly : printlayer.transformed_slices()) + for(const ClipperLib::Polygon& poly : printlayer.transformed_slices()) printer.draw_polygon(poly, level_id); - -// auto draw = -// [&printer, flpXY, level_id](Polygon& poly, const Instance& tr) -// { -// poly.rotate(double(tr.rotation)); -// poly.translate(tr.shift(X), tr.shift(Y)); -// if(flpXY) for(auto& p : poly.points) std::swap(p(X), p(Y)); -// printer.draw_polygon(poly, level_id); -// }; - -// for(const SliceRecord& sr : printlayer.slices()) { -// if(! sr.print_obj()) continue; - -// for(const Instance& inst : sr.print_obj()->instances()) { -// ExPolygons objsl = sr.get_slice(soModel); -// for(ExPolygon& poly : objsl) draw(poly, inst); - -// ExPolygons supsl = sr.get_slice(soSupport); -// for(ExPolygon& poly : supsl) draw(poly, inst); -// } -// } - // Finish the layer for later saving it. printer.finish_layer(level_id); @@ -1221,149 +1443,6 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector& instances) - { - const size_t inst_cnt = instances.size(); - - size_t polygon_cnt = 0; - for (const ExPolygon& polygon : input_polygons) - polygon_cnt += polygon.holes.size() + 1; - - Polygons polygons; - polygons.reserve(polygon_cnt * inst_cnt); - for (const ExPolygon& polygon : input_polygons) { - for (size_t i = 0; i < inst_cnt; ++i) - { - ExPolygon tmp = polygon; - tmp.rotate(double(instances[i].rotation)); - tmp.translate(instances[i].shift.x(), instances[i].shift.y()); - if(flpXY) swapXY(tmp); - polygons_append(polygons, to_polygons(std::move(tmp))); - } - } - return polygons; - }; - - double supports_volume = 0.0; - double models_volume = 0.0; - - double estim_time = 0.0; - - size_t slow_layers = 0; - size_t fast_layers = 0; - - const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1); - double fade_layer_time = init_exp_time; - - int sliced_layer_cnt = 0; - for (PrintLayer& layer : m_printer_input) - { - if(layer.slices().empty()) continue; - - // Layer height should match for all object slices for a given level. - const auto l_height = double(layer.slices().front().get().layer_height()); - - // Calculation of the consumed material - - Polygons model_polygons; - Polygons supports_polygons; - - for(const SliceRecord& record : layer.slices()) { - const SLAPrintObject *po = record.print_obj(); - - const ExPolygons &modelslices = record.get_slice(soModel); - if (!modelslices.empty()) - append(model_polygons, get_all_polygons(modelslices, po->instances())); - - const ExPolygons &supportslices = record.get_slice(soSupport); - if (!supportslices.empty()) - append(supports_polygons, get_all_polygons(supportslices, po->instances())); - } - - model_polygons = union_(model_polygons); - double layer_model_area = 0; - for (const Polygon& polygon : model_polygons) - layer_model_area += polygon.area(); - - if (layer_model_area < 0 || layer_model_area > 0) - models_volume += layer_model_area * l_height; - - if (!supports_polygons.empty() && !model_polygons.empty()) - supports_polygons = diff(supports_polygons, model_polygons); - double layer_support_area = 0; - for (const Polygon& polygon : supports_polygons) - layer_support_area += polygon.area(); - - if (layer_support_area < 0 || layer_model_area > 0) - supports_volume += layer_support_area * l_height; - - // Here we can save the expensively calculated polygons for printing - append(model_polygons, supports_polygons); - layer.transformed_slices(union_(model_polygons)); - - // Calculation of the slow and fast layers to the future controlling those values on FW - - const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill; - const double tilt_time = is_fast_layer ? fast_tilt : slow_tilt; - if (is_fast_layer) - fast_layers++; - else - slow_layers++; - - - // Calculation of the printing time - - if (sliced_layer_cnt < 3) - estim_time += init_exp_time; - else if (fade_layer_time > exp_time) - { - fade_layer_time -= delta_fade_time; - estim_time += fade_layer_time; - } - else - estim_time += exp_time; - - estim_time += tilt_time; - - sliced_layer_cnt++; - } - - m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR; - m_print_statistics.objects_used_material = models_volume * SCALING_FACTOR * SCALING_FACTOR; - - // Estimated printing time - // A layers count o the highest object - if (m_printer_input.size() == 0) - m_print_statistics.estimated_print_time = "N/A"; - else - m_print_statistics.estimated_print_time = get_time_dhms(float(estim_time)); - - m_print_statistics.fast_layers_count = fast_layers; - m_print_statistics.slow_layers_count = slow_layers; -} - // Returns true if an object step is done on all objects and there's at least one object. bool SLAPrint::is_step_done(SLAPrintObjectStep step) const { diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index e645a9574..068830771 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -6,6 +6,7 @@ #include "PrintExport.hpp" #include "Point.hpp" #include "MTUtils.hpp" +#include #include namespace Slic3r { @@ -328,46 +329,8 @@ class SLAPrint : public PrintBaseWithState private: // Prevents erroneous use by other classes. typedef PrintBaseWithState Inherited; - void fill_statistics(); public: - // An aggregation of SliceRecord-s from all the print objects for each - // occupied layer. Slice record levels dont have to match exactly. - // They are unified if the level difference is within +/- SCALED_EPSILON - class PrintLayer { - coord_t m_level; - - // The collection of slice records for the current level. - std::vector> m_slices; - - Polygons m_transformed_slices; - - template void transformed_slices(Container&& c) { - m_transformed_slices = std::forward(c); - } - - friend void SLAPrint::fill_statistics(); - - public: - - explicit PrintLayer(coord_t lvl) : m_level(lvl) {} - - // for being sorted in their container (see m_printer_input) - bool operator<(const PrintLayer& other) const { - return m_level < other.m_level; - } - - void add(const SliceRecord& sr) { m_slices.emplace_back(sr); } - - coord_t level() const { return m_level; } - - auto slices() const -> const decltype (m_slices)& { return m_slices; } - - const Polygons& transformed_slices() const { - return m_transformed_slices; - } - }; - SLAPrint(): m_stepmask(slapsCount, true) {} virtual ~SLAPrint() override { this->clear(); } @@ -401,6 +364,43 @@ public: std::string validate() const override; + // An aggregation of SliceRecord-s from all the print objects for each + // occupied layer. Slice record levels dont have to match exactly. + // They are unified if the level difference is within +/- SCALED_EPSILON + class PrintLayer { + coord_t m_level; + + // The collection of slice records for the current level. + std::vector> m_slices; + + std::vector m_transformed_slices; + + template void transformed_slices(Container&& c) { + m_transformed_slices = std::forward(c); + } + + friend void SLAPrint::process(); + + public: + + explicit PrintLayer(coord_t lvl) : m_level(lvl) {} + + // for being sorted in their container (see m_printer_input) + bool operator<(const PrintLayer& other) const { + return m_level < other.m_level; + } + + void add(const SliceRecord& sr) { m_slices.emplace_back(sr); } + + coord_t level() const { return m_level; } + + auto slices() const -> const decltype (m_slices)& { return m_slices; } + + const std::vector & transformed_slices() const { + return m_transformed_slices; + } + }; + // The aggregated and leveled print records from various objects. // TODO: use this structure for the preview in the future. const std::vector& print_layers() const { return m_printer_input; } From 50c351e0f4bf498d4890b652074103569145bddf Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 28 Mar 2019 11:01:41 +0100 Subject: [PATCH 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 2c9550cf8..d0cc44896 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp +++ b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp @@ -150,9 +150,10 @@ template<> inline void offset(PolygonImpl& sh, TCoord distance) // but throwing would be an overkill. Instead, we should warn the // caller about the inability to create correct geometries if(!found_the_contour) { - sh.Contour = r; + sh.Contour = std::move(r); ClipperLib::ReversePath(sh.Contour); - sh.Contour.push_back(sh.Contour.front()); + auto front_p = sh.Contour.front(); + sh.Contour.emplace_back(std::move(front_p)); found_the_contour = true; } else { dout() << "Warning: offsetting result is invalid!"; @@ -162,9 +163,10 @@ template<> inline void offset(PolygonImpl& sh, TCoord distance) // TODO If there are multiple contours we can't be sure which hole // belongs to the first contour. (But in this case the situation is // bad enough to let it go...) - sh.Holes.push_back(r); + sh.Holes.emplace_back(std::move(r)); ClipperLib::ReversePath(sh.Holes.back()); - sh.Holes.back().push_back(sh.Holes.back().front()); + auto front_p = sh.Holes.back().front(); + sh.Holes.back().emplace_back(std::move(front_p)); } } } @@ -328,16 +330,18 @@ inline std::vector clipper_execute( std::function processHole; auto processPoly = [&retv, &processHole](ClipperLib::PolyNode *pptr) { - PolygonImpl poly(pptr->Contour); - poly.Contour.push_back(poly.Contour.front()); + PolygonImpl poly; + poly.Contour.swap(pptr->Contour); auto front_p = poly.Contour.front(); + poly.Contour.emplace_back(std::move(front_p)); for(auto h : pptr->Childs) { processHole(h, poly); } retv.push_back(poly); }; processHole = [&processPoly](ClipperLib::PolyNode *pptr, PolygonImpl& poly) { - poly.Holes.push_back(pptr->Contour); - poly.Holes.back().push_back(poly.Holes.back().front()); + poly.Holes.emplace_back(std::move(pptr->Contour)); + auto front_p = poly.Holes.back().front(); + poly.Holes.back().emplace_back(std::move(front_p)); for(auto c : pptr->Childs) processPoly(c); }; @@ -365,7 +369,9 @@ merge(const std::vector& shapes) for(auto& path : shapes) { valid &= clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed); - valid &= clipper.AddPaths(path.Holes, ClipperLib::ptSubject, closed); + + for(auto& h : path.Holes) + valid &= clipper.AddPath(h, ClipperLib::ptSubject, closed); } if(!valid) throw GeometryException(GeomErr::MERGE); diff --git a/src/libnest2d/include/libnest2d/libnest2d.hpp b/src/libnest2d/include/libnest2d/libnest2d.hpp index 49baa65f2..c7b252e5d 100644 --- a/src/libnest2d/include/libnest2d/libnest2d.hpp +++ b/src/libnest2d/include/libnest2d/libnest2d.hpp @@ -966,7 +966,7 @@ private: for(size_t i = 0; i < pckgrp.size(); i++) { auto items = pckgrp[i]; - pg.push_back({}); + pg.emplace_back(); pg[i].reserve(items.size()); for(Item& itemA : items) { diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp index 6fb717a7a..91affe978 100644 --- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp +++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp @@ -261,7 +261,7 @@ template class EdgeCache { while(next != endit) { contour_.emap.emplace_back(*(first++), *(next++)); contour_.full_distance += contour_.emap.back().length(); - contour_.distances.push_back(contour_.full_distance); + contour_.distances.emplace_back(contour_.full_distance); } } @@ -276,10 +276,10 @@ template class EdgeCache { while(next != endit) { hc.emap.emplace_back(*(first++), *(next++)); hc.full_distance += hc.emap.back().length(); - hc.distances.push_back(hc.full_distance); + hc.distances.emplace_back(hc.full_distance); } - holes_.push_back(hc); + holes_.emplace_back(std::move(hc)); } } diff --git a/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp b/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp index 309a5007d..abcd86183 100644 --- a/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp +++ b/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp @@ -63,7 +63,7 @@ public: bool pack(Item& item, const Range& rem = Range()) { auto&& r = static_cast(this)->trypack(item, rem); if(r) { - items_.push_back(*(r.item_ptr_)); + items_.emplace_back(*(r.item_ptr_)); farea_valid_ = false; } return r; @@ -78,7 +78,7 @@ public: if(r) { r.item_ptr_->translation(r.move_); r.item_ptr_->rotation(r.rot_); - items_.push_back(*(r.item_ptr_)); + items_.emplace_back(*(r.item_ptr_)); farea_valid_ = false; } } diff --git a/src/libnest2d/include/libnest2d/selections/djd_heuristic.hpp b/src/libnest2d/include/libnest2d/selections/djd_heuristic.hpp index b03534dc4..25007e580 100644 --- a/src/libnest2d/include/libnest2d/selections/djd_heuristic.hpp +++ b/src/libnest2d/include/libnest2d/selections/djd_heuristic.hpp @@ -667,7 +667,7 @@ public: addBin(); ItemList& not_packed = not_packeds[b]; for(unsigned idx = b; idx < store_.size(); idx+=bincount_guess) { - not_packed.push_back(store_[idx]); + not_packed.emplace_back(store_[idx]); } } diff --git a/src/libnest2d/include/libnest2d/utils/boost_alg.hpp b/src/libnest2d/include/libnest2d/utils/boost_alg.hpp index a6988ca00..baf1c6a10 100644 --- a/src/libnest2d/include/libnest2d/utils/boost_alg.hpp +++ b/src/libnest2d/include/libnest2d/utils/boost_alg.hpp @@ -463,7 +463,7 @@ template<> inline std::string serialize( auto& v = *it; hf.emplace_back(getX(v)*scale, getY(v)*scale); }; - holes.push_back(hf); + holes.emplace_back(std::move(hf)); } Polygonf poly; From b19d411738979ec9416827aec52d494489ba5363 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 29 Mar 2019 13:34:22 +0100 Subject: [PATCH 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 eaa4642b0..ba6e5a904 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -578,11 +578,6 @@ sla::PoolConfig make_pool_config(const SLAPrintObjectConfig& c) { return pcfg; } - -void swapXY(ExPolygon& expoly) { - for(auto& p : expoly.contour.points) std::swap(p(X), p(Y)); - for(auto& h : expoly.holes) for(auto& p : h.points) std::swap(p(X), p(Y)); -} } std::string SLAPrint::validate() const @@ -1008,13 +1003,7 @@ void SLAPrint::process() return libnest2d::clipper_execute(clipper, ClipperLib::ctDifference, mode, mode); }; - auto area = [](const ClipperPolygon& poly) - { - using ClipperLib::Area; - return std::accumulate( poly.Holes.begin(), poly.Holes.end(), - Area(poly.Contour), - [](double a, const ClipperPath& p) { return a + Area(p); }); - }; + auto area = [](const ClipperPolygon& poly) { return - sl::area(poly); }; const double area_fill = m_printer_config.area_fill.getFloat()*0.01;// 0.5 (50%); const double fast_tilt = m_printer_config.fast_tilt_time.getFloat();// 5.0; From 3cfb234e865c2f2eb67717691519a582d86b298c 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 bdfd2fc26..fdb8968d3 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 0932c8ce9..f626fa7f5 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 35d0b5636..7e022532a 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 65934218028121fdb6f8a494122a64f17778cd66 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 5b0a91177..04b993a52 100644 --- a/src/libslic3r/PrintExport.hpp +++ b/src/libslic3r/PrintExport.hpp @@ -224,7 +224,7 @@ public: inline void draw_polygon(const ClipperLib::Polygon& p, unsigned lyr) { assert(lyr < m_layers_rst.size()); - m_layers_rst[lyr].first.draw(p); + m_layers_rst[lyr].raster.draw(p); } inline void begin_layer(unsigned lyr) { diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index ba6e5a904..9e03b6f84 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1143,7 +1143,7 @@ void SLAPrint::process() for (const ClipperPolygon& polygon : supports_polygons) layer_support_area += area(polygon); - if (layer_support_area < 0 || layer_model_area > 0) + if (layer_support_area < 0 || layer_support_area > 0) supports_volume += layer_support_area * l_height; // Here we can save the expensively calculated polygons for printing From ba89f04429cd89da25c97c9d474697ac4fe14700 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 fb35b500e..5d286846b 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 62539bc35b240d38dc8a44f47a08f86d09364307 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 a25b7e7c1..5fd058ff7 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 cc69117bf..2b1061c95 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 4eb5d91a8f2209f5b5a192a80dd7f03905a3aa10 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 d0cc44896..15eeb57b8 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp +++ b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp @@ -347,9 +347,7 @@ inline std::vector clipper_execute( auto traverse = [&processPoly] (ClipperLib::PolyNode *node) { - for(auto ch : node->Childs) { - processPoly(ch); - } + for(auto ch : node->Childs) processPoly(ch); }; traverse(&result); diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 9e03b6f84..a5aa826c9 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -956,16 +956,15 @@ void SLAPrint::process() m_print_statistics.clear(); - using ClipperPolygon = libnest2d::PolygonImpl; - using ClipperPath = ClipperLib::Path; using ClipperPoint = ClipperLib::IntPoint; + using ClipperPolygon = ClipperLib::Polygon; // see clipper_polygon.hpp in libnest2d using ClipperPolygons = std::vector; - using libnest2d::Radians; - namespace sl = libnest2d::shapelike; + namespace sl = libnest2d::shapelike; // For algorithms // If the raster has vertical orientation, we will flip the coordinates bool flpXY = m_printer_config.display_orientation.getInt() == SLADisplayOrientation::sladoPortrait; + // Set up custom union and diff functions for clipper polygons auto polyunion = [] (const ClipperPolygons& subjects) { ClipperLib::Clipper clipper; @@ -1003,7 +1002,8 @@ void SLAPrint::process() return libnest2d::clipper_execute(clipper, ClipperLib::ctDifference, mode, mode); }; - auto area = [](const ClipperPolygon& poly) { return - sl::area(poly); }; + // libnest calculates positive area for clockwise polygons, Slic3r is in counter-clockwise + auto areafn = [](const ClipperPolygon& poly) { return - sl::area(poly); }; const double area_fill = m_printer_config.area_fill.getFloat()*0.01;// 0.5 (50%); const double fast_tilt = m_printer_config.fast_tilt_time.getFloat();// 5.0; @@ -1051,7 +1051,7 @@ void SLAPrint::process() auto pfirst = hole.front(); hole.emplace_back(pfirst); } - sl::rotate(poly, Radians(double(instances[i].rotation))); + sl::rotate(poly, double(instances[i].rotation)); sl::translate(poly, ClipperPoint{instances[i].shift(X), instances[i].shift(Y)}); if (flpXY) { @@ -1070,10 +1070,10 @@ void SLAPrint::process() return polygons; }; - double supports_volume = 0.0; - double models_volume = 0.0; + double supports_volume(0.0); + double models_volume(0.0); - double estim_time = 0.0; + double estim_time(0.0); size_t slow_layers = 0; size_t fast_layers = 0; @@ -1081,16 +1081,22 @@ void SLAPrint::process() const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1); double fade_layer_time = init_exp_time; - int sliced_layer_cnt = 0; - for (PrintLayer& layer : m_printer_input) - { - // vector of slice record references - auto& lyrslices = layer.slices(); + SpinMutex mutex; + using Lock = std::lock_guard; - if(lyrslices.empty()) continue; +// for (PrintLayer& layer : m_printer_input) + auto printlayerfn = [this, get_all_polygons, polyunion, polydiff, areafn, area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, delta_fade_time, + &mutex, &models_volume, &supports_volume, &estim_time, &slow_layers, &fast_layers, &fade_layer_time](size_t sliced_layer_cnt) + { + PrintLayer& layer = m_printer_input[sliced_layer_cnt]; + + // vector of slice record references + auto& slicerecord_references = layer.slices(); + + if(slicerecord_references.empty()) return; // Layer height should match for all object slices for a given level. - const auto l_height = double(lyrslices.front().get().layer_height()); + const auto l_height = double(slicerecord_references.front().get().layer_height()); // Calculation of the consumed material @@ -1128,23 +1134,25 @@ void SLAPrint::process() model_polygons = polyunion(model_polygons); double layer_model_area = 0; for (const ClipperPolygon& polygon : model_polygons) - layer_model_area += area(polygon); + layer_model_area += areafn(polygon); - if (layer_model_area < 0 || layer_model_area > 0) - models_volume += layer_model_area * l_height; + if (layer_model_area < 0 || layer_model_area > 0) { + Lock lck(mutex); models_volume += layer_model_area * l_height; + } if(!supports_polygons.empty()) { - if(model_polygons.empty()) supports_polygons = polyunion(supports_polygons); - else supports_polygons = polydiff(supports_polygons, model_polygons); + /*if(model_polygons.empty()) */supports_polygons = polyunion(supports_polygons); + /*else */ if(!model_polygons.empty())supports_polygons = polydiff(supports_polygons, model_polygons); // allegedly, union of subject is done withing the diff } double layer_support_area = 0; for (const ClipperPolygon& polygon : supports_polygons) - layer_support_area += area(polygon); + layer_support_area += areafn(polygon); - if (layer_support_area < 0 || layer_support_area > 0) - supports_volume += layer_support_area * l_height; + if (layer_support_area < 0 || layer_support_area > 0) { + Lock lck(mutex); supports_volume += layer_support_area * l_height; + } // Here we can save the expensively calculated polygons for printing ClipperPolygons trslices; @@ -1158,28 +1166,32 @@ void SLAPrint::process() const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill; const double tilt_time = is_fast_layer ? fast_tilt : slow_tilt; - if (is_fast_layer) - fast_layers++; - else - slow_layers++; + + { Lock lck(mutex); + if (is_fast_layer) + fast_layers++; + else + slow_layers++; - // Calculation of the printing time + // Calculation of the printing time - if (sliced_layer_cnt < 3) - estim_time += init_exp_time; - else if (fade_layer_time > exp_time) - { - fade_layer_time -= delta_fade_time; - estim_time += fade_layer_time; + if (sliced_layer_cnt < 3) + estim_time += init_exp_time; + else if (fade_layer_time > exp_time) + { + fade_layer_time -= delta_fade_time; + estim_time += fade_layer_time; + } + else + estim_time += exp_time; + + estim_time += tilt_time; } - else - estim_time += exp_time; + }; - estim_time += tilt_time; - - sliced_layer_cnt++; - } + for(size_t i = 0; i < m_printer_input.size(); ++i) printlayerfn(i); +// tbb::parallel_for(0, m_printer_input.size(), printlayerfn); m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR; m_print_statistics.objects_used_material = models_volume * SCALING_FACTOR * SCALING_FACTOR; From 19dc89bfab33fd242c105fa90a17f26ba2f4b5ec 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 f9db9fea0..ffb80c573 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 eaa11b738..467c44a8a 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 a4387e5c1..b204a9a3e 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 69199215b0be02799f40e4e24e3292f6dd62b43e 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 ffb80c573..b5b9a008d 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 467c44a8a..9a1a9def4 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 c13df4546..dfd72b7a9 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 4a9e05194c57e2fd2c00459828ba7509bc73b883 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 9a1a9def4..759568860 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 cd3cec3e45535ab42f7e36d50730299a91dada3e 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 b5b9a008d..a9835eaa1 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 8a48f8ee9..919e7715c 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 759568860..1baf3cee3 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 b204a9a3e..e538b7693 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 2baa651f1e21b81a00bf23975fce711c5642e4ae 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 15eeb57b8..232668f61 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp +++ b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp @@ -331,8 +331,15 @@ inline std::vector clipper_execute( auto processPoly = [&retv, &processHole](ClipperLib::PolyNode *pptr) { PolygonImpl poly; - poly.Contour.swap(pptr->Contour); auto front_p = poly.Contour.front(); - poly.Contour.emplace_back(std::move(front_p)); + poly.Contour.swap(pptr->Contour); + + assert(!pptr->IsHole()); + + if(pptr->IsOpen()) { + auto front_p = poly.Contour.front(); + poly.Contour.emplace_back(front_p); + } + for(auto h : pptr->Childs) { processHole(h, poly); } retv.push_back(poly); }; @@ -340,8 +347,14 @@ inline std::vector clipper_execute( processHole = [&processPoly](ClipperLib::PolyNode *pptr, PolygonImpl& poly) { poly.Holes.emplace_back(std::move(pptr->Contour)); - auto front_p = poly.Holes.back().front(); - poly.Holes.back().emplace_back(std::move(front_p)); + + assert(pptr->IsHole()); + + if(pptr->IsOpen()) { + auto front_p = poly.Holes.back().front(); + poly.Holes.back().emplace_back(front_p); + } + for(auto c : pptr->Childs) processPoly(c); }; diff --git a/src/libslic3r/Rasterizer/Rasterizer.cpp b/src/libslic3r/Rasterizer/Rasterizer.cpp index ab584821f..496a584a2 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.cpp +++ b/src/libslic3r/Rasterizer/Rasterizer.cpp @@ -71,16 +71,41 @@ public: clear(); } - template inline void draw(const Geometry &poly) { + void draw(const ExPolygon &poly) { agg::rasterizer_scanline_aa<> ras; agg::scanline_p8 scanlines; - auto&& path = to_path(poly); + auto&& path = to_path(poly.contour); if(m_o == Origin::TOP_LEFT) flipy(path); ras.add_path(path); + for(auto h : poly.holes) { + auto&& holepath = to_path(h); + if(m_o == Origin::TOP_LEFT) flipy(holepath); + ras.add_path(holepath); + } + + agg::render_scanlines(ras, scanlines, m_renderer); + } + + void draw(const ClipperLib::Polygon &poly) { + agg::rasterizer_scanline_aa<> ras; + agg::scanline_p8 scanlines; + + auto&& path = to_path(poly.Contour); + + if(m_o == Origin::TOP_LEFT) flipy(path); + + ras.add_path(path); + + for(auto h : poly.Holes) { + auto&& holepath = to_path(h); + if(m_o == Origin::TOP_LEFT) flipy(holepath); + ras.add_path(holepath); + } + agg::render_scanlines(ras, scanlines, m_renderer); } @@ -186,14 +211,12 @@ void Raster::clear() void Raster::draw(const ExPolygon &expoly) { - m_impl->draw(expoly.contour); - for(auto& h : expoly.holes) m_impl->draw(h); + m_impl->draw(expoly); } void Raster::draw(const ClipperLib::Polygon &poly) { - m_impl->draw(poly.Contour); - for(auto& h : poly.Holes) m_impl->draw(h); + m_impl->draw(poly); } void Raster::save(std::ostream& stream, Compression comp) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index a5aa826c9..424881491 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1084,9 +1084,15 @@ void SLAPrint::process() SpinMutex mutex; using Lock = std::lock_guard; -// for (PrintLayer& layer : m_printer_input) - auto printlayerfn = [this, get_all_polygons, polyunion, polydiff, areafn, area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, delta_fade_time, - &mutex, &models_volume, &supports_volume, &estim_time, &slow_layers, &fast_layers, &fade_layer_time](size_t sliced_layer_cnt) + // Going to parallel: + auto printlayerfn = [this, + // functions and read only vars + get_all_polygons, polyunion, polydiff, areafn, + area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, delta_fade_time, + + // write vars + &mutex, &models_volume, &supports_volume, &estim_time, &slow_layers, + &fast_layers, &fade_layer_time](size_t sliced_layer_cnt) { PrintLayer& layer = m_printer_input[sliced_layer_cnt]; @@ -1141,9 +1147,9 @@ void SLAPrint::process() } if(!supports_polygons.empty()) { - /*if(model_polygons.empty()) */supports_polygons = polyunion(supports_polygons); - /*else */ if(!model_polygons.empty())supports_polygons = polydiff(supports_polygons, model_polygons); - // allegedly, union of subject is done withing the diff + if(model_polygons.empty()) supports_polygons = polyunion(supports_polygons); + else supports_polygons = polydiff(supports_polygons, model_polygons); + // allegedly, union of subject is done withing the diff according to the pftPositive polyFillType } double layer_support_area = 0; @@ -1190,8 +1196,9 @@ void SLAPrint::process() } }; - for(size_t i = 0; i < m_printer_input.size(); ++i) printlayerfn(i); -// tbb::parallel_for(0, m_printer_input.size(), printlayerfn); + // sequential version for debugging: + // for(size_t i = 0; i < m_printer_input.size(); ++i) printlayerfn(i); + tbb::parallel_for(0, m_printer_input.size(), printlayerfn); m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR; m_print_statistics.objects_used_material = models_volume * SCALING_FACTOR * SCALING_FACTOR; From d728f4be5e9a4c78c85a8e0bc1880b4cdb025f9c 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 a9835eaa1..b5b9a008d 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 919e7715c..8a48f8ee9 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 1baf3cee3..759568860 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 e538b7693..b204a9a3e 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 d4b22cfb87f8b6bc9c8c7ec34158be2e852450e8 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 5d286846b..34b5f4067 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 200f239c1..4b2a72d7c 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 32a49d1468344f43722330bcdcc9495a6e35af61 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 5198eeaa3..958b66305 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 88cc93cdc94ffd95c76d14ddfae2e0b11eb1f320 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 4178dcb43..31c3717ff 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 fdb8968d3..f1a7d9263 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 f626fa7f5..001e0b33f 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 7e022532a..476379da2 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 fbce7b001b8449d2a5bcee3a6fc4185e6626462c 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 759568860..c145380c9 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 b204a9a3e..a65a4be75 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 5f66a2d181aa1f249f7b9ba9b048182c59318f38 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 d83ef9ed8..d094225ac 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 b8289c32b0a099abdc8d73f3b9043bf0470d5449 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 424881491..c7bacaa31 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 c1b7d987a0540e8d686f9b78b0fe9c0e6963bc52 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 913ba76a6..19fbb3bb6 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 a8c8e1866..671dcbb3d 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 e20ffbfd858b36ae090ac3946bedeadec7cf5255 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 d094225ac..c5d0f28ed 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 75990923f7b74ddb97bf0d12f977a18c8c46fad2 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 1a294d210..5da818395 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 9e0803325..26596f629 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 1201d23a4..742ae00e6 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 145b8fd0dfa013d7965fba1ac8fb51694a2310d4 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 5da818395..8095a3237 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 c542413962eb4f49c28d19a36b4b9546a064968e 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 31c3717ff..e6365e32a 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 566090504..02d663e93 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 001e0b33f..b008c17a7 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 476379da2..84a60e3d1 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 a3dcb6863e1887319fb74a655aab08e13bccc4f0 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 9e9f07b6c..0a2537b91 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 038b505da..d32d182bc 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 c7bacaa31..454fbe78b 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 9cf826097..54128e3bf 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 adf9c4bd40afa3e1cfd50e5988aa7ae46987cc20 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 34b5f4067..7103ca12d 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 9d5eb2cd48b84a079f6f5adcb48ae63aed5af09e 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 c5d0f28ed..75f13cdcf 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 6a745649001133420fadd4e7c31b48c8860558f5 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 454fbe78b..0304363f6 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 086f11df98c20d133baac7367ffda2988eb0cd7d 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 380245b5f..d556f664c 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 8a48f8ee9..3d476cbb0 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 c7bacaa31..04778f584 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 9cf826097..272252a2a 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 58011730b..7ba61bdb6 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 e421997e5..5cc301a39 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 31c3717ff..862ce74b7 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 2b1061c95..7e414d52a 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 14d19e251..438e9d236 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 96c49e54f..a2929f2e6 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 c92c22c50..435d9548f 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 e1177b1810bffcbf6c19e7a142e260deeec3f18e 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 3d476cbb0..5cf7f49ca 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 f147da1e5d9d341ca83a67dee3029c9e82f27598 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 eb934ba7d..1ae4d642f 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 ba4f0445c361c24bde074e1ab321debef5614a18 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 1ae4d642f..ca3f6261b 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 1979baf619025cd8bb1c7524e69e93546e9bba48 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 ca3f6261b..a600f9ce1 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 b008c17a7..1b4d4edf9 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 84a60e3d1..c1bf491e1 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 66fce6d46c7b6c0274026ba5edbba023b84fff7f 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 4663fe447..81d01958d 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 c0ab616b0..a1e382acb 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 eeae1c0495ba74ab7a9f89df100db40de36e38e6 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 81d01958d..7dc920517 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 a600f9ce1..79a3684ef 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(); }