diff --git a/src/libslic3r/PrintExport.hpp b/src/libslic3r/PrintExport.hpp index 917a39e08..60bc7dbe6 100644 --- a/src/libslic3r/PrintExport.hpp +++ b/src/libslic3r/PrintExport.hpp @@ -1,22 +1,21 @@ #ifndef PRINTEXPORT_HPP #define PRINTEXPORT_HPP -#include "Print.hpp" - // For png export of the sliced model #include #include +#include #include #include "Rasterizer/Rasterizer.hpp" -#include -#include //#include "tbb/mutex.h" +//#include +//#include //#include "tbb/mutex.h" namespace Slic3r { enum class FilePrinterFormat { - PNG, + SLA_PNGZIP, SVG }; @@ -28,7 +27,7 @@ enum class FilePrinterFormat { * different implementations of this class template for each supported format. * */ -template +template class FilePrinter { public: @@ -69,15 +68,17 @@ public: void save_layer(unsigned lyr, const std::string& path); }; +// Provokes static_assert in the right way. template struct VeryFalse { static const bool value = false; }; // This has to be explicitly implemented in the gui layer or a default zlib -// based implementation is needed. -template class LayerWriter { +// based implementation is needed. I don't have time for that and I'm delegating +// the implementation to the gui layer where the gui toolkit can cover this. +template class LayerWriter { public: LayerWriter(const std::string& /*zipfile_path*/) { - static_assert(VeryFalse::value, + static_assert(VeryFalse::value, "No layer writer implementation provided!"); } @@ -97,8 +98,8 @@ public: // Implementation for PNG raster output // Be aware that if a large number of layers are allocated, it can very well // exhaust the available memory especially on 32 bit platform. -template class FilePrinter { - +template<> class FilePrinter +{ struct Layer { Raster first; std::stringstream second; @@ -115,13 +116,11 @@ template class FilePrinter { std::vector m_layers_rst; Raster::Resolution m_res; Raster::PixelDim m_pxdim; - const Print *m_print = nullptr; double m_exp_time_s = .0, m_exp_time_first_s = .0; + double m_layer_height = .0; std::string createIniContent(const std::string& projectname) { - double layer_height = m_print? - m_print->default_object_config().layer_height.getFloat() : - 0.05; + double layer_height = m_layer_height; using std::string; using std::to_string; @@ -154,11 +153,13 @@ template class FilePrinter { public: inline FilePrinter(double width_mm, double height_mm, unsigned width_px, unsigned height_px, + double layer_height, double exp_time, double exp_time_first): m_res(width_px, height_px), m_pxdim(width_mm/width_px, height_mm/height_px), m_exp_time_s(exp_time), - m_exp_time_first_s(exp_time_first) + m_exp_time_first_s(exp_time_first), + m_layer_height(layer_height) { } @@ -171,8 +172,6 @@ public: inline void layers(unsigned cnt) { if(cnt > 0) m_layers_rst.resize(cnt); } inline unsigned layers() const { return unsigned(m_layers_rst.size()); } - void print_config(const Print& printconf) { m_print = &printconf; } - inline void draw_polygon(const ExPolygon& p, unsigned lyr) { assert(lyr < m_layers_rst.size()); m_layers_rst[lyr].first.draw(p); @@ -203,9 +202,10 @@ public: } } + template inline void save(const std::string& path) { try { - LayerWriter writer(path); + LayerWriter writer(path); std::string project = writer.get_name(); @@ -250,145 +250,145 @@ public: } }; -// Let's shadow this eigen interface -inline coord_t px(const Point& p) { return p(0); } -inline coord_t py(const Point& p) { return p(1); } -inline coordf_t px(const Vec2d& p) { return p(0); } -inline coordf_t py(const Vec2d& p) { return p(1); } +//// Let's shadow this eigen interface +//inline coord_t px(const Point& p) { return p(0); } +//inline coord_t py(const Point& p) { return p(1); } +//inline coordf_t px(const Vec2d& p) { return p(0); } +//inline coordf_t py(const Vec2d& p) { return p(1); } -template -void print_to(Print& print, - std::string dirpath, - double width_mm, - double height_mm, - Args&&...args) -{ +//template +//void print_to(Print& print, +// std::string dirpath, +// double width_mm, +// double height_mm, +// Args&&...args) +//{ - std::string& dir = dirpath; +// std::string& dir = dirpath; - // This map will hold the layers sorted by z coordinate. Layers on the - // same height (from different objects) will be mapped to the same key and - // rasterized to the same image. - std::map layers; +// // This map will hold the layers sorted by z coordinate. Layers on the +// // same height (from different objects) will be mapped to the same key and +// // rasterized to the same image. +// std::map layers; - auto& objects = print.objects(); +// auto& objects = print.objects(); - // Merge the sliced layers with the support layers - std::for_each(objects.cbegin(), objects.cend(), - [&layers](const PrintObject *o) - { - for(const auto l : o->layers()) { - auto& lyrs = layers[static_cast(scale_(l->print_z))]; - lyrs.push_back(l); - } +// // Merge the sliced layers with the support layers +// std::for_each(objects.cbegin(), objects.cend(), +// [&layers](const PrintObject *o) +// { +// for(const auto l : o->layers()) { +// auto& lyrs = layers[static_cast(scale_(l->print_z))]; +// lyrs.push_back(l); +// } - for(const auto l : o->support_layers()) { - auto& lyrs = layers[static_cast(scale_(l->print_z))]; - lyrs.push_back(l); - } - }); +// for(const auto l : o->support_layers()) { +// auto& lyrs = layers[static_cast(scale_(l->print_z))]; +// lyrs.push_back(l); +// } +// }); - auto print_bb = print.bounding_box(); - Vec2d punsc = unscale(print_bb.size()); +// auto print_bb = print.bounding_box(); +// Vec2d punsc = unscale(print_bb.size()); - // If the print does not fit into the print area we should cry about it. - if(px(punsc) > width_mm || py(punsc) > height_mm) { - BOOST_LOG_TRIVIAL(warning) << "Warning: Print will not fit!" << "\n" - << "Width needed: " << px(punsc) << "\n" - << "Height needed: " << py(punsc) << "\n"; - } +// // If the print does not fit into the print area we should cry about it. +// if(px(punsc) > width_mm || py(punsc) > height_mm) { +// BOOST_LOG_TRIVIAL(warning) << "Warning: Print will not fit!" << "\n" +// << "Width needed: " << px(punsc) << "\n" +// << "Height needed: " << py(punsc) << "\n"; +// } - // Offset for centering the print onto the print area - auto cx = scale_(width_mm)/2 - (px(print_bb.center()) - px(print_bb.min)); - auto cy = scale_(height_mm)/2 - (py(print_bb.center()) - py(print_bb.min)); +// // Offset for centering the print onto the print area +// auto cx = scale_(width_mm)/2 - (px(print_bb.center()) - px(print_bb.min)); +// auto cy = scale_(height_mm)/2 - (py(print_bb.center()) - py(print_bb.min)); - // Create the actual printer, forward any additional arguments to it. - FilePrinter printer(width_mm, height_mm, - std::forward(args)...); +// // Create the actual printer, forward any additional arguments to it. +// FilePrinter printer(width_mm, height_mm, +// std::forward(args)...); - printer.print_config(print); +// printer.print_config(print); - printer.layers(layers.size()); // Allocate space for all the layers +// printer.layers(layers.size()); // Allocate space for all the layers - int st_prev = 0; - const std::string jobdesc = "Rasterizing and compressing sliced layers"; - tbb::spin_mutex m; +// int st_prev = 0; +// const std::string jobdesc = "Rasterizing and compressing sliced layers"; +// tbb::spin_mutex m; - std::vector keys; - keys.reserve(layers.size()); - for(auto& e : layers) keys.push_back(e.first); +// std::vector keys; +// keys.reserve(layers.size()); +// for(auto& e : layers) keys.push_back(e.first); - print.set_status(0, jobdesc); +// print.set_status(0, jobdesc); - // Method that prints one layer - auto process_layer = [&layers, &keys, &printer, &st_prev, &m, - &jobdesc, print_bb, dir, cx, cy, &print] - (unsigned layer_id) - { - LayerPtrs lrange = layers[keys[layer_id]]; +// // Method that prints one layer +// auto process_layer = [&layers, &keys, &printer, &st_prev, &m, +// &jobdesc, print_bb, dir, cx, cy, &print] +// (unsigned layer_id) +// { +// LayerPtrs lrange = layers[keys[layer_id]]; - printer.begin_layer(layer_id); // Switch to the appropriate layer +// printer.begin_layer(layer_id); // Switch to the appropriate layer - for(Layer *lp : lrange) { - Layer& l = *lp; +// for(Layer *lp : lrange) { +// Layer& l = *lp; - ExPolygonCollection slices = l.slices; // Copy the layer slices +// ExPolygonCollection slices = l.slices; // Copy the layer slices - // Sort the polygons in the layer - std::stable_sort(slices.expolygons.begin(), slices.expolygons.end(), - [](const ExPolygon& a, const ExPolygon& b) { - return a.contour.contains(b.contour.first_point()) ? false : - true; - }); +// // Sort the polygons in the layer +// std::stable_sort(slices.expolygons.begin(), slices.expolygons.end(), +// [](const ExPolygon& a, const ExPolygon& b) { +// return a.contour.contains(b.contour.first_point()) ? false : +// true; +// }); - // Draw all the polygons in the slice to the actual layer. - for (const Point &d : l.object()->copies()) - for (ExPolygon slice : slices.expolygons) { - slice.translate(px(d), py(d)); - slice.translate(-px(print_bb.min) + cx, - -py(print_bb.min) + cy); +// // Draw all the polygons in the slice to the actual layer. +// for (const Point &d : l.object()->copies()) +// for (ExPolygon slice : slices.expolygons) { +// slice.translate(px(d), py(d)); +// slice.translate(-px(print_bb.min) + cx, +// -py(print_bb.min) + cy); - printer.draw_polygon(slice, layer_id); - } +// printer.draw_polygon(slice, layer_id); +// } - /*if(print.has_support_material() && layer_id > 0) { - BOOST_LOG_TRIVIAL(warning) << "support material for layer " - << layer_id - << " defined but export is " - "not yet implemented."; +// /*if(print.has_support_material() && layer_id > 0) { +// BOOST_LOG_TRIVIAL(warning) << "support material for layer " +// << layer_id +// << " defined but export is " +// "not yet implemented."; - }*/ +// }*/ - } +// } - printer.finish_layer(layer_id); // Finish the layer for later saving it. +// printer.finish_layer(layer_id); // Finish the layer for later saving it. - auto st = static_cast(layer_id*80.0/layers.size()); - m.lock(); - if( st - st_prev > 10) { - print.set_status(st, jobdesc); - st_prev = st; - } - m.unlock(); +// auto st = static_cast(layer_id*80.0/layers.size()); +// m.lock(); +// if( st - st_prev > 10) { +// print.set_status(st, jobdesc); +// st_prev = st; +// } +// m.unlock(); - // printer.saveLayer(layer_id, dir); We could save the layer immediately - }; +// // printer.saveLayer(layer_id, dir); We could save the layer immediately +// }; - // Print all the layers in parallel - tbb::parallel_for(0, - layers.size(), - process_layer); +// // Print all the layers in parallel +// tbb::parallel_for(0, +// layers.size(), +// process_layer); - // Sequential version (for testing) - // for(unsigned l = 0; l < layers.size(); ++l) process_layer(l); +// // Sequential version (for testing) +// // for(unsigned l = 0; l < layers.size(); ++l) process_layer(l); -// print.set_status(100, jobdesc); +//// print.set_status(100, jobdesc); - // Save the print into the file system. - print.set_status(90, "Writing layers to disk"); - printer.save(dir); - print.set_status(100, "Writing layers completed"); -} +// // Save the print into the file system. +// print.set_status(90, "Writing layers to disk"); +// printer.save(dir); +// print.set_status(100, "Writing layers completed"); +//} } diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp index c95dcef34..42799ffd0 100644 --- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp +++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp @@ -57,7 +57,7 @@ void SpatIndex::insert(const SpatElement &el) bool SpatIndex::remove(const SpatElement& el) { - return m_impl->m_store.remove(el); + return m_impl->m_store.remove(el) == 1; } std::vector diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 27b4d25ed..d062405c1 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1,6 +1,9 @@ #include "SLAPrint.hpp" #include "SLA/SLASupportTree.hpp" +#include +//#include //#include "tbb/mutex.h" + #include "I18N.hpp" //! macro used to mark string used at localization, @@ -9,12 +12,15 @@ namespace Slic3r { +using SlicedModel = SlicedSupports; +using SupportTreePtr = std::unique_ptr; + class SLAPrintObject::SupportData { public: - sla::EigenMesh3D emesh; // index-triangle representation - sla::PointSet support_points; // all the support points (manual/auto) - std::unique_ptr support_tree_ptr; // the supports - SlicedSupports slice_cache; // sliced supports + sla::EigenMesh3D emesh; // index-triangle representation + sla::PointSet support_points; // all the support points (manual/auto) + SupportTreePtr support_tree_ptr; // the supports + SlicedSupports support_slices; // sliced supports }; namespace { @@ -88,8 +94,14 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, m_model.assign_copy(model); // Generate new SLAPrintObjects. for (ModelObject *model_object : m_model.objects) { - //TODO - m_objects.emplace_back(new SLAPrintObject(this, model_object)); + auto po = new SLAPrintObject(this, model_object); + m_objects.emplace_back(po); + for(ModelInstance *oinst : model_object->instances) { + Point tr = Point::new_scale(oinst->get_offset()(X), + oinst->get_offset()(Y)); + auto rotZ = float(oinst->get_rotation()(Z)); + po->m_instances.emplace_back(tr, rotZ); + } } } @@ -105,19 +117,33 @@ void SLAPrint::process() // Assumption: at this point the print objects should be populated only with // the model objects we have to process and the instances are also filtered - auto slice_model = [](const SLAPrintObject&) { + // shortcut to initial layer height + auto ilh = float(m_material_config.initial_layer_height.getFloat()); + auto slice_model = [ilh](SLAPrintObject& po) { + auto lh = float(po.m_config.layer_height.getFloat()); + ModelObject *o = po.m_model_object; + + TriangleMesh&& mesh = o->raw_mesh(); + TriangleMeshSlicer slicer(&mesh); + auto bb3d = mesh.bounding_box(); + + auto H = bb3d.max(Z) - bb3d.min(Z); + std::vector heights = {ilh}; + for(float h = ilh; h < H; h += lh) heights.emplace_back(h); + auto& layers = po.m_model_slices; + slicer.slice(heights, &layers, [](){}); }; - auto support_points = [](const SLAPrintObject&) { + auto support_points = [](SLAPrintObject&) { // for(SLAPrintObject *po : pobjects) { // TODO: calculate automatic support points // po->m_supportdata->slice_cache contains the slices at this point //} }; - auto support_tree = [this](const SLAPrintObject& po) { + auto support_tree = [this](SLAPrintObject& po) { auto& emesh = po.m_supportdata->emesh; auto& pts = po.m_supportdata->support_points; // nowhere filled yet auto& supportd = *po.m_supportdata; @@ -141,19 +167,112 @@ void SLAPrint::process() } }; - auto base_pool = [](const SLAPrintObject&) { + auto base_pool = [](SLAPrintObject&) { }; - auto slice_supports = [](const SLAPrintObject&) { + auto slice_supports = [](SLAPrintObject&) { }; - auto rasterize = []() { + auto rasterize = [this, ilh]() { + using Layer = ExPolygons; + using LayerCopies = std::vector; + struct LayerRef { + std::reference_wrapper lref; + std::reference_wrapper copies; + LayerRef(const Layer& lyr, const LayerCopies& cp) : + lref(std::cref(lyr)), copies(std::cref(cp)) {} + }; + using LayerRefs = std::vector; + + // layers according to quantized height levels + std::map levels; + + // For all print objects, go through its initial layers and place them + // into the layers hash + long long initlyridx = static_cast(scale_(ilh)); + for(SLAPrintObject *o : m_objects) { + auto& oslices = o->m_model_slices; + auto& firstlyr = oslices.front(); + auto& initlevel = levels[initlyridx]; + initlevel.emplace_back(firstlyr, o->m_instances); + double lh = o->m_config.layer_height.getFloat(); + + size_t li = 1; + for(auto lit = std::next(oslices.begin()); + lit != oslices.end(); + ++lit) + { + double h = ilh + li++ * lh; + long long lyridx = static_cast(scale_(h)); + auto& lyrs = levels[lyridx]; + lyrs.emplace_back(*lit, o->m_instances); + } + } + + // collect all the keys + std::vector keys; keys.reserve(levels.size()); + for(auto& e : levels) keys.emplace_back(e.first); + + { // create a raster printer for the current print parameters + // I don't know any better + auto& ocfg = m_objects.front()->m_config; + auto& matcfg = m_material_config; + auto& printcfg = m_printer_config; + + double w = printcfg.display_width.getFloat(); + double h = printcfg.display_height.getFloat(); + unsigned pw = printcfg.display_pixels_x.getInt(); + unsigned ph = printcfg.display_pixels_y.getInt(); + double lh = ocfg.layer_height.getFloat(); + double exp_t = matcfg.exposure_time.getFloat(); + double iexp_t = matcfg.initial_exposure_time.getFloat(); + + m_printer.reset(new SLAPrinter(w, h, pw, ph, lh, exp_t, iexp_t)); + } + + // Allocate space for all the layers + SLAPrinter& printer = *m_printer; + printer.layers(unsigned(levels.size())); + + // procedure to process one height level. This will run in parallel + auto process_level = [&keys, &levels, &printer](unsigned level_id) { + LayerRefs& lrange = levels[keys[level_id]]; + + for(auto& lyrref : lrange) { // for all layers in the current level + const Layer& l = lyrref.lref; // get the layer reference + const LayerCopies& copies = lyrref.copies; + ExPolygonCollection sl = l; + + // Switch to the appropriate layer in the printer + printer.begin_layer(level_id); + + // Draw all the polygons in the slice to the actual layer. + for(auto& cp : copies) { + for(ExPolygon slice : sl.expolygons) { + slice.translate(cp.shift(X), cp.shift(Y)); + slice.rotate(cp.rotation); + printer.draw_polygon(slice, level_id); + } + } + + // Finish the layer for later saving it. + printer.finish_layer(level_id); + } + }; + + // Sequential version (for testing) + // for(unsigned l = 0; l < levels.size(); ++l) process_level(l); + + // Print all the layers in parallel + tbb::parallel_for(0, + levels.size(), + process_level); }; - using slaposFn = std::function; + using slaposFn = std::function; using slapsFn = std::function; std::array objectsteps = { @@ -168,7 +287,7 @@ void SLAPrint::process() std::array pobj_program = { slice_model, - [](const SLAPrintObject&){}, // slaposSupportIslands now empty + [](SLAPrintObject&){}, // slaposSupportIslands now empty support_points, support_tree, base_pool, @@ -229,11 +348,6 @@ void SLAPrint::render_supports(SLASupportRenderer &renderer) std::cout << "Would show the SLA supports" << std::endl; } -void SLAPrint::export_raster(const std::string &fname) -{ - std::cout << "Would export the SLA raster" << std::endl; -} - SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object): Inherited(print), m_model_object(model_object), @@ -242,6 +356,7 @@ SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object): { m_supportdata->emesh = sla::to_eigenmesh(*m_model_object); m_supportdata->support_points = sla::support_points(*m_model_object); + std::cout << "support points copied " << m_supportdata->support_points.rows() << std::endl; } diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 3a6e73ff3..7a3af4b76 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -2,6 +2,7 @@ #define slic3r_SLAPrint_hpp_ #include "PrintBase.hpp" +#include "PrintExport.hpp" #include "Point.hpp" namespace Slic3r { @@ -58,8 +59,10 @@ protected: // Slic3r::Point objects in scaled G-code coordinates Point shift; // Rotation along the Z axis, in radians. - float rotation; + float rotation; + Instance(const Point& tr, float rotZ): shift(tr), rotation(rotZ) {} }; + bool set_instances(const std::vector &instances); // Invalidates the step, and its depending steps in SLAPrintObject and SLAPrint. bool invalidate_step(SLAPrintObjectStep step); @@ -75,6 +78,7 @@ private: // Which steps have to be performed. Implicitly: all std::vector m_stepmask; + std::vector m_model_slices; class SupportData; std::unique_ptr m_supportdata; @@ -132,6 +136,7 @@ private: // Prevents erroneous use by other classes. public: SLAPrint(): m_stepmask(slapsCount, true) {} + virtual ~SLAPrint() { this->clear(); } PrinterTechnology technology() const noexcept { return ptSLA; } @@ -143,14 +148,21 @@ public: void render_supports(SLASupportRenderer& renderer); - void export_raster(const std::string& fname); + template void export_raster(const std::string& fname) { + if(m_printer) m_printer->save(fname); + std::cout << "Would export the SLA raster" << std::endl; + } private: + using SLAPrinter = FilePrinter; + using SLAPrinterPtr = std::unique_ptr; + Model m_model; SLAPrinterConfig m_printer_config; SLAMaterialConfig m_material_config; PrintObjects m_objects; std::vector m_stepmask; + SLAPrinterPtr m_printer; friend SLAPrintObject; }; diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 7e1908b64..b914e0af6 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -6,6 +6,11 @@ #include #include +// For zipped archive creation +#include +#include +#include + // Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx. #include "libslic3r/Print.hpp" #include "libslic3r/SLAPrint.hpp" @@ -75,13 +80,53 @@ void BackgroundSlicingProcess::process_fff() } } +// Pseudo type for specializing LayerWriter trait class +struct SLAZipFmt {}; + +// The implementation of creating zipped archives with wxWidgets +template<> class LayerWriter { + wxFileName fpath; + wxFFileOutputStream zipfile; + wxZipOutputStream zipstream; + wxStdOutputStream pngstream; + +public: + + inline LayerWriter(const std::string& zipfile_path): + fpath(zipfile_path), + zipfile(zipfile_path), + zipstream(zipfile), + pngstream(zipstream) + { + if(!zipfile.IsOk()) + throw std::runtime_error("Cannot create zip file."); + } + + inline void next_entry(const std::string& fname) { + zipstream.PutNextEntry(fname); + } + + inline std::string get_name() const { + return fpath.GetName().ToStdString(); + } + + template inline LayerWriter& operator<<(const T& arg) { + pngstream << arg; return *this; + } + + inline void close() { + zipstream.Close(); + zipfile.Close(); + } +}; + void BackgroundSlicingProcess::process_sla() { assert(m_print == m_sla_print); m_print->process(); if(!m_print->canceled() && ! this->is_step_done(bspsGCodeFinalize)) { this->set_step_started(bspsGCodeFinalize); if (! m_export_path.empty()) { - m_sla_print->export_raster(m_export_path); + m_sla_print->export_raster(m_export_path); m_print->set_status(100, "Zip file exported to " + m_export_path); } this->set_step_done(bspsGCodeFinalize);