diff --git a/xs/src/libslic3r/PrintExport.hpp b/xs/src/libslic3r/PrintExport.hpp index 4de12d3c2..c3c59fc30 100644 --- a/xs/src/libslic3r/PrintExport.hpp +++ b/xs/src/libslic3r/PrintExport.hpp @@ -7,10 +7,6 @@ #include #include -//#include -//#include -//#include - #include #include "Rasterizer/Rasterizer.hpp" @@ -81,14 +77,12 @@ template class Zipper { public: Zipper(const std::string& /*zipfile_path*/) { - // static_assert(Backend>::value, - // "No zipper implementation provided!"); + static_assert(VeryFalse::value, + "No zipper implementation provided!"); } void next_entry(const std::string& /*fname*/) {} - bool is_ok() { return false; } - std::string get_name() { return ""; } template Zipper& operator<<(const T& /*arg*/) { @@ -208,33 +202,32 @@ public: } inline void save(const std::string& path) { + try { + Zipper zipper(path); - Zipper zipper(path); + std::string project = zipper.get_name(); - std::string project = zipper.get_name(); + zipper.next_entry(project); + zipper << createIniContent(project); - if(!zipper.is_ok()) { + for(unsigned i = 0; i < layers_rst_.size(); i++) { + if(layers_rst_[i].second.rdbuf()->in_avail() > 0) { + char lyrnum[6]; + std::sprintf(lyrnum, "%.5d", i); + auto zfilename = project + lyrnum + ".png"; + zipper.next_entry(zfilename); + zipper << layers_rst_[i].second.rdbuf(); + layers_rst_[i].second.str(""); + } + } + + zipper.close(); + } catch(std::exception&) { BOOST_LOG_TRIVIAL(error) << "Can't create zip file for layers! " << path; return; } - zipper.next_entry(project); - zipper << createIniContent(project); - - for(unsigned i = 0; i < layers_rst_.size(); i++) { - if(layers_rst_[i].second.rdbuf()->in_avail() > 0) { - char lyrnum[6]; - std::sprintf(lyrnum, "%.5d", i); - auto zfilename = project + lyrnum + ".png"; - zipper.next_entry(zfilename); - zipper << layers_rst_[i].second.rdbuf(); - layers_rst_[i].second.str(""); - } - } - - zipper.close(); - // wxFileName filepath(path); // wxFFileOutputStream zipfile(path); @@ -294,7 +287,7 @@ 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 +template void print_to(Print& print, std::string dirpath, double width_mm, @@ -312,7 +305,9 @@ void print_to(Print& print, auto& objects = print.objects(); // Merge the sliced layers with the support layers - std::for_each(objects.cbegin(), objects.cend(), [&layers](const PrintObject *o) { + 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); @@ -339,8 +334,8 @@ void print_to(Print& print, 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)...); + FilePrinter printer(width_mm, height_mm, + std::forward(args)...); printer.printConfig(print); @@ -354,14 +349,11 @@ void print_to(Print& print, keys.reserve(layers.size()); for(auto& e : layers) keys.push_back(e.first); - //FIXME - int initstatus = //print.progressindicator? print.progressindicator->state() : - 0; - print.set_status(initstatus, 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, initstatus] + &jobdesc, print_bb, dir, cx, cy, &print] (unsigned layer_id) { LayerPtrs lrange = layers[keys[layer_id]]; @@ -405,7 +397,7 @@ void print_to(Print& print, auto st = static_cast(layer_id*80.0/layers.size()); m.lock(); if( st - st_prev > 10) { - print.set_status(initstatus + st, jobdesc); + print.set_status(st, jobdesc); st_prev = st; } m.unlock(); @@ -424,9 +416,9 @@ void print_to(Print& print, // print.set_status(100, jobdesc); // Save the print into the file system. - print.set_status(initstatus + 90, "Writing layers to disk"); + print.set_status(90, "Writing layers to disk"); printer.save(dir); - print.set_status(initstatus + 100, "Writing layers completed"); + print.set_status(100, "Writing layers completed"); } } diff --git a/xs/src/slic3r/AppController.cpp b/xs/src/slic3r/AppController.cpp index 4a36b5d7f..6728c6c00 100644 --- a/xs/src/slic3r/AppController.cpp +++ b/xs/src/slic3r/AppController.cpp @@ -11,12 +11,17 @@ #include #include -#include #include #include +#include +#include #include #include +#include +#include +#include + namespace Slic3r { class AppControllerBoilerplate::PriData { @@ -43,6 +48,15 @@ namespace GUI { PresetBundle* get_preset_bundle(); } +static const PrintObjectStep STEP_SLICE = posSlice; +static const PrintObjectStep STEP_PERIMETERS = posPerimeters; +static const PrintObjectStep STEP_PREPARE_INFILL = posPrepareInfill; +static const PrintObjectStep STEP_INFILL = posInfill; +static const PrintObjectStep STEP_SUPPORTMATERIAL = posSupportMaterial; +static const PrintStep STEP_SKIRT = psSkirt; +static const PrintStep STEP_BRIM = psBrim; +static const PrintStep STEP_WIPE_TOWER = psWipeTower; + AppControllerBoilerplate::ProgresIndicatorPtr AppControllerBoilerplate::global_progress_indicator() { ProgresIndicatorPtr ret; @@ -62,6 +76,376 @@ void AppControllerBoilerplate::global_progress_indicator( pri_data_->m.unlock(); } +//void PrintController::make_skirt() +//{ +// assert(print_ != nullptr); + +// // prerequisites +// for(auto obj : print_->objects) make_perimeters(obj); +// for(auto obj : print_->objects) infill(obj); +// for(auto obj : print_->objects) gen_support_material(obj); + +// if(!print_->state.is_done(STEP_SKIRT)) { +// print_->state.set_started(STEP_SKIRT); +// print_->skirt.clear(); +// if(print_->has_skirt()) print_->_make_skirt(); + +// print_->state.set_done(STEP_SKIRT); +// } +//} + +//void PrintController::make_brim() +//{ +// assert(print_ != nullptr); + +// // prerequisites +// for(auto obj : print_->objects) make_perimeters(obj); +// for(auto obj : print_->objects) infill(obj); +// for(auto obj : print_->objects) gen_support_material(obj); +// make_skirt(); + +// if(!print_->state.is_done(STEP_BRIM)) { +// print_->state.set_started(STEP_BRIM); + +// // since this method must be idempotent, we clear brim paths *before* +// // checking whether we need to generate them +// print_->brim.clear(); + +// if(print_->config.brim_width > 0) print_->_make_brim(); + +// print_->state.set_done(STEP_BRIM); +// } +//} + +//void PrintController::make_wipe_tower() +//{ +// assert(print_ != nullptr); + +// // prerequisites +// for(auto obj : print_->objects) make_perimeters(obj); +// for(auto obj : print_->objects) infill(obj); +// for(auto obj : print_->objects) gen_support_material(obj); +// make_skirt(); +// make_brim(); + +// if(!print_->state.is_done(STEP_WIPE_TOWER)) { +// print_->state.set_started(STEP_WIPE_TOWER); + +// // since this method must be idempotent, we clear brim paths *before* +// // checking whether we need to generate them +// print_->brim.clear(); + +// if(print_->has_wipe_tower()) print_->_make_wipe_tower(); + +// print_->state.set_done(STEP_WIPE_TOWER); +// } +//} + +//void PrintController::slice(PrintObject *pobj) +//{ +// assert(pobj != nullptr && print_ != nullptr); + +// if(pobj->state.is_done(STEP_SLICE)) return; + +// pobj->state.set_started(STEP_SLICE); + +// pobj->_slice(); + +// auto msg = pobj->_fix_slicing_errors(); +// if(!msg.empty()) report_issue(IssueType::WARN, msg); + +// // simplify slices if required +// if (print_->config.resolution) +// pobj->_simplify_slices(scale_(print_->config.resolution)); + + +// if(pobj->layers.empty()) +// report_issue(IssueType::ERR, +// L("No layers were detected. You might want to repair your " +// "STL file(s) or check their size or thickness and retry") +// ); + +// pobj->state.set_done(STEP_SLICE); +//} + +//void PrintController::make_perimeters(PrintObject *pobj) +//{ +// assert(pobj != nullptr); + +// slice(pobj); + +// if (!pobj->state.is_done(STEP_PERIMETERS)) { +// pobj->_make_perimeters(); +// } +//} + +//void PrintController::infill(PrintObject *pobj) +//{ +// assert(pobj != nullptr); + +// make_perimeters(pobj); + +// if (!pobj->state.is_done(STEP_PREPARE_INFILL)) { +// pobj->state.set_started(STEP_PREPARE_INFILL); + +// pobj->_prepare_infill(); + +// pobj->state.set_done(STEP_PREPARE_INFILL); +// } + +// pobj->_infill(); +//} + +//void PrintController::gen_support_material(PrintObject *pobj) +//{ +// assert(pobj != nullptr); + +// // prerequisites +// slice(pobj); + +// if(!pobj->state.is_done(STEP_SUPPORTMATERIAL)) { +// pobj->state.set_started(STEP_SUPPORTMATERIAL); + +// pobj->clear_support_layers(); + +// if((pobj->config.support_material || pobj->config.raft_layers > 0) +// && pobj->layers.size() > 1) { +// pobj->_generate_support_material(); +// } + +// pobj->state.set_done(STEP_SUPPORTMATERIAL); +// } +//} + +PrintController::PngExportData +PrintController::query_png_export_data(const DynamicPrintConfig& conf) +{ + PngExportData ret; + + auto zippath = query_destination_path("Output zip file", "*.zip", "out"); + + ret.zippath = zippath; + + ret.width_mm = conf.opt_float("display_width"); + ret.height_mm = conf.opt_float("display_height"); + + ret.width_px = conf.opt_int("display_pixels_x"); + ret.height_px = conf.opt_int("display_pixels_y"); + + auto opt_corr = conf.opt("printer_correction"); + + if(opt_corr) { + ret.corr_x = opt_corr->values[0]; + ret.corr_y = opt_corr->values[1]; + ret.corr_z = opt_corr->values[2]; + } + + ret.exp_time_first_s = conf.opt_float("initial_exposure_time"); + ret.exp_time_s = conf.opt_float("exposure_time"); + + return ret; +} + +void PrintController::slice(AppControllerBoilerplate::ProgresIndicatorPtr pri) +{ + auto st = pri->state(); + + Slic3r::trace(3, "Starting the slicing process."); + + pri->update(st+20, L("Generating perimeters")); +// for(auto obj : print_->objects) make_perimeters(obj); + + pri->update(st+60, L("Infilling layers")); +// for(auto obj : print_->objects) infill(obj); + + pri->update(st+70, L("Generating support material")); +// for(auto obj : print_->objects) gen_support_material(obj); + +// pri->message_fmt(L("Weight: %.1fg, Cost: %.1f"), +// print_->total_weight, print_->total_cost); + pri->state(st+85); + + + pri->update(st+88, L("Generating skirt")); + make_skirt(); + + + pri->update(st+90, L("Generating brim")); + make_brim(); + + pri->update(st+95, L("Generating wipe tower")); + make_wipe_tower(); + + pri->update(st+100, L("Done")); + + // time to make some statistics.. + + Slic3r::trace(3, L("Slicing process finished.")); +} + +void PrintController::slice() +{ + auto pri = global_progress_indicator(); + if(!pri) pri = create_progress_indicator(100, L("Slicing")); + slice(pri); +} + +struct wxZipper {}; + +template<> class Zipper { + wxFileName m_fpath; + wxFFileOutputStream m_zipfile; + wxZipOutputStream m_zipstream; + wxStdOutputStream m_pngstream; +public: + + Zipper(const std::string& zipfile_path): + m_fpath(zipfile_path), + m_zipfile(zipfile_path), + m_zipstream(m_zipfile), + m_pngstream(m_zipstream) + { + if(!m_zipfile.IsOk()) + throw std::runtime_error(L("Cannot create zip file.")); + } + + void next_entry(const std::string& fname) { + m_zipstream.PutNextEntry(fname); + } + + std::string get_name() { + return m_fpath.GetName().ToStdString(); + } + + template Zipper& operator<<(const T& arg) { + m_pngstream << arg; return *this; + } + + void close() { + m_zipstream.Close(); + m_zipfile.Close(); + } +}; + +void PrintController::slice_to_png() +{ + using Pointf3 = Vec3d; + + auto presetbundle = GUI::get_preset_bundle(); + + assert(presetbundle); + + auto pt = presetbundle->printers.get_selected_preset().printer_technology(); + if(pt != ptSLA) { + report_issue(IssueType::ERR, L("Printer technology is not SLA!"), + L("Error")); + return; + } + + auto conf = presetbundle->full_config(); + conf.validate(); + + auto exd = query_png_export_data(conf); + if(exd.zippath.empty()) return; + + Print *print = print_; + + try { + print->apply_config(conf); + print->validate(); + } catch(std::exception& e) { + report_issue(IssueType::ERR, e.what(), "Error"); + return; + } + + // TODO: copy the model and work with the copy only + bool correction = false; + if(exd.corr_x != 1.0 || exd.corr_y != 1.0 || exd.corr_z != 1.0) { + correction = true; +// print->invalidate_all_steps(); + +// for(auto po : print->objects) { +// po->model_object()->scale( +// Pointf3(exd.corr_x, exd.corr_y, exd.corr_z) +// ); +// po->model_object()->invalidate_bounding_box(); +// po->reload_model_instances(); +// po->invalidate_all_steps(); +// } + } + + // Turn back the correction scaling on the model. + auto scale_back = [this, print, correction, exd]() { + if(correction) { // scale the model back +// print->invalidate_all_steps(); +// for(auto po : print->objects) { +// po->model_object()->scale( +// Pointf3(1.0/exd.corr_x, 1.0/exd.corr_y, 1.0/exd.corr_z) +// ); +// po->model_object()->invalidate_bounding_box(); +// po->reload_model_instances(); +// po->invalidate_all_steps(); +// } + } + }; + + 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) > exd.width_mm || py(punsc) > exd.height_mm) { + std::stringstream ss; + + ss << L("Print will not fit and will be truncated!") << "\n" + << L("Width needed: ") << px(punsc) << " mm\n" + << L("Height needed: ") << py(punsc) << " mm\n"; + + if(!report_issue(IssueType::WARN_Q, ss.str(), L("Warning"))) { + scale_back(); + return; + } + } + + auto pri = create_progress_indicator( + 200, L("Slicing to zipped png files...")); + + pri->on_cancel([&print](){ print->cancel(); }); + + try { + pri->update(0, L("Slicing...")); + slice(pri); + } catch (std::exception& e) { + report_issue(IssueType::ERR, e.what(), L("Exception occurred")); + scale_back(); + if(print->canceled()) print->restart(); + return; + } + + auto initstate = unsigned(pri->state()); + print->set_status_callback([pri, initstate](int st, const std::string& msg) + { + pri->update(initstate + unsigned(st), msg); + }); + + try { + print_to( *print, exd.zippath, + exd.width_mm, exd.height_mm, + exd.width_px, exd.height_px, + exd.exp_time_s, exd.exp_time_first_s); + + } catch (std::exception& e) { + report_issue(IssueType::ERR, e.what(), L("Exception occurred")); + } + + scale_back(); + if(print->canceled()) print->restart(); +} + +const PrintConfig &PrintController::config() const +{ + return print_->config(); +} + void ProgressIndicator::message_fmt( const std::string &fmtstr, ...) { std::stringstream ss; diff --git a/xs/src/slic3r/AppController.hpp b/xs/src/slic3r/AppController.hpp index 71472835e..88d1f0eca 100644 --- a/xs/src/slic3r/AppController.hpp +++ b/xs/src/slic3r/AppController.hpp @@ -165,12 +165,49 @@ protected: ProgresIndicatorPtr global_progressind_; }; -#if 0 /** * @brief Implementation of the printing logic. */ class PrintController: public AppControllerBoilerplate { Print *print_ = nullptr; + std::function rempools_; +protected: + + void make_skirt() {} + void make_brim() {} + void make_wipe_tower() {} + + void make_perimeters(PrintObject *pobj) {} + void infill(PrintObject *pobj) {} + void gen_support_material(PrintObject *pobj) {} + + // Data structure with the png export input data + struct PngExportData { + std::string zippath; // output zip file + unsigned long width_px = 1440; // resolution - rows + unsigned long height_px = 2560; // resolution columns + double width_mm = 68.0, height_mm = 120.0; // dimensions in mm + double exp_time_first_s = 35.0; // first exposure time + double exp_time_s = 8.0; // global exposure time + double corr_x = 1.0; // offsetting in x + double corr_y = 1.0; // offsetting in y + double corr_z = 1.0; // offsetting in y + }; + + // Should display a dialog with the input fields for printing to png + PngExportData query_png_export_data(const DynamicPrintConfig&); + + // The previous export data, to pre-populate the dialog + PngExportData prev_expdata_; + + /** + * @brief Slice one pront object. + * @param pobj The print object. + */ + void slice(PrintObject *pobj); + + void slice(ProgresIndicatorPtr pri); + public: // Must be public for perl to use it @@ -185,24 +222,18 @@ public: return PrintController::Ptr( new PrintController(print) ); } - void slice() {} - void slice_to_png() {} + /** + * @brief Slice the loaded print scene. + */ + void slice(); + + /** + * @brief Slice the print into zipped png files. + */ + void slice_to_png(); const PrintConfig& config() const; }; -#else -class PrintController: public AppControllerBoilerplate { -public: - using Ptr = std::unique_ptr; - explicit inline PrintController(Print *print){} - inline static Ptr create(Print *print) { - return PrintController::Ptr( new PrintController(print) ); - } - void slice() {} - void slice_to_png() {} - const PrintConfig& config() const { static PrintConfig cfg; return cfg; } -}; -#endif /** * @brief Top level controller.