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 ea06b0561..7448c85cd 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 { @@ -75,8 +81,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, return APPLY_STATUS_UNCHANGED; // Temporary quick fix, just invalidate everything. - { - std::cout << "deleting object cache " << std::endl; + { for (SLAPrintObject *print_object : m_objects) { print_object->invalidate_all_steps(); delete print_object; @@ -89,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); + } } } @@ -106,19 +117,36 @@ 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()); + // Slicing the model object. This method is oversimplified and needs to + // be compared with the fff slicing algorithm for verification + 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) { + // In this step we create the supports + 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; @@ -142,19 +170,119 @@ void SLAPrint::process() } }; - auto base_pool = [](const SLAPrintObject&) { + // This step generates the sla base pad + auto base_pool = [](SLAPrintObject&) { }; - auto slice_supports = [](const SLAPrintObject&) { + // Slicing the support geometries similarly to the model slicing procedure + auto slice_supports = [](SLAPrintObject&) { }; - auto rasterize = []() { + // Rasterizing the model objects, and their supports + 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); + + // now push the support slices as well + // TODO + + 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 = { slaposObjectSlice, @@ -165,18 +293,24 @@ void SLAPrint::process() slaposSliceSupports }; - std::array fullprogram = + std::array pobj_program = { slice_model, - [](const SLAPrintObject&){}, // slaposSupportIslands now empty + [](SLAPrintObject&){}, // slaposSupportIslands now empty support_points, support_tree, base_pool, slice_supports }; + std::array print_program = + { + rasterize, + [](){} // validate + }; + for(SLAPrintObject * po : m_objects) { - for(size_t s = 0; s < fullprogram.size(); ++s) { + for(size_t s = 0; s < pobj_program.size(); ++s) { auto currentstep = objectsteps[s]; // Cancellation checking. Each step will check for cancellation @@ -184,16 +318,38 @@ void SLAPrint::process() // execution gets to this point and throws the canceled signal. throw_if_canceled(); - if(po->m_stepmask[s]) { + if(po->m_stepmask[s] && !po->is_step_done(currentstep)) { set_status(OBJ_STEP_LEVELS[currentstep], OBJ_STEP_LABELS[currentstep]); po->set_started(currentstep); - fullprogram[s](*po); + pobj_program[s](*po); po->set_done(currentstep); } } } + + std::array printsteps = { + slapsRasterize, slapsValidate + }; + + for(size_t s = 0; s < print_program.size(); ++s) { + auto currentstep = printsteps[s]; + + throw_if_canceled(); + + if(m_stepmask[s] && !is_step_done(currentstep)) { + set_status(PRINT_STEP_LEVELS[currentstep], + PRINT_STEP_LABELS[currentstep]); + + set_started(currentstep); + print_program[s](); + set_done(currentstep); + } + } + + // If everything vent well + set_status(100, L("Slicing done")); } void SLAPrint::render_supports(SLASupportRenderer &renderer) @@ -209,6 +365,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 94040ce38..7e0d0b2c2 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 { @@ -85,6 +86,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; @@ -141,7 +143,8 @@ private: // Prevents erroneous use by other classes. typedef PrintBaseWithState Inherited; public: - SLAPrint() {} + SLAPrint(): m_stepmask(slapsCount, true) {} + virtual ~SLAPrint() { this->clear(); } PrinterTechnology technology() const noexcept { return ptSLA; } @@ -153,13 +156,22 @@ public: void render_supports(SLASupportRenderer& renderer); + template void export_raster(const std::string& fname) { + if(m_printer) m_printer->save(fname); + std::cout << "Would export the SLA raster" << std::endl; + } const PrintObjects& objects() const { return m_objects; } 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 d6bb01c87..5dcef44a1 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,6 +80,59 @@ 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_print->set_status(100, "Zip file exported to " + m_export_path); + } + this->set_step_done(bspsGCodeFinalize); + } +} + void BackgroundSlicingProcess::thread_proc() { assert(m_print != nullptr); @@ -100,6 +158,7 @@ void BackgroundSlicingProcess::thread_proc() assert(m_print != nullptr); switch(m_print->technology()) { case ptFFF: this->process_fff(); break; + case ptSLA: this->process_sla(); break; default: m_print->process(); break; } } catch (CanceledException & /* ex */) { diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index da3eb776e..92bc512d7 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -100,6 +100,9 @@ private: // Helper to wrap the FFF slicing & G-code generation. void process_fff(); + // Temporary: for mimicking the fff file export behavior with the raster output + void process_sla(); + // Currently active print. It is one of m_fff_print and m_sla_print. PrintBase *m_print = nullptr; // Non-owned pointers to Print instances. diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index f23d2ae90..11e7bfe23 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1683,7 +1683,7 @@ void GLGizmoSlaSupports::clicked_on_object(const Vec2d& mouse_position) m_model_object->sla_support_points.push_back(new_pos); // This should trigger the support generation - wxGetApp().plater()->reslice(); + // wxGetApp().plater()->reslice(); } catch (...) {} } @@ -1695,7 +1695,7 @@ void GLGizmoSlaSupports::delete_current_grabber(bool delete_all) m_model_object->sla_support_points.clear(); // This should trigger the support generation - wxGetApp().plater()->reslice(); + // wxGetApp().plater()->reslice(); } else if (m_hover_id != -1) { @@ -1704,7 +1704,7 @@ void GLGizmoSlaSupports::delete_current_grabber(bool delete_all) m_hover_id = -1; // This should trigger the support generation - wxGetApp().plater()->reslice(); + // wxGetApp().plater()->reslice(); } } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 258d153cd..66ac7a979 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -48,6 +48,7 @@ const wxString file_wildcards[FT_SIZE] = { /* FT_INI */ "INI files *.ini|*.ini;*.INI", /* FT_SVG */ "SVG files *.svg|*.svg;*.SVG", + /* FT_PNGZIP */"Zipped PNG files *.zip|*.zip;*.ZIP", // This is lame, but that's what we use for SLA }; @@ -713,4 +714,4 @@ wxNotebook* GUI_App::tab_panel() const } // GUI -} //Slic3r \ No newline at end of file +} //Slic3r diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 3d08b8bd7..ee74d6293 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -38,6 +38,7 @@ enum FileType FT_INI, FT_SVG, + FT_PNGZIP, FT_SIZE, }; @@ -152,4 +153,4 @@ DECLARE_APP(GUI_App) } // GUI } //Slic3r -#endif // slic3r_GUI_App_hpp_ \ No newline at end of file +#endif // slic3r_GUI_App_hpp_ diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index fe3cd48ed..df4cba60b 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -255,8 +255,6 @@ void MainFrame::init_menubar() fileMenu->AppendSeparator(); append_menu_item(fileMenu, wxID_ANY, _(L("Slice to SV&G…\tCtrl+G")), _(L("Slice file to a multi-layer SVG")), [this](wxCommandEvent&) { quick_slice(qsSaveAs | qsExportSVG); }, "shape_handles.png"); - append_menu_item(fileMenu, wxID_ANY, _(L("Slice to PNG…")), _(L("Slice file to a set of PNG files")), - [this](wxCommandEvent&) { slice_to_png(); /*$self->quick_slice(save_as = > 0, export_png = > 1);*/ }, "shape_handles.png"); m_menu_item_reslice_now = append_menu_item(fileMenu, wxID_ANY, _(L("(&Re)Slice Now\tCtrl+S")), _(L("Start new slicing process")), [this](wxCommandEvent&) { reslice_now(); }, "shape_handles.png"); fileMenu->AppendSeparator(); @@ -358,13 +356,6 @@ void MainFrame::init_menubar() } } -void MainFrame::slice_to_png() -{ -// m_plater->stop_background_process(); -// m_plater->async_apply_config(); -// m_appController->print_ctl()->slice_to_png(); -} - // To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG". void MainFrame::quick_slice(const int qs) { diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index eb45e155e..e00216cbc 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -83,7 +83,6 @@ public: bool is_loaded() const { return m_loaded; } bool is_last_input_file() const { return !m_qs_last_input_file.IsEmpty(); } - void slice_to_png(); void quick_slice(const int qs = qsUndef); void reslice_now(); void repair_stl(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 77b817a3d..6e30c6794 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1003,12 +1003,15 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : // Default printer technology for default config. background_process.select_technology(this->printer_technology); // Register progress callback from the Print class to the Platter. - print.set_status_callback([this](int percent, const std::string &message) { + + auto statuscb = [this](int percent, const std::string &message) { wxCommandEvent event(EVT_PROGRESS_BAR); event.SetInt(percent); event.SetString(message); wxQueueEvent(this->q, event.Clone()); - }); + }; + print.set_status_callback(statuscb); + sla_print.set_status_callback(statuscb); this->q->Bind(EVT_PROGRESS_BAR, &priv::on_progress_event, this); _3DScene::add_canvas(canvas3D); @@ -2220,24 +2223,44 @@ void Plater::export_gcode(fs::path output_path) return; } - // Copy the names of active presets into the placeholder parser. - wxGetApp().preset_bundle->export_selections(p->print.placeholder_parser()); + std::string final_path; + if(printer_technology() == ptFFF) { // TODO: custom button for SLA export - // select output file - if (output_path.empty()) { - // XXX: take output path from CLI opts? Ancient Slic3r versions used to do that... + // Copy the names of active presets into the placeholder parser. + wxGetApp().preset_bundle->export_selections(p->print.placeholder_parser()); - // If possible, remove accents from accented latin characters. - // This function is useful for generating file names to be processed by legacy firmwares. - auto default_output_file = fs::path(Slic3r::fold_utf8_to_ascii( - p->print.output_filepath(output_path.string()) - // FIXME: ^ errors to handle? - )); - auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); - wxFileDialog dlg(this, _(L("Save G-code file as:")), - start_dir, - default_output_file.filename().string(), - GUI::file_wildcards[FT_GCODE], + // select output file + if (output_path.empty()) { + // XXX: take output path from CLI opts? Ancient Slic3r versions used to do that... + + // If possible, remove accents from accented latin characters. + // This function is useful for generating file names to be processed by legacy firmwares. + auto default_output_file = fs::path(Slic3r::fold_utf8_to_ascii( + p->print.output_filepath(output_path.string()) + // FIXME: ^ errors to handle? + )); + auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); + + wxFileDialog dlg(this, _(L("Save G-code file as:")), + start_dir, + default_output_file.filename().string(), + GUI::file_wildcards[FT_GCODE], + wxFD_SAVE | wxFD_OVERWRITE_PROMPT + ); + + if (dlg.ShowModal() == wxID_OK) { + fs::path path(dlg.GetPath()); + wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); + output_path = path; + } + } + + final_path = p->print.output_filepath(output_path.string()); + } else { + wxFileDialog dlg(this, _(L("Save Zip file as:")), + wxGetApp().app_config->get_last_output_dir(""), + "out.zip", + GUI::file_wildcards[FT_PNGZIP], wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); @@ -2246,10 +2269,12 @@ void Plater::export_gcode(fs::path output_path) wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); output_path = path; } + + final_path = output_path.string(); } if (! output_path.empty()) { - this->p->background_process.schedule_export(p->print.output_filepath(output_path.string())); + this->p->background_process.schedule_export(final_path); this->p->background_process.start(); } }