From ed10d7d2e67613da835cf8454dfb419c56cd64f7 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 23 May 2024 13:09:25 +0200 Subject: [PATCH 01/11] Add some missing imports NP-205 --- include/geometry/LinesSet.h | 1 + include/settings/types/LayerIndex.h | 1 + include/slicer.h | 1 + 3 files changed, 3 insertions(+) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index 1e885cb89c..a344e763b5 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -9,6 +9,7 @@ #include #include "geometry/OpenLinesSet.h" +#include "geometry/Polygon.h" #include "geometry/Point2LL.h" namespace cura diff --git a/include/settings/types/LayerIndex.h b/include/settings/types/LayerIndex.h index 9e2100da87..a4de451913 100644 --- a/include/settings/types/LayerIndex.h +++ b/include/settings/types/LayerIndex.h @@ -9,6 +9,7 @@ #include #include "utils/types/generic.h" +#include "geometry/Polygon.h" namespace cura { diff --git a/include/slicer.h b/include/slicer.h index ddafd67ca3..e3d3500fe1 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -11,6 +11,7 @@ #include "geometry/LinesSet.h" #include "geometry/OpenLinesSet.h" #include "geometry/OpenPolyline.h" +#include "geometry/Polygon.h" #include "geometry/Shape.h" #include "settings/EnumSettings.h" From 0b161852a0d197dbbc6f0fe47d4566777dc5d046 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 23 May 2024 13:10:14 +0200 Subject: [PATCH 02/11] Don't use `NoCopy` class to prevent copying But delete copy operator/assignment instead NP-205 --- include/MeshGroup.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/MeshGroup.h b/include/MeshGroup.h index 232bf08662..6f20523f4a 100644 --- a/include/MeshGroup.h +++ b/include/MeshGroup.h @@ -18,9 +18,21 @@ class Matrix4x3D; * One MeshGroup is a whole which is printed at once. * Generally there is one single MeshGroup, though when using one-at-a-time printing, multiple MeshGroups are processed consecutively. */ -class MeshGroup : public NoCopy +class MeshGroup { public: + MeshGroup() = default; + + ~MeshGroup() = default; + + MeshGroup(MeshGroup&& other) noexcept = default; + + MeshGroup& operator=(MeshGroup&& other) noexcept = default; + + /* Copying a MeshGroup is not allowed */ + MeshGroup(const MeshGroup& other) = delete; + MeshGroup& operator=(const MeshGroup& other) = delete; + std::vector meshes; Settings settings; From f1ad7840f777896cdf45003add0fec85b203904c Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 23 May 2024 15:21:42 +0200 Subject: [PATCH 03/11] Add command line option to parse json's NP-205 --- include/communication/CommandLine.h | 15 +++ src/Application.cpp | 1 + src/MeshGroup.cpp | 5 + src/communication/CommandLine.cpp | 155 ++++++++++++++++++++++++++++ 4 files changed, 176 insertions(+) diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index 47b27f6586..5f70994517 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -5,6 +5,7 @@ #define COMMANDLINE_H #include +#include #include //Loading JSON documents to get settings from them. #include //To store the command line arguments. #include //To store the command line arguments. @@ -212,6 +213,20 @@ class CommandLine : public Communication * \return The first definition file that matches the definition ID. */ static std::string findDefinitionFile(const std::string& definition_id, const std::vector& search_directories); + + /* + * \brief Read the resolved JSON values from a file. + * \param element The path to the file to read the JSON values from. + * \return The resolved JSON values. + */ + static std::optional>> readResolvedJsonValues(const std::filesystem::path& element); + + /* + * \brief Read the resolved JSON values from a document. + * \param document The document to read the JSON values from. + * \return The resolved JSON values. + */ + static std::optional>> readResolvedJsonValues(const rapidjson::Document& document); }; } // namespace cura diff --git a/src/Application.cpp b/src/Application.cpp index 14f5a1bf7d..cb0f17b297 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -131,6 +131,7 @@ void Application::printHelp() const fmt::print(" -p\n\tLog progress information.\n"); fmt::print(" -d Add definition search paths seperated by a `:` (Unix) or `;` (Windows)\n"); fmt::print(" -j\n\tLoad settings.def.json file to register all settings and their defaults.\n"); + fmt::print(" -r\n\tLoad a json file containing resolved setting values.\n"); fmt::print(" -s =\n\tSet a setting to a value for the last supplied object, \n\textruder train, or general settings.\n"); fmt::print(" -l \n\tLoad an STL model. \n"); fmt::print(" -g\n\tSwitch setting focus to the current mesh group only.\n\tUsed for one-at-a-time printing.\n"); diff --git a/src/MeshGroup.cpp b/src/MeshGroup.cpp index f71b2f7bd5..b518d77328 100644 --- a/src/MeshGroup.cpp +++ b/src/MeshGroup.cpp @@ -293,6 +293,11 @@ bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, const Mat spdlog::info("loading '{}' took {:03.3f} seconds", filename, load_timer.restart()); return true; } + else + { + spdlog::warn("loading '{}' failed", filename); + return false; + } } spdlog::warn("Unable to recognize the extension of the file. Currently only .stl and .STL are supported."); return false; diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index de88960fbf..fb078b0df7 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -8,12 +8,16 @@ #include #include //To check if files exist. #include //For std::accumulate. +#include #include //Loading JSON documents to get settings from them. #include #include #include #include +#include +#include #include +#include #include #include @@ -22,6 +26,7 @@ #include "Application.h" //To get the extruders for material estimates. #include "ExtruderTrain.h" #include "FffProcessor.h" //To start a slice and get time estimates. +#include "MeshGroup.h" #include "Slice.h" #include "utils/Matrix4x3D.h" //For the mesh_rotation_matrix setting. #include "utils/format/filesystem_path.h" @@ -354,6 +359,107 @@ void CommandLine::sliceNext() last_settings->add(key, value); break; } + case 'r': + { + // read in resolved values + + argument_index++; + if (argument_index >= arguments_.size()) + { + spdlog::error("Missing setting name and value with -s argument."); + exit(1); + } + argument = arguments_[argument_index]; + const auto settings = readResolvedJsonValues(std::filesystem::path{ argument }); + + if (! settings.has_value()) + { + spdlog::error("Failed to load JSON file: {}", argument); + exit(1); + } + + constexpr std::string_view global_identifier = "global"; + constexpr std::string_view extruder_identifier = "extruder."; + constexpr std::string_view model_identifier = "model."; + constexpr std::string_view limit_to_extruder_identifier = "limit_to_extruder"; + + // Split the settings into global, extruder and model settings. This is needed since the order in which the settings are applied is important. + // first global settings, then extruder settings, then model settings. The order of these stacks is not enforced in the JSON files. + std::unordered_map global_settings; + std::unordered_map> extruder_settings; + std::unordered_map> model_settings; + std::unordered_map limit_to_extruder; + + for (const auto& [key, values] : settings.value()) + { + if (key == global_identifier) + { + global_settings = values; + } + else if (key.starts_with(extruder_identifier)) + { + extruder_settings[key] = values; + } + else if (key == limit_to_extruder_identifier) + { + limit_to_extruder = values; + } + else + { + model_settings[key] = values; + } + } + + for (const auto& [setting_key, setting_value] : global_settings) + { + slice.scene.settings.add(setting_key, setting_value); + } + + for (const auto& [key, values] : extruder_settings) + { + const auto extruder_nr = std::stoi(key.substr(extruder_identifier.size())); + while (slice.scene.extruders.size() <= static_cast(extruder_nr)) + { + slice.scene.extruders.emplace_back(extruder_nr, &slice.scene.settings); + } + for (const auto& [setting_key, setting_value] : values) + { + slice.scene.extruders[extruder_nr].settings_.add(setting_key, setting_value); + } + } + + for (const auto& [key, values] : model_settings) + { + const auto model_name = key; + + cura::MeshGroup mesh_group; + for (const auto& [setting_key, setting_value] : values) + { + mesh_group.settings.add(setting_key, setting_value); + } + + const auto transformation = mesh_group.settings.get("mesh_rotation_matrix"); + const auto extruder_nr = mesh_group.settings.get("extruder_nr"); + + if (! loadMeshIntoMeshGroup(&mesh_group, model_name.c_str(), transformation, slice.scene.extruders[extruder_nr].settings_)) + { + spdlog::error("Failed to load model: {}. (error number {})", model_name, errno); + exit(1); + } + + slice.scene.mesh_groups.push_back(std::move(mesh_group)); + } + for (const auto& [key, value] : limit_to_extruder) + { + const auto extruder_nr = std::stoi(value.substr(extruder_identifier.size())); + if (extruder_nr >= 0) + { + slice.scene.limit_to_extruder[key] = &slice.scene.extruders[extruder_nr]; + } + } + + break; + } default: { spdlog::error("Unknown option: -{}", argument[1]); @@ -586,6 +692,55 @@ void CommandLine::loadJSONSettings(const rapidjson::Value& element, Settings& se } } +std::optional>> CommandLine::readResolvedJsonValues(const std::filesystem::path& json_filename) +{ + std::ifstream file(json_filename, std::ios::binary); + if (! file) + { + spdlog::error("Couldn't open JSON file: {}", json_filename); + return std::nullopt; + } + + std::vector read_buffer(std::istreambuf_iterator(file), {}); + rapidjson::MemoryStream memory_stream(read_buffer.data(), read_buffer.size()); + + rapidjson::Document json_document; + json_document.ParseStream(memory_stream); + if (json_document.HasParseError()) + { + spdlog::error("Error parsing JSON (offset {}): {}", json_document.GetErrorOffset(), GetParseError_En(json_document.GetParseError())); + return std::nullopt; + } + + return readResolvedJsonValues(json_document); +} + +std::optional>> CommandLine::readResolvedJsonValues(const rapidjson::Document& document) +{ + if (! document.IsObject()) + { + return std::nullopt; + } + + std::unordered_map> result; + for (rapidjson::Value::ConstMemberIterator resolved_key = document.MemberBegin(); resolved_key != document.MemberEnd(); resolved_key++) + { + std::unordered_map values; + for (rapidjson::Value::ConstMemberIterator resolved_value = resolved_key->value.MemberBegin(); resolved_value != resolved_key->value.MemberEnd(); resolved_value++) + { + std::string value_string; + if (! jsonValue2Str(resolved_value->value, value_string)) + { + spdlog::warn("Unrecognized data type in JSON setting {}", resolved_value->name.GetString()); + continue; + } + values.emplace(resolved_value->name.GetString(), value_string); + } + result.emplace(resolved_key->name.GetString(), std::move(values)); + } + return result; +} + std::string CommandLine::findDefinitionFile(const std::string& definition_id, const std::vector& search_directories) { for (const auto& search_directory : search_directories) From 1f66d0ee584321118957825b065dc863822a920f Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Thu, 23 May 2024 13:49:08 +0000 Subject: [PATCH 04/11] Applied clang-format. --- include/geometry/LinesSet.h | 2 +- include/settings/types/LayerIndex.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index a344e763b5..e76a1a77c7 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -9,8 +9,8 @@ #include #include "geometry/OpenLinesSet.h" -#include "geometry/Polygon.h" #include "geometry/Point2LL.h" +#include "geometry/Polygon.h" namespace cura { diff --git a/include/settings/types/LayerIndex.h b/include/settings/types/LayerIndex.h index a4de451913..d707c1eca2 100644 --- a/include/settings/types/LayerIndex.h +++ b/include/settings/types/LayerIndex.h @@ -8,8 +8,8 @@ #include -#include "utils/types/generic.h" #include "geometry/Polygon.h" +#include "utils/types/generic.h" namespace cura { From 7991a2d8714ef067a1e6a5385ea944c5f9f365ed Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 23 May 2024 17:02:18 +0200 Subject: [PATCH 05/11] Add missing import NP-205 --- include/communication/CommandLine.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index 5f70994517..f09f64cee2 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -6,6 +6,7 @@ #include #include +#include #include //Loading JSON documents to get settings from them. #include //To store the command line arguments. #include //To store the command line arguments. @@ -219,7 +220,7 @@ class CommandLine : public Communication * \param element The path to the file to read the JSON values from. * \return The resolved JSON values. */ - static std::optional>> readResolvedJsonValues(const std::filesystem::path& element); + static std::optional>> readResolvedJsonValues(const std::filesystem::path& json_filename); /* * \brief Read the resolved JSON values from a document. From 2977386be1323aaa64d1c93018480cd4c9244d03 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Thu, 23 May 2024 15:03:01 +0000 Subject: [PATCH 06/11] Applied clang-format. --- include/communication/CommandLine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index f09f64cee2..c277f61614 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -6,9 +6,9 @@ #include #include -#include #include //Loading JSON documents to get settings from them. #include //To store the command line arguments. +#include #include //To store the command line arguments. #include "Communication.h" //The class we're implementing. From ed9004ae312aaf32bef5b2ff71ca0bfe412364cd Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 23 May 2024 17:14:53 +0200 Subject: [PATCH 07/11] Add documentation regarding the format of the resolved json file NP-205 --- src/communication/CommandLine.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index fb078b0df7..040948c5b5 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -361,7 +361,27 @@ void CommandLine::sliceNext() } case 'r': { - // read in resolved values + /* + * read in resolved values from a json file. The json format of the file resolved settings is the following: + * + * ``` + * { + * "global": [SETTINGS], + * "extruder.0": [SETTINGS], + * "extruder.1": [SETTINGS], + * "model.stl": [SETTINGS] + * } + * ``` + * where `[SETTINGS]` follow the schema + * ``` + * { + * [key: string]: bool | string | number | number[] | number[][] + * } + * ``` + * There can be any number of extruders (denoted with `extruder.n`) and any number of models (denoted with `[modelname].stl`). + * The key of the model values will also be the filename of the relevant model, when running CuraEngine with this option the + * model file with that same name _must_ be in the same folder as the resolved settings json. + */ argument_index++; if (argument_index >= arguments_.size()) From d30480b4122f257a3d87569b73fb8db7b15805e2 Mon Sep 17 00:00:00 2001 From: Casper Lamboo Date: Thu, 23 May 2024 19:15:17 +0200 Subject: [PATCH 08/11] Remove redundant else Co-authored-by: Jelle Spijker --- src/MeshGroup.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/MeshGroup.cpp b/src/MeshGroup.cpp index b518d77328..91fae7ae5c 100644 --- a/src/MeshGroup.cpp +++ b/src/MeshGroup.cpp @@ -293,11 +293,8 @@ bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, const Mat spdlog::info("loading '{}' took {:03.3f} seconds", filename, load_timer.restart()); return true; } - else - { - spdlog::warn("loading '{}' failed", filename); - return false; - } + spdlog::warn("loading '{}' failed", filename); + return false; } spdlog::warn("Unable to recognize the extension of the file. Currently only .stl and .STL are supported."); return false; From 57d357d497f7e824cb0c8526799b5ed1978fb1d5 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 24 May 2024 10:16:59 +0200 Subject: [PATCH 09/11] Fix polygon imports NP-205 --- include/geometry/LinesSet.h | 1 - include/geometry/Shape.h | 1 + include/settings/types/LayerIndex.h | 1 - include/slicer.h | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index e76a1a77c7..1e885cb89c 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -10,7 +10,6 @@ #include "geometry/OpenLinesSet.h" #include "geometry/Point2LL.h" -#include "geometry/Polygon.h" namespace cura { diff --git a/include/geometry/Shape.h b/include/geometry/Shape.h index 46091d49a3..f2edf6c79c 100644 --- a/include/geometry/Shape.h +++ b/include/geometry/Shape.h @@ -6,6 +6,7 @@ #include "geometry/LinesSet.h" #include "settings/types/Angle.h" +#include "geometry/Polygon.h" namespace cura { diff --git a/include/settings/types/LayerIndex.h b/include/settings/types/LayerIndex.h index d707c1eca2..9e2100da87 100644 --- a/include/settings/types/LayerIndex.h +++ b/include/settings/types/LayerIndex.h @@ -8,7 +8,6 @@ #include -#include "geometry/Polygon.h" #include "utils/types/generic.h" namespace cura diff --git a/include/slicer.h b/include/slicer.h index e3d3500fe1..ddafd67ca3 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -11,7 +11,6 @@ #include "geometry/LinesSet.h" #include "geometry/OpenLinesSet.h" #include "geometry/OpenPolyline.h" -#include "geometry/Polygon.h" #include "geometry/Shape.h" #include "settings/EnumSettings.h" From 5c2dcea607f993186a96a33cd643066d14df9e28 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Fri, 24 May 2024 08:17:36 +0000 Subject: [PATCH 10/11] Applied clang-format. --- include/geometry/Shape.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/geometry/Shape.h b/include/geometry/Shape.h index f2edf6c79c..aaa373f4e1 100644 --- a/include/geometry/Shape.h +++ b/include/geometry/Shape.h @@ -5,8 +5,8 @@ #define GEOMETRY_SHAPE_H #include "geometry/LinesSet.h" -#include "settings/types/Angle.h" #include "geometry/Polygon.h" +#include "settings/types/Angle.h" namespace cura { From 549f4a9fa8bf5b42bcf935138962c8319687f7b4 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 24 May 2024 12:48:19 +0200 Subject: [PATCH 11/11] Add type aliases NP-205 --- include/communication/CommandLine.h | 7 +++++-- src/communication/CommandLine.cpp | 14 +++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index c277f61614..55c742871a 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -17,6 +17,9 @@ namespace cura { class Settings; +using setting_map = std::unordered_map; +using container_setting_map = std::unordered_map; + /* * \brief When slicing via the command line, interprets the command line * arguments to initiate a slice. @@ -220,14 +223,14 @@ class CommandLine : public Communication * \param element The path to the file to read the JSON values from. * \return The resolved JSON values. */ - static std::optional>> readResolvedJsonValues(const std::filesystem::path& json_filename); + static std::optional readResolvedJsonValues(const std::filesystem::path& json_filename); /* * \brief Read the resolved JSON values from a document. * \param document The document to read the JSON values from. * \return The resolved JSON values. */ - static std::optional>> readResolvedJsonValues(const rapidjson::Document& document); + static std::optional readResolvedJsonValues(const rapidjson::Document& document); }; } // namespace cura diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index 040948c5b5..12e04adc13 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -386,7 +386,7 @@ void CommandLine::sliceNext() argument_index++; if (argument_index >= arguments_.size()) { - spdlog::error("Missing setting name and value with -s argument."); + spdlog::error("Missing setting name and value with -r argument."); exit(1); } argument = arguments_[argument_index]; @@ -406,8 +406,8 @@ void CommandLine::sliceNext() // Split the settings into global, extruder and model settings. This is needed since the order in which the settings are applied is important. // first global settings, then extruder settings, then model settings. The order of these stacks is not enforced in the JSON files. std::unordered_map global_settings; - std::unordered_map> extruder_settings; - std::unordered_map> model_settings; + container_setting_map extruder_settings; + container_setting_map model_settings; std::unordered_map limit_to_extruder; for (const auto& [key, values] : settings.value()) @@ -450,7 +450,7 @@ void CommandLine::sliceNext() for (const auto& [key, values] : model_settings) { - const auto model_name = key; + const auto& model_name = key; cura::MeshGroup mesh_group; for (const auto& [setting_key, setting_value] : values) @@ -712,7 +712,7 @@ void CommandLine::loadJSONSettings(const rapidjson::Value& element, Settings& se } } -std::optional>> CommandLine::readResolvedJsonValues(const std::filesystem::path& json_filename) +std::optional CommandLine::readResolvedJsonValues(const std::filesystem::path& json_filename) { std::ifstream file(json_filename, std::ios::binary); if (! file) @@ -735,14 +735,14 @@ std::optional>> CommandLine::readResolvedJsonValues(const rapidjson::Document& document) +std::optional CommandLine::readResolvedJsonValues(const rapidjson::Document& document) { if (! document.IsObject()) { return std::nullopt; } - std::unordered_map> result; + container_setting_map result; for (rapidjson::Value::ConstMemberIterator resolved_key = document.MemberBegin(); resolved_key != document.MemberEnd(); resolved_key++) { std::unordered_map values;