diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index a06da54910..69ea01ad48 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -48,6 +48,7 @@ #include "libslic3r/GCode/PostProcessor.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/ModelProcessing.hpp" +#include "libslic3r/FileReader.hpp" #include "libslic3r/CutUtils.hpp" #include #include "libslic3r/Platform.hpp" @@ -292,13 +293,13 @@ int CLI::run(int argc, char **argv) Model model; try { if (has_config_from_profiles) - model = Model::read_from_file(file, nullptr, nullptr, Model::LoadAttribute::AddDefaultInstances); + model = FileReader::load_model(file); else { // When loading an AMF or 3MF, config is imported as well, including the printer technology. DynamicPrintConfig config; ConfigSubstitutionContext config_substitutions(config_substitution_rule); //FIXME should we check the version here? // | Model::LoadAttribute::CheckVersion ? - model = Model::read_from_file(file, &config, &config_substitutions, Model::LoadAttribute::AddDefaultInstances); + model = FileReader::read_from_file(file, &config, &config_substitutions, FileReader::LoadAttribute::AddDefaultInstances); PrinterTechnology other_printer_technology = get_printer_technology(config); if (printer_technology == ptUnknown) { printer_technology = other_printer_technology; diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index e979b5a5e7..57d42e6409 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -264,6 +264,8 @@ set(SLIC3R_SOURCES Model.hpp ModelProcessing.cpp ModelProcessing.hpp + FileReader.cpp + FileReader.hpp MultiMaterialSegmentation.cpp MultiMaterialSegmentation.hpp MeshNormals.hpp diff --git a/src/libslic3r/FileReader.cpp b/src/libslic3r/FileReader.cpp new file mode 100644 index 0000000000..b0d0fd14f2 --- /dev/null +++ b/src/libslic3r/FileReader.cpp @@ -0,0 +1,155 @@ +///|/ Copyright (c) Prusa Research 2016 - 2023 Tomáš Mészáros @tamasmeszaros, Oleksandra Iushchenko @YuSanka, David Kocík @kocikdav, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Lukáš Hejl @hejllukas, Filip Sykala @Jony01, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2021 Boleslaw Ciesielski +///|/ Copyright (c) 2019 John Drake @foxox +///|/ Copyright (c) 2019 Sijmen Schoon +///|/ Copyright (c) Slic3r 2014 - 2016 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2015 Maksim Derbasov @ntfshard +///|/ +///|/ ported from lib/Slic3r/Model.pm: +///|/ Copyright (c) Prusa Research 2016 - 2022 Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966 +///|/ Copyright (c) Slic3r 2012 - 2016 Alessandro Ranellucci @alranel +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#include "FileReader.hpp" +#include "Model.hpp" +#include "TriangleMesh.hpp" + +#include "Format/AMF.hpp" +#include "Format/OBJ.hpp" +#include "Format/STL.hpp" +#include "Format/3mf.hpp" +#include "Format/STEP.hpp" +#include "Format/SVG.hpp" +#include "Format/PrintRequest.hpp" + +namespace Slic3r::FileReader +{ +// Loading model from a file, it may be a simple geometry file as STL or OBJ, however it may be a project file as well. +Model read_from_file(const std::string& input_file, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, LoadAttributes options) +{ + Model model; + + DynamicPrintConfig temp_config; + ConfigSubstitutionContext temp_config_substitutions_context(ForwardCompatibilitySubstitutionRule::EnableSilent); + if (config == nullptr) + config = &temp_config; + if (config_substitutions == nullptr) + config_substitutions = &temp_config_substitutions_context; + + bool result = false; + if (boost::algorithm::iends_with(input_file, ".stl")) + result = load_stl(input_file.c_str(), &model); + else if (boost::algorithm::iends_with(input_file, ".obj")) + result = load_obj(input_file.c_str(), &model); + else if (boost::algorithm::iends_with(input_file, ".step") || boost::algorithm::iends_with(input_file, ".stp")) + result = load_step(input_file.c_str(), &model); + else if (boost::algorithm::iends_with(input_file, ".amf") || boost::algorithm::iends_with(input_file, ".amf.xml")) + result = load_amf(input_file.c_str(), config, config_substitutions, &model, options & LoadAttribute::CheckVersion); + else if (boost::algorithm::iends_with(input_file, ".3mf") || boost::algorithm::iends_with(input_file, ".zip")) { + //FIXME options & LoadAttribute::CheckVersion ? + boost::optional prusaslicer_generator_version; + result = load_3mf(input_file.c_str(), *config, *config_substitutions, &model, false, prusaslicer_generator_version); + } else if (boost::algorithm::iends_with(input_file, ".svg")) + result = load_svg(input_file, model); + else if (boost::ends_with(input_file, ".printRequest")) + result = load_printRequest(input_file.c_str(), &model); + else + throw Slic3r::RuntimeError("Unknown file format. Input file must have .stl, .obj, .step/.stp, .svg, .amf(.xml) or extension .3mf(.zip)."); + + if (!result) + throw Slic3r::RuntimeError("Loading of a model file failed."); + + if (model.objects.empty()) + throw Slic3r::RuntimeError("The supplied file couldn't be read because it's empty"); + + if (!boost::ends_with(input_file, ".printRequest")) + for (ModelObject* o : model.objects) + o->input_file = input_file; + + if (options & LoadAttribute::AddDefaultInstances) + model.add_default_instances(); + + for (CustomGCode::Info& info : model.get_custom_gcode_per_print_z_vector()) { + CustomGCode::update_custom_gcode_per_print_z_from_config(info, config); + CustomGCode::check_mode_for_custom_gcode_per_print_z(info); + } + + sort_remove_duplicates(config_substitutions->substitutions); + return model; +} + +// Loading model from a file (3MF or AMF), not from a simple geometry file (STL or OBJ). +Model read_from_archive(const std::string& input_file, + DynamicPrintConfig* config, + ConfigSubstitutionContext*, + config_substitutions, + boost::optional &prusaslicer_generator_version, + LoadAttributes options) +{ + assert(config != nullptr); + assert(config_substitutions != nullptr); + + Model model; + + bool result = false; + if (boost::algorithm::iends_with(input_file, ".3mf") || boost::algorithm::iends_with(input_file, ".zip")) + result = load_3mf(input_file.c_str(), *config, *config_substitutions, &model, options & LoadAttribute::CheckVersion, prusaslicer_generator_version); + else if (boost::algorithm::iends_with(input_file, ".zip.amf")) + result = load_amf(input_file.c_str(), config, config_substitutions, &model, options & LoadAttribute::CheckVersion); + else + throw Slic3r::RuntimeError("Unknown file format. Input file must have .3mf or .zip.amf extension."); + + if (!result) + throw Slic3r::RuntimeError("Loading of a model file failed."); + + for (ModelObject* o : model.objects) { + //if (boost::algorithm::iends_with(input_file, ".zip.amf")) { + // // we remove the .zip part of the extension to avoid it be added to filenames when exporting + // o->input_file = boost::ireplace_last_copy(input_file, ".zip.", "."); + //} + //else + o->input_file = input_file; + } + + if (options & LoadAttribute::AddDefaultInstances) + model.add_default_instances(); + + for (CustomGCode::Info& info : model.get_custom_gcode_per_print_z_vector()) { + CustomGCode::update_custom_gcode_per_print_z_from_config(info, config); + CustomGCode::check_mode_for_custom_gcode_per_print_z(info); + } + handle_legacy_sla(*config); + + return model; +} + +Model load_model(const std::string& input_file, std::string& errors) +{ + Model model; + try { + model = read_from_file(input_file); + } + catch (std::exception& e) { + errors = input_file + " : " + e.what(); + return model; + } + + return model; +} + +Model load_model(const std::string& input_file) +{ + std::string errors; + Model model = load_model(input_file, errors); + return model; +} + +TriangleMesh load_mesh(const std::string& input_file) +{ + Model model = load_model(input_file); + return model.mesh(); +} + + +} diff --git a/src/libslic3r/FileReader.hpp b/src/libslic3r/FileReader.hpp new file mode 100644 index 0000000000..a3b4ef9a82 --- /dev/null +++ b/src/libslic3r/FileReader.hpp @@ -0,0 +1,50 @@ +///|/ Copyright (c) Prusa Research 2016 - 2023 Tomáš Mészáros @tamasmeszaros, Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Filip Sykala @Jony01, Lukáš Hejl @hejllukas, David Kocík @kocikdav, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2019 John Drake @foxox +///|/ Copyright (c) 2019 Sijmen Schoon +///|/ Copyright (c) 2017 Eyal Soha @eyal0 +///|/ Copyright (c) Slic3r 2014 - 2015 Alessandro Ranellucci @alranel +///|/ +///|/ ported from lib/Slic3r/Model.pm: +///|/ Copyright (c) Prusa Research 2016 - 2022 Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966 +///|/ Copyright (c) Slic3r 2012 - 2016 Alessandro Ranellucci @alranel +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#pragma once + +//#include "TriangleMesh.hpp" + +#include "PrintConfig.hpp" +#include "enum_bitmask.hpp" + +namespace Slic3r { + +class Model; +class TriangleMesh; + +namespace FileReader +{ + enum class LoadAttribute : int { + AddDefaultInstances, + CheckVersion + }; + using LoadAttributes = enum_bitmask; + + Model read_from_file(const std::string& input_file, + DynamicPrintConfig* config = nullptr, + ConfigSubstitutionContext* config_substitutions = nullptr, + LoadAttributes options = LoadAttribute::AddDefaultInstances); + Model read_from_archive(const std::string& input_file, + DynamicPrintConfig* config, + ConfigSubstitutionContext* config_substitutions, + boost::optional &prusaslicer_generator_version, + LoadAttributes options = LoadAttribute::AddDefaultInstances); + + Model load_model(const std::string& input_file); + Model load_model(const std::string& input_file, std::string& errors); + TriangleMesh load_mesh(const std::string& input_file); +} + +ENABLE_ENUM_BITMASK_OPERATORS(FileReader::LoadAttribute) + +} // namespace Slic3r::ModelProcessing diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index f87bf28e3b..e435940b2f 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -22,14 +22,6 @@ #include "TriangleSelector.hpp" #include "MultipleBeds.hpp" -#include "Format/AMF.hpp" -#include "Format/OBJ.hpp" -#include "Format/STL.hpp" -#include "Format/3mf.hpp" -#include "Format/STEP.hpp" -#include "Format/SVG.hpp" -#include "Format/PrintRequest.hpp" - #include #include @@ -148,109 +140,6 @@ const CustomGCode::Info& Model::custom_gcode_per_print_z() const { return custom_gcode_per_print_z_vector[s_multiple_beds.get_active_bed()]; } - - -// Loading model from a file, it may be a simple geometry file as STL or OBJ, however it may be a project file as well. -Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, LoadAttributes options) -{ - Model model; - - DynamicPrintConfig temp_config; - ConfigSubstitutionContext temp_config_substitutions_context(ForwardCompatibilitySubstitutionRule::EnableSilent); - if (config == nullptr) - config = &temp_config; - if (config_substitutions == nullptr) - config_substitutions = &temp_config_substitutions_context; - - bool result = false; - if (boost::algorithm::iends_with(input_file, ".stl")) - result = load_stl(input_file.c_str(), &model); - else if (boost::algorithm::iends_with(input_file, ".obj")) - result = load_obj(input_file.c_str(), &model); - else if (boost::algorithm::iends_with(input_file, ".step") || boost::algorithm::iends_with(input_file, ".stp")) - result = load_step(input_file.c_str(), &model); - else if (boost::algorithm::iends_with(input_file, ".amf") || boost::algorithm::iends_with(input_file, ".amf.xml")) - result = load_amf(input_file.c_str(), config, config_substitutions, &model, options & LoadAttribute::CheckVersion); - else if (boost::algorithm::iends_with(input_file, ".3mf") || boost::algorithm::iends_with(input_file, ".zip")) { - //FIXME options & LoadAttribute::CheckVersion ? - boost::optional prusaslicer_generator_version; - result = load_3mf(input_file.c_str(), *config, *config_substitutions, &model, false, prusaslicer_generator_version); - } else if (boost::algorithm::iends_with(input_file, ".svg")) - result = load_svg(input_file, model); - else if (boost::ends_with(input_file, ".printRequest")) - result = load_printRequest(input_file.c_str(), &model); - else - throw Slic3r::RuntimeError("Unknown file format. Input file must have .stl, .obj, .step/.stp, .svg, .amf(.xml) or extension .3mf(.zip)."); - - if (! result) - throw Slic3r::RuntimeError("Loading of a model file failed."); - - if (model.objects.empty()) - throw Slic3r::RuntimeError("The supplied file couldn't be read because it's empty"); - - if (!boost::ends_with(input_file, ".printRequest")) - for (ModelObject *o : model.objects) - o->input_file = input_file; - - if (options & LoadAttribute::AddDefaultInstances) - model.add_default_instances(); - - for (CustomGCode::Info& info : model.custom_gcode_per_print_z_vector) { - CustomGCode::update_custom_gcode_per_print_z_from_config(info, config); - CustomGCode::check_mode_for_custom_gcode_per_print_z(info); - } - - sort_remove_duplicates(config_substitutions->substitutions); - return model; -} - -// Loading model from a file (3MF or AMF), not from a simple geometry file (STL or OBJ). -Model Model::read_from_archive( - const std::string& input_file, - DynamicPrintConfig* config, - ConfigSubstitutionContext* config_substitutions, - boost::optional &prusaslicer_generator_version, - LoadAttributes options -) { - assert(config != nullptr); - assert(config_substitutions != nullptr); - - Model model; - - bool result = false; - if (boost::algorithm::iends_with(input_file, ".3mf") || boost::algorithm::iends_with(input_file, ".zip")) { - result = load_3mf(input_file.c_str(), *config, *config_substitutions, &model, options & LoadAttribute::CheckVersion, prusaslicer_generator_version); - } else if (boost::algorithm::iends_with(input_file, ".zip.amf")) - result = load_amf(input_file.c_str(), config, config_substitutions, &model, options & LoadAttribute::CheckVersion); - else - throw Slic3r::RuntimeError("Unknown file format. Input file must have .3mf or .zip.amf extension."); - - if (!result) - throw Slic3r::RuntimeError("Loading of a model file failed."); - - for (ModelObject *o : model.objects) { -// if (boost::algorithm::iends_with(input_file, ".zip.amf")) -// { -// // we remove the .zip part of the extension to avoid it be added to filenames when exporting -// o->input_file = boost::ireplace_last_copy(input_file, ".zip.", "."); -// } -// else - o->input_file = input_file; - } - - if (options & LoadAttribute::AddDefaultInstances) - model.add_default_instances(); - - for (CustomGCode::Info& info : model.custom_gcode_per_print_z_vector) { - CustomGCode::update_custom_gcode_per_print_z_from_config(info, config); - CustomGCode::check_mode_for_custom_gcode_per_print_z(info); - } - - handle_legacy_sla(*config); - - return model; -} - ModelObject* Model::add_object() { this->objects.emplace_back(new ModelObject(this)); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 986d34e08f..bd0127791e 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -14,17 +14,14 @@ #define slic3r_Model_hpp_ #include "libslic3r.h" -#include "enum_bitmask.hpp" #include "Geometry.hpp" #include "ObjectID.hpp" #include "Point.hpp" -#include "PrintConfig.hpp" #include "Slicing.hpp" #include "SLA/SupportPoint.hpp" #include "SLA/Hollowing.hpp" #include "TriangleMesh.hpp" #include "CustomGCode.hpp" -#include "enum_bitmask.hpp" #include "TextConfiguration.hpp" #include "EmbossShape.hpp" #include "TriangleSelector.hpp" @@ -1295,24 +1292,6 @@ public: OBJECTBASE_DERIVED_COPY_MOVE_CLONE(Model) - enum class LoadAttribute : int { - AddDefaultInstances, - CheckVersion - }; - using LoadAttributes = enum_bitmask; - - static Model read_from_file( - const std::string& input_file, - DynamicPrintConfig* config = nullptr, ConfigSubstitutionContext* config_substitutions = nullptr, - LoadAttributes options = LoadAttribute::AddDefaultInstances); - static Model read_from_archive( - const std::string& input_file, - DynamicPrintConfig* config, - ConfigSubstitutionContext* config_substitutions, - boost::optional &prusaslicer_generator_version, - LoadAttributes options = LoadAttribute::AddDefaultInstances - ); - // Add a new ModelObject to this Model, generate a new ID for this ModelObject. ModelObject* add_object(); ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh); @@ -1381,8 +1360,6 @@ private: } }; -ENABLE_ENUM_BITMASK_OPERATORS(Model::LoadAttribute) - #undef OBJECTBASE_DERIVED_COPY_MOVE_CLONE #undef OBJECTBASE_DERIVED_PRIVATE_COPY_MOVE diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index 8a6f3dddb7..9f8acb10ff 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -19,8 +19,9 @@ #include #include "libslic3r/BoundingBox.hpp" -#include "libslic3r/Model.hpp" #include "libslic3r/Polygon.hpp" +#include "libslic3r/FileReader.hpp" +#include "libslic3r/TriangleMesh.hpp" #include #include @@ -535,17 +536,15 @@ void BedShapePanel::load_stl() } wxBusyCursor wait; - - Model model; - try { - model = Model::read_from_file(file_name); - } - catch (std::exception &) { - show_error(this, _L("Error! Invalid model")); + TriangleMesh mesh; + try { + mesh = FileReader::load_mesh(file_name); + } + catch (std::exception& e) { + show_error(this, e.what()); return; } - auto mesh = model.mesh(); auto expolygons = mesh.horizontal_projection(); if (expolygons.size() == 0) { diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 3b714714dc..5b50723363 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -14,7 +14,7 @@ #endif // ENABLE_GLMODEL_STATISTICS #include "libslic3r/TriangleMesh.hpp" -#include "libslic3r/Model.hpp" +#include "libslic3r/FileReader.hpp" #include "libslic3r/Polygon.hpp" #include "libslic3r/BuildVolume.hpp" #include "libslic3r/Geometry/ConvexHull.hpp" @@ -653,15 +653,14 @@ bool GLModel::init_from_file(const std::string& filename) if (!boost::algorithm::iends_with(filename, ".stl")) return false; - Model model; + TriangleMesh mesh; try { - model = Model::read_from_file(filename); + mesh = FileReader::load_mesh(filename); } catch (std::exception&) { return false; } - - init_from(model.mesh()); + init_from(mesh); m_filename = filename; diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 34cfead654..d1cc9f5c4a 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -5,6 +5,7 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/PresetBundle.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/ModelProcessing.hpp" #include "GUI_Factories.hpp" #include "GUI_ObjectList.hpp" diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 763873a6da..e5160deab7 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -9,6 +9,7 @@ #include "libslic3r/TextConfiguration.hpp" #include "libslic3r/BuildVolume.hpp" // IWYU pragma: keep #include "libslic3r/ModelProcessing.hpp" +#include "libslic3r/FileReader.hpp" #include "GUI_ObjectList.hpp" #include "GUI_Factories.hpp" #include "GUI_ObjectManipulation.hpp" @@ -1608,10 +1609,10 @@ void ObjectList::load_from_files(const wxArrayString& input_files, ModelObject& Model model; try { - model = Model::read_from_file(input_file); + model = FileReader::load_model(input_file); } catch (std::exception& e) { - auto msg = _L("Error!") + " " + input_file + " : " + e.what() + "."; + auto msg = _L("Error!") + " " + input_file + " : " + _(e.what()) + "."; show_error(parent, msg); exit(1); } diff --git a/src/slic3r/GUI/GalleryDialog.cpp b/src/slic3r/GUI/GalleryDialog.cpp index 438fc42962..e344ffc9ba 100644 --- a/src/slic3r/GUI/GalleryDialog.cpp +++ b/src/slic3r/GUI/GalleryDialog.cpp @@ -33,6 +33,7 @@ #include "libslic3r/AppConfig.hpp" #include "libslic3r/BuildVolume.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/FileReader.hpp" #include "libslic3r/GCode/ThumbnailData.hpp" #include "libslic3r/Format/OBJ.hpp" #include "libslic3r/MultipleBeds.hpp" @@ -64,7 +65,7 @@ bool GalleryDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& f // hides the system icon this->MSWUpdateDragImageOnLeave(); #endif // WIN32 - return gallery_dlg ? gallery_dlg->load_files(filenames) : false; + return gallery_dlg ? gallery_dlg->add_files_to_custom_dir(filenames) : false; } @@ -281,7 +282,7 @@ static void generate_thumbnail_from_model(const std::string& filename) Model model; try { - model = Model::read_from_file(filename); + model = FileReader::load_model(filename); } catch (std::exception&) { BOOST_LOG_TRIVIAL(error) << "Error loading model from " << filename << " in generate_thumbnail_from_model()"; @@ -343,10 +344,15 @@ void GalleryDialog::load_label_icon_list() std::vector sorted_names; for (auto& dir_entry : fs::directory_iterator(dir)) { - TriangleMesh mesh; - if ((is_gallery_file(dir_entry, ".stl") && mesh.ReadSTLFile(dir_entry.path().string().c_str())) || - (is_gallery_file(dir_entry, ".obj") && load_obj(dir_entry.path().string().c_str(), &mesh) ) ) + if (is_gallery_file(dir_entry, ".stl") || is_gallery_file(dir_entry, ".obj")) { + try { + Model model = FileReader::load_model(dir_entry.path().string()); + } + catch (std::exception&) { + continue; + } sorted_names.push_back(dir_entry.path().filename().string()); + } } // sort the filename case insensitive @@ -441,7 +447,7 @@ void GalleryDialog::add_custom_shapes(wxEvent& event) if (input_files.IsEmpty()) return; - load_files(input_files); + add_files_to_custom_dir(input_files); } void GalleryDialog::del_custom_shapes() @@ -558,7 +564,7 @@ void GalleryDialog::update() load_label_icon_list(); } -bool GalleryDialog::load_files(const wxArrayString& input_files) +bool GalleryDialog::add_files_to_custom_dir(const wxArrayString& input_files) { auto dest_dir = get_dir(false); @@ -577,16 +583,14 @@ bool GalleryDialog::load_files(const wxArrayString& input_files) // Iterate through the input files for (size_t i = 0; i < input_files.size(); ++i) { std::string input_file = into_u8(input_files.Item(i)); - - TriangleMesh mesh; - if (is_gallery_file(input_file, ".stl") && !mesh.ReadSTLFile(input_file.c_str())) { - show_warning(format_wxstr(_L("Loading of the \"%1%\""), input_file), "STL"); - continue; - } - - if (is_gallery_file(input_file, ".obj") && !load_obj(input_file.c_str(), &mesh)) { - show_warning(format_wxstr(_L("Loading of the \"%1%\""), input_file), "OBJ"); - continue; + if (is_gallery_file(input_file, ".stl") || is_gallery_file(input_file, ".obj")) { + try { + Model model = FileReader::load_model(input_file); + } + catch (std::exception&) { + show_warning(format_wxstr(_L("Loading of the \"%1%\""), input_file), is_gallery_file(input_file, ".obj") ? "OBJ" : "STL"); + continue; + } } try { diff --git a/src/slic3r/GUI/GalleryDialog.hpp b/src/slic3r/GUI/GalleryDialog.hpp index 085335c8b2..94799708b7 100644 --- a/src/slic3r/GUI/GalleryDialog.hpp +++ b/src/slic3r/GUI/GalleryDialog.hpp @@ -58,7 +58,7 @@ public: int show(bool show_from_menu = false); void get_input_files(wxArrayString& input_files); - bool load_files(const wxArrayString& input_files); + bool add_files_to_custom_dir(const wxArrayString& input_files); protected: void on_dpi_changed(const wxRect& suggested_rect) override; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 7b24ac2780..23a49fe0ca 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -77,6 +77,7 @@ #include "libslic3r/PresetBundle.hpp" #include "libslic3r/miniz_extension.hpp" #include "libslic3r/ModelProcessing.hpp" +#include "libslic3r/FileReader.hpp" #include "libslic3r/MultipleBeds.hpp" // For stl export @@ -1303,7 +1304,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ { DynamicPrintConfig config_loaded; ConfigSubstitutionContext config_substitutions{ ForwardCompatibilitySubstitutionRule::Enable }; - model = Slic3r::Model::read_from_archive( + model = FileReader::read_from_archive( path.string(), &config_loaded, &config_substitutions, @@ -1368,7 +1369,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ } } else { - model = Slic3r::Model::read_from_file(path.string(), nullptr, nullptr, only_if(load_config, Model::LoadAttribute::CheckVersion)); + model = FileReader::read_from_file(path.string(), nullptr, nullptr, only_if(load_config, FileReader::LoadAttribute::CheckVersion)); for (auto obj : model.objects) if (obj->name.empty()) obj->name = fs::path(obj->input_file).filename().string(); @@ -2638,7 +2639,7 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const Model new_model; try { - new_model = Model::read_from_file(path, nullptr, nullptr, Model::LoadAttribute::AddDefaultInstances); + new_model = FileReader::load_model(path); for (ModelObject* model_object : new_model.objects) { model_object->center_around_origin(); model_object->ensure_on_bed(); @@ -2888,7 +2889,7 @@ void Plater::priv::reload_from_disk() Model new_model; try { - new_model = Model::read_from_file(path, nullptr, nullptr, Model::LoadAttribute::AddDefaultInstances); + new_model = FileReader::load_model(path); for (ModelObject* model_object : new_model.objects) { model_object->center_around_origin(); model_object->ensure_on_bed(); diff --git a/tests/sla_print/sla_archive_readwrite_tests.cpp b/tests/sla_print/sla_archive_readwrite_tests.cpp index fb1af3d7f7..3c1dc835fd 100644 --- a/tests/sla_print/sla_archive_readwrite_tests.cpp +++ b/tests/sla_print/sla_archive_readwrite_tests.cpp @@ -6,6 +6,7 @@ #include "libslic3r/Format/SLAArchiveFormatRegistry.hpp" #include "libslic3r/Format/SLAArchiveWriter.hpp" #include "libslic3r/Format/SLAArchiveReader.hpp" +#include "libslic3r/FileReader.hpp" #include @@ -20,7 +21,7 @@ TEST_CASE("Archive export test", "[sla_archives]") { SLAPrint print; SLAFullPrintConfig fullcfg; - auto m = Model::read_from_file(TEST_DATA_DIR PATH_SEPARATOR + std::string(pname) + ".obj", nullptr); + auto m = FileReader::load_model(TEST_DATA_DIR PATH_SEPARATOR + std::string(pname) + ".obj"); fullcfg.printer_technology.setInt(ptSLA); // FIXME this should be ensured fullcfg.set("sla_archive_format", entry.id); diff --git a/tests/slic3rutils/slic3r_arrangejob_tests.cpp b/tests/slic3rutils/slic3r_arrangejob_tests.cpp index 1cd35de5b4..ee492ff2cb 100644 --- a/tests/slic3rutils/slic3r_arrangejob_tests.cpp +++ b/tests/slic3rutils/slic3r_arrangejob_tests.cpp @@ -9,6 +9,7 @@ #include "slic3r/GUI/Jobs/ArrangeJob2.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/FileReader.hpp" #include "libslic3r/SLAPrint.hpp" #include "libslic3r/Format/3mf.hpp" @@ -84,7 +85,7 @@ TEST_CASE("Basic arrange with cube", "[arrangejob]") { DynamicPrintConfig cfg; cfg.load_from_ini(basepath + "default_fff.ini", ForwardCompatibilitySubstitutionRule::Enable); - Model m = Model::read_from_file(basepath + "20mm_cube.obj", &cfg); + Model m = FileReader::load_model(basepath + "20mm_cube.obj"); UIThreadWorker w; arr2::ArrangeSettings settings;