From 784105f5adfcf5ee46c748c7b36af73fd3b89b35 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 26 Apr 2022 10:57:49 +0200 Subject: [PATCH] Extend sla archive tests with read-back --- src/libslic3r/Format/SLAArchiveReader.hpp | 37 ++++++++-- src/slic3r/GUI/Jobs/SLAImportJob.cpp | 17 +++-- tests/sla_print/CMakeLists.txt | 2 +- tests/sla_print/sla_archive_export_tests.cpp | 40 ----------- .../sla_print/sla_archive_readwrite_tests.cpp | 68 +++++++++++++++++++ 5 files changed, 112 insertions(+), 52 deletions(-) delete mode 100644 tests/sla_print/sla_archive_export_tests.cpp create mode 100644 tests/sla_print/sla_archive_readwrite_tests.cpp diff --git a/src/libslic3r/Format/SLAArchiveReader.hpp b/src/libslic3r/Format/SLAArchiveReader.hpp index 3ece8bd369..d3b7185134 100644 --- a/src/libslic3r/Format/SLAArchiveReader.hpp +++ b/src/libslic3r/Format/SLAArchiveReader.hpp @@ -8,22 +8,37 @@ struct indexed_triangle_set; namespace Slic3r { +// A generic indicator for the quality of an imported model. Obviously, the +// original cannot be fully reconstructed. enum class SLAImportQuality { Accurate, Balanced, Fast }; -class MissingProfileError : public RuntimeError { using RuntimeError::RuntimeError; }; +// Raised when the needed metadata cannot be retrieved or guessed from an archive +class MissingProfileError : public RuntimeError +{ + using RuntimeError::RuntimeError; +}; +// A shortname for status indication function. +// The argument is the status (from <0, 100>) +// Returns false if cancel was requested. using ProgrFn = std::function; +// Abstract interface for an archive reader. This needs to be implemented for +// every supported archive format. class SLAArchiveReader { public: virtual ~SLAArchiveReader() = default; + // Read the profile and reconstruct the slices virtual ConfigSubstitutions read(std::vector &slices, DynamicPrintConfig &profile) = 0; + // Overload for reading only the profile contained in the archive (if present) virtual ConfigSubstitutions read(DynamicPrintConfig &profile) = 0; + // Creates a reader instance based on the provided file path. + // Currently only considers the file extension. static std::unique_ptr create( const std::string &fname, SLAImportQuality quality = SLAImportQuality::Balanced, @@ -32,17 +47,22 @@ public: // Get the names of currently known archive reader implementations static const std::vector & registered_archives(); - // Get the default file extensions belonging to an archive format + // Get the understood file extensions belonging to an archive format static std::vector get_extensions(const char *archtype); + // Generic description (usable in GUI) about an archive format static const char * get_description(const char *archtype); }; -class ReaderUnimplementedError : public RuntimeError { using RuntimeError::RuntimeError; }; - -ConfigSubstitutions import_sla_archive(const std::string &zipfname, - DynamicPrintConfig &out); +// Raised in import_sla_archive when a nullptr reader is returned by +// SLAArchiveReader::create() +class ReaderUnimplementedError : public RuntimeError +{ + using RuntimeError::RuntimeError; +}; +// Helper free functions to import an archive using the above interface. +// Can throw ReaderUnimplementedError or MissingProfileError ConfigSubstitutions import_sla_archive( const std::string &zipfname, indexed_triangle_set &out, @@ -50,6 +70,11 @@ ConfigSubstitutions import_sla_archive( SLAImportQuality quality = SLAImportQuality::Balanced, const ProgrFn &progr = [](int) { return true; }); +// Only reads the profile, doesn't reconstruct the model. +ConfigSubstitutions import_sla_archive(const std::string &zipfname, + DynamicPrintConfig &out); + + } // namespace Slic3r #endif // SLAARCHIVEREADER_HPP diff --git a/src/slic3r/GUI/Jobs/SLAImportJob.cpp b/src/slic3r/GUI/Jobs/SLAImportJob.cpp index 5aa936be1f..fac4983c2f 100644 --- a/src/slic3r/GUI/Jobs/SLAImportJob.cpp +++ b/src/slic3r/GUI/Jobs/SLAImportJob.cpp @@ -123,8 +123,8 @@ void SLAImportJob::finalize(bool canceled, std::exception_ptr &eptr) p->plater->get_notification_manager()->push_notification( NotificationType::CustomNotification, NotificationManager::NotificationLevel::WarningNotificationLevel, - _L("The imported SLA archive did not contain any presets. " - "The current SLA presets were used as fallback.").ToStdString()); + _u8L("The imported SLA archive did not contain any presets. " + "The current SLA presets were used as fallback.")); } if (p->sel != Sel::modelOnly) { @@ -146,9 +146,16 @@ void SLAImportJob::finalize(bool canceled, std::exception_ptr &eptr) config.apply(SLAFullPrintConfig::defaults()); config += std::move(p->profile); - wxGetApp().preset_bundle->load_config_model(name, std::move(config)); - p->plater->check_selected_presets_visibility(ptSLA); - wxGetApp().load_current_presets(); + if (Preset::printer_technology(config) == ptSLA) { + wxGetApp().preset_bundle->load_config_model(name, std::move(config)); + p->plater->check_selected_presets_visibility(ptSLA); + wxGetApp().load_current_presets(); + } else { + p->plater->get_notification_manager()->push_notification( + NotificationType::CustomNotification, + NotificationManager::NotificationLevel::WarningNotificationLevel, + _u8L("The profile in the imported archive is corrupt and will not be loaded.")); + } } if (!p->mesh.empty()) { diff --git a/tests/sla_print/CMakeLists.txt b/tests/sla_print/CMakeLists.txt index 88c1cd1866..a26d5f4801 100644 --- a/tests/sla_print/CMakeLists.txt +++ b/tests/sla_print/CMakeLists.txt @@ -4,7 +4,7 @@ add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp sla_test_utils.hpp sla_test_utils.cpp sla_supptgen_tests.cpp sla_raycast_tests.cpp - sla_archive_export_tests.cpp) + sla_archive_readwrite_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 deleted file mode 100644 index 2c0d68c3ce..0000000000 --- a/tests/sla_print/sla_archive_export_tests.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include - -#include "libslic3r/SLAPrint.hpp" -#include "libslic3r/Format/SLAArchiveWriter.hpp" - -#include - -using namespace Slic3r; - -TEST_CASE("Archive export test", "[sla_archives]") { - constexpr const char *PNAME = "20mm_cube"; - - for (auto &archname : SLAArchiveWriter::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); - fullcfg.set("supports_enable", false); - fullcfg.set("pad_enable", false); - - DynamicPrintConfig cfg; - cfg.apply(fullcfg); - - print.set_status_callback([](const PrintBase::SlicingStatus&) {}); - print.apply(m, cfg); - print.process(); - - ThumbnailsList thumbnails; - auto outputfname = std::string("output.") + SLAArchiveWriter::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/sla_print/sla_archive_readwrite_tests.cpp b/tests/sla_print/sla_archive_readwrite_tests.cpp new file mode 100644 index 0000000000..251d7e8f36 --- /dev/null +++ b/tests/sla_print/sla_archive_readwrite_tests.cpp @@ -0,0 +1,68 @@ +#include +#include + +#include "libslic3r/SLAPrint.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/Format/SLAArchiveWriter.hpp" +#include "libslic3r/Format/SLAArchiveReader.hpp" + +#include + +using namespace Slic3r; + +TEST_CASE("Archive export test", "[sla_archives]") { + constexpr const char *PNAME = "extruder_idler"; + + for (auto &archname : SLAArchiveWriter::registered_archives()) { + INFO(std::string("Testing archive type: ") + archname + " -- writing..."); + SLAPrint print; + SLAFullPrintConfig fullcfg; + + auto m = Model::read_from_file(TEST_DATA_DIR PATH_SEPARATOR + std::string(PNAME) + ".obj", nullptr); + + fullcfg.printer_technology.setInt(ptSLA); // FIXME this should be ensured + fullcfg.set("sla_archive_format", archname); + fullcfg.set("supports_enable", false); + fullcfg.set("pad_enable", false); + + DynamicPrintConfig cfg; + cfg.apply(fullcfg); + + print.set_status_callback([](const PrintBase::SlicingStatus&) {}); + print.apply(m, cfg); + print.process(); + + ThumbnailsList thumbnails; + auto outputfname = std::string("output.") + SLAArchiveWriter::get_extension(archname); + + print.export_print(outputfname, thumbnails, PNAME); + + // Not much can be checked about the archives... + REQUIRE(boost::filesystem::exists(outputfname)); + + double vol_written = m.mesh().volume(); + + auto readable_formats = SLAArchiveReader::registered_archives(); + if (std::any_of(readable_formats.begin(), readable_formats.end(), + [&archname](const std::string &a) { return a == archname; })) { + + INFO(std::string("Testing archive type: ") + archname + " -- reading back..."); + + indexed_triangle_set its; + DynamicPrintConfig cfg; + + try { + import_sla_archive(outputfname, its, cfg); + } catch (...) { + REQUIRE(false); + } + + REQUIRE(!cfg.empty()); + REQUIRE(!its.empty()); + + double vol_read = its_volume(its); + double rel_err = std::abs(vol_written - vol_read) / vol_written; + REQUIRE(rel_err < 0.1); + } + } +}