diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index ea663f2e1..046aba763 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -94,6 +94,8 @@ set(SLIC3R_SOURCES Format/objparser.hpp Format/STL.cpp Format/STL.hpp + Format/SLAArchive.hpp + Format/SLAArchive.cpp Format/SL1.hpp Format/SL1.cpp Format/SL1_SVG.hpp diff --git a/src/libslic3r/Format/SL1.hpp b/src/libslic3r/Format/SL1.hpp index 874786eb9..8ed9dc329 100644 --- a/src/libslic3r/Format/SL1.hpp +++ b/src/libslic3r/Format/SL1.hpp @@ -3,8 +3,10 @@ #include +#include "SLAArchive.hpp" + #include "libslic3r/Zipper.hpp" -#include "libslic3r/SLAPrint.hpp" +#include "libslic3r/PrintConfig.hpp" namespace Slic3r { diff --git a/src/libslic3r/Format/SLAArchive.cpp b/src/libslic3r/Format/SLAArchive.cpp new file mode 100644 index 000000000..8e2bf2824 --- /dev/null +++ b/src/libslic3r/Format/SLAArchive.cpp @@ -0,0 +1,74 @@ +#include "SLAArchive.hpp" + +#include "SL1.hpp" +#include "SL1_SVG.hpp" +#include "pwmx.hpp" + +#include "libslic3r/libslic3r.h" + +#include +#include +#include +#include + +namespace Slic3r { + +using ArchiveFactory = std::function(const SLAPrinterConfig&)>; + +struct ArchiveEntry { + const char *ext; + ArchiveFactory factoryfn; +}; + +static const std::map REGISTERED_ARCHIVES { + { + "SL1", + { "sl1", [] (const auto &cfg) { return std::make_unique(cfg); } } + }, + { + "SL2", + { "sl2", [] (const auto &cfg) { return std::make_unique(cfg); } } + }, + { + "pwmx", + { "pwmx", [] (const auto &cfg) { return std::make_unique(cfg); } } + } +}; + +std::unique_ptr +SLAArchive::create(const std::string &archtype, const SLAPrinterConfig &cfg) +{ + auto entry = REGISTERED_ARCHIVES.find(archtype); + + if (entry != REGISTERED_ARCHIVES.end()) + return entry->second.factoryfn(cfg); + + return nullptr; +} + +const std::vector& SLAArchive::registered_archives() +{ + static std::vector archnames; + + if (archnames.empty()) { + archnames.reserve(REGISTERED_ARCHIVES.size()); + + for (auto &[name, _] : REGISTERED_ARCHIVES) + archnames.emplace_back(name.c_str()); + } + + return archnames; +} + +const char *SLAArchive::get_extension(const char *archtype) +{ + static const char* DEFAULT_EXT = "zip"; + + auto entry = REGISTERED_ARCHIVES.find(archtype); + if (entry != REGISTERED_ARCHIVES.end()) + return entry->second.ext; + + return DEFAULT_EXT; +} + +} // namespace Slic3r diff --git a/src/libslic3r/Format/SLAArchive.hpp b/src/libslic3r/Format/SLAArchive.hpp new file mode 100644 index 000000000..971d7ba7b --- /dev/null +++ b/src/libslic3r/Format/SLAArchive.hpp @@ -0,0 +1,64 @@ +#ifndef SLAARCHIVE_HPP +#define SLAARCHIVE_HPP + +#include + +#include "libslic3r/SLA/RasterBase.hpp" +#include "libslic3r/Execution/ExecutionTBB.hpp" +#include "libslic3r/GCode/ThumbnailData.hpp" + +namespace Slic3r { + +class SLAPrint; +class SLAPrinterConfig; + +class SLAArchive { +protected: + std::vector m_layers; + + virtual std::unique_ptr create_raster() const = 0; + virtual sla::RasterEncoder get_encoder() const = 0; + +public: + virtual ~SLAArchive() = default; + + // Fn have to be thread safe: void(sla::RasterBase& raster, size_t lyrid); + template + void draw_layers( + size_t layer_num, + Fn && drawfn, + CancelFn cancelfn = []() { return false; }, + const EP & ep = {}) + { + m_layers.resize(layer_num); + execution::for_each( + ep, size_t(0), m_layers.size(), + [this, &drawfn, &cancelfn](size_t idx) { + if (cancelfn()) return; + + sla::EncodedRaster &enc = m_layers[idx]; + auto rst = create_raster(); + drawfn(*rst, idx); + enc = rst->encode(get_encoder()); + }, + execution::max_concurrency(ep)); + } + + // Export the print into an archive using the provided filename. + virtual void export_print(const std::string fname, + const SLAPrint &print, + const ThumbnailsList &thumbnails, + const std::string &projectname = "") = 0; + + // Factory method to create an archiver instance + static std::unique_ptr create(const std::string &archtype, const SLAPrinterConfig&); + + // Get the names of currently known archiver implementations + static const std::vector & registered_archives(); + + // Get the default file extension belonging to an archive format + static const char *get_extension(const char *archtype); +}; + +} // namespace Slic3r +#endif // SLAARCHIVE_HPP diff --git a/src/libslic3r/Format/pwmx.cpp b/src/libslic3r/Format/pwmx.cpp index 5b420a49e..f3f0f6802 100644 --- a/src/libslic3r/Format/pwmx.cpp +++ b/src/libslic3r/Format/pwmx.cpp @@ -1,6 +1,7 @@ #include "pwmx.hpp" #include "GCode/ThumbnailData.hpp" #include "SLA/RasterBase.hpp" +#include "libslic3r/SLAPrint.hpp" #include #include @@ -277,8 +278,9 @@ void fill_header(pwmx_format_header &h, std::float_t bottle_volume_ml; std::float_t bottle_cost; std::float_t material_density; - auto & cfg = print.full_print_config(); - std::string mnotes = cfg.option("material_notes")->serialize(); + auto &cfg = print.full_print_config(); + auto mat_opt = cfg.option("material_notes"); + std::string mnotes = mat_opt? cfg.option("material_notes")->serialize() : ""; // create a config parser from the material notes Slic3r::PwmxFormatDynamicConfig mat_cfg; SLAPrintStatistics stats = print.print_statistics(); diff --git a/src/libslic3r/Format/pwmx.hpp b/src/libslic3r/Format/pwmx.hpp index d1179c014..65fb19910 100644 --- a/src/libslic3r/Format/pwmx.hpp +++ b/src/libslic3r/Format/pwmx.hpp @@ -3,7 +3,9 @@ #include -#include "libslic3r/SLAPrint.hpp" +#include "SLAArchive.hpp" + +#include "libslic3r/PrintConfig.hpp" namespace Slic3r { diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 2622b6a23..72cb96dd0 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -245,15 +245,8 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con // Handle changes to object config defaults m_default_object_config.apply_only(config, object_diff, true); - if (!m_archiver || !printer_diff.empty()) { - if (m_printer_config.sla_archive_format.value == "SL1") - m_archiver = std::make_unique(m_printer_config); - else if (m_printer_config.sla_archive_format.value == "SL2") - m_archiver = std::make_unique(m_printer_config); - else if (m_printer_config.sla_archive_format.value == "pwmx") { - m_archiver = std::make_unique(m_printer_config); - } - } + if (!m_archiver || !printer_diff.empty()) + m_archiver = SLAArchive::create(m_printer_config.sla_archive_format.value.c_str(), m_printer_config); struct ModelObjectStatus { enum Status { diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 2d49139a4..0723382b3 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -9,6 +9,7 @@ #include "Point.hpp" #include "MTUtils.hpp" #include "Zipper.hpp" +#include "Format/SLAArchive.hpp" #include "GCode/ThumbnailData.hpp" #include "libslic3r/Execution/ExecutionTBB.hpp" @@ -390,45 +391,6 @@ struct SLAPrintStatistics } }; -class SLAArchive { -protected: - std::vector m_layers; - - virtual std::unique_ptr create_raster() const = 0; - virtual sla::RasterEncoder get_encoder() const = 0; - -public: - virtual ~SLAArchive() = default; - - // Fn have to be thread safe: void(sla::RasterBase& raster, size_t lyrid); - template - void draw_layers( - size_t layer_num, - Fn && drawfn, - CancelFn cancelfn = []() { return false; }, - const EP & ep = {}) - { - m_layers.resize(layer_num); - execution::for_each( - ep, size_t(0), m_layers.size(), - [this, &drawfn, &cancelfn](size_t idx) { - if (cancelfn()) return; - - sla::EncodedRaster &enc = m_layers[idx]; - auto rst = create_raster(); - drawfn(*rst, idx); - enc = rst->encode(get_encoder()); - }, - execution::max_concurrency(ep)); - } - - // Export the print into an archive using the provided filename. - virtual void export_print(const std::string fname, - const SLAPrint &print, - const ThumbnailsList &thumbnails, - const std::string &projectname = "") = 0; -}; - /** * @brief This class is the high level FSM for the SLA printing process. * diff --git a/src/slic3r/GUI/Jobs/SLAImportJob.cpp b/src/slic3r/GUI/Jobs/SLAImportJob.cpp index 1bb8cdf6c..96702d158 100644 --- a/src/slic3r/GUI/Jobs/SLAImportJob.cpp +++ b/src/slic3r/GUI/Jobs/SLAImportJob.cpp @@ -1,5 +1,6 @@ #include "SLAImportJob.hpp" +#include "libslic3r/SLAPrint.hpp" #include "libslic3r/Format/SL1.hpp" #include "slic3r/GUI/GUI.hpp" diff --git a/tests/libnest2d/CMakeLists.txt b/tests/libnest2d/CMakeLists.txt index bcb759452..9bafe84a0 100644 --- a/tests/libnest2d/CMakeLists.txt +++ b/tests/libnest2d/CMakeLists.txt @@ -4,4 +4,6 @@ target_link_libraries(${_TEST_NAME}_tests test_common libnest2d ) set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") # catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") -add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "${CATCH_EXTRA_ARGS} exclude:[NotWorking]") +set(_catch_args "exclude:[NotWorking]") +list(APPEND _catch_args "${CATCH_EXTRA_ARGS}") +add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests ${_catch_args}) diff --git a/tests/sla_print/CMakeLists.txt b/tests/sla_print/CMakeLists.txt index dc583f1a1..26d576549 100644 --- a/tests/sla_print/CMakeLists.txt +++ b/tests/sla_print/CMakeLists.txt @@ -3,7 +3,8 @@ add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp sla_print_tests.cpp sla_test_utils.hpp sla_test_utils.cpp sla_supptgen_tests.cpp - sla_raycast_tests.cpp) + sla_raycast_tests.cpp + sla_archive_export_tests.cpp) target_link_libraries(${_TEST_NAME}_tests test_common libslic3r) set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") diff --git a/tests/sla_print/sla_archive_export_tests.cpp b/tests/sla_print/sla_archive_export_tests.cpp new file mode 100644 index 000000000..586b0eb67 --- /dev/null +++ b/tests/sla_print/sla_archive_export_tests.cpp @@ -0,0 +1,37 @@ +#include +#include + +#include "libslic3r/SLAPrint.hpp" +#include "libslic3r/Format/SLAArchive.hpp" + +#include + +using namespace Slic3r; + +TEST_CASE("Archive export test", "[sla_archives]") { + constexpr const char *PNAME = "20mm_cube"; + + for (auto &archname : SLAArchive::registered_archives()) { + INFO(std::string("Testing archive type: ") + archname); + SLAPrint print; + SLAFullPrintConfig fullcfg; + + auto m = Model::read_from_file(TEST_DATA_DIR PATH_SEPARATOR + std::string(PNAME) + ".obj", nullptr); + + fullcfg.set("sla_archive_format", archname); + + DynamicPrintConfig cfg; + cfg.apply(fullcfg); + + print.apply(m, cfg); + print.process(); + + ThumbnailsList thumbnails; + auto outputfname = std::string("output.") + SLAArchive::get_extension(archname); + + print.export_print(outputfname, thumbnails, PNAME); + + // Not much can be checked about the archives... + REQUIRE(boost::filesystem::exists(outputfname)); + } +} diff --git a/tests/slic3rutils/CMakeLists.txt b/tests/slic3rutils/CMakeLists.txt index be1b645d7..256e6efd6 100644 --- a/tests/slic3rutils/CMakeLists.txt +++ b/tests/slic3rutils/CMakeLists.txt @@ -15,4 +15,6 @@ if (WIN32) endif() # catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") -add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "${CATCH_EXTRA_ARGS} exclude:[NotWorking]") +set(_catch_args "exclude:[NotWorking]") +list(APPEND _catch_args "${CATCH_EXTRA_ARGS}") +add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests ${_catch_args})