diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 3a8974d254..9e19dd2d9e 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -118,7 +118,7 @@ jobs: - name: Run Unit Test CuraEngine id: run-test run: ctest --output-junit engine_test.xml - working-directory: cmake-build-release + working-directory: build/Release - name: Publish Unit Test Results id: test-results diff --git a/CMakeLists.txt b/CMakeLists.txt index 92c523ffc0..9d37805e43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,7 +121,6 @@ set(engine_SRCS # Except main.cpp. src/utils/gettime.cpp src/utils/LinearAlg2D.cpp src/utils/ListPolyIt.cpp - src/utils/logoutput.cpp src/utils/MinimumSpanningTree.cpp src/utils/Point3.cpp src/utils/PolygonConnector.cpp @@ -184,12 +183,14 @@ find_package(clipper REQUIRED) find_package(rapidjson REQUIRED) find_package(stb REQUIRED) find_package(Boost REQUIRED) +find_package(spdlog REQUIRED) +find_package(fmt REQUIRED) if (ENABLE_TESTING) find_package(GTest REQUIRED) endif () -target_link_libraries(_CuraEngine PRIVATE clipper::clipper rapidjson::rapidjson stb::stb boost::boost $<$:GTest::gtest>) +target_link_libraries(_CuraEngine PUBLIC spdlog::spdlog PRIVATE fmt::fmt clipper::clipper rapidjson::rapidjson stb::stb boost::boost $<$:GTest::gtest>) if (NOT WIN32) add_executable(CuraEngine src/main.cpp) # Then compile main.cpp as separate executable, and link the library to it. diff --git a/conandata.yml b/conandata.yml index b254cd7bb6..5bba26feca 100644 --- a/conandata.yml +++ b/conandata.yml @@ -4,12 +4,14 @@ - "boost/1.79.0" - "rapidjson/1.1.0" - "stb/20200203" + - "spdlog/1.10.0" + - "fmt/9.0.0" requirements_arcus: - - "protobuf/3.17.1" + - "protobuf/3.21.4" - "arcus/(latest)@ultimaker/testing" - "zlib/1.2.12" build_requirements_arcus: - - "protobuf/3.17.1" + - "protobuf/3.21.4" build_requirements_testing: - "gtest/1.12.1" "5.1.0": @@ -60,11 +62,13 @@ - "boost/1.79.0" - "rapidjson/1.1.0" - "stb/20200203" + - "spdlog/1.10.0" + - "fmt/9.0.0" requirements_arcus: - - "protobuf/3.17.1" + - "protobuf/3.21.4" - "arcus/(latest)@ultimaker/testing" - "zlib/1.2.12" build_requirements_arcus: - - "protobuf/3.17.1" + - "protobuf/3.21.4" build_requirements_testing: - "gtest/1.12.1" diff --git a/include/BeadingStrategy/BeadingStrategy.h b/include/BeadingStrategy/BeadingStrategy.h index 50c676f967..5f2625bac8 100644 --- a/include/BeadingStrategy/BeadingStrategy.h +++ b/include/BeadingStrategy/BeadingStrategy.h @@ -1,26 +1,25 @@ -// Copyright (c) 2021 Ultimaker B.V. -// CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #ifndef BEADING_STRATEGY_H #define BEADING_STRATEGY_H #include -#include "../utils/IntPoint.h" -#include "../utils/logoutput.h" #include "../settings/types/Angle.h" #include "../settings/types/Ratio.h" //For the wall transition threshold. +#include "../utils/IntPoint.h" namespace cura { /*! * Mostly virtual base class template. - * + * * Strategy for covering a given (constant) horizontal model thickness with a number of beads. - * + * * The beads may have different widths. - * + * * TODO: extend with printing order? */ class BeadingStrategy @@ -37,24 +36,19 @@ class BeadingStrategy coord_t left_over; //! The distance not covered by any bead; gap area. }; - BeadingStrategy - ( - coord_t optimal_width, - Ratio wall_split_middle_threshold, - Ratio wall_add_middle_threshold, - coord_t default_transition_length, - float transitioning_angle = pi_div(3) - ); + BeadingStrategy(coord_t optimal_width, Ratio wall_split_middle_threshold, Ratio wall_add_middle_threshold, coord_t default_transition_length, float transitioning_angle = pi_div(3)); BeadingStrategy(const BeadingStrategy& other); - virtual ~BeadingStrategy() {} + virtual ~BeadingStrategy() + { + } /*! * Retrieve the bead widths with which to cover a given thickness. - * + * * Requirement: Given a constant \p bead_count the output of each bead width must change gradually along with the \p thickness. - * + * * \note The \p bead_count might be different from the \ref BeadingStrategy::optimal_bead_count */ virtual Beading compute(coord_t thickness, coord_t bead_count) const = 0; @@ -76,14 +70,14 @@ class BeadingStrategy /*! * The length of the transitioning region along the marked / significant regions of the skeleton. - * + * * Transitions are used to smooth out the jumps in integer bead count; the jumps turn into ramps with some incline defined by their length. */ virtual coord_t getTransitioningLength(coord_t lower_bead_count) const; /*! * The fraction of the transition length to put between the lower end of the transition and the point where the unsmoothed bead count jumps. - * + * * Transitions are used to smooth out the jumps in integer bead count; the jumps turn into ramps which could be positioned relative to the jump location. */ virtual float getTransitionAnchorPos(coord_t lower_bead_count) const; @@ -91,11 +85,11 @@ class BeadingStrategy /*! * Get the locations in a bead count region where \ref BeadingStrategy::compute exhibits a bend in the widths. * Ordered from lower thickness to higher. - * + * * This is used to insert extra support bones into the skeleton, so that the resulting beads in long trapezoids don't linearly change between the two ends. */ virtual std::vector getNonlinearThicknesses(coord_t lower_bead_count) const; - + virtual std::string toString() const; coord_t getOptimalWidth() const; diff --git a/include/BeadingStrategy/LimitedBeadingStrategy.h b/include/BeadingStrategy/LimitedBeadingStrategy.h index 679d1db5b6..e727015db6 100644 --- a/include/BeadingStrategy/LimitedBeadingStrategy.h +++ b/include/BeadingStrategy/LimitedBeadingStrategy.h @@ -1,12 +1,11 @@ -//Copyright (c) 2020 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #ifndef LIMITED_BEADING_STRATEGY_H #define LIMITED_BEADING_STRATEGY_H -#include "BeadingStrategy.h" -#include "../utils/logoutput.h" #include "../utils/macros.h" +#include "BeadingStrategy.h" namespace cura { @@ -29,17 +28,17 @@ class LimitedBeadingStrategy : public BeadingStrategy { public: LimitedBeadingStrategy(const coord_t max_bead_count, BeadingStrategyPtr parent); - + virtual ~LimitedBeadingStrategy() override = default; - + Beading compute(coord_t thickness, coord_t bead_count) const override; coord_t getOptimalThickness(coord_t bead_count) const override; coord_t getTransitionThickness(coord_t lower_bead_count) const override; coord_t getOptimalBeadCount(coord_t thickness) const override; virtual std::string toString() const override; - + coord_t getTransitioningLength(coord_t lower_bead_count) const override; - + float getTransitionAnchorPos(coord_t lower_bead_count) const override; protected: diff --git a/include/utils/ThreadPool.h b/include/utils/ThreadPool.h index f9042fc9eb..28f17b8080 100644 --- a/include/utils/ThreadPool.h +++ b/include/utils/ThreadPool.h @@ -88,7 +88,6 @@ class ThreadPool /// `std::make_signed_t` fails for non integral types in a way that doesn't allows SFINAE fallbacks. This alias solves that. template using make_signed_if_integral_t = typename std::enable_if_t, std::make_signed>::type; -using std::distance; /// Overloads `std::distance()` to work on integral types template> inline Signed distance(const Int& first, const Int& last) diff --git a/include/utils/logoutput.h b/include/utils/logoutput.h deleted file mode 100644 index cdb9facc5c..0000000000 --- a/include/utils/logoutput.h +++ /dev/null @@ -1,59 +0,0 @@ -//Copyright (c) 2018 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. - -#ifndef LOGOUTPUT_H -#define LOGOUTPUT_H - -namespace cura { - -/* - * \brief Increase verbosity level by 1. - */ -void increaseVerboseLevel(); - -/* - * \brief Enable logging the current slicing progress to the log. - */ -void enableProgressLogging(); - -/* - * \brief Report an error message. - * - * This is always reported, regardless of verbosity level. - */ -void logError(const char* fmt, ...); - -/* - * \brief Report a warning message. - * - * Always reported, regardless of verbosity level. - */ -void logWarning(const char* fmt, ...); - -/* - * \brief Report a message if the verbosity level is 1 or higher. - */ -void log(const char* fmt, ...); - -/* - * \brief Log a message, regardless of verbosity level. - */ -void logAlways(const char* fmt, ...); - -/* - * \brief Log a debugging message. - * - * The message is only logged if the verbosity level is 2 or higher. - */ -void logDebug(const char* fmt, ...); - -/* - * \brief Report the progress in the log. - * - * Only works if ``enableProgressLogging()`` has been called. - */ -void logProgress(const char* type, int value, int maxValue, float percent); - -} //namespace cura - -#endif //LOGOUTPUT_H \ No newline at end of file diff --git a/include/utils/string.h b/include/utils/string.h index 192bbf2948..7ca857c191 100644 --- a/include/utils/string.h +++ b/include/utils/string.h @@ -1,22 +1,22 @@ -//Copyright (c) 2020 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #ifndef UTILS_STRING_H #define UTILS_STRING_H -#include #include // sprintf +#include #include // ostringstream -#include "logoutput.h" +#include namespace cura { - -//c++11 no longer supplies a strcasecmp, so define our own version. + +// c++11 no longer supplies a strcasecmp, so define our own version. static inline int stringcasecompare(const char* a, const char* b) { - while(*a && *b) + while (*a && *b) { if (tolower(*a) != tolower(*b)) return tolower(*a) - tolower(*b); @@ -28,11 +28,11 @@ static inline int stringcasecompare(const char* a, const char* b) /*! * Efficient conversion of micron integer type to millimeter string. - * + * * The integer type is half the size of the normal integer type because of implementation details. * However, half the integer type should suffice, because we made the basic coord_t twice as big as necessary * so as to support multiplication within the same integer type. - * + * * \param coord The micron unit to convert * \param ss The output stream to write the string to */ @@ -44,11 +44,11 @@ static inline void writeInt2mm(const int32_t coord, std::ostream& ss) #ifdef DEBUG if (char_count + 1 >= int(buffer_size)) // + 1 for the null character { - logError("Cannot write %ld to buffer of size %i", coord, buffer_size); + spdlog::error("Cannot write {} to buffer of size {}", coord, buffer_size); } if (char_count < 0) { - logError("Encoding error while writing %ld", coord); + spdlog::error("Encoding error while writing {}", coord); } #endif // DEBUG int end_pos = char_count; // the first character not to write any more @@ -103,7 +103,7 @@ struct MMtoStream { int64_t value; //!< The coord in micron - friend inline std::ostream& operator<< (std::ostream& out, const MMtoStream precision_and_input) + friend inline std::ostream& operator<<(std::ostream& out, const MMtoStream precision_and_input) { writeInt2mm(precision_and_input.value, out); return out; @@ -112,11 +112,11 @@ struct MMtoStream /*! * Efficient writing of a double to a stringstream - * + * * writes with \p precision digits after the decimal dot, but removes trailing zeros - * + * * \warning only works with precision up to 9 and input up to 10^14 - * + * * \param precision The number of (non-zero) digits after the decimal dot * \param coord double to output * \param ss The output stream to write the string to @@ -131,11 +131,11 @@ static inline void writeDoubleToStream(const unsigned int precision, const doubl #ifdef DEBUG if (char_count + 1 >= int(buffer_size)) // + 1 for the null character { - logError("Cannot write %f to buffer of size %i", coord, buffer_size); + spdlog::error("Cannot write {} to buffer of size {}", coord, buffer_size); } if (char_count < 0) { - logError("Encoding error while writing %f", coord); + spdlog::error("Encoding error while writing {}", coord); } #endif // DEBUG if (char_count <= 0) @@ -169,7 +169,7 @@ struct PrecisionedDouble unsigned int precision; //!< Number of digits after the decimal mark with which to convert to string double value; //!< The double value - friend inline std::ostream& operator<< (std::ostream& out, const PrecisionedDouble precision_and_input) + friend inline std::ostream& operator<<(std::ostream& out, const PrecisionedDouble precision_and_input) { writeDoubleToStream(precision_and_input.precision, precision_and_input.value, out); return out; @@ -182,7 +182,7 @@ struct PrecisionedDouble struct Escaped { const char* str; - + /*! * Streaming function which replaces escape sequences with extra slashes */ @@ -192,24 +192,47 @@ struct Escaped { switch (*char_p) { - case '\a': os << "\\a"; break; - case '\b': os << "\\b"; break; - case '\f': os << "\\f"; break; - case '\n': os << "\\n"; break; - case '\r': os << "\\r"; break; - case '\t': os << "\\t"; break; - case '\v': os << "\\v"; break; - case '\\': os << "\\\\"; break; - case '\'': os << "\\'"; break; - case '\"': os << "\\\""; break; - case '\?': os << "\\\?"; break; - default: os << *char_p; + case '\a': + os << "\\a"; + break; + case '\b': + os << "\\b"; + break; + case '\f': + os << "\\f"; + break; + case '\n': + os << "\\n"; + break; + case '\r': + os << "\\r"; + break; + case '\t': + os << "\\t"; + break; + case '\v': + os << "\\v"; + break; + case '\\': + os << "\\\\"; + break; + case '\'': + os << "\\'"; + break; + case '\"': + os << "\\\""; + break; + case '\?': + os << "\\\?"; + break; + default: + os << *char_p; } } return os; } }; -}//namespace cura +} // namespace cura -#endif//UTILS_STRING_H +#endif // UTILS_STRING_H diff --git a/src/Application.cpp b/src/Application.cpp index b790a10f35..13ed4291e6 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -1,22 +1,32 @@ // Copyright (c) 2022 Ultimaker B.V. -// CuraEngine is released under the terms of the AGPLv3 or higher. +// CuraEngine is released under the terms of the AGPLv3 or higher -#include #include "Application.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + #include "FffProcessor.h" #include "communication/ArcusCommunication.h" //To connect via Arcus to the front-end. #include "communication/CommandLine.h" //To use the command line to slice stuff. #include "progress/Progress.h" -#include "utils/logoutput.h" -#include "utils/string.h" //For stringcasecompare. - #include "utils/ThreadPool.h" +#include "utils/string.h" //For stringcasecompare. namespace cura { Application::Application() { + auto dup_filter = std::make_shared(std::chrono::seconds(5)); + spdlog::default_logger()->sinks().push_back(dup_filter); } Application::~Application() @@ -27,7 +37,7 @@ Application::~Application() Application& Application::getInstance() { - static Application instance; //Constructs using the default constructor. + static Application instance; // Constructs using the default constructor. return instance; } @@ -37,7 +47,7 @@ void Application::connect() std::string ip = "127.0.0.1"; int port = 49674; - //Parse port number from IP address. + // Parse port number from IP address. std::string ip_port(argv[2]); std::size_t found_pos = ip_port.find(':'); if (found_pos != std::string::npos) @@ -48,17 +58,17 @@ void Application::connect() int n_threads; - for(size_t argn = 3; argn < argc; argn++) + for (size_t argn = 3; argn < argc; argn++) { char* str = argv[argn]; if (str[0] == '-') { - for(str++; *str; str++) + for (str++; *str; str++) { - switch(*str) + switch (*str) { case 'v': - increaseVerboseLevel(); + spdlog::set_level(spdlog::level::debug); break; case 'm': str++; @@ -67,7 +77,7 @@ void Application::connect() startThreadPool(n_threads); break; default: - logError("Unknown option: %c\n", *str); + spdlog::error("Unknown option: {}", str); printCall(); printHelp(); break; @@ -80,73 +90,68 @@ void Application::connect() arcus_communication->connect(ip, port); communication = arcus_communication; } -#endif //ARCUS +#endif // ARCUS void Application::printCall() const { - cura::logError("Command called:\n"); - for (size_t argument_index = 0; argument_index < argc; argument_index++) - { - cura::logError("%s ", argv[argument_index]); - } - cura::logError("\n"); + spdlog::error("Command called: {}", *argv); } void Application::printHelp() const { - logAlways("\n"); - logAlways("usage:\n"); - logAlways("CuraEngine help\n"); - logAlways("\tShow this help message\n"); - logAlways("\n"); + fmt::print("\n"); + fmt::print("usage:\n"); + fmt::print("CuraEngine help\n"); + fmt::print("\tShow this help message\n"); + fmt::print("\n"); #ifdef ARCUS - logAlways("CuraEngine connect [:] [-j ]\n"); - logAlways(" --connect [:]\n\tConnect to via a command socket, \n\tinstead of passing information via the command line\n"); - logAlways(" -v\n\tIncrease the verbose level (show log messages).\n"); + fmt::print("CuraEngine connect [:] [-j ]\n"); + fmt::print(" --connect [:]\n\tConnect to via a command socket, \n\tinstead of passing information via the command line\n"); + fmt::print(" -v\n\tIncrease the verbose level (show log messages).\n"); #ifdef _OPENMP - logAlways(" -m\n\tSet the desired number of threads. Supports only a single digit.\n"); + fmt::print(" -m\n\tSet the desired number of threads. Supports only a single digit.\n"); #endif // _OPENMP - logAlways("\n"); -#endif //ARCUS - logAlways("CuraEngine slice [-v] [-p] [-j ] [-s =] [-g] [-e] [-o ] [-l ] [--next]\n"); - logAlways(" -v\n\tIncrease the verbose level (show log messages).\n"); + fmt::print("\n"); +#endif // ARCUS + fmt::print("CuraEngine slice [-v] [-p] [-j ] [-s =] [-g] [-e] [-o ] [-l ] [--next]\n"); + fmt::print(" -v\n\tIncrease the verbose level (show log messages).\n"); #ifdef _OPENMP - logAlways(" -m\n\tSet the desired number of threads.\n"); + fmt::print(" -m\n\tSet the desired number of threads.\n"); #endif // _OPENMP - logAlways(" -p\n\tLog progress information.\n"); - logAlways(" -j\n\tLoad settings.def.json file to register all settings and their defaults.\n"); - logAlways(" -s =\n\tSet a setting to a value for the last supplied object, \n\textruder train, or general settings.\n"); - logAlways(" -l \n\tLoad an STL model. \n"); - logAlways(" -g\n\tSwitch setting focus to the current mesh group only.\n\tUsed for one-at-a-time printing.\n"); - logAlways(" -e\n\tSwitch setting focus to the extruder train with the given number.\n"); - logAlways(" --next\n\tGenerate gcode for the previously supplied mesh group and append that to \n\tthe gcode of further models for one-at-a-time printing.\n"); - logAlways(" -o \n\tSpecify a file to which to write the generated gcode.\n"); - logAlways("\n"); - logAlways("The settings are appended to the last supplied object:\n"); - logAlways("CuraEngine slice [general settings] \n\t-g [current group settings] \n\t-e0 [extruder train 0 settings] \n\t-l obj_inheriting_from_last_extruder_train.stl [object settings] \n\t--next [next group settings]\n\t... etc.\n"); - logAlways("\n"); - logAlways("In order to load machine definitions from custom locations, you need to create the environment variable CURA_ENGINE_SEARCH_PATH, which should contain all search paths delimited by a (semi-)colon.\n"); - logAlways("\n"); + fmt::print(" -p\n\tLog progress information.\n"); + fmt::print(" -j\n\tLoad settings.def.json file to register all settings and their defaults.\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"); + fmt::print(" -e\n\tSwitch setting focus to the extruder train with the given number.\n"); + fmt::print(" --next\n\tGenerate gcode for the previously supplied mesh group and append that to \n\tthe gcode of further models for one-at-a-time printing.\n"); + fmt::print(" -o \n\tSpecify a file to which to write the generated gcode.\n"); + fmt::print("\n"); + fmt::print("The settings are appended to the last supplied object:\n"); + fmt::print("CuraEngine slice [general settings] \n\t-g [current group settings] \n\t-e0 [extruder train 0 settings] \n\t-l obj_inheriting_from_last_extruder_train.stl [object settings] \n\t--next [next group settings]\n\t... etc.\n"); + fmt::print("\n"); + fmt::print("In order to load machine definitions from custom locations, you need to create the environment variable CURA_ENGINE_SEARCH_PATH, which should contain all search paths delimited by a (semi-)colon.\n"); + fmt::print("\n"); } void Application::printLicense() const { - logAlways("\n"); - logAlways("Cura_SteamEngine version %s\n", CURA_ENGINE_VERSION); - logAlways("Copyright (C) 2022 Ultimaker\n"); - logAlways("\n"); - logAlways("This program is free software: you can redistribute it and/or modify\n"); - logAlways("it under the terms of the GNU Affero General Public License as published by\n"); - logAlways("the Free Software Foundation, either version 3 of the License, or\n"); - logAlways("(at your option) any later version.\n"); - logAlways("\n"); - logAlways("This program is distributed in the hope that it will be useful,\n"); - logAlways("but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); - logAlways("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); - logAlways("GNU Affero General Public License for more details.\n"); - logAlways("\n"); - logAlways("You should have received a copy of the GNU Affero General Public License\n"); - logAlways("along with this program. If not, see .\n"); + fmt::print("\n"); + fmt::print("Cura_SteamEngine version {}\n", CURA_ENGINE_VERSION); + fmt::print("Copyright (C) 2022 Ultimaker\n"); + fmt::print("\n"); + fmt::print("This program is free software: you can redistribute it and/or modify\n"); + fmt::print("it under the terms of the GNU Affero General Public License as published by\n"); + fmt::print("the Free Software Foundation, either version 3 of the License, or\n"); + fmt::print("(at your option) any later version.\n"); + fmt::print("\n"); + fmt::print("This program is distributed in the hope that it will be useful,\n"); + fmt::print("but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); + fmt::print("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); + fmt::print("GNU Affero General Public License for more details.\n"); + fmt::print("\n"); + fmt::print("You should have received a copy of the GNU Affero General Public License\n"); + fmt::print("along with this program. If not, see .\n"); } void Application::slice() @@ -180,29 +185,29 @@ void Application::run(const size_t argc, char** argv) connect(); } else -#endif //ARCUS - if (stringcasecompare(argv[1], "slice") == 0) - { - slice(); - } - else if (stringcasecompare(argv[1], "help") == 0) - { - printHelp(); - } - else - { - logError("Unknown command: %s\n", argv[1]); - printCall(); - printHelp(); - exit(1); - } +#endif // ARCUS + if (stringcasecompare(argv[1], "slice") == 0) + { + slice(); + } + else if (stringcasecompare(argv[1], "help") == 0) + { + printHelp(); + } + else + { + spdlog::error("Unknown command: {}", argv[1]); + printCall(); + printHelp(); + exit(1); + } - if (!communication) + if (! communication) { - //No communication channel is open any more, so either: + // No communication channel is open any more, so either: //- communication failed to connect, or //- the engine was called with an unknown command or a command that doesn't connect (like "help"). - //In either case, we don't want to slice. + // In either case, we don't want to slice. exit(0); } startThreadPool(); // Start the thread pool @@ -212,11 +217,12 @@ void Application::run(const size_t argc, char** argv) } } -void Application::startThreadPool(int nworkers) { +void Application::startThreadPool(int nworkers) +{ size_t nthreads; - if(nworkers <= 0) + if (nworkers <= 0) { - if(thread_pool) + if (thread_pool) { return; // Keep the previous ThreadPool } @@ -226,7 +232,7 @@ void Application::startThreadPool(int nworkers) { { nthreads = nworkers - 1; // Minus one for the main thread } - if(thread_pool && thread_pool->thread_count() == nthreads) + if (thread_pool && thread_pool->thread_count() == nthreads) { return; // Keep the previous ThreadPool } @@ -234,4 +240,4 @@ void Application::startThreadPool(int nworkers) { thread_pool = new ThreadPool(nthreads); } -} //Cura namespace. \ No newline at end of file +} // namespace cura \ No newline at end of file diff --git a/src/BeadingStrategy/BeadingStrategyFactory.cpp b/src/BeadingStrategy/BeadingStrategyFactory.cpp index 5d425866f4..f9682eb2ef 100644 --- a/src/BeadingStrategy/BeadingStrategyFactory.cpp +++ b/src/BeadingStrategy/BeadingStrategyFactory.cpp @@ -1,55 +1,55 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include "BeadingStrategy/BeadingStrategyFactory.h" -#include "BeadingStrategy/LimitedBeadingStrategy.h" -#include "BeadingStrategy/WideningBeadingStrategy.h" +#include + +#include + #include "BeadingStrategy/DistributedBeadingStrategy.h" -#include "BeadingStrategy/RedistributeBeadingStrategy.h" +#include "BeadingStrategy/LimitedBeadingStrategy.h" #include "BeadingStrategy/OuterWallInsetBeadingStrategy.h" - -#include +#include "BeadingStrategy/RedistributeBeadingStrategy.h" +#include "BeadingStrategy/WideningBeadingStrategy.h" namespace cura { -BeadingStrategyPtr BeadingStrategyFactory::makeStrategy -( - const coord_t preferred_bead_width_outer, - const coord_t preferred_bead_width_inner, - const coord_t preferred_transition_length, - const float transitioning_angle, - const bool print_thin_walls, - const coord_t min_bead_width, - const coord_t min_feature_size, - const Ratio wall_split_middle_threshold, - const Ratio wall_add_middle_threshold, - const coord_t max_bead_count, - const coord_t outer_wall_offset, - const int inward_distributed_center_wall_count, - const Ratio minimum_variable_line_ratio -) +BeadingStrategyPtr BeadingStrategyFactory::makeStrategy(const coord_t preferred_bead_width_outer, + const coord_t preferred_bead_width_inner, + const coord_t preferred_transition_length, + const float transitioning_angle, + const bool print_thin_walls, + const coord_t min_bead_width, + const coord_t min_feature_size, + const Ratio wall_split_middle_threshold, + const Ratio wall_add_middle_threshold, + const coord_t max_bead_count, + const coord_t outer_wall_offset, + const int inward_distributed_center_wall_count, + const Ratio minimum_variable_line_ratio) { using std::make_unique; using std::move; - BeadingStrategyPtr ret = make_unique(preferred_bead_width_inner, preferred_transition_length, transitioning_angle, wall_split_middle_threshold, wall_add_middle_threshold, inward_distributed_center_wall_count); - logDebug("Applying the Redistribute meta-strategy with outer-wall width = %d, inner-wall width = %d\n", preferred_bead_width_outer, preferred_bead_width_inner); + BeadingStrategyPtr ret = + make_unique(preferred_bead_width_inner, preferred_transition_length, transitioning_angle, wall_split_middle_threshold, wall_add_middle_threshold, inward_distributed_center_wall_count); + spdlog::debug("Applying the Redistribute meta-strategy with outer-wall width = {}, inner-wall width = {}", preferred_bead_width_outer, preferred_bead_width_inner); ret = make_unique(preferred_bead_width_outer, minimum_variable_line_ratio, move(ret)); - if(print_thin_walls) + if (print_thin_walls) { - logDebug("Applying the Widening Beading meta-strategy with minimum input width %d and minimum output width %d.\n", min_feature_size, min_bead_width); + spdlog::debug("Applying the Widening Beading meta-strategy with minimum input width {} and minimum output width {}.", min_feature_size, min_bead_width); ret = make_unique(move(ret), min_feature_size, min_bead_width); } if (outer_wall_offset > 0) { - logDebug("Applying the OuterWallOffset meta-strategy with offset = %d.\n", outer_wall_offset); + spdlog::debug("Applying the OuterWallOffset meta-strategy with offset = {}", outer_wall_offset); ret = make_unique(outer_wall_offset, move(ret)); } - //Apply the LimitedBeadingStrategy last, since that adds a 0-width marker wall which other beading strategies shouldn't touch. - logDebug("Applying the Limited Beading meta-strategy with maximum bead count = %d.\n", max_bead_count); + // Apply the LimitedBeadingStrategy last, since that adds a 0-width marker wall which other beading strategies shouldn't touch. + spdlog::debug("Applying the Limited Beading meta-strategy with maximum bead count = {}", max_bead_count); ret = make_unique(max_bead_count, move(ret)); return ret; } diff --git a/src/BeadingStrategy/LimitedBeadingStrategy.cpp b/src/BeadingStrategy/LimitedBeadingStrategy.cpp index 9ab6db60ca..a563cfb779 100644 --- a/src/BeadingStrategy/LimitedBeadingStrategy.cpp +++ b/src/BeadingStrategy/LimitedBeadingStrategy.cpp @@ -1,9 +1,11 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher + +#include "BeadingStrategy/LimitedBeadingStrategy.h" #include -#include "BeadingStrategy/LimitedBeadingStrategy.h" +#include namespace cura { @@ -23,14 +25,11 @@ float LimitedBeadingStrategy::getTransitionAnchorPos(coord_t lower_bead_count) c return parent->getTransitionAnchorPos(lower_bead_count); } -LimitedBeadingStrategy::LimitedBeadingStrategy(const coord_t max_bead_count, BeadingStrategyPtr parent) - : BeadingStrategy(*parent) - , max_bead_count(max_bead_count) - , parent(std::move(parent)) +LimitedBeadingStrategy::LimitedBeadingStrategy(const coord_t max_bead_count, BeadingStrategyPtr parent) : BeadingStrategy(*parent), max_bead_count(max_bead_count), parent(std::move(parent)) { if (max_bead_count % 2 == 1) { - RUN_ONCE(logWarning("LimitedBeadingStrategy with odd bead count is odd indeed!\n")); + spdlog::warn("LimitedBeadingStrategy with odd bead count is odd indeed!"); } } @@ -51,9 +50,9 @@ LimitedBeadingStrategy::Beading LimitedBeadingStrategy::compute(coord_t thicknes return ret; } assert(bead_count == max_bead_count + 1); - if(bead_count != max_bead_count + 1) + if (bead_count != max_bead_count + 1) { - RUN_ONCE(logWarning("Too many beads! %i != %i", bead_count, max_bead_count + 1)); + spdlog::warn("Too many beads! {} != {}", bead_count, max_bead_count + 1); } coord_t optimal_thickness = parent->getOptimalThickness(max_bead_count); @@ -61,7 +60,7 @@ LimitedBeadingStrategy::Beading LimitedBeadingStrategy::compute(coord_t thicknes bead_count = ret.toolpath_locations.size(); ret.left_over += thickness - ret.total_thickness; ret.total_thickness = thickness; - + // Enforce symmetry if (bead_count % 2 == 1) { @@ -73,14 +72,14 @@ LimitedBeadingStrategy::Beading LimitedBeadingStrategy::compute(coord_t thicknes ret.toolpath_locations[bead_count - 1 - bead_idx] = thickness - ret.toolpath_locations[bead_idx]; } - //Create a "fake" inner wall with 0 width to indicate the edge of the walled area. - //This wall can then be used by other structures to e.g. fill the infill area adjacent to the variable-width walls. + // Create a "fake" inner wall with 0 width to indicate the edge of the walled area. + // This wall can then be used by other structures to e.g. fill the infill area adjacent to the variable-width walls. coord_t innermost_toolpath_location = ret.toolpath_locations[max_bead_count / 2 - 1]; coord_t innermost_toolpath_width = ret.bead_widths[max_bead_count / 2 - 1]; ret.toolpath_locations.insert(ret.toolpath_locations.begin() + max_bead_count / 2, innermost_toolpath_location + innermost_toolpath_width / 2); ret.bead_widths.insert(ret.bead_widths.begin() + max_bead_count / 2, 0); - //Symmetry on both sides. Symmetry is guaranteed since this code is stopped early if the bead_count <= max_bead_count, and never reaches this point then. + // Symmetry on both sides. Symmetry is guaranteed since this code is stopped early if the bead_count <= max_bead_count, and never reaches this point then. const size_t opposite_bead = bead_count - (max_bead_count / 2 - 1); innermost_toolpath_location = ret.toolpath_locations[opposite_bead]; innermost_toolpath_width = ret.bead_widths[opposite_bead]; @@ -123,10 +122,11 @@ coord_t LimitedBeadingStrategy::getOptimalBeadCount(coord_t thickness) const { if (thickness < parent->getOptimalThickness(max_bead_count + 1) - 10) return max_bead_count; - else + else return max_bead_count + 1; } - else return max_bead_count + 1; + else + return max_bead_count + 1; } } // namespace cura diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index ee8b032fc4..ab309b43aa 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1,37 +1,38 @@ // Copyright (c) 2022 Ultimaker B.V. -// CuraEngine is released under the terms of the AGPLv3 or higher. +// CuraEngine is released under the terms of the AGPLv3 or higher -#include -#include // numeric_limits #include +#include // numeric_limits +#include #include +#include //For generating a UUID. +#include //For generating a UUID. +#include + #include "Application.h" -#include "bridge.h" -#include "communication/Communication.h" //To send layer view data. #include "ExtruderTrain.h" #include "FffGcodeWriter.h" #include "FffProcessor.h" -#include "utils/ThreadPool.h" -#include "infill.h" #include "InsetOrderOptimizer.h" #include "LayerPlan.h" +#include "Slice.h" +#include "WallToolPaths.h" +#include "bridge.h" +#include "communication/Communication.h" //To send layer view data. +#include "infill.h" #include "progress/Progress.h" #include "raft.h" -#include "Slice.h" +#include "utils/Simplify.h" //Removing micro-segments created by offsetting. +#include "utils/ThreadPool.h" #include "utils/linearAlg2D.h" #include "utils/math.h" #include "utils/orderOptimizer.h" -#include "utils/Simplify.h" //Removing micro-segments created by offsetting. -#include "WallToolPaths.h" -#include //For generating a UUID. -#include //For generating a UUID. namespace cura { -FffGcodeWriter::FffGcodeWriter() - : max_object_height(0), layer_plan_buffer(gcode), slice_uuid(boost::uuids::to_string(boost::uuids::random_generator()())) +FffGcodeWriter::FffGcodeWriter() : max_object_height(0), layer_plan_buffer(gcode), slice_uuid(boost::uuids::to_string(boost::uuids::random_generator()())) { for (unsigned int extruder_nr = 0; extruder_nr < MAX_EXTRUDERS; extruder_nr++) { // initialize all as max layer_nr, so that they get updated to the lowest layer on which they are used. @@ -72,7 +73,7 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep gcode.setSliceUUID(slice_uuid); Scene& scene = Application::getInstance().current_slice->scene; - if (scene.current_mesh_group == scene.mesh_groups.begin()) //First mesh group. + if (scene.current_mesh_group == scene.mesh_groups.begin()) // First mesh group. { gcode.resetTotalPrintTimeAndFilament(); gcode.setInitialAndBuildVolumeTemps(start_extruder_nr); @@ -98,7 +99,7 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep size_t total_layers = 0; for (SliceMeshStorage& mesh : storage.meshes) { - if (mesh.isPrinted()) //No need to process higher layers if the non-printed meshes are higher than the normal meshes. + if (mesh.isPrinted()) // No need to process higher layers if the non-printed meshes are higher than the normal meshes. { total_layers = std::max(total_layers, mesh.layers.size()); } @@ -107,12 +108,12 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep } setSupportAngles(storage); - + gcode.writeLayerCountComment(total_layers); { // calculate the mesh order for each extruder const size_t extruder_count = Application::getInstance().current_slice->scene.extruders.size(); - mesh_order_per_extruder.clear(); // Might be not empty in case of sequential printing. + mesh_order_per_extruder.clear(); // Might be not empty in case of sequential printing. mesh_order_per_extruder.reserve(extruder_count); for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) { @@ -144,24 +145,22 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep } } - run_multiple_producers_ordered_consumer(process_layer_starting_layer_nr, total_layers, - [&storage, total_layers, this](int layer_nr) - { - return &processLayer(storage, layer_nr, total_layers); - }, + run_multiple_producers_ordered_consumer( + process_layer_starting_layer_nr, + total_layers, + [&storage, total_layers, this](int layer_nr) { return &processLayer(storage, layer_nr, total_layers); }, [this, total_layers](LayerPlan* gcode_layer) { - Progress::messageProgress(Progress::Stage::EXPORT, std::max(0, gcode_layer->getLayerNr()) + 1, total_layers); - layer_plan_buffer.handle(*gcode_layer, gcode); - } - ); + Progress::messageProgress(Progress::Stage::EXPORT, std::max(0, gcode_layer->getLayerNr()) + 1, total_layers); + layer_plan_buffer.handle(*gcode_layer, gcode); + }); layer_plan_buffer.flush(); Progress::messageProgressStage(Progress::Stage::FINISH, &time_keeper); - //Store the object height for when we are printing multiple objects, as we need to clear every one of them when moving to the next position. + // Store the object height for when we are printing multiple objects, as we need to clear every one of them when moving to the next position. max_object_height = std::max(max_object_height, storage.model_max.z); @@ -192,8 +191,8 @@ unsigned int FffGcodeWriter::findSpiralizedLayerSeamVertexIndex(const SliceDataS // to come out pretty weird if that isn't true as it implies that there are empty layers ConstPolygonRef last_wall = (*storage.spiralize_wall_outlines[last_layer_nr])[0]; - //Even though this is just one (contiguous) part, the spiralize wall may still be multiple parts if the part is somewhere thinner than 1 line width. - //This case is so rare that we don't bother with finding the best polygon to start with. Just start with the first polygon (`spiral_wall[0]`). + // Even though this is just one (contiguous) part, the spiralize wall may still be multiple parts if the part is somewhere thinner than 1 line width. + // This case is so rare that we don't bother with finding the best polygon to start with. Just start with the first polygon (`spiral_wall[0]`). ConstPolygonRef wall = layer.parts[0].spiral_wall[0]; const size_t n_points = wall.size(); const Point last_wall_seam_vertex = last_wall[storage.spiralize_seam_vertex_indices[last_layer_nr]]; @@ -246,7 +245,7 @@ void FffGcodeWriter::findLayerSeamsForSpiralize(SliceDataStorage& storage, size_ // iterate through extruders until we find a mesh that has a part with insets const std::vector& extruder_order = extruder_order_per_layer[layer_nr]; - for (unsigned int extruder_idx = 0; !done_this_layer && extruder_idx < extruder_order.size(); ++extruder_idx) + for (unsigned int extruder_idx = 0; ! done_this_layer && extruder_idx < extruder_order.size(); ++extruder_idx) { const size_t extruder_nr = extruder_order[extruder_idx]; // iterate through this extruder's meshes until we find a part with insets @@ -255,11 +254,11 @@ void FffGcodeWriter::findLayerSeamsForSpiralize(SliceDataStorage& storage, size_ { SliceMeshStorage& mesh = storage.meshes[mesh_idx]; // if this mesh has layer data for this layer process it - if (!done_this_layer && mesh.layers.size() > layer_nr) + if (! done_this_layer && mesh.layers.size() > layer_nr) { SliceLayer& layer = mesh.layers[layer_nr]; // if the first part in the layer (if any) has insets, process it - if (!layer.parts.empty() && !layer.parts[0].spiral_wall.empty()) + if (! layer.parts.empty() && ! layer.parts[0].spiral_wall.empty()) { // save the seam vertex index for this layer as we need it to determine the seam vertex index for the next layer storage.spiralize_seam_vertex_indices[layer_nr] = findSpiralizedLayerSeamVertexIndex(storage, mesh, layer_nr, last_layer_nr); @@ -288,7 +287,7 @@ void FffGcodeWriter::setConfigFanSpeedLayerTime() fan_speed_layer_time_settings.cool_fan_speed_max = train.settings.get("cool_fan_speed_max") * 100.0; fan_speed_layer_time_settings.cool_min_speed = train.settings.get("cool_min_speed"); fan_speed_layer_time_settings.cool_fan_full_layer = train.settings.get("cool_fan_full_layer"); - if (!train.settings.get("cool_fan_enabled")) + if (! train.settings.get("cool_fan_enabled")) { fan_speed_layer_time_settings.cool_fan_speed_0 = 0; fan_speed_layer_time_settings.cool_fan_speed_min = 0; @@ -297,24 +296,24 @@ void FffGcodeWriter::setConfigFanSpeedLayerTime() } } -void FffGcodeWriter::setConfigRetraction(SliceDataStorage& storage) +void FffGcodeWriter::setConfigRetraction(SliceDataStorage& storage) { Scene& scene = Application::getInstance().current_slice->scene; for (size_t extruder_index = 0; extruder_index < scene.extruders.size(); extruder_index++) { ExtruderTrain& train = scene.extruders[extruder_index]; RetractionConfig& retraction_config = storage.retraction_config_per_extruder[extruder_index]; - retraction_config.distance = (train.settings.get("retraction_enable")) ? train.settings.get("retraction_amount") : 0; //Retraction distance in mm. - retraction_config.prime_volume = train.settings.get("retraction_extra_prime_amount"); //Extra prime volume in mm^3. + retraction_config.distance = (train.settings.get("retraction_enable")) ? train.settings.get("retraction_amount") : 0; // Retraction distance in mm. + retraction_config.prime_volume = train.settings.get("retraction_extra_prime_amount"); // Extra prime volume in mm^3. retraction_config.speed = train.settings.get("retraction_retract_speed"); retraction_config.primeSpeed = train.settings.get("retraction_prime_speed"); retraction_config.zHop = train.settings.get("retraction_hop"); retraction_config.retraction_min_travel_distance = train.settings.get("retraction_min_travel"); - retraction_config.retraction_extrusion_window = train.settings.get("retraction_extrusion_window"); //Window to count retractions in in mm of extruded filament. + retraction_config.retraction_extrusion_window = train.settings.get("retraction_extrusion_window"); // Window to count retractions in in mm of extruded filament. retraction_config.retraction_count_max = train.settings.get("retraction_count_max"); RetractionConfig& switch_retraction_config = storage.extruder_switch_retraction_config_per_extruder[extruder_index]; - switch_retraction_config.distance = train.settings.get("switch_extruder_retraction_amount"); //Retraction distance in mm. + switch_retraction_config.distance = train.settings.get("switch_extruder_retraction_amount"); // Retraction distance in mm. switch_retraction_config.prime_volume = 0.0; switch_retraction_config.speed = train.settings.get("switch_extruder_retraction_speed"); switch_retraction_config.primeSpeed = train.settings.get("switch_extruder_prime_speed"); @@ -364,21 +363,20 @@ size_t FffGcodeWriter::getStartExtruder(const SliceDataStorage& storage) const ExtruderTrain& skirt_brim_extruder = mesh_group_settings.get("skirt_brim_extruder_nr"); size_t start_extruder_nr; - if(adhesion_type == EPlatformAdhesion::SKIRT - && (skirt_brim_extruder.settings.get("skirt_line_count") > 0 || skirt_brim_extruder.settings.get("skirt_brim_minimal_length") > 0)) + if (adhesion_type == EPlatformAdhesion::SKIRT && (skirt_brim_extruder.settings.get("skirt_line_count") > 0 || skirt_brim_extruder.settings.get("skirt_brim_minimal_length") > 0)) { start_extruder_nr = skirt_brim_extruder.extruder_nr; } - else if((adhesion_type == EPlatformAdhesion::BRIM || mesh_group_settings.get("prime_tower_brim_enable")) - && (skirt_brim_extruder.settings.get("brim_line_count") > 0 || skirt_brim_extruder.settings.get("skirt_brim_minimal_length") > 0)) + else if ((adhesion_type == EPlatformAdhesion::BRIM || mesh_group_settings.get("prime_tower_brim_enable")) + && (skirt_brim_extruder.settings.get("brim_line_count") > 0 || skirt_brim_extruder.settings.get("skirt_brim_minimal_length") > 0)) { start_extruder_nr = skirt_brim_extruder.extruder_nr; } - else if(adhesion_type == EPlatformAdhesion::RAFT) + else if (adhesion_type == EPlatformAdhesion::RAFT) { start_extruder_nr = mesh_group_settings.get("raft_base_extruder_nr").extruder_nr; } - else //No adhesion. + else // No adhesion. { if (mesh_group_settings.get("support_enable") && mesh_group_settings.get("support_brim_enable")) { @@ -473,11 +471,11 @@ void FffGcodeWriter::setSupportAngles(SliceDataStorage& storage) { if (pattern == EFillMethod::CONCENTRIC) { - angles.push_back(0); //Concentric has no rotation. + angles.push_back(0); // Concentric has no rotation. } else if (pattern == EFillMethod::TRIANGLES) { - angles.push_back(90); //Triangular support interface shouldn't alternate every layer. + angles.push_back(90); // Triangular support interface shouldn't alternate every layer. } else { @@ -485,15 +483,15 @@ void FffGcodeWriter::setSupportAngles(SliceDataStorage& storage) { if (mesh.settings.get(interface_height_setting) >= 2 * Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height")) { - //Some roofs are quite thick. - //Alternate between the two kinds of diagonal: / and \ . + // Some roofs are quite thick. + // Alternate between the two kinds of diagonal: / and \ . angles.push_back(45); angles.push_back(135); } } if (angles.empty()) { - angles.push_back(90); //Perpendicular to support lines. + angles.push_back(90); // Perpendicular to support lines. } } } @@ -530,11 +528,11 @@ void FffGcodeWriter::processInitialLayerTemperature(const SliceDataStorage& stor gcode.writeLine(tmp.str().c_str()); } - if(scene.current_mesh_group->settings.get("material_bed_temp_prepend") && scene.current_mesh_group->settings.get("machine_heated_bed")) + if (scene.current_mesh_group->settings.get("material_bed_temp_prepend") && scene.current_mesh_group->settings.get("machine_heated_bed")) { const Temperature bed_temp = scene.current_mesh_group->settings.get("material_bed_temperature_layer_0"); - if(scene.current_mesh_group == scene.mesh_groups.begin() //Always write bed temperature for first mesh group. - || bed_temp != (scene.current_mesh_group - 1)->settings.get("material_bed_temperature")) //Don't write bed temperature if identical to temperature of previous group. + if (scene.current_mesh_group == scene.mesh_groups.begin() // Always write bed temperature for first mesh group. + || bed_temp != (scene.current_mesh_group - 1)->settings.get("material_bed_temperature")) // Don't write bed temperature if identical to temperature of previous group. { if (bed_temp != 0) { @@ -591,7 +589,7 @@ void FffGcodeWriter::processInitialLayerTemperature(const SliceDataStorage& stor void FffGcodeWriter::processStartingCode(const SliceDataStorage& storage, const size_t start_extruder_nr) { std::vector extruder_is_used = storage.getExtrudersUsed(); - if (Application::getInstance().communication->isSequential()) //If we must output the g-code sequentially, we must already place the g-code header here even if we don't know the exact time/material usages yet. + if (Application::getInstance().communication->isSequential()) // If we must output the g-code sequentially, we must already place the g-code header here even if we don't know the exact time/material usages yet. { std::string prefix = gcode.getFileHeader(extruder_is_used); gcode.writeCode(prefix.c_str()); @@ -678,7 +676,7 @@ void FffGcodeWriter::processNextMeshGroupCode(const SliceDataStorage& storage) processInitialLayerTemperature(storage, gcode.getExtruderNr()); } - + void FffGcodeWriter::processRaft(const SliceDataStorage& storage) { Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; @@ -729,7 +727,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Application::getInstance().communication->sendLayerComplete(layer_nr, z, layer_height); Polygons raftLines; - AngleDegrees fill_angle = (num_surface_layers + num_interface_layers) % 2 ? 45 : 135; //90 degrees rotated from the interface layer. + AngleDegrees fill_angle = (num_surface_layers + num_interface_layers) % 2 ? 45 : 135; // 90 degrees rotated from the interface layer. constexpr bool zig_zaggify_infill = false; constexpr bool connect_polygons = true; // causes less jerks, so better adhesion constexpr bool retract_before_outer_wall = false; @@ -756,21 +754,36 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) for (const Polygons& raft_outline_path : raft_outline_paths) { - Infill infill_comp( - EFillMethod::LINES, zig_zaggify_infill, connect_polygons, raft_outline_path, gcode_layer.configs_storage.raft_base_config.getLineWidth(), line_spacing, - fill_overlap, infill_multiplier, fill_angle, z, extra_infill_shift, - max_resolution, max_deviation, - wall_line_count, infill_origin, skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size - ); + Infill infill_comp(EFillMethod::LINES, + zig_zaggify_infill, + connect_polygons, + raft_outline_path, + gcode_layer.configs_storage.raft_base_config.getLineWidth(), + line_spacing, + fill_overlap, + infill_multiplier, + fill_angle, + z, + extra_infill_shift, + max_resolution, + max_deviation, + wall_line_count, + infill_origin, + skip_stitching, + fill_gaps, + connected_zigzags, + use_endpieces, + skip_some_zags, + zag_skip_count, + pocket_size); std::vector raft_paths; infill_comp.generate(raft_paths, raft_polygons, raftLines, base_settings); - if (!raft_paths.empty()) + if (! raft_paths.empty()) { const GCodePathConfig& config = gcode_layer.configs_storage.raft_base_config; const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); - InsetOrderOptimizer wall_orderer(*this, storage, gcode_layer, base_settings, base_extruder_nr, - config, config, config, config, - retract_before_outer_wall, wipe_dist, wipe_dist, base_extruder_nr, base_extruder_nr, z_seam_config, raft_paths); + InsetOrderOptimizer wall_orderer( + *this, storage, gcode_layer, base_settings, base_extruder_nr, config, config, config, config, retract_before_outer_wall, wipe_dist, wipe_dist, base_extruder_nr, base_extruder_nr, z_seam_config, raft_paths); wall_orderer.addToLayer(); } gcode_layer.addLinesByOptimizer(raftLines, gcode_layer.configs_storage.raft_base_config, SpaceFillType::Lines); @@ -800,7 +813,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) const coord_t interface_max_resolution = interface_settings.get("meshfix_maximum_resolution"); const coord_t interface_max_deviation = interface_settings.get("meshfix_maximum_deviation"); - for(LayerIndex raft_interface_layer = 1; static_cast(raft_interface_layer) <= num_interface_layers; ++raft_interface_layer) + for (LayerIndex raft_interface_layer = 1; static_cast(raft_interface_layer) <= num_interface_layers; ++raft_interface_layer) { // raft interface layer const LayerIndex layer_nr = initial_raft_layer_nr + raft_interface_layer; z += interface_layer_height; @@ -823,17 +836,17 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Application::getInstance().communication->sendLayerComplete(layer_nr, z, interface_layer_height); std::vector raft_outline_paths; - const coord_t small_offset = gcode_layer.configs_storage.raft_interface_config.getLineWidth() / 2; //Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. + const coord_t small_offset = gcode_layer.configs_storage.raft_interface_config.getLineWidth() / 2; // Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. if (storage.primeRaftOutline.area() > 0) { raft_outline_paths.emplace_back(storage.primeRaftOutline.offset(-small_offset)); - raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); //Remove those micron-movements. + raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); // Remove those micron-movements. } raft_outline_paths.emplace_back(storage.raftOutline.offset(-small_offset)); - raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); //Remove those micron-movements. + raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage.raft_interface_config.getLineWidth(); Polygons raft_lines; - AngleDegrees fill_angle = (num_surface_layers + num_interface_layers - raft_interface_layer) % 2 ? 45 : 135; //90 degrees rotated from the first top layer. + AngleDegrees fill_angle = (num_surface_layers + num_interface_layers - raft_interface_layer) % 2 ? 45 : 135; // 90 degrees rotated from the first top layer. constexpr bool zig_zaggify_infill = true; constexpr bool connect_polygons = true; // why not? @@ -848,13 +861,29 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) for (const Polygons& raft_outline_path : raft_outline_paths) { - Infill infill_comp( - EFillMethod::ZIG_ZAG, zig_zaggify_infill, connect_polygons, raft_outline_path, infill_outline_width, interface_line_spacing, - fill_overlap, infill_multiplier, fill_angle, z, extra_infill_shift, - interface_max_resolution, interface_max_deviation, - wall_line_count, infill_origin, skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size - ); - std::vector raft_paths; //Should remain empty, since we have no walls. + Infill infill_comp(EFillMethod::ZIG_ZAG, + zig_zaggify_infill, + connect_polygons, + raft_outline_path, + infill_outline_width, + interface_line_spacing, + fill_overlap, + infill_multiplier, + fill_angle, + z, + extra_infill_shift, + interface_max_resolution, + interface_max_deviation, + wall_line_count, + infill_origin, + skip_stitching, + fill_gaps, + connected_zigzags, + use_endpieces, + skip_some_zags, + zag_skip_count, + pocket_size); + std::vector raft_paths; // Should remain empty, since we have no walls. infill_comp.generate(raft_paths, raft_polygons, raft_lines, interface_settings); gcode_layer.addLinesByOptimizer(raft_lines, gcode_layer.configs_storage.raft_interface_config, SpaceFillType::Lines, false, 0, 1.0, last_planned_position); @@ -898,17 +927,17 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Application::getInstance().communication->sendLayerComplete(layer_nr, z, surface_layer_height); std::vector raft_outline_paths; - const coord_t small_offset = gcode_layer.configs_storage.raft_interface_config.getLineWidth() / 2; //Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. + const coord_t small_offset = gcode_layer.configs_storage.raft_interface_config.getLineWidth() / 2; // Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. if (storage.primeRaftOutline.area() > 0) { raft_outline_paths.emplace_back(storage.primeRaftOutline.offset(-small_offset)); - raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); //Remove those micron-movements. + raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); // Remove those micron-movements. } raft_outline_paths.emplace_back(storage.raftOutline.offset(-small_offset)); - raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); //Remove those micron-movements. + raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage.raft_interface_config.getLineWidth(); Polygons raft_lines; - AngleDegrees fill_angle = (num_surface_layers - raft_surface_layer) % 2 ? 45 : 135; //Alternate between -45 and +45 degrees, ending up 90 degrees rotated from the default skin angle. + AngleDegrees fill_angle = (num_surface_layers - raft_surface_layer) % 2 ? 45 : 135; // Alternate between -45 and +45 degrees, ending up 90 degrees rotated from the default skin angle. constexpr bool zig_zaggify_infill = true; constexpr size_t wall_line_count = 0; @@ -923,13 +952,29 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) for (const Polygons& raft_outline_path : raft_outline_paths) { - Infill infill_comp( - EFillMethod::ZIG_ZAG, zig_zaggify_infill, connect_polygons, raft_outline_path, infill_outline_width, surface_line_spacing, - fill_overlap, infill_multiplier, fill_angle, z, extra_infill_shift, - surface_max_resolution, surface_max_deviation, - wall_line_count, infill_origin, skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size - ); - std::vector raft_paths; //Should remain empty, since we have no walls. + Infill infill_comp(EFillMethod::ZIG_ZAG, + zig_zaggify_infill, + connect_polygons, + raft_outline_path, + infill_outline_width, + surface_line_spacing, + fill_overlap, + infill_multiplier, + fill_angle, + z, + extra_infill_shift, + surface_max_resolution, + surface_max_deviation, + wall_line_count, + infill_origin, + skip_stitching, + fill_gaps, + connected_zigzags, + use_endpieces, + skip_some_zags, + zag_skip_count, + pocket_size); + std::vector raft_paths; // Should remain empty, since we have no walls. infill_comp.generate(raft_paths, raft_polygons, raft_lines, surface_settings); gcode_layer.addLinesByOptimizer(raft_lines, gcode_layer.configs_storage.raft_surface_config, SpaceFillType::Lines, false, 0, 1.0, last_planned_position); @@ -943,7 +988,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIndex layer_nr, const size_t total_layers) const { - logDebug("GcodeWriter processing layer %i of %i\n", layer_nr, total_layers); + spdlog::debug("GcodeWriter processing layer {} of {}", layer_nr, total_layers); const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; coord_t layer_thickness = mesh_group_settings.get("layer_height"); @@ -964,10 +1009,7 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn // find printZ of first actual printed mesh for (const SliceMeshStorage& mesh : storage.meshes) { - if (layer_nr >= static_cast(mesh.layers.size()) - || mesh.settings.get("support_mesh") - || mesh.settings.get("anti_overhang_mesh") - || mesh.settings.get("cutting_mesh") + if (layer_nr >= static_cast(mesh.layers.size()) || mesh.settings.get("support_mesh") || mesh.settings.get("anti_overhang_mesh") || mesh.settings.get("cutting_mesh") || mesh.settings.get("infill_mesh")) { continue; @@ -1007,7 +1049,7 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn for (const SliceMeshStorage& mesh : storage.meshes) { coord_t mesh_inner_wall_width = mesh.settings.get((mesh.settings.get("wall_line_count") > 1) ? "wall_line_width_x" : "wall_line_width_0"); - if(layer_nr == 0) + if (layer_nr == 0) { const ExtruderTrain& train = mesh.settings.get((mesh.settings.get("wall_line_count") > 1) ? "wall_0_extruder_nr" : "wall_x_extruder_nr"); mesh_inner_wall_width *= train.settings.get("initial_layer_line_width_factor"); @@ -1017,11 +1059,7 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn const coord_t comb_offset_from_outlines = max_inner_wall_width * 2; assert(static_cast(extruder_order_per_layer_negative_layers.size()) + layer_nr >= 0 && "Layer numbers shouldn't get more negative than there are raft/filler layers"); - const std::vector& extruder_order = - (layer_nr < 0) ? - extruder_order_per_layer_negative_layers[extruder_order_per_layer_negative_layers.size() + layer_nr] - : - extruder_order_per_layer[layer_nr]; + const std::vector& extruder_order = (layer_nr < 0) ? extruder_order_per_layer_negative_layers[extruder_order_per_layer_negative_layers.size() + layer_nr] : extruder_order_per_layer[layer_nr]; const coord_t first_outer_wall_line_width = scene.extruders[extruder_order.front()].settings.get("wall_line_width_0"); LayerPlan& gcode_layer = *new LayerPlan(storage, layer_nr, z, layer_thickness, extruder_order.front(), fan_speed_layer_time_settings_per_extruder, comb_offset_from_outlines, first_outer_wall_line_width, avoid_distance); @@ -1047,8 +1085,7 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn for (const size_t& extruder_nr : extruder_order) { - if (include_helper_parts - && (extruder_nr == support_infill_extruder_nr || extruder_nr == support_roof_extruder_nr || extruder_nr == support_bottom_extruder_nr)) + if (include_helper_parts && (extruder_nr == support_infill_extruder_nr || extruder_nr == support_roof_extruder_nr || extruder_nr == support_bottom_extruder_nr)) { addSupportToGCode(storage, gcode_layer, extruder_nr); } @@ -1096,12 +1133,12 @@ bool FffGcodeWriter::getExtruderNeedPrimeBlobDuringFirstLayer(const SliceDataSto bool need_prime_blob = false; switch (gcode.getFlavor()) { - case EGCodeFlavor::GRIFFIN: - need_prime_blob = true; - break; - default: - need_prime_blob = false; // TODO: change this once priming for other firmware types is implemented - break; + case EGCodeFlavor::GRIFFIN: + need_prime_blob = true; + break; + default: + need_prime_blob = false; // TODO: change this once priming for other firmware types is implemented + break; } // check the settings if the prime blob is disabled @@ -1157,7 +1194,7 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan } } - if (!first_skirt_brim.empty()) + if (! first_skirt_brim.empty()) { gcode_layer.addTravel(first_skirt_brim.back().closestPointTo(start_close_to)); gcode_layer.addPolygonsByOptimizer(first_skirt_brim, gcode_layer.configs_storage.skirt_brim_config_per_extruder[extruder_nr]); @@ -1176,10 +1213,10 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan else { Polygons outer_brim, inner_brim; - for(unsigned int index = 0; index < skirt_brim.size(); index++) + for (unsigned int index = 0; index < skirt_brim.size(); index++) { ConstPolygonRef polygon = skirt_brim[index]; - if(polygon.area() > 0) + if (polygon.area() > 0) { outer_brim.add(polygon); } @@ -1197,7 +1234,7 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan if (! inner_brim.empty()) { - //Add polygon in reverse order + // Add polygon in reverse order const coord_t wall_0_wipe_dist = 0; const bool spiralize = false; const float flow_ratio = 1.0; @@ -1229,7 +1266,7 @@ void FffGcodeWriter::processDraftShield(const SliceDataStorage& storage, LayerPl { return; } - if (!mesh_group_settings.get("draft_shield_enabled")) + if (! mesh_group_settings.get("draft_shield_enabled")) { return; } @@ -1276,12 +1313,12 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor void FffGcodeWriter::calculatePrimeLayerPerExtruder(const SliceDataStorage& storage) { - for(LayerIndex layer_nr = -Raft::getTotalExtraLayers(); layer_nr < static_cast(storage.print_layer_count); ++layer_nr) + for (LayerIndex layer_nr = -Raft::getTotalExtraLayers(); layer_nr < static_cast(storage.print_layer_count); ++layer_nr) { const std::vector used_extruders = storage.getExtrudersUsed(layer_nr); - for(size_t extruder_nr = 0; extruder_nr < used_extruders.size(); ++extruder_nr) + for (size_t extruder_nr = 0; extruder_nr < used_extruders.size(); ++extruder_nr) { - if(used_extruders[extruder_nr]) + if (used_extruders[extruder_nr]) { extruder_prime_layer_nr[extruder_nr] = std::min(extruder_prime_layer_nr[extruder_nr], layer_nr); } @@ -1298,7 +1335,7 @@ std::vector FffGcodeWriter::getUsedExtrudersOnLayerExcludingStartingExtr ret.push_back(start_extruder); std::vector extruder_is_used_on_this_layer = storage.getExtrudersUsed(layer_nr); - //The outermost prime tower extruder is always used if there is a prime tower, apart on layers with negative index (e.g. for the raft) + // The outermost prime tower extruder is always used if there is a prime tower, apart on layers with negative index (e.g. for the raft) if (mesh_group_settings.get("prime_tower_enable") && layer_nr >= 0 && layer_nr <= storage.max_print_height_second_to_last_extruder) { extruder_is_used_on_this_layer[storage.primeTower.extruder_order[0]] = true; @@ -1324,7 +1361,7 @@ std::vector FffGcodeWriter::getUsedExtrudersOnLayerExcludingStartingExtr { // skip the current extruder, it's the one we started out planning continue; } - if (!extruder_is_used_on_this_layer[extruder_nr]) + if (! extruder_is_used_on_this_layer[extruder_nr]) { continue; } @@ -1356,7 +1393,7 @@ std::vector FffGcodeWriter::calculateMeshOrder(const SliceDataStorage& s std::vector ret; ret.reserve(mesh_indices_order.size()); - for(size_t i: mesh_indices_order) + for (size_t i : mesh_indices_order) { const size_t mesh_idx = mesh_idx_order_optimizer.items[i].second; ret.push_back(mesh_idx); @@ -1399,7 +1436,7 @@ void FffGcodeWriter::addMeshLayerToGCode_meshSurfaceMode(const SliceDataStorage& void FffGcodeWriter::addMeshOpenPolyLinesToGCode(const SliceMeshStorage& mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, LayerPlan& gcode_layer) const { const SliceLayer* layer = &mesh.layers[gcode_layer.getLayerNr()]; - + gcode_layer.addLinesByOptimizer(layer->openPolyLines, mesh_config.inset0_config, SpaceFillType::PolyLines); } @@ -1410,9 +1447,7 @@ void FffGcodeWriter::addMeshLayerToGCode(const SliceDataStorage& storage, const return; } - if (mesh.settings.get("anti_overhang_mesh") - || mesh.settings.get("support_mesh") - ) + if (mesh.settings.get("anti_overhang_mesh") || mesh.settings.get("support_mesh")) { return; } @@ -1427,22 +1462,22 @@ void FffGcodeWriter::addMeshLayerToGCode(const SliceDataStorage& storage, const gcode_layer.setMesh(mesh.mesh_name); ZSeamConfig z_seam_config; - if(mesh.isPrinted()) //"normal" meshes with walls, skin, infill, etc. get the traditional part ordering based on the z-seam settings. + if (mesh.isPrinted()) //"normal" meshes with walls, skin, infill, etc. get the traditional part ordering based on the z-seam settings. { z_seam_config = ZSeamConfig(mesh.settings.get("z_seam_type"), mesh.getZSeamHint(), mesh.settings.get("z_seam_corner"), mesh.settings.get("wall_line_width_0") * 2); } PathOrderOptimizer part_order_optimizer(gcode_layer.getLastPlannedPositionOrStartingPosition(), z_seam_config); - for(const SliceLayerPart& part : layer.parts) + for (const SliceLayerPart& part : layer.parts) { part_order_optimizer.addPolygon(&part); } part_order_optimizer.optimize(); - for(const PathOrderPath& path : part_order_optimizer.paths) + for (const PathOrderPath& path : part_order_optimizer.paths) { addMeshPartToGCode(storage, mesh, extruder_nr, mesh_config, *path.vertices, gcode_layer); } - const std::string extruder_identifier = (mesh.settings.get("roofing_layer_count") > 0)? "roofing_extruder_nr" : "top_bottom_extruder_nr"; + const std::string extruder_identifier = (mesh.settings.get("roofing_layer_count") > 0) ? "roofing_extruder_nr" : "top_bottom_extruder_nr"; if (extruder_nr == mesh.settings.get(extruder_identifier).extruder_nr) { processIroning(storage, mesh, layer, mesh_config.ironing_config, gcode_layer); @@ -1454,7 +1489,8 @@ void FffGcodeWriter::addMeshLayerToGCode(const SliceDataStorage& storage, const gcode_layer.setMesh("NONMESH"); } -void FffGcodeWriter::addMeshPartToGCode(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, LayerPlan& gcode_layer) const +void FffGcodeWriter::addMeshPartToGCode(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, LayerPlan& gcode_layer) + const { const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; @@ -1467,15 +1503,15 @@ void FffGcodeWriter::addMeshPartToGCode(const SliceDataStorage& storage, const S added_something = added_something | processInsets(storage, gcode_layer, mesh, extruder_nr, mesh_config, part); - if (!mesh.settings.get("infill_before_walls")) + if (! mesh.settings.get("infill_before_walls")) { added_something = added_something | processInfill(storage, gcode_layer, mesh, extruder_nr, mesh_config, part); } added_something = added_something | processSkin(storage, gcode_layer, mesh, extruder_nr, mesh_config, part); - //After a layer part, make sure the nozzle is inside the comb boundary, so we do not retract on the perimeter. - if (added_something && (!mesh_group_settings.get("magic_spiralize") || gcode_layer.getLayerNr() < static_cast(mesh.settings.get("initial_bottom_layers")))) + // After a layer part, make sure the nozzle is inside the comb boundary, so we do not retract on the perimeter. + if (added_something && (! mesh_group_settings.get("magic_spiralize") || gcode_layer.getLayerNr() < static_cast(mesh.settings.get("initial_bottom_layers")))) { coord_t innermost_wall_line_width = mesh.settings.get((mesh.settings.get("wall_line_count") > 1) ? "wall_line_width_x" : "wall_line_width_0"); if (gcode_layer.getLayerNr() == 0) @@ -1499,7 +1535,8 @@ bool FffGcodeWriter::processInfill(const SliceDataStorage& storage, LayerPlan& g return added_something; } -bool FffGcodeWriter::processMultiLayerInfill(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part) const +bool FffGcodeWriter::processMultiLayerInfill(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part) + const { if (extruder_nr != mesh.settings.get("infill_extruder_nr").extruder_nr) { @@ -1512,8 +1549,8 @@ bool FffGcodeWriter::processMultiLayerInfill(const SliceDataStorage& storage, La } coord_t max_resolution = mesh.settings.get("meshfix_maximum_resolution"); coord_t max_deviation = mesh.settings.get("meshfix_maximum_deviation"); - AngleDegrees infill_angle = 45; //Original default. This will get updated to an element from mesh->infill_angles. - if (!mesh.infill_angles.empty()) + AngleDegrees infill_angle = 45; // Original default. This will get updated to an element from mesh->infill_angles. + if (! mesh.infill_angles.empty()) { const size_t combined_infill_layers = std::max(uint64_t(1), round_divide(mesh.settings.get("infill_sparse_thickness"), std::max(mesh.settings.get("layer_height"), coord_t(1)))); infill_angle = mesh.infill_angles.at((gcode_layer.getLayerNr() / combined_infill_layers) % mesh.infill_angles.size()); @@ -1521,9 +1558,9 @@ bool FffGcodeWriter::processMultiLayerInfill(const SliceDataStorage& storage, La const Point3 mesh_middle = mesh.bounding_box.getMiddle(); const Point infill_origin(mesh_middle.x + mesh.settings.get("infill_offset_x"), mesh_middle.y + mesh.settings.get("infill_offset_y")); - //Print the thicker infill lines first. (double or more layer thickness, infill combined with previous layers) + // Print the thicker infill lines first. (double or more layer thickness, infill combined with previous layers) bool added_something = false; - for(unsigned int combine_idx = 1; combine_idx < part.infill_area_per_combine_per_density[0].size(); combine_idx++) + for (unsigned int combine_idx = 1; combine_idx < part.infill_area_per_combine_per_density[0].size(); combine_idx++) { const coord_t infill_line_width = mesh_config.infill_config[combine_idx].getLineWidth(); const EFillMethod infill_pattern = mesh.settings.get("infill_pattern"); @@ -1550,35 +1587,51 @@ bool FffGcodeWriter::processMultiLayerInfill(const SliceDataStorage& storage, La constexpr bool use_endpieces = true; constexpr bool skip_some_zags = false; constexpr size_t zag_skip_count = 0; - const bool fill_gaps = density_idx == 0; //Only fill gaps for the lowest density. + const bool fill_gaps = density_idx == 0; // Only fill gaps for the lowest density. - const LightningLayer * lightning_layer = nullptr; + const LightningLayer* lightning_layer = nullptr; if (mesh.lightning_generator) { lightning_layer = &mesh.lightning_generator->getTreesForLayer(gcode_layer.getLayerNr()); } - Infill infill_comp(infill_pattern, zig_zaggify_infill, connect_polygons, - part.infill_area_per_combine_per_density[density_idx][combine_idx], infill_line_width, - infill_line_distance_here, infill_overlap, infill_multiplier, infill_angle, - gcode_layer.z, infill_shift, max_resolution, max_deviation, wall_line_count, - infill_origin, skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, + Infill infill_comp(infill_pattern, + zig_zaggify_infill, + connect_polygons, + part.infill_area_per_combine_per_density[density_idx][combine_idx], + infill_line_width, + infill_line_distance_here, + infill_overlap, + infill_multiplier, + infill_angle, + gcode_layer.z, + infill_shift, + max_resolution, + max_deviation, + wall_line_count, + infill_origin, + skip_stitching, + fill_gaps, + connected_zigzags, + use_endpieces, + skip_some_zags, + zag_skip_count, mesh.settings.get("cross_infill_pocket_size")); infill_comp.generate(infill_paths, infill_polygons, infill_lines, mesh.settings, mesh.cross_fill_provider, lightning_layer, &mesh); } - if (!infill_lines.empty() || !infill_polygons.empty()) + if (! infill_lines.empty() || ! infill_polygons.empty()) { added_something = true; setExtruder_addPrime(storage, gcode_layer, extruder_nr); gcode_layer.setIsInside(true); // going to print stuff inside print object - if (!infill_polygons.empty()) + if (! infill_polygons.empty()) { constexpr bool force_comb_retract = false; gcode_layer.addTravel(infill_polygons[0][0], force_comb_retract); gcode_layer.addPolygonsByOptimizer(infill_polygons, mesh_config.infill_config[combine_idx]); } - if (!infill_lines.empty()) + if (! infill_lines.empty()) { std::optional near_start_location; if (mesh.settings.get("infill_randomize_start_location")) @@ -1601,7 +1654,12 @@ bool FffGcodeWriter::processMultiLayerInfill(const SliceDataStorage& storage, La return added_something; } -bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part) const +bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, + LayerPlan& gcode_layer, + const SliceMeshStorage& mesh, + const size_t extruder_nr, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const SliceLayerPart& part) const { if (extruder_nr != mesh.settings.get("infill_extruder_nr").extruder_nr) { @@ -1615,7 +1673,7 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L bool added_something = false; const coord_t infill_line_width = mesh_config.infill_config[0].getLineWidth(); - //Combine the 1 layer thick infill with the top/bottom skin and print that as one thing. + // Combine the 1 layer thick infill with the top/bottom skin and print that as one thing. Polygons infill_polygons; std::vector> wall_tool_paths; // All wall toolpaths binned by inset_idx (inner) and by density_idx (outer) Polygons infill_lines; @@ -1629,8 +1687,8 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L const size_t last_idx = part.infill_area_per_combine_per_density.size() - 1; const auto max_resolution = mesh.settings.get("meshfix_maximum_resolution"); const auto max_deviation = mesh.settings.get("meshfix_maximum_deviation"); - AngleDegrees infill_angle = 45; //Original default. This will get updated to an element from mesh->infill_angles. - if (!mesh.infill_angles.empty()) + AngleDegrees infill_angle = 45; // Original default. This will get updated to an element from mesh->infill_angles. + if (! mesh.infill_angles.empty()) { const size_t combined_infill_layers = std::max(uint64_t(1), round_divide(mesh.settings.get("infill_sparse_thickness"), std::max(mesh.settings.get("layer_height"), coord_t(1)))); infill_angle = mesh.infill_angles.at((static_cast(gcode_layer.getLayerNr()) / combined_infill_layers) % mesh.infill_angles.size()); @@ -1642,9 +1700,9 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L { if (zig_zaggify) { - return - line_width / 2 - static_cast(line_count) * line_width - 5; + return -line_width / 2 - static_cast(line_count) * line_width - 5; } - return - static_cast(line_count) * line_width; + return -static_cast(line_count) * line_width; }; Polygons sparse_in_outline = part.infill_area_per_combine_per_density[last_idx][0]; @@ -1658,7 +1716,7 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L const auto pocket_size = mesh.settings.get("cross_infill_pocket_size"); constexpr bool skip_stitching = false; constexpr bool connected_zigzags = false; - const bool use_endpieces = part.infill_area_per_combine_per_density.size() == 1; //Only use endpieces when not using gradual infill, since they will then overlap. + const bool use_endpieces = part.infill_area_per_combine_per_density.size() == 1; // Only use endpieces when not using gradual infill, since they will then overlap. constexpr bool skip_some_zags = false; constexpr int zag_skip_count = 0; @@ -1693,7 +1751,7 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L >>>>>>>>""""""""""""""""" */ - //All of that doesn't hold for the Cross patterns; they should just always be multiplied by 2. + // All of that doesn't hold for the Cross patterns; they should just always be multiplied by 2. if (density_idx == part.infill_area_per_combine_per_density.size() - 1 || pattern == EFillMethod::CROSS || pattern == EFillMethod::CROSS_3D) { /* the least dense infill should fill up all remaining gaps @@ -1708,19 +1766,19 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L ^ middle density line dist ^ highest density line dist*/ - //All of that doesn't hold for the Cross patterns; they should just always be multiplied by 2 for every density index. + // All of that doesn't hold for the Cross patterns; they should just always be multiplied by 2 for every density index. infill_line_distance_here /= 2; } Polygons in_outline = part.infill_area_per_combine_per_density[density_idx][0]; - const LightningLayer * lightning_layer = nullptr; + const LightningLayer* lightning_layer = nullptr; if (mesh.lightning_generator) { lightning_layer = &mesh.lightning_generator->getTreesForLayer(gcode_layer.getLayerNr()); } - const bool fill_gaps = density_idx == 0; //Only fill gaps in the lowest infill density pattern. + const bool fill_gaps = density_idx == 0; // Only fill gaps in the lowest infill density pattern. if (hasSkinEdgeSupport) { // infill region with skin above has to have at least one infill wall line @@ -1728,15 +1786,32 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L const size_t skin_below_wall_count = density_idx == last_idx ? min_skin_below_wall_count : 0; wall_tool_paths.emplace_back(std::vector()); const coord_t overlap = infill_overlap - (density_idx == last_idx ? 0 : wall_line_count * infill_line_width); - Infill infill_comp(pattern, zig_zaggify_infill, connect_polygons, infill_below_skin, infill_line_width, - infill_line_distance_here, overlap, infill_multiplier, infill_angle, gcode_layer.z, - infill_shift, max_resolution, max_deviation, skin_below_wall_count, infill_origin, - skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size); + Infill infill_comp(pattern, + zig_zaggify_infill, + connect_polygons, + infill_below_skin, + infill_line_width, + infill_line_distance_here, + overlap, + infill_multiplier, + infill_angle, + gcode_layer.z, + infill_shift, + max_resolution, + max_deviation, + skin_below_wall_count, + infill_origin, + skip_stitching, + fill_gaps, + connected_zigzags, + use_endpieces, + skip_some_zags, + zag_skip_count, + pocket_size); infill_comp.generate(wall_tool_paths.back(), infill_polygons, infill_lines, mesh.settings, mesh.cross_fill_provider, lightning_layer, &mesh); if (density_idx < last_idx) { - const coord_t cut_offset = - get_cut_offset(zig_zaggify_infill, infill_line_width, min_skin_below_wall_count); + const coord_t cut_offset = get_cut_offset(zig_zaggify_infill, infill_line_width, min_skin_below_wall_count); Polygons tool = infill_below_skin.offset(static_cast(cut_offset)); infill_lines_here = tool.intersectionPolyLines(infill_lines_here); } @@ -1750,9 +1825,9 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L } const coord_t circumference = in_outline.polygonLength(); - //Originally an area of 0.4*0.4*2 (2 line width squares) was found to be a good threshold for removal. - //However we found that this doesn't scale well with polygons with larger circumference (https://github.com/Ultimaker/Cura/issues/3992). - //Given that the original test worked for approximately 2x2cm models, this scaling by circumference should make it work for any size. + // Originally an area of 0.4*0.4*2 (2 line width squares) was found to be a good threshold for removal. + // However we found that this doesn't scale well with polygons with larger circumference (https://github.com/Ultimaker/Cura/issues/3992). + // Given that the original test worked for approximately 2x2cm models, this scaling by circumference should make it work for any size. constexpr double minimum_small_area_factor = 0.4 * 0.4 / 40000; const double minimum_small_area = minimum_small_area_factor * circumference; @@ -1764,10 +1839,28 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L constexpr coord_t overlap = 0; // overlap is already applied for the sparsest density in the generateGradualInfill wall_tool_paths.emplace_back(); - Infill infill_comp(pattern, zig_zaggify_infill, connect_polygons, in_outline, infill_line_width, - infill_line_distance_here, overlap, infill_multiplier, infill_angle, gcode_layer.z, - infill_shift, max_resolution, max_deviation, wall_line_count_here, infill_origin, - skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size); + Infill infill_comp(pattern, + zig_zaggify_infill, + connect_polygons, + in_outline, + infill_line_width, + infill_line_distance_here, + overlap, + infill_multiplier, + infill_angle, + gcode_layer.z, + infill_shift, + max_resolution, + max_deviation, + wall_line_count_here, + infill_origin, + skip_stitching, + fill_gaps, + connected_zigzags, + use_endpieces, + skip_some_zags, + zag_skip_count, + pocket_size); infill_comp.generate(wall_tool_paths.back(), infill_polygons, infill_lines, mesh.settings, mesh.cross_fill_provider, lightning_layer, &mesh); if (density_idx < last_idx) { @@ -1779,39 +1872,31 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L infill_polygons.add(infill_polygons_here); } - wall_tool_paths.emplace_back(part.infill_wall_toolpaths); //The extra infill walls were generated separately. Add these too. + wall_tool_paths.emplace_back(part.infill_wall_toolpaths); // The extra infill walls were generated separately. Add these too. const bool walls_generated = - std::any_of - ( - wall_tool_paths.cbegin(), - wall_tool_paths.cend(), - [](const std::vector& tp) - { - return ! (tp.empty() || std::all_of(tp.begin(), tp.end(), [](const VariableWidthLines& vwl) { return vwl.empty(); })); - } - ); - if(!infill_lines.empty() || !infill_polygons.empty() || walls_generated) + std::any_of(wall_tool_paths.cbegin(), wall_tool_paths.cend(), [](const std::vector& tp) { return ! (tp.empty() || std::all_of(tp.begin(), tp.end(), [](const VariableWidthLines& vwl) { return vwl.empty(); })); }); + if (! infill_lines.empty() || ! infill_polygons.empty() || walls_generated) { added_something = true; setExtruder_addPrime(storage, gcode_layer, extruder_nr); gcode_layer.setIsInside(true); // going to print stuff inside print object std::optional near_start_location; - if(mesh.settings.get("infill_randomize_start_location")) + if (mesh.settings.get("infill_randomize_start_location")) { srand(gcode_layer.getLayerNr()); - if(!infill_lines.empty()) + if (! infill_lines.empty()) { near_start_location = infill_lines[rand() % infill_lines.size()][0]; } - else if(!infill_polygons.empty()) + else if (! infill_polygons.empty()) { PolygonRef start_poly = infill_polygons[rand() % infill_polygons.size()]; near_start_location = start_poly[rand() % start_poly.size()]; } - else //So walls_generated must be true. + else // So walls_generated must be true. { std::vector* start_paths = &wall_tool_paths[rand() % wall_tool_paths.size()]; - while(start_paths->empty() || (*start_paths)[0].empty()) //We know for sure (because walls_generated) that one of them is not empty. So randomise until we hit it. Should almost always be very quick. + while (start_paths->empty() || (*start_paths)[0].empty()) // We know for sure (because walls_generated) that one of them is not empty. So randomise until we hit it. Should almost always be very quick. { start_paths = &wall_tool_paths[rand() % wall_tool_paths.size()]; } @@ -1820,18 +1905,31 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L } if (walls_generated) { - for(const std::vector& tool_paths: wall_tool_paths) + for (const std::vector& tool_paths : wall_tool_paths) { constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; const ZSeamConfig z_seam_config(mesh.settings.get("z_seam_type"), mesh.getZSeamHint(), mesh.settings.get("z_seam_corner"), mesh_config.infill_config[0].getLineWidth() * 2); - InsetOrderOptimizer wall_orderer(*this, storage, gcode_layer, mesh.settings, extruder_nr, - mesh_config.infill_config[0], mesh_config.infill_config[0], mesh_config.infill_config[0], mesh_config.infill_config[0], - retract_before_outer_wall, wipe_dist, wipe_dist, extruder_nr, extruder_nr, z_seam_config, tool_paths); + InsetOrderOptimizer wall_orderer(*this, + storage, + gcode_layer, + mesh.settings, + extruder_nr, + mesh_config.infill_config[0], + mesh_config.infill_config[0], + mesh_config.infill_config[0], + mesh_config.infill_config[0], + retract_before_outer_wall, + wipe_dist, + wipe_dist, + extruder_nr, + extruder_nr, + z_seam_config, + tool_paths); added_something |= wall_orderer.addToLayer(); } } - if (!infill_polygons.empty()) + if (! infill_polygons.empty()) { constexpr bool force_comb_retract = false; // start the infill polygons at the nearest vertex to the current location @@ -1839,22 +1937,15 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L gcode_layer.addPolygonsByOptimizer(infill_polygons, mesh_config.infill_config[0], ZSeamConfig(), 0, false, 1.0_r, false, false, near_start_location); } const bool enable_travel_optimization = mesh.settings.get("infill_enable_travel_optimization"); - if (pattern == EFillMethod::GRID - || pattern == EFillMethod::LINES - || pattern == EFillMethod::TRIANGLES - || pattern == EFillMethod::CUBIC - || pattern == EFillMethod::TETRAHEDRAL - || pattern == EFillMethod::QUARTER_CUBIC - || pattern == EFillMethod::CUBICSUBDIV - || pattern == EFillMethod::LIGHTNING) - { - gcode_layer.addLinesByOptimizer(infill_lines, mesh_config.infill_config[0], SpaceFillType::Lines, enable_travel_optimization - , mesh.settings.get("infill_wipe_dist"), /*float_ratio = */ 1.0, near_start_location); + if (pattern == EFillMethod::GRID || pattern == EFillMethod::LINES || pattern == EFillMethod::TRIANGLES || pattern == EFillMethod::CUBIC || pattern == EFillMethod::TETRAHEDRAL || pattern == EFillMethod::QUARTER_CUBIC + || pattern == EFillMethod::CUBICSUBDIV || pattern == EFillMethod::LIGHTNING) + { + gcode_layer.addLinesByOptimizer(infill_lines, mesh_config.infill_config[0], SpaceFillType::Lines, enable_travel_optimization, mesh.settings.get("infill_wipe_dist"), /*float_ratio = */ 1.0, near_start_location); } else { - gcode_layer.addLinesByOptimizer(infill_lines, mesh_config.infill_config[0], (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines, enable_travel_optimization - , /* wipe_dist = */ 0, /*float_ratio = */ 1.0, near_start_location); + gcode_layer.addLinesByOptimizer( + infill_lines, mesh_config.infill_config[0], (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines, enable_travel_optimization, /* wipe_dist = */ 0, /*float_ratio = */ 1.0, near_start_location); } } return added_something; @@ -1864,7 +1955,7 @@ bool FffGcodeWriter::partitionInfillBySkinAbove(Polygons& infill_below_skin, Pol { constexpr coord_t tiny_infill_offset = 20; const auto skin_edge_support_layers = mesh.settings.get("skin_edge_support_layers"); - Polygons skin_above_combined; // skin regions on the layers above combined with small gaps between + Polygons skin_above_combined; // skin regions on the layers above combined with small gaps between // working from the highest layer downwards, combine the regions of skin on all the layers // but don't let the regions merge together @@ -1925,7 +2016,7 @@ bool FffGcodeWriter::partitionInfillBySkinAbove(Polygons& infill_below_skin, Pol // // ------- ------------------------------------- - skin_above_combined = skin_above_combined.difference( skin_part.outline.offset(tiny_infill_offset)); + skin_above_combined = skin_above_combined.difference(skin_part.outline.offset(tiny_infill_offset)); skin_above_combined.add(skin_part.outline); } } @@ -1943,7 +2034,7 @@ bool FffGcodeWriter::partitionInfillBySkinAbove(Polygons& infill_below_skin, Pol } // the shrink/expand here is to remove regions of infill below skin that are narrower than the width of the infill walls otherwise the infill walls could merge and form a bump - infill_below_skin = skin_above_combined.intersection(part.infill_area_per_combine_per_density.back().front()).offset(-infill_line_width).offset(infill_line_width); + infill_below_skin = skin_above_combined.intersection(part.infill_area_per_combine_per_density.back().front()).offset(-infill_line_width).offset(infill_line_width); constexpr bool remove_small_holes_from_infill_below_skin = true; constexpr double min_area_multiplier = 25; @@ -1959,12 +2050,12 @@ bool FffGcodeWriter::partitionInfillBySkinAbove(Polygons& infill_below_skin, Pol const coord_t infill_skin_overlap = mesh.settings.get((part.wall_toolpaths.size() > 1) ? "wall_line_width_x" : "wall_line_width_0") / 2; const Polygons infill_below_skin_overlap = infill_below_skin.offset(-(infill_skin_overlap + tiny_infill_offset)); - return !infill_below_skin_overlap.empty() && !infill_not_below_skin.empty(); + return ! infill_below_skin_overlap.empty() && ! infill_not_below_skin.empty(); } void FffGcodeWriter::processSpiralizedWall(const SliceDataStorage& storage, LayerPlan& gcode_layer, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, const SliceMeshStorage& mesh) const { - if(part.spiral_wall.empty()) + if (part.spiral_wall.empty()) { // wall doesn't have usable outline return; @@ -1986,7 +2077,7 @@ void FffGcodeWriter::processSpiralizedWall(const SliceDataStorage& storage, Laye const bool is_top_layer = ((size_t)layer_nr == (storage.spiralize_wall_outlines.size() - 1) || storage.spiralize_wall_outlines[layer_nr + 1] == nullptr); const int seam_vertex_idx = storage.spiralize_seam_vertex_indices[layer_nr]; // use pre-computed seam vertex index for current layer // output a wall slice that is interpolated between the last and current walls - for(const ConstPolygonRef& wall_outline : part.spiral_wall) + for (const ConstPolygonRef& wall_outline : part.spiral_wall) { gcode_layer.spiralizeWallSlice(mesh_config.inset0_config, wall_outline, ConstPolygonRef(*last_wall_outline), seam_vertex_idx, last_seam_vertex_idx, is_top_layer, is_bottom_layer); } @@ -2005,7 +2096,7 @@ bool FffGcodeWriter::processInsets(const SliceDataStorage& storage, LayerPlan& g } bool spiralize = false; - if(Application::getInstance().current_slice->scene.current_mesh_group->settings.get("magic_spiralize")) + if (Application::getInstance().current_slice->scene.current_mesh_group->settings.get("magic_spiralize")) { const size_t initial_bottom_layers = mesh.settings.get("initial_bottom_layers"); const int layer_nr = gcode_layer.getLayerNr(); @@ -2036,7 +2127,7 @@ bool FffGcodeWriter::processInsets(const SliceDataStorage& storage, LayerPlan& g } } // for non-spiralized layers, determine the shape of the unsupported areas below this part - if (!spiralize && gcode_layer.getLayerNr() > 0) + if (! spiralize && gcode_layer.getLayerNr() > 0) { // accumulate the outlines of all of the parts that are on the layer below @@ -2071,7 +2162,7 @@ bool FffGcodeWriter::processInsets(const SliceDataStorage& storage, LayerPlan& g { const SupportLayer& support_layer = storage.support.supportLayers[support_layer_nr]; - if (!support_layer.support_roof.empty()) + if (! support_layer.support_roof.empty()) { AABB support_roof_bb(support_layer.support_roof); if (boundaryBox.hit(support_roof_bb)) @@ -2148,7 +2239,7 @@ bool FffGcodeWriter::processInsets(const SliceDataStorage& storage, LayerPlan& g gcode_layer.setOverhangMask(Polygons()); } - if(spiralize && extruder_nr == mesh.settings.get("wall_0_extruder_nr").extruder_nr && !part.spiral_wall.empty()) + if (spiralize && extruder_nr == mesh.settings.get("wall_0_extruder_nr").extruder_nr && ! part.spiral_wall.empty()) { added_something = true; setExtruder_addPrime(storage, gcode_layer, extruder_nr); @@ -2157,26 +2248,37 @@ bool FffGcodeWriter::processInsets(const SliceDataStorage& storage, LayerPlan& g // Only spiralize the first part in the mesh, any other parts will be printed using the normal, non-spiralize codepath. // This sounds weird but actually does the right thing when you have a model that has multiple parts at the bottom that merge into // one part higher up. Once all the parts have merged, layers above that level will be spiralized - if(&mesh.layers[gcode_layer.getLayerNr()].parts[0] == &part) + if (&mesh.layers[gcode_layer.getLayerNr()].parts[0] == &part) { processSpiralizedWall(storage, gcode_layer, mesh_config, part, mesh); } else { - //Print the spiral walls of other parts as single walls without Z gradient. + // Print the spiral walls of other parts as single walls without Z gradient. gcode_layer.addWalls(part.spiral_wall, mesh.settings, mesh_config.inset0_config, mesh_config.inset0_config); } } else { - //Main case: Optimize the insets with the InsetOrderOptimizer. + // Main case: Optimize the insets with the InsetOrderOptimizer. const coord_t wall_x_wipe_dist = 0; const ZSeamConfig z_seam_config(mesh.settings.get("z_seam_type"), mesh.getZSeamHint(), mesh.settings.get("z_seam_corner"), mesh.settings.get("wall_line_width_0") * 2); - InsetOrderOptimizer wall_orderer(*this, storage, gcode_layer, mesh.settings, extruder_nr, - mesh_config.inset0_config, mesh_config.insetX_config, mesh_config.bridge_inset0_config, mesh_config.bridge_insetX_config, - mesh.settings.get("travel_retract_before_outer_wall"), mesh.settings.get("wall_0_wipe_dist"), wall_x_wipe_dist, - mesh.settings.get("wall_0_extruder_nr").extruder_nr, mesh.settings.get("wall_x_extruder_nr").extruder_nr, - z_seam_config, part.wall_toolpaths); + InsetOrderOptimizer wall_orderer(*this, + storage, + gcode_layer, + mesh.settings, + extruder_nr, + mesh_config.inset0_config, + mesh_config.insetX_config, + mesh_config.bridge_inset0_config, + mesh_config.bridge_insetX_config, + mesh.settings.get("travel_retract_before_outer_wall"), + mesh.settings.get("wall_0_wipe_dist"), + wall_x_wipe_dist, + mesh.settings.get("wall_0_extruder_nr").extruder_nr, + mesh.settings.get("wall_x_extruder_nr").extruder_nr, + z_seam_config, + part.wall_toolpaths); added_something |= wall_orderer.addToLayer(); } return added_something; @@ -2200,7 +2302,7 @@ std::optional FffGcodeWriter::getSeamAvoidingLocation(const Polygons& fil const PolygonsPointIndex pa = PolygonUtils::findNearestVert(bb_middle + vec, filling_part); // and find another outline vertex, this time using the vector + 180 deg const PolygonsPointIndex pb = PolygonUtils::findNearestVert(bb_middle - vec, filling_part); - if (!pa.initialized() || !pb.initialized()) + if (! pa.initialized() || ! pb.initialized()) { return std::optional(); } @@ -2221,26 +2323,24 @@ bool FffGcodeWriter::processSkin(const SliceDataStorage& storage, LayerPlan& gco const size_t roofing_extruder_nr = mesh.settings.get("roofing_extruder_nr").extruder_nr; const size_t wall_0_extruder_nr = mesh.settings.get("wall_0_extruder_nr").extruder_nr; const size_t roofing_layer_count = std::min(mesh.settings.get("roofing_layer_count"), mesh.settings.get("top_layers")); - if (extruder_nr != top_bottom_extruder_nr && extruder_nr != wall_0_extruder_nr - && (extruder_nr != roofing_extruder_nr || roofing_layer_count <= 0)) + if (extruder_nr != top_bottom_extruder_nr && extruder_nr != wall_0_extruder_nr && (extruder_nr != roofing_extruder_nr || roofing_layer_count <= 0)) { return false; } bool added_something = false; PathOrderOptimizer part_order_optimizer(gcode_layer.getLastPlannedPositionOrStartingPosition()); - for(const SkinPart& skin_part : part.skin_parts) + for (const SkinPart& skin_part : part.skin_parts) { part_order_optimizer.addPolygon(&skin_part); } part_order_optimizer.optimize(); - for(const PathOrderPath& path : part_order_optimizer.paths) + for (const PathOrderPath& path : part_order_optimizer.paths) { const SkinPart& skin_part = *path.vertices; - added_something = added_something | - processSkinPart(storage, gcode_layer, mesh, extruder_nr, mesh_config, skin_part); + added_something = added_something | processSkinPart(storage, gcode_layer, mesh, extruder_nr, mesh_config, skin_part); } return added_something; @@ -2259,7 +2359,13 @@ bool FffGcodeWriter::processSkinPart(const SliceDataStorage& storage, LayerPlan& return added_something; } -void FffGcodeWriter::processRoofing(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SkinPart& skin_part, bool& added_something) const +void FffGcodeWriter::processRoofing(const SliceDataStorage& storage, + LayerPlan& gcode_layer, + const SliceMeshStorage& mesh, + const size_t extruder_nr, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const SkinPart& skin_part, + bool& added_something) const { const size_t roofing_extruder_nr = mesh.settings.get("roofing_extruder_nr").extruder_nr; if (extruder_nr != roofing_extruder_nr) @@ -2280,7 +2386,13 @@ void FffGcodeWriter::processRoofing(const SliceDataStorage& storage, LayerPlan& processSkinPrintFeature(storage, gcode_layer, mesh, mesh_config, extruder_nr, skin_part.roofing_fill, mesh_config.roofing_config, pattern, roofing_angle, skin_overlap, skin_density, monotonic, added_something); } -void FffGcodeWriter::processTopBottom(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SkinPart& skin_part, bool& added_something) const +void FffGcodeWriter::processTopBottom(const SliceDataStorage& storage, + LayerPlan& gcode_layer, + const SliceMeshStorage& mesh, + const size_t extruder_nr, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const SkinPart& skin_part, + bool& added_something) const { if (skin_part.skin_fill.empty()) { @@ -2295,9 +2407,7 @@ void FffGcodeWriter::processTopBottom(const SliceDataStorage& storage, LayerPlan const size_t layer_nr = gcode_layer.getLayerNr(); - EFillMethod pattern = (layer_nr == 0) ? - mesh.settings.get("top_bottom_pattern_0") : - mesh.settings.get("top_bottom_pattern"); + EFillMethod pattern = (layer_nr == 0) ? mesh.settings.get("top_bottom_pattern_0") : mesh.settings.get("top_bottom_pattern"); AngleDegrees skin_angle = 45; if (mesh.skin_angles.size() > 0) @@ -2347,28 +2457,28 @@ void FffGcodeWriter::processTopBottom(const SliceDataStorage& storage, LayerPlan { switch (bridge_layer) { - default: - case 1: - skin_angle = angle; - break; + default: + case 1: + skin_angle = angle; + break; - case 2: - if (bottom_layers > 2) - { - // orientate second bridge skin at +45 deg to first - skin_angle = angle + 45; - } - else - { - // orientate second bridge skin at 90 deg to first - skin_angle = angle + 90; - } - break; + case 2: + if (bottom_layers > 2) + { + // orientate second bridge skin at +45 deg to first + skin_angle = angle + 45; + } + else + { + // orientate second bridge skin at 90 deg to first + skin_angle = angle + 90; + } + break; - case 3: - // orientate third bridge skin at 135 (same result as -45) deg to first - skin_angle = angle + 135; - break; + case 3: + // orientate third bridge skin at 135 (same result as -45) deg to first + skin_angle = angle + 135; + break; } } pattern = EFillMethod::LINES; // force lines pattern when bridging @@ -2389,11 +2499,11 @@ void FffGcodeWriter::processTopBottom(const SliceDataStorage& storage, LayerPlan { is_bridge_skin = handle_bridge_skin(1, &mesh_config.bridge_skin_config, mesh.settings.get("bridge_skin_density")); } - if (bridge_enable_more_layers && !is_bridge_skin && layer_nr > 1 && bottom_layers > 1) + if (bridge_enable_more_layers && ! is_bridge_skin && layer_nr > 1 && bottom_layers > 1) { is_bridge_skin = handle_bridge_skin(2, &mesh_config.bridge_skin_config2, mesh.settings.get("bridge_skin_density_2")); - if (!is_bridge_skin && layer_nr > 2 && bottom_layers > 2) + if (! is_bridge_skin && layer_nr > 2 && bottom_layers > 2) { is_bridge_skin = handle_bridge_skin(3, &mesh_config.bridge_skin_config3, mesh.settings.get("bridge_skin_density_3")); } @@ -2411,12 +2521,12 @@ void FffGcodeWriter::processTopBottom(const SliceDataStorage& storage, LayerPlan bool supported = false; - if (!support_layer->support_roof.empty()) + if (! support_layer->support_roof.empty()) { AABB support_roof_bb(support_layer->support_roof); if (skin_bb.hit(support_roof_bb)) { - supported = !skin_part.skin_fill.intersection(support_layer->support_roof).empty(); + supported = ! skin_part.skin_fill.intersection(support_layer->support_roof).empty(); } } else @@ -2426,7 +2536,7 @@ void FffGcodeWriter::processTopBottom(const SliceDataStorage& storage, LayerPlan AABB support_part_bb(support_part.getInfillArea()); if (skin_bb.hit(support_part_bb)) { - supported = !skin_part.skin_fill.intersection(support_part.getInfillArea()).empty(); + supported = ! skin_part.skin_fill.intersection(support_part.getInfillArea()).empty(); if (supported) { @@ -2445,7 +2555,20 @@ void FffGcodeWriter::processTopBottom(const SliceDataStorage& storage, LayerPlan processSkinPrintFeature(storage, gcode_layer, mesh, mesh_config, extruder_nr, skin_part.skin_fill, *skin_config, pattern, skin_angle, skin_overlap, skin_density, monotonic, added_something, fan_speed); } -void FffGcodeWriter::processSkinPrintFeature(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, const size_t extruder_nr, const Polygons& area, const GCodePathConfig& config, EFillMethod pattern, const AngleDegrees skin_angle, const coord_t skin_overlap, const Ratio skin_density, const bool monotonic, bool& added_something, double fan_speed) const +void FffGcodeWriter::processSkinPrintFeature(const SliceDataStorage& storage, + LayerPlan& gcode_layer, + const SliceMeshStorage& mesh, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const size_t extruder_nr, + const Polygons& area, + const GCodePathConfig& config, + EFillMethod pattern, + const AngleDegrees skin_angle, + const coord_t skin_overlap, + const Ratio skin_density, + const bool monotonic, + bool& added_something, + double fan_speed) const { Polygons skin_polygons; Polygons skin_lines; @@ -2467,22 +2590,37 @@ void FffGcodeWriter::processSkinPrintFeature(const SliceDataStorage& storage, La constexpr int zag_skip_count = 0; constexpr coord_t pocket_size = 0; - Infill infill_comp( - pattern, zig_zaggify_infill, connect_polygons, area, config.getLineWidth(), config.getLineWidth() / skin_density, skin_overlap, infill_multiplier, skin_angle, gcode_layer.z, extra_infill_shift - , max_resolution, max_deviation - , wall_line_count, infill_origin, - skip_line_stitching, fill_gaps, - connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size - ); + Infill infill_comp(pattern, + zig_zaggify_infill, + connect_polygons, + area, + config.getLineWidth(), + config.getLineWidth() / skin_density, + skin_overlap, + infill_multiplier, + skin_angle, + gcode_layer.z, + extra_infill_shift, + max_resolution, + max_deviation, + wall_line_count, + infill_origin, + skip_line_stitching, + fill_gaps, + connected_zigzags, + use_endpieces, + skip_some_zags, + zag_skip_count, + pocket_size); infill_comp.generate(skin_paths, skin_polygons, skin_lines, mesh.settings); // add paths - if(!skin_polygons.empty() || !skin_lines.empty() || !skin_paths.empty()) + if (! skin_polygons.empty() || ! skin_lines.empty() || ! skin_paths.empty()) { added_something = true; setExtruder_addPrime(storage, gcode_layer, extruder_nr); gcode_layer.setIsInside(true); // going to print stuff inside print object - if(!skin_paths.empty()) + if (! skin_paths.empty()) { // Add skin-walls a.k.a. skin-perimeters, skin-insets. const size_t skin_extruder_nr = mesh.settings.get("top_bottom_extruder_nr").extruder_nr; @@ -2491,34 +2629,41 @@ void FffGcodeWriter::processSkinPrintFeature(const SliceDataStorage& storage, La constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; const ZSeamConfig z_seam_config(mesh.settings.get("z_seam_type"), mesh.getZSeamHint(), mesh.settings.get("z_seam_corner"), config.getLineWidth() * 2); - InsetOrderOptimizer wall_orderer(*this, storage, gcode_layer, mesh.settings, extruder_nr, - mesh_config.skin_config, mesh_config.skin_config, mesh_config.skin_config, mesh_config.skin_config, - retract_before_outer_wall, wipe_dist, wipe_dist, skin_extruder_nr, skin_extruder_nr, z_seam_config, skin_paths); + InsetOrderOptimizer wall_orderer(*this, + storage, + gcode_layer, + mesh.settings, + extruder_nr, + mesh_config.skin_config, + mesh_config.skin_config, + mesh_config.skin_config, + mesh_config.skin_config, + retract_before_outer_wall, + wipe_dist, + wipe_dist, + skin_extruder_nr, + skin_extruder_nr, + z_seam_config, + skin_paths); added_something |= wall_orderer.addToLayer(); } } - if(!skin_polygons.empty()) + if (! skin_polygons.empty()) { constexpr bool force_comb_retract = false; gcode_layer.addTravel(skin_polygons[0][0], force_comb_retract); gcode_layer.addPolygonsByOptimizer(skin_polygons, config); } - if(monotonic) + if (monotonic) { const coord_t exclude_distance = config.getLineWidth() * 0.8; const AngleRadians monotonic_direction = AngleRadians(skin_angle); constexpr Ratio flow = 1.0_r; - const coord_t max_adjacent_distance = config.getLineWidth() * 1.1; //Lines are considered adjacent if they are 1 line width apart, with 10% extra play. The monotonic order is enforced if they are adjacent. - if(pattern == EFillMethod::GRID - || pattern == EFillMethod::LINES - || pattern == EFillMethod::TRIANGLES - || pattern == EFillMethod::CUBIC - || pattern == EFillMethod::TETRAHEDRAL - || pattern == EFillMethod::QUARTER_CUBIC - || pattern == EFillMethod::CUBICSUBDIV - || pattern == EFillMethod::LIGHTNING) + const coord_t max_adjacent_distance = config.getLineWidth() * 1.1; // Lines are considered adjacent if they are 1 line width apart, with 10% extra play. The monotonic order is enforced if they are adjacent. + if (pattern == EFillMethod::GRID || pattern == EFillMethod::LINES || pattern == EFillMethod::TRIANGLES || pattern == EFillMethod::CUBIC || pattern == EFillMethod::TETRAHEDRAL || pattern == EFillMethod::QUARTER_CUBIC + || pattern == EFillMethod::CUBICSUBDIV || pattern == EFillMethod::LIGHTNING) { gcode_layer.addLinesMonotonic(area, skin_lines, config, SpaceFillType::Lines, monotonic_direction, max_adjacent_distance, exclude_distance, mesh.settings.get("infill_wipe_dist"), flow, fan_speed); } @@ -2532,9 +2677,7 @@ void FffGcodeWriter::processSkinPrintFeature(const SliceDataStorage& storage, La else { std::optional near_start_location; - const EFillMethod pattern = (gcode_layer.getLayerNr() == 0) ? - mesh.settings.get("top_bottom_pattern_0") : - mesh.settings.get("top_bottom_pattern"); + const EFillMethod pattern = (gcode_layer.getLayerNr() == 0) ? mesh.settings.get("top_bottom_pattern_0") : mesh.settings.get("top_bottom_pattern"); if (pattern == EFillMethod::LINES || pattern == EFillMethod::ZIG_ZAG) { // update near_start_location to a location which tries to avoid seams in skin near_start_location = getSeamAvoidingLocation(area, skin_angle, gcode_layer.getLastPlannedPositionOrStartingPosition()); @@ -2542,14 +2685,8 @@ void FffGcodeWriter::processSkinPrintFeature(const SliceDataStorage& storage, La constexpr bool enable_travel_optimization = false; constexpr float flow = 1.0; - if(pattern == EFillMethod::GRID - || pattern == EFillMethod::LINES - || pattern == EFillMethod::TRIANGLES - || pattern == EFillMethod::CUBIC - || pattern == EFillMethod::TETRAHEDRAL - || pattern == EFillMethod::QUARTER_CUBIC - || pattern == EFillMethod::CUBICSUBDIV - || pattern == EFillMethod::LIGHTNING) + if (pattern == EFillMethod::GRID || pattern == EFillMethod::LINES || pattern == EFillMethod::TRIANGLES || pattern == EFillMethod::CUBIC || pattern == EFillMethod::TETRAHEDRAL || pattern == EFillMethod::QUARTER_CUBIC + || pattern == EFillMethod::CUBICSUBDIV || pattern == EFillMethod::LIGHTNING) { gcode_layer.addLinesByOptimizer(skin_lines, config, SpaceFillType::Lines, enable_travel_optimization, mesh.settings.get("infill_wipe_dist"), flow, near_start_location, fan_speed); } @@ -2568,7 +2705,7 @@ bool FffGcodeWriter::processIroning(const SliceDataStorage& storage, const Slice bool added_something = false; const bool ironing_enabled = mesh.settings.get("ironing_enabled"); const bool ironing_only_highest_layer = mesh.settings.get("ironing_only_highest_layer"); - if (ironing_enabled && (!ironing_only_highest_layer || mesh.layer_nr_max_filled_layer == gcode_layer.getLayerNr())) + if (ironing_enabled && (! ironing_only_highest_layer || mesh.layer_nr_max_filled_layer == gcode_layer.getLayerNr())) { // Since we are ironing after all the parts are completed, it believes that it is outside. // But the truth is that we are inside a part, so we need to change it before we do the ironing @@ -2584,7 +2721,7 @@ bool FffGcodeWriter::processIroning(const SliceDataStorage& storage, const Slice bool FffGcodeWriter::addSupportToGCode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const size_t extruder_nr) const { bool support_added = false; - if (!storage.support.generated || gcode_layer.getLayerNr() > storage.support.layer_nr_max_filled_layer) + if (! storage.support.generated || gcode_layer.getLayerNr() > storage.support.layer_nr_max_filled_layer) { return support_added; } @@ -2592,7 +2729,8 @@ bool FffGcodeWriter::addSupportToGCode(const SliceDataStorage& storage, LayerPla const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; const size_t support_roof_extruder_nr = mesh_group_settings.get("support_roof_extruder_nr").extruder_nr; const size_t support_bottom_extruder_nr = mesh_group_settings.get("support_bottom_extruder_nr").extruder_nr; - size_t support_infill_extruder_nr = (gcode_layer.getLayerNr() <= 0) ? mesh_group_settings.get("support_extruder_nr_layer_0").extruder_nr : mesh_group_settings.get("support_infill_extruder_nr").extruder_nr; + size_t support_infill_extruder_nr = + (gcode_layer.getLayerNr() <= 0) ? mesh_group_settings.get("support_extruder_nr_layer_0").extruder_nr : mesh_group_settings.get("support_infill_extruder_nr").extruder_nr; const SupportLayer& support_layer = storage.support.supportLayers[std::max(0, gcode_layer.getLayerNr())]; if (support_layer.support_bottom.empty() && support_layer.support_roof.empty() && support_layer.support_infill_parts.empty()) @@ -2631,11 +2769,11 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer const ExtruderTrain& infill_extruder = Application::getInstance().current_slice->scene.extruders[extruder_nr]; coord_t default_support_line_distance = infill_extruder.settings.get("support_line_distance"); - + // To improve adhesion for the "support initial layer" the first layer might have different properties - if(gcode_layer.getLayerNr() == 0) + if (gcode_layer.getLayerNr() == 0) { - default_support_line_distance = infill_extruder.settings.get("support_initial_layer_line_distance"); + default_support_line_distance = infill_extruder.settings.get("support_initial_layer_line_distance"); } const coord_t default_support_infill_overlap = infill_extruder.settings.get("infill_overlap_mm"); @@ -2643,14 +2781,14 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer // Helper to get the support infill angle const auto get_support_infill_angle = [](const SupportStorage& support_storage, const int layer_nr) { - if (layer_nr <= 0) - { - // handle negative layer numbers - const size_t divisor = support_storage.support_infill_angles_layer_0.size(); - const size_t index = ((layer_nr % divisor) + divisor) % divisor; - return support_storage.support_infill_angles_layer_0.at(index); - } - return support_storage.support_infill_angles.at(static_cast(layer_nr) % support_storage.support_infill_angles.size()); + if (layer_nr <= 0) + { + // handle negative layer numbers + const size_t divisor = support_storage.support_infill_angles_layer_0.size(); + const size_t index = ((layer_nr % divisor) + divisor) % divisor; + return support_storage.support_infill_angles_layer_0.at(index); + } + return support_storage.support_infill_angles.at(static_cast(layer_nr) % support_storage.support_infill_angles.size()); }; const AngleDegrees support_infill_angle = get_support_infill_angle(storage.support, gcode_layer.getLayerNr()); @@ -2667,11 +2805,11 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer // Helper to get the support pattern const auto get_support_pattern = [](const EFillMethod pattern, const int layer_nr) { - if (layer_nr <= 0 && (pattern == EFillMethod::LINES || pattern == EFillMethod::ZIG_ZAG)) - { - return EFillMethod::GRID; - } - return pattern; + if (layer_nr <= 0 && (pattern == EFillMethod::LINES || pattern == EFillMethod::ZIG_ZAG)) + { + return EFillMethod::GRID; + } + return pattern; }; const EFillMethod support_pattern = get_support_pattern(infill_extruder.settings.get("support_pattern"), gcode_layer.getLayerNr()); @@ -2681,21 +2819,20 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer // create a list of outlines and use PathOrderOptimizer to optimize the travel move PathOrderOptimizer island_order_optimizer(gcode_layer.getLastPlannedPositionOrStartingPosition()); - for(const SupportInfillPart& part : support_layer.support_infill_parts) + for (const SupportInfillPart& part : support_layer.support_infill_parts) { island_order_optimizer.addPolygon(&part); } island_order_optimizer.optimize(); // Helper to determine the appropriate support area - const auto get_support_area = [](const Polygons& area, const int layer_nr, const EFillMethod pattern, - const coord_t line_width, const coord_t brim_line_count) - { - if (layer_nr == 0 && pattern == EFillMethod::CONCENTRIC) - { - return area.offset(static_cast(line_width * brim_line_count / 1000)); - } - return area; + const auto get_support_area = [](const Polygons& area, const int layer_nr, const EFillMethod pattern, const coord_t line_width, const coord_t brim_line_count) + { + if (layer_nr == 0 && pattern == EFillMethod::CONCENTRIC) + { + return area.offset(static_cast(line_width * brim_line_count / 1000)); + } + return area; }; const auto support_brim_line_count = infill_extruder.settings.get("support_brim_line_count"); const auto support_connect_zigzags = infill_extruder.settings.get("support_connect_zigzags"); @@ -2707,35 +2844,34 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer constexpr bool connect_polygons = false; // polygons are too distant to connect for sparse support bool need_travel_to_end_of_last_spiral = true; - //Print the thicker infill lines first. (double or more layer thickness, infill combined with previous layers) - for(const PathOrderPath& path : island_order_optimizer.paths) + // Print the thicker infill lines first. (double or more layer thickness, infill combined with previous layers) + for (const PathOrderPath& path : island_order_optimizer.paths) { const SupportInfillPart& part = *path.vertices; // always process the wall overlap if walls are generated const int current_support_infill_overlap = (part.inset_count_to_generate > 0) ? default_support_infill_overlap : 0; - //The support infill walls were generated separately, first. Always add them, regardless of how many densities we have. + // The support infill walls were generated separately, first. Always add them, regardless of how many densities we have. std::vector wall_toolpaths = part.wall_toolpaths; - - if ( ! wall_toolpaths.empty()) + + if (! wall_toolpaths.empty()) { const GCodePathConfig& config = gcode_layer.configs_storage.support_infill_config[0]; constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); - InsetOrderOptimizer wall_orderer(*this, storage, gcode_layer, infill_extruder.settings, extruder_nr, - config, config, config, config, - retract_before_outer_wall, wipe_dist, wipe_dist, extruder_nr, extruder_nr, z_seam_config, wall_toolpaths); + InsetOrderOptimizer wall_orderer( + *this, storage, gcode_layer, infill_extruder.settings, extruder_nr, config, config, config, config, retract_before_outer_wall, wipe_dist, wipe_dist, extruder_nr, extruder_nr, z_seam_config, wall_toolpaths); added_something |= wall_orderer.addToLayer(); } - if((default_support_line_distance <= 0 && support_structure != ESupportStructure::TREE) || part.infill_area_per_combine_per_density.empty()) + if ((default_support_line_distance <= 0 && support_structure != ESupportStructure::TREE) || part.infill_area_per_combine_per_density.empty()) { continue; } - for(unsigned int combine_idx = 0; combine_idx < part.infill_area_per_combine_per_density[0].size(); ++combine_idx) + for (unsigned int combine_idx = 0; combine_idx < part.infill_area_per_combine_per_density[0].size(); ++combine_idx) { const coord_t support_line_width = default_support_line_width * (combine_idx + 1); @@ -2743,9 +2879,9 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer std::vector wall_toolpaths_here; Polygons support_lines; const size_t max_density_idx = part.infill_area_per_combine_per_density.size() - 1; - for(size_t density_idx = max_density_idx; (density_idx + 1) > 0; --density_idx) + for (size_t density_idx = max_density_idx; (density_idx + 1) > 0; --density_idx) { - if(combine_idx >= part.infill_area_per_combine_per_density[density_idx].size()) + if (combine_idx >= part.infill_area_per_combine_per_density[density_idx].size()) { continue; } @@ -2753,33 +2889,47 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer const unsigned int density_factor = 2 << density_idx; // == pow(2, density_idx + 1) int support_line_distance_here = default_support_line_distance * density_factor; // the highest density infill combines with the next to create a grid with density_factor 1 const int support_shift = support_line_distance_here / 2; - if(density_idx == max_density_idx || support_pattern == EFillMethod::CROSS || support_pattern == EFillMethod::CROSS_3D) + if (density_idx == max_density_idx || support_pattern == EFillMethod::CROSS || support_pattern == EFillMethod::CROSS_3D) { support_line_distance_here /= 2; } - const Polygons& area = get_support_area(part.infill_area_per_combine_per_density[density_idx][combine_idx], - gcode_layer.getLayerNr(), support_pattern, support_line_width, - support_brim_line_count); + const Polygons& area = get_support_area(part.infill_area_per_combine_per_density[density_idx][combine_idx], gcode_layer.getLayerNr(), support_pattern, support_line_width, support_brim_line_count); constexpr size_t wall_count = 0; // Walls are generated somewhere else, so their layers aren't vertically combined. constexpr bool skip_stitching = false; - const bool fill_gaps = density_idx == 0; //Only fill gaps for one of the densities. - Infill infill_comp(support_pattern, zig_zaggify_infill, connect_polygons, area, - support_line_width, support_line_distance_here, current_support_infill_overlap - (density_idx == max_density_idx ? 0 : wall_line_count * support_line_width), - infill_multiplier, support_infill_angle, gcode_layer.z, support_shift, - max_resolution, max_deviation, - wall_count, infill_origin, skip_stitching, fill_gaps, support_connect_zigzags, - use_endpieces, skip_some_zags, zag_skip_count, pocket_size); + const bool fill_gaps = density_idx == 0; // Only fill gaps for one of the densities. + Infill infill_comp(support_pattern, + zig_zaggify_infill, + connect_polygons, + area, + support_line_width, + support_line_distance_here, + current_support_infill_overlap - (density_idx == max_density_idx ? 0 : wall_line_count * support_line_width), + infill_multiplier, + support_infill_angle, + gcode_layer.z, + support_shift, + max_resolution, + max_deviation, + wall_count, + infill_origin, + skip_stitching, + fill_gaps, + support_connect_zigzags, + use_endpieces, + skip_some_zags, + zag_skip_count, + pocket_size); infill_comp.generate(wall_toolpaths_here, support_polygons, support_lines, infill_extruder.settings, storage.support.cross_fill_provider); } if (need_travel_to_end_of_last_spiral && infill_extruder.settings.get("magic_spiralize")) { - if ((!wall_toolpaths.empty() || !support_polygons.empty() || !support_lines.empty())) + if ((! wall_toolpaths.empty() || ! support_polygons.empty() || ! support_lines.empty())) { int layer_nr = gcode_layer.getLayerNr(); - if(layer_nr > (int)infill_extruder.settings.get("bottom_layers")) + if (layer_nr > (int)infill_extruder.settings.get("bottom_layers")) { // bit of subtlety here... support is being used on a spiralized model and to ensure the travel move from the end of the last spiral // to the start of the support does not go through the model we have to tell the slicer what the current location of the nozzle is @@ -2801,7 +2951,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer const bool alternate_inset_direction = infill_extruder.settings.get("material_alternate_walls"); const bool alternate_layer_print_direction = alternate_inset_direction && gcode_layer.getLayerNr() % 2 == 1; - if(!support_polygons.empty()) + if (! support_polygons.empty()) { constexpr bool force_comb_retract = false; gcode_layer.addTravel(support_polygons[0][0], force_comb_retract); @@ -2813,22 +2963,12 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer constexpr bool always_retract = false; const std::optional start_near_location = std::optional(); - gcode_layer.addPolygonsByOptimizer - ( - support_polygons, - gcode_layer.configs_storage.support_infill_config[combine_idx], - z_seam_config, - wall_0_wipe_dist, - spiralize, - flow_ratio, - always_retract, - alternate_layer_print_direction, - start_near_location - ); + gcode_layer.addPolygonsByOptimizer( + support_polygons, gcode_layer.configs_storage.support_infill_config[combine_idx], z_seam_config, wall_0_wipe_dist, spiralize, flow_ratio, always_retract, alternate_layer_print_direction, start_near_location); added_something = true; } - if(!support_lines.empty()) + if (! support_lines.empty()) { constexpr bool enable_travel_optimization = false; constexpr coord_t wipe_dist = 0; @@ -2836,34 +2976,30 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer const std::optional near_start_location = std::optional(); constexpr double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT; - gcode_layer.addLinesByOptimizer - ( - support_lines, - gcode_layer.configs_storage.support_infill_config[combine_idx], - (support_pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines, - enable_travel_optimization, - wipe_dist, - flow_ratio, - near_start_location, - fan_speed, - alternate_layer_print_direction - ); + gcode_layer.addLinesByOptimizer(support_lines, + gcode_layer.configs_storage.support_infill_config[combine_idx], + (support_pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines, + enable_travel_optimization, + wipe_dist, + flow_ratio, + near_start_location, + fan_speed, + alternate_layer_print_direction); added_something = true; } - //If we're printing with a support wall, that support wall generates gap filling as well. - //If not, the pattern may still generate gap filling (if it's connected infill or zigzag). We still want to print those. - if(wall_line_count == 0 && !wall_toolpaths_here.empty()) + // If we're printing with a support wall, that support wall generates gap filling as well. + // If not, the pattern may still generate gap filling (if it's connected infill or zigzag). We still want to print those. + if (wall_line_count == 0 && ! wall_toolpaths_here.empty()) { const GCodePathConfig& config = gcode_layer.configs_storage.support_infill_config[0]; constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; constexpr coord_t simplify_curvature = 0; const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, simplify_curvature); - InsetOrderOptimizer wall_orderer(*this, storage, gcode_layer, infill_extruder.settings, extruder_nr, - config, config, config, config, - retract_before_outer_wall, wipe_dist, wipe_dist, extruder_nr, extruder_nr, z_seam_config, wall_toolpaths_here); + InsetOrderOptimizer wall_orderer( + *this, storage, gcode_layer, infill_extruder.settings, extruder_nr, config, config, config, config, retract_before_outer_wall, wipe_dist, wipe_dist, extruder_nr, extruder_nr, z_seam_config, wall_toolpaths_here); added_something |= wall_orderer.addToLayer(); } } @@ -2877,11 +3013,9 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay { const SupportLayer& support_layer = storage.support.supportLayers[std::max(0, gcode_layer.getLayerNr())]; - if (!storage.support.generated - || gcode_layer.getLayerNr() > storage.support.layer_nr_max_filled_layer - || support_layer.support_roof.empty()) + if (! storage.support.generated || gcode_layer.getLayerNr() > storage.support.layer_nr_max_filled_layer || support_layer.support_roof.empty()) { - return false; //No need to generate support roof if there's no support. + return false; // No need to generate support roof if there's no support. } const size_t roof_extruder_nr = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("support_roof_extruder_nr").extruder_nr; @@ -2889,7 +3023,7 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay const EFillMethod pattern = roof_extruder.settings.get("support_roof_pattern"); AngleDegrees fill_angle = 0; - if (!storage.support.support_roof_angles.empty()) + if (! storage.support.support_roof_angles.empty()) { // handle negative layer numbers int divisor = static_cast(storage.support.support_roof_angles.size()); @@ -2929,19 +3063,35 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay infill_outline = wall.offset(-support_roof_line_width / 2); } - Infill roof_computation( - pattern, zig_zaggify_infill, connect_polygons, infill_outline, gcode_layer.configs_storage.support_roof_config.getLineWidth(), - support_roof_line_distance, support_roof_overlap, infill_multiplier, fill_angle, gcode_layer.z, extra_infill_shift, - max_resolution, max_deviation, - wall_line_count, infill_origin, skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size - ); + Infill roof_computation(pattern, + zig_zaggify_infill, + connect_polygons, + infill_outline, + gcode_layer.configs_storage.support_roof_config.getLineWidth(), + support_roof_line_distance, + support_roof_overlap, + infill_multiplier, + fill_angle, + gcode_layer.z, + extra_infill_shift, + max_resolution, + max_deviation, + wall_line_count, + infill_origin, + skip_stitching, + fill_gaps, + connected_zigzags, + use_endpieces, + skip_some_zags, + zag_skip_count, + pocket_size); Polygons roof_polygons; std::vector roof_paths; Polygons roof_lines; roof_computation.generate(roof_paths, roof_polygons, roof_lines, roof_extruder.settings); if ((gcode_layer.getLayerNr() == 0 && wall.empty()) || (gcode_layer.getLayerNr() > 0 && roof_paths.empty() && roof_polygons.empty() && roof_lines.empty())) { - return false; //We didn't create any support roof. + return false; // We didn't create any support roof. } setExtruder_addPrime(storage, gcode_layer, roof_extruder_nr); gcode_layer.setIsInside(false); // going to print stuff outside print object, i.e. support @@ -2949,22 +3099,21 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay { gcode_layer.addPolygonsByOptimizer(wall, gcode_layer.configs_storage.support_roof_config); } - if ( ! roof_polygons.empty()) + if (! roof_polygons.empty()) { constexpr bool force_comb_retract = false; gcode_layer.addTravel(roof_polygons[0][0], force_comb_retract); gcode_layer.addPolygonsByOptimizer(roof_polygons, gcode_layer.configs_storage.support_roof_config); } - if ( ! roof_paths.empty()) + if (! roof_paths.empty()) { const GCodePathConfig& config = gcode_layer.configs_storage.support_roof_config; constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); - InsetOrderOptimizer wall_orderer(*this, storage, gcode_layer, roof_extruder.settings, roof_extruder_nr, - config, config, config, config, - retract_before_outer_wall, wipe_dist, wipe_dist, roof_extruder_nr, roof_extruder_nr, z_seam_config, roof_paths); + InsetOrderOptimizer wall_orderer( + *this, storage, gcode_layer, roof_extruder.settings, roof_extruder_nr, config, config, config, config, retract_before_outer_wall, wipe_dist, wipe_dist, roof_extruder_nr, roof_extruder_nr, z_seam_config, roof_paths); wall_orderer.addToLayer(); } gcode_layer.addLinesByOptimizer(roof_lines, gcode_layer.configs_storage.support_roof_config, (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines); @@ -2975,11 +3124,9 @@ bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, L { const SupportLayer& support_layer = storage.support.supportLayers[std::max(0, gcode_layer.getLayerNr())]; - if (!storage.support.generated - || gcode_layer.getLayerNr() > storage.support.layer_nr_max_filled_layer - || support_layer.support_bottom.empty()) + if (! storage.support.generated || gcode_layer.getLayerNr() > storage.support.layer_nr_max_filled_layer || support_layer.support_bottom.empty()) { - return false; //No need to generate support bottoms if there's no support. + return false; // No need to generate support bottoms if there's no support. } const size_t bottom_extruder_nr = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("support_bottom_extruder_nr").extruder_nr; @@ -2987,7 +3134,7 @@ bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, L const EFillMethod pattern = bottom_extruder.settings.get("support_bottom_pattern"); AngleDegrees fill_angle = 0; - if (!storage.support.support_bottom_angles.empty()) + if (! storage.support.support_bottom_angles.empty()) { // handle negative layer numbers int divisor = static_cast(storage.support.support_bottom_angles.size()); @@ -3012,12 +3159,28 @@ bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, L const coord_t max_deviation = bottom_extruder.settings.get("meshfix_maximum_deviation"); const coord_t support_bottom_line_distance = bottom_extruder.settings.get("support_bottom_line_distance"); // note: no need to apply initial line width factor; support bottoms cannot exist on the first layer - Infill bottom_computation( - pattern, zig_zaggify_infill, connect_polygons, support_layer.support_bottom, gcode_layer.configs_storage.support_bottom_config.getLineWidth(), - support_bottom_line_distance, support_bottom_overlap, infill_multiplier, fill_angle, gcode_layer.z, extra_infill_shift, - max_resolution, max_deviation, - wall_line_count, infill_origin, skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size - ); + Infill bottom_computation(pattern, + zig_zaggify_infill, + connect_polygons, + support_layer.support_bottom, + gcode_layer.configs_storage.support_bottom_config.getLineWidth(), + support_bottom_line_distance, + support_bottom_overlap, + infill_multiplier, + fill_angle, + gcode_layer.z, + extra_infill_shift, + max_resolution, + max_deviation, + wall_line_count, + infill_origin, + skip_stitching, + fill_gaps, + connected_zigzags, + use_endpieces, + skip_some_zags, + zag_skip_count, + pocket_size); Polygons bottom_polygons; std::vector bottom_paths; Polygons bottom_lines; @@ -3028,7 +3191,7 @@ bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, L } setExtruder_addPrime(storage, gcode_layer, bottom_extruder_nr); gcode_layer.setIsInside(false); // going to print stuff outside print object, i.e. support - if (!bottom_polygons.empty()) + if (! bottom_polygons.empty()) { constexpr bool force_comb_retract = false; gcode_layer.addTravel(bottom_polygons[0][0], force_comb_retract); @@ -3041,9 +3204,8 @@ bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, L constexpr coord_t wipe_dist = 0; const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); - InsetOrderOptimizer wall_orderer(*this, storage, gcode_layer, bottom_extruder.settings, bottom_extruder_nr, - config, config, config, config, - retract_before_outer_wall, wipe_dist, wipe_dist, bottom_extruder_nr, bottom_extruder_nr, z_seam_config, bottom_paths); + InsetOrderOptimizer wall_orderer( + *this, storage, gcode_layer, bottom_extruder.settings, bottom_extruder_nr, config, config, config, config, retract_before_outer_wall, wipe_dist, wipe_dist, bottom_extruder_nr, bottom_extruder_nr, z_seam_config, bottom_paths); wall_orderer.addToLayer(); } gcode_layer.addLinesByOptimizer(bottom_lines, gcode_layer.configs_storage.support_bottom_config, (pattern == EFillMethod::ZIG_ZAG) ? SpaceFillType::PolyLines : SpaceFillType::Lines); @@ -3055,9 +3217,8 @@ void FffGcodeWriter::setExtruder_addPrime(const SliceDataStorage& storage, Layer const size_t outermost_prime_tower_extruder = storage.primeTower.extruder_order[0]; const size_t previous_extruder = gcode_layer.getExtruder(); - if (previous_extruder == extruder_nr && - !(gcode_layer.getLayerNr() > -static_cast(Raft::getFillerLayerCount()) && extruder_nr == outermost_prime_tower_extruder) && - !(gcode_layer.getLayerNr() == -static_cast(Raft::getFillerLayerCount()))) //No unnecessary switches, unless switching to extruder for the outer shell of the prime tower. + if (previous_extruder == extruder_nr && ! (gcode_layer.getLayerNr() > -static_cast(Raft::getFillerLayerCount()) && extruder_nr == outermost_prime_tower_extruder) + && ! (gcode_layer.getLayerNr() == -static_cast(Raft::getFillerLayerCount()))) // No unnecessary switches, unless switching to extruder for the outer shell of the prime tower. { return; } @@ -3085,7 +3246,7 @@ void FffGcodeWriter::setExtruder_addPrime(const SliceDataStorage& storage, Layer } } - if (gcode_layer.getLayerNr() == 0 && !gcode_layer.getSkirtBrimIsPlanned(extruder_nr)) + if (gcode_layer.getLayerNr() == 0 && ! gcode_layer.getSkirtBrimIsPlanned(extruder_nr)) { processSkirtBrim(storage, gcode_layer, extruder_nr); } @@ -3102,7 +3263,7 @@ void FffGcodeWriter::setExtruder_addPrime(const SliceDataStorage& storage, Layer void FffGcodeWriter::addPrimeTower(const SliceDataStorage& storage, LayerPlan& gcode_layer, const size_t prev_extruder) const { - if (!Application::getInstance().current_slice->scene.current_mesh_group->settings.get("prime_tower_enable")) + if (! Application::getInstance().current_slice->scene.current_mesh_group->settings.get("prime_tower_enable")) { return; } @@ -3115,12 +3276,12 @@ void FffGcodeWriter::finalize() const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; if (mesh_group_settings.get("machine_heated_bed")) { - gcode.writeBedTemperatureCommand(0); //Cool down the bed (M140). - //Nozzles are cooled down automatically after the last time they are used (which might be earlier than the end of the print). + gcode.writeBedTemperatureCommand(0); // Cool down the bed (M140). + // Nozzles are cooled down automatically after the last time they are used (which might be earlier than the end of the print). } if (mesh_group_settings.get("machine_heated_build_volume") && mesh_group_settings.get("build_volume_temperature") != 0) { - gcode.writeBuildVolumeTemperatureCommand(0); //Cool down the build volume. + gcode.writeBuildVolumeTemperatureCommand(0); // Cool down the build volume. } const Duration print_time = gcode.getSumTotalPrintTimes(); @@ -3135,16 +3296,14 @@ void FffGcodeWriter::finalize() extruder_is_used.push_back(gcode.getExtruderIsUsed(extruder_nr)); } std::string prefix = gcode.getFileHeader(extruder_is_used, &print_time, filament_used, material_ids); - if (!Application::getInstance().communication->isSequential()) + if (! Application::getInstance().communication->isSequential()) { Application::getInstance().communication->sendGCodePrefix(prefix); Application::getInstance().communication->sendSliceUUID(slice_uuid); } else { - log("Gcode header after slicing:\n"); - log("%s", prefix.c_str()); - log("End of gcode header.\n"); + spdlog::info("Gcode header after slicing: {}", prefix); } if (mesh_group_settings.get("acceleration_enabled")) { @@ -3182,5 +3341,4 @@ void FffGcodeWriter::finalize() } -}//namespace cura - +} // namespace cura diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 9206eea646..9b7f7c6eb9 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -1,12 +1,16 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include +#include +#include // ifstream.good() #include // multimap (ordered map allowing duplicate keys) #include -#include // ifstream.good() -#include +#include + +// Code smell: Order of the includes is important here, probably due to some forward declarations which might be masking some undefined behaviours +// clang-format off #include "Application.h" #include "ConicalOverhang.h" #include "ExtruderTrain.h" @@ -43,10 +47,9 @@ #include "utils/algorithm.h" #include "utils/ThreadPool.h" #include "utils/gettime.h" -#include "utils/logoutput.h" #include "utils/math.h" #include "utils/Simplify.h" - +// clang-format on namespace cura { @@ -54,7 +57,7 @@ namespace cura bool FffPolygonGenerator::generateAreas(SliceDataStorage& storage, MeshGroup* meshgroup, TimeKeeper& timeKeeper) { - if (!sliceModel(meshgroup, timeKeeper, storage)) + if (! sliceModel(meshgroup, timeKeeper, storage)) { return false; } @@ -67,19 +70,19 @@ bool FffPolygonGenerator::generateAreas(SliceDataStorage& storage, MeshGroup* me size_t FffPolygonGenerator::getDraftShieldLayerCount(const size_t total_layers) const { const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; - if (!mesh_group_settings.get("draft_shield_enabled")) + if (! mesh_group_settings.get("draft_shield_enabled")) { return 0; } switch (mesh_group_settings.get("draft_shield_height_limitation")) { - case DraftShieldHeightLimitation::FULL: - return total_layers; - case DraftShieldHeightLimitation::LIMITED: - return std::max((coord_t)0, (mesh_group_settings.get("draft_shield_height") - mesh_group_settings.get("layer_height_0")) / mesh_group_settings.get("layer_height") + 1); - default: - logWarning("A draft shield height limitation option was added without implementing the new option in getDraftShieldLayerCount."); - return total_layers; + case DraftShieldHeightLimitation::FULL: + return total_layers; + case DraftShieldHeightLimitation::LIMITED: + return std::max((coord_t)0, (mesh_group_settings.get("draft_shield_height") - mesh_group_settings.get("layer_height_0")) / mesh_group_settings.get("layer_height") + 1); + default: + spdlog::warn("A draft shield height limitation option was added without implementing the new option in getDraftShieldLayerCount."); + return total_layers; } } @@ -91,26 +94,26 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe storage.model_max = meshgroup->max(); storage.model_size = storage.model_max - storage.model_min; - log("Slicing model...\n"); + spdlog::info("Slicing model..."); const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; // regular layers - int slice_layer_count = 0; //Use signed int because we need to subtract the initial layer in a calculation temporarily. + int slice_layer_count = 0; // Use signed int because we need to subtract the initial layer in a calculation temporarily. // Initial layer height of 0 is not allowed. Negative layer height is nonsense. coord_t initial_layer_thickness = mesh_group_settings.get("layer_height_0"); if (initial_layer_thickness <= 0) { - logError("Initial layer height %i is disallowed.\n", initial_layer_thickness); + spdlog::error("Initial layer height {} is disallowed.", initial_layer_thickness); return false; } // Layer height of 0 is not allowed. Negative layer height is nonsense. const coord_t layer_thickness = mesh_group_settings.get("layer_height"); - if(layer_thickness <= 0) + if (layer_thickness <= 0) { - logError("Layer height %i is disallowed.\n", layer_thickness); + spdlog::error("Layer height {} is disallowed.\n", layer_thickness); return false; } @@ -124,61 +127,60 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe const coord_t variable_layer_height_max_variation = mesh_group_settings.get("adaptive_layer_height_variation"); const coord_t variable_layer_height_variation_step = mesh_group_settings.get("adaptive_layer_height_variation_step"); const coord_t adaptive_threshold = mesh_group_settings.get("adaptive_layer_height_threshold"); - adaptive_layer_heights = new AdaptiveLayerHeights(layer_thickness, variable_layer_height_max_variation, - variable_layer_height_variation_step, adaptive_threshold); + adaptive_layer_heights = new AdaptiveLayerHeights(layer_thickness, variable_layer_height_max_variation, variable_layer_height_variation_step, adaptive_threshold); // Get the amount of layers slice_layer_count = adaptive_layer_heights->getLayerCount(); } else { - //Find highest layer count according to each mesh's settings. - for(const Mesh& mesh : meshgroup->meshes) + // Find highest layer count according to each mesh's settings. + for (const Mesh& mesh : meshgroup->meshes) { - if ( ! mesh.isPrinted()) + if (! mesh.isPrinted()) { continue; } const coord_t mesh_height = mesh.max().z; - switch(mesh.settings.get("slicing_tolerance")) + switch (mesh.settings.get("slicing_tolerance")) { - case SlicingTolerance::MIDDLE: - if(storage.model_max.z < initial_layer_thickness) - { - slice_layer_count = std::max(slice_layer_count, (mesh_height > initial_layer_thickness / 2) ? 1 : 0); //One layer if higher than half initial layer height. - } - else - { - slice_layer_count = std::max(slice_layer_count, static_cast(round_divide_signed(mesh_height - initial_layer_thickness, layer_thickness) + 1)); - } - break; - case SlicingTolerance::EXCLUSIVE: + case SlicingTolerance::MIDDLE: + if (storage.model_max.z < initial_layer_thickness) { - int new_slice_layer_count = 0; - if(mesh_height >= initial_layer_thickness) //If less than the initial layer thickness, leave it at 0. - { - new_slice_layer_count = static_cast(floor_divide_signed(mesh_height - 1 - initial_layer_thickness, layer_thickness) + 1); - } - if(new_slice_layer_count > 0) // If there is at least one layer already, then... - { - new_slice_layer_count += 1; // ... need one extra, since we clear the top layer after the repeated intersections with the layer above. - } - slice_layer_count = std::max(slice_layer_count, new_slice_layer_count); - break; + slice_layer_count = std::max(slice_layer_count, (mesh_height > initial_layer_thickness / 2) ? 1 : 0); // One layer if higher than half initial layer height. } - case SlicingTolerance::INCLUSIVE: - if(mesh_height < initial_layer_thickness) - { - slice_layer_count = std::max(slice_layer_count, (mesh_height > 0) ? 1 : 0); //If less than the initial layer height, it always has 1 layer unless the height is truly zero. - } - else - { - slice_layer_count = std::max(slice_layer_count, static_cast(ceil_divide_signed(mesh_height - initial_layer_thickness, layer_thickness) + 1)); - } - break; - default: - logError("Unknown slicing tolerance. Did you forget to add a case here?"); - return false; + else + { + slice_layer_count = std::max(slice_layer_count, static_cast(round_divide_signed(mesh_height - initial_layer_thickness, layer_thickness) + 1)); + } + break; + case SlicingTolerance::EXCLUSIVE: + { + int new_slice_layer_count = 0; + if (mesh_height >= initial_layer_thickness) // If less than the initial layer thickness, leave it at 0. + { + new_slice_layer_count = static_cast(floor_divide_signed(mesh_height - 1 - initial_layer_thickness, layer_thickness) + 1); + } + if (new_slice_layer_count > 0) // If there is at least one layer already, then... + { + new_slice_layer_count += 1; // ... need one extra, since we clear the top layer after the repeated intersections with the layer above. + } + slice_layer_count = std::max(slice_layer_count, new_slice_layer_count); + break; + } + case SlicingTolerance::INCLUSIVE: + if (mesh_height < initial_layer_thickness) + { + slice_layer_count = std::max(slice_layer_count, (mesh_height > 0) ? 1 : 0); // If less than the initial layer height, it always has 1 layer unless the height is truly zero. + } + else + { + slice_layer_count = std::max(slice_layer_count, static_cast(ceil_divide_signed(mesh_height - initial_layer_thickness, layer_thickness) + 1)); + } + break; + default: + spdlog::error("Unknown slicing tolerance. Did you forget to add a case here?"); + return false; } } } @@ -190,7 +192,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe } std::vector slicerList; - for(unsigned int mesh_idx = 0; mesh_idx < meshgroup->meshes.size(); mesh_idx++) + for (unsigned int mesh_idx = 0; mesh_idx < meshgroup->meshes.size(); mesh_idx++) { // Check if adaptive layers is populated to prevent accessing a method on NULL std::vector* adaptive_layer_height_values = {}; @@ -225,7 +227,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe for (unsigned int mesh_idx = 0; mesh_idx < slicerList.size(); mesh_idx++) { Mesh& mesh = scene.current_mesh_group->meshes[mesh_idx]; - if (mesh.settings.get("conical_overhang_enabled") && !mesh.settings.get("anti_overhang_mesh")) + if (mesh.settings.get("conical_overhang_enabled") && ! mesh.settings.get("anti_overhang_mesh")) { ConicalOverhang::apply(slicerList[mesh_idx], mesh); } @@ -247,7 +249,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe { Mesh& mesh = scene.current_mesh_group->meshes[meshIdx]; Slicer* slicer = slicerList[meshIdx]; - if (!mesh.settings.get("anti_overhang_mesh") && !mesh.settings.get("infill_mesh") && !mesh.settings.get("cutting_mesh")) + if (! mesh.settings.get("anti_overhang_mesh") && ! mesh.settings.get("infill_mesh") && ! mesh.settings.get("cutting_mesh")) { storage.print_layer_count = std::max(storage.print_layer_count, slicer->layers.size()); } @@ -266,7 +268,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe // only create layer parts for normal meshes const bool is_support_modifier = AreaSupport::handleSupportModifierMesh(storage, mesh.settings, slicer); - if (!is_support_modifier) + if (! is_support_modifier) { createLayerParts(meshStorage, slicer); } @@ -274,7 +276,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe // Do not add and process support _modifier_ meshes further, and ONLY skip support _modifiers_. They have been // processed in AreaSupport::handleSupportModifierMesh(), but other helper meshes such as infill meshes are // processed in a later stage, except for support mesh itself, so an exception is made for that. - if(is_support_modifier && !mesh.settings.get("support_mesh")) + if (is_support_modifier && ! mesh.settings.get("support_mesh")) { storage.meshes.pop_back(); continue; @@ -311,10 +313,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe if (has_raft) { const ExtruderTrain& train = mesh_group_settings.get("raft_surface_extruder_nr"); - layer.printZ += - Raft::getTotalThickness() - + train.settings.get("raft_airgap") - - train.settings.get("layer_0_z_overlap"); // shift all layers (except 0) down + layer.printZ += Raft::getTotalThickness() + train.settings.get("raft_airgap") - train.settings.get("layer_0_z_overlap"); // shift all layers (except 0) down if (layer_nr == 0) { @@ -337,7 +336,7 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper& unsigned int slice_layer_count = 0; for (SliceMeshStorage& mesh : storage.meshes) { - if (!mesh.settings.get("infill_mesh") && !mesh.settings.get("anti_overhang_mesh")) + if (! mesh.settings.get("infill_mesh") && ! mesh.settings.get("anti_overhang_mesh")) { slice_layer_count = std::max(slice_layer_count, mesh.layers.size()); } @@ -371,7 +370,7 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper& } const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; - if (isEmptyLayer(storage, 0) && !isEmptyLayer(storage, 1)) + if (isEmptyLayer(storage, 0) && ! isEmptyLayer(storage, 1)) { // the first layer is empty, the second is not empty, so remove the empty first layer as support isn't going to be generated under it. // Do this irrespective of the value of remove_empty_first_layers as that setting is hidden when support is enabled and so cannot be relied upon @@ -379,9 +378,9 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper& removeEmptyFirstLayers(storage, storage.print_layer_count); // changes storage.print_layer_count! } - log("Layer count: %i\n", storage.print_layer_count); + spdlog::info("Layer count: {}", storage.print_layer_count); - //layerparts2HTML(storage, "output/output.html"); + // layerparts2HTML(storage, "output/output.html"); Progress::messageProgressStage(Progress::Stage::SUPPORT, &time_keeper); @@ -401,7 +400,7 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper& } if (storage.print_layer_count == 0) { - log("Stopping process because there are no non-empty layers.\n"); + spdlog::warn("Stopping process because there are no non-empty layers."); return; } @@ -412,28 +411,28 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper& storage.primeTower.generatePaths(storage); storage.primeTower.subtractFromSupport(storage); - logDebug("Processing ooze shield\n"); + spdlog::debug("Processing ooze shield"); processOozeShield(storage); - logDebug("Processing draft shield\n"); + spdlog::debug("Processing draft shield"); processDraftShield(storage); // This catches a special case in which the models are in the air, and then // the adhesion mustn't be calculated. - if (!isEmptyLayer(storage, 0) || storage.primeTower.enabled) + if (! isEmptyLayer(storage, 0) || storage.primeTower.enabled) { - log("Processing platform adhesion\n"); + spdlog::debug("Processing platform adhesion"); processPlatformAdhesion(storage); } - logDebug("Meshes post-processing\n"); + spdlog::debug("Meshes post-processing"); // meshes post processing for (SliceMeshStorage& mesh : storage.meshes) { processDerivedWallsSkinInfill(mesh); } - logDebug("Processing gradual support\n"); + spdlog::debug("Processing gradual support"); // generate gradual support AreaSupport::generateSupportInfillFeatures(storage); } @@ -450,7 +449,7 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage, // TODO: make progress more accurate!! // note: estimated time for insets : skins = 22.953 : 48.858 - std::vector walls_vs_skin_timing({22.953, 48.858}); + std::vector walls_vs_skin_timing({ 22.953, 48.858 }); ProgressStageEstimator* mesh_inset_skin_progress_estimator = new ProgressStageEstimator(walls_vs_skin_timing); inset_skin_progress_estimate.nextStage(mesh_inset_skin_progress_estimator); // the stage of this function call @@ -461,14 +460,14 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage, struct { ProgressStageEstimator& progress_estimator; - std::mutex mutex {}; + std::mutex mutex{}; std::atomic processed_layer_count = 0; void operator++(int) { std::unique_lock lock(mutex, std::try_to_lock); - if(lock) - { // progress estimation is done only in one thread so that no two threads message progress at the same time + if (lock) + { // progress estimation is done only in one thread so that no two threads message progress at the same time size_t processed_layer_count_ = processed_layer_count.fetch_add(1, std::memory_order_relaxed); double progress = progress_estimator.progress(processed_layer_count_); Progress::messageProgress(Progress::Stage::INSET_SKIN, progress * 100, 100); @@ -482,21 +481,23 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage, { processed_layer_count.store(0, std::memory_order_relaxed); } - } guarded_progress = {inset_skin_progress_estimate}; + } guarded_progress = { inset_skin_progress_estimate }; // walls - cura::parallel_for(0, mesh_layer_count, [&](size_t layer_number) - { - logDebug("Processing insets for layer %i of %i\n", layer_number, mesh.layers.size()); - processWalls(mesh, layer_number); - guarded_progress++; - }); + cura::parallel_for(0, + mesh_layer_count, + [&](size_t layer_number) + { + spdlog::debug("Processing insets for layer {} of {}", layer_number, mesh.layers.size()); + processWalls(mesh, layer_number); + guarded_progress++; + }); ProgressEstimatorLinear* skin_estimator = new ProgressEstimatorLinear(mesh_layer_count); mesh_inset_skin_progress_estimator->nextStage(skin_estimator); bool process_infill = mesh.settings.get("infill_line_distance") > 0; - if (!process_infill) + if (! process_infill) { // do process infill anyway if it's modified by modifier meshes const Scene& scene = Application::getInstance().current_slice->scene; for (size_t other_mesh_order_idx = mesh_order_idx + 1; other_mesh_order_idx < mesh_order.size(); ++other_mesh_order_idx) @@ -525,15 +526,17 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage, } guarded_progress.reset(); - cura::parallel_for(0, mesh_layer_count, [&](size_t layer_number) - { - logDebug("Processing skins and infill layer %i of %i\n", layer_number, mesh.layers.size()); - if (!magic_spiralize || layer_number < mesh_max_initial_bottom_layer_count) //Only generate up/downskin and infill for the first X layers when spiralize is choosen. - { - processSkinsAndInfill(mesh, layer_number, process_infill); - } - guarded_progress++; - }); + cura::parallel_for(0, + mesh_layer_count, + [&](size_t layer_number) + { + spdlog::debug("Processing skins and infill layer {} of {}", layer_number, mesh.layers.size()); + if (! magic_spiralize || layer_number < mesh_max_initial_bottom_layer_count) // Only generate up/downskin and infill for the first X layers when spiralize is choosen. + { + processSkinsAndInfill(mesh, layer_number, process_infill); + } + guarded_progress++; + }); } void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const size_t mesh_order_idx, const std::vector& mesh_order) @@ -585,7 +588,7 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz { for (SliceLayerPart& part : layer.parts) { // limit the outline of each part of this infill mesh to the infill of parts of the other mesh with lower infill mesh order - if (!part.boundaryBox.hit(other_part.boundaryBox)) + if (! part.boundaryBox.hit(other_part.boundaryBox)) { // early out continue; } @@ -616,7 +619,7 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz Polygons cut_lines = own_infill_area.intersectionPolyLines(layer.openPolyLines); new_polylines.add(cut_lines); // NOTE: closed polygons will be represented as polylines, which will be closed automatically in the PathOrderOptimizer - if ( ! own_infill_area.empty()) + if (! own_infill_area.empty()) { other_part.infill_area_own = own_infill_area.difference(layer.openPolyLines.offsetPolyLine(surface_line_width / 2)); } @@ -637,27 +640,25 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz layer.openPolyLines = new_polylines; } - if (layer.parts.size() > 0 || (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer.openPolyLines.size() > 0) ) + if (layer.parts.size() > 0 || (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer.openPolyLines.size() > 0)) { mesh.layer_nr_max_filled_layer = layer_idx; // last set by the highest non-empty layer } } - } void FffPolygonGenerator::processDerivedWallsSkinInfill(SliceMeshStorage& mesh) { if (mesh.settings.get("infill_support_enabled")) - {// create gradual infill areas + { // create gradual infill areas SkinInfillAreaComputation::generateInfillSupport(mesh); } // create gradual infill areas SkinInfillAreaComputation::generateGradualInfill(mesh); - //SubDivCube Pre-compute Octree - if (mesh.settings.get("infill_line_distance") > 0 - && mesh.settings.get("infill_pattern") == EFillMethod::CUBICSUBDIV) + // SubDivCube Pre-compute Octree + if (mesh.settings.get("infill_line_distance") > 0 && mesh.settings.get("infill_pattern") == EFillMethod::CUBICSUBDIV) { const Point3 mesh_middle = mesh.bounding_box.getMiddle(); const Point infill_origin(mesh_middle.x + mesh.settings.get("infill_offset_x"), mesh_middle.y + mesh.settings.get("infill_offset_y")); @@ -665,22 +666,19 @@ void FffPolygonGenerator::processDerivedWallsSkinInfill(SliceMeshStorage& mesh) } // Pre-compute Cross Fractal - if (mesh.settings.get("infill_line_distance") > 0 - && (mesh.settings.get("infill_pattern") == EFillMethod::CROSS - || mesh.settings.get("infill_pattern") == EFillMethod::CROSS_3D) - ) + if (mesh.settings.get("infill_line_distance") > 0 && (mesh.settings.get("infill_pattern") == EFillMethod::CROSS || mesh.settings.get("infill_pattern") == EFillMethod::CROSS_3D)) { const std::string cross_subdivision_spec_image_file = mesh.settings.get("cross_infill_density_image"); std::ifstream cross_fs(cross_subdivision_spec_image_file.c_str()); - if (!cross_subdivision_spec_image_file.empty() && cross_fs.good()) + if (! cross_subdivision_spec_image_file.empty() && cross_fs.good()) { mesh.cross_fill_provider = new SierpinskiFillProvider(mesh.bounding_box, mesh.settings.get("infill_line_distance"), mesh.settings.get("infill_line_width"), cross_subdivision_spec_image_file); } else { - if (!cross_subdivision_spec_image_file.empty() && cross_subdivision_spec_image_file != " ") + if (! cross_subdivision_spec_image_file.empty() && cross_subdivision_spec_image_file != " ") { - logError("Cannot find density image \'%s\'.", cross_subdivision_spec_image_file.c_str()); + spdlog::error("Cannot find density image: {}.", cross_subdivision_spec_image_file); } mesh.cross_fill_provider = new SierpinskiFillProvider(mesh.bounding_box, mesh.settings.get("infill_line_distance"), mesh.settings.get("infill_line_width")); } @@ -721,7 +719,7 @@ bool FffPolygonGenerator::isEmptyLayer(SliceDataStorage& storage, const unsigned if (storage.support.generated && layer_idx < storage.support.supportLayers.size()) { SupportLayer& support_layer = storage.support.supportLayers[layer_idx]; - if (!support_layer.support_infill_parts.empty() || !support_layer.support_bottom.empty() || !support_layer.support_roof.empty()) + if (! support_layer.support_infill_parts.empty() || ! support_layer.support_bottom.empty() || ! support_layer.support_roof.empty()) { return false; } @@ -756,7 +754,8 @@ void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, size if (isEmptyLayer(storage, layer_idx)) { n_empty_first_layers++; - } else + } + else { break; } @@ -764,7 +763,7 @@ void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, size if (n_empty_first_layers > 0) { - log("Removing %d layers because they are empty\n", n_empty_first_layers); + spdlog::info("Removing {} layers because they are empty", n_empty_first_layers); const coord_t layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height"); for (SliceMeshStorage& mesh : storage.meshes) { @@ -808,7 +807,7 @@ void FffPolygonGenerator::processSkinsAndInfill(SliceMeshStorage& mesh, const La SkinInfillAreaComputation skin_infill_area_computation(layer_nr, mesh, process_infill); skin_infill_area_computation.generateSkinsAndInfill(); - if (mesh.settings.get("ironing_enabled") && (!mesh.settings.get("ironing_only_highest_layer") || mesh.layer_nr_max_filled_layer == layer_nr)) + if (mesh.settings.get("ironing_enabled") && (! mesh.settings.get("ironing_only_highest_layer") || mesh.layer_nr_max_filled_layer == layer_nr)) { // Generate the top surface to iron over. mesh.layers[layer_nr].top_surface.setAreasFromMeshAndLayerNumber(mesh, layer_nr); @@ -822,14 +821,14 @@ void FffPolygonGenerator::computePrintHeightStatistics(SliceDataStorage& storage std::vector& max_print_height_per_extruder = storage.max_print_height_per_extruder; assert(max_print_height_per_extruder.size() == 0 && "storage.max_print_height_per_extruder shouldn't have been initialized yet!"); const int raft_layers = Raft::getTotalExtraLayers(); - max_print_height_per_extruder.resize(extruder_count, -(raft_layers + 1)); //Initialize all as -1 (or lower in case of raft). + max_print_height_per_extruder.resize(extruder_count, -(raft_layers + 1)); // Initialize all as -1 (or lower in case of raft). { // compute max_object_height_per_extruder - //Height of the meshes themselves. + // Height of the meshes themselves. for (SliceMeshStorage& mesh : storage.meshes) { if (mesh.settings.get("anti_overhang_mesh") || mesh.settings.get("support_mesh")) { - continue; //Special type of mesh that doesn't get printed. + continue; // Special type of mesh that doesn't get printed. } for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) { @@ -844,45 +843,39 @@ void FffPolygonGenerator::computePrintHeightStatistics(SliceDataStorage& storage } } - //Height of where the support reaches. + // Height of where the support reaches. Scene& scene = Application::getInstance().current_slice->scene; const Settings& mesh_group_settings = scene.current_mesh_group->settings; const size_t support_infill_extruder_nr = mesh_group_settings.get("support_infill_extruder_nr").extruder_nr; // TODO: Support extruder should be configurable per object. - max_print_height_per_extruder[support_infill_extruder_nr] = - std::max(max_print_height_per_extruder[support_infill_extruder_nr], - storage.support.layer_nr_max_filled_layer); + max_print_height_per_extruder[support_infill_extruder_nr] = std::max(max_print_height_per_extruder[support_infill_extruder_nr], storage.support.layer_nr_max_filled_layer); const size_t support_roof_extruder_nr = mesh_group_settings.get("support_roof_extruder_nr").extruder_nr; // TODO: Support roof extruder should be configurable per object. - max_print_height_per_extruder[support_roof_extruder_nr] = - std::max(max_print_height_per_extruder[support_roof_extruder_nr], - storage.support.layer_nr_max_filled_layer); - const size_t support_bottom_extruder_nr = mesh_group_settings.get("support_bottom_extruder_nr").extruder_nr; //TODO: Support bottom extruder should be configurable per object. - max_print_height_per_extruder[support_bottom_extruder_nr] = - std::max(max_print_height_per_extruder[support_bottom_extruder_nr], - storage.support.layer_nr_max_filled_layer); - - //Height of where the platform adhesion reaches. + max_print_height_per_extruder[support_roof_extruder_nr] = std::max(max_print_height_per_extruder[support_roof_extruder_nr], storage.support.layer_nr_max_filled_layer); + const size_t support_bottom_extruder_nr = mesh_group_settings.get("support_bottom_extruder_nr").extruder_nr; // TODO: Support bottom extruder should be configurable per object. + max_print_height_per_extruder[support_bottom_extruder_nr] = std::max(max_print_height_per_extruder[support_bottom_extruder_nr], storage.support.layer_nr_max_filled_layer); + + // Height of where the platform adhesion reaches. const EPlatformAdhesion adhesion_type = mesh_group_settings.get("adhesion_type"); - switch(adhesion_type) + switch (adhesion_type) { - case EPlatformAdhesion::SKIRT: - case EPlatformAdhesion::BRIM: - { - const size_t skirt_brim_extruder_nr = mesh_group_settings.get("skirt_brim_extruder_nr").extruder_nr; - max_print_height_per_extruder[skirt_brim_extruder_nr] = std::max(0, max_print_height_per_extruder[skirt_brim_extruder_nr]); //Includes layer 0. - break; - } - case EPlatformAdhesion::RAFT: - { - const size_t base_extruder_nr = mesh_group_settings.get("raft_base_extruder_nr").extruder_nr; - max_print_height_per_extruder[base_extruder_nr] = std::max(-raft_layers, max_print_height_per_extruder[base_extruder_nr]); //Includes the lowest raft layer. - const size_t interface_extruder_nr = mesh_group_settings.get("raft_interface_extruder_nr").extruder_nr; - max_print_height_per_extruder[interface_extruder_nr] = std::max(-raft_layers + 1, max_print_height_per_extruder[interface_extruder_nr]); //Includes the second-lowest raft layer. - const size_t surface_extruder_nr = mesh_group_settings.get("raft_surface_extruder_nr").extruder_nr; - max_print_height_per_extruder[surface_extruder_nr] = std::max(-1, max_print_height_per_extruder[surface_extruder_nr]); //Includes up to the first layer below the model (so -1). - break; - } - default: - break; //No adhesion, so no maximum necessary. + case EPlatformAdhesion::SKIRT: + case EPlatformAdhesion::BRIM: + { + const size_t skirt_brim_extruder_nr = mesh_group_settings.get("skirt_brim_extruder_nr").extruder_nr; + max_print_height_per_extruder[skirt_brim_extruder_nr] = std::max(0, max_print_height_per_extruder[skirt_brim_extruder_nr]); // Includes layer 0. + break; + } + case EPlatformAdhesion::RAFT: + { + const size_t base_extruder_nr = mesh_group_settings.get("raft_base_extruder_nr").extruder_nr; + max_print_height_per_extruder[base_extruder_nr] = std::max(-raft_layers, max_print_height_per_extruder[base_extruder_nr]); // Includes the lowest raft layer. + const size_t interface_extruder_nr = mesh_group_settings.get("raft_interface_extruder_nr").extruder_nr; + max_print_height_per_extruder[interface_extruder_nr] = std::max(-raft_layers + 1, max_print_height_per_extruder[interface_extruder_nr]); // Includes the second-lowest raft layer. + const size_t surface_extruder_nr = mesh_group_settings.get("raft_surface_extruder_nr").extruder_nr; + max_print_height_per_extruder[surface_extruder_nr] = std::max(-1, max_print_height_per_extruder[surface_extruder_nr]); // Includes up to the first layer below the model (so -1). + break; + } + default: + break; // No adhesion, so no maximum necessary. } } @@ -902,7 +895,7 @@ void FffPolygonGenerator::computePrintHeightStatistics(SliceDataStorage& storage void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage) { const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; - if (!mesh_group_settings.get("ooze_shield_enabled")) + if (! mesh_group_settings.get("ooze_shield_enabled")) { return; } @@ -960,10 +953,10 @@ void FffPolygonGenerator::processDraftShield(SliceDataStorage& storage) const coord_t draft_shield_dist = mesh_group_settings.get("draft_shield_dist"); storage.draft_protection_shield = draft_shield.approxConvexHull(draft_shield_dist); - //Extra offset has rounded joints, so simplify again. - coord_t maximum_resolution = 0; //Draft shield is printed with every extruder, so resolve with the max() or min() of them to meet the requirements of all extruders. + // Extra offset has rounded joints, so simplify again. + coord_t maximum_resolution = 0; // Draft shield is printed with every extruder, so resolve with the max() or min() of them to meet the requirements of all extruders. coord_t maximum_deviation = std::numeric_limits::max(); - for(const ExtruderTrain& extruder : Application::getInstance().current_slice->scene.extruders) + for (const ExtruderTrain& extruder : Application::getInstance().current_slice->scene.extruders) { maximum_resolution = std::max(maximum_resolution, extruder.settings.get("meshfix_maximum_resolution")); maximum_deviation = std::min(maximum_deviation, extruder.settings.get("meshfix_maximum_deviation")); @@ -995,7 +988,7 @@ void FffPolygonGenerator::processPlatformAdhesion(SliceDataStorage& storage) SkirtBrim::generate(storage, storage.primeTower.outer_poly, 0, train.settings.get("brim_line_count"), dont_allow_helpers); } - switch(adhesion_type) + switch (adhesion_type) { case EPlatformAdhesion::SKIRT: // Already done, because of prime-tower-brim & ordering, see above. @@ -1038,7 +1031,7 @@ void FffPolygonGenerator::processFuzzyWalls(SliceMeshStorage& mesh) const coord_t avg_dist_between_points = mesh.settings.get("magic_fuzzy_skin_point_dist"); const coord_t min_dist_between_points = avg_dist_between_points * 3 / 4; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value const coord_t range_random_point_dist = avg_dist_between_points / 2; - unsigned int start_layer_nr = (mesh.settings.get("adhesion_type") == EPlatformAdhesion::BRIM)? 1 : 0; // don't make fuzzy skin on first layer if there's a brim + unsigned int start_layer_nr = (mesh.settings.get("adhesion_type") == EPlatformAdhesion::BRIM) ? 1 : 0; // don't make fuzzy skin on first layer if there's a brim auto hole_area = Polygons(); std::function accumulate_is_in_hole = [](const bool& prev_result, const ExtrusionJunction& junction) { return false; }; @@ -1063,8 +1056,7 @@ void FffPolygonGenerator::processFuzzyWalls(SliceMeshStorage& mesh) if (apply_outside_only) { hole_area = part.print_outline.getOutsidePolygons().offset(-line_width); - accumulate_is_in_hole = - [&hole_area](const bool& prev_result, const ExtrusionJunction& junction) { return prev_result || hole_area.inside(junction.p); }; + accumulate_is_in_hole = [&hole_area](const bool& prev_result, const ExtrusionJunction& junction) { return prev_result || hole_area.inside(junction.p); }; } for (auto& line : toolpath) { @@ -1143,4 +1135,4 @@ void FffPolygonGenerator::processFuzzyWalls(SliceMeshStorage& mesh) } -}//namespace cura +} // namespace cura diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index cc21dbddb6..9f168a07ec 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -1,11 +1,10 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher +#include "InsetOrderOptimizer.h" #include "ExtruderTrain.h" #include "FffGcodeWriter.h" -#include "InsetOrderOptimizer.h" #include "LayerPlan.h" -#include "utils/logoutput.h" #include "WallToolPaths.h" #include @@ -28,26 +27,26 @@ InsetOrderOptimizer::InsetOrderOptimizer(const FffGcodeWriter& gcode_writer, const size_t wall_0_extruder_nr, const size_t wall_x_extruder_nr, const ZSeamConfig& z_seam_config, - const std::vector& paths) : - gcode_writer(gcode_writer), - storage(storage), - gcode_layer(gcode_layer), - settings(settings), - extruder_nr(extruder_nr), - inset_0_non_bridge_config(inset_0_non_bridge_config), - inset_X_non_bridge_config(inset_X_non_bridge_config), - inset_0_bridge_config(inset_0_bridge_config), - inset_X_bridge_config(inset_X_bridge_config), - retract_before_outer_wall(retract_before_outer_wall), - wall_0_wipe_dist(wall_0_wipe_dist), - wall_x_wipe_dist(wall_x_wipe_dist), - wall_0_extruder_nr(wall_0_extruder_nr), - wall_x_extruder_nr(wall_x_extruder_nr), - z_seam_config(z_seam_config), - paths(paths), - layer_nr(gcode_layer.getLayerNr()), - added_something(false), - retraction_region_calculated(false) + const std::vector& paths) + : gcode_writer(gcode_writer) + , storage(storage) + , gcode_layer(gcode_layer) + , settings(settings) + , extruder_nr(extruder_nr) + , inset_0_non_bridge_config(inset_0_non_bridge_config) + , inset_X_non_bridge_config(inset_X_non_bridge_config) + , inset_0_bridge_config(inset_0_bridge_config) + , inset_X_bridge_config(inset_X_bridge_config) + , retract_before_outer_wall(retract_before_outer_wall) + , wall_0_wipe_dist(wall_0_wipe_dist) + , wall_x_wipe_dist(wall_x_wipe_dist) + , wall_0_extruder_nr(wall_0_extruder_nr) + , wall_x_extruder_nr(wall_x_extruder_nr) + , z_seam_config(z_seam_config) + , paths(paths) + , layer_nr(gcode_layer.getLayerNr()) + , added_something(false) + , retraction_region_calculated(false) { } @@ -62,7 +61,8 @@ bool InsetOrderOptimizer::addToLayer() const bool use_one_extruder = wall_0_extruder_nr == wall_x_extruder_nr; const bool current_extruder_is_wall_x = wall_x_extruder_nr == extruder_nr; - const auto should_reverse = [&](){ + const auto should_reverse = [&]() + { if (use_one_extruder && current_extruder_is_wall_x) { // The entire wall is printed with the current extruder. @@ -74,7 +74,7 @@ bool InsetOrderOptimizer::addToLayer() // If the wall is partially printed with the current extruder we need to move forward // for the outer wall extruder and iterate back for the inner wall extruder return current_extruder_is_wall_x; - }; // Helper lambda to ensure that the reverse bool can be a const type + }; // Helper lambda to ensure that the reverse bool can be a const type const bool reverse = should_reverse(); // Switches the begin()...end() forward iterator for a rbegin()...rend() reverse iterator @@ -102,18 +102,18 @@ bool InsetOrderOptimizer::addToLayer() const auto walls_to_be_added = get_walls_to_be_added(reverse, paths); const auto order = pack_by_inset ? getInsetOrder(walls_to_be_added, outer_to_inner) : getRegionOrder(walls_to_be_added, outer_to_inner); - + constexpr Ratio flow = 1.0_r; - + bool added_something = false; constexpr bool detect_loops = false; constexpr Polygons* combing_boundary = nullptr; - //When we alternate walls, also alternate the direction at which the first wall starts in. - //On even layers we start with normal direction, on odd layers with inverted direction. + // When we alternate walls, also alternate the direction at which the first wall starts in. + // On even layers we start with normal direction, on odd layers with inverted direction. constexpr bool reverse_all_paths = false; PathOrderOptimizer order_optimizer(gcode_layer.getLastPlannedPositionOrStartingPosition(), z_seam_config, detect_loops, combing_boundary, reverse_all_paths, order); - + for (const ExtrusionLine* line : walls_to_be_added) { if (line->is_closed) @@ -125,19 +125,20 @@ bool InsetOrderOptimizer::addToLayer() order_optimizer.addPolyline(line); } } - - + + order_optimizer.optimize(); - - cura::Point p_end {0, 0}; - for(const PathOrderPath& path : order_optimizer.paths) + + cura::Point p_end{ 0, 0 }; + for (const PathOrderPath& path : order_optimizer.paths) { - if (path.vertices->empty()) continue; - + if (path.vertices->empty()) + continue; + const bool is_outer_wall = path.vertices->inset_idx == 0; // or thin wall 'gap filler' const bool is_gap_filler = path.vertices->is_odd; const GCodePathConfig& non_bridge_config = is_outer_wall ? inset_0_non_bridge_config : inset_X_non_bridge_config; - const GCodePathConfig& bridge_config = is_outer_wall? inset_0_bridge_config : inset_X_bridge_config; + const GCodePathConfig& bridge_config = is_outer_wall ? inset_0_bridge_config : inset_X_bridge_config; const coord_t wipe_dist = is_outer_wall && ! is_gap_filler ? wall_0_wipe_dist : wall_x_wipe_dist; const bool retract_before = is_outer_wall ? retract_before_outer_wall : false; @@ -151,7 +152,7 @@ bool InsetOrderOptimizer::addToLayer() const bool linked_path = p_start != p_end; gcode_writer.setExtruder_addPrime(storage, gcode_layer, extruder_nr); - gcode_layer.setIsInside(true); //Going to print walls, which are always inside. + gcode_layer.setIsInside(true); // Going to print walls, which are always inside. gcode_layer.addWall(*path.vertices, start_index, settings, non_bridge_config, bridge_config, wipe_dist, flow, retract_before, path.is_closed, backwards, linked_path); added_something = true; } @@ -159,8 +160,6 @@ bool InsetOrderOptimizer::addToLayer() } - - std::unordered_set> InsetOrderOptimizer::getRegionOrder(const std::vector& input, const bool outer_to_inner) { std::unordered_set> order_requirements; @@ -168,7 +167,7 @@ std::unordered_set> InsetO // We build a grid where we map toolpath vertex locations to toolpaths, // so that we can easily find which two toolpaths are next to each other, // which is the requirement for there to be an order constraint. - // + // // We use a PointGrid rather than a LineGrid to save on computation time. // In very rare cases two insets might lie next to each other without having neighboring vertices, e.g. // \ . @@ -193,8 +192,9 @@ std::unordered_set> InsetO max_line_w = std::max(max_line_w, junction.w); } } - if (max_line_w == 0u) return order_requirements; - + if (max_line_w == 0u) + return order_requirements; + struct LineLoc { ExtrusionJunction j; @@ -207,7 +207,7 @@ std::unordered_set> InsetO return elem.j.p; } }; - + // How much farther two verts may be apart due to corners. // This distance must be smaller than 2, because otherwise // we could create an order requirement between e.g. @@ -219,12 +219,12 @@ std::unordered_set> InsetO using GridT = SparsePointGrid; GridT grid(searching_radius); - + for (const ExtrusionLine* line : input) { for (const ExtrusionJunction& junction : *line) { - grid.insert(LineLoc{junction, line}); + grid.insert(LineLoc{ junction, line }); } } for (const std::pair& pair : grid) @@ -236,11 +236,16 @@ std::unordered_set> InsetO for (const LineLoc& lineloc_nearby : nearby_verts) { const ExtrusionLine* nearby = lineloc_nearby.line; - if (nearby == here) continue; - if (nearby->inset_idx == here->inset_idx) continue; - if (nearby->inset_idx > here->inset_idx + 1) continue; // not directly adjacent - if (here->inset_idx > nearby->inset_idx + 1) continue; // not directly adjacent - if ( ! shorterThan(loc_here - lineloc_nearby.j.p, (lineloc_here.j.w + lineloc_nearby.j.w) / 2 * diagonal_extension)) continue; // points are too far away from each other + if (nearby == here) + continue; + if (nearby->inset_idx == here->inset_idx) + continue; + if (nearby->inset_idx > here->inset_idx + 1) + continue; // not directly adjacent + if (here->inset_idx > nearby->inset_idx + 1) + continue; // not directly adjacent + if (! shorterThan(loc_here - lineloc_nearby.j.p, (lineloc_here.j.w + lineloc_nearby.j.w) / 2 * diagonal_extension)) + continue; // points are too far away from each other if (here->is_odd || nearby->is_odd) { if (here->is_odd && ! nearby->is_odd && nearby->inset_idx < here->inset_idx) @@ -269,7 +274,7 @@ std::unordered_set> InsetO std::unordered_set> InsetOrderOptimizer::getInsetOrder(const std::vector& input, const bool outer_to_inner) { std::unordered_set> order; - + std::vector> walls_by_inset; std::vector> fillers_by_inset; @@ -312,17 +317,17 @@ std::unordered_set> InsetO { for (const ExtrusionLine* line : fillers_by_inset[inset_idx]) { - if (inset_idx - 1 >= walls_by_inset.size()) continue; + if (inset_idx - 1 >= walls_by_inset.size()) + continue; for (const ExtrusionLine* enclosing_wall : walls_by_inset[inset_idx - 1]) { order.emplace(enclosing_wall, line); } } - } - + return order; } -}//namespace cura +} // namespace cura diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index ad66bf37ff..6a5a5124e8 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -1,50 +1,58 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include #include +#include + #include "Application.h" //To communicate layer view data. #include "ExtruderTrain.h" #include "LayerPlan.h" #include "PathOrderMonotonic.h" //Monotonic ordering of skin lines. -#include "raft.h" // getTotalExtraLayers #include "Slice.h" -#include "sliceDataStorage.h" +#include "WipeScriptConfig.h" #include "communication/Communication.h" #include "pathPlanning/Comb.h" #include "pathPlanning/CombPaths.h" +#include "raft.h" // getTotalExtraLayers #include "settings/types/Ratio.h" -#include "utils/logoutput.h" +#include "sliceDataStorage.h" +#include "utils/Simplify.h" #include "utils/linearAlg2D.h" #include "utils/polygonUtils.h" -#include "utils/Simplify.h" -#include "WipeScriptConfig.h" -namespace cura { +namespace cura +{ constexpr int MINIMUM_LINE_LENGTH = 5; // in uM. Generated lines shorter than this may be discarded constexpr int MINIMUM_SQUARED_LINE_LENGTH = MINIMUM_LINE_LENGTH * MINIMUM_LINE_LENGTH; -ExtruderPlan::ExtruderPlan(const size_t extruder, const LayerIndex layer_nr, const bool is_initial_layer, const bool is_raft_layer, const coord_t layer_thickness, const FanSpeedLayerTimeSettings& fan_speed_layer_time_settings, const RetractionConfig& retraction_config) -: heated_pre_travel_time(0) -, required_start_temperature(-1) -, extruder_nr(extruder) -, layer_nr(layer_nr) -, is_initial_layer(is_initial_layer) -, is_raft_layer(is_raft_layer) -, layer_thickness(layer_thickness) -, fan_speed_layer_time_settings(fan_speed_layer_time_settings) -, retraction_config(retraction_config) -, extrudeSpeedFactor(1.0) -, extraTime(0.0) -, totalPrintTime(0) +ExtruderPlan::ExtruderPlan(const size_t extruder, + const LayerIndex layer_nr, + const bool is_initial_layer, + const bool is_raft_layer, + const coord_t layer_thickness, + const FanSpeedLayerTimeSettings& fan_speed_layer_time_settings, + const RetractionConfig& retraction_config) + : heated_pre_travel_time(0) + , required_start_temperature(-1) + , extruder_nr(extruder) + , layer_nr(layer_nr) + , is_initial_layer(is_initial_layer) + , is_raft_layer(is_raft_layer) + , layer_thickness(layer_thickness) + , fan_speed_layer_time_settings(fan_speed_layer_time_settings) + , retraction_config(retraction_config) + , extrudeSpeedFactor(1.0) + , extraTime(0.0) + , totalPrintTime(0) { } void ExtruderPlan::handleInserts(unsigned int& path_idx, GCodeExport& gcode) { - while ( ! inserts.empty() && path_idx >= inserts.front().path_idx) + while (! inserts.empty() && path_idx >= inserts.front().path_idx) { // handle the Insert to be inserted before this path_idx (and all inserts not handled yet) inserts.front().write(gcode); inserts.pop_front(); @@ -53,7 +61,7 @@ void ExtruderPlan::handleInserts(unsigned int& path_idx, GCodeExport& gcode) void ExtruderPlan::handleAllRemainingInserts(GCodeExport& gcode) { - while ( ! inserts.empty() ) + while (! inserts.empty()) { // handle the Insert to be inserted before this path_idx (and all inserts not handled yet) NozzleTempInsert& insert = inserts.front(); assert(insert.path_idx == paths.size()); @@ -87,7 +95,7 @@ void ExtruderPlan::applyBackPressureCompensation(const Ratio back_pressure_compe for (auto& path : paths) { const double nominal_width_for_path = static_cast(path.config->getLineWidth()); - if(path.width_factor <= 0.0 || nominal_width_for_path <= 0.0 || path.config->isTravelPath() || path.config->isBridgePath()) + if (path.width_factor <= 0.0 || nominal_width_for_path <= 0.0 || path.config->isTravelPath() || path.config->isBridgePath()) { continue; } @@ -99,7 +107,8 @@ void ExtruderPlan::applyBackPressureCompensation(const Ratio back_pressure_compe GCodePath* LayerPlan::getLatestPathWithConfig(const GCodePathConfig& config, SpaceFillType space_fill_type, const Ratio flow, const Ratio width_factor, bool spiralize, const Ratio speed_factor) { std::vector& paths = extruder_plans.back().paths; - if(paths.size() > 0 && paths.back().config == &config && !paths.back().done && paths.back().flow == flow && paths.back().width_factor == width_factor && paths.back().speed_factor == speed_factor && paths.back().mesh_id == current_mesh) // spiralize can only change when a travel path is in between + if (paths.size() > 0 && paths.back().config == &config && ! paths.back().done && paths.back().flow == flow && paths.back().width_factor == width_factor && paths.back().speed_factor == speed_factor + && paths.back().mesh_id == current_mesh) // spiralize can only change when a travel path is in between { return &paths.back(); } @@ -118,28 +127,36 @@ void LayerPlan::forceNewPathStart() { std::vector& paths = extruder_plans.back().paths; if (paths.size() > 0) - paths[paths.size()-1].done = true; + paths[paths.size() - 1].done = true; } -LayerPlan::LayerPlan(const SliceDataStorage& storage, LayerIndex layer_nr, coord_t z, coord_t layer_thickness, size_t start_extruder, const std::vector& fan_speed_layer_time_settings_per_extruder, coord_t comb_boundary_offset, coord_t comb_move_inside_distance, coord_t travel_avoid_distance) -: configs_storage(storage, layer_nr, layer_thickness) -, z(z) -, final_travel_z(z) -, mode_skip_agressive_merge(false) -, storage(storage) -, layer_nr(layer_nr) -, is_initial_layer(layer_nr == 0 - static_cast(Raft::getTotalExtraLayers())) -, is_raft_layer(layer_nr < 0 - static_cast(Raft::getFillerLayerCount())) -, layer_thickness(layer_thickness) -, has_prime_tower_planned_per_extruder(Application::getInstance().current_slice->scene.extruders.size(), false) -, current_mesh("NONMESH") -, last_extruder_previous_layer(start_extruder) -, last_planned_extruder(&Application::getInstance().current_slice->scene.extruders[start_extruder]) -, first_travel_destination_is_inside(false) // set properly when addTravel is called for the first time (otherwise not set properly) -, comb_boundary_minimum(computeCombBoundary(CombBoundary::MINIMUM)) -, comb_boundary_preferred(computeCombBoundary(CombBoundary::PREFERRED)) -, comb_move_inside_distance(comb_move_inside_distance) -, fan_speed_layer_time_settings_per_extruder(fan_speed_layer_time_settings_per_extruder) +LayerPlan::LayerPlan(const SliceDataStorage& storage, + LayerIndex layer_nr, + coord_t z, + coord_t layer_thickness, + size_t start_extruder, + const std::vector& fan_speed_layer_time_settings_per_extruder, + coord_t comb_boundary_offset, + coord_t comb_move_inside_distance, + coord_t travel_avoid_distance) + : configs_storage(storage, layer_nr, layer_thickness) + , z(z) + , final_travel_z(z) + , mode_skip_agressive_merge(false) + , storage(storage) + , layer_nr(layer_nr) + , is_initial_layer(layer_nr == 0 - static_cast(Raft::getTotalExtraLayers())) + , is_raft_layer(layer_nr < 0 - static_cast(Raft::getFillerLayerCount())) + , layer_thickness(layer_thickness) + , has_prime_tower_planned_per_extruder(Application::getInstance().current_slice->scene.extruders.size(), false) + , current_mesh("NONMESH") + , last_extruder_previous_layer(start_extruder) + , last_planned_extruder(&Application::getInstance().current_slice->scene.extruders[start_extruder]) + , first_travel_destination_is_inside(false) // set properly when addTravel is called for the first time (otherwise not set properly) + , comb_boundary_minimum(computeCombBoundary(CombBoundary::MINIMUM)) + , comb_boundary_preferred(computeCombBoundary(CombBoundary::PREFERRED)) + , comb_move_inside_distance(comb_move_inside_distance) + , fan_speed_layer_time_settings_per_extruder(fan_speed_layer_time_settings_per_extruder) { size_t current_extruder = start_extruder; was_inside = true; // not used, because the first travel move is bogus @@ -160,7 +177,7 @@ LayerPlan::LayerPlan(const SliceDataStorage& storage, LayerIndex layer_nr, coord extruder_plans.emplace_back(current_extruder, layer_nr, is_initial_layer, is_raft_layer, layer_thickness, fan_speed_layer_time_settings_per_extruder[current_extruder], storage.retraction_config_per_extruder[current_extruder]); for (size_t extruder_nr = 0; extruder_nr < Application::getInstance().current_slice->scene.extruders.size(); extruder_nr++) - { //Skirt and brim. + { // Skirt and brim. skirt_brim_is_processed[extruder_nr] = false; } } @@ -180,7 +197,7 @@ Polygons LayerPlan::computeCombBoundary(const CombBoundary boundary_type) { Polygons comb_boundary; const CombingMode mesh_combing_mode = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("retraction_combing"); - if (mesh_combing_mode != CombingMode::OFF && (layer_nr >=0 || mesh_combing_mode != CombingMode::NO_SKIN)) + if (mesh_combing_mode != CombingMode::OFF && (layer_nr >= 0 || mesh_combing_mode != CombingMode::NO_SKIN)) { if (layer_nr < 0) { @@ -197,18 +214,18 @@ Polygons LayerPlan::computeCombBoundary(const CombBoundary boundary_type) continue; } coord_t offset; - switch(boundary_type) + switch (boundary_type) { - case CombBoundary::MINIMUM: - offset = -mesh.settings.get("machine_nozzle_size") / 2 - 0.1 - mesh.settings.get("wall_line_width_0") / 2; - break; - case CombBoundary::PREFERRED: - offset = -mesh.settings.get("machine_nozzle_size") * 3 / 2 - mesh.settings.get("wall_line_width_0") / 2; - break; - default: - offset = 0; - logWarning("Unknown combing boundary type. Did you forget to configure the comb offset for a new boundary type?"); - break; + case CombBoundary::MINIMUM: + offset = -mesh.settings.get("machine_nozzle_size") / 2 - 0.1 - mesh.settings.get("wall_line_width_0") / 2; + break; + case CombBoundary::PREFERRED: + offset = -mesh.settings.get("machine_nozzle_size") * 3 / 2 - mesh.settings.get("wall_line_width_0") / 2; + break; + default: + offset = 0; + spdlog::warn("Unknown combing boundary type. Did you forget to configure the comb offset for a new boundary type?"); + break; } const CombingMode combing_mode = mesh.settings.get("retraction_combing"); @@ -262,11 +279,11 @@ bool LayerPlan::setExtruder(const size_t extruder_nr) ExtruderTrain* extruder = getLastPlannedExtruderTrain(); const bool end_pos_absolute = extruder->settings.get("machine_extruder_end_pos_abs"); Point end_pos(extruder->settings.get("machine_extruder_end_pos_x"), extruder->settings.get("machine_extruder_end_pos_y")); - if (!end_pos_absolute) + if (! end_pos_absolute) { end_pos += getLastPlannedPositionOrStartingPosition(); } - else + else { const Point extruder_offset(extruder->settings.get("machine_nozzle_offset_x"), extruder->settings.get("machine_nozzle_offset_y")); end_pos += extruder_offset; // absolute end pos is given as a head position @@ -288,11 +305,11 @@ bool LayerPlan::setExtruder(const size_t extruder_nr) ExtruderTrain* extruder = getLastPlannedExtruderTrain(); const bool start_pos_absolute = extruder->settings.get("machine_extruder_start_pos_abs"); Point start_pos(extruder->settings.get("machine_extruder_start_pos_x"), extruder->settings.get("machine_extruder_start_pos_y")); - if (!start_pos_absolute) + if (! start_pos_absolute) { start_pos += getLastPlannedPositionOrStartingPosition(); } - else + else { Point extruder_offset(extruder->settings.get("machine_nozzle_offset_x"), extruder->settings.get("machine_nozzle_offset_y")); start_pos += extruder_offset; // absolute start pos is given as a head position @@ -316,13 +333,12 @@ void LayerPlan::moveInsideCombBoundary(const coord_t distance, const std::option Point p = getLastPlannedPositionOrStartingPosition(); // copy, since we are going to move p if (PolygonUtils::moveInside(comb_boundary_preferred, p, distance, max_dist2) != NO_INDEX) { - //Move inside again, so we move out of tight 90deg corners + // Move inside again, so we move out of tight 90deg corners PolygonUtils::moveInside(comb_boundary_preferred, p, distance, max_dist2); - if (comb_boundary_preferred.inside(p) && - (part == std::nullopt || part->outline.inside(p))) + if (comb_boundary_preferred.inside(p) && (part == std::nullopt || part->outline.inside(p))) { addTravel_simple(p); - //Make sure the that any retraction happens after this move, not before it by starting a new move path. + // Make sure the that any retraction happens after this move, not before it by starting a new move path. forceNewPathStart(); } } @@ -362,7 +378,7 @@ GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract) const bool is_first_travel_of_extruder_after_switch = extruder_plans.back().paths.size() == 1 && (extruder_plans.size() > 1 || last_extruder_previous_layer != getExtruder()); bool bypass_combing = is_first_travel_of_extruder_after_switch && extruder->settings.get("retraction_hop_after_extruder_switch"); - const bool is_first_travel_of_layer = !static_cast(last_planned_position); + const bool is_first_travel_of_layer = ! static_cast(last_planned_position); const bool retraction_enable = extruder->settings.get("retraction_enable"); if (is_first_travel_of_layer) { @@ -376,7 +392,7 @@ GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract) } forceNewPathStart(); // force a new travel path after this first bogus move } - else if (force_retract && last_planned_position && !shorterThen(*last_planned_position - p, retraction_config.retraction_min_travel_distance)) + else if (force_retract && last_planned_position && ! shorterThen(*last_planned_position - p, retraction_config.retraction_min_travel_distance)) { // path is not shorter than min travel distance, force a retraction path->retract = true; @@ -386,7 +402,7 @@ GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract) } } - if (comb != nullptr && !bypass_combing) + if (comb != nullptr && ! bypass_combing) { CombPaths combPaths; @@ -399,7 +415,7 @@ GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract) if (combed) { bool retract = path->retract || (combPaths.size() > 1 && retraction_enable); - if (!retract) + if (! retract) { // check whether we want to retract if (combPaths.throughAir) { @@ -419,8 +435,7 @@ GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract) if (combPaths.size() == 1) { CombPath comb_path = combPaths[0]; - if (extruder->settings.get("limit_support_retractions") && - combPaths.throughAir && !comb_path.cross_boundary && comb_path.size() == 2 && comb_path[0] == *last_planned_position && comb_path[1] == p) + if (extruder->settings.get("limit_support_retractions") && combPaths.throughAir && ! comb_path.cross_boundary && comb_path.size() == 2 && comb_path[0] == *last_planned_position && comb_path[1] == p) { // limit the retractions from support to support, which didn't cross anything retract = false; } @@ -461,18 +476,18 @@ GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract) // CURA-6675: // Retraction Minimal Travel Distance should work for all travel moves. If the travel move is shorter than the // Retraction Minimal Travel Distance, retraction should be disabled. - if (!is_first_travel_of_layer && last_planned_position && shorterThen(*last_planned_position - p, retraction_config.retraction_min_travel_distance)) + if (! is_first_travel_of_layer && last_planned_position && shorterThen(*last_planned_position - p, retraction_config.retraction_min_travel_distance)) { path->retract = false; path->perform_z_hop = false; } // no combing? retract only when path is not shorter than minimum travel distance - if (!combed && !is_first_travel_of_layer && last_planned_position && !shorterThen(*last_planned_position - p, retraction_config.retraction_min_travel_distance)) + if (! combed && ! is_first_travel_of_layer && last_planned_position && ! shorterThen(*last_planned_position - p, retraction_config.retraction_min_travel_distance)) { if (was_inside) // when the previous location was from printing something which is considered inside (not support or prime tower etc) - { // then move inside the printed part, so that we don't ooze on the outer wall while retraction, but on the inside of the print. - assert (extruder != nullptr); + { // then move inside the printed part, so that we don't ooze on the outer wall while retraction, but on the inside of the print. + assert(extruder != nullptr); coord_t innermost_wall_line_width = extruder->settings.get((extruder->settings.get("wall_line_count") > 1) ? "wall_line_width_x" : "wall_line_width_0"); if (layer_nr == 0) { @@ -494,7 +509,7 @@ GCodePath& LayerPlan::addTravel(const Point p, const bool force_retract) GCodePath& LayerPlan::addTravel_simple(Point p, GCodePath* path) { - bool is_first_travel_of_layer = !static_cast(last_planned_position); + bool is_first_travel_of_layer = ! static_cast(last_planned_position); if (is_first_travel_of_layer) { // spiralize calls addTravel_simple directly as the first travel move in a layer first_travel_destination = p; @@ -524,7 +539,7 @@ void LayerPlan::addExtrusionMove(Point p, const GCodePathConfig& config, SpaceFi GCodePath* path = getLatestPathWithConfig(config, space_fill_type, flow, width_factor, spiralize, speed_factor); path->points.push_back(p); path->setFanSpeed(fan_speed); - if(!static_cast(first_extrusion_acc_jerk)) + if (! static_cast(first_extrusion_acc_jerk)) { first_extrusion_acc_jerk = std::make_pair(path->config->getAcceleration(), path->config->getJerk()); } @@ -533,26 +548,26 @@ void LayerPlan::addExtrusionMove(Point p, const GCodePathConfig& config, SpaceFi void LayerPlan::addPolygon(ConstPolygonRef polygon, int start_idx, const bool backwards, const GCodePathConfig& config, coord_t wall_0_wipe_dist, bool spiralize, const Ratio& flow_ratio, bool always_retract) { - constexpr Ratio width_ratio = 1.0_r; //Not printed with variable line width. + constexpr Ratio width_ratio = 1.0_r; // Not printed with variable line width. Point p0 = polygon[start_idx]; addTravel(p0, always_retract); const int direction = backwards ? -1 : 1; - for(size_t point_idx = 1; point_idx < polygon.size(); point_idx++) + for (size_t point_idx = 1; point_idx < polygon.size(); point_idx++) { Point p1 = polygon[(start_idx + point_idx * direction + polygon.size()) % polygon.size()]; addExtrusionMove(p1, config, SpaceFillType::Polygons, flow_ratio, width_ratio, spiralize); p0 = p1; } - if(polygon.size() > 2) + if (polygon.size() > 2) { const Point& p1 = polygon[start_idx]; addExtrusionMove(p1, config, SpaceFillType::Polygons, flow_ratio, width_ratio, spiralize); - if(wall_0_wipe_dist > 0) + if (wall_0_wipe_dist > 0) { // apply outer wall wipe p0 = polygon[start_idx]; int distance_traversed = 0; - for(size_t point_idx = 1; ; point_idx++) + for (size_t point_idx = 1;; point_idx++) { Point p1 = polygon[(start_idx + point_idx * direction + polygon.size()) % polygon.size()]; int p0p1_dist = vSize(p1 - p0); @@ -573,35 +588,43 @@ void LayerPlan::addPolygon(ConstPolygonRef polygon, int start_idx, const bool ba forceNewPathStart(); } } - else + else { - logWarning("WARNING: line added as polygon! (LayerPlan)\n"); + spdlog::warn("line added as polygon! (LayerPlan)"); } } -void LayerPlan::addPolygonsByOptimizer(const Polygons& polygons, const GCodePathConfig& config, const ZSeamConfig& z_seam_config, coord_t wall_0_wipe_dist, bool spiralize, const Ratio flow_ratio, bool always_retract, bool reverse_order, const std::optional start_near_location) +void LayerPlan::addPolygonsByOptimizer(const Polygons& polygons, + const GCodePathConfig& config, + const ZSeamConfig& z_seam_config, + coord_t wall_0_wipe_dist, + bool spiralize, + const Ratio flow_ratio, + bool always_retract, + bool reverse_order, + const std::optional start_near_location) { - if(polygons.empty()) + if (polygons.empty()) { return; } PathOrderOptimizer orderOptimizer(start_near_location ? start_near_location.value() : getLastPlannedPositionOrStartingPosition(), z_seam_config); - for(size_t poly_idx = 0; poly_idx < polygons.size(); poly_idx++) + for (size_t poly_idx = 0; poly_idx < polygons.size(); poly_idx++) { orderOptimizer.addPolygon(polygons[poly_idx]); } orderOptimizer.optimize(); - if(!reverse_order) + if (! reverse_order) { - for(const PathOrderPath& path : orderOptimizer.paths) + for (const PathOrderPath& path : orderOptimizer.paths) { addPolygon(*path.vertices, path.start_vertex, path.backwards, config, wall_0_wipe_dist, spiralize, flow_ratio, always_retract); } } else { - for(int index = orderOptimizer.paths.size() - 1; index >= 0; --index) + for (int index = orderOptimizer.paths.size() - 1; index >= 0; --index) { const PathOrderPath& path = orderOptimizer.paths[index]; addPolygon(**path.vertices, path.start_vertex, path.backwards, config, wall_0_wipe_dist, spiralize, flow_ratio, always_retract); @@ -611,7 +634,16 @@ void LayerPlan::addPolygonsByOptimizer(const Polygons& polygons, const GCodePath static constexpr float max_non_bridge_line_volume = MM2INT(100); // limit to accumulated "volume" of non-bridge lines which is proportional to distance x extrusion rate -void LayerPlan::addWallLine(const Point& p0, const Point& p1, const Settings& settings, const GCodePathConfig& non_bridge_config, const GCodePathConfig& bridge_config, float flow, const Ratio width_factor, float& non_bridge_line_volume, Ratio speed_factor, double distance_to_bridge_start) +void LayerPlan::addWallLine(const Point& p0, + const Point& p1, + const Settings& settings, + const GCodePathConfig& non_bridge_config, + const GCodePathConfig& bridge_config, + float flow, + const Ratio width_factor, + float& non_bridge_line_volume, + Ratio speed_factor, + double distance_to_bridge_start) { const coord_t min_line_len = 5; // we ignore lines less than 5um long const double acceleration_segment_len = MM2INT(1); // accelerate using segments of this length @@ -669,14 +701,19 @@ void LayerPlan::addWallLine(const Point& p0, const Point& p1, const Settings& se addExtrusionMove(segment_end + coast_dist * (cur_point - segment_end) / len, non_bridge_config, SpaceFillType::Polygons, segment_flow, width_factor, spiralize, speed_factor); } // then coast to start of bridge segment - constexpr Ratio flow = 0.0_r; //Coasting has no flow rate. + constexpr Ratio flow = 0.0_r; // Coasting has no flow rate. addExtrusionMove(segment_end, non_bridge_config, SpaceFillType::Polygons, flow, width_factor, spiralize, speed_factor); } else { // no coasting required, just normal segment using non-bridge config - addExtrusionMove(segment_end, non_bridge_config, SpaceFillType::Polygons, segment_flow, width_factor, spiralize, - (overhang_mask.empty() || (!overhang_mask.inside(p0, true) && !overhang_mask.inside(p1, true))) ? speed_factor : overhang_speed_factor); + addExtrusionMove(segment_end, + non_bridge_config, + SpaceFillType::Polygons, + segment_flow, + width_factor, + spiralize, + (overhang_mask.empty() || (! overhang_mask.inside(p0, true) && ! overhang_mask.inside(p1, true))) ? speed_factor : overhang_speed_factor); } distance_to_bridge_start -= len; @@ -684,8 +721,13 @@ void LayerPlan::addWallLine(const Point& p0, const Point& p1, const Settings& se else { // no coasting required, just normal segment using non-bridge config - addExtrusionMove(segment_end, non_bridge_config, SpaceFillType::Polygons, segment_flow, width_factor, spiralize, - (overhang_mask.empty() || (!overhang_mask.inside(p0, true) && !overhang_mask.inside(p1, true))) ? speed_factor : overhang_speed_factor); + addExtrusionMove(segment_end, + non_bridge_config, + SpaceFillType::Polygons, + segment_flow, + width_factor, + spiralize, + (overhang_mask.empty() || (! overhang_mask.inside(p0, true) && ! overhang_mask.inside(p1, true))) ? speed_factor : overhang_speed_factor); } non_bridge_line_volume += vSize(cur_point - segment_end) * segment_flow * width_factor * speed_factor * non_bridge_config.getSpeed(); cur_point = segment_end; @@ -701,8 +743,7 @@ void LayerPlan::addWallLine(const Point& p0, const Point& p1, const Settings& se if (bridge_wall_mask.empty()) { // no bridges required - addExtrusionMove(p1, non_bridge_config, SpaceFillType::Polygons, flow, width_factor, spiralize, - (overhang_mask.empty() || (!overhang_mask.inside(p0, true) && !overhang_mask.inside(p1, true))) ? 1.0_r : overhang_speed_factor); + addExtrusionMove(p1, non_bridge_config, SpaceFillType::Polygons, flow, width_factor, spiralize, (overhang_mask.empty() || (! overhang_mask.inside(p0, true) && ! overhang_mask.inside(p1, true))) ? 1.0_r : overhang_speed_factor); } else { @@ -725,7 +766,7 @@ void LayerPlan::addWallLine(const Point& p0, const Point& p1, const Settings& se // find the bridge line segment that's nearest to the current point int nearest = 0; float smallest_dist2 = vSize2f(cur_point - line_polys[0][0]); - for(unsigned i = 1; i < line_polys.size(); ++i) + for (unsigned i = 1; i < line_polys.size(); ++i) { float dist2 = vSize2f(cur_point - line_polys[i][0]); if (dist2 < smallest_dist2) @@ -796,20 +837,17 @@ void LayerPlan::addWallLine(const Point& p0, const Point& p1, const Settings& se void LayerPlan::addWall(ConstPolygonRef wall, int start_idx, const Settings& settings, const GCodePathConfig& non_bridge_config, const GCodePathConfig& bridge_config, coord_t wall_0_wipe_dist, float flow_ratio, bool always_retract) { - //TODO: Deprecated in favor of ExtrusionJunction version below. + // TODO: Deprecated in favor of ExtrusionJunction version below. if (wall.size() < 3) { - logWarning("WARNING: point, or line added as (polygon) wall sequence! (LayerPlan)\n"); + spdlog::warn("Point, or line added as (polygon) wall sequence! (LayerPlan)"); } - constexpr size_t dummy_perimeter_id = 0; // <-- Here, don't care about which perimeter any more. - const coord_t nominal_line_width = non_bridge_config.getLineWidth(); // <-- The line width which it's 'supposed to' be will be used to adjust the flow ratio each time, this'll give a flow-ratio-multiplier of 1. + constexpr size_t dummy_perimeter_id = 0; // <-- Here, don't care about which perimeter any more. + const coord_t nominal_line_width = non_bridge_config.getLineWidth(); // <-- The line width which it's 'supposed to' be will be used to adjust the flow ratio each time, this'll give a flow-ratio-multiplier of 1. ExtrusionLine ewall; - std::for_each(wall.begin(), wall.end(), [&dummy_perimeter_id, &nominal_line_width, &ewall](const Point& p) - { - ewall.emplace_back(p, nominal_line_width, dummy_perimeter_id); - }); + std::for_each(wall.begin(), wall.end(), [&dummy_perimeter_id, &nominal_line_width, &ewall](const Point& p) { ewall.emplace_back(p, nominal_line_width, dummy_perimeter_id); }); ewall.emplace_back(*wall.begin(), nominal_line_width, dummy_perimeter_id); constexpr bool is_closed = true; constexpr bool is_reversed = false; @@ -817,13 +855,23 @@ void LayerPlan::addWall(ConstPolygonRef wall, int start_idx, const Settings& set addWall(ewall, start_idx, settings, non_bridge_config, bridge_config, wall_0_wipe_dist, flow_ratio, always_retract, is_closed, is_reversed, is_linked_path); } -void LayerPlan::addWall(const ExtrusionLine& wall, int start_idx, const Settings& settings, const GCodePathConfig& non_bridge_config, const GCodePathConfig& bridge_config, coord_t wall_0_wipe_dist, float flow_ratio, bool always_retract, const bool is_closed, const bool is_reversed, const bool is_linked_path) +void LayerPlan::addWall(const ExtrusionLine& wall, + int start_idx, + const Settings& settings, + const GCodePathConfig& non_bridge_config, + const GCodePathConfig& bridge_config, + coord_t wall_0_wipe_dist, + float flow_ratio, + bool always_retract, + const bool is_closed, + const bool is_reversed, + const bool is_linked_path) { if (wall.empty()) { return; } - if(is_closed) + if (is_closed) { // make sure wall start point is not above air! start_idx = locateFirstSupportedVertex(wall, start_idx); @@ -843,7 +891,7 @@ void LayerPlan::addWall(const ExtrusionLine& wall, int start_idx, const Settings { distance_to_bridge_start = 0; - if (!bridge_wall_mask.empty()) + if (! bridge_wall_mask.empty()) { // there is air below the part so iterate through the lines that have not yet been output accumulating the total distance to the first bridge segment for (unsigned point_idx = current_index; point_idx < wall.size(); ++point_idx) @@ -867,7 +915,7 @@ void LayerPlan::addWall(const ExtrusionLine& wall, int start_idx, const Settings // find the bridge line segment that's nearest to p0 int nearest = 0; float smallest_dist2 = vSize2f(p0.p - line_polys[0][0]); - for(unsigned i = 1; i < line_polys.size(); ++i) + for (unsigned i = 1; i < line_polys.size(); ++i) { float dist2 = vSize2f(p0.p - line_polys[i][0]); if (dist2 < smallest_dist2) @@ -905,7 +953,7 @@ void LayerPlan::addWall(const ExtrusionLine& wall, int start_idx, const Settings line_polys.remove(nearest); } } - else if (!bridge_wall_mask.inside(p0.p, true)) + else if (! bridge_wall_mask.inside(p0.p, true)) { // none of the line is over air distance_to_bridge_start += vSize(p1.p - p0.p); @@ -924,23 +972,23 @@ void LayerPlan::addWall(const ExtrusionLine& wall, int start_idx, const Settings Ratio small_feature_speed_factor = settings.get((layer_nr == 0) ? "small_feature_speed_factor_0" : "small_feature_speed_factor"); const Velocity min_speed = fan_speed_layer_time_settings_per_extruder[getLastPlannedExtruderTrain()->extruder_nr].cool_min_speed; small_feature_speed_factor = std::max((double)small_feature_speed_factor, (double)(min_speed / non_bridge_config.getSpeed())); - const coord_t max_area_deviation = std::max(settings.get("meshfix_maximum_extrusion_area_deviation"), 1); //Square micrometres! + const coord_t max_area_deviation = std::max(settings.get("meshfix_maximum_extrusion_area_deviation"), 1); // Square micrometres! const coord_t max_resolution = std::max(settings.get("meshfix_maximum_resolution"), coord_t(1)); ExtrusionJunction p0 = wall[start_idx]; const int direction = is_reversed ? -1 : 1; const size_t max_index = is_closed ? wall.size() + 1 : wall.size(); - for(size_t point_idx = 1; point_idx < max_index; point_idx++) + for (size_t point_idx = 1; point_idx < max_index; point_idx++) { const ExtrusionJunction& p1 = wall[(wall.size() + start_idx + point_idx * direction) % wall.size()]; - if(!bridge_wall_mask.empty()) + if (! bridge_wall_mask.empty()) { computeDistanceToBridgeStart((wall.size() + start_idx + point_idx * direction - 1) % wall.size()); } - if(first_line) + if (first_line) { addTravel(p0.p, always_retract); first_line = false; @@ -970,17 +1018,17 @@ void LayerPlan::addWall(const ExtrusionLine& wall, int start_idx, const Settings This results in delta_line_width / 2 * line_length / 2 / 2 * 2 == delta_line_width * line_length / 4. */ const coord_t line_area_deviation = std::abs(delta_line_width) * line_length / 4; - const size_t pieces_limit_deviation = round_up_divide(line_area_deviation, max_area_deviation); //How many pieces we'd need to stay beneath the max area deviation. - const size_t pieces_limit_resolution = line_length / max_resolution; //Round down this time, to not exceed the maximum resolution. - const size_t pieces = std::max(size_t(1), std::min(pieces_limit_deviation, pieces_limit_resolution)); //Resolution overrides deviation, if resolution is a constraint. + const size_t pieces_limit_deviation = round_up_divide(line_area_deviation, max_area_deviation); // How many pieces we'd need to stay beneath the max area deviation. + const size_t pieces_limit_resolution = line_length / max_resolution; // Round down this time, to not exceed the maximum resolution. + const size_t pieces = std::max(size_t(1), std::min(pieces_limit_deviation, pieces_limit_resolution)); // Resolution overrides deviation, if resolution is a constraint. const coord_t piece_length = round_divide(line_length, pieces); - for(size_t piece = 0; piece < pieces; ++piece) + for (size_t piece = 0; piece < pieces; ++piece) { - const float average_progress = (float(piece) + 0.5) / pieces; //How far along this line to sample the line width in the middle of this piece. + const float average_progress = (float(piece) + 0.5) / pieces; // How far along this line to sample the line width in the middle of this piece. const coord_t line_width = p0.w + average_progress * delta_line_width; const Point destination = p0.p + normal(line_vector, piece_length * (piece + 1)); - if(is_small_feature) + if (is_small_feature) { constexpr bool spiralize = false; addExtrusionMove(destination, non_bridge_config, SpaceFillType::Polygons, flow_ratio, line_width * nominal_line_width_multiplier, spiralize, small_feature_speed_factor); @@ -997,20 +1045,20 @@ void LayerPlan::addWall(const ExtrusionLine& wall, int start_idx, const Settings if (wall.size() >= 2) { - if (!bridge_wall_mask.empty()) + if (! bridge_wall_mask.empty()) { computeDistanceToBridgeStart((start_idx + wall.size() - 1) % wall.size()); } - if (wall_0_wipe_dist > 0 && !is_linked_path) + if (wall_0_wipe_dist > 0 && ! is_linked_path) { // apply outer wall wipe p0 = wall[start_idx]; int distance_traversed = 0; - for (unsigned int point_idx = 1; ; point_idx++) + for (unsigned int point_idx = 1;; point_idx++) { - if(point_idx > wall.size() && distance_traversed == 0) //Wall has a total circumference of 0. This loop would never end. + if (point_idx > wall.size() && distance_traversed == 0) // Wall has a total circumference of 0. This loop would never end. { - break; //No wipe if the wall has no circumference. + break; // No wipe if the wall has no circumference. } ExtrusionJunction p1 = wall[(start_idx + point_idx) % wall.size()]; int p0p1_dist = vSize(p1 - p0); @@ -1033,18 +1081,17 @@ void LayerPlan::addWall(const ExtrusionLine& wall, int start_idx, const Settings } else { - logWarning("WARNING: point added as wall sequence! (LayerPlan)\n"); + spdlog::warn("Point added as wall sequence! (LayerPlan)"); } } -void LayerPlan::addInfillWall(const ExtrusionLine& wall, const GCodePathConfig& path_config, - bool force_retract) +void LayerPlan::addInfillWall(const ExtrusionLine& wall, const GCodePathConfig& path_config, bool force_retract) { - assert(("All empty walls should have been filtered at this stage", !wall.empty())); - ExtrusionJunction junction{*wall.begin()}; + assert(("All empty walls should have been filtered at this stage", ! wall.empty())); + ExtrusionJunction junction{ *wall.begin() }; addTravel(junction.p, force_retract); - for (const auto &junction_n : wall) + for (const auto& junction_n : wall) { const Ratio width_factor = junction_n.w / Ratio(path_config.getLineWidth()); constexpr SpaceFillType space_fill_type = SpaceFillType::Polygons; @@ -1054,47 +1101,41 @@ void LayerPlan::addInfillWall(const ExtrusionLine& wall, const GCodePathConfig& } } -void LayerPlan::addWalls -( - const Polygons& walls, - const Settings& settings, - const GCodePathConfig& non_bridge_config, - const GCodePathConfig& bridge_config, - const ZSeamConfig& z_seam_config, - coord_t wall_0_wipe_dist, - float flow_ratio, - bool always_retract -) +void LayerPlan::addWalls(const Polygons& walls, + const Settings& settings, + const GCodePathConfig& non_bridge_config, + const GCodePathConfig& bridge_config, + const ZSeamConfig& z_seam_config, + coord_t wall_0_wipe_dist, + float flow_ratio, + bool always_retract) { - //TODO: Deprecated in favor of ExtrusionJunction version below. + // TODO: Deprecated in favor of ExtrusionJunction version below. PathOrderOptimizer orderOptimizer(getLastPlannedPositionOrStartingPosition(), z_seam_config); - for(size_t poly_idx = 0; poly_idx < walls.size(); poly_idx++) + for (size_t poly_idx = 0; poly_idx < walls.size(); poly_idx++) { orderOptimizer.addPolygon(walls[poly_idx]); } orderOptimizer.optimize(); - for(const PathOrderPath& path : orderOptimizer.paths) + for (const PathOrderPath& path : orderOptimizer.paths) { addWall(**path.vertices, path.start_vertex, settings, non_bridge_config, bridge_config, wall_0_wipe_dist, flow_ratio, always_retract); } } -void LayerPlan::addLinesByOptimizer -( - const Polygons& polygons, - const GCodePathConfig& config, - const SpaceFillType space_fill_type, - const bool enable_travel_optimization, - const coord_t wipe_dist, - const Ratio flow_ratio, - const std::optional near_start_location, - const double fan_speed, - const bool reverse_print_direction -) +void LayerPlan::addLinesByOptimizer(const Polygons& polygons, + const GCodePathConfig& config, + const SpaceFillType space_fill_type, + const bool enable_travel_optimization, + const coord_t wipe_dist, + const Ratio flow_ratio, + const std::optional near_start_location, + const double fan_speed, + const bool reverse_print_direction) { Polygons boundary; - if (enable_travel_optimization && !comb_boundary_minimum.empty()) + if (enable_travel_optimization && ! comb_boundary_minimum.empty()) { // use the combing boundary inflated so that all infill lines are inside the boundary int dist = 0; @@ -1117,28 +1158,21 @@ void LayerPlan::addLinesByOptimizer } constexpr bool detect_loops = true; PathOrderOptimizer order_optimizer(near_start_location.value_or(getLastPlannedPositionOrStartingPosition()), ZSeamConfig(), detect_loops, &boundary, reverse_print_direction); - for(size_t line_idx = 0; line_idx < polygons.size(); line_idx++) + for (size_t line_idx = 0; line_idx < polygons.size(); line_idx++) { order_optimizer.addPolyline(polygons[line_idx]); } order_optimizer.optimize(); - + addLinesInGivenOrder(order_optimizer.paths, config, space_fill_type, wipe_dist, flow_ratio, fan_speed); } -void LayerPlan::addLinesInGivenOrder( - const std::vector>& paths, - const GCodePathConfig& config, - const SpaceFillType space_fill_type, - const coord_t wipe_dist, - const Ratio flow_ratio, - const double fan_speed -) +void LayerPlan::addLinesInGivenOrder(const std::vector>& paths, const GCodePathConfig& config, const SpaceFillType space_fill_type, const coord_t wipe_dist, const Ratio flow_ratio, const double fan_speed) { coord_t half_line_width = config.getLineWidth() / 2; coord_t line_width_2 = half_line_width * half_line_width; - for(size_t order_idx = 0; order_idx < paths.size(); order_idx++) + for (size_t order_idx = 0; order_idx < paths.size(); order_idx++) { const PathOrderPath& path = paths[order_idx]; ConstPolygonRef polyline = *path.vertices; @@ -1146,7 +1180,7 @@ void LayerPlan::addLinesInGivenOrder( assert(start_idx == 0 || start_idx == polyline.size() - 1 || path.is_closed); const Point start = polyline[start_idx]; - if(vSize2(getLastPlannedPositionOrStartingPosition() - start) < line_width_2) + if (vSize2(getLastPlannedPositionOrStartingPosition() - start) < line_width_2) { // Instead of doing a small travel that is shorter than the line width (which is generally done at pretty high jerk & move) do a // "fake" extrusion move @@ -1192,11 +1226,10 @@ void LayerPlan::addLinesInGivenOrder( } Point p1 = polyline[(start_idx == 0) ? polyline.size() - 1 : 0]; - p0 = (polyline.size() <= 1) ? p1 - : polyline[(start_idx == 0) ? polyline.size() - 2 : 1]; + p0 = (polyline.size() <= 1) ? p1 : polyline[(start_idx == 0) ? polyline.size() - 2 : 1]; // Wipe - if(wipe_dist != 0) + if (wipe_dist != 0) { bool wipe = true; int line_width = config.getLineWidth(); @@ -1208,7 +1241,7 @@ void LayerPlan::addLinesInGivenOrder( } // Don't wipe if next starting point is very near - if(wipe && (order_idx < paths.size() - 1)) + if (wipe && (order_idx < paths.size() - 1)) { const PathOrderPath& next_path = paths[order_idx + 1]; ConstPolygonRef next_polygon = *next_path.vertices; @@ -1232,19 +1265,16 @@ void LayerPlan::addLinesInGivenOrder( } } -void LayerPlan::addLinesMonotonic -( - const Polygons& area, - const Polygons& polygons, - const GCodePathConfig& config, - const SpaceFillType space_fill_type, - const AngleRadians monotonic_direction, - const coord_t max_adjacent_distance, - const coord_t exclude_distance, - const coord_t wipe_dist, - const Ratio flow_ratio, - const double fan_speed -) +void LayerPlan::addLinesMonotonic(const Polygons& area, + const Polygons& polygons, + const GCodePathConfig& config, + const SpaceFillType space_fill_type, + const AngleRadians monotonic_direction, + const coord_t max_adjacent_distance, + const coord_t exclude_distance, + const coord_t wipe_dist, + const Ratio flow_ratio, + const double fan_speed) { const Polygons exclude_areas = area.tubeShape(exclude_distance, exclude_distance); const coord_t exclude_dist2 = exclude_distance * exclude_distance; @@ -1252,23 +1282,19 @@ void LayerPlan::addLinesMonotonic // First lay all adjacent lines next to each other, to have a sensible input to the monotonic part of the algorithm. PathOrderOptimizer line_order(last_position); - for(const ConstPolygonRef polyline : polygons) + for (const ConstPolygonRef polyline : polygons) { line_order.addPolyline(polyline); } line_order.optimize(); - const auto is_inside_exclusion = - [&exclude_areas, &exclude_dist2](ConstPolygonRef path) - { - return vSize2(path[1] - path[0]) < exclude_dist2 && exclude_areas.inside((path[0] + path[1]) / 2); - }; + const auto is_inside_exclusion = [&exclude_areas, &exclude_dist2](ConstPolygonRef path) { return vSize2(path[1] - path[0]) < exclude_dist2 && exclude_areas.inside((path[0] + path[1]) / 2); }; // Order monotonically, except for line-segments which stay in the excluded areas (read: close to the walls) consecutively. PathOrderMonotonic order(monotonic_direction, max_adjacent_distance, last_position); Polygons left_over; bool last_would_have_been_excluded = false; - for(size_t line_idx = 0; line_idx < line_order.paths.size(); ++line_idx) + for (size_t line_idx = 0; line_idx < line_order.paths.size(); ++line_idx) { const ConstPolygonRef polyline = *line_order.paths[line_idx].vertices; const bool inside_exclusion = is_inside_exclusion(polyline); @@ -1295,16 +1321,17 @@ void LayerPlan::addLinesMonotonic void LayerPlan::spiralizeWallSlice(const GCodePathConfig& config, ConstPolygonRef wall, ConstPolygonRef last_wall, const int seam_vertex_idx, const int last_seam_vertex_idx, const bool is_top_layer, const bool is_bottom_layer) { const bool smooth_contours = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("smooth_spiralized_contours"); - constexpr bool spiralize = true; //In addExtrusionMove calls, enable spiralize and use nominal line width. + constexpr bool spiralize = true; // In addExtrusionMove calls, enable spiralize and use nominal line width. constexpr Ratio width_factor = 1.0_r; // once we are into the spiral we always start at the end point of the last layer (if any) - const Point origin = (last_seam_vertex_idx >= 0 && !is_bottom_layer) ? last_wall[last_seam_vertex_idx] : wall[seam_vertex_idx]; + const Point origin = (last_seam_vertex_idx >= 0 && ! is_bottom_layer) ? last_wall[last_seam_vertex_idx] : wall[seam_vertex_idx]; // NOTE: this used to use addTravel_simple() but if support is being generated then combed travel is required to avoid // the nozzle crossing the model on its return from printing the support. addTravel(origin); - if (!smooth_contours && last_seam_vertex_idx >= 0) { + if (! smooth_contours && last_seam_vertex_idx >= 0) + { // when not smoothing, we get to the (unchanged) outline for this layer as quickly as possible so that the remainder of the // outline wall has the correct direction - although this creates a little step, the end result is generally better because when the first // outline wall has the wrong direction (due to it starting from the finish point of the last layer) the visual effect is very noticeable @@ -1386,7 +1413,7 @@ void LayerPlan::spiralizeWallSlice(const GCodePathConfig& config, ConstPolygonRe // if required, use interpolation to smooth the x/y coordinates between layers but not for the first spiralized layer // as that lies directly on top of a non-spiralized wall with exactly the same outline and not for the last point in each layer // because we want that to be numerically exactly the same as the starting point on the next layer (not subject to any rounding) - if (smooth_contours && !is_bottom_layer && wall_point_idx < n_points) + if (smooth_contours && ! is_bottom_layer && wall_point_idx < n_points) { // now find the point on the last wall that is closest to p ClosestPolygonPoint cpp = PolygonUtils::findClosest(p, last_wall_polygons); @@ -1438,7 +1465,7 @@ void LayerPlan::spiralizeWallSlice(const GCodePathConfig& config, ConstPolygonRe void ExtruderPlan::forceMinimalLayerTime(double minTime, double minimalSpeed, double travelTime, double extrudeTime) { - double totalTime = travelTime + extrudeTime; + double totalTime = travelTime + extrudeTime; if (totalTime < minTime && extrudeTime > 0.0) { double minExtrudeTime = minTime - travelTime; @@ -1454,19 +1481,19 @@ void ExtruderPlan::forceMinimalLayerTime(double minTime, double minimalSpeed, do factor = minimalSpeed / (path.config->getSpeed() * path.speed_factor); } - //Only slow down for the minimal time if that will be slower. + // Only slow down for the minimal time if that will be slower. assert(getExtrudeSpeedFactor() == 1.0); // The extrude speed factor is assumed not to be changed yet if (factor < 1.0) { setExtrudeSpeedFactor(factor); } - else + else { factor = 1.0; } - + double inv_factor = 1.0 / factor; // cause multiplication is faster than division - + // Adjust stored naive time estimates estimates.extrude_time *= inv_factor; for (GCodePath& path : paths) @@ -1493,18 +1520,18 @@ TimeMaterialEstimates ExtruderPlan::computeNaiveTimeEstimates(Point starting_pos bool is_extrusion_path = false; double* path_time_estimate; double& material_estimate = path.estimates.material; - if (!path.isTravelPath()) + if (! path.isTravelPath()) { is_extrusion_path = true; path_time_estimate = &path.estimates.extrude_time; } - else + else { if (path.retract) { path_time_estimate = &path.estimates.retracted_travel_time; } - else + else { path_time_estimate = &path.estimates.unretracted_travel_time; } @@ -1515,7 +1542,7 @@ TimeMaterialEstimates ExtruderPlan::computeNaiveTimeEstimates(Point starting_pos { retract_unretract_time = retraction_config.distance / retraction_config.speed; } - else + else { retract_unretract_time = retraction_config.distance / retraction_config.primeSpeed; } @@ -1523,7 +1550,7 @@ TimeMaterialEstimates ExtruderPlan::computeNaiveTimeEstimates(Point starting_pos path.estimates.unretracted_travel_time += 0.5 * retract_unretract_time; } } - for(Point& p1 : path.points) + for (Point& p1 : path.points) { double length = vSizeMM(p0 - p1); if (is_extrusion_path) @@ -1597,12 +1624,11 @@ void ExtruderPlan::processFanSpeedAndMinimalLayerTime(bool force_minimal_layer_t layer nr > */ - if (layer_nr < fan_speed_layer_time_settings.cool_fan_full_layer - && fan_speed_layer_time_settings.cool_fan_full_layer > 0 // don't apply initial layer fan speed speedup if disabled. - && !is_raft_layer // don't apply initial layer fan speed speedup to raft, but to model layers + if (layer_nr < fan_speed_layer_time_settings.cool_fan_full_layer && fan_speed_layer_time_settings.cool_fan_full_layer > 0 // don't apply initial layer fan speed speedup if disabled. + && ! is_raft_layer // don't apply initial layer fan speed speedup to raft, but to model layers ) { - //Slow down the fan on the layers below the [cool_fan_full_layer], where layer 0 is speed 0. + // Slow down the fan on the layers below the [cool_fan_full_layer], where layer 0 is speed 0. fan_speed = fan_speed_layer_time_settings.cool_fan_speed_0 + (fan_speed - fan_speed_layer_time_settings.cool_fan_speed_0) * std::max(LayerIndex(0), layer_nr) / fan_speed_layer_time_settings.cool_fan_full_layer; } } @@ -1614,7 +1640,7 @@ void LayerPlan::processFanSpeedAndMinimalLayerTime(Point starting_position) ExtruderPlan& extruder_plan = extruder_plans[extr_plan_idx]; bool force_minimal_layer_time = extr_plan_idx == extruder_plans.size() - 1; extruder_plan.processFanSpeedAndMinimalLayerTime(force_minimal_layer_time, starting_position); - if (!extruder_plan.paths.empty() && !extruder_plan.paths.back().points.empty()) + if (! extruder_plan.paths.empty() && ! extruder_plan.paths.back().points.empty()) { starting_position = extruder_plan.paths.back().points.back(); } @@ -1622,21 +1648,20 @@ void LayerPlan::processFanSpeedAndMinimalLayerTime(Point starting_position) } - void LayerPlan::writeGCode(GCodeExport& gcode) { Communication* communication = Application::getInstance().communication; communication->setLayerForSend(layer_nr); communication->sendCurrentPosition(gcode.getPositionXY()); gcode.setLayerNr(layer_nr); - + gcode.writeLayerComment(layer_nr); // flow-rate compensation const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; - gcode.setFlowRateExtrusionSettings(mesh_group_settings.get("flow_rate_max_extrusion_offset"), mesh_group_settings.get("flow_rate_extrusion_offset_factor")); //Offset is in mm. + gcode.setFlowRateExtrusionSettings(mesh_group_settings.get("flow_rate_max_extrusion_offset"), mesh_group_settings.get("flow_rate_extrusion_offset_factor")); // Offset is in mm. - static LayerIndex layer_1 {1 - static_cast(Raft::getTotalExtraLayers())}; + static LayerIndex layer_1{ 1 - static_cast(Raft::getTotalExtraLayers()) }; if (layer_nr == layer_1 && mesh_group_settings.get("machine_heated_bed") && mesh_group_settings.get("material_bed_temperature") != mesh_group_settings.get("material_bed_temperature_layer_0")) { constexpr bool wait = false; @@ -1654,7 +1679,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode) const bool jerk_travel_enabled = mesh_group_settings.get("jerk_travel_enabled"); std::string current_mesh = "NONMESH"; - for(size_t extruder_plan_idx = 0; extruder_plan_idx < extruder_plans.size(); extruder_plan_idx++) + for (size_t extruder_plan_idx = 0; extruder_plan_idx < extruder_plans.size(); extruder_plan_idx++) { ExtruderPlan& extruder_plan = extruder_plans[extruder_plan_idx]; const RetractionConfig& retraction_config = storage.retraction_config_per_extruder[extruder_plan.extruder_nr]; @@ -1711,7 +1736,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode) else if (layer_nr != 0 && Application::getInstance().current_slice->scene.extruders[extruder_nr].settings.get("retract_at_layer_change")) { // only do the retract if the paths are not spiralized - if (!mesh_group_settings.get("magic_spiralize")) + if (! mesh_group_settings.get("magic_spiralize")) { gcode.writeRetraction(retraction_config); } @@ -1720,19 +1745,16 @@ void LayerPlan::writeGCode(GCodeExport& gcode) gcode.writeFanCommand(extruder_plan.getFanSpeed()); std::vector& paths = extruder_plan.paths; - extruder_plan.inserts.sort([](const NozzleTempInsert& a, const NozzleTempInsert& b) -> bool - { - return a.path_idx < b.path_idx; - }); + extruder_plan.inserts.sort([](const NozzleTempInsert& a, const NozzleTempInsert& b) -> bool { return a.path_idx < b.path_idx; }); const ExtruderTrain& extruder = Application::getInstance().current_slice->scene.extruders[extruder_nr]; bool update_extrusion_offset = true; - for(unsigned int path_idx = 0; path_idx < paths.size(); path_idx++) + for (unsigned int path_idx = 0; path_idx < paths.size(); path_idx++) { extruder_plan.handleInserts(path_idx, gcode); - + GCodePath& path = paths[path_idx]; if (path.perform_prime) @@ -1741,17 +1763,17 @@ void LayerPlan::writeGCode(GCodeExport& gcode) gcode.writeRetraction(retraction_config); } - if (!path.retract && path.config->isTravelPath() && path.points.size() == 1 && path.points[0] == gcode.getPositionXY() && z == gcode.getPositionZ()) + if (! path.retract && path.config->isTravelPath() && path.points.size() == 1 && path.points[0] == gcode.getPositionXY() && z == gcode.getPositionZ()) { // ignore travel moves to the current location to avoid needless change of acceleration/jerk continue; } - //In some cases we want to find the next non-travel move. + // In some cases we want to find the next non-travel move. size_t next_extrusion_idx = path_idx + 1; - if((acceleration_enabled && !acceleration_travel_enabled) || (jerk_enabled && !jerk_travel_enabled)) + if ((acceleration_enabled && ! acceleration_travel_enabled) || (jerk_enabled && ! jerk_travel_enabled)) { - while(next_extrusion_idx < paths.size() && paths[next_extrusion_idx].config->isTravelPath()) + while (next_extrusion_idx < paths.size() && paths[next_extrusion_idx].config->isTravelPath()) { ++next_extrusion_idx; } @@ -1761,19 +1783,19 @@ void LayerPlan::writeGCode(GCodeExport& gcode) { if (path.config->isTravelPath()) { - if(acceleration_travel_enabled) + if (acceleration_travel_enabled) { gcode.writeTravelAcceleration(path.config->getAcceleration()); } else { - //Use the acceleration of the first non-travel move *after* the travel. - if(next_extrusion_idx >= paths.size()) //Only travel moves for the remainder of the layer. + // Use the acceleration of the first non-travel move *after* the travel. + if (next_extrusion_idx >= paths.size()) // Only travel moves for the remainder of the layer. { - if(static_cast(next_layer_acc_jerk)) + if (static_cast(next_layer_acc_jerk)) { gcode.writeTravelAcceleration(next_layer_acc_jerk->first); - } //If the next layer has no extruded move, just keep the old acceleration. Should be very rare to have an empty layer. + } // If the next layer has no extruded move, just keep the old acceleration. Should be very rare to have an empty layer. } else { @@ -1788,19 +1810,19 @@ void LayerPlan::writeGCode(GCodeExport& gcode) } if (jerk_enabled) { - if(jerk_travel_enabled) + if (jerk_travel_enabled) { gcode.writeJerk(path.config->getJerk()); } else { - //Use the jerk of the first non-travel move *after* the travel. - if(next_extrusion_idx >= paths.size()) //Only travel moves for the remainder of the layer. + // Use the jerk of the first non-travel move *after* the travel. + if (next_extrusion_idx >= paths.size()) // Only travel moves for the remainder of the layer. { - if(static_cast(next_layer_acc_jerk)) + if (static_cast(next_layer_acc_jerk)) { gcode.writeJerk(next_layer_acc_jerk->second); - } //If the next layer has no extruded move, just keep the old jerk. Should be very rare to have an empty layer. + } // If the next layer has no extruded move, just keep the old jerk. Should be very rare to have an empty layer. } else { @@ -1822,7 +1844,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode) gcode.writeZhopEnd(); } } - if (!path.config->isTravelPath() && last_extrusion_config != path.config) + if (! path.config->isTravelPath() && last_extrusion_config != path.config) { gcode.writeTypeComment(path.config->type); if (path.config->isBridgePath()) @@ -1842,12 +1864,12 @@ void LayerPlan::writeGCode(GCodeExport& gcode) // for some movements such as prime tower purge, the speed may get changed by this factor speed *= path.speed_factor; - //Apply the extrusion speed factor if it's an extrusion move. - if (!path.config->isTravelPath()) + // Apply the extrusion speed factor if it's an extrusion move. + if (! path.config->isTravelPath()) { speed *= extruder_plan.getExtrudeSpeedFactor(); } - //This seems to be the best location to place this, but still not ideal. + // This seems to be the best location to place this, but still not ideal. if (path.mesh_id != current_mesh) { current_mesh = path.mesh_id; @@ -1857,7 +1879,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode) } if (path.config->isTravelPath()) { // early comp for travel paths, which are handled more simply - if (!path.perform_z_hop && final_travel_z != z && extruder_plan_idx == (extruder_plans.size() - 1) && path_idx == (paths.size() - 1)) + if (! path.perform_z_hop && final_travel_z != z && extruder_plan_idx == (extruder_plans.size() - 1) && path_idx == (paths.size() - 1)) { // Before the final travel, move up to the next layer height, on the current spot, with a sensible speed. Point3 current_position = gcode.getPosition(); @@ -1867,7 +1889,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode) // Prevent the final travel(s) from resetting to the 'previous' layer height. gcode.setZ(final_travel_z); } - for(unsigned int point_idx = 0; point_idx < path.points.size() - 1; point_idx++) + for (unsigned int point_idx = 0; point_idx < path.points.size() - 1; point_idx++) { gcode.writeTravel(path.points[point_idx], speed); } @@ -1881,7 +1903,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode) } bool spiralize = path.spiralize; - if (!spiralize) // normal (extrusion) move (with coasting) + if (! spiralize) // normal (extrusion) move (with coasting) { // if path provides a valid (in range 0-100) fan speed, use it const double path_fan_speed = path.getFanSpeed(); @@ -1892,9 +1914,9 @@ void LayerPlan::writeGCode(GCodeExport& gcode) { coasting = writePathWithCoasting(gcode, extruder_plan_idx, path_idx, layer_thickness); } - if (!coasting) // not same as 'else', cause we might have changed [coasting] in the line above... + if (! coasting) // not same as 'else', cause we might have changed [coasting] in the line above... { // normal path to gcode algorithm - for(unsigned int point_idx = 0; point_idx < path.points.size(); point_idx++) + for (unsigned int point_idx = 0; point_idx < path.points.size(); point_idx++) { const double extrude_speed = speed * path.speed_back_pressure_factor; communication->sendLineTo(path.config->type, path.points[point_idx], path.getLineWidthForLayerView(), path.config->getLayerThickness(), extrude_speed); @@ -1904,10 +1926,10 @@ void LayerPlan::writeGCode(GCodeExport& gcode) } else { // SPIRALIZE - //If we need to spiralize then raise the head slowly by 1 layer as this path progresses. + // If we need to spiralize then raise the head slowly by 1 layer as this path progresses. float totalLength = 0.0; Point p0 = gcode.getPositionXY(); - for (unsigned int _path_idx = path_idx; _path_idx < paths.size() && !paths[_path_idx].isTravelPath(); _path_idx++) + for (unsigned int _path_idx = path_idx; _path_idx < paths.size() && ! paths[_path_idx].isTravelPath(); _path_idx++) { GCodePath& _path = paths[_path_idx]; for (unsigned int point_idx = 0; point_idx < _path.points.size(); point_idx++) @@ -1955,8 +1977,8 @@ void LayerPlan::writeGCode(GCodeExport& gcode) gcode.writeComment("Small layer, adding delay"); const RetractionConfig& retraction_config = storage.retraction_config_per_extruder[gcode.getExtruderNr()]; gcode.writeRetraction(retraction_config); - if (extruder_plan_idx == extruder_plans.size() - 1 || !extruder.settings.get("machine_extruder_end_pos_abs")) - { // only move the head if it's the last extruder plan; otherwise it's already at the switching bay area + if (extruder_plan_idx == extruder_plans.size() - 1 || ! extruder.settings.get("machine_extruder_end_pos_abs")) + { // only move the head if it's the last extruder plan; otherwise it's already at the switching bay area // or do it anyway when we switch extruder in-place gcode.setZ(gcode.getPositionZ() + MM2INT(3.0)); gcode.writeTravel(gcode.getPositionXY(), configs_storage.travel_config_per_extruder[extruder_nr].getSpeed()); @@ -1971,7 +1993,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode) extruder_plan.handleAllRemainingInserts(gcode); } // extruder plans /\ . - + communication->sendLayerComplete(layer_nr, z, layer_thickness); gcode.updateTotalPrintTime(); } @@ -1990,41 +2012,39 @@ bool LayerPlan::makeRetractSwitchRetract(unsigned int extruder_plan_idx, unsigne std::vector& paths = extruder_plans[extruder_plan_idx].paths; for (unsigned int path_idx2 = path_idx + 1; path_idx2 < paths.size(); path_idx2++) { - if (paths[path_idx2].getExtrusionMM3perMM() > 0) + if (paths[path_idx2].getExtrusionMM3perMM() > 0) { - return false; + return false; } } - - if (extruder_plans.size() <= extruder_plan_idx+1) + + if (extruder_plans.size() <= extruder_plan_idx + 1) { return false; // TODO: check first extruder of the next layer! (generally only on the last layer of the second extruder) } - + if (extruder_plans[extruder_plan_idx + 1].extruder_nr != extruder_plans[extruder_plan_idx].extruder_nr) { return true; } - else + else { return false; } } - + bool LayerPlan::writePathWithCoasting(GCodeExport& gcode, const size_t extruder_plan_idx, const size_t path_idx, const coord_t layer_thickness) { ExtruderPlan& extruder_plan = extruder_plans[extruder_plan_idx]; const ExtruderTrain& extruder = Application::getInstance().current_slice->scene.extruders[extruder_plan.extruder_nr]; const double coasting_volume = extruder.settings.get("coasting_volume"); if (coasting_volume <= 0) - { - return false; + { + return false; } const std::vector& paths = extruder_plan.paths; const GCodePath& path = paths[path_idx]; - if (path_idx + 1 >= paths.size() - || (path.isTravelPath() || !paths[path_idx + 1].config->isTravelPath()) - || path.points.size() < 2) + if (path_idx + 1 >= paths.size() || (path.isTravelPath() || ! paths[path_idx + 1].config->isTravelPath()) || path.points.size() < 2) { return false; } @@ -2046,7 +2066,7 @@ bool LayerPlan::writePathWithCoasting(GCodeExport& gcode, const size_t extruder_ bool length_is_less_than_min_dist = true; unsigned int acc_dist_idx_gt_coast_dist = NO_INDEX; // the index of the first point with accumulated_dist more than coasting_dist (= index into accumulated_dist_per_point) - // == the point printed BEFORE the start point for coasting + // == the point printed BEFORE the start point for coasting const Point* last = &path.points[path.points.size() - 1]; for (unsigned int backward_point_idx = 1; backward_point_idx < path.points.size(); backward_point_idx++) @@ -2055,21 +2075,21 @@ bool LayerPlan::writePathWithCoasting(GCodeExport& gcode, const size_t extruder_ const coord_t distance = vSize(point - *last); accumulated_dist += distance; accumulated_dist_per_point.push_back(accumulated_dist); - + if (acc_dist_idx_gt_coast_dist == NO_INDEX && accumulated_dist >= coasting_dist) { acc_dist_idx_gt_coast_dist = backward_point_idx; // the newly added point } - + if (accumulated_dist >= coasting_min_dist) { length_is_less_than_min_dist = false; break; } - + last = &point; } - + if (accumulated_dist < coasting_min_dist_considered) { return false; @@ -2079,11 +2099,11 @@ bool LayerPlan::writePathWithCoasting(GCodeExport& gcode, const size_t extruder_ { // in this case accumulated_dist is the length of the whole path actual_coasting_dist = accumulated_dist * coasting_dist / coasting_min_dist; - if(actual_coasting_dist == 0) //Downscaling due to Minimum Coasting Distance reduces coasting to less than 1 micron. + if (actual_coasting_dist == 0) // Downscaling due to Minimum Coasting Distance reduces coasting to less than 1 micron. { - return false; //Skip coasting at all then. + return false; // Skip coasting at all then. } - for (acc_dist_idx_gt_coast_dist = 1; acc_dist_idx_gt_coast_dist < accumulated_dist_per_point.size() ; acc_dist_idx_gt_coast_dist++) + for (acc_dist_idx_gt_coast_dist = 1; acc_dist_idx_gt_coast_dist < accumulated_dist_per_point.size(); acc_dist_idx_gt_coast_dist++) { // search for the correct coast_dist_idx if (accumulated_dist_per_point[acc_dist_idx_gt_coast_dist] >= actual_coasting_dist) { @@ -2106,7 +2126,7 @@ bool LayerPlan::writePathWithCoasting(GCodeExport& gcode, const size_t extruder_ { // write normal extrude path: Communication* communication = Application::getInstance().communication; - for(size_t point_idx = 0; point_idx <= point_idx_before_start; point_idx++) + for (size_t point_idx = 0; point_idx <= point_idx_before_start; point_idx++) { communication->sendLineTo(path.config->type, path.points[point_idx], path.getLineWidthForLayerView(), path.config->getLayerThickness(), extrude_speed); gcode.writeExtrusion(path.points[point_idx], extrude_speed, path.getExtrusionMM3perMM(), path.config->type); @@ -2129,8 +2149,7 @@ void LayerPlan::applyBackPressureCompensation() { for (auto& extruder_plan : extruder_plans) { - const Ratio back_pressure_compensation = - Application::getInstance().current_slice->scene.extruders[extruder_plan.extruder_nr].settings.get("speed_equalize_flow_width_factor"); + const Ratio back_pressure_compensation = Application::getInstance().current_slice->scene.extruders[extruder_plan.extruder_nr].settings.get("speed_equalize_flow_width_factor"); if (back_pressure_compensation != 0.0) { extruder_plan.applyBackPressureCompensation(back_pressure_compensation); @@ -2178,4 +2197,4 @@ void LayerPlan::setOverhangMask(const Polygons& polys) overhang_mask = polys; } -}//namespace cura +} // namespace cura diff --git a/src/LayerPlanBuffer.cpp b/src/LayerPlanBuffer.cpp index d5faaf8b96..192fea08dd 100644 --- a/src/LayerPlanBuffer.cpp +++ b/src/LayerPlanBuffer.cpp @@ -1,17 +1,19 @@ -//Copyright (c) 2021 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher + +#include #include "Application.h" //To flush g-code through the communication channel. #include "ExtruderTrain.h" #include "FffProcessor.h" -#include "gcodeExport.h" #include "LayerPlan.h" #include "LayerPlanBuffer.h" #include "Slice.h" #include "communication/Communication.h" //To flush g-code through the communication channel. -#include "utils/logoutput.h" +#include "gcodeExport.h" -namespace cura { +namespace cura +{ constexpr Duration LayerPlanBuffer::extra_preheat_time; @@ -60,12 +62,12 @@ LayerPlan* LayerPlanBuffer::processBuffer() void LayerPlanBuffer::flush() { - Application::getInstance().communication->flushGCode(); //If there was still g-code in a layer, flush that as a separate layer. Don't want to group them together accidentally. + Application::getInstance().communication->flushGCode(); // If there was still g-code in a layer, flush that as a separate layer. Don't want to group them together accidentally. if (buffer.size() > 0) { insertTempCommands(); // insert preheat commands of the very last layer } - while (!buffer.empty()) + while (! buffer.empty()) { buffer.front()->writeGCode(gcode); Application::getInstance().communication->flushGCode(); @@ -78,9 +80,9 @@ void LayerPlanBuffer::addConnectingTravelMove(LayerPlan* prev_layer, const Layer { std::optional> new_layer_destination_state = newest_layer->getFirstTravelDestinationState(); - if (!new_layer_destination_state) + if (! new_layer_destination_state) { - logWarning("Layer %d is empty (or it has empty extruder plans). Temperature control and cross layer travel moves might suffer!\n", newest_layer->layer_nr); + spdlog::warn("Layer {} is empty (or it has empty extruder plans). Temperature control and cross layer travel moves might suffer!", newest_layer->layer_nr); return; } @@ -90,16 +92,17 @@ void LayerPlanBuffer::addConnectingTravelMove(LayerPlan* prev_layer, const Layer assert(newest_layer->extruder_plans.front().paths[0].points[0] == first_location_new_layer); // if the last planned position in the previous layer isn't the same as the first location of the new layer, travel to the new location - if (!prev_layer->last_planned_position || *prev_layer->last_planned_position != first_location_new_layer) + if (! prev_layer->last_planned_position || *prev_layer->last_planned_position != first_location_new_layer) { const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; const Settings& extruder_settings = Application::getInstance().current_slice->scene.extruders[prev_layer->extruder_plans.back().extruder_nr].settings; prev_layer->setIsInside(new_layer_destination_state->second); - const bool force_retract = extruder_settings.get("retract_at_layer_change") || - (mesh_group_settings.get("travel_retract_before_outer_wall") && (mesh_group_settings.get("inset_direction") == InsetDirection::OUTSIDE_IN || mesh_group_settings.get("wall_line_count") == 1)); //Moving towards an outer wall. + const bool force_retract = extruder_settings.get("retract_at_layer_change") + || (mesh_group_settings.get("travel_retract_before_outer_wall") + && (mesh_group_settings.get("inset_direction") == InsetDirection::OUTSIDE_IN || mesh_group_settings.get("wall_line_count") == 1)); // Moving towards an outer wall. prev_layer->final_travel_z = newest_layer->z; - GCodePath &path = prev_layer->addTravel(first_location_new_layer, force_retract); - if (force_retract && !path.retract) + GCodePath& path = prev_layer->addTravel(first_location_new_layer, force_retract); + if (force_retract && ! path.retract) { // addTravel() won't use retraction if the travel distance is less than retraction minimum travel setting // so to avoid blobs when moving to the new layer height, which can occur if the z-axis speed is very slow, @@ -108,7 +111,7 @@ void LayerPlanBuffer::addConnectingTravelMove(LayerPlan* prev_layer, const Layer } } - //If not using travel-specific jerk and acceleration, the layer plan needs to know the jerk/acc of the first extrusion move of the next layer. + // If not using travel-specific jerk and acceleration, the layer plan needs to know the jerk/acc of the first extrusion move of the next layer. prev_layer->next_layer_acc_jerk = newest_layer->first_extrusion_acc_jerk; } @@ -135,7 +138,7 @@ void LayerPlanBuffer::processFanSpeedLayerTime() void LayerPlanBuffer::insertPreheatCommand(ExtruderPlan& extruder_plan_before, const Duration time_after_extruder_plan_start, const size_t extruder_nr, const Temperature temp) { Duration acc_time = 0.0; - for (unsigned int path_idx = extruder_plan_before.paths.size() - 1; int(path_idx) != -1 ; path_idx--) + for (unsigned int path_idx = extruder_plan_before.paths.size() - 1; int(path_idx) != -1; path_idx--) { GCodePath& path = extruder_plan_before.paths[path_idx]; const Duration time_this_path = path.estimates.getTotalTime(); @@ -196,7 +199,7 @@ Preheat::WarmUpResult LayerPlanBuffer::computeStandbyTempPlan(std::vectorscene.extruders[extruder_nr].settings.get("machine_nozzle_temp_enabled")) + if (! Application::getInstance().current_slice->scene.extruders[extruder_nr].settings.get("machine_nozzle_temp_enabled")) { return; } @@ -222,7 +225,7 @@ void LayerPlanBuffer::handleStandbyTemp(std::vector& extruder_pla return; } } - logWarning("Warning: Couldn't find previous extruder plan so as to set the standby temperature. Inserting temp command in earliest available layer.\n"); + spdlog::warn("Couldn't find previous extruder plan so as to set the standby temperature. Inserting temp command in earliest available layer."); ExtruderPlan& earliest_extruder_plan = *extruder_plans[0]; constexpr bool wait = false; earliest_extruder_plan.insertCommand(0, extruder, standby_temp, wait); @@ -233,12 +236,12 @@ void LayerPlanBuffer::insertPreheatCommand_multiExtrusion(std::vectorscene.extruders[extruder].settings; - if (!extruder_settings.get("machine_nozzle_temp_enabled")) + if (! extruder_settings.get("machine_nozzle_temp_enabled")) { return; } double initial_print_temp = extruder_plan.required_start_temperature; - + Preheat::WarmUpResult heating_time_and_from_temp = computeStandbyTempPlan(extruder_plans, extruder_plan_idx); if (heating_time_and_from_temp.total_time_window < extruder_settings.get("machine_min_cool_heat_time_window")) @@ -256,7 +259,7 @@ void LayerPlanBuffer::insertPreheatCommand_multiExtrusion(std::vector= 0; extruder_plan_before_idx--) { ExtruderPlan& extruder_plan_before = *extruder_plans[extruder_plan_before_idx]; - assert (extruder_plan_before.extruder_nr != extruder); + assert(extruder_plan_before.extruder_nr != extruder); double time_here = extruder_plan_before.estimates.getTotalTime(); if (time_here >= time_before_extruder_plan_to_insert) @@ -274,7 +277,7 @@ void LayerPlanBuffer::insertPreheatCommand_multiExtrusion(std::vector& extruder_plans, unsigned int extruder_plan_idx) -{ +{ ExtruderPlan& extruder_plan = *extruder_plans[extruder_plan_idx]; const size_t extruder = extruder_plan.extruder_nr; @@ -287,7 +290,7 @@ void LayerPlanBuffer::insertTempCommands(std::vector& extruder_pl const Settings& previous_extruder_settings = Application::getInstance().current_slice->scene.extruders[prev_extruder].settings; extruder_plan.prev_extruder_standby_temp = previous_extruder_settings.get("material_standby_temperature"); } - + if (prev_extruder == extruder) { insertPreheatCommand_singleExtrusion(*prev_extruder_plan, extruder, extruder_plan.required_start_temperature); @@ -308,16 +311,16 @@ void LayerPlanBuffer::insertTempCommands(std::vector& extruder_pl void LayerPlanBuffer::insertPrintTempCommand(ExtruderPlan& extruder_plan) { - if (!extruder_plan.extrusion_temperature) + if (! extruder_plan.extrusion_temperature) { - logWarning("Empty extruder plan detected! Discarding extrusion temperature command.\n"); + spdlog::warn("Empty extruder plan detected! Discarding extrusion temperature command."); return; } const double print_temp = *extruder_plan.extrusion_temperature; const unsigned int extruder = extruder_plan.extruder_nr; const Settings& extruder_settings = Application::getInstance().current_slice->scene.extruders[extruder].settings; - if (!extruder_settings.get("machine_nozzle_temp_enabled")) + if (! extruder_settings.get("machine_nozzle_temp_enabled")) { return; } @@ -330,7 +333,7 @@ void LayerPlanBuffer::insertPrintTempCommand(ExtruderPlan& extruder_plan) { GCodePath& path = extruder_plan.paths[path_idx]; heated_pre_travel_time += path.estimates.getTotalTime(); - if (!path.isTravelPath()) + if (! path.isTravelPath()) { break; } @@ -346,7 +349,7 @@ void LayerPlanBuffer::insertFinalPrintTempCommand(std::vector& ex ExtruderPlan& last_extruder_plan = *extruder_plans[last_extruder_plan_idx]; const size_t extruder = last_extruder_plan.extruder_nr; const Settings& extruder_settings = Application::getInstance().current_slice->scene.extruders[extruder].settings; - if (!extruder_settings.get("machine_nozzle_temp_enabled")) + if (! extruder_settings.get("machine_nozzle_temp_enabled")) { return; } @@ -363,7 +366,7 @@ void LayerPlanBuffer::insertFinalPrintTempCommand(std::vector& ex for (path_idx = last_extruder_plan.paths.size() - 1; int(path_idx) >= 0; path_idx--) { GCodePath& path = last_extruder_plan.paths[path_idx]; - if (!path.isTravelPath()) + if (! path.isTravelPath()) { break; } @@ -371,7 +374,8 @@ void LayerPlanBuffer::insertFinalPrintTempCommand(std::vector& ex } } - double time_window = 0; // The time window within which the nozzle needs to heat from the initial print temp to the printing temperature and then back to the final print temp; i.e. from the first to the last extrusion move with this extruder + double time_window = + 0; // The time window within which the nozzle needs to heat from the initial print temp to the printing temperature and then back to the final print temp; i.e. from the first to the last extrusion move with this extruder double weighted_average_extrusion_temp = 0; // The average of the normal extrusion temperatures of the extruder plans (which might be different due to flow dependent temp or due to initial layer temp) Weighted by time std::optional initial_print_temp; // The initial print temp of the first extruder plan with this extruder { // compute time window and print temp statistics @@ -393,9 +397,9 @@ void LayerPlanBuffer::insertFinalPrintTempCommand(std::vector& ex initial_print_temp = prev_extruder_plan.required_start_temperature; } } - if (time_window <= 0.0) //There was a move in this plan but it was length 0. + if (time_window <= 0.0) // There was a move in this plan but it was length 0. { - logWarning("Unnecessary extruder switch detected! SliceDataStorage::getExtrudersUsed should probably be updated.\n"); + spdlog::warn("Unnecessary extruder switch detected! SliceDataStorage::getExtrudersUsed should probably be updated."); return; } weighted_average_extrusion_temp /= time_window; @@ -403,9 +407,9 @@ void LayerPlanBuffer::insertFinalPrintTempCommand(std::vector& ex assert(heated_pre_travel_time != -1 && "heated_pre_travel_time must have been computed; there must have been an extruder plan!"); } - if (!initial_print_temp) + if (! initial_print_temp) { // none of the extruder plans had unretracted moves - logWarning("Unnecessary extruder switch detected! Discarding final print temperature commands.\n"); + spdlog::warn("Unnecessary extruder switch detected! Discarding final print temperature commands."); return; } @@ -503,9 +507,9 @@ void LayerPlanBuffer::insertTempCommands() else { assert(extruder_plan.estimates.getMaterial() == 0.0 && "No extrusion time should mean no material usage!"); - if (extruder_settings.get("material_flow_dependent_temperature")) //Average flow is only used with flow dependent temperature. + if (extruder_settings.get("material_flow_dependent_temperature")) // Average flow is only used with flow dependent temperature. { - logWarning("Empty extruder plans detected! Temperature control might suffer.\n"); + spdlog::warn("Empty extruder plans detected! Temperature control might suffer."); } avg_flow = 0.0; } @@ -514,8 +518,8 @@ void LayerPlanBuffer::insertTempCommands() const Temperature initial_print_temp = extruder_settings.get("material_initial_print_temperature"); if (initial_print_temp == 0.0 // user doesn't want to use initial print temp feature || extruder_settings.get("machine_extruders_share_heater") // ignore initial print temps when extruders share a heater - || !extruder_used_in_meshgroup[extruder] // prime blob uses print temp rather than initial print temp - || (overall_extruder_plan_idx > 0 && extruder_plans[overall_extruder_plan_idx - 1]->extruder_nr == extruder // prev plan has same extruder .. + || ! extruder_used_in_meshgroup[extruder] // prime blob uses print temp rather than initial print temp + || (overall_extruder_plan_idx > 0 && extruder_plans[overall_extruder_plan_idx - 1]->extruder_nr == extruder // prev plan has same extruder .. && extruder_plans[overall_extruder_plan_idx - 1]->estimates.getTotalUnretractedTime() > 0.0) // and prev extruder plan already heated to printing temperature ) { @@ -535,7 +539,7 @@ void LayerPlanBuffer::insertTempCommands() for (size_t extruder_idx = 0; extruder_idx < scene.extruders.size(); extruder_idx++) { // set temperature of the first nozzle, turn other nozzles down const Settings& other_extruder_settings = Application::getInstance().current_slice->scene.extruders[extruder_idx].settings; - if (scene.current_mesh_group == scene.mesh_groups.begin()) //First mesh group. + if (scene.current_mesh_group == scene.mesh_groups.begin()) // First mesh group. { // override values from GCodeExport::setInitialTemps // the first used extruder should be set to the required temp in the start gcode @@ -544,7 +548,7 @@ void LayerPlanBuffer::insertTempCommands() { gcode.setInitialTemp(extruder_idx, extruder_plan.extrusion_temperature.value_or(extruder_plan.required_start_temperature)); } - else + else { gcode.setInitialTemp(extruder_idx, other_extruder_settings.get("material_standby_temperature")); } diff --git a/src/MeshGroup.cpp b/src/MeshGroup.cpp index ad31d7e0a2..68a6a1b68d 100644 --- a/src/MeshGroup.cpp +++ b/src/MeshGroup.cpp @@ -1,16 +1,17 @@ -//Copyright (C) 2020 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher -#include -#include #include +#include +#include + +#include #include "MeshGroup.h" #include "settings/types/Ratio.h" //For the shrinkage percentage and scale factor. -#include "utils/floatpoint.h" //To accept incoming meshes with floating point vertices. #include "utils/FMatrix4x3.h" //To transform the input meshes for shrinkage compensation and to align in command line mode. +#include "utils/floatpoint.h" //To accept incoming meshes with floating point vertices. #include "utils/gettime.h" -#include "utils/logoutput.h" #include "utils/string.h" namespace cura @@ -21,7 +22,7 @@ FILE* binaryMeshBlob = nullptr; /* Custom fgets function to support Mac line-ends in Ascii STL files. OpenSCAD produces this when used on Mac */ void* fgets_(char* ptr, size_t len, FILE* f) { - while(len && fread(ptr, 1, 1, f) > 0) + while (len && fread(ptr, 1, 1, f) > 0) { if (*ptr == '\n' || *ptr == '\r') { @@ -43,7 +44,7 @@ Point3 MeshGroup::min() const Point3 ret(std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()); for (const Mesh& mesh : meshes) { - if (mesh.settings.get("infill_mesh") || mesh.settings.get("cutting_mesh") || mesh.settings.get("anti_overhang_mesh")) //Don't count pieces that are not printed. + if (mesh.settings.get("infill_mesh") || mesh.settings.get("cutting_mesh") || mesh.settings.get("anti_overhang_mesh")) // Don't count pieces that are not printed. { continue; } @@ -64,7 +65,7 @@ Point3 MeshGroup::max() const Point3 ret(std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min()); for (const Mesh& mesh : meshes) { - if (mesh.settings.get("infill_mesh") || mesh.settings.get("cutting_mesh") || mesh.settings.get("anti_overhang_mesh")) //Don't count pieces that are not printed. + if (mesh.settings.get("infill_mesh") || mesh.settings.get("cutting_mesh") || mesh.settings.get("anti_overhang_mesh")) // Don't count pieces that are not printed. { continue; } @@ -78,7 +79,7 @@ Point3 MeshGroup::max() const void MeshGroup::clear() { - for(Mesh& m : meshes) + for (Mesh& m : meshes) { m.clear(); } @@ -86,16 +87,16 @@ void MeshGroup::clear() void MeshGroup::finalize() { - //If the machine settings have been supplied, offset the given position vertices to the center of vertices (0,0,0) is at the bed center. + // If the machine settings have been supplied, offset the given position vertices to the center of vertices (0,0,0) is at the bed center. Point3 meshgroup_offset(0, 0, 0); - if (!settings.get("machine_center_is_zero")) + if (! settings.get("machine_center_is_zero")) { meshgroup_offset.x = settings.get("machine_width") / 2; meshgroup_offset.y = settings.get("machine_depth") / 2; } - - // If a mesh position was given, put the mesh at this position in 3D space. - for(Mesh& mesh : meshes) + + // If a mesh position was given, put the mesh at this position in 3D space. + for (Mesh& mesh : meshes) { Point3 mesh_offset(mesh.settings.get("mesh_position_x"), mesh.settings.get("mesh_position_y"), mesh.settings.get("mesh_position_z")); if (mesh.settings.get("center_object")) @@ -107,7 +108,7 @@ void MeshGroup::finalize() } mesh.offset(mesh_offset + meshgroup_offset); } - scaleFromBottom(settings.get("material_shrinkage_percentage_xy"), settings.get("material_shrinkage_percentage_z")); //Compensate for the shrinkage of the material. + scaleFromBottom(settings.get("material_shrinkage_percentage_xy"), settings.get("material_shrinkage_percentage_z")); // Compensate for the shrinkage of the material. } void MeshGroup::scaleFromBottom(const Ratio factor_xy, const Ratio factor_z) @@ -116,7 +117,7 @@ void MeshGroup::scaleFromBottom(const Ratio factor_xy, const Ratio factor_z) const Point3 origin(center.x, center.y, 0); const FMatrix4x3 transformation = FMatrix4x3::scale(factor_xy, factor_xy, factor_z, origin); - for(Mesh& mesh : meshes) + for (Mesh& mesh : meshes) { mesh.transform(transformation); } @@ -128,13 +129,13 @@ bool loadMeshSTL_ascii(Mesh* mesh, const char* filename, const FMatrix4x3& matri char buffer[1024]; FPoint3 vertex; int n = 0; - Point3 v0(0,0,0), v1(0,0,0), v2(0,0,0); - while(fgets_(buffer, sizeof(buffer), f)) + Point3 v0(0, 0, 0), v1(0, 0, 0), v2(0, 0, 0); + while (fgets_(buffer, sizeof(buffer), f)) { if (sscanf(buffer, " vertex %f %f %f", &vertex.x, &vertex.y, &vertex.z) == 3) { n++; - switch(n) + switch (n) { case 1: v0 = matrix.apply(vertex); @@ -160,12 +161,12 @@ bool loadMeshSTL_binary(Mesh* mesh, const char* filename, const FMatrix4x3& matr FILE* f = fopen(filename, "rb"); fseek(f, 0L, SEEK_END); - long long file_size = ftell(f); //The file size is the position of the cursor after seeking to the end. - rewind(f); //Seek back to start. - size_t face_count = (file_size - 80 - sizeof(uint32_t)) / 50; //Subtract the size of the header. Every face uses exactly 50 bytes. + long long file_size = ftell(f); // The file size is the position of the cursor after seeking to the end. + rewind(f); // Seek back to start. + size_t face_count = (file_size - 80 - sizeof(uint32_t)) / 50; // Subtract the size of the header. Every face uses exactly 50 bytes. char buffer[80]; - //Skip the header + // Skip the header if (fread(buffer, 80, 1, f) != 1) { fclose(f); @@ -173,7 +174,7 @@ bool loadMeshSTL_binary(Mesh* mesh, const char* filename, const FMatrix4x3& matr } uint32_t reported_face_count; - //Read the face count. We'll use it as a sort of redundancy code to check for file corruption. + // Read the face count. We'll use it as a sort of redundancy code to check for file corruption. if (fread(&reported_face_count, sizeof(uint32_t), 1, f) != 1) { fclose(f); @@ -181,12 +182,12 @@ bool loadMeshSTL_binary(Mesh* mesh, const char* filename, const FMatrix4x3& matr } if (reported_face_count != face_count) { - logWarning("Face count reported by file (%s) is not equal to actual face count (%s). File could be corrupt!\n", std::to_string(reported_face_count).c_str(), std::to_string(face_count).c_str()); + spdlog::warn("Face count reported by file ({}) is not equal to actual face count ({}). File could be corrupt!", reported_face_count, face_count); } - //For each face read: - //float(x,y,z) = normal, float(X,Y,Z)*3 = vertexes, uint16_t = flags - // Every Face is 50 Bytes: Normal(3*float), Vertices(9*float), 2 Bytes Spacer + // For each face read: + // float(x,y,z) = normal, float(X,Y,Z)*3 = vertexes, uint16_t = flags + // Every Face is 50 Bytes: Normal(3*float), Vertices(9*float), 2 Bytes Spacer mesh->faces.reserve(face_count); mesh->vertices.reserve(face_count); for (unsigned int i = 0; i < face_count; i++) @@ -196,7 +197,7 @@ bool loadMeshSTL_binary(Mesh* mesh, const char* filename, const FMatrix4x3& matr fclose(f); return false; } - float *v= ((float*)buffer)+3; + float* v = ((float*)buffer) + 3; Point3 v0 = matrix.apply(FPoint3(v[0], v[1], v[2])); Point3 v1 = matrix.apply(FPoint3(v[3], v[4], v[5])); @@ -215,19 +216,19 @@ bool loadMeshSTL(Mesh* mesh, const char* filename, const FMatrix4x3& matrix) { return false; } - - //assign filename to mesh_name + + // assign filename to mesh_name mesh->mesh_name = filename; - - //Skip any whitespace at the beginning of the file. - unsigned long long num_whitespace = 0; //Number of whitespace characters. + + // Skip any whitespace at the beginning of the file. + unsigned long long num_whitespace = 0; // Number of whitespace characters. unsigned char whitespace; if (fread(&whitespace, 1, 1, f) != 1) { fclose(f); return false; } - while(isspace(whitespace)) + while (isspace(whitespace)) { num_whitespace++; if (fread(&whitespace, 1, 1, f) != 1) @@ -236,7 +237,7 @@ bool loadMeshSTL(Mesh* mesh, const char* filename, const FMatrix4x3& matrix) return false; } } - fseek(f, num_whitespace, SEEK_SET); //Seek to the place after all whitespace (we may have just read too far). + fseek(f, num_whitespace, SEEK_SET); // Seek to the place after all whitespace (we may have just read too far). char buffer[6]; if (fread(buffer, 5, 1, f) != 1) @@ -250,7 +251,7 @@ bool loadMeshSTL(Mesh* mesh, const char* filename, const FMatrix4x3& matrix) if (stringcasecompare(buffer, "solid") == 0) { bool load_success = loadMeshSTL_ascii(mesh, filename, matrix); - if (!load_success) + if (! load_success) return false; // This logic is used to handle the case where the file starts with @@ -273,15 +274,15 @@ bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, const FMa if (ext && (strcmp(ext, ".stl") == 0 || strcmp(ext, ".STL") == 0)) { Mesh mesh(object_parent_settings); - if (loadMeshSTL(&mesh, filename, transformation)) //Load it! If successful... + if (loadMeshSTL(&mesh, filename, transformation)) // Load it! If successful... { meshgroup->meshes.push_back(mesh); - log("loading '%s' took %.3f seconds\n", filename, load_timer.restart()); + spdlog::info("loading '{}' took {:3} seconds", filename, load_timer.restart()); return true; } } - logWarning("Unable to recognize the extension of the file. Currently only .stl and .STL are supported."); + spdlog::warn("Unable to recognize the extension of the file. Currently only .stl and .STL are supported."); return false; } -}//namespace cura +} // namespace cura diff --git a/src/Preheat.cpp b/src/Preheat.cpp index 83b0bb61d4..1907ec26f9 100644 --- a/src/Preheat.cpp +++ b/src/Preheat.cpp @@ -1,5 +1,7 @@ -//Copyright (c) 2018 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher + +#include #include "Application.h" //To get settings. #include "ExtruderTrain.h" @@ -7,9 +9,8 @@ #include "Slice.h" #include "settings/FlowTempGraph.h" #include "settings/types/Ratio.h" -#include "utils/logoutput.h" -namespace cura +namespace cura { Duration Preheat::getTimeToGoFromTempToTemp(const size_t extruder, const Temperature& temp_before, const Temperature& temp_after, const bool during_printing) @@ -104,7 +105,7 @@ Preheat::WarmUpResult Preheat::getWarmUpPointAfterCoolDown(double time_window, u result.heating_time += time_to_heat_from_standby_to_print_temp; result.lowest_temperature = temp_mid; } - else + else { result.heating_time += limited_time_window * time_to_heatup_1_degree / (time_to_cooldown_1_degree + time_to_heatup_1_degree); result.lowest_temperature = std::max(temp_mid, temp_end - result.heating_time / time_to_heatup_1_degree); @@ -112,7 +113,7 @@ Preheat::WarmUpResult Preheat::getWarmUpPointAfterCoolDown(double time_window, u if (result.heating_time > time_window || result.heating_time < 0.0) { - logWarning("getWarmUpPointAfterCoolDown returns result outside of the time window!"); + spdlog::warn("getWarmUpPointAfterCoolDown returns result outside of the time window!"); } return result; } @@ -176,7 +177,7 @@ Preheat::CoolDownResult Preheat::getCoolDownPointAfterWarmUp(double time_window, result.cooling_time += cool_down_time; result.highest_temperature = temp_mid; } - else + else { result.cooling_time += limited_time_window * time_to_heatup_1_degree / (time_to_cooldown_1_degree + time_to_heatup_1_degree); result.highest_temperature = std::min(temp_mid, temp_end + result.cooling_time / time_to_cooldown_1_degree); @@ -184,9 +185,9 @@ Preheat::CoolDownResult Preheat::getCoolDownPointAfterWarmUp(double time_window, if (result.cooling_time > time_window || result.cooling_time < 0.0) { - logWarning("getCoolDownPointAfterWarmUp returns result outside of the time window!"); + spdlog::warn("getCoolDownPointAfterWarmUp returns result outside of the time window!"); } return result; } -}//namespace cura +} // namespace cura diff --git a/src/Scene.cpp b/src/Scene.cpp index fd6d58d1b0..558a18bb4b 100644 --- a/src/Scene.cpp +++ b/src/Scene.cpp @@ -1,22 +1,21 @@ -//Copyright (c) 2019 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher + +#include #include "Application.h" #include "FffProcessor.h" //To start a slice. #include "Scene.h" -#include "sliceDataStorage.h" #include "Weaver.h" #include "Wireframe2gcode.h" #include "communication/Communication.h" //To flush g-code and layer view when we're done. #include "progress/Progress.h" -#include "utils/logoutput.h" +#include "sliceDataStorage.h" namespace cura { -Scene::Scene(const size_t num_mesh_groups) -: mesh_groups(num_mesh_groups) -, current_mesh_group(mesh_groups.begin()) +Scene::Scene(const size_t num_mesh_groups) : mesh_groups(num_mesh_groups), current_mesh_group(mesh_groups.begin()) { for (MeshGroup& mesh_group : mesh_groups) { @@ -27,9 +26,9 @@ Scene::Scene(const size_t num_mesh_groups) const std::string Scene::getAllSettingsString() const { std::stringstream output; - output << settings.getAllSettingsString(); //Global settings. + output << settings.getAllSettingsString(); // Global settings. - //Per-extruder settings. + // Per-extruder settings. for (size_t extruder_nr = 0; extruder_nr < extruders.size(); extruder_nr++) { output << " -e" << extruder_nr << extruders[extruder_nr].settings.getAllSettingsString(); @@ -46,11 +45,11 @@ const std::string Scene::getAllSettingsString() const output << " --next"; } - //Per-mesh-group settings. + // Per-mesh-group settings. const MeshGroup& mesh_group = mesh_groups[mesh_group_index]; output << mesh_group.settings.getAllSettingsString(); - //Per-object settings. + // Per-object settings. for (size_t mesh_index = 0; mesh_index < mesh_group.meshes.size(); mesh_index++) { const Mesh& mesh = mesh_group.meshes[mesh_index]; @@ -72,7 +71,7 @@ void Scene::processMeshGroup(MeshGroup& mesh_group) bool empty = true; for (Mesh& mesh : mesh_group.meshes) { - if (!mesh.settings.get("infill_mesh") && !mesh.settings.get("anti_overhang_mesh")) + if (! mesh.settings.get("infill_mesh") && ! mesh.settings.get("anti_overhang_mesh")) { empty = false; break; @@ -81,31 +80,31 @@ void Scene::processMeshGroup(MeshGroup& mesh_group) if (empty) { Progress::messageProgress(Progress::Stage::FINISH, 1, 1); // 100% on this meshgroup - log("Total time elapsed %5.2fs.\n", time_keeper_total.restart()); + spdlog::info("Total time elapsed {:3}s.", time_keeper_total.restart()); return; } if (mesh_group.settings.get("wireframe_enabled")) { - log("Starting Neith Weaver...\n"); + spdlog::info("Starting Neith Weaver..."); Weaver weaver; weaver.weave(&mesh_group); - - log("Starting Neith Gcode generation...\n"); + + spdlog::info("Starting Neith Gcode generation..."); Wireframe2gcode gcoder(weaver, fff_processor->gcode_writer.gcode); gcoder.writeGCode(); - log("Finished Neith Gcode generation...\n"); + spdlog::info("Finished Neith Gcode generation..."); } - else //Normal operation (not wireframe). + else // Normal operation (not wireframe). { SliceDataStorage storage; - if (!fff_processor->polygon_generator.generateAreas(storage, &mesh_group, fff_processor->time_keeper)) + if (! fff_processor->polygon_generator.generateAreas(storage, &mesh_group, fff_processor->time_keeper)) { return; } - + Progress::messageProgressStage(Progress::Stage::EXPORT, &fff_processor->time_keeper); fff_processor->gcode_writer.writeGCode(storage, fff_processor->time_keeper); } @@ -113,7 +112,7 @@ void Scene::processMeshGroup(MeshGroup& mesh_group) Progress::messageProgress(Progress::Stage::FINISH, 1, 1); // 100% on this meshgroup Application::getInstance().communication->flushGCode(); Application::getInstance().communication->sendOptimizedLayerData(); - log("Total time elapsed %5.2fs.\n", time_keeper_total.restart()); + spdlog::info("Total time elapsed {:3}s.\n", time_keeper_total.restart()); } -} //namespace cura \ No newline at end of file +} // namespace cura \ No newline at end of file diff --git a/src/SkeletalTrapezoidation.cpp b/src/SkeletalTrapezoidation.cpp index 13462c18c1..cbd549400f 100644 --- a/src/SkeletalTrapezoidation.cpp +++ b/src/SkeletalTrapezoidation.cpp @@ -1,15 +1,16 @@ -//Copyright (c) 2021 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include "SkeletalTrapezoidation.h" -#include +#include + +#include "settings/types/Ratio.h" #include -#include -#include #include -#include -#include "settings/types/Ratio.h" +#include +#include +#include #include "BoostInterface.hpp" @@ -19,7 +20,7 @@ #include "utils/macros.h" -#define SKELETAL_TRAPEZOIDATION_BEAD_SEARCH_MAX 1000 //A limit to how long it'll keep searching for adjacent beads. Increasing will re-use beadings more often (saving performance), but search longer for beading (costing performance). +#define SKELETAL_TRAPEZOIDATION_BEAD_SEARCH_MAX 1000 // A limit to how long it'll keep searching for adjacent beads. Increasing will re-use beadings more often (saving performance), but search longer for beading (costing performance). namespace cura { @@ -50,12 +51,12 @@ void SkeletalTrapezoidation::transferEdge(Point from, Point to, vd_t::edge_type& auto end_node_it = vd_node_to_he_node.find(vd_edge.vertex1()); assert(end_node_it != vd_node_to_he_node.end()); node_t* end_node = end_node_it->second; - for (edge_t* twin = source_twin; ;twin = twin->prev->twin->prev) + for (edge_t* twin = source_twin;; twin = twin->prev->twin->prev) { - if(!twin) + if (! twin) { - RUN_ONCE(logWarning("Encountered a voronoi edge without twin.")); - continue; //Prevent reading unallocated memory. + spdlog::warn("Encountered a voronoi edge without twin."); + continue; // Prevent reading unallocated memory. } assert(twin); graph.edges.emplace_front(SkeletalTrapezoidationEdge()); @@ -65,7 +66,7 @@ void SkeletalTrapezoidation::transferEdge(Point from, Point to, vd_t::edge_type& edge->twin = twin; twin->twin = edge; edge->from->incident_edge = edge; - + if (prev_edge) { edge->prev = prev_edge; @@ -78,17 +79,17 @@ void SkeletalTrapezoidation::transferEdge(Point from, Point to, vd_t::edge_type& { return; } - - if (!twin->prev || !twin->prev->twin || !twin->prev->twin->prev) + + if (! twin->prev || ! twin->prev->twin || ! twin->prev->twin->prev) { - RUN_ONCE(logError("Discretized segment behaves oddly!\n")); + spdlog::error("Discretized segment behaves oddly!"); return; } - + assert(twin->prev); // Forth rib assert(twin->prev->twin); // Back rib assert(twin->prev->twin->prev); // Prev segment along parabola - + constexpr bool is_not_next_to_start_or_end = false; // Only ribs at the end of a cell should be skipped graph.makeRib(prev_edge, start_source_point, end_source_point, is_not_next_to_start_or_end); } @@ -98,17 +99,17 @@ void SkeletalTrapezoidation::transferEdge(Point from, Point to, vd_t::edge_type& { std::vector discretized = discretize(vd_edge, points, segments); assert(discretized.size() >= 2); - if(discretized.size() < 2) + if (discretized.size() < 2) { - RUN_ONCE(logWarning("Discretized Voronoi edge is degenerate.")); + spdlog::warn("Discretized Voronoi edge is degenerate."); } - - assert(!prev_edge || prev_edge->to); - if(prev_edge && !prev_edge->to) + + assert(! prev_edge || prev_edge->to); + if (prev_edge && ! prev_edge->to) { - RUN_ONCE(logWarning("Previous edge doesn't go anywhere.")); + spdlog::warn("Previous edge doesn't go anywhere."); } - node_t* v0 = (prev_edge)? prev_edge->to : &makeNode(*vd_edge.vertex0(), from); // TODO: investigate whether boost:voronoi can produce multiple verts and violates consistency + node_t* v0 = (prev_edge) ? prev_edge->to : &makeNode(*vd_edge.vertex0(), from); // TODO: investigate whether boost:voronoi can produce multiple verts and violates consistency Point p0 = discretized.front(); for (size_t p1_idx = 1; p1_idx < discretized.size(); p1_idx++) { @@ -129,17 +130,17 @@ void SkeletalTrapezoidation::transferEdge(Point from, Point to, vd_t::edge_type& edge->from = v0; edge->to = v1; edge->from->incident_edge = edge; - + if (prev_edge) { edge->prev = prev_edge; prev_edge->next = edge; } - + prev_edge = edge; p0 = p1; v0 = v1; - + if (p1_idx < discretized.size() - 1) { // Rib for last segment gets introduced outside this function! constexpr bool is_not_next_to_start_or_end = false; // Only ribs at the end of a cell should be skipped @@ -161,20 +162,20 @@ std::vector SkeletalTrapezoidation::discretize(const vd_t::edge_type& vd_ const vd_t::cell_type* right_cell = vd_edge.twin()->cell(); Point start = VoronoiUtils::p(vd_edge.vertex0()); Point end = VoronoiUtils::p(vd_edge.vertex1()); - + bool point_left = left_cell->contains_point(); bool point_right = right_cell->contains_point(); - if ((!point_left && !point_right) || vd_edge.is_secondary()) // Source vert is directly connected to source segment + if ((! point_left && ! point_right) || vd_edge.is_secondary()) // Source vert is directly connected to source segment { return std::vector({ start, end }); } - else if (point_left != point_right) //This is a parabolic edge between a point and a line. + else if (point_left != point_right) // This is a parabolic edge between a point and a line. { Point p = VoronoiUtils::getSourcePoint(*(point_left ? left_cell : right_cell), points, segments); const Segment& s = VoronoiUtils::getSourceSegment(*(point_left ? right_cell : left_cell), points, segments); return VoronoiUtils::discretizeParabola(p, s, start, end, discretization_step_size, transitioning_angle); } - else //This is a straight edge between two points. + else // This is a straight edge between two points. { /*While the edge is straight, it is still discretized since the part becomes narrower between the two points. As such it may need different @@ -186,42 +187,42 @@ std::vector SkeletalTrapezoidation::discretize(const vd_t::edge_type& vd_ Point x_axis_dir = turn90CCW(right_point - left_point); coord_t x_axis_length = vSize(x_axis_dir); - const auto projected_x = [x_axis_dir, x_axis_length, middle](Point from) //Project a point on the edge. + const auto projected_x = [x_axis_dir, x_axis_length, middle](Point from) // Project a point on the edge. { Point vec = from - middle; coord_t x = dot(vec, x_axis_dir) / x_axis_length; return x; }; - + coord_t start_x = projected_x(start); coord_t end_x = projected_x(end); - //Part of the edge will be bound to the markings on the endpoints of the edge. Calculate how far that is. + // Part of the edge will be bound to the markings on the endpoints of the edge. Calculate how far that is. float bound = 0.5 / tan((M_PI - transitioning_angle) * 0.5); - coord_t marking_start_x = - d * bound; + coord_t marking_start_x = -d * bound; coord_t marking_end_x = d * bound; Point marking_start = middle + x_axis_dir * marking_start_x / x_axis_length; Point marking_end = middle + x_axis_dir * marking_end_x / x_axis_length; int direction = 1; - - if (start_x > end_x) //Oops, the Voronoi edge is the other way around. + + if (start_x > end_x) // Oops, the Voronoi edge is the other way around. { direction = -1; std::swap(marking_start, marking_end); std::swap(marking_start_x, marking_end_x); } - //Start generating points along the edge. + // Start generating points along the edge. Point a = start; Point b = end; std::vector ret; ret.emplace_back(a); - //Introduce an extra edge at the borders of the markings? + // Introduce an extra edge at the borders of the markings? bool add_marking_start = marking_start_x * direction > start_x * direction; bool add_marking_end = marking_end_x * direction > start_x * direction; - //The edge's length may not be divisible by the step size, so calculate an integer step count and evenly distribute the vertices among those. + // The edge's length may not be divisible by the step size, so calculate an integer step count and evenly distribute the vertices among those. Point ab = b - a; coord_t ab_size = vSize(ab); coord_t step_count = (ab_size + discretization_step_size / 2) / discretization_step_size; @@ -231,8 +232,8 @@ std::vector SkeletalTrapezoidation::discretize(const vd_t::edge_type& vd_ } for (coord_t step = 1; step < step_count; step++) { - Point here = a + ab * step / step_count; //Now simply interpolate the coordinates to get the new vertices! - coord_t x_here = projected_x(here); //If we've surpassed the position of the extra markings, we may need to insert them first. + Point here = a + ab * step / step_count; // Now simply interpolate the coordinates to get the new vertices! + coord_t x_here = projected_x(here); // If we've surpassed the position of the extra markings, we may need to insert them first. if (add_marking_start && marking_start_x * direction < x_here * direction) { ret.emplace_back(marking_start); @@ -255,15 +256,21 @@ std::vector SkeletalTrapezoidation::discretize(const vd_t::edge_type& vd_ } -bool SkeletalTrapezoidation::computePointCellRange(vd_t::cell_type& cell, Point& start_source_point, Point& end_source_point, vd_t::edge_type*& starting_vd_edge, vd_t::edge_type*& ending_vd_edge, const std::vector& points, const std::vector& segments) +bool SkeletalTrapezoidation::computePointCellRange(vd_t::cell_type& cell, + Point& start_source_point, + Point& end_source_point, + vd_t::edge_type*& starting_vd_edge, + vd_t::edge_type*& ending_vd_edge, + const std::vector& points, + const std::vector& segments) { if (cell.incident_edge()->is_infinite()) { - return false; //Infinite edges only occur outside of the polygon. Don't copy any part of this cell. + return false; // Infinite edges only occur outside of the polygon. Don't copy any part of this cell. } // Check if any point of the cell is inside or outside polygon // Copy whole cell into graph or not at all - + const Point source_point = VoronoiUtils::getSourcePoint(cell, points, segments); const PolygonsPointIndex source_point_index = VoronoiUtils::getSourcePointIndex(cell, points, segments); Point some_point = VoronoiUtils::p(cell.incident_edge()->vertex0()); @@ -271,11 +278,11 @@ bool SkeletalTrapezoidation::computePointCellRange(vd_t::cell_type& cell, Point& { some_point = VoronoiUtils::p(cell.incident_edge()->vertex1()); } - //Test if the some_point is even inside the polygon. - //The edge leading out of a polygon must have an endpoint that's not in the corner following the contour of the polygon at that vertex. - //So if it's inside the corner formed by the polygon vertex, it's all fine. - //But if it's outside of the corner, it must be a vertex of the Voronoi diagram that goes outside of the polygon towards infinity. - if (!LinearAlg2D::isInsideCorner(source_point_index.prev().p(), source_point_index.p(), source_point_index.next().p(), some_point)) + // Test if the some_point is even inside the polygon. + // The edge leading out of a polygon must have an endpoint that's not in the corner following the contour of the polygon at that vertex. + // So if it's inside the corner formed by the polygon vertex, it's all fine. + // But if it's outside of the corner, it must be a vertex of the Voronoi diagram that goes outside of the polygon towards infinity. + if (! LinearAlg2D::isInsideCorner(source_point_index.prev().p(), source_point_index.p(), source_point_index.next().p(), some_point)) { return false; // Don't copy any part of this cell } @@ -293,16 +300,21 @@ bool SkeletalTrapezoidation::computePointCellRange(vd_t::cell_type& cell, Point& } else { - assert((VoronoiUtils::p(vd_edge->vertex0()) == source_point || !vd_edge->is_secondary()) && "point cells must end in the point! They cannot cross the point with an edge, because collinear edges are not allowed in the input."); + assert((VoronoiUtils::p(vd_edge->vertex0()) == source_point || ! vd_edge->is_secondary()) && "point cells must end in the point! They cannot cross the point with an edge, because collinear edges are not allowed in the input."); } - } - while (vd_edge = vd_edge->next(), vd_edge != cell.incident_edge()); + } while (vd_edge = vd_edge->next(), vd_edge != cell.incident_edge()); assert(starting_vd_edge && ending_vd_edge); assert(starting_vd_edge != ending_vd_edge); return true; } -void SkeletalTrapezoidation::computeSegmentCellRange(vd_t::cell_type& cell, Point& start_source_point, Point& end_source_point, vd_t::edge_type*& starting_vd_edge, vd_t::edge_type*& ending_vd_edge, const std::vector& points, const std::vector& segments) +void SkeletalTrapezoidation::computeSegmentCellRange(vd_t::cell_type& cell, + Point& start_source_point, + Point& end_source_point, + vd_t::edge_type*& starting_vd_edge, + vd_t::edge_type*& ending_vd_edge, + const std::vector& points, + const std::vector& segments) { const Segment& source_segment = VoronoiUtils::getSourceSegment(cell, points, segments); Point from = source_segment.from(); @@ -322,8 +334,8 @@ void SkeletalTrapezoidation::computeSegmentCellRange(vd_t::cell_type& cell, Poin } Point v0 = VoronoiUtils::p(edge->vertex0()); Point v1 = VoronoiUtils::p(edge->vertex1()); - assert(!(v0 == to && v1 == from)); - if (v0 == to && !after_start) // Use the last edge which starts in source_segment.to + assert(! (v0 == to && v1 == from)); + if (v0 == to && ! after_start) // Use the last edge which starts in source_segment.to { starting_vd_edge = edge; seen_possible_start = true; @@ -333,30 +345,33 @@ void SkeletalTrapezoidation::computeSegmentCellRange(vd_t::cell_type& cell, Poin after_start = true; } - if (v1 == from && (!ending_vd_edge || ending_edge_is_set_before_start)) + if (v1 == from && (! ending_vd_edge || ending_edge_is_set_before_start)) { - ending_edge_is_set_before_start = !after_start; + ending_edge_is_set_before_start = ! after_start; ending_vd_edge = edge; } } while (edge = edge->next(), edge != cell.incident_edge()); - + assert(starting_vd_edge && ending_vd_edge); assert(starting_vd_edge != ending_vd_edge); - + start_source_point = source_segment.to(); end_source_point = source_segment.from(); } -SkeletalTrapezoidation::SkeletalTrapezoidation(const Polygons& polys, const BeadingStrategy& beading_strategy, - AngleRadians transitioning_angle, coord_t discretization_step_size, - coord_t transition_filter_dist, coord_t allowed_filter_deviation, - coord_t beading_propagation_transition_dist - ): transitioning_angle(transitioning_angle), - discretization_step_size(discretization_step_size), - transition_filter_dist(transition_filter_dist), - allowed_filter_deviation(allowed_filter_deviation), - beading_propagation_transition_dist(beading_propagation_transition_dist), - beading_strategy(beading_strategy) +SkeletalTrapezoidation::SkeletalTrapezoidation(const Polygons& polys, + const BeadingStrategy& beading_strategy, + AngleRadians transitioning_angle, + coord_t discretization_step_size, + coord_t transition_filter_dist, + coord_t allowed_filter_deviation, + coord_t beading_propagation_transition_dist) + : transitioning_angle(transitioning_angle) + , discretization_step_size(discretization_step_size) + , transition_filter_dist(transition_filter_dist) + , allowed_filter_deviation(allowed_filter_deviation) + , beading_propagation_transition_dist(beading_propagation_transition_dist) + , beading_strategy(beading_strategy) { constructFromPolygons(polys); } @@ -383,7 +398,7 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) for (vd_t::cell_type cell : vonoroi_diagram.cells()) { - if (!cell.incident_edge()) + if (! cell.incident_edge()) { // There is no spoon continue; } @@ -392,11 +407,11 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) vd_t::edge_type* starting_vonoroi_edge = nullptr; vd_t::edge_type* ending_vonoroi_edge = nullptr; // Compute and store result in above variables - + if (cell.contains_point()) { const bool keep_going = computePointCellRange(cell, start_source_point, end_source_point, starting_vonoroi_edge, ending_vonoroi_edge, points, segments); - if (!keep_going) + if (! keep_going) { continue; } @@ -405,13 +420,13 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) { computeSegmentCellRange(cell, start_source_point, end_source_point, starting_vonoroi_edge, ending_vonoroi_edge, points, segments); } - - if (!starting_vonoroi_edge || !ending_vonoroi_edge) + + if (! starting_vonoroi_edge || ! ending_vonoroi_edge) { assert(false && "Each cell should start / end in a polygon vertex"); continue; } - + // Copy start to end edge to graph edge_t* prev_edge = nullptr; transferEdge(start_source_point, VoronoiUtils::p(starting_vonoroi_edge->vertex1()), *starting_vonoroi_edge, prev_edge, start_source_point, end_source_point, points, segments); @@ -435,14 +450,14 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) } separatePointyQuadEndNodes(); - + graph.collapseSmallEdges(); // Set [incident_edge] the the first possible edge that way we can iterate over all reachable edges from node.incident_edge, // without needing to iterate backward for (edge_t& edge : graph.edges) { - if (!edge.prev) + if (! edge.prev) { edge.from->incident_edge = &edge; } @@ -454,7 +469,7 @@ void SkeletalTrapezoidation::separatePointyQuadEndNodes() std::unordered_set visited_nodes; for (edge_t& edge : graph.edges) { - if (edge.prev) + if (edge.prev) { continue; } @@ -526,23 +541,23 @@ void SkeletalTrapezoidation::updateIsCentral() coord_t outer_edge_filter_length = beading_strategy.getTransitionThickness(0) / 2; float cap = sin(beading_strategy.getTransitioningAngle() * 0.5); // = cos(bisector_angle / 2) - for (edge_t& edge: graph.edges) + for (edge_t& edge : graph.edges) { assert(edge.twin); - if(!edge.twin) + if (! edge.twin) { - RUN_ONCE(logWarning("Encountered a Voronoi edge without twin!")); + spdlog::warn("Encountered a Voronoi edge without twin!"); continue; } - if(edge.twin->data.centralIsSet()) + if (edge.twin->data.centralIsSet()) { edge.data.setIsCentral(edge.twin->data.isCentral()); } - else if(edge.data.type == SkeletalTrapezoidationEdge::EdgeType::EXTRA_VD) + else if (edge.data.type == SkeletalTrapezoidationEdge::EdgeType::EXTRA_VD) { edge.data.setIsCentral(false); } - else if(std::max(edge.from->data.distance_to_boundary, edge.to->data.distance_to_boundary) < outer_edge_filter_length) + else if (std::max(edge.from->data.distance_to_boundary, edge.to->data.distance_to_boundary) < outer_edge_filter_length) { edge.data.setIsCentral(false); } @@ -562,7 +577,7 @@ void SkeletalTrapezoidation::filterCentral(coord_t max_length) { for (edge_t& edge : graph.edges) { - if (isEndOfCentral(edge) && edge.to->isLocalMaximum() && !edge.to->isLocalMaximum()) + if (isEndOfCentral(edge) && edge.to->isLocalMaximum() && ! edge.to->isLocalMaximum()) { filterCentral(edge.twin, 0, max_length); } @@ -576,8 +591,8 @@ bool SkeletalTrapezoidation::filterCentral(edge_t* starting_edge, coord_t travel { return false; } - - bool should_dissolve = true; //Should we unmark this as central and propagate that? + + bool should_dissolve = true; // Should we unmark this as central and propagate that? for (edge_t* next_edge = starting_edge->next; next_edge && next_edge != starting_edge->twin; next_edge = next_edge->twin->next) { if (next_edge->data.isCentral()) @@ -586,7 +601,7 @@ bool SkeletalTrapezoidation::filterCentral(edge_t* starting_edge, coord_t travel } } - should_dissolve &= !starting_edge->to->isLocalMaximum(); // Don't filter central regions with a local maximum! + should_dissolve &= ! starting_edge->to->isLocalMaximum(); // Don't filter central regions with a local maximum! if (should_dissolve) { starting_edge->data.setIsCentral(false); @@ -599,7 +614,7 @@ void SkeletalTrapezoidation::filterOuterCentral() { for (edge_t& edge : graph.edges) { - if (!edge.prev) + if (! edge.prev) { edge.data.setIsCentral(false); edge.twin->data.setIsCentral(false); @@ -624,7 +639,7 @@ void SkeletalTrapezoidation::updateBeadCount() { if (node.data.distance_to_boundary < 0) { - RUN_ONCE(logWarning("Distance to boundary not yet computed for local maximum!\n")); + spdlog::warn("Distance to boundary not yet computed for local maximum!"); node.data.distance_to_boundary = std::numeric_limits::max(); edge_t* edge = node.incident_edge; do @@ -642,13 +657,13 @@ void SkeletalTrapezoidation::filterNoncentralRegions() { for (edge_t& edge : graph.edges) { - if (!isEndOfCentral(edge)) + if (! isEndOfCentral(edge)) { continue; } - if(edge.to->data.bead_count < 0 && edge.to->data.distance_to_boundary != 0) + if (edge.to->data.bead_count < 0 && edge.to->data.distance_to_boundary != 0) { - logWarning("Encountered an uninitialized bead at the boundary!\n"); + spdlog::warn("Encountered an uninitialized bead at the boundary!"); } assert(edge.to->data.bead_count >= 0 || edge.to->data.distance_to_boundary == 0); constexpr coord_t max_dist = 400; @@ -714,7 +729,7 @@ void SkeletalTrapezoidation::generateTransitioningRibs() assert(edge.data.hasTransitions() || edge.twin->data.hasTransitions()); } } - + filterTransitionMids(); ptr_vector_t> edge_transition_ends; // We only map the half edge in the upward direction. mapped items are not sorted @@ -730,7 +745,7 @@ void SkeletalTrapezoidation::generateTransitionMids(ptr_vector_tdata.bead_count == edge.to->data.bead_count); - if(edge.from->data.bead_count != edge.to->data.bead_count) + if (edge.from->data.bead_count != edge.to->data.bead_count) { - RUN_ONCE(logWarning("Bead count %i is different from %i even though distance to boundary is the same.", edge.from->data.bead_count, edge.to->data.bead_count)); + spdlog::warn("Bead count {} is different from {} even though distance to boundary is the same.", edge.from->data.bead_count, edge.to->data.bead_count); } continue; } @@ -758,15 +773,14 @@ void SkeletalTrapezoidation::generateTransitionMids(ptr_vector_t beading_strategy.getOptimalBeadCount(start_R * 2) - || end_bead_count > beading_strategy.getOptimalBeadCount(end_R * 2)) + if (start_bead_count > beading_strategy.getOptimalBeadCount(start_R * 2) || end_bead_count > beading_strategy.getOptimalBeadCount(end_R * 2)) { // Wasn't the case earlier in this function because of already introduced transitions - RUN_ONCE(logError("transitioning segment overlap! (?)\n")); + spdlog::error("transitioning segment overlap!"); } assert(start_R < end_R); - if(start_R >= end_R) + if (start_R >= end_R) { - RUN_ONCE(logWarning("Transitioning the wrong way around! This function expects to transition from small R to big R, but was transitioning from %i to %i.", start_R, end_R)); + spdlog::warn("Transitioning the wrong way around! This function expects to transition from small R to big R, but was transitioning from {} to {}.", start_R, end_R); } coord_t edge_size = vSize(edge.from->p - edge.to->p); for (int transition_lower_bead_count = start_bead_count; transition_lower_bead_count < end_bead_count; transition_lower_bead_count++) @@ -774,20 +788,20 @@ void SkeletalTrapezoidation::generateTransitionMids(ptr_vector_t end_R) { - RUN_ONCE(logError("transition on segment lies outside of segment!\n")); + spdlog::error("transition on segment lies outside of segment!"); mid_R = end_R; } if (mid_R < start_R) { - RUN_ONCE(logError("transition on segment lies outside of segment!\n")); + spdlog::error("transition on segment lies outside of segment!"); mid_R = start_R; } coord_t mid_pos = edge_size * (mid_R - start_R) / (end_R - start_R); assert(mid_pos >= 0); assert(mid_pos <= edge_size); - if(mid_pos < 0 || mid_pos > edge_size) + if (mid_pos < 0 || mid_pos > edge_size) { - RUN_ONCE(logWarning("Transition mid is out of bounds of the edge.")); + spdlog::warn("Transition mid is out of bounds of the edge."); } auto transitions = edge.data.getTransitions(); constexpr bool ignore_empty = true; @@ -795,7 +809,7 @@ void SkeletalTrapezoidation::generateTransitionMids(ptr_vector_t>()); - edge.data.setTransitions(edge_transitions.back()); // initialization + edge.data.setTransitions(edge_transitions.back()); // initialization transitions = edge.data.getTransitions(); } transitions->emplace_back(mid_pos, transition_lower_bead_count, mid_R); @@ -817,7 +831,7 @@ void SkeletalTrapezoidation::filterTransitionMids() // This is how stuff should be stored in transitions assert(transitions.front().lower_bead_count <= transitions.back().lower_bead_count); assert(edge.from->data.distance_to_boundary <= edge.to->data.distance_to_boundary); - + const Point a = edge.from->p; const Point b = edge.to->p; Point ab = b - a; @@ -825,7 +839,7 @@ void SkeletalTrapezoidation::filterTransitionMids() bool going_up = true; std::list to_be_dissolved_back = dissolveNearbyTransitions(&edge, transitions.back(), ab_size - transitions.back().pos, transition_filter_dist, going_up); - bool should_dissolve_back = !to_be_dissolved_back.empty(); + bool should_dissolve_back = ! to_be_dissolved_back.empty(); for (TransitionMidRef& ref : to_be_dissolved_back) { dissolveBeadCountRegion(&edge, transitions.back().lower_bead_count + 1, transitions.back().lower_bead_count); @@ -837,7 +851,7 @@ void SkeletalTrapezoidation::filterTransitionMids() coord_t upper_transition_half_length = (1.0 - beading_strategy.getTransitionAnchorPos(trans_bead_count)) * beading_strategy.getTransitioningLength(trans_bead_count); should_dissolve_back |= filterEndOfCentralTransition(&edge, ab_size - transitions.back().pos, upper_transition_half_length, trans_bead_count); } - + if (should_dissolve_back) { transitions.pop_back(); @@ -849,7 +863,7 @@ void SkeletalTrapezoidation::filterTransitionMids() going_up = false; std::list to_be_dissolved_front = dissolveNearbyTransitions(edge.twin, transitions.front(), transitions.front().pos, transition_filter_dist, going_up); - bool should_dissolve_front = !to_be_dissolved_front.empty(); + bool should_dissolve_front = ! to_be_dissolved_front.empty(); for (TransitionMidRef& ref : to_be_dissolved_front) { dissolveBeadCountRegion(edge.twin, transitions.front().lower_bead_count, transitions.front().lower_bead_count + 1); @@ -861,7 +875,7 @@ void SkeletalTrapezoidation::filterTransitionMids() coord_t lower_transition_half_length = beading_strategy.getTransitionAnchorPos(trans_bead_count) * beading_strategy.getTransitioningLength(trans_bead_count); should_dissolve_front |= filterEndOfCentralTransition(edge.twin, transitions.front().pos, lower_transition_half_length, trans_bead_count + 1); } - + if (should_dissolve_front) { transitions.pop_front(); @@ -883,24 +897,24 @@ std::list SkeletalTrapezoidation::diss bool should_dissolve = true; for (edge_t* edge = edge_to_start->next; edge && edge != edge_to_start->twin; edge = edge->twin->next) { - if (!edge->data.isCentral()) + if (! edge->data.isCentral()) { continue; } - + Point a = edge->from->p; Point b = edge->to->p; Point ab = b - a; coord_t ab_size = vSize(ab); bool is_aligned = edge->isUpward(); - edge_t* aligned_edge = is_aligned? edge : edge->twin; + edge_t* aligned_edge = is_aligned ? edge : edge->twin; bool seen_transition_on_this_edge = false; const coord_t origin_radius = origin_transition.feature_radius; const coord_t radius_here = edge->from->data.distance_to_boundary; const bool dissolve_result_is_odd = bool(origin_transition.lower_bead_count % 2) == going_up; const coord_t width_deviation = std::abs(origin_radius - radius_here) * 2; // times by two because the deviation happens at both sides of the significant edge - const coord_t line_width_deviation = dissolve_result_is_odd? width_deviation : width_deviation / 2; // assume the deviation will be split over either 1 or 2 lines, i.e. assume wall_distribution_count = 1 + const coord_t line_width_deviation = dissolve_result_is_odd ? width_deviation : width_deviation / 2; // assume the deviation will be split over either 1 or 2 lines, i.e. assume wall_distribution_count = 1 if (line_width_deviation > allowed_filter_deviation) { should_dissolve = false; @@ -909,24 +923,23 @@ std::list SkeletalTrapezoidation::diss if (should_dissolve && aligned_edge->data.hasTransitions()) { auto& transitions = *aligned_edge->data.getTransitions(); - for (auto transition_it = transitions.begin(); transition_it != transitions.end(); ++ transition_it) + for (auto transition_it = transitions.begin(); transition_it != transitions.end(); ++transition_it) { // Note: this is not necessarily iterating in the traveling direction! // Check whether we should dissolve - coord_t pos = is_aligned? transition_it->pos : ab_size - transition_it->pos; - if (traveled_dist + pos < max_dist - && transition_it->lower_bead_count == origin_transition.lower_bead_count) // Only dissolve local optima + coord_t pos = is_aligned ? transition_it->pos : ab_size - transition_it->pos; + if (traveled_dist + pos < max_dist && transition_it->lower_bead_count == origin_transition.lower_bead_count) // Only dissolve local optima { if (traveled_dist + pos < beading_strategy.getTransitioningLength(transition_it->lower_bead_count)) { // Consecutive transitions both in/decreasing in bead count should never be closer together than the transition distance - assert(going_up != is_aligned || transition_it->lower_bead_count == 0); + assert(going_up != is_aligned || transition_it->lower_bead_count == 0); } to_be_dissolved.emplace_back(aligned_edge, transition_it); seen_transition_on_this_edge = true; } } } - if (should_dissolve && !seen_transition_on_this_edge) + if (should_dissolve && ! seen_transition_on_this_edge) { std::list to_be_dissolved_here = dissolveNearbyTransitions(edge, origin_transition, traveled_dist + ab_size, max_dist, going_up); if (to_be_dissolved_here.empty()) @@ -935,15 +948,15 @@ std::list SkeletalTrapezoidation::diss return to_be_dissolved; } to_be_dissolved.splice(to_be_dissolved.end(), to_be_dissolved_here); // Transfer to_be_dissolved_here into to_be_dissolved - should_dissolve = should_dissolve && !to_be_dissolved.empty(); + should_dissolve = should_dissolve && ! to_be_dissolved.empty(); } } - - if (!should_dissolve) + + if (! should_dissolve) { to_be_dissolved.clear(); } - + return to_be_dissolved; } @@ -955,11 +968,11 @@ void SkeletalTrapezoidation::dissolveBeadCountRegion(edge_t* edge_to_start, coor { return; } - + edge_to_start->to->data.bead_count = to_bead_count; for (edge_t* edge = edge_to_start->next; edge && edge != edge_to_start->twin; edge = edge->twin->next) { - if (!edge->data.isCentral()) + if (! edge->data.isCentral()) { continue; } @@ -973,7 +986,7 @@ bool SkeletalTrapezoidation::filterEndOfCentralTransition(edge_t* edge_to_start, { return false; } - + bool is_end_of_central = true; bool should_dissolve = false; for (edge_t* next_edge = edge_to_start->next; next_edge && next_edge != edge_to_start->twin; next_edge = next_edge->twin->next) @@ -989,7 +1002,7 @@ bool SkeletalTrapezoidation::filterEndOfCentralTransition(edge_t* edge_to_start, { should_dissolve = true; } - + if (should_dissolve) { edge_to_start->to->data.bead_count = replacing_bead_count; @@ -1046,7 +1059,7 @@ void SkeletalTrapezoidation::generateTransitionEnds(edge_t& edge, coord_t mid_po #ifdef DEBUG if (! generateTransitionEnd(edge, start_pos, end_pos, transition_half_length, mid_rest, end_rest, lower_bead_count, edge_transition_ends)) { - RUN_ONCE(logWarning("There must have been at least one direction in which the bead count is increasing enough for the transition to happen!\n")); + spdlog::warn("There must have been at least one direction in which the bead count is increasing enough for the transition to happen!")); } #else generateTransitionEnd(edge, start_pos, end_pos, transition_half_length, mid_rest, end_rest, lower_bead_count, edge_transition_ends); @@ -1054,7 +1067,14 @@ void SkeletalTrapezoidation::generateTransitionEnds(edge_t& edge, coord_t mid_po } } -bool SkeletalTrapezoidation::generateTransitionEnd(edge_t& edge, coord_t start_pos, coord_t end_pos, coord_t transition_half_length, Ratio start_rest, Ratio end_rest, coord_t lower_bead_count, ptr_vector_t>& edge_transition_ends) +bool SkeletalTrapezoidation::generateTransitionEnd(edge_t& edge, + coord_t start_pos, + coord_t end_pos, + coord_t transition_half_length, + Ratio start_rest, + Ratio end_rest, + coord_t lower_bead_count, + ptr_vector_t>& edge_transition_ends) { Point a = edge.from->p; Point b = edge.to->p; @@ -1062,17 +1082,17 @@ bool SkeletalTrapezoidation::generateTransitionEnd(edge_t& edge, coord_t start_p coord_t ab_size = vSize(ab); // TODO: prevent recalculation of these values assert(start_pos <= ab_size); - if(start_pos > ab_size) + if (start_pos > ab_size) { - RUN_ONCE(logWarning("Start position of edge is beyond edge range.")); + spdlog::warn("Start position of edge is beyond edge range."); } bool going_up = end_rest > start_rest; assert(edge.data.isCentral()); - if (!edge.data.isCentral()) + if (! edge.data.isCentral()) { - RUN_ONCE(logWarning("This function shouldn't generate ends in or beyond non-central regions.")); + spdlog::warn("This function shouldn't generate ends in or beyond non-central regions."); return false; } @@ -1086,7 +1106,8 @@ bool SkeletalTrapezoidation::generateTransitionEnd(edge_t& edge, coord_t start_p coord_t central_edge_count = 0; for (edge_t* outgoing = edge.next; outgoing && outgoing != edge.twin; outgoing = outgoing->twin->next) { - if (!outgoing->data.isCentral()) continue; + if (! outgoing->data.isCentral()) + continue; central_edge_count++; } @@ -1095,7 +1116,7 @@ bool SkeletalTrapezoidation::generateTransitionEnd(edge_t& edge, coord_t start_p for (edge_t* outgoing = edge.next; outgoing && outgoing != edge.twin;) { edge_t* next = outgoing->twin->next; // Before we change the outgoing edge itself - if (!outgoing->data.isCentral()) + if (! outgoing->data.isCentral()) { outgoing = next; continue; // Don't put transition ends in non-central regions @@ -1112,7 +1133,7 @@ bool SkeletalTrapezoidation::generateTransitionEnd(edge_t& edge, coord_t start_p outgoing = next; has_recursed = true; } - if (!going_up || (has_recursed && !is_only_going_down)) + if (! going_up || (has_recursed && ! is_only_going_down)) { edge.to->data.transition_ratio = rest; edge.to->data.bead_count = lower_bead_count; @@ -1136,15 +1157,15 @@ bool SkeletalTrapezoidation::generateTransitionEnd(edge_t& edge, coord_t start_p pos = ab_size - end_pos; } - if(!upward_edge->data.hasTransitionEnds()) + if (! upward_edge->data.hasTransitionEnds()) { - //This edge doesn't have a data structure yet for the transition ends. Make one. + // This edge doesn't have a data structure yet for the transition ends. Make one. edge_transition_ends.emplace_back(std::make_shared>()); upward_edge->data.setTransitionEnds(edge_transition_ends.back()); } auto transitions = upward_edge->data.getTransitionEnds(); - //Add a transition to it (on the correct side). + // Add a transition to it (on the correct side). assert(ab_size == vSize(edge.twin->from->p - edge.twin->to->p)); assert(pos <= ab_size); if (transitions->empty() || pos < transitions->front().pos) @@ -1169,13 +1190,13 @@ bool SkeletalTrapezoidation::isGoingDown(edge_t* outgoing, coord_t traveled_dist return true; } bool is_upward = outgoing->to->data.distance_to_boundary >= outgoing->from->data.distance_to_boundary; - edge_t* upward_edge = is_upward? outgoing : outgoing->twin; + edge_t* upward_edge = is_upward ? outgoing : outgoing->twin; if (outgoing->to->data.bead_count > lower_bead_count + 1) { assert(upward_edge->data.hasTransitions() && "If the bead count is going down there has to be a transition mid!"); - if(!upward_edge->data.hasTransitions()) + if (! upward_edge->data.hasTransitions()) { - logWarning("If the bead count is going down there has to be a transition mid!"); + spdlog::warn("If the bead count is going down there has to be a transition mid!"); } return false; } @@ -1183,12 +1204,8 @@ bool SkeletalTrapezoidation::isGoingDown(edge_t* outgoing, coord_t traveled_dist if (upward_edge->data.hasTransitions()) { auto& transition_mids = *upward_edge->data.getTransitions(); - TransitionMiddle& mid = is_upward? transition_mids.front() : transition_mids.back(); - if ( - mid.lower_bead_count == lower_bead_count && - ((is_upward && mid.pos + traveled_dist < max_dist) - || (!is_upward && length - mid.pos + traveled_dist < max_dist)) - ) + TransitionMiddle& mid = is_upward ? transition_mids.front() : transition_mids.back(); + if (mid.lower_bead_count == lower_bead_count && ((is_upward && mid.pos + traveled_dist < max_dist) || (! is_upward && length - mid.pos + traveled_dist < max_dist))) { return true; } @@ -1197,17 +1214,16 @@ bool SkeletalTrapezoidation::isGoingDown(edge_t* outgoing, coord_t traveled_dist { return false; } - if (outgoing->to->data.bead_count <= lower_bead_count - && !(outgoing->to->data.bead_count == lower_bead_count && outgoing->to->data.transition_ratio > 0.0)) + if (outgoing->to->data.bead_count <= lower_bead_count && ! (outgoing->to->data.bead_count == lower_bead_count && outgoing->to->data.transition_ratio > 0.0)) { return true; } - + bool is_only_going_down = true; bool has_recursed = false; for (edge_t* next = outgoing->next; next && next != outgoing->twin; next = next->twin->next) { - if (!next->data.isCentral()) + if (! next->data.isCentral()) { continue; } @@ -1239,7 +1255,7 @@ void SkeletalTrapezoidation::applyTransitions(ptr_vector_t ab_size - snap_dist) - && close_node->data.bead_count == new_node_bead_count - ) + node_t* close_node = (end_pos < ab_size / 2) ? from : to; + if ((end_pos < snap_dist || end_pos > ab_size - snap_dist) && close_node->data.bead_count == new_node_bead_count) { assert(end_pos <= ab_size); close_node->data.transition_ratio = 0; continue; } Point mid = a + normal(ab, end_pos); - + assert(last_edge_replacing_input->data.isCentral()); assert(last_edge_replacing_input->data.type != SkeletalTrapezoidationEdge::EdgeType::EXTRA_VD); last_edge_replacing_input = graph.insertNode(last_edge_replacing_input, mid, new_node_bead_count); @@ -1286,11 +1300,11 @@ void SkeletalTrapezoidation::applyTransitions(ptr_vector_tp - edge.from->p, discretization_step_size) - || edge.from->data.distance_to_boundary >= edge.to->data.distance_to_boundary) + + if (! edge.data.isCentral() || shorterThen(edge.to->p - edge.from->p, discretization_step_size) || edge.from->data.distance_to_boundary >= edge.to->data.distance_to_boundary) { continue; } @@ -1322,7 +1334,8 @@ void SkeletalTrapezoidation::generateExtraRibs() std::vector rib_thicknesses = beading_strategy.getNonlinearThicknesses(edge.from->data.bead_count); - if (rib_thicknesses.empty()) continue; + if (rib_thicknesses.empty()) + continue; // Preload some variables before [edge] gets changed node_t* from = edge.from; @@ -1333,34 +1346,32 @@ void SkeletalTrapezoidation::generateExtraRibs() coord_t ab_size = vSize(ab); coord_t a_R = edge.from->data.distance_to_boundary; coord_t b_R = edge.to->data.distance_to_boundary; - + edge_t* last_edge_replacing_input = &edge; for (coord_t rib_thickness : rib_thicknesses) { - if (rib_thickness / 2 <= a_R) + if (rib_thickness / 2 <= a_R) { continue; } - if (rib_thickness / 2 >= b_R) + if (rib_thickness / 2 >= b_R) { break; } - + coord_t new_node_bead_count = std::min(edge.from->data.bead_count, edge.to->data.bead_count); coord_t end_pos = ab_size * (rib_thickness / 2 - a_R) / (b_R - a_R); assert(end_pos > 0); assert(end_pos < ab_size); - node_t* close_node = (end_pos < ab_size / 2)? from : to; - if ((end_pos < snap_dist || end_pos > ab_size - snap_dist) - && close_node->data.bead_count == new_node_bead_count - ) + node_t* close_node = (end_pos < ab_size / 2) ? from : to; + if ((end_pos < snap_dist || end_pos > ab_size - snap_dist) && close_node->data.bead_count == new_node_bead_count) { assert(end_pos <= ab_size); close_node->data.transition_ratio = 0; continue; } Point mid = a + normal(ab, end_pos); - + assert(last_edge_replacing_input->data.isCentral()); assert(last_edge_replacing_input->data.type != SkeletalTrapezoidationEdge::EdgeType::EXTRA_VD); last_edge_replacing_input = graph.insertNode(last_edge_replacing_input, mid, new_node_bead_count); @@ -1388,34 +1399,35 @@ void SkeletalTrapezoidation::generateSegments() upward_quad_mids.emplace_back(&edge); } } - - std::sort(upward_quad_mids.begin(), upward_quad_mids.end(), [this](edge_t* a, edge_t* b) - { - if (a->to->data.distance_to_boundary == b->to->data.distance_to_boundary) - { // Ordering between two 'upward' edges of the same distance is important when one of the edges is flat and connected to the other - if (a->from->data.distance_to_boundary == a->to->data.distance_to_boundary - && b->from->data.distance_to_boundary == b->to->data.distance_to_boundary) - { - coord_t max = std::numeric_limits::max(); - coord_t a_dist_from_up = std::min(a->distToGoUp().value_or(max), a->twin->distToGoUp().value_or(max)) - vSize(a->to->p - a->from->p); - coord_t b_dist_from_up = std::min(b->distToGoUp().value_or(max), b->twin->distToGoUp().value_or(max)) - vSize(b->to->p - b->from->p); - return a_dist_from_up < b_dist_from_up; - } - else if (a->from->data.distance_to_boundary == a->to->data.distance_to_boundary) - { - return true; // Edge a might be 'above' edge b - } - else if (b->from->data.distance_to_boundary == b->to->data.distance_to_boundary) - { - return false; // Edge b might be 'above' edge a - } - else - { - // Ordering is not important - } - } - return a->to->data.distance_to_boundary > b->to->data.distance_to_boundary; - }); + + std::sort(upward_quad_mids.begin(), + upward_quad_mids.end(), + [this](edge_t* a, edge_t* b) + { + if (a->to->data.distance_to_boundary == b->to->data.distance_to_boundary) + { // Ordering between two 'upward' edges of the same distance is important when one of the edges is flat and connected to the other + if (a->from->data.distance_to_boundary == a->to->data.distance_to_boundary && b->from->data.distance_to_boundary == b->to->data.distance_to_boundary) + { + coord_t max = std::numeric_limits::max(); + coord_t a_dist_from_up = std::min(a->distToGoUp().value_or(max), a->twin->distToGoUp().value_or(max)) - vSize(a->to->p - a->from->p); + coord_t b_dist_from_up = std::min(b->distToGoUp().value_or(max), b->twin->distToGoUp().value_or(max)) - vSize(b->to->p - b->from->p); + return a_dist_from_up < b_dist_from_up; + } + else if (a->from->data.distance_to_boundary == a->to->data.distance_to_boundary) + { + return true; // Edge a might be 'above' edge b + } + else if (b->from->data.distance_to_boundary == b->to->data.distance_to_boundary) + { + return false; // Edge b might be 'above' edge a + } + else + { + // Ordering is not important + } + } + return a->to->data.distance_to_boundary > b->to->data.distance_to_boundary; + }); ptr_vector_t node_beadings; { // Store beading @@ -1430,9 +1442,9 @@ void SkeletalTrapezoidation::generateSegments() node_beadings.emplace_back(new BeadingPropagation(beading_strategy.compute(node.data.distance_to_boundary * 2, node.data.bead_count))); node.data.setBeading(node_beadings.back()); assert(node_beadings.back()->beading.total_thickness == node.data.distance_to_boundary * 2); - if(node_beadings.back()->beading.total_thickness != node.data.distance_to_boundary * 2) + if (node_beadings.back()->beading.total_thickness != node.data.distance_to_boundary * 2) { - RUN_ONCE(logWarning("If transitioning to an endpoint (ratio 0), the node should be exactly in the middle.")); + spdlog::warn("If transitioning to an endpoint (ratio 0), the node should be exactly in the middle."); } } else @@ -1443,14 +1455,14 @@ void SkeletalTrapezoidation::generateSegments() node_beadings.emplace_back(new BeadingPropagation(merged)); node.data.setBeading(node_beadings.back()); assert(merged.total_thickness == node.data.distance_to_boundary * 2); - if(merged.total_thickness != node.data.distance_to_boundary * 2) + if (merged.total_thickness != node.data.distance_to_boundary * 2) { - RUN_ONCE(logWarning("If merging two beads, the new bead must be exactly in the middle.")); + spdlog::warn("If merging two beads, the new bead must be exactly in the middle."); } } } } - + propagateBeadingsUpward(upward_quad_mids, node_beadings); propagateBeadingsDownward(upward_quad_mids, node_beadings); @@ -1459,7 +1471,7 @@ void SkeletalTrapezoidation::generateSegments() generateJunctions(node_beadings, edge_junctions); connectJunctions(edge_junctions); - + generateLocalMaximaSingleBeads(); } @@ -1478,7 +1490,7 @@ SkeletalTrapezoidation::edge_t* SkeletalTrapezoidation::getQuadMaxRedgeTo(edge_t ret = edge; } } - if (!ret->next && ret->to->data.distance_to_boundary - 5 < ret->from->data.distance_to_boundary) + if (! ret->next && ret->to->data.distance_to_boundary - 5 < ret->from->data.distance_to_boundary) { ret = ret->prev; } @@ -1505,7 +1517,8 @@ void SkeletalTrapezoidation::propagateBeadingsUpward(std::vector& upwar { // Only propagate to places where there is place continue; } - assert((upward_edge->from->data.distance_to_boundary != upward_edge->to->data.distance_to_boundary || shorterThen(upward_edge->to->p - upward_edge->from->p, central_filter_dist)) && "zero difference R edges should always be central"); + assert((upward_edge->from->data.distance_to_boundary != upward_edge->to->data.distance_to_boundary || shorterThen(upward_edge->to->p - upward_edge->from->p, central_filter_dist)) + && "zero difference R edges should always be central"); coord_t length = vSize(upward_edge->to->p - upward_edge->from->p); BeadingPropagation upper_beading = lower_beading; upper_beading.dist_to_bottom_source += length; @@ -1521,13 +1534,10 @@ void SkeletalTrapezoidation::propagateBeadingsDownward(std::vector& upw for (edge_t* upward_quad_mid : upward_quad_mids) { // Transfer beading information to lower nodes - if (!upward_quad_mid->data.isCentral()) + if (! upward_quad_mid->data.isCentral()) { // for equidistant edge: propagate from known beading to node with unknown beading - if (upward_quad_mid->from->data.distance_to_boundary == upward_quad_mid->to->data.distance_to_boundary - && upward_quad_mid->from->data.hasBeading() - && ! upward_quad_mid->to->data.hasBeading() - ) + if (upward_quad_mid->from->data.distance_to_boundary == upward_quad_mid->to->data.distance_to_boundary && upward_quad_mid->from->data.hasBeading() && ! upward_quad_mid->to->data.hasBeading()) { propagateBeadingsDownward(upward_quad_mid->twin, node_beadings); } @@ -1544,22 +1554,22 @@ void SkeletalTrapezoidation::propagateBeadingsDownward(edge_t* edge_to_peak, ptr coord_t length = vSize(edge_to_peak->to->p - edge_to_peak->from->p); BeadingPropagation& top_beading = *getOrCreateBeading(edge_to_peak->to, node_beadings); assert(top_beading.beading.total_thickness >= edge_to_peak->to->data.distance_to_boundary * 2); - if(top_beading.beading.total_thickness < edge_to_peak->to->data.distance_to_boundary * 2) + if (top_beading.beading.total_thickness < edge_to_peak->to->data.distance_to_boundary * 2) { - RUN_ONCE(logWarning("Top bead is beyond the center of the total width.")); + spdlog::warn("Top bead is beyond the center of the total width."); } - assert(!top_beading.is_upward_propagated_only); + assert(! top_beading.is_upward_propagated_only); - if(!edge_to_peak->from->data.hasBeading()) + if (! edge_to_peak->from->data.hasBeading()) { // Set new beading if there is no beading associated with the node yet BeadingPropagation propagated_beading = top_beading; propagated_beading.dist_from_top_source += length; node_beadings.emplace_back(new BeadingPropagation(propagated_beading)); edge_to_peak->from->data.setBeading(node_beadings.back()); assert(propagated_beading.beading.total_thickness >= edge_to_peak->from->data.distance_to_boundary * 2); - if(propagated_beading.beading.total_thickness < edge_to_peak->from->data.distance_to_boundary * 2) + if (propagated_beading.beading.total_thickness < edge_to_peak->from->data.distance_to_boundary * 2) { - RUN_ONCE(logWarning("Propagated bead is beyond the center of the total width.")); + spdlog::warn("Propagated bead is beyond the center of the total width."); } } else @@ -1579,9 +1589,9 @@ void SkeletalTrapezoidation::propagateBeadingsDownward(edge_t* edge_to_peak, ptr bottom_beading = BeadingPropagation(merged_beading); bottom_beading.is_upward_propagated_only = false; assert(merged_beading.total_thickness >= edge_to_peak->from->data.distance_to_boundary * 2); - if(merged_beading.total_thickness < edge_to_peak->from->data.distance_to_boundary * 2) + if (merged_beading.total_thickness < edge_to_peak->from->data.distance_to_boundary * 2) { - RUN_ONCE(logWarning("Merged bead is beyond the center of the total width.")); + spdlog::warn("Merged bead is beyond the center of the total width."); } } } @@ -1636,12 +1646,12 @@ SkeletalTrapezoidation::Beading SkeletalTrapezoidation::interpolate(const Beadin assert(ratio_left_to_whole >= 0.0 && ratio_left_to_whole <= 1.0); float ratio_right_to_whole = 1.0 - ratio_left_to_whole; - Beading ret = (left.total_thickness > right.total_thickness)? left : right; + Beading ret = (left.total_thickness > right.total_thickness) ? left : right; for (size_t inset_idx = 0; inset_idx < std::min(left.bead_widths.size(), right.bead_widths.size()); inset_idx++) { - if(left.bead_widths[inset_idx] == 0 || right.bead_widths[inset_idx] == 0) + if (left.bead_widths[inset_idx] == 0 || right.bead_widths[inset_idx] == 0) { - ret.bead_widths[inset_idx] = 0; //0-width wall markers stay 0-width. + ret.bead_widths[inset_idx] = 0; // 0-width wall markers stay 0-width. } else { @@ -1665,21 +1675,20 @@ void SkeletalTrapezoidation::generateJunctions(ptr_vector_t& coord_t start_R = edge->to->data.distance_to_boundary; // higher R coord_t end_R = edge->from->data.distance_to_boundary; // lower R - if ((edge->from->data.bead_count == edge->to->data.bead_count && edge->from->data.bead_count >= 0) - || end_R >= start_R) + if ((edge->from->data.bead_count == edge->to->data.bead_count && edge->from->data.bead_count >= 0) || end_R >= start_R) { // No beads to generate continue; } Beading* beading = &getOrCreateBeading(edge->to, node_beadings)->beading; edge_junctions.emplace_back(std::make_shared()); - edge_.data.setExtrusionJunctions(edge_junctions.back()); // initialization + edge_.data.setExtrusionJunctions(edge_junctions.back()); // initialization LineJunctions& ret = *edge_junctions.back(); assert(beading->total_thickness >= edge->to->data.distance_to_boundary * 2); - if(beading->total_thickness < edge->to->data.distance_to_boundary * 2) + if (beading->total_thickness < edge->to->data.distance_to_boundary * 2) { - RUN_ONCE(logWarning("Generated junction is beyond the center of total width.")) + spdlog::warn("Generated junction is beyond the center of total width."); } Point a = edge->to->p; @@ -1700,15 +1709,12 @@ void SkeletalTrapezoidation::generateJunctions(ptr_vector_t& // Robustness against odd segments which might lie just slightly outside of the range due to rounding errors // not sure if this is really needed (TODO) - if (junction_idx + 1 < num_junctions - && beading->toolpath_locations[junction_idx + 1] <= start_R + 5 - && beading->total_thickness < start_R + 5 - ) + if (junction_idx + 1 < num_junctions && beading->toolpath_locations[junction_idx + 1] <= start_R + 5 && beading->total_thickness < start_R + 5) { junction_idx++; } - for (; junction_idx < num_junctions; junction_idx--) //When junction_idx underflows, it'll be more than num_junctions too. + for (; junction_idx < num_junctions; junction_idx--) // When junction_idx underflows, it'll be more than num_junctions too. { coord_t bead_R = beading->toolpath_locations[junction_idx]; assert(bead_R >= 0); @@ -1738,7 +1744,7 @@ std::shared_ptr SkeletalTrapezo { return nearest_beading; } - + // Else make a new beading: bool has_central_edge = false; bool first = true; @@ -1753,9 +1759,9 @@ std::shared_ptr SkeletalTrapezo dist = std::min(dist, edge->to->data.distance_to_boundary + vSize(edge->to->p - edge->from->p)); first = false; } - if (!has_central_edge) + if (! has_central_edge) { - RUN_ONCE(logError("Unknown beading for non-central node!\n")); + spdlog::error("Unknown beading for non-central node!"); } assert(dist != std::numeric_limits::max()); node->data.bead_count = beading_strategy.getOptimalBeadCount(dist * 2); @@ -1774,9 +1780,9 @@ std::shared_ptr SkeletalTrapezo { edge_t* edge_to; coord_t dist; - DistEdge(edge_t* edge_to, coord_t dist) - : edge_to(edge_to), dist(dist) - {} + DistEdge(edge_t* edge_to, coord_t dist) : edge_to(edge_to), dist(dist) + { + } }; auto compare = [](const DistEdge& l, const DistEdge& r) -> bool { return l.dist > r.dist; }; @@ -1790,10 +1796,12 @@ std::shared_ptr SkeletalTrapezo for (coord_t counter = 0; counter < SKELETAL_TRAPEZOIDATION_BEAD_SEARCH_MAX; counter++) { // Prevent endless recursion - if (further_edges.empty()) return nullptr; + if (further_edges.empty()) + return nullptr; DistEdge here = further_edges.top(); further_edges.pop(); - if (here.dist > max_dist) return nullptr; + if (here.dist > max_dist) + return nullptr; if (here.edge_to->to->data.hasBeading()) { return here.edge_to->to->data.getBeading(); @@ -1811,7 +1819,8 @@ std::shared_ptr SkeletalTrapezo void SkeletalTrapezoidation::addToolpathSegment(const ExtrusionJunction& from, const ExtrusionJunction& to, bool is_odd, bool force_new_path, bool from_is_3way, bool to_is_3way) { - if (from == to) return; + if (from == to) + return; std::vector& generated_toolpaths = *p_generated_toolpaths; @@ -1820,31 +1829,25 @@ void SkeletalTrapezoidation::addToolpathSegment(const ExtrusionJunction& from, c { generated_toolpaths.resize(inset_idx + 1); } - assert((generated_toolpaths[inset_idx].empty() || !generated_toolpaths[inset_idx].back().junctions.empty()) && "empty extrusion lines should never have been generated"); - if (generated_toolpaths[inset_idx].empty() - || generated_toolpaths[inset_idx].back().is_odd != is_odd - || generated_toolpaths[inset_idx].back().junctions.back().perimeter_index != inset_idx // inset_idx should always be consistent - ) + assert((generated_toolpaths[inset_idx].empty() || ! generated_toolpaths[inset_idx].back().junctions.empty()) && "empty extrusion lines should never have been generated"); + if (generated_toolpaths[inset_idx].empty() || generated_toolpaths[inset_idx].back().is_odd != is_odd || generated_toolpaths[inset_idx].back().junctions.back().perimeter_index != inset_idx // inset_idx should always be consistent + ) { force_new_path = true; } - if (!force_new_path - && shorterThen(generated_toolpaths[inset_idx].back().junctions.back().p - from.p, 10) - && std::abs(generated_toolpaths[inset_idx].back().junctions.back().w - from.w) < 10 + if (! force_new_path && shorterThen(generated_toolpaths[inset_idx].back().junctions.back().p - from.p, 10) && std::abs(generated_toolpaths[inset_idx].back().junctions.back().w - from.w) < 10 && ! from_is_3way // force new path at 3way intersection - ) + ) { generated_toolpaths[inset_idx].back().junctions.push_back(to); } - else if (!force_new_path - && shorterThen(generated_toolpaths[inset_idx].back().junctions.back().p - to.p, 10) - && std::abs(generated_toolpaths[inset_idx].back().junctions.back().w - to.w) < 10 - && ! to_is_3way // force new path at 3way intersection - ) + else if (! force_new_path && shorterThen(generated_toolpaths[inset_idx].back().junctions.back().p - to.p, 10) && std::abs(generated_toolpaths[inset_idx].back().junctions.back().w - to.w) < 10 + && ! to_is_3way // force new path at 3way intersection + ) { - if ( ! is_odd) + if (! is_odd) { - logError("Reversing even wall line causes it to be printed CCW instead of CW!\n"); + spdlog::error("Reversing even wall line causes it to be printed CCW instead of CW!"); } generated_toolpaths[inset_idx].back().junctions.push_back(from); } @@ -1857,19 +1860,19 @@ void SkeletalTrapezoidation::addToolpathSegment(const ExtrusionJunction& from, c }; void SkeletalTrapezoidation::connectJunctions(ptr_vector_t& edge_junctions) -{ +{ std::unordered_set unprocessed_quad_starts(graph.edges.size() * 5 / 2); for (edge_t& edge : graph.edges) { - if (!edge.prev) + if (! edge.prev) { unprocessed_quad_starts.insert(&edge); } } - + std::unordered_set passed_odd_edges; - - while (!unprocessed_quad_starts.empty()) + + while (! unprocessed_quad_starts.empty()) { edge_t* poly_domain_start = *unprocessed_quad_starts.begin(); edge_t* quad_start = poly_domain_start; @@ -1884,10 +1887,11 @@ void SkeletalTrapezoidation::connectJunctions(ptr_vector_t& edge_ edge_t* edge_to_peak = getQuadMaxRedgeTo(quad_start); // walk down on both sides and connect junctions - edge_t* edge_from_peak = edge_to_peak->next; assert(edge_from_peak); - + edge_t* edge_from_peak = edge_to_peak->next; + assert(edge_from_peak); + unprocessed_quad_starts.erase(quad_start); - + if (! edge_to_peak->data.hasExtrusionJunctions()) { edge_junctions.emplace_back(std::make_shared()); @@ -1905,37 +1909,37 @@ void SkeletalTrapezoidation::connectJunctions(ptr_vector_t& edge_ if (edge_to_peak->prev) { LineJunctions from_prev_junctions = *edge_to_peak->prev->data.getExtrusionJunctions(); - while (!from_junctions.empty() && !from_prev_junctions.empty() && from_junctions.back().perimeter_index <= from_prev_junctions.front().perimeter_index) + while (! from_junctions.empty() && ! from_prev_junctions.empty() && from_junctions.back().perimeter_index <= from_prev_junctions.front().perimeter_index) { from_junctions.pop_back(); } from_junctions.reserve(from_junctions.size() + from_prev_junctions.size()); from_junctions.insert(from_junctions.end(), from_prev_junctions.begin(), from_prev_junctions.end()); - assert(!edge_to_peak->prev->prev); - if(edge_to_peak->prev->prev) + assert(! edge_to_peak->prev->prev); + if (edge_to_peak->prev->prev) { - RUN_ONCE(logWarning("The edge we're about to connect is already connected.")); + spdlog::warn("The edge we're about to connect is already connected."); } } if (edge_from_peak->next) { LineJunctions to_next_junctions = *edge_from_peak->next->twin->data.getExtrusionJunctions(); - while (!to_junctions.empty() && !to_next_junctions.empty() && to_junctions.back().perimeter_index <= to_next_junctions.front().perimeter_index) + while (! to_junctions.empty() && ! to_next_junctions.empty() && to_junctions.back().perimeter_index <= to_next_junctions.front().perimeter_index) { to_junctions.pop_back(); } to_junctions.reserve(to_junctions.size() + to_next_junctions.size()); to_junctions.insert(to_junctions.end(), to_next_junctions.begin(), to_next_junctions.end()); - assert(!edge_from_peak->next->next); - if(edge_from_peak->next->next) + assert(! edge_from_peak->next->next); + if (edge_from_peak->next->next) { - RUN_ONCE(logWarning("The edge we're about to connect is already connected!\n")); + spdlog::warn("The edge we're about to connect is already connected!"); } } assert(std::abs(int(from_junctions.size()) - int(to_junctions.size())) <= 1); // at transitions one end has more beads - if(std::abs(int(from_junctions.size()) - int(to_junctions.size())) > 1) + if (std::abs(int(from_junctions.size()) - int(to_junctions.size())) > 1) { - logWarning("Can't create a transition when connecting two perimeters where the number of beads differs too much! %i vs. %i", from_junctions.size(), to_junctions.size()); + spdlog::warn("Can't create a transition when connecting two perimeters where the number of beads differs too much! {} vs. {}", from_junctions.size(), to_junctions.size()); } size_t segment_count = std::min(from_junctions.size(), to_junctions.size()); @@ -1944,24 +1948,21 @@ void SkeletalTrapezoidation::connectJunctions(ptr_vector_t& edge_ ExtrusionJunction& from = from_junctions[from_junctions.size() - 1 - junction_rev_idx]; ExtrusionJunction& to = to_junctions[to_junctions.size() - 1 - junction_rev_idx]; assert(from.perimeter_index == to.perimeter_index); - if(from.perimeter_index != to.perimeter_index) + if (from.perimeter_index != to.perimeter_index) { - logWarning("Connecting two perimeters with different indices! Perimeter %i and %i", from.perimeter_index, to.perimeter_index); + spdlog::warn("Connecting two perimeters with different indices! Perimeter {} and {}", from.perimeter_index, to.perimeter_index); } - const bool from_is_odd = - quad_start->to->data.bead_count > 0 && quad_start->to->data.bead_count % 2 == 1 // quad contains single bead segment - && quad_start->to->data.transition_ratio == 0 // We're not in a transition - && junction_rev_idx == segment_count - 1 // Is single bead segment - && shorterThen(from.p - quad_start->to->p, 5); - const bool to_is_odd = - quad_end->from->data.bead_count > 0 && quad_end->from->data.bead_count % 2 == 1 // quad contains single bead segment - && quad_end->from->data.transition_ratio == 0 // We're not in a transition - && junction_rev_idx == segment_count - 1 // Is single bead segment - && shorterThen(to.p - quad_end->from->p, 5); + const bool from_is_odd = quad_start->to->data.bead_count > 0 && quad_start->to->data.bead_count % 2 == 1 // quad contains single bead segment + && quad_start->to->data.transition_ratio == 0 // We're not in a transition + && junction_rev_idx == segment_count - 1 // Is single bead segment + && shorterThen(from.p - quad_start->to->p, 5); + const bool to_is_odd = quad_end->from->data.bead_count > 0 && quad_end->from->data.bead_count % 2 == 1 // quad contains single bead segment + && quad_end->from->data.transition_ratio == 0 // We're not in a transition + && junction_rev_idx == segment_count - 1 // Is single bead segment + && shorterThen(to.p - quad_end->from->p, 5); const bool is_odd_segment = from_is_odd && to_is_odd; - - if (is_odd_segment - && passed_odd_edges.count(quad_start->next->twin) > 0) // Only generate toolpath for odd segments once + + if (is_odd_segment && passed_odd_edges.count(quad_start->next->twin) > 0) // Only generate toolpath for odd segments once { continue; // Prevent duplication of single bead segments } @@ -1974,8 +1975,7 @@ void SkeletalTrapezoidation::connectJunctions(ptr_vector_t& edge_ addToolpathSegment(from, to, is_odd_segment, new_domain_start, from_is_3way, to_is_3way); } new_domain_start = false; - } - while(quad_start = quad_start->getNextUnconnected(), quad_start != poly_domain_start); + } while (quad_start = quad_start->getNextUnconnected(), quad_start != poly_domain_start); } } @@ -1990,7 +1990,7 @@ void SkeletalTrapezoidation::generateLocalMaximaSingleBeads() continue; } Beading& beading = node.data.getBeading()->beading; - if (beading.bead_widths.size() % 2 == 1 && node.isLocalMaximum(true) && !node.isCentral()) + if (beading.bead_widths.size() % 2 == 1 && node.isLocalMaximum(true) && ! node.isCentral()) { const size_t inset_index = beading.bead_widths.size() / 2; constexpr bool is_odd = true; diff --git a/src/SkeletalTrapezoidationGraph.cpp b/src/SkeletalTrapezoidationGraph.cpp index 44034cd449..8bdfe603e3 100644 --- a/src/SkeletalTrapezoidationGraph.cpp +++ b/src/SkeletalTrapezoidationGraph.cpp @@ -1,16 +1,21 @@ -//Copyright (c) 2020 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include "SkeletalTrapezoidationGraph.h" + #include +#include + #include "utils/linearAlg2D.h" #include "utils/macros.h" namespace cura { -STHalfEdge::STHalfEdge(SkeletalTrapezoidationEdge data) : HalfEdge(data) {} +STHalfEdge::STHalfEdge(SkeletalTrapezoidationEdge data) : HalfEdge(data) +{ +} bool STHalfEdge::canGoUp(bool strict) const { @@ -30,8 +35,12 @@ bool STHalfEdge::canGoUp(bool strict) const { return true; } - assert(outgoing->twin); if (!outgoing->twin) return false; - assert(outgoing->twin->next); if (!outgoing->twin->next) return true; // This point is on the boundary?! Should never occur + assert(outgoing->twin); + if (! outgoing->twin) + return false; + assert(outgoing->twin->next); + if (! outgoing->twin->next) + return true; // This point is on the boundary?! Should never occur } return false; } @@ -94,8 +103,12 @@ std::optional STHalfEdge::distToGoUp() const ret = dist_to_up; } } - assert(outgoing->twin); if (!outgoing->twin) return std::optional(); - assert(outgoing->twin->next); if (!outgoing->twin->next) return 0; // This point is on the boundary?! Should never occur + assert(outgoing->twin); + if (! outgoing->twin) + return std::optional(); + assert(outgoing->twin->next); + if (! outgoing->twin->next) + return 0; // This point is on the boundary?! Should never occur } if (ret) { @@ -118,7 +131,9 @@ STHalfEdge* STHalfEdge::getNextUnconnected() return result->twin; } -STHalfEdgeNode::STHalfEdgeNode(SkeletalTrapezoidationJoint data, Point p) : HalfEdgeNode(data, p) {} +STHalfEdgeNode::STHalfEdgeNode(SkeletalTrapezoidationJoint data, Point p) : HalfEdgeNode(data, p) +{ +} bool STHalfEdgeNode::isMultiIntersection() { @@ -126,7 +141,7 @@ bool STHalfEdgeNode::isMultiIntersection() edge_t* outgoing = this->incident_edge; do { - if ( ! outgoing) + if (! outgoing) { // This is a node on the outside return false; } @@ -147,7 +162,9 @@ bool STHalfEdgeNode::isCentral() const { return true; } - assert(edge->twin); if (!edge->twin) return false; + assert(edge->twin); + if (! edge->twin) + return false; } while (edge = edge->twin->next, edge != incident_edge); return false; } @@ -166,35 +183,36 @@ bool STHalfEdgeNode::isLocalMaximum(bool strict) const { return false; } - assert(edge->twin); if (!edge->twin) return false; + assert(edge->twin); + if (! edge->twin) + return false; - if (!edge->twin->next) + if (! edge->twin->next) { // This point is on the boundary return false; } } while (edge = edge->twin->next, edge != incident_edge); return true; } - + void SkeletalTrapezoidationGraph::collapseSmallEdges(coord_t snap_dist) { std::unordered_map::iterator> edge_locator; std::unordered_map::iterator> node_locator; - + for (auto edge_it = edges.begin(); edge_it != edges.end(); ++edge_it) { edge_locator.emplace(&*edge_it, edge_it); } - + for (auto node_it = nodes.begin(); node_it != nodes.end(); ++node_it) { node_locator.emplace(&*node_it, node_it); } - + auto safelyRemoveEdge = [this, &edge_locator](edge_t* to_be_removed, std::list::iterator& current_edge_it, bool& edge_it_is_updated) { - if (current_edge_it != edges.end() - && to_be_removed == &*current_edge_it) + if (current_edge_it != edges.end() && to_be_removed == &*current_edge_it) { current_edge_it = edges.erase(current_edge_it); edge_it_is_updated = true; @@ -205,11 +223,8 @@ void SkeletalTrapezoidationGraph::collapseSmallEdges(coord_t snap_dist) } }; - auto should_collapse = [snap_dist](node_t* a, node_t* b) - { - return shorterThen(a->p - b->p, snap_dist); - }; - + auto should_collapse = [snap_dist](node_t* a, node_t* b) { return shorterThen(a->p - b->p, snap_dist); }; + for (auto edge_it = edges.begin(); edge_it != edges.end();) { if (edge_it->prev) @@ -217,19 +232,21 @@ void SkeletalTrapezoidationGraph::collapseSmallEdges(coord_t snap_dist) edge_it++; continue; } - + edge_t* quad_start = &*edge_it; - edge_t* quad_end = quad_start; while (quad_end->next) quad_end = quad_end->next; - edge_t* quad_mid = (quad_start->next == quad_end)? nullptr : quad_start->next; + edge_t* quad_end = quad_start; + while (quad_end->next) + quad_end = quad_end->next; + edge_t* quad_mid = (quad_start->next == quad_end) ? nullptr : quad_start->next; bool edge_it_is_updated = false; if (quad_mid && should_collapse(quad_mid->from, quad_mid->to)) { assert(quad_mid->twin); - if(!quad_mid->twin) + if (! quad_mid->twin) { - RUN_ONCE(logWarning("Encountered quad edge without a twin.")); - continue; //Prevent accessing unallocated memory. + spdlog::warn("Encountered quad edge without a twin."); + continue; // Prevent accessing unallocated memory. } int count = 0; for (edge_t* edge_from_3 = quad_end; edge_from_3 && edge_from_3 != quad_mid->twin; edge_from_3 = edge_from_3->twin->next) @@ -240,7 +257,7 @@ void SkeletalTrapezoidationGraph::collapseSmallEdges(coord_t snap_dist) { std::cerr << edge_from_3->from->p << " - " << edge_from_3->to->p << '\n'; } - if (++count > 1000) + if (++count > 1000) { break; } @@ -262,7 +279,7 @@ void SkeletalTrapezoidationGraph::collapseSmallEdges(coord_t snap_dist) quad_mid->from->incident_edge = quad_mid->prev->twin; } } - + nodes.erase(node_locator[quad_mid->to]); quad_mid->prev->next = quad_mid->next; @@ -277,7 +294,7 @@ void SkeletalTrapezoidationGraph::collapseSmallEdges(coord_t snap_dist) // o-o // | | > collapse sides // o o - if ( should_collapse(quad_start->from, quad_end->to) && should_collapse(quad_start->to, quad_end->from)) + if (should_collapse(quad_start->from, quad_end->to) && should_collapse(quad_start->to, quad_end->from)) { // Collapse start and end edges and remove whole cell quad_start->twin->to = quad_end->to; @@ -304,7 +321,7 @@ void SkeletalTrapezoidationGraph::collapseSmallEdges(coord_t snap_dist) // if we would collapse that one edge then that would change the quad_start and/or quad_end of neighboring cells // this is to do with the constraint that !prev == !twin.next - if (!edge_it_is_updated) + if (! edge_it_is_updated) { edge_it++; } @@ -321,12 +338,12 @@ void SkeletalTrapezoidationGraph::makeRib(edge_t*& prev_edge, Point start_source nodes.emplace_front(SkeletalTrapezoidationJoint(), p); node_t* node = &nodes.front(); node->data.distance_to_boundary = 0; - + edges.emplace_front(SkeletalTrapezoidationEdge(SkeletalTrapezoidationEdge::EdgeType::EXTRA_VD)); edge_t* forth_edge = &edges.front(); edges.emplace_front(SkeletalTrapezoidationEdge(SkeletalTrapezoidationEdge::EdgeType::EXTRA_VD)); edge_t* back_edge = &edges.front(); - + prev_edge->next = forth_edge; forth_edge->prev = prev_edge; forth_edge->from = prev_edge->to; @@ -336,7 +353,7 @@ void SkeletalTrapezoidationGraph::makeRib(edge_t*& prev_edge, Point start_source back_edge->from = node; back_edge->to = prev_edge->to; node->incident_edge = back_edge; - + prev_edge = back_edge; } @@ -346,7 +363,7 @@ std::pairp; std::pair source_segment = getSource(edge); @@ -377,7 +394,7 @@ std::pairnext = second; second->next = edge_after; - if (edge_after) + if (edge_after) { edge_after->prev = second; } @@ -399,7 +416,7 @@ std::pairincident_edge = first; mid_node->incident_edge = outward_edge; source_node->incident_edge = inward_edge; - if (edge_after) + if (edge_after) { node_after->incident_edge = edge_after; } @@ -450,18 +467,18 @@ SkeletalTrapezoidationGraph::edge_t* SkeletalTrapezoidationGraph::insertNode(edg std::pair SkeletalTrapezoidationGraph::getSource(const edge_t& edge) { const edge_t* from_edge = &edge; - while(from_edge->prev) + while (from_edge->prev) { from_edge = from_edge->prev; } const edge_t* to_edge = &edge; - while(to_edge->next) + while (to_edge->next) { to_edge = to_edge->next; } - + return std::make_pair(from_edge->from->p, to_edge->to->p); } -} +} // namespace cura diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 4675b50c6f..9313f98e99 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -1,24 +1,25 @@ -//Copyright (C) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher + +#include #include "Application.h" #include "ExtruderTrain.h" #include "SkirtBrim.h" #include "Slice.h" +#include "settings/types/Ratio.h" #include "sliceDataStorage.h" -#include "utils/logoutput.h" -#include "utils/Simplify.h" //Simplifying the brim/skirt at every inset. #include "support.h" -#include "settings/types/Ratio.h" +#include "utils/Simplify.h" //Simplifying the brim/skirt at every inset. -namespace cura +namespace cura { void SkirtBrim::getFirstLayerOutline(SliceDataStorage& storage, const size_t primary_line_count, const bool is_skirt, Polygons& first_layer_outline) { const ExtruderTrain& train = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("skirt_brim_extruder_nr"); const ExtruderTrain& support_infill_extruder = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("support_infill_extruder_nr"); - const bool external_only = is_skirt || train.settings.get("brim_outside_only"); //Whether to include holes or not. Skirt doesn't have any holes. + const bool external_only = is_skirt || train.settings.get("brim_outside_only"); // Whether to include holes or not. Skirt doesn't have any holes. const LayerIndex layer_nr = 0; if (is_skirt) { @@ -29,19 +30,19 @@ void SkirtBrim::getFirstLayerOutline(SliceDataStorage& storage, const size_t pri } else { // add brim underneath support by removing support where there's brim around the model - constexpr bool include_support = false; //Include manually below. - constexpr bool include_prime_tower = false; //Include manually below. - constexpr bool external_outlines_only = false; //Remove manually below. + constexpr bool include_support = false; // Include manually below. + constexpr bool include_prime_tower = false; // Include manually below. + constexpr bool external_outlines_only = false; // Remove manually below. constexpr bool for_brim = true; first_layer_outline = storage.getLayerOutlines(layer_nr, include_support, include_prime_tower, external_outlines_only, for_brim); - first_layer_outline = first_layer_outline.unionPolygons(); //To guard against overlapping outlines, which would produce holes according to the even-odd rule. + first_layer_outline = first_layer_outline.unionPolygons(); // To guard against overlapping outlines, which would produce holes according to the even-odd rule. Polygons first_layer_empty_holes; if (external_only) { first_layer_empty_holes = first_layer_outline.getEmptyHoles(); first_layer_outline = first_layer_outline.removeEmptyHoles(); } - if (storage.support.generated && primary_line_count > 0 && !storage.support.supportLayers.empty()) + if (storage.support.generated && primary_line_count > 0 && ! storage.support.supportLayers.empty()) { // remove model-brim from support SupportLayer& support_layer = storage.support.supportLayers[0]; if (support_infill_extruder.settings.get("brim_replaces_support")) @@ -54,7 +55,8 @@ void SkirtBrim::getFirstLayerOutline(SliceDataStorage& storage, const size_t pri // |+-+| |+--+| // +---+ +----+ const coord_t primary_extruder_skirt_brim_line_width = train.settings.get("skirt_brim_line_width") * train.settings.get("initial_layer_line_width_factor"); - Polygons model_brim_covered_area = first_layer_outline.offset(primary_extruder_skirt_brim_line_width * (primary_line_count + primary_line_count % 2), ClipperLib::jtRound); // always leave a gap of an even number of brim lines, so that it fits if it's generating brim from both sides + Polygons model_brim_covered_area = first_layer_outline.offset(primary_extruder_skirt_brim_line_width * (primary_line_count + primary_line_count % 2), + ClipperLib::jtRound); // always leave a gap of an even number of brim lines, so that it fits if it's generating brim from both sides if (external_only) { // don't remove support within empty holes where no brim is generated. model_brim_covered_area.add(first_layer_empty_holes); @@ -72,7 +74,7 @@ void SkirtBrim::getFirstLayerOutline(SliceDataStorage& storage, const size_t pri first_layer_outline.add(support_layer.support_bottom); first_layer_outline.add(support_layer.support_roof); } - if (storage.primeTower.enabled && !train.settings.get("prime_tower_brim_enable")) + if (storage.primeTower.enabled && ! train.settings.get("prime_tower_brim_enable")) { first_layer_outline.add(storage.primeTower.outer_poly_first_layer); // don't remove parts of the prime tower, but make a brim for it } @@ -82,9 +84,9 @@ void SkirtBrim::getFirstLayerOutline(SliceDataStorage& storage, const size_t pri constexpr coord_t smallest_line_length = 200; constexpr coord_t largest_error_of_removed_point = 50; first_layer_outline = Simplify(smallest_line_length, largest_error_of_removed_point, 0).polygon(first_layer_outline); - if(first_layer_outline.size() == 0) + if (first_layer_outline.size() == 0) { - logError("Couldn't generate skirt / brim! No polygons on first layer.\n"); + spdlog::error("Couldn't generate skirt / brim! No polygons on first layer."); } } @@ -99,7 +101,7 @@ coord_t SkirtBrim::generatePrimarySkirtBrimLines(const coord_t start_distance, s Polygons outer_skirt_brim_line = first_layer_outline.offset(offset_distance, ClipperLib::jtRound); - //Remove small inner skirt and brim holes. Holes have a negative area, remove anything smaller then 100x extrusion "area" + // Remove small inner skirt and brim holes. Holes have a negative area, remove anything smaller then 100x extrusion "area" for (unsigned int n = 0; n < outer_skirt_brim_line.size(); n++) { double area = outer_skirt_brim_line[n].area(); @@ -112,7 +114,7 @@ coord_t SkirtBrim::generatePrimarySkirtBrimLines(const coord_t start_distance, s skirt_brim_primary_extruder.add(outer_skirt_brim_line); const coord_t length = skirt_brim_primary_extruder.polygonLength(); - if (skirt_brim_number + 1 >= primary_line_count && length > 0 && length < primary_extruder_minimal_length) //Make brim or skirt have more lines when total length is too small. + if (skirt_brim_number + 1 >= primary_line_count && length > 0 && length < primary_extruder_minimal_length) // Make brim or skirt have more lines when total length is too small. { primary_line_count++; } @@ -160,12 +162,12 @@ void SkirtBrim::generate(SliceDataStorage& storage, Polygons first_layer_outline const ExtruderTrain& support_infill_extruder = scene.current_mesh_group->settings.get("support_infill_extruder_nr"); if (allow_helpers && support_infill_extruder.settings.get("support_brim_enable")) { - const bool merge_with_model_skirtbrim = !is_skirt; + const bool merge_with_model_skirtbrim = ! is_skirt; generateSupportBrim(storage, merge_with_model_skirtbrim); } // generate brim for ooze shield and draft shield - if (!is_skirt && (has_ooze_shield || has_draft_shield)) + if (! is_skirt && (has_ooze_shield || has_draft_shield)) { // generate areas where to make extra brim for the shields // avoid gap in the middle @@ -174,7 +176,7 @@ void SkirtBrim::generate(SliceDataStorage& storage, Polygons first_layer_outline // |+-+| |+--+| // || || ||[]|| > expand to fit an extra brim line // |+-+| |+--+| - // +---+ +----+ + // +---+ +----+ const coord_t primary_skirt_brim_width = (primary_line_count + primary_line_count % 2) * primary_extruder_skirt_brim_line_width; // always use an even number, because we will fil the area from both sides Polygons shield_brim; @@ -217,14 +219,14 @@ void SkirtBrim::generate(SliceDataStorage& storage, Polygons first_layer_outline std::vector extruder_is_used = storage.getExtrudersUsed(); for (size_t extruder_nr = 0; extruder_nr < Application::getInstance().current_slice->scene.extruders.size(); extruder_nr++) { - if (extruder_nr == skirt_brim_extruder_nr || !extruder_is_used[extruder_nr]) + if (extruder_nr == skirt_brim_extruder_nr || ! extruder_is_used[extruder_nr]) { continue; } const ExtruderTrain& train = Application::getInstance().current_slice->scene.extruders[extruder_nr]; const coord_t width = train.settings.get("skirt_brim_line_width") * train.settings.get("initial_layer_line_width_factor"); const coord_t minimal_length = train.settings.get("skirt_brim_minimal_length"); - offset_distance += last_width / 2 + width/2; + offset_distance += last_width / 2 + width / 2; last_width = width; while (storage.skirt_brim[extruder_nr].polygonLength() < minimal_length) { @@ -244,7 +246,7 @@ void SkirtBrim::generateSupportBrim(SliceDataStorage& storage, const bool merge_ const coord_t brim_line_width = support_infill_extruder.settings.get("skirt_brim_line_width") * support_infill_extruder.settings.get("initial_layer_line_width_factor"); size_t line_count = support_infill_extruder.settings.get("support_brim_line_count"); const coord_t minimal_length = support_infill_extruder.settings.get("skirt_brim_minimal_length"); - if (!storage.support.generated || line_count <= 0 || storage.support.supportLayers.empty()) + if (! storage.support.generated || line_count <= 0 || storage.support.supportLayers.empty()) { return; } @@ -271,7 +273,7 @@ void SkirtBrim::generateSupportBrim(SliceDataStorage& storage, const bool merge_ Polygons brim_line = support_outline.offset(offset_distance, ClipperLib::jtRound); - //Remove small inner skirt and brim holes. Holes have a negative area, remove anything smaller then multiplier x extrusion "area" + // Remove small inner skirt and brim holes. Holes have a negative area, remove anything smaller then multiplier x extrusion "area" for (size_t n = 0; n < brim_line.size(); n++) { const double area = brim_line[n].area(); @@ -284,7 +286,7 @@ void SkirtBrim::generateSupportBrim(SliceDataStorage& storage, const bool merge_ support_brim.add(brim_line); const coord_t length = skirt_brim.polygonLength() + support_brim.polygonLength(); - if (skirt_brim_number + 1 >= line_count && length > 0 && length < minimal_length) //Make brim or skirt have more lines when total length is too small. + if (skirt_brim_number + 1 >= line_count && length > 0 && length < minimal_length) // Make brim or skirt have more lines when total length is too small. { line_count++; } @@ -312,4 +314,4 @@ void SkirtBrim::generateSupportBrim(SliceDataStorage& storage, const bool merge_ } } -}//namespace cura +} // namespace cura diff --git a/src/Slice.cpp b/src/Slice.cpp index 2d5287949f..994e3810fb 100644 --- a/src/Slice.cpp +++ b/src/Slice.cpp @@ -1,20 +1,21 @@ -//Copyright (c) 2018 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher + +#include #include "ExtruderTrain.h" #include "Slice.h" -#include "utils/logoutput.h" namespace cura { -Slice::Slice(const size_t num_mesh_groups) -: scene(num_mesh_groups) -{} +Slice::Slice(const size_t num_mesh_groups) : scene(num_mesh_groups) +{ +} void Slice::compute() { - logWarning("%s", scene.getAllSettingsString().c_str()); + spdlog::debug("All settings: {}", scene.getAllSettingsString()); for (std::vector::iterator mesh_group = scene.mesh_groups.begin(); mesh_group != scene.mesh_groups.end(); mesh_group++) { scene.current_mesh_group = mesh_group; @@ -33,4 +34,4 @@ void Slice::reset() scene.settings = Settings(); } -} \ No newline at end of file +} // namespace cura \ No newline at end of file diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 678ccf05fc..94c4b14b71 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -1,6 +1,9 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher + +// Code smell: Order of the includes is important here, probably due to some forward declarations which might be masking some undefined behaviours +// clang-format off #include "Application.h" //To get settings. #include "ExtruderTrain.h" #include "Slice.h" @@ -12,23 +15,23 @@ #include "settings/types/Ratio.h" #include "utils/ThreadPool.h" #include "utils/IntPoint.h" //To normalize vectors. -#include "utils/logoutput.h" #include "utils/math.h" //For round_up_divide and PI. #include "utils/MinimumSpanningTree.h" //For connecting the correct nodes together to form an efficient tree. #include "utils/polygon.h" //For splitting polygons into parts. #include "utils/polygonUtils.h" //For moveInside. #include "utils/Simplify.h" //Reduce the resolution of small branches. +// clang-format on #include #include -#define SQRT_2 1.4142135623730950488 //Square root of 2. -#define CIRCLE_RESOLUTION 10 //The number of vertices in each circle. +#define SQRT_2 1.4142135623730950488 // Square root of 2. +#define CIRCLE_RESOLUTION 10 // The number of vertices in each circle. -//The various stages of the process can be weighted differently in the progress bar. -//These weights are obtained experimentally. -#define PROGRESS_WEIGHT_DROPDOWN 50 //Dropping down support. -#define PROGRESS_WEIGHT_AREAS 1 //Creating support areas. +// The various stages of the process can be weighted differently in the progress bar. +// These weights are obtained experimentally. +#define PROGRESS_WEIGHT_DROPDOWN 50 // Dropping down support. +#define PROGRESS_WEIGHT_AREAS 1 // Creating support areas. namespace cura { @@ -42,22 +45,16 @@ TreeSupport::TreeSupport(const SliceDataStorage& storage) void TreeSupport::generateSupportAreas(SliceDataStorage& storage) { const Settings& group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; - const bool global_use_tree_support = - group_settings.get("support_enable")&& - group_settings.get("support_structure") == ESupportStructure::TREE; - - if (!(global_use_tree_support || - std::any_of(storage.meshes.cbegin(), - storage.meshes.cend(), - [](const SliceMeshStorage& m) { - return m.settings.get("support_enable") && - m.settings.get("support_structure") == ESupportStructure::TREE; - }))) + const bool global_use_tree_support = group_settings.get("support_enable") && group_settings.get("support_structure") == ESupportStructure::TREE; + + if (! (global_use_tree_support + || std::any_of( + storage.meshes.cbegin(), storage.meshes.cend(), [](const SliceMeshStorage& m) { return m.settings.get("support_enable") && m.settings.get("support_structure") == ESupportStructure::TREE; }))) { return; } - std::vector> contact_nodes(storage.support.supportLayers.size()); //Generate empty layers to store the points in. + std::vector> contact_nodes(storage.support.supportLayers.size()); // Generate empty layers to store the points in. for (SliceMeshStorage& mesh : storage.meshes) { if (mesh.settings.get("support_structure") == ESupportStructure::TREE) @@ -66,10 +63,10 @@ void TreeSupport::generateSupportAreas(SliceDataStorage& storage) } } - //Drop nodes to lower layers. + // Drop nodes to lower layers. dropNodes(contact_nodes); - //Generate support areas. + // Generate support areas. drawCircles(storage, contact_nodes); for (auto& layer : contact_nodes) @@ -90,146 +87,147 @@ void TreeSupport::drawCircles(SliceDataStorage& storage, const std::vectorscene.current_mesh_group->settings; const coord_t branch_radius = mesh_group_settings.get("support_tree_branch_diameter") / 2; const size_t wall_count = mesh_group_settings.get("support_wall_count"); - Polygon branch_circle = PolygonUtils::makeCircle(Point(0, 0), branch_radius, TAU / CIRCLE_RESOLUTION); //Pre-generate a circle with correct diameter so that we don't have to recompute those (co)sines every time. - const coord_t circle_side_length = 2 * branch_radius * sin(M_PI / CIRCLE_RESOLUTION); //Side length of a regular polygon. + Polygon branch_circle = PolygonUtils::makeCircle(Point(0, 0), branch_radius, TAU / CIRCLE_RESOLUTION); // Pre-generate a circle with correct diameter so that we don't have to recompute those (co)sines every time. + const coord_t circle_side_length = 2 * branch_radius * sin(M_PI / CIRCLE_RESOLUTION); // Side length of a regular polygon. const coord_t z_distance_bottom = mesh_group_settings.get("support_bottom_distance"); const coord_t layer_height = mesh_group_settings.get("layer_height"); const size_t z_distance_bottom_layers = round_up_divide(z_distance_bottom, layer_height) > 0 ? round_up_divide(z_distance_bottom, layer_height) : 1; - const double diameter_angle_scale_factor = sin(mesh_group_settings.get("support_tree_branch_diameter_angle")) * layer_height / branch_radius; //Scale factor per layer to produce the desired angle. + const double diameter_angle_scale_factor = sin(mesh_group_settings.get("support_tree_branch_diameter_angle")) * layer_height / branch_radius; // Scale factor per layer to produce the desired angle. const coord_t line_width = mesh_group_settings.get("support_line_width"); - const coord_t minimum_tip_radius = line_width / 2 * 1.5; //End up slightly wider than 1 line width in the tip. - const size_t tip_layers = (branch_radius - minimum_tip_radius) / layer_height; //The number of layers to be shrinking the circle to create a tip. This produces a 45 degree angle. + const coord_t minimum_tip_radius = line_width / 2 * 1.5; // End up slightly wider than 1 line width in the tip. + const size_t tip_layers = (branch_radius - minimum_tip_radius) / layer_height; // The number of layers to be shrinking the circle to create a tip. This produces a 45 degree angle. const coord_t resolution = mesh_group_settings.get("support_tree_collision_resolution"); - size_t completed = 0; //To track progress, should be locked when altered. + size_t completed = 0; // To track progress, should be locked when altered. std::mutex critical_section_volumes; std::mutex critical_section_progress; - cura::parallel_for(0, contact_nodes.size(), [&](const size_t layer_nr) - { - Polygons support_layer; - Polygons& roof_layer = storage.support.supportLayers[layer_nr].support_roof; - - //Draw the support areas and add the roofs appropriately to the support roof instead of normal areas. - for (const Node* p_node : contact_nodes[layer_nr]) - { - const Node& node = *p_node; - - Polygon circle; - //Scale linearly between branch radius and 1 line width. - //At the tip we want to end up at 1 line width diameter so that the tip still prints if you have 1 support wall. - const double ratio_to_tip = static_cast(node.distance_to_top) / tip_layers; - const double scale = (minimum_tip_radius + ratio_to_tip * (branch_radius - minimum_tip_radius)) / branch_radius; - for (Point corner : branch_circle) - { - if (node.distance_to_top < tip_layers) //We're in the tip. - { - const int mul = node.skin_direction ? 1 : -1; - corner = Point(corner.X * (0.5 + scale / 2) + mul * corner.Y * (0.5 - scale / 2), - mul * corner.X * (0.5 - scale / 2) + corner.Y * (0.5 + scale / 2)); - } - else - { - corner = corner * (1 + static_cast(node.distance_to_top - tip_layers) * diameter_angle_scale_factor); - } - circle.add(node.position + corner); - } - if (node.support_roof_layers_below > 0) - { - roof_layer.add(circle); - } - else - { - support_layer.add(circle); - } - } - support_layer = support_layer.unionPolygons(); - roof_layer = roof_layer.unionPolygons(); - const size_t z_collision_layer = static_cast(std::max(0, static_cast(layer_nr) - static_cast(z_distance_bottom_layers) + 1)); //Layer to test against to create a Z-distance. - { - const std::lock_guard lock(critical_section_volumes); - - support_layer = support_layer.difference(volumes_.getCollision(0, z_collision_layer)); //Subtract the model itself (sample 0 is with 0 diameter but proper X/Y offset). - roof_layer = roof_layer.difference(volumes_.getCollision(0, z_collision_layer)); - } - support_layer = support_layer.difference(roof_layer); - //We smooth this support as much as possible without altering single circles. So we remove any line less than the side length of those circles. - const double diameter_angle_scale_factor_this_layer = static_cast(storage.support.supportLayers.size() - layer_nr - tip_layers) * diameter_angle_scale_factor; //Maximum scale factor. - //Don't deviate more than the collision resolution so that the lines still stack properly. - support_layer = Simplify(circle_side_length * (1 + diameter_angle_scale_factor_this_layer), resolution, 0).polygon(support_layer); - - //Subtract support floors. - if (mesh_group_settings.get("support_bottom_enable")) - { - Polygons& floor_layer = storage.support.supportLayers[layer_nr].support_bottom; - const coord_t support_interface_resolution = mesh_group_settings.get("support_interface_skip_height"); - const size_t support_interface_skip_layers = round_up_divide(support_interface_resolution, layer_height); - const coord_t support_bottom_height = mesh_group_settings.get("support_bottom_height"); - const size_t support_bottom_height_layers = round_up_divide(support_bottom_height, layer_height); - for(size_t layers_below = 0; layers_below < support_bottom_height_layers; layers_below += support_interface_skip_layers) - { - const size_t sample_layer = static_cast(std::max(0, static_cast(layer_nr) - static_cast(layers_below) - static_cast(z_distance_bottom_layers))); - constexpr bool no_support = false; - constexpr bool no_prime_tower = false; - floor_layer.add(support_layer.intersection(storage.getLayerOutlines(sample_layer, no_support, no_prime_tower))); - } - { //One additional sample at the complete bottom height. - const size_t sample_layer = static_cast(std::max(0, static_cast(layer_nr) - static_cast(support_bottom_height_layers) - static_cast(z_distance_bottom_layers))); - constexpr bool no_support = false; - constexpr bool no_prime_tower = false; - floor_layer.add(support_layer.intersection(storage.getLayerOutlines(sample_layer, no_support, no_prime_tower))); - } - floor_layer = floor_layer.unionPolygons(); - support_layer = support_layer.difference(floor_layer.offset(10)); //Subtract the support floor from the normal support. - } - - std::vector support_layer_parts = support_layer.splitIntoParts(); - for (PolygonsPart& part : support_layer_parts) //Convert every part into a PolygonsPart for the support. - { - storage.support.supportLayers[layer_nr].support_infill_parts.emplace_back(part, line_width, wall_count); - } - - { - const std::lock_guard lock(critical_section_progress); - - if (!storage.support.supportLayers[layer_nr].support_infill_parts.empty() || !storage.support.supportLayers[layer_nr].support_roof.empty()) - { - storage.support.layer_nr_max_filled_layer = std::max(storage.support.layer_nr_max_filled_layer, static_cast(layer_nr)); - } - - ++completed; - const double progress_contact_nodes = contact_nodes.size() * PROGRESS_WEIGHT_DROPDOWN; - const double progress_current = completed * PROGRESS_WEIGHT_AREAS; - const double progress_total = completed * PROGRESS_WEIGHT_AREAS; - Progress::messageProgress(Progress::Stage::SUPPORT, progress_contact_nodes + progress_current, progress_contact_nodes + progress_total); - } - }); + cura::parallel_for(0, + contact_nodes.size(), + [&](const size_t layer_nr) + { + Polygons support_layer; + Polygons& roof_layer = storage.support.supportLayers[layer_nr].support_roof; + + // Draw the support areas and add the roofs appropriately to the support roof instead of normal areas. + for (const Node* p_node : contact_nodes[layer_nr]) + { + const Node& node = *p_node; + + Polygon circle; + // Scale linearly between branch radius and 1 line width. + // At the tip we want to end up at 1 line width diameter so that the tip still prints if you have 1 support wall. + const double ratio_to_tip = static_cast(node.distance_to_top) / tip_layers; + const double scale = (minimum_tip_radius + ratio_to_tip * (branch_radius - minimum_tip_radius)) / branch_radius; + for (Point corner : branch_circle) + { + if (node.distance_to_top < tip_layers) // We're in the tip. + { + const int mul = node.skin_direction ? 1 : -1; + corner = Point(corner.X * (0.5 + scale / 2) + mul * corner.Y * (0.5 - scale / 2), mul * corner.X * (0.5 - scale / 2) + corner.Y * (0.5 + scale / 2)); + } + else + { + corner = corner * (1 + static_cast(node.distance_to_top - tip_layers) * diameter_angle_scale_factor); + } + circle.add(node.position + corner); + } + if (node.support_roof_layers_below > 0) + { + roof_layer.add(circle); + } + else + { + support_layer.add(circle); + } + } + support_layer = support_layer.unionPolygons(); + roof_layer = roof_layer.unionPolygons(); + const size_t z_collision_layer = static_cast(std::max(0, static_cast(layer_nr) - static_cast(z_distance_bottom_layers) + 1)); // Layer to test against to create a Z-distance. + { + const std::lock_guard lock(critical_section_volumes); + + support_layer = support_layer.difference(volumes_.getCollision(0, z_collision_layer)); // Subtract the model itself (sample 0 is with 0 diameter but proper X/Y offset). + roof_layer = roof_layer.difference(volumes_.getCollision(0, z_collision_layer)); + } + support_layer = support_layer.difference(roof_layer); + // We smooth this support as much as possible without altering single circles. So we remove any line less than the side length of those circles. + const double diameter_angle_scale_factor_this_layer = static_cast(storage.support.supportLayers.size() - layer_nr - tip_layers) * diameter_angle_scale_factor; // Maximum scale factor. + // Don't deviate more than the collision resolution so that the lines still stack properly. + support_layer = Simplify(circle_side_length * (1 + diameter_angle_scale_factor_this_layer), resolution, 0).polygon(support_layer); + + // Subtract support floors. + if (mesh_group_settings.get("support_bottom_enable")) + { + Polygons& floor_layer = storage.support.supportLayers[layer_nr].support_bottom; + const coord_t support_interface_resolution = mesh_group_settings.get("support_interface_skip_height"); + const size_t support_interface_skip_layers = round_up_divide(support_interface_resolution, layer_height); + const coord_t support_bottom_height = mesh_group_settings.get("support_bottom_height"); + const size_t support_bottom_height_layers = round_up_divide(support_bottom_height, layer_height); + for (size_t layers_below = 0; layers_below < support_bottom_height_layers; layers_below += support_interface_skip_layers) + { + const size_t sample_layer = static_cast(std::max(0, static_cast(layer_nr) - static_cast(layers_below) - static_cast(z_distance_bottom_layers))); + constexpr bool no_support = false; + constexpr bool no_prime_tower = false; + floor_layer.add(support_layer.intersection(storage.getLayerOutlines(sample_layer, no_support, no_prime_tower))); + } + { // One additional sample at the complete bottom height. + const size_t sample_layer = static_cast(std::max(0, static_cast(layer_nr) - static_cast(support_bottom_height_layers) - static_cast(z_distance_bottom_layers))); + constexpr bool no_support = false; + constexpr bool no_prime_tower = false; + floor_layer.add(support_layer.intersection(storage.getLayerOutlines(sample_layer, no_support, no_prime_tower))); + } + floor_layer = floor_layer.unionPolygons(); + support_layer = support_layer.difference(floor_layer.offset(10)); // Subtract the support floor from the normal support. + } + + std::vector support_layer_parts = support_layer.splitIntoParts(); + for (PolygonsPart& part : support_layer_parts) // Convert every part into a PolygonsPart for the support. + { + storage.support.supportLayers[layer_nr].support_infill_parts.emplace_back(part, line_width, wall_count); + } + + { + const std::lock_guard lock(critical_section_progress); + + if (! storage.support.supportLayers[layer_nr].support_infill_parts.empty() || ! storage.support.supportLayers[layer_nr].support_roof.empty()) + { + storage.support.layer_nr_max_filled_layer = std::max(storage.support.layer_nr_max_filled_layer, static_cast(layer_nr)); + } + + ++completed; + const double progress_contact_nodes = contact_nodes.size() * PROGRESS_WEIGHT_DROPDOWN; + const double progress_current = completed * PROGRESS_WEIGHT_AREAS; + const double progress_total = completed * PROGRESS_WEIGHT_AREAS; + Progress::messageProgress(Progress::Stage::SUPPORT, progress_contact_nodes + progress_current, progress_contact_nodes + progress_total); + } + }); } void TreeSupport::dropNodes(std::vector>& contact_nodes) { const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; - //Use Minimum Spanning Tree to connect the points on each layer and move them while dropping them down. + // Use Minimum Spanning Tree to connect the points on each layer and move them while dropping them down. const coord_t layer_height = mesh_group_settings.get("layer_height"); const auto support_xy_distance = mesh_group_settings.get("support_xy_distance"); const double angle = mesh_group_settings.get("support_tree_angle"); const coord_t maximum_move_distance = angle < 90 ? static_cast(tan(angle) * layer_height) : std::numeric_limits::max(); const coord_t branch_radius = mesh_group_settings.get("support_tree_branch_diameter") / 2; - const size_t tip_layers = branch_radius / layer_height; //The number of layers to be shrinking the circle to create a tip. This produces a 45 degree angle. - const double diameter_angle_scale_factor = sin(mesh_group_settings.get("support_tree_branch_diameter_angle")) * layer_height / branch_radius; //Scale factor per layer to produce the desired angle. + const size_t tip_layers = branch_radius / layer_height; // The number of layers to be shrinking the circle to create a tip. This produces a 45 degree angle. + const double diameter_angle_scale_factor = sin(mesh_group_settings.get("support_tree_branch_diameter_angle")) * layer_height / branch_radius; // Scale factor per layer to produce the desired angle. const coord_t radius_sample_resolution = mesh_group_settings.get("support_tree_collision_resolution"); const bool support_rests_on_model = mesh_group_settings.get("support_type") == ESupportType::EVERYWHERE; std::unordered_set to_free_node_set; - for (size_t layer_nr = contact_nodes.size() - 1; layer_nr > 0; layer_nr--) //Skip layer 0, since we can't drop down the vertices there. + for (size_t layer_nr = contact_nodes.size() - 1; layer_nr > 0; layer_nr--) // Skip layer 0, since we can't drop down the vertices there. { auto& layer_contact_nodes = contact_nodes[layer_nr]; std::deque> unsupported_branch_leaves; // All nodes that are leaves on this layer that would result in unsupported ('mid-air') branches. - //Group together all nodes for each part. + // Group together all nodes for each part. std::vector parts = volumes_.getAvoidance(support_xy_distance, layer_nr).splitIntoParts(); std::vector> nodes_per_part; - nodes_per_part.emplace_back(); //All nodes that aren't inside a part get grouped together in the 0th part. + nodes_per_part.emplace_back(); // All nodes that aren't inside a part get grouped together in the 0th part. for (size_t part_index = 0; part_index < parts.size(); part_index++) { nodes_per_part.emplace_back(); @@ -238,12 +236,12 @@ void TreeSupport::dropNodes(std::vector>& contact_nodes) { const Node& node = *p_node; - if (!support_rests_on_model && !node.to_buildplate) //Can't rest on model and unable to reach the build plate. Then we must drop the node and leave parts unsupported. + if (! support_rests_on_model && ! node.to_buildplate) // Can't rest on model and unable to reach the build plate. Then we must drop the node and leave parts unsupported. { unsupported_branch_leaves.push_front({ layer_nr, p_node }); continue; } - if (node.to_buildplate || parts.empty()) //It's outside, so make it go towards the build plate. + if (node.to_buildplate || parts.empty()) // It's outside, so make it go towards the build plate. { nodes_per_part[0][node.position] = p_node; continue; @@ -262,7 +260,7 @@ void TreeSupport::dropNodes(std::vector>& contact_nodes) for (size_t part_index = 0; part_index < parts.size(); part_index++) { constexpr bool border_result = true; - if (parts[part_index].inside(node.position, border_result)) //If it's inside, the distance is 0 and this part is considered the best. + if (parts[part_index].inside(node.position, border_result)) // If it's inside, the distance is 0 and this part is considered the best. { closest_part = part_index; closest_part_distance2 = 0; @@ -276,18 +274,17 @@ void TreeSupport::dropNodes(std::vector>& contact_nodes) closest_part = part_index; } } - //Put it in the best one. - nodes_per_part[closest_part + 1][node.position] = p_node; //Index + 1 because the 0th index is the outside part. - + // Put it in the best one. + nodes_per_part[closest_part + 1][node.position] = p_node; // Index + 1 because the 0th index is the outside part. } - //Create a MST for every part. + // Create a MST for every part. std::vector spanning_trees; for (const std::unordered_map& group : nodes_per_part) { std::vector points_to_buildplate; for (const std::pair& entry : group) { - points_to_buildplate.emplace_back(entry.first); //Just the position of the node. + points_to_buildplate.emplace_back(entry.first); // Just the position of the node. } spanning_trees.emplace_back(points_to_buildplate); } @@ -295,7 +292,7 @@ void TreeSupport::dropNodes(std::vector>& contact_nodes) for (size_t group_index = 0; group_index < nodes_per_part.size(); group_index++) { const MinimumSpanningTree& mst = spanning_trees[group_index]; - //In the first pass, merge all nodes that are close together. + // In the first pass, merge all nodes that are close together. std::unordered_set to_delete; for (const std::pair& entry : nodes_per_part[group_index]) { @@ -303,27 +300,27 @@ void TreeSupport::dropNodes(std::vector>& contact_nodes) Node& node = *p_node; if (to_delete.find(p_node) != to_delete.end()) { - continue; //Delete this node (don't create a new node for it on the next layer). + continue; // Delete this node (don't create a new node for it on the next layer). } const std::vector& neighbours = mst.adjacentNodes(node.position); - if (neighbours.size() == 1 && vSize2(neighbours[0] - node.position) < maximum_move_distance * maximum_move_distance && mst.adjacentNodes(neighbours[0]).size() == 1) //We have just two nodes left, and they're very close! + if (neighbours.size() == 1 && vSize2(neighbours[0] - node.position) < maximum_move_distance * maximum_move_distance && mst.adjacentNodes(neighbours[0]).size() == 1) // We have just two nodes left, and they're very close! { - //Insert a completely new node and let both original nodes fade. - Point next_position = (node.position + neighbours[0]) / 2; //Average position of the two nodes. + // Insert a completely new node and let both original nodes fade. + Point next_position = (node.position + neighbours[0]) / 2; // Average position of the two nodes. const coord_t branch_radius_node = [&]() -> coord_t { if ((node.distance_to_top + 1) > tip_layers) { - return branch_radius + branch_radius * (node.distance_to_top + 1) * diameter_angle_scale_factor; + return branch_radius + branch_radius * (node.distance_to_top + 1) * diameter_angle_scale_factor; } else { - return branch_radius * (node.distance_to_top + 1) / tip_layers; + return branch_radius * (node.distance_to_top + 1) / tip_layers; } }(); - //Avoid collisions. + // Avoid collisions. constexpr size_t rounding_compensation = 100; const coord_t maximum_move_between_samples = maximum_move_distance + radius_sample_resolution + rounding_compensation; const Polygons avoidance = group_index == 0 ? volumes_.getAvoidance(branch_radius_node, layer_nr - 1) : volumes_.getCollision(branch_radius_node, layer_nr - 1); @@ -333,18 +330,18 @@ void TreeSupport::dropNodes(std::vector>& contact_nodes) size_t new_distance_to_top = std::max(node.distance_to_top, neighbour->distance_to_top) + 1; size_t new_support_roof_layers_below = std::max(node.support_roof_layers_below, neighbour->support_roof_layers_below) - 1; - const bool to_buildplate = !volumes_.getAvoidance(branch_radius_node, layer_nr - 1).inside(next_position); + const bool to_buildplate = ! volumes_.getAvoidance(branch_radius_node, layer_nr - 1).inside(next_position); Node* next_node = new Node(next_position, new_distance_to_top, node.skin_direction, new_support_roof_layers_below, to_buildplate, p_node); - insertDroppedNode(contact_nodes[layer_nr - 1], next_node); //Insert the node, resolving conflicts of the two colliding nodes. + insertDroppedNode(contact_nodes[layer_nr - 1], next_node); // Insert the node, resolving conflicts of the two colliding nodes. // Make sure the next pass doesn't drop down either of these (since that already happened). node.merged_neighbours.push_front(neighbour); to_delete.insert(neighbour); to_delete.insert(p_node); } - else if (neighbours.size() > 1) //Don't merge leaf nodes because we would then incur movement greater than the maximum move distance. + else if (neighbours.size() > 1) // Don't merge leaf nodes because we would then incur movement greater than the maximum move distance. { - //Remove all neighbours that are too close and merge them into this node. + // Remove all neighbours that are too close and merge them into this node. for (const Point& neighbour : neighbours) { if (vSize2(neighbour - node.position) < maximum_move_distance * maximum_move_distance) @@ -359,7 +356,7 @@ void TreeSupport::dropNodes(std::vector>& contact_nodes) } } } - //In the second pass, move all middle nodes. + // In the second pass, move all middle nodes. for (const std::pair& entry : nodes_per_part[group_index]) { Node* p_node = entry.second; @@ -368,7 +365,7 @@ void TreeSupport::dropNodes(std::vector>& contact_nodes) { continue; } - //If the branch falls completely inside a collision area (the entire branch would be removed by the X/Y offset), delete it. + // If the branch falls completely inside a collision area (the entire branch would be removed by the X/Y offset), delete it. const Polygons collision = volumes_.getCollision(0, layer_nr); if (group_index > 0 && collision.inside(node.position)) @@ -388,7 +385,8 @@ void TreeSupport::dropNodes(std::vector>& contact_nodes) const ClosestPolygonPoint to_outside = PolygonUtils::findClosest(node.position, collision); const bool node_is_tip = node.distance_to_top <= tip_layers; coord_t max_inside_dist = branch_radius_node; - if (node_is_tip) { + if (node_is_tip) + { // if the node is part of the tip allow the branch to travel through the support xy distance max_inside_dist += (tip_layers - node.distance_to_top) * maximum_move_distance; } @@ -403,15 +401,15 @@ void TreeSupport::dropNodes(std::vector>& contact_nodes) } Point next_layer_vertex = node.position; const std::vector neighbours = mst.adjacentNodes(node.position); - if (neighbours.size() > 1 || (neighbours.size() == 1 && vSize2(neighbours[0] - node.position) >= maximum_move_distance * maximum_move_distance)) //Only nodes that aren't about to collapse. + if (neighbours.size() > 1 || (neighbours.size() == 1 && vSize2(neighbours[0] - node.position) >= maximum_move_distance * maximum_move_distance)) // Only nodes that aren't about to collapse. { - //Move towards the average position of all neighbours. + // Move towards the average position of all neighbours. Point sum_direction(0, 0); for (const Point& neighbour : neighbours) { sum_direction += neighbour - node.position; } - if(vSize2(sum_direction) <= maximum_move_distance * maximum_move_distance) + if (vSize2(sum_direction) <= maximum_move_distance * maximum_move_distance) { next_layer_vertex += sum_direction; } @@ -433,20 +431,20 @@ void TreeSupport::dropNodes(std::vector>& contact_nodes) } }(); - //Avoid collisions. + // Avoid collisions. constexpr size_t rounding_compensation = 100; const coord_t maximum_move_between_samples = maximum_move_distance + radius_sample_resolution + rounding_compensation; const Polygons avoidance = group_index == 0 ? volumes_.getAvoidance(branch_radius_node, layer_nr - 1) : volumes_.getCollision(branch_radius_node, layer_nr - 1); PolygonUtils::moveOutside(avoidance, next_layer_vertex, radius_sample_resolution + rounding_compensation, maximum_move_between_samples * maximum_move_between_samples); - const bool to_buildplate = !volumes_.getAvoidance(branch_radius_node, layer_nr - 1).inside(next_layer_vertex); + const bool to_buildplate = ! volumes_.getAvoidance(branch_radius_node, layer_nr - 1).inside(next_layer_vertex); Node* next_node = new Node(next_layer_vertex, node.distance_to_top + 1, node.skin_direction, node.support_roof_layers_below - 1, to_buildplate, p_node); insertDroppedNode(contact_nodes[layer_nr - 1], next_node); } } // Prune all branches that couldn't find support on either the model or the buildplate (resulting in 'mid-air' branches). - for (;! unsupported_branch_leaves.empty(); unsupported_branch_leaves.pop_back()) + for (; ! unsupported_branch_leaves.empty(); unsupported_branch_leaves.pop_back()) { const auto& entry = unsupported_branch_leaves.back(); Node* i_node = entry.second; @@ -472,7 +470,7 @@ void TreeSupport::dropNodes(std::vector>& contact_nodes) Progress::messageProgress(Progress::Stage::SUPPORT, progress_current, progress_total); } - for (Node *node : to_free_node_set) + for (Node* node : to_free_node_set) { delete node; } @@ -483,7 +481,7 @@ void TreeSupport::generateContactPoints(const SliceMeshStorage& mesh, std::vecto { const coord_t point_spread = mesh.settings.get("support_tree_branch_distance"); - //First generate grid points to cover the entire area of the print. + // First generate grid points to cover the entire area of the print. AABB bounding_box = mesh.bounding_box.flatten(); // We want to create the grid pattern at an angle, so compute the bounding // box required to cover that angle. @@ -501,9 +499,7 @@ void TreeSupport::generateContactPoints(const SliceMeshStorage& mesh, std::vecto // This formulation will only work with rotation angles <90 degrees. If the // rotation angle becomes a user-configurable value then this will need to // be changed - const Point rotated_dims = Point( - bounding_box_size.X * cos_angle + bounding_box_size.Y * sin_angle, - bounding_box_size.X * sin_angle + bounding_box_size.Y * cos_angle) / 2; + const Point rotated_dims = Point(bounding_box_size.X * cos_angle + bounding_box_size.Y * sin_angle, bounding_box_size.X * sin_angle + bounding_box_size.Y * cos_angle) / 2; std::vector grid_points; for (auto x = -rotated_dims.X; x <= rotated_dims.X; x += point_spread) @@ -525,12 +521,12 @@ void TreeSupport::generateContactPoints(const SliceMeshStorage& mesh, std::vecto const coord_t layer_height = mesh.settings.get("layer_height"); const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + 1; //Support must always be 1 layer below overhang. + const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + 1; // Support must always be 1 layer below overhang. const size_t support_roof_layers = [&]() -> size_t { if (mesh.settings.get("support_roof_enable")) { - return round_divide(mesh.settings.get("support_roof_height"), mesh.settings.get("layer_height")); //How many roof layers, if roof is enabled. + return round_divide(mesh.settings.get("support_roof_height"), mesh.settings.get("layer_height")); // How many roof layers, if roof is enabled. } else { @@ -548,17 +544,17 @@ void TreeSupport::generateContactPoints(const SliceMeshStorage& mesh, std::vecto for (const ConstPolygonRef overhang_part : overhang) { - AABB overhang_bounds(overhang_part); //Pre-generate the AABB for a quick pre-filter. - overhang_bounds.expand(half_overhang_distance); //Allow for points to be within half an overhang step of the overhang area. - bool added = false; //Did we add a point this way? + AABB overhang_bounds(overhang_part); // Pre-generate the AABB for a quick pre-filter. + overhang_bounds.expand(half_overhang_distance); // Allow for points to be within half an overhang step of the overhang area. + bool added = false; // Did we add a point this way? for (Point candidate : grid_points) { if (overhang_bounds.contains(candidate)) { - constexpr coord_t distance_inside = 1; //Move point towards the border of the polygon if it is closer than half the overhang distance: Catch points that fall between overhang areas on constant surfaces. + constexpr coord_t distance_inside = 1; // Move point towards the border of the polygon if it is closer than half the overhang distance: Catch points that fall between overhang areas on constant surfaces. PolygonUtils::moveInside(overhang_part, candidate, distance_inside, half_overhang_distance * half_overhang_distance); constexpr bool border_is_inside = true; - if (overhang_part.inside(candidate, border_is_inside) && !volumes_.getCollision(0, layer_nr).inside(candidate, border_is_inside)) + if (overhang_part.inside(candidate, border_is_inside) && ! volumes_.getCollision(0, layer_nr).inside(candidate, border_is_inside)) { constexpr size_t distance_to_top = 0; constexpr bool to_buildplate = true; @@ -568,7 +564,7 @@ void TreeSupport::generateContactPoints(const SliceMeshStorage& mesh, std::vecto } } } - if (!added) //If we didn't add any points due to bad luck, we want to add one anyway such that loose parts are also supported. + if (! added) // If we didn't add any points due to bad luck, we want to add one anyway such that loose parts are also supported. { Point candidate = bounding_box.getMiddle(); PolygonUtils::moveInside(overhang_part, candidate); @@ -582,7 +578,7 @@ void TreeSupport::generateContactPoints(const SliceMeshStorage& mesh, std::vecto { if (overhang_part.area() < 0) { - for (auto iter = contact_nodes[layer_nr].begin(); iter != contact_nodes[layer_nr].end(); ) + for (auto iter = contact_nodes[layer_nr].begin(); iter != contact_nodes[layer_nr].end();) { if (overhang_part.inside((*iter)->position)) { @@ -601,7 +597,7 @@ void TreeSupport::generateContactPoints(const SliceMeshStorage& mesh, std::vecto void TreeSupport::insertDroppedNode(std::vector& nodes_layer, Node* p_node) { std::vector::iterator conflicting_node_it = std::find(nodes_layer.begin(), nodes_layer.end(), p_node); - if (conflicting_node_it == nodes_layer.end()) //No conflict. + if (conflicting_node_it == nodes_layer.end()) // No conflict. { nodes_layer.emplace_back(p_node); return; @@ -612,4 +608,4 @@ void TreeSupport::insertDroppedNode(std::vector& nodes_layer, Node* p_nod conflicting_node->support_roof_layers_below = std::max(conflicting_node->support_roof_layers_below, p_node->support_roof_layers_below); } -} //namespace cura +} // namespace cura diff --git a/src/Weaver.cpp b/src/Weaver.cpp index 776fd3b24f..d84c24c42e 100644 --- a/src/Weaver.cpp +++ b/src/Weaver.cpp @@ -1,27 +1,28 @@ -//Copyright (c) 2021 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include // sqrt #include // debug IO +#include + #include "Application.h" //To get the communication channel. #include "PrintFeature.h" #include "Slice.h" -#include "slicer.h" #include "Weaver.h" #include "communication/Communication.h" //To send layer view data. #include "progress/Progress.h" -#include "utils/logoutput.h" #include "settings/AdaptiveLayerHeights.h" #include "settings/types/Angle.h" +#include "slicer.h" -namespace cura +namespace cura { void Weaver::weave(MeshGroup* meshgroup) -{ +{ wireFrame.meshgroup = meshgroup; - + const coord_t maxz = meshgroup->max().z; const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; @@ -30,11 +31,11 @@ void Weaver::weave(MeshGroup* meshgroup) const size_t layer_count = (maxz - initial_layer_thickness) / connection_height + 1; std::vector layer_thicknesses; - log("Layer count: %i\n", layer_count); + spdlog::info("Layer count: {}", layer_count); std::vector slicerList; - for(Mesh& mesh : meshgroup->meshes) + for (Mesh& mesh : meshgroup->meshes) { constexpr bool variable_layer_heights = false; cura::Slicer* slicer = new cura::Slicer(&mesh, connection_height, layer_count, variable_layer_heights, &layer_thicknesses); @@ -47,26 +48,26 @@ void Weaver::weave(MeshGroup* meshgroup) { Polygons parts; for (cura::Slicer* slicer : slicerList) - parts.add(slicer->layers[starting_layer_idx].polygons); - + parts.add(slicer->layers[starting_layer_idx].polygons); + if (parts.size() > 0) break; } if (starting_layer_idx > 0) { - logWarning("First %i layers are empty!\n", starting_layer_idx); + spdlog::warn("First {} layers are empty!", starting_layer_idx); } } - log("Chainifying layers...\n"); + spdlog::info("Chainifying layers..."); { int starting_z = -1; for (cura::Slicer* slicer : slicerList) wireFrame.bottom_outline.add(slicer->layers[starting_layer_idx].polygons); Application::getInstance().communication->sendPolygons(PrintFeatureType::OuterWall, wireFrame.bottom_outline, 1, 1, 1); - - if (slicerList.empty()) //Wait, there is nothing to slice. + + if (slicerList.empty()) // Wait, there is nothing to slice. { wireFrame.z_bottom = 0; } @@ -74,7 +75,7 @@ void Weaver::weave(MeshGroup* meshgroup) { wireFrame.z_bottom = slicerList[0]->layers[starting_layer_idx].z; } - + Point starting_point_in_layer; if (wireFrame.bottom_outline.size() > 0) { @@ -82,19 +83,19 @@ void Weaver::weave(MeshGroup* meshgroup) } else { - starting_point_in_layer = (Point(0,0) + meshgroup->max() + meshgroup->min()) / 2; + starting_point_in_layer = (Point(0, 0) + meshgroup->max() + meshgroup->min()) / 2; } - + Progress::messageProgressStage(Progress::Stage::INSET_SKIN, nullptr); for (LayerIndex layer_idx = starting_layer_idx + 1; layer_idx < LayerIndex(layer_count); layer_idx++) { - Progress::messageProgress(Progress::Stage::INSET_SKIN, layer_idx+1, layer_count); // abuse the progress system of the normal mode of CuraEngine - + Progress::messageProgress(Progress::Stage::INSET_SKIN, layer_idx + 1, layer_count); // abuse the progress system of the normal mode of CuraEngine + Polygons parts1; for (cura::Slicer* slicer : slicerList) parts1.add(slicer->layers[layer_idx].polygons); - + Polygons chainified; chainify_polygons(parts1, starting_point_in_layer, chainified); @@ -103,120 +104,119 @@ void Weaver::weave(MeshGroup* meshgroup) if (chainified.size() > 0) { - if (starting_z == -1) starting_z = slicerList[0]->layers[layer_idx-1].z; + if (starting_z == -1) + starting_z = slicerList[0]->layers[layer_idx - 1].z; wireFrame.layers.emplace_back(); WeaveLayer& layer = wireFrame.layers.back(); - - layer.z0 = slicerList[0]->layers[layer_idx-1].z - starting_z; + + layer.z0 = slicerList[0]->layers[layer_idx - 1].z - starting_z; layer.z1 = slicerList[0]->layers[layer_idx].z - starting_z; - + layer.supported = chainified; - + starting_point_in_layer = layer.supported.back().back(); } } } - log("Finding horizontal parts...\n"); + spdlog::info("Finding horizontal parts..."); { Progress::messageProgressStage(Progress::Stage::SUPPORT, nullptr); for (unsigned int layer_idx = 0; layer_idx < wireFrame.layers.size(); layer_idx++) { - Progress::messageProgress(Progress::Stage::SUPPORT, layer_idx+1, wireFrame.layers.size()); // abuse the progress system of the normal mode of CuraEngine - + Progress::messageProgress(Progress::Stage::SUPPORT, layer_idx + 1, wireFrame.layers.size()); // abuse the progress system of the normal mode of CuraEngine + WeaveLayer& layer = wireFrame.layers[layer_idx]; - + Polygons empty; - Polygons& layer_above = (layer_idx+1 < wireFrame.layers.size())? wireFrame.layers[layer_idx+1].supported : empty; - + Polygons& layer_above = (layer_idx + 1 < wireFrame.layers.size()) ? wireFrame.layers[layer_idx + 1].supported : empty; + createHorizontalFill(layer, layer_above); } } // at this point layer.supported still only contains the polygons to be connected // when connecting layers, we further add the supporting polygons created by the roofs - log("Connecting layers...\n"); + spdlog::info("Connecting layers..."); { Polygons* lower_top_parts = &wireFrame.bottom_outline; int last_z = wireFrame.z_bottom; for (unsigned int layer_idx = 0; layer_idx < wireFrame.layers.size(); layer_idx++) // use top of every layer but the last { WeaveLayer& layer = wireFrame.layers[layer_idx]; - + connect_polygons(*lower_top_parts, last_z, layer.supported, layer.z1, layer); layer.supported.add(layer.roofs.roof_outlines); lower_top_parts = &layer.supported; - + last_z = layer.z1; } } { // roofs: - if (!wireFrame.layers.empty()) //If there are no layers, create no roof. + if (! wireFrame.layers.empty()) // If there are no layers, create no roof. { WeaveLayer& top_layer = wireFrame.layers.back(); Polygons to_be_supported; // empty for the top layer fillRoofs(top_layer.supported, to_be_supported, -1, top_layer.z1, top_layer.roofs); } } - - + + { // bottom: - if (!wireFrame.layers.empty()) //If there are no layers, create no bottom. + if (! wireFrame.layers.empty()) // If there are no layers, create no bottom. { Polygons to_be_supported; // is empty for the bottom layer, cause the order of insets doesn't really matter (in a sense everything is to be supported) fillRoofs(wireFrame.bottom_outline, to_be_supported, -1, wireFrame.layers.front().z0, wireFrame.bottom_infill); } } - } - void Weaver::createHorizontalFill(WeaveLayer& layer, Polygons& layer_above) { const coord_t bridgable_dist = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("wireframe_height"); - -// Polygons& polys_below = lower_top_parts; + + // Polygons& polys_below = lower_top_parts; Polygons& polys_here = layer.supported; Polygons& polys_above = layer_above; - + { // roofs - Polygons to_be_supported = polys_above.offset(bridgable_dist); + Polygons to_be_supported = polys_above.offset(bridgable_dist); fillRoofs(polys_here, to_be_supported, -1, layer.z1, layer.roofs); - } - + { // floors - Polygons to_be_supported = polys_above.offset(-bridgable_dist); + Polygons to_be_supported = polys_above.offset(-bridgable_dist); fillFloors(polys_here, to_be_supported, 1, layer.z1, layer.roofs); } - - {// optimize away doubly printed regions (boundaries of holes in layer etc.) + + { // optimize away doubly printed regions (boundaries of holes in layer etc.) for (WeaveRoofPart& inset : layer.roofs.roof_insets) connections2moves(inset); } - } - + void Weaver::fillRoofs(Polygons& supporting, Polygons& to_be_supported, int direction, int z, WeaveRoof& horizontals) { std::vector& insets = horizontals.roof_insets; - - if (supporting.size() == 0) return; // no parts to start the roof from! - + + if (supporting.size() == 0) + return; // no parts to start the roof from! + Polygons roofs = supporting.difference(to_be_supported); const coord_t roof_inset = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("wireframe_roof_inset"); roofs = roofs.offset(-roof_inset).offset(roof_inset); - - if (roofs.size() == 0) return; - - - Polygons roof_outlines; + + if (roofs.size() == 0) + return; + + + Polygons roof_outlines; Polygons roof_holes; { // split roofs into outlines and holes std::vector roof_parts = roofs.splitIntoParts(); @@ -231,15 +231,14 @@ void Weaver::fillRoofs(Polygons& supporting, Polygons& to_be_supported, int dire } } - + Polygons supporting_outlines; - + std::vector supporting_parts = supporting.splitIntoParts(); - for (PolygonsPart& supporting_part : supporting_parts) + for (PolygonsPart& supporting_part : supporting_parts) supporting_outlines.add(supporting_part[0]); // only add outlines, not the holes - - - + + Polygons inset1; Polygons last_inset; Polygons last_supported = supporting; @@ -247,43 +246,45 @@ void Weaver::fillRoofs(Polygons& supporting, Polygons& to_be_supported, int dire { last_inset = inset0.offset(direction * roof_inset, ClipperLib::jtRound); inset1 = last_inset.intersection(roof_outlines); // stay within roof area - inset1 = inset1.unionPolygons(roof_holes);// make insets go around holes + inset1 = inset1.unionPolygons(roof_holes); // make insets go around holes + + if (inset1.size() == 0) + break; - if (inset1.size() == 0) break; - insets.emplace_back(); - + connect(last_supported, z, inset1, z, insets.back()); - + inset1 = inset1.remove(roof_holes); // throw away holes which appear in every intersection - inset1 = inset1.remove(roof_outlines);// throw away fully filled regions - + inset1 = inset1.remove(roof_outlines); // throw away fully filled regions + last_supported = insets.back().supported; // chainified - } - - + horizontals.roof_outlines.add(roofs); // TODO just add the new lines, not the lines of the roofs which are already supported ==> make outlines into a connection from which we only print the top, not the connection -} +} void Weaver::fillFloors(Polygons& supporting, Polygons& to_be_supported, int direction, int z, WeaveRoof& horizontals) { std::vector& outsets = horizontals.roof_insets; - - if (to_be_supported.size() == 0) return; // no parts to start the floor from! - if (supporting.size() == 0) return; // no parts to start the floor from! - + + if (to_be_supported.size() == 0) + return; // no parts to start the floor from! + if (supporting.size() == 0) + return; // no parts to start the floor from! + Polygons floors = to_be_supported.difference(supporting); const coord_t roof_inset = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("wireframe_roof_inset"); floors = floors.offset(-roof_inset).offset(roof_inset); - - if (floors.size() == 0) return; - - + + if (floors.size() == 0) + return; + + std::vector floor_parts = floors.splitIntoParts(); - + Polygons floor_outlines; Polygons floor_holes; for (PolygonsPart& floor_part : floor_parts) @@ -292,33 +293,32 @@ void Weaver::fillFloors(Polygons& supporting, Polygons& to_be_supported, int dir for (unsigned int hole_idx = 1; hole_idx < floor_part.size(); hole_idx++) { floor_holes.add(floor_part[hole_idx]); - //floor_holes.back().reverse(); + // floor_holes.back().reverse(); } } - - + + Polygons outset1; - + Polygons last_supported = supporting; - + for (Polygons outset0 = supporting; outset0.size() > 0; outset0 = outset1) { outset1 = outset0.offset(roof_inset * direction, ClipperLib::jtRound).intersection(floors); outset1 = outset1.remove(floor_holes); // throw away holes which appear in every intersection outset1 = outset1.remove(floor_outlines); // throw away holes which appear in every intersection - - + + outsets.emplace_back(); - + connect(last_supported, z, outset1, z, outsets.back()); - - outset1 = outset1.remove(floor_outlines);// throw away fully filled regions - - last_supported = outsets.back().supported; // chainified + outset1 = outset1.remove(floor_outlines); // throw away fully filled regions + + last_supported = outsets.back().supported; // chainified } - - + + horizontals.roof_outlines.add(floors); } @@ -336,7 +336,7 @@ void Weaver::connections2moves(WeaveRoofPart& inset) { WeaveConnectionSegment& segment = segments[idx]; assert(segment.segmentType == WeaveSegmentType::UP); - Point3 from = (idx == 0)? part.connection.from : segments[idx-1].to; + Point3 from = (idx == 0) ? part.connection.from : segments[idx - 1].to; bool skipped = (segment.to - from).vSize2() < line_width * line_width; if (skipped) { @@ -345,26 +345,26 @@ void Weaver::connections2moves(WeaveRoofPart& inset) { WeaveConnectionSegment& segment = segments[idx]; assert(segments[idx].segmentType == WeaveSegmentType::UP); - Point3 from = (idx == 0)? part.connection.from : segments[idx-1].to; + Point3 from = (idx == 0) ? part.connection.from : segments[idx - 1].to; bool skipped = (segment.to - from).vSize2() < line_width * line_width; - if (!skipped) + if (! skipped) { break; } } - int end = idx - ((include_half_of_last_down)? 2 : 1); + int end = idx - ((include_half_of_last_down) ? 2 : 1); if (idx >= segments.size()) segments.erase(segments.begin() + begin, segments.end()); - else + else { segments.erase(segments.begin() + begin, segments.begin() + end); - if (begin < segments.size()) + if (begin < segments.size()) { segments[begin].segmentType = WeaveSegmentType::MOVE; if (include_half_of_last_down) - segments[begin+1].segmentType = WeaveSegmentType::DOWN_AND_FLAT; + segments[begin + 1].segmentType = WeaveSegmentType::DOWN_AND_FLAT; } - idx = begin + ((include_half_of_last_down)? 2 : 1); + idx = begin + ((include_half_of_last_down) ? 2 : 1); } } } @@ -379,22 +379,23 @@ void Weaver::connect(Polygons& parts0, int z0, Polygons& parts1, int z1, WeaveCo // parts[m] = parts[m].difference(parts[n].offset(nozzle_top_diameter)) // according to the printing order! // - // OR! : + // OR! : // // unify different parts if gap is too small - + Polygons& supported = result.supported; - - if (parts1.size() == 0) return; - - Point& start_close_to = (parts0.size() > 0)? parts0.back().back() : parts1.back().back(); - + + if (parts1.size() == 0) + return; + + Point& start_close_to = (parts0.size() > 0) ? parts0.back().back() : parts1.back().back(); + chainify_polygons(parts1, start_close_to, supported); - - if (parts0.size() == 0) return; - - connect_polygons(parts0, z0, supported, z1, result); + if (parts0.size() == 0) + return; + + connect_polygons(parts0, z0, supported, z1, result); } @@ -402,95 +403,92 @@ void Weaver::chainify_polygons(Polygons& parts1, Point start_close_to, Polygons& { const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; const coord_t connection_height = mesh_group_settings.get("wireframe_height"); - const coord_t nozzle_outer_diameter = mesh_group_settings.get("machine_nozzle_tip_outer_diameter"); // ___ ___ + const coord_t nozzle_outer_diameter = mesh_group_settings.get("machine_nozzle_tip_outer_diameter"); // ___ ___ const AngleRadians nozzle_expansion_angle = mesh_group_settings.get("machine_nozzle_expansion_angle"); // \_U_/ - const coord_t nozzle_clearance = mesh_group_settings.get("wireframe_nozzle_clearance"); // at least line width + const coord_t nozzle_clearance = mesh_group_settings.get("wireframe_nozzle_clearance"); // at least line width const coord_t nozzle_top_diameter = tan(nozzle_expansion_angle) * connection_height + nozzle_outer_diameter + nozzle_clearance; - for (unsigned int prt = 0 ; prt < parts1.size(); prt++) + for (unsigned int prt = 0; prt < parts1.size(); prt++) { ConstPolygonRef upperPart = parts1[prt]; - + ClosestPolygonPoint closestInPoly = PolygonUtils::findClosest(start_close_to, upperPart); - + PolygonRef part_top = result.newPoly(); - + GivenDistPoint next_upper; bool found = true; int idx = 0; - + for (Point upper_point = upperPart[closestInPoly.point_idx]; found; upper_point = next_upper.location) { found = PolygonUtils::getNextPointWithDistance(upper_point, nozzle_top_diameter, upperPart, idx, closestInPoly.point_idx, next_upper); - - if (!found) + + if (! found) { break; } - + part_top.add(upper_point); - + idx = next_upper.pos; } if (part_top.size() > 0) start_close_to = part_top.back(); else - result.remove(result.size()-1); + result.remove(result.size() - 1); } } void Weaver::connect_polygons(Polygons& supporting, int z0, Polygons& supported, int z1, WeaveConnection& result) { - if (supporting.size() < 1) { std::cerr << "lower layer has zero parts!\n"; return; } - + result.z0 = z0; result.z1 = z1; - + std::vector& parts = result.connections; - - for (unsigned int prt = 0 ; prt < supported.size(); prt++) + + for (unsigned int prt = 0; prt < supported.size(); prt++) { - ConstPolygonRef upperPart(supported[prt]); - - + + parts.emplace_back(prt); WeaveConnectionPart& part = parts.back(); PolyLine3& connection = part.connection; - + Point3 last_upper; bool firstIter = true; - + for (const Point& upper_point : upperPart) { - ClosestPolygonPoint lowerPolyPoint = PolygonUtils::findClosest(upper_point, supporting); Point& lower = lowerPolyPoint.location; - + Point3 lower3 = Point3(lower.X, lower.Y, z0); Point3 upper3 = Point3(upper_point.X, upper_point.Y, z1); - - + + if (firstIter) connection.from = lower3; else connection.segments.emplace_back<>(lower3, WeaveSegmentType::DOWN); - + connection.segments.emplace_back<>(upper3, WeaveSegmentType::UP); last_upper = upper3; - + firstIter = false; } } } -}//namespace cura +} // namespace cura diff --git a/src/Wireframe2gcode.cpp b/src/Wireframe2gcode.cpp index bde62a01e6..3c78d2ee29 100644 --- a/src/Wireframe2gcode.cpp +++ b/src/Wireframe2gcode.cpp @@ -1,23 +1,24 @@ // Copyright (c) 2022 Ultimaker B.V. -// CuraEngine is released under the terms of the AGPLv3 or higher. +// CuraEngine is released under the terms of the AGPLv3 or higher #include // sqrt #include // debug IO +#include + #include "Application.h" //To get the communication channel. #include "ExtruderTrain.h" #include "PathOrderOptimizer.h" //For skirt/brim. #include "PrintFeature.h" #include "Slice.h" -#include "weaveDataStorage.h" #include "Weaver.h" #include "Wireframe2gcode.h" #include "communication/Communication.h" //To write g-code output. #include "progress/Progress.h" #include "utils/math.h" -#include "utils/logoutput.h" +#include "weaveDataStorage.h" -namespace cura +namespace cura { @@ -31,7 +32,7 @@ void Wireframe2gcode::writeGCode() Application::getInstance().communication->beginGCode(); processStartingCode(); - + int maxObjectHeight; if (wireFrame.layers.empty()) { @@ -52,61 +53,65 @@ void Wireframe2gcode::writeGCode() for (PolygonRef bottom_part : wireFrame.bottom_infill.roof_outlines) { - if (bottom_part.size() == 0) continue; - writeMoveWithRetract(bottom_part[bottom_part.size()-1]); + if (bottom_part.size() == 0) + continue; + writeMoveWithRetract(bottom_part[bottom_part.size() - 1]); for (Point& segment_to : bottom_part) { gcode.writeExtrusion(segment_to, speedBottom, extrusion_mm3_per_mm_flat, PrintFeatureType::Skin); } } - - - + + // bottom: Polygons empty_outlines; - writeFill(wireFrame.bottom_infill.roof_insets, empty_outlines, - [this](Wireframe2gcode&, WeaveConnectionPart& part, unsigned int segment_idx) { - WeaveConnectionSegment& segment = part.connection.segments[segment_idx]; - if (segment.segmentType == WeaveSegmentType::MOVE || segment.segmentType == WeaveSegmentType::DOWN_AND_FLAT) // this is the case when an inset overlaps with a hole - { - writeMoveWithRetract(segment.to); - } else - { - gcode.writeExtrusion(segment.to, speedBottom, extrusion_mm3_per_mm_connection, PrintFeatureType::Skin); - } - } - , - [this](Wireframe2gcode&, WeaveConnectionSegment& segment) { - if (segment.segmentType == WeaveSegmentType::MOVE) - writeMoveWithRetract(segment.to); - else if (segment.segmentType == WeaveSegmentType::DOWN_AND_FLAT) - return; // do nothing - else - gcode.writeExtrusion(segment.to, speedBottom, extrusion_mm3_per_mm_flat, PrintFeatureType::Skin); - } - ); + writeFill( + wireFrame.bottom_infill.roof_insets, + empty_outlines, + [this](Wireframe2gcode&, WeaveConnectionPart& part, unsigned int segment_idx) + { + WeaveConnectionSegment& segment = part.connection.segments[segment_idx]; + if (segment.segmentType == WeaveSegmentType::MOVE || segment.segmentType == WeaveSegmentType::DOWN_AND_FLAT) // this is the case when an inset overlaps with a hole + { + writeMoveWithRetract(segment.to); + } + else + { + gcode.writeExtrusion(segment.to, speedBottom, extrusion_mm3_per_mm_connection, PrintFeatureType::Skin); + } + }, + [this](Wireframe2gcode&, WeaveConnectionSegment& segment) + { + if (segment.segmentType == WeaveSegmentType::MOVE) + writeMoveWithRetract(segment.to); + else if (segment.segmentType == WeaveSegmentType::DOWN_AND_FLAT) + return; // do nothing + else + gcode.writeExtrusion(segment.to, speedBottom, extrusion_mm3_per_mm_flat, PrintFeatureType::Skin); + }); Progress::messageProgressStage(Progress::Stage::EXPORT, nullptr); for (LayerIndex layer_nr = 0; layer_nr < static_cast(wireFrame.layers.size()); layer_nr++) { - Progress::messageProgress(Progress::Stage::EXPORT, layer_nr+1, total_layers); // abuse the progress system of the normal mode of CuraEngine - + Progress::messageProgress(Progress::Stage::EXPORT, layer_nr + 1, total_layers); // abuse the progress system of the normal mode of CuraEngine + WeaveLayer& layer = wireFrame.layers[layer_nr]; - - gcode.writeLayerComment(layer_nr+1); - + + gcode.writeLayerComment(layer_nr + 1); + double fanSpeed = scene_settings.get("cool_fan_speed_max") * 100.0; if (layer_nr == 0) { fanSpeed = scene_settings.get("cool_fan_speed_min") * 100.0; } gcode.writeFanCommand(fanSpeed); - + for (size_t part_nr = 0; part_nr < layer.connections.size(); part_nr++) { WeaveConnectionPart& part = layer.connections[part_nr]; - - if (part.connection.segments.size() == 0) continue; - + + if (part.connection.segments.size() == 0) + continue; + gcode.writeTypeComment(PrintFeatureType::Support); // connection { if (vSize2(gcode.getPositionXY() - part.connection.from) > connectionHeight) @@ -120,9 +125,8 @@ void Wireframe2gcode::writeGCode() handle_segment(part, segment_idx); } } - - - + + gcode.writeTypeComment(PrintFeatureType::OuterWall); // top { for (WeaveConnectionSegment& segment : part.connection.segments) @@ -131,11 +135,11 @@ void Wireframe2gcode::writeGCode() { continue; } - if (segment.segmentType == WeaveSegmentType::MOVE) + if (segment.segmentType == WeaveSegmentType::MOVE) { writeMoveWithRetract(segment.to); } - else + else { gcode.writeExtrusion(segment.to, speedFlat, extrusion_mm3_per_mm_flat, PrintFeatureType::OuterWall); gcode.writeDelay(flat_delay); @@ -143,79 +147,74 @@ void Wireframe2gcode::writeGCode() } } } - + // roofs: gcode.setZ(layer.z1); - std::function - handle_roof = &Wireframe2gcode::handle_roof_segment; - writeFill(layer.roofs.roof_insets, layer.roofs.roof_outlines, - handle_roof, - [this](Wireframe2gcode&, WeaveConnectionSegment& segment) { // handle flat segments - if (segment.segmentType == WeaveSegmentType::MOVE) - { - writeMoveWithRetract(segment.to); - } else if (segment.segmentType == WeaveSegmentType::DOWN_AND_FLAT) - { - // do nothing - } else - { - gcode.writeExtrusion(segment.to, speedFlat, extrusion_mm3_per_mm_flat, PrintFeatureType::Skin); - gcode.writeDelay(flat_delay); - } - }); - - - + std::function handle_roof = &Wireframe2gcode::handle_roof_segment; + writeFill(layer.roofs.roof_insets, layer.roofs.roof_outlines, handle_roof, [this](Wireframe2gcode&, WeaveConnectionSegment& segment) { // handle flat segments + if (segment.segmentType == WeaveSegmentType::MOVE) + { + writeMoveWithRetract(segment.to); + } + else if (segment.segmentType == WeaveSegmentType::DOWN_AND_FLAT) + { + // do nothing + } + else + { + gcode.writeExtrusion(segment.to, speedFlat, extrusion_mm3_per_mm_flat, PrintFeatureType::Skin); + gcode.writeDelay(flat_delay); + } + }); } - + gcode.setZ(maxObjectHeight); - + gcode.writeRetraction(standard_retraction_config); - - + + gcode.updateTotalPrintTime(); - + gcode.writeDelay(0.3); - + gcode.writeFanCommand(0); finalize(); } - + void Wireframe2gcode::go_down(WeaveConnectionPart& part, unsigned int segment_idx) { WeaveConnectionSegment& segment = part.connection.segments[segment_idx]; - Point3 from = (segment_idx == 0)? part.connection.from : part.connection.segments[segment_idx - 1].to; + Point3 from = (segment_idx == 0) ? part.connection.from : part.connection.segments[segment_idx - 1].to; if (go_back_to_last_top) gcode.writeTravel(from, speedDown); if (straight_first_when_going_down <= 0) { gcode.writeExtrusion(segment.to, speedDown, extrusion_mm3_per_mm_connection, PrintFeatureType::OuterWall); - } else + } + else { Point3& to = segment.to; - Point3 from = gcode.getPosition();// segment.from; + Point3 from = gcode.getPosition(); // segment.from; Point3 vec = to - from; Point3 in_between = from + vec * static_cast(straight_first_when_going_down); - + Point3 up(in_between.x, in_between.y, from.z); int64_t new_length = (up - from).vSize() + (to - up).vSize() + 5; int64_t orr_length = vec.vSize(); double enlargement = new_length / orr_length; - gcode.writeExtrusion(up, speedDown*enlargement, extrusion_mm3_per_mm_connection / enlargement, PrintFeatureType::OuterWall); - gcode.writeExtrusion(to, speedDown*enlargement, extrusion_mm3_per_mm_connection / enlargement, PrintFeatureType::OuterWall); + gcode.writeExtrusion(up, speedDown * enlargement, extrusion_mm3_per_mm_connection / enlargement, PrintFeatureType::OuterWall); + gcode.writeExtrusion(to, speedDown * enlargement, extrusion_mm3_per_mm_connection / enlargement, PrintFeatureType::OuterWall); } gcode.writeDelay(bottom_delay); if (up_dist_half_speed > 0) { - - gcode.writeExtrusion(Point3(0,0,up_dist_half_speed) + gcode.getPosition(), speedUp / 2, extrusion_mm3_per_mm_connection * 2, PrintFeatureType::OuterWall); + gcode.writeExtrusion(Point3(0, 0, up_dist_half_speed) + gcode.getPosition(), speedUp / 2, extrusion_mm3_per_mm_connection * 2, PrintFeatureType::OuterWall); } } - void Wireframe2gcode::strategy_knot(WeaveConnectionPart& part, unsigned int segment_idx) { WeaveConnectionSegment& segment = part.connection.segments[segment_idx]; @@ -223,18 +222,19 @@ void Wireframe2gcode::strategy_knot(WeaveConnectionPart& part, unsigned int segm Point3 next_vector; if (segment_idx + 1 < part.connection.segments.size()) { - WeaveConnectionSegment& next_segment = part.connection.segments[segment_idx+1]; + WeaveConnectionSegment& next_segment = part.connection.segments[segment_idx + 1]; next_vector = next_segment.to - segment.to; - } else + } + else { next_vector = part.connection.segments[0].to - segment.to; } Point next_dir_2D(next_vector.x, next_vector.y); next_dir_2D = next_dir_2D * top_jump_dist / vSize(next_dir_2D); - Point3 next_dir (next_dir_2D.X / 2, next_dir_2D.Y / 2, -top_jump_dist); - + Point3 next_dir(next_dir_2D.X / 2, next_dir_2D.Y / 2, -top_jump_dist); + Point3 current_pos = gcode.getPosition(); - + gcode.writeTravel(current_pos - next_dir, speedUp); gcode.writeDelay(top_delay); gcode.writeTravel(current_pos + next_dir_2D, speedUp); @@ -243,26 +243,26 @@ void Wireframe2gcode::strategy_knot(WeaveConnectionPart& part, unsigned int segm void Wireframe2gcode::strategy_retract(WeaveConnectionPart& part, unsigned int segment_idx) { WeaveConnectionSegment& segment = part.connection.segments[segment_idx]; - Point3 from = (segment_idx == 0)? part.connection.from : part.connection.segments[segment_idx - 1].to; + Point3 from = (segment_idx == 0) ? part.connection.from : part.connection.segments[segment_idx - 1].to; Settings& scene_settings = Application::getInstance().current_slice->scene.settings; RetractionConfig retraction_config; // TODO: get these from the settings! - retraction_config.distance = MM2INT(0.5); //INT2MM(getSettingInt("retraction_amount")) - retraction_config.prime_volume = 0;//INT2MM(getSettingInt("retractionPrime + retraction_config.distance = MM2INT(0.5); // INT2MM(getSettingInt("retraction_amount")) + retraction_config.prime_volume = 0; // INT2MM(getSettingInt("retractionPrime retraction_config.speed = 20; // 40; retraction_config.primeSpeed = 15; // 30; - retraction_config.zHop = 0; //getSettingInt("retraction_hop"); + retraction_config.zHop = 0; // getSettingInt("retraction_hop"); retraction_config.retraction_count_max = scene_settings.get("retraction_count_max"); - retraction_config.retraction_extrusion_window = scene_settings.get("retraction_extrusion_window"); //Window in which to count retractions in mm of extruded filament. + retraction_config.retraction_extrusion_window = scene_settings.get("retraction_extrusion_window"); // Window in which to count retractions in mm of extruded filament. retraction_config.retraction_min_travel_distance = scene_settings.get("retraction_min_travel"); double top_retract_pause = 2.0; const coord_t retract_hop_dist = MM2INT(1); bool after_retract_hop = false; - //bool go_horizontal_first = true; + // bool go_horizontal_first = true; bool lower_retract_start = true; - + Point3& to = segment.to; if (lower_retract_start) { @@ -278,15 +278,15 @@ void Wireframe2gcode::strategy_retract(WeaveConnectionPart& part, unsigned int s gcode.writeTravel(to + Point3(0, 0, retract_hop_dist), speedFlat); } } - else + else { gcode.writeExtrusion(to, speedUp, extrusion_mm3_per_mm_connection, PrintFeatureType::OuterWall); gcode.writeRetraction(retraction_config); gcode.writeTravel(to + Point3(0, 0, retract_hop_dist), speedFlat); gcode.writeDelay(top_retract_pause); - if (after_retract_hop) + if (after_retract_hop) { - gcode.writeTravel(to + Point3(0, 0, retract_hop_dist*3), speedFlat); + gcode.writeTravel(to + Point3(0, 0, retract_hop_dist * 3), speedFlat); } } } @@ -294,17 +294,18 @@ void Wireframe2gcode::strategy_retract(WeaveConnectionPart& part, unsigned int s void Wireframe2gcode::strategy_compensate(WeaveConnectionPart& part, unsigned int segment_idx) { WeaveConnectionSegment& segment = part.connection.segments[segment_idx]; - Point3 from = (segment_idx == 0)? part.connection.from : part.connection.segments[segment_idx - 1].to; - Point3 to = segment.to + Point3(0, 0, fall_down*(segment.to - from).vSize() / connectionHeight); + Point3 from = (segment_idx == 0) ? part.connection.from : part.connection.segments[segment_idx - 1].to; + Point3 to = segment.to + Point3(0, 0, fall_down * (segment.to - from).vSize() / connectionHeight); Point3 vector = segment.to - from; Point3 dir = vector * drag_along / vector.vSize(); - + Point3 next_point; if (segment_idx + 1 < part.connection.segments.size()) { - WeaveConnectionSegment& next_segment = part.connection.segments[segment_idx+1]; + WeaveConnectionSegment& next_segment = part.connection.segments[segment_idx + 1]; next_point = next_segment.to; - } else + } + else { next_point = part.connection.segments[0].to; } @@ -313,128 +314,128 @@ void Wireframe2gcode::strategy_compensate(WeaveConnectionPart& part, unsigned in int64_t next_dir_2D_size = vSize(next_dir_2D); if (next_dir_2D_size > 0) next_dir_2D = next_dir_2D * drag_along / next_dir_2D_size; - Point3 next_dir (next_dir_2D.X, next_dir_2D.Y, 0); - + Point3 next_dir(next_dir_2D.X, next_dir_2D.Y, 0); + Point3 newTop = to - next_dir + dir; - + int64_t orrLength = (segment.to - from).vSize() + next_vector.vSize() + 1; // + 1 in order to avoid division by zero int64_t newLength = (newTop - from).vSize() + (next_point - newTop).vSize() + 1; // + 1 in order to avoid division by zero - + gcode.writeExtrusion(newTop, speedUp * newLength / orrLength, extrusion_mm3_per_mm_connection * orrLength / newLength, PrintFeatureType::OuterWall); } void Wireframe2gcode::handle_segment(WeaveConnectionPart& part, unsigned int segment_idx) { WeaveConnectionSegment& segment = part.connection.segments[segment_idx]; - - switch(segment.segmentType) + + switch (segment.segmentType) { - case WeaveSegmentType::MOVE: - writeMoveWithRetract(segment.to); - break; - case WeaveSegmentType::DOWN: - go_down(part, segment_idx); - break; - case WeaveSegmentType::FLAT: - logWarning("Warning: flat piece in wire print connection.\n"); - break; - case WeaveSegmentType::UP: - if (strategy == STRATEGY_KNOT) - { - strategy_knot(part, segment_idx); - } else if (strategy == STRATEGY_RETRACT) - { - strategy_retract(part, segment_idx); - } else if (strategy == STRATEGY_COMPENSATE) - { - strategy_compensate(part, segment_idx); - } - break; - case WeaveSegmentType::DOWN_AND_FLAT: - logError("Down and flat move in non-horizontal connection!"); - break; + case WeaveSegmentType::MOVE: + writeMoveWithRetract(segment.to); + break; + case WeaveSegmentType::DOWN: + go_down(part, segment_idx); + break; + case WeaveSegmentType::FLAT: + spdlog::warn("Warning: flat piece in wire print connection."); + break; + case WeaveSegmentType::UP: + if (strategy == STRATEGY_KNOT) + { + strategy_knot(part, segment_idx); + } + else if (strategy == STRATEGY_RETRACT) + { + strategy_retract(part, segment_idx); + } + else if (strategy == STRATEGY_COMPENSATE) + { + strategy_compensate(part, segment_idx); + } + break; + case WeaveSegmentType::DOWN_AND_FLAT: + spdlog::error("Down and flat move in non-horizontal connection!"); + break; } } - - void Wireframe2gcode::handle_roof_segment(WeaveConnectionPart& part, unsigned int segment_idx) { WeaveConnectionSegment& segment = part.connection.segments[segment_idx]; - Point3 from = (segment_idx == 0)? part.connection.from : part.connection.segments[segment_idx - 1].to; + Point3 from = (segment_idx == 0) ? part.connection.from : part.connection.segments[segment_idx - 1].to; WeaveConnectionSegment* next_segment = nullptr; if (segment_idx + 1 < part.connection.segments.size()) - next_segment = &part.connection.segments[segment_idx+1]; - switch(segment.segmentType) + next_segment = &part.connection.segments[segment_idx + 1]; + switch (segment.segmentType) { - case WeaveSegmentType::MOVE: - case WeaveSegmentType::DOWN_AND_FLAT: - if (next_segment && next_segment->segmentType != WeaveSegmentType::DOWN_AND_FLAT) - { - writeMoveWithRetract(segment.to); - } - break; - case WeaveSegmentType::UP: - { - Point3 to = segment.to + Point3(0, 0, roof_fall_down); - - Point3 vector = segment.to - from; - if (vector.vSize2() == 0) return; - Point3 dir = vector * roof_drag_along / vector.vSize(); - - Point3 next_vector; - if (next_segment) - { - next_vector = next_segment->to - segment.to; - } else - { - next_vector = part.connection.segments[0].to - segment.to; - } - Point next_dir_2D(next_vector.x, next_vector.y); - Point3 detoured = to + dir; - if (vSize2(next_dir_2D) > 0) - { - next_dir_2D = next_dir_2D * roof_drag_along / vSize(next_dir_2D); - Point3 next_dir (next_dir_2D.X, next_dir_2D.Y, 0); - detoured -= next_dir; - } - - gcode.writeExtrusion(detoured, speedUp, extrusion_mm3_per_mm_connection, PrintFeatureType::Skin); + case WeaveSegmentType::MOVE: + case WeaveSegmentType::DOWN_AND_FLAT: + if (next_segment && next_segment->segmentType != WeaveSegmentType::DOWN_AND_FLAT) + { + writeMoveWithRetract(segment.to); + } + break; + case WeaveSegmentType::UP: + { + Point3 to = segment.to + Point3(0, 0, roof_fall_down); - } - break; - case WeaveSegmentType::DOWN: - gcode.writeExtrusion(segment.to, speedDown, extrusion_mm3_per_mm_connection, PrintFeatureType::Skin); - gcode.writeDelay(roof_outer_delay); - break; - case WeaveSegmentType::FLAT: - logError("Flat move in connection!"); - break; - } + Point3 vector = segment.to - from; + if (vector.vSize2() == 0) + return; + Point3 dir = vector * roof_drag_along / vector.vSize(); -} + Point3 next_vector; + if (next_segment) + { + next_vector = next_segment->to - segment.to; + } + else + { + next_vector = part.connection.segments[0].to - segment.to; + } + Point next_dir_2D(next_vector.x, next_vector.y); + Point3 detoured = to + dir; + if (vSize2(next_dir_2D) > 0) + { + next_dir_2D = next_dir_2D * roof_drag_along / vSize(next_dir_2D); + Point3 next_dir(next_dir_2D.X, next_dir_2D.Y, 0); + detoured -= next_dir; + } + gcode.writeExtrusion(detoured, speedUp, extrusion_mm3_per_mm_connection, PrintFeatureType::Skin); + } + break; + case WeaveSegmentType::DOWN: + gcode.writeExtrusion(segment.to, speedDown, extrusion_mm3_per_mm_connection, PrintFeatureType::Skin); + gcode.writeDelay(roof_outer_delay); + break; + case WeaveSegmentType::FLAT: + spdlog::error("Flat move in connection!"); + break; + } +} -void Wireframe2gcode::writeFill(std::vector& infill_insets, Polygons& roof_outlines - , std::function connectionHandler - , std::function flatHandler) +void Wireframe2gcode::writeFill(std::vector& infill_insets, + Polygons& roof_outlines, + std::function connectionHandler, + std::function flatHandler) { - // bottom: gcode.writeTypeComment(PrintFeatureType::Infill); for (unsigned int inset_idx = 0; inset_idx < infill_insets.size(); inset_idx++) { WeaveRoofPart& inset = infill_insets[inset_idx]; - - + + for (unsigned int inset_part_nr = 0; inset_part_nr < inset.connections.size(); inset_part_nr++) { WeaveConnectionPart& inset_part = inset.connections[inset_part_nr]; std::vector& segments = inset_part.connection.segments; - + gcode.writeTypeComment(PrintFeatureType::Support); // connection - if (segments.size() == 0) continue; + if (segments.size() == 0) + continue; Point3 first_extrusion_from = inset_part.connection.from; unsigned int first_segment_idx; for (first_segment_idx = 0; first_segment_idx < segments.size() && segments[first_segment_idx].segmentType == WeaveSegmentType::MOVE; first_segment_idx++) @@ -448,21 +449,20 @@ void Wireframe2gcode::writeFill(std::vector& infill_insets, Polyg { connectionHandler(*this, inset_part, segment_idx); } - + gcode.writeTypeComment(PrintFeatureType::InnerWall); // top for (unsigned int segment_idx = 0; segment_idx < segments.size(); segment_idx++) { WeaveConnectionSegment& segment = segments[segment_idx]; - if (segment.segmentType == WeaveSegmentType::DOWN) continue; + if (segment.segmentType == WeaveSegmentType::DOWN) + continue; - flatHandler(*this, segment); + flatHandler(*this, segment); } } - - } - + gcode.writeTypeComment(PrintFeatureType::OuterWall); // outer perimeter of the flat parts for (PolygonRef poly : roof_outlines) { @@ -471,14 +471,12 @@ void Wireframe2gcode::writeFill(std::vector& infill_insets, Polyg { Point3 to(p.X, p.Y, gcode.getPositionZ()); WeaveConnectionSegment segment(to, WeaveSegmentType::FLAT); - flatHandler(*this, segment); + flatHandler(*this, segment); } } } - - void Wireframe2gcode::writeMoveWithRetract(Point3 to) { if ((gcode.getPosition() - to).vSize2() >= nozzle_top_diameter * nozzle_top_diameter * 2 * 2) @@ -493,18 +491,16 @@ void Wireframe2gcode::writeMoveWithRetract(Point to) gcode.writeTravel(to, moveSpeed); } -Wireframe2gcode::Wireframe2gcode(Weaver& weaver, GCodeExport& gcode) -: gcode(gcode) -, wireFrame(weaver.wireFrame) +Wireframe2gcode::Wireframe2gcode(Weaver& weaver, GCodeExport& gcode) : gcode(gcode), wireFrame(weaver.wireFrame) { const Settings& scene_settings = Application::getInstance().current_slice->scene.settings; initial_layer_thickness = scene_settings.get("layer_height_0"); - connectionHeight = scene_settings.get("wireframe_height"); - roof_inset = scene_settings.get("wireframe_roof_inset"); - + connectionHeight = scene_settings.get("wireframe_height"); + roof_inset = scene_settings.get("wireframe_roof_inset"); + filament_diameter = scene_settings.get("material_diameter"); line_width = scene_settings.get("wall_line_width_x"); - + flowConnection = scene_settings.get("wireframe_flow_connection"); flowFlat = scene_settings.get("wireframe_flow_flat"); @@ -514,12 +510,12 @@ Wireframe2gcode::Wireframe2gcode(Weaver& weaver, GCodeExport& gcode) update_extrusion_offset = false; - nozzle_outer_diameter = scene_settings.get("machine_nozzle_tip_outer_diameter"); // ___ ___ . - // \ / . + nozzle_outer_diameter = scene_settings.get("machine_nozzle_tip_outer_diameter"); // ___ ___ . + // \ / . nozzle_expansion_angle = scene_settings.get("machine_nozzle_expansion_angle"); // \_U_/ . - nozzle_clearance = scene_settings.get("wireframe_nozzle_clearance"); // at least line width + nozzle_clearance = scene_settings.get("wireframe_nozzle_clearance"); // at least line width nozzle_top_diameter = tan(nozzle_expansion_angle) * connectionHeight + nozzle_outer_diameter + nozzle_clearance; - + moveSpeed = 40; speedBottom = scene_settings.get("wireframe_printspeed_bottom"); speedUp = scene_settings.get("wireframe_printspeed_up"); @@ -529,14 +525,14 @@ Wireframe2gcode::Wireframe2gcode(Weaver& weaver, GCodeExport& gcode) flat_delay = scene_settings.get("wireframe_flat_delay"); bottom_delay = scene_settings.get("wireframe_bottom_delay"); top_delay = scene_settings.get("wireframe_top_delay"); - + up_dist_half_speed = scene_settings.get("wireframe_up_half_speed"); - + top_jump_dist = scene_settings.get("wireframe_top_jump"); - + fall_down = scene_settings.get("wireframe_fall_down"); drag_along = scene_settings.get("wireframe_drag_along"); - + strategy = STRATEGY_COMPENSATE; if (scene_settings.get("wireframe_strategy") == "compensate") strategy = STRATEGY_COMPENSATE; @@ -544,22 +540,22 @@ Wireframe2gcode::Wireframe2gcode(Weaver& weaver, GCodeExport& gcode) strategy = STRATEGY_KNOT; if (scene_settings.get("wireframe_strategy") == "retract") strategy = STRATEGY_RETRACT; - + go_back_to_last_top = false; straight_first_when_going_down = scene_settings.get("wireframe_straight_before_down"); - + roof_fall_down = scene_settings.get("wireframe_roof_fall_down"); roof_drag_along = scene_settings.get("wireframe_roof_drag_along"); roof_outer_delay = scene_settings.get("wireframe_roof_outer_delay"); - - - standard_retraction_config.distance = scene_settings.get("retraction_amount"); //Retraction distance in mm. + + + standard_retraction_config.distance = scene_settings.get("retraction_amount"); // Retraction distance in mm. standard_retraction_config.prime_volume = std::max(0.0, scene_settings.get("retraction_extra_prime_amount")); standard_retraction_config.speed = scene_settings.get("retraction_retract_speed"); standard_retraction_config.primeSpeed = scene_settings.get("retraction_prime_speed"); standard_retraction_config.zHop = scene_settings.get("retraction_hop"); standard_retraction_config.retraction_count_max = scene_settings.get("retraction_count_max"); - standard_retraction_config.retraction_extrusion_window = scene_settings.get("retraction_extrusion_window"); //Window in which to count retractions in mm of extruded filament. + standard_retraction_config.retraction_extrusion_window = scene_settings.get("retraction_extrusion_window"); // Window in which to count retractions in mm of extruded filament. standard_retraction_config.retraction_min_travel_distance = scene_settings.get("retraction_min_travel"); } @@ -632,26 +628,29 @@ void Wireframe2gcode::processStartingCode() void Wireframe2gcode::processSkirt() { - if (wireFrame.bottom_outline.size() == 0) //If we have no layers, don't create a skirt either. + if (wireFrame.bottom_outline.size() == 0) // If we have no layers, don't create a skirt either. { return; } Polygons skirt = wireFrame.bottom_outline.offset(MM2INT(100 + 5), ClipperLib::jtRound).offset(MM2INT(-100), ClipperLib::jtRound); PathOrderOptimizer order(Point(INT32_MIN, INT32_MIN)); - for(PolygonRef skirt_path : skirt) + for (PolygonRef skirt_path : skirt) { order.addPolygon(skirt_path); } order.optimize(); const Settings& scene_settings = Application::getInstance().current_slice->scene.settings; - for(const PathOrderPath& path : order.paths) + for (const PathOrderPath& path : order.paths) { gcode.writeTravel((*path.vertices)[path.start_vertex], scene_settings.get("speed_travel")); - for(size_t vertex_index = 0; vertex_index < path.vertices->size(); ++vertex_index) + for (size_t vertex_index = 0; vertex_index < path.vertices->size(); ++vertex_index) { Point vertex = (*path.vertices)[(vertex_index + path.start_vertex + 1) % path.vertices->size()]; - gcode.writeExtrusion(vertex, scene_settings.get("skirt_brim_speed"), scene_settings.get("skirt_brim_line_width") * scene_settings.get("initial_layer_line_width_factor") * INT2MM(initial_layer_thickness), PrintFeatureType::SkirtBrim); + gcode.writeExtrusion(vertex, + scene_settings.get("skirt_brim_speed"), + scene_settings.get("skirt_brim_line_width") * scene_settings.get("initial_layer_line_width_factor") * INT2MM(initial_layer_thickness), + PrintFeatureType::SkirtBrim); } } } @@ -665,4 +664,4 @@ void Wireframe2gcode::finalize() gcode.writeTemperatureCommand(e, 0, false); } } -}//namespace cura +} // namespace cura diff --git a/src/communication/ArcusCommunication.cpp b/src/communication/ArcusCommunication.cpp index 90fd7da9c1..30786e2cce 100644 --- a/src/communication/ArcusCommunication.cpp +++ b/src/communication/ArcusCommunication.cpp @@ -1,5 +1,5 @@ -// Copyright (c) 2022 Ultimaker B.V. -// CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #ifdef ARCUS @@ -7,18 +7,19 @@ #include //To sleep while waiting for the connection. #include //To map settings to their extruder numbers for limit_to_extruder. -#include "communication/ArcusCommunication.h" -#include "communication/ArcusCommunicationPrivate.h" //Our PIMPL. -#include "communication/Listener.h" //To listen to the Arcus socket. -#include "communication/SliceDataStruct.h" //To store sliced layer data. +#include + #include "Application.h" //To get and set the current slice command. #include "ExtruderTrain.h" #include "FffProcessor.h" //To start a slice. #include "PrintFeature.h" #include "Slice.h" //To process slices. +#include "communication/ArcusCommunication.h" +#include "communication/ArcusCommunicationPrivate.h" //Our PIMPL. +#include "communication/Listener.h" //To listen to the Arcus socket. +#include "communication/SliceDataStruct.h" //To store sliced layer data. #include "settings/types/LayerIndex.h" //To point to layers. #include "settings/types/Velocity.h" //To send to layer view how fast stuff is printing. -#include "utils/logoutput.h" #include "utils/polygon.h" namespace cura @@ -52,22 +53,24 @@ class ArcusCommunication::PathCompiler PathCompiler(const PathCompiler&) = delete; PathCompiler& operator=(const PathCompiler&) = delete; + public: /* * Create a new path compiler. */ - PathCompiler(ArcusCommunication::Private& cs_private_data): - _cs_private_data(cs_private_data), - _layer_nr(0), - extruder(0), - data_point_type(cura::proto::PathSegment::Point2D), - line_types(), - line_widths(), - line_thicknesses(), - line_velocities(), - points(), - last_point{0,0} - {} + PathCompiler(ArcusCommunication::Private& cs_private_data) + : _cs_private_data(cs_private_data) + , _layer_nr(0) + , extruder(0) + , data_point_type(cura::proto::PathSegment::Point2D) + , line_types() + , line_widths() + , line_thicknesses() + , line_velocities() + , points() + , last_point{ 0, 0 } + { + } /* * Flush the remaining unflushed paths when destroying this compiler. @@ -142,7 +145,7 @@ class ArcusCommunication::PathCompiler { if (line_types.empty()) { - return; //Nothing to do. + return; // Nothing to do. } std::shared_ptr proto_layer = _cs_private_data.getOptimizedLayerById(_layer_nr); @@ -198,7 +201,7 @@ class ArcusCommunication::PathCompiler */ void sendLineTo(const PrintFeatureType& print_feature_type, const Point& to, const coord_t& width, const coord_t& thickness, const Velocity& feedrate) { - assert(!points.empty() && "A point must already be in the buffer for sendLineTo(.) to function properly."); + assert(! points.empty() && "A point must already be in the buffer for sendLineTo(.) to function properly."); if (to != last_point) { @@ -217,7 +220,7 @@ class ArcusCommunication::PathCompiler */ void sendPolygon(const PrintFeatureType& print_feature_type, const ConstPolygonRef& polygon, const coord_t& width, const coord_t& thickness, const Velocity& velocity) { - if (polygon.size() < 2) //Don't send single points or empty polygons. + if (polygon.size() < 2) // Don't send single points or empty polygons. { return; } @@ -225,17 +228,17 @@ class ArcusCommunication::PathCompiler ClipperLib::Path::const_iterator point = polygon.begin(); handleInitialPoint(*point); - //Send all coordinates one by one. - while(++point != polygon.end()) + // Send all coordinates one by one. + while (++point != polygon.end()) { if (*point == last_point) { - continue; //Ignore zero-length segments. + continue; // Ignore zero-length segments. } addLineSegment(print_feature_type, *point, width, thickness, velocity); } - //Make sure the polygon is closed. + // Make sure the polygon is closed. if (*polygon.begin() != polygon.back()) { addLineSegment(print_feature_type, *polygon.begin(), width, thickness, velocity); @@ -278,15 +281,13 @@ class ArcusCommunication::PathCompiler } }; -ArcusCommunication::ArcusCommunication() - : private_data(new Private) - , path_compiler(new PathCompiler(*private_data)) +ArcusCommunication::ArcusCommunication() : private_data(new Private), path_compiler(new PathCompiler(*private_data)) { } ArcusCommunication::~ArcusCommunication() { - log("Closing connection.\n"); + spdlog::info("Closing connection."); private_data->socket->close(); delete private_data->socket; } @@ -307,17 +308,17 @@ void ArcusCommunication::connect(const std::string& ip, const uint16_t port) private_data->socket->registerMessageType(&cura::proto::SlicingFinished::default_instance()); private_data->socket->registerMessageType(&cura::proto::SettingExtruder::default_instance()); - log("Connecting to %s:%i\n", ip.c_str(), port); + spdlog::info("Connecting to {}:{}", ip, port); private_data->socket->connect(ip, port); auto socket_state = private_data->socket->getState(); while (socket_state != Arcus::SocketState::Connected && socket_state != Arcus::SocketState::Error) { - std::this_thread::sleep_for(std::chrono::milliseconds(private_data->millisecUntilNextTry)); //Wait until we're connected. Check every XXXms. + std::this_thread::sleep_for(std::chrono::milliseconds(private_data->millisecUntilNextTry)); // Wait until we're connected. Check every XXXms. socket_state = private_data->socket->getState(); } - if(socket_state != Arcus::SocketState::Connected) + if (socket_state != Arcus::SocketState::Connected) { - log("Connected to %s:%i\n", ip.c_str(), port); + spdlog::info("Connected to {}:{}", ip, port); } } @@ -342,7 +343,7 @@ void ArcusCommunication::flushGCode() std::shared_ptr message = std::make_shared(); message->set_data(message_str); - //Send the g-code to the front-end! Yay! + // Send the g-code to the front-end! Yay! private_data->socket->sendMessage(message); private_data->gcode_output_stream.str(""); @@ -350,14 +351,13 @@ void ArcusCommunication::flushGCode() bool ArcusCommunication::isSequential() const { - return false; //We don't necessarily need to send the start g-code before the rest. We can send it afterwards when we have more accurate print statistics. + return false; // We don't necessarily need to send the start g-code before the rest. We can send it afterwards when we have more accurate print statistics. } bool ArcusCommunication::hasSlice() const { - return private_data->socket->getState() != Arcus::SocketState::Closed - && private_data->socket->getState() != Arcus::SocketState::Error - && private_data->slice_count < 1; //Only slice once per run of CuraEngine. See documentation of slice_count. + return private_data->socket->getState() != Arcus::SocketState::Closed && private_data->socket->getState() != Arcus::SocketState::Error + && private_data->slice_count < 1; // Only slice once per run of CuraEngine. See documentation of slice_count. } void ArcusCommunication::sendCurrentPosition(const Point& position) @@ -383,7 +383,7 @@ void ArcusCommunication::sendFinishedSlicing() const { std::shared_ptr done_message = std::make_shared(); private_data->socket->sendMessage(done_message); - logDebug("Sent slicing finished message.\n"); + spdlog::debug("Sent slicing finished message."); } void ArcusCommunication::sendLayerComplete(const LayerIndex& layer_nr, const coord_t& z, const coord_t& thickness) @@ -400,21 +400,21 @@ void ArcusCommunication::sendLineTo(const PrintFeatureType& type, const Point& t void ArcusCommunication::sendOptimizedLayerData() { - path_compiler->flushPathSegments(); //Make sure the last path segment has been flushed from the compiler. + path_compiler->flushPathSegments(); // Make sure the last path segment has been flushed from the compiler. SliceDataStruct& data = private_data->optimized_layers; data.sliced_objects++; data.current_layer_offset = data.current_layer_count; - if (data.sliced_objects < private_data->object_count) //Nothing to send. + if (data.sliced_objects < private_data->object_count) // Nothing to send. { return; } - log("Sending %d layers.", data.current_layer_count); + spdlog::info("Sending {} layers.", data.current_layer_count); - for (std::pair> entry : data.slice_data) //Note: This is in no particular order! + for (std::pair> entry : data.slice_data) // Note: This is in no particular order! { - logDebug("Sending layer data for layer %i of %i.\n", entry.first, data.slice_data.size()); - private_data->socket->sendMessage(entry.second); //Send the actual layers. + spdlog::debug("Sending layer data for layer {} of {}.", entry.first, data.slice_data.size()); + private_data->socket->sendMessage(entry.second); // Send the actual layers. } data.sliced_objects = 0; data.current_layer_count = 0; @@ -429,7 +429,7 @@ void ArcusCommunication::sendPolygon(const PrintFeatureType& type, const ConstPo void ArcusCommunication::sendPolygons(const PrintFeatureType& type, const Polygons& polygons, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity) { - for(const std::vector& polygon : polygons) + for (const std::vector& polygon : polygons) { path_compiler->sendPolygon(type, polygon, line_width, line_thickness, velocity); } @@ -437,7 +437,7 @@ void ArcusCommunication::sendPolygons(const PrintFeatureType& type, const Polygo void ArcusCommunication::sendPrintTimeMaterialEstimates() const { - logDebug("Sending print time and material estimates.\n"); + spdlog::debug("Sending print time and material estimates."); std::shared_ptr message = std::make_shared(); std::vector time_estimates = FffProcessor::getInstance()->getTotalPrintTimePerFeature(); @@ -462,13 +462,13 @@ void ArcusCommunication::sendPrintTimeMaterialEstimates() const } private_data->socket->sendMessage(message); - logDebug("Done sending print time and material estimates.\n"); + spdlog::debug("Done sending print time and material estimates."); } void ArcusCommunication::sendProgress(const float& progress) const { const int rounded_amount = 1000 * progress; - if (private_data->last_sent_progress == rounded_amount) //No need to send another tiny update step. + if (private_data->last_sent_progress == rounded_amount) // No need to send another tiny update step. { return; } @@ -496,13 +496,13 @@ void ArcusCommunication::sliceNext() { const Arcus::MessagePtr message = private_data->socket->takeNextMessage(); - //Handle the main Slice message. - const cura::proto::Slice* slice_message = dynamic_cast(message.get()); //See if the message is of the message type Slice. Returns nullptr otherwise. - if (!slice_message) + // Handle the main Slice message. + const cura::proto::Slice* slice_message = dynamic_cast(message.get()); // See if the message is of the message type Slice. Returns nullptr otherwise. + if (! slice_message) { return; } - logDebug("Received a Slice message.\n"); + spdlog::debug("Received a Slice message."); Slice slice(slice_message->object_lists().size()); Application::getInstance().current_slice = &slice; @@ -511,28 +511,28 @@ void ArcusCommunication::sliceNext() private_data->readExtruderSettingsMessage(slice_message->extruders()); const size_t extruder_count = slice.scene.extruders.size(); - //For each setting, register what extruder it should be obtained from (if this is limited to an extruder). + // For each setting, register what extruder it should be obtained from (if this is limited to an extruder). for (const cura::proto::SettingExtruder& setting_extruder : slice_message->limit_to_extruder()) { - const int32_t extruder_nr = setting_extruder.extruder(); //Cast from proto::int to int32_t! + const int32_t extruder_nr = setting_extruder.extruder(); // Cast from proto::int to int32_t! if (extruder_nr < 0 || extruder_nr > static_cast(extruder_count)) { - //If it's -1 it should be ignored as per the spec. Let's also ignore it if it's beyond range. + // If it's -1 it should be ignored as per the spec. Let's also ignore it if it's beyond range. continue; } ExtruderTrain& extruder = slice.scene.extruders[setting_extruder.extruder()]; slice.scene.limit_to_extruder.emplace(setting_extruder.name(), &extruder); } - //Load all mesh groups, meshes and their settings. + // Load all mesh groups, meshes and their settings. private_data->object_count = 0; for (const cura::proto::ObjectList& mesh_group_message : slice_message->object_lists()) { private_data->readMeshGroupMessage(mesh_group_message); } - logDebug("Done reading Slice message.\n"); + spdlog::debug("Done reading Slice message."); - if (!slice.scene.mesh_groups.empty()) + if (! slice.scene.mesh_groups.empty()) { slice.compute(); FffProcessor::getInstance()->finalize(); @@ -543,9 +543,9 @@ void ArcusCommunication::sliceNext() private_data->slice_count++; } - std::this_thread::sleep_for(std::chrono::milliseconds(250)); //Pause before checking again for a slice message. + std::this_thread::sleep_for(std::chrono::milliseconds(250)); // Pause before checking again for a slice message. } -} //namespace cura +} // namespace cura -#endif //ARCUS \ No newline at end of file +#endif // ARCUS \ No newline at end of file diff --git a/src/communication/ArcusCommunicationPrivate.cpp b/src/communication/ArcusCommunicationPrivate.cpp index c25d445a9f..9de1b6e2d3 100644 --- a/src/communication/ArcusCommunicationPrivate.cpp +++ b/src/communication/ArcusCommunicationPrivate.cpp @@ -1,38 +1,35 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #ifdef ARCUS -#include "communication/ArcusCommunicationPrivate.h" +#include + #include "Application.h" #include "ExtruderTrain.h" #include "Slice.h" +#include "communication/ArcusCommunicationPrivate.h" #include "settings/types/LayerIndex.h" -#include "utils/floatpoint.h" //To accept vertices (which are provided in floating point). #include "utils/FMatrix4x3.h" //To convert vertices to integer-points. -#include "utils/logoutput.h" +#include "utils/floatpoint.h" //To accept vertices (which are provided in floating point). namespace cura { -ArcusCommunication::Private::Private() - : socket(nullptr) - , object_count(0) - , last_sent_progress(-1) - , slice_count(0) - , millisecUntilNextTry(100) -{} +ArcusCommunication::Private::Private() : socket(nullptr), object_count(0), last_sent_progress(-1), slice_count(0), millisecUntilNextTry(100) +{ +} std::shared_ptr ArcusCommunication::Private::getOptimizedLayerById(LayerIndex layer_nr) { layer_nr += optimized_layers.current_layer_offset; std::unordered_map>::iterator find_result = optimized_layers.slice_data.find(layer_nr); - if (find_result != optimized_layers.slice_data.end()) //Load layer from the cache. + if (find_result != optimized_layers.slice_data.end()) // Load layer from the cache. { return find_result->second; } - else //Not in the cache yet. Create an empty layer. + else // Not in the cache yet. Create an empty layer. { std::shared_ptr layer = std::make_shared(); layer->set_id(layer_nr); @@ -53,7 +50,7 @@ void ArcusCommunication::Private::readGlobalSettingsMessage(const proto::Setting void ArcusCommunication::Private::readExtruderSettingsMessage(const google::protobuf::RepeatedPtrField& extruder_messages) { - //Make sure we have enough extruders added currently. + // Make sure we have enough extruders added currently. Slice* slice = Application::getInstance().current_slice; const size_t extruder_count = slice->scene.settings.get("machine_extruder_count"); for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) @@ -61,16 +58,16 @@ void ArcusCommunication::Private::readExtruderSettingsMessage(const google::prot slice->scene.extruders.emplace_back(extruder_nr, &slice->scene.settings); } - //Parse the extruder number and the settings from the messages. + // Parse the extruder number and the settings from the messages. for (const cura::proto::Extruder& extruder_message : extruder_messages) { - const int32_t extruder_nr = extruder_message.id(); //Cast from proto::int to int32_t! + const int32_t extruder_nr = extruder_message.id(); // Cast from proto::int to int32_t! if (extruder_nr < 0 || extruder_nr >= static_cast(extruder_count)) { - logWarning("Received extruder index that is out of range: %i\n", extruder_nr); + spdlog::warn("Received extruder index that is out of range: {}", extruder_nr); continue; } - ExtruderTrain& extruder = slice->scene.extruders[extruder_nr]; //Extruder messages may arrive out of order, so don't iteratively get the next extruder but take the extruder_nr from this message. + ExtruderTrain& extruder = slice->scene.extruders[extruder_nr]; // Extruder messages may arrive out of order, so don't iteratively get the next extruder but take the extruder_nr from this message. for (const cura::proto::Setting& setting_message : extruder_message.settings().settings()) { extruder.settings.add(setting_message.name(), setting_message.value()); @@ -82,13 +79,13 @@ void ArcusCommunication::Private::readMeshGroupMessage(const proto::ObjectList& { if (mesh_group_message.objects_size() <= 0) { - return; //Don't slice empty mesh groups. + return; // Don't slice empty mesh groups. } Scene& scene = Application::getInstance().current_slice->scene; MeshGroup& mesh_group = scene.mesh_groups.at(object_count); - //Load the settings in the mesh group. + // Load the settings in the mesh group. for (const cura::proto::Setting& setting : mesh_group_message.settings()) { mesh_group.settings.add(setting.name(), setting.value()); @@ -97,24 +94,24 @@ void ArcusCommunication::Private::readMeshGroupMessage(const proto::ObjectList& FMatrix4x3 matrix; for (const cura::proto::Object& object : mesh_group_message.objects()) { - const size_t bytes_per_face = sizeof(FPoint3) * 3; //3 vectors per face. + const size_t bytes_per_face = sizeof(FPoint3) * 3; // 3 vectors per face. const size_t face_count = object.vertices().size() / bytes_per_face; if (face_count <= 0) { - logWarning("Got an empty mesh. Ignoring it!"); + spdlog::warn("Got an empty mesh. Ignoring it!"); continue; } mesh_group.meshes.emplace_back(); Mesh& mesh = mesh_group.meshes.back(); - //Load the settings for the mesh. + // Load the settings for the mesh. for (const cura::proto::Setting& setting : object.settings()) { mesh.settings.add(setting.name(), setting.value()); } - ExtruderTrain& extruder = mesh.settings.get("extruder_nr"); //Set the parent setting to the correct extruder. + ExtruderTrain& extruder = mesh.settings.get("extruder_nr"); // Set the parent setting to the correct extruder. mesh.settings.setParent(&extruder.settings); for (size_t face = 0; face < face_count; face++) @@ -136,6 +133,6 @@ void ArcusCommunication::Private::readMeshGroupMessage(const proto::ObjectList& mesh_group.finalize(); } -} //namespace cura +} // namespace cura -#endif //ARCUS \ No newline at end of file +#endif // ARCUS \ No newline at end of file diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index 998d4fc55f..1c9504b1a3 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -2,48 +2,70 @@ // CuraEngine is released under the terms of the AGPLv3 or higher #include //For strtok and strcopy. -#include //To check if files exist. #include // error number when trying to read file +#include //To check if files exist. #include //For std::accumulate. #include #include #include //Loading JSON documents to get settings from them. #include +#include #include -#include "communication/CommandLine.h" +#include + #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 "Slice.h" +#include "communication/CommandLine.h" #include "utils/FMatrix4x3.h" //For the mesh_rotation_matrix setting. -#include "utils/logoutput.h" namespace cura { -CommandLine::CommandLine(const std::vector& arguments) -: arguments(arguments) -, last_shown_progress(0) +CommandLine::CommandLine(const std::vector& arguments) : arguments(arguments), last_shown_progress(0) { } -//These are not applicable to command line slicing. -void CommandLine::beginGCode() { } -void CommandLine::flushGCode() { } -void CommandLine::sendCurrentPosition(const Point&) { } -void CommandLine::sendFinishedSlicing() const { } -void CommandLine::sendLayerComplete(const LayerIndex&, const coord_t&, const coord_t&) { } -void CommandLine::sendLineTo(const PrintFeatureType&, const Point&, const coord_t&, const coord_t&, const Velocity&) { } -void CommandLine::sendOptimizedLayerData() { } -void CommandLine::sendPolygon(const PrintFeatureType&, const ConstPolygonRef&, const coord_t&, const coord_t&, const Velocity&) { } -void CommandLine::sendPolygons(const PrintFeatureType&, const Polygons&, const coord_t&, const coord_t&, const Velocity&) { } -void CommandLine::setExtruderForSend(const ExtruderTrain&) { } -void CommandLine::setLayerForSend(const LayerIndex&) { } +// These are not applicable to command line slicing. +void CommandLine::beginGCode() +{ +} +void CommandLine::flushGCode() +{ +} +void CommandLine::sendCurrentPosition(const Point&) +{ +} +void CommandLine::sendFinishedSlicing() const +{ +} +void CommandLine::sendLayerComplete(const LayerIndex&, const coord_t&, const coord_t&) +{ +} +void CommandLine::sendLineTo(const PrintFeatureType&, const Point&, const coord_t&, const coord_t&, const Velocity&) +{ +} +void CommandLine::sendOptimizedLayerData() +{ +} +void CommandLine::sendPolygon(const PrintFeatureType&, const ConstPolygonRef&, const coord_t&, const coord_t&, const Velocity&) +{ +} +void CommandLine::sendPolygons(const PrintFeatureType&, const Polygons&, const coord_t&, const coord_t&, const Velocity&) +{ +} +void CommandLine::setExtruderForSend(const ExtruderTrain&) +{ +} +void CommandLine::setLayerForSend(const LayerIndex&) +{ +} bool CommandLine::hasSlice() const { - return !arguments.empty(); + return ! arguments.empty(); } bool CommandLine::isSequential() const @@ -65,7 +87,7 @@ void CommandLine::sendPrintTimeMaterialEstimates() const { std::vector time_estimates = FffProcessor::getInstance()->getTotalPrintTimePerFeature(); double sum = std::accumulate(time_estimates.begin(), time_estimates.end(), 0.0); - log("Total print time: %5.3fs\n", sum); + spdlog::info("Total print time: {:3}", sum); sum = 0.0; for (size_t extruder_nr = 0; extruder_nr < Application::getInstance().current_slice->scene.extruders.size(); extruder_nr++) @@ -77,22 +99,22 @@ void CommandLine::sendPrintTimeMaterialEstimates() const void CommandLine::sendProgress(const float& progress) const { const unsigned int rounded_amount = 100 * progress; - if (last_shown_progress == rounded_amount) //No need to send another tiny update step. + if (last_shown_progress == rounded_amount) // No need to send another tiny update step. { return; } - //TODO: Do we want to print a progress bar? We'd need a better solution to not have that progress bar be ruined by any logging. + // TODO: Do we want to print a progress bar? We'd need a better solution to not have that progress bar be ruined by any logging. } void CommandLine::sliceNext() { FffProcessor::getInstance()->time_keeper.restart(); - //Count the number of mesh groups to slice for. + // Count the number of mesh groups to slice for. size_t num_mesh_groups = 1; for (size_t argument_index = 2; argument_index < arguments.size(); argument_index++) { - if (arguments[argument_index].find("--next") == 0) //Starts with "--next". + if (arguments[argument_index].find("--next") == 0) // Starts with "--next". { num_mesh_groups++; } @@ -104,224 +126,224 @@ void CommandLine::sliceNext() size_t mesh_group_index = 0; Settings* last_settings = &slice.scene.settings; - slice.scene.extruders.reserve(arguments.size() >> 1); //Allocate enough memory to prevent moves. - slice.scene.extruders.emplace_back(0, &slice.scene.settings); //Always have one extruder. + slice.scene.extruders.reserve(arguments.size() >> 1); // Allocate enough memory to prevent moves. + slice.scene.extruders.emplace_back(0, &slice.scene.settings); // Always have one extruder. ExtruderTrain* last_extruder = &slice.scene.extruders[0]; for (size_t argument_index = 2; argument_index < arguments.size(); argument_index++) { std::string argument = arguments[argument_index]; - if (argument[0] == '-') //Starts with "-". + if (argument[0] == '-') // Starts with "-". { - if (argument[1] == '-') //Starts with "--". + if (argument[1] == '-') // Starts with "--". { - if (argument.find("--next") == 0) //Starts with "--next". + if (argument.find("--next") == 0) // Starts with "--next". { try { - log("Loaded from disk in %5.3fs\n", FffProcessor::getInstance()->time_keeper.restart()); + spdlog::info("Loaded from disk in {}", FffProcessor::getInstance()->time_keeper.restart()); mesh_group_index++; FffProcessor::getInstance()->time_keeper.restart(); last_settings = &slice.scene.mesh_groups[mesh_group_index].settings; } - catch(...) + catch (...) { - //Catch all exceptions. - //This prevents the "something went wrong" dialogue on Windows to pop up on a thrown exception. - //Only ClipperLib currently throws exceptions. And only in the case that it makes an internal error. - logError("Unknown exception!\n"); + // Catch all exceptions. + // This prevents the "something went wrong" dialogue on Windows to pop up on a thrown exception. + // Only ClipperLib currently throws exceptions. And only in the case that it makes an internal error. + spdlog::error("Unknown exception!"); exit(1); } } else { - logError("Unknown option: %s\n", argument.c_str()); + spdlog::error("Unknown option: {}", argument); } } - else //Starts with "-" but not with "--". + else // Starts with "-" but not with "--". { argument = arguments[argument_index]; - switch(argument[1]) + switch (argument[1]) { - case 'v': - { - increaseVerboseLevel(); - break; - } - case 'm': + case 'v': + { + spdlog::set_level(spdlog::level::debug); + break; + } + case 'm': + { + int threads = stoi(argument.substr(2)); + Application::getInstance().startThreadPool(threads); + break; + } + case 'p': + { + // enableProgressLogging(); FIXME: how to handle progress logging? Is this still relevant? + break; + } + case 'j': + { + argument_index++; + if (argument_index >= arguments.size()) { - int threads = stoi(argument.substr(2)); - Application::getInstance().startThreadPool(threads); - break; + spdlog::error("Missing JSON file with -j argument."); + exit(1); } - case 'p': + argument = arguments[argument_index]; + if (loadJSON(argument, *last_settings)) { - enableProgressLogging(); - break; + spdlog::error("Failed to load JSON file: {}", argument); + exit(1); } - case 'j': - { - argument_index++; - if (argument_index >= arguments.size()) - { - logError("Missing JSON file with -j argument."); - exit(1); - } - argument = arguments[argument_index]; - if (loadJSON(argument, *last_settings)) - { - logError("Failed to load JSON file: %s\n", argument.c_str()); - exit(1); - } - //If this was the global stack, create extruders for the machine_extruder_count setting. - if (last_settings == &slice.scene.settings) - { - const size_t extruder_count = slice.scene.settings.get("machine_extruder_count"); - while (slice.scene.extruders.size() < extruder_count) - { - slice.scene.extruders.emplace_back(slice.scene.extruders.size(), &slice.scene.settings); - } - } - //If this was an extruder stack, make sure that the extruder_nr setting is correct. - if (last_settings == &last_extruder->settings) + // If this was the global stack, create extruders for the machine_extruder_count setting. + if (last_settings == &slice.scene.settings) + { + const size_t extruder_count = slice.scene.settings.get("machine_extruder_count"); + while (slice.scene.extruders.size() < extruder_count) { - last_extruder->settings.add("extruder_nr", std::to_string(last_extruder->extruder_nr)); + slice.scene.extruders.emplace_back(slice.scene.extruders.size(), &slice.scene.settings); } - break; } - case 'e': + // If this was an extruder stack, make sure that the extruder_nr setting is correct. + if (last_settings == &last_extruder->settings) { - size_t extruder_nr = stoul(argument.substr(2)); - while (slice.scene.extruders.size() <= extruder_nr) //Make sure we have enough extruders up to the extruder_nr that the user wanted. - { - slice.scene.extruders.emplace_back(extruder_nr, &slice.scene.settings); - } - last_settings = &slice.scene.extruders[extruder_nr].settings; - last_settings->add("extruder_nr", argument.substr(2)); - last_extruder = &slice.scene.extruders[extruder_nr]; - break; + last_extruder->settings.add("extruder_nr", std::to_string(last_extruder->extruder_nr)); } - case 'l': + break; + } + case 'e': + { + size_t extruder_nr = stoul(argument.substr(2)); + while (slice.scene.extruders.size() <= extruder_nr) // Make sure we have enough extruders up to the extruder_nr that the user wanted. { - argument_index++; - if (argument_index >= arguments.size()) - { - logError("Missing model file with -l argument."); - exit(1); - } - argument = arguments[argument_index]; + slice.scene.extruders.emplace_back(extruder_nr, &slice.scene.settings); + } + last_settings = &slice.scene.extruders[extruder_nr].settings; + last_settings->add("extruder_nr", argument.substr(2)); + last_extruder = &slice.scene.extruders[extruder_nr]; + break; + } + case 'l': + { + argument_index++; + if (argument_index >= arguments.size()) + { + spdlog::error("Missing model file with -l argument."); + exit(1); + } + argument = arguments[argument_index]; - const FMatrix4x3 transformation = last_settings->get("mesh_rotation_matrix"); //The transformation applied to the model when loaded. + const FMatrix4x3 transformation = last_settings->get("mesh_rotation_matrix"); // The transformation applied to the model when loaded. - if (!loadMeshIntoMeshGroup(&slice.scene.mesh_groups[mesh_group_index], argument.c_str(), transformation, last_extruder->settings)) - { - logError("Failed to load model: %s. (error number %d)\n", argument.c_str(), errno); - exit(1); - } - else - { - last_settings = &slice.scene.mesh_groups[mesh_group_index].meshes.back().settings; - } - break; + if (! loadMeshIntoMeshGroup(&slice.scene.mesh_groups[mesh_group_index], argument.c_str(), transformation, last_extruder->settings)) + { + spdlog::error("Failed to load model: {}. (error number {})", argument, errno); + exit(1); } - case 'o': + else { - argument_index++; - if (argument_index >= arguments.size()) - { - logError("Missing output file with -o argument."); - exit(1); - } - argument = arguments[argument_index]; - if (!FffProcessor::getInstance()->setTargetFile(argument.c_str())) - { - logError("Failed to open %s for output.\n", argument.c_str()); - exit(1); - } - break; + last_settings = &slice.scene.mesh_groups[mesh_group_index].meshes.back().settings; } - case 'g': + break; + } + case 'o': + { + argument_index++; + if (argument_index >= arguments.size()) { - last_settings = &slice.scene.mesh_groups[mesh_group_index].settings; - break; + spdlog::error("Missing output file with -o argument."); + exit(1); } - /* ... falls through ... */ - case 's': + argument = arguments[argument_index]; + if (! FffProcessor::getInstance()->setTargetFile(argument.c_str())) { - //Parse the given setting and store it. - argument_index++; - if (argument_index >= arguments.size()) - { - logError("Missing setting name and value with -s argument."); - exit(1); - } - argument = arguments[argument_index]; - const size_t value_position = argument.find("="); - std::string key = argument.substr(0, value_position); - if (value_position == std::string::npos) - { - logError("Missing value in setting argument: -s %s", argument.c_str()); - exit(1); - } - std::string value = argument.substr(value_position + 1); - last_settings->add(key, value); - break; + spdlog::error("Failed to open {} for output.", argument.c_str()); + exit(1); } - default: + break; + } + case 'g': + { + last_settings = &slice.scene.mesh_groups[mesh_group_index].settings; + break; + } + /* ... falls through ... */ + case 's': + { + // Parse the given setting and store it. + argument_index++; + if (argument_index >= arguments.size()) { - logError("Unknown option: -%c\n", argument[1]); - Application::getInstance().printCall(); - Application::getInstance().printHelp(); + spdlog::error("Missing setting name and value with -s argument."); exit(1); - break; } + argument = arguments[argument_index]; + const size_t value_position = argument.find("="); + std::string key = argument.substr(0, value_position); + if (value_position == std::string::npos) + { + spdlog::error("Missing value in setting argument: -s {}", argument); + exit(1); + } + std::string value = argument.substr(value_position + 1); + last_settings->add(key, value); + break; + } + default: + { + spdlog::error("Unknown option: -{}", argument[1]); + Application::getInstance().printCall(); + Application::getInstance().printHelp(); + exit(1); + break; + } } } } else { - logError("Unknown option: %s\n", argument.c_str()); + spdlog::error("Unknown option: {}", argument); Application::getInstance().printCall(); Application::getInstance().printHelp(); exit(1); } } - arguments.clear(); //We've processed all arguments now. + arguments.clear(); // We've processed all arguments now. #ifndef DEBUG try { -#endif //DEBUG +#endif // DEBUG slice.scene.mesh_groups[mesh_group_index].finalize(); - log("Loaded from disk in %5.3fs\n", FffProcessor::getInstance()->time_keeper.restart()); + spdlog::info("Loaded from disk in {:3}s\n", FffProcessor::getInstance()->time_keeper.restart()); - //Start slicing. + // Start slicing. slice.compute(); #ifndef DEBUG } - catch(...) + catch (...) { - //Catch all exceptions. - //This prevents the "something went wrong" dialogue on Windows to pop up on a thrown exception. - //Only ClipperLib currently throws exceptions. And only in the case that it makes an internal error. - logError("Unknown exception.\n"); + // Catch all exceptions. + // This prevents the "something went wrong" dialogue on Windows to pop up on a thrown exception. + // Only ClipperLib currently throws exceptions. And only in the case that it makes an internal error. + spdlog::error("Unknown exception."); exit(1); } -#endif //DEBUG +#endif // DEBUG - //Finalize the processor. This adds the end g-code and reports statistics. + // Finalize the processor. This adds the end g-code and reports statistics. FffProcessor::getInstance()->finalize(); } int CommandLine::loadJSON(const std::string& json_filename, Settings& settings) { FILE* file = fopen(json_filename.c_str(), "rb"); - if (!file) + if (! file) { - logError("Couldn't open JSON file: %s\n", json_filename.c_str()); + spdlog::error("Couldn't open JSON file: {}", json_filename); return 1; } @@ -332,7 +354,7 @@ int CommandLine::loadJSON(const std::string& json_filename, Settings& settings) fclose(file); if (json_document.HasParseError()) { - logError("Error parsing JSON (offset %u): %s\n", static_cast(json_document.GetErrorOffset()), GetParseError_En(json_document.GetParseError())); + spdlog::error("Error parsing JSON (offset {}): {}", json_document.GetErrorOffset(), GetParseError_En(json_document.GetParseError())); return 2; } @@ -351,17 +373,17 @@ std::unordered_set CommandLine::defaultSearchDirectories() if (search_path_env) { #if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) - char delims[] = ":"; //Colon for Unix. + char delims[] = ":"; // Colon for Unix. #else - char delims[] = ";"; //Semicolon for Windows. + char delims[] = ";"; // Semicolon for Windows. #endif - char paths[128 * 1024]; //Maximum length of environment variable. - strcpy(paths, search_path_env); //Necessary because strtok actually modifies the original string, and we don't want to modify the environment variable itself. + char paths[128 * 1024]; // Maximum length of environment variable. + strcpy(paths, search_path_env); // Necessary because strtok actually modifies the original string, and we don't want to modify the environment variable itself. char* path = strtok(paths, delims); while (path != nullptr) { result.emplace(path); - path = strtok(nullptr, ";:,"); //Continue searching in last call to strtok. + path = strtok(nullptr, ";:,"); // Continue searching in last call to strtok. } } @@ -370,24 +392,24 @@ std::unordered_set CommandLine::defaultSearchDirectories() int CommandLine::loadJSON(const rapidjson::Document& document, const std::unordered_set& search_directories, Settings& settings) { - //Inheritance from other JSON documents. + // Inheritance from other JSON documents. if (document.HasMember("inherits") && document["inherits"].IsString()) { std::string parent_file = findDefinitionFile(document["inherits"].GetString(), search_directories); if (parent_file == "") { - logError("Inherited JSON file \"%s\" not found.\n", document["inherits"].GetString()); + spdlog::error("Inherited JSON file: {} not found.", document["inherits"].GetString()); return 1; } - int error_code = loadJSON(parent_file, settings); //Head-recursively load the settings file that we inherit from. + int error_code = loadJSON(parent_file, settings); // Head-recursively load the settings file that we inherit from. if (error_code) { return error_code; } } - //Extruders defined from here, if any. - //Note that this always puts the extruder settings in the slice of the current extruder. It doesn't keep the nested structure of the JSON files, if extruders would have their own sub-extruders. + // Extruders defined from here, if any. + // Note that this always puts the extruder settings in the slice of the current extruder. It doesn't keep the nested structure of the JSON files, if extruders would have their own sub-extruders. Scene& scene = Application::getInstance().current_slice->scene; if (document.HasMember("metadata") && document["metadata"].IsObject()) { @@ -407,7 +429,7 @@ int CommandLine::loadJSON(const rapidjson::Document& document, const std::unorde scene.extruders.emplace_back(scene.extruders.size(), &scene.settings); } const rapidjson::Value& extruder_id = extruder_train->value; - if (!extruder_id.IsString()) + if (! extruder_id.IsString()) { continue; } @@ -436,9 +458,9 @@ void CommandLine::loadJSONSettings(const rapidjson::Value& element, Settings& se const std::string name = setting->name.GetString(); const rapidjson::Value& setting_object = setting->value; - if (!setting_object.IsObject()) + if (! setting_object.IsObject()) { - logError("JSON setting %s is not an object!\n", name.c_str()); + spdlog::error("JSON setting {} is not an object!", name); continue; } @@ -446,11 +468,11 @@ void CommandLine::loadJSONSettings(const rapidjson::Value& element, Settings& se { loadJSONSettings(setting_object["children"], settings); } - else //Only process leaf settings. We don't process categories or settings that have sub-settings. + else // Only process leaf settings. We don't process categories or settings that have sub-settings. { - if (!setting_object.HasMember("default_value")) + if (! setting_object.HasMember("default_value")) { - logWarning("JSON setting %s has no default_value!\n", name.c_str()); + spdlog::warn("JSON setting {} has no default_value!", name); continue; } const rapidjson::Value& default_value = setting_object["default_value"]; @@ -475,7 +497,7 @@ void CommandLine::loadJSONSettings(const rapidjson::Value& element, Settings& se } else { - logWarning("Unrecognized data type in JSON setting %s\n", name.c_str()); + spdlog::warn("Unrecognized data type in JSON setting {}", name); continue; } settings.add(name, value_string); @@ -488,14 +510,14 @@ const std::string CommandLine::findDefinitionFile(const std::string& definition_ for (const std::string& search_directory : search_directories) { const std::string candidate = search_directory + std::string("/") + definition_id + std::string(".def.json"); - const std::ifstream ifile(candidate.c_str()); //Check whether the file exists and is readable by opening it. + const std::ifstream ifile(candidate.c_str()); // Check whether the file exists and is readable by opening it. if (ifile) { return candidate; } } - logError("Couldn't find definition file with ID: %s\n", definition_id.c_str()); + spdlog::error("Couldn't find definition file with ID: {}", definition_id); return std::string(""); } -} //namespace cura \ No newline at end of file +} // namespace cura \ No newline at end of file diff --git a/src/communication/Listener.cpp b/src/communication/Listener.cpp index 13566598c7..c28cfac327 100644 --- a/src/communication/Listener.cpp +++ b/src/communication/Listener.cpp @@ -1,38 +1,38 @@ -//Copyright (c) 2018 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #ifdef ARCUS #include //To process error codes. +#include #include "communication/Listener.h" -#include "utils/logoutput.h" namespace cura { void Listener::stateChanged(Arcus::SocketState) { - //Do nothing. + // Do nothing. } void Listener::messageReceived() { - //Do nothing. + // Do nothing. } void Listener::error(const Arcus::Error& error) { if (error.getErrorCode() == Arcus::ErrorCode::Debug) { - log("%s\n", error.getErrorMessage().c_str()); + spdlog::debug("{}", error.getErrorMessage()); } else { - logError("%s\n", error.getErrorMessage().c_str()); + spdlog::error("{}", error.getErrorMessage()); } } -} //namespace cura +} // namespace cura -#endif //ARCUS \ No newline at end of file +#endif // ARCUS \ No newline at end of file diff --git a/src/gcodeExport.cpp b/src/gcodeExport.cpp index 1661bf2aa4..970aeb0ed5 100644 --- a/src/gcodeExport.cpp +++ b/src/gcodeExport.cpp @@ -1,25 +1,27 @@ // Copyright (c) 2022 Ultimaker B.V. -// CuraEngine is released under the terms of the AGPLv3 or higher. +// CuraEngine is released under the terms of the AGPLv3 or higher #include #include #include #include +#include + #include "Application.h" //To send layer view data. #include "ExtruderTrain.h" -#include "gcodeExport.h" #include "PrintFeature.h" #include "RetractionConfig.h" #include "Slice.h" +#include "WipeScriptConfig.h" #include "communication/Communication.h" //To send layer view data. +#include "gcodeExport.h" #include "settings/types/LayerIndex.h" #include "utils/Date.h" -#include "utils/logoutput.h" #include "utils/string.h" // MMtoStream, PrecisionedDouble -#include "WipeScriptConfig.h" -namespace cura { +namespace cura +{ std::string transliterate(const std::string& text) { @@ -33,11 +35,7 @@ std::string transliterate(const std::string& text) return stream.str(); } -GCodeExport::GCodeExport() -: output_stream(&std::cout) -, currentPosition(0,0,MM2INT(20)) -, layer_nr(0) -, relative_extrusion(false) +GCodeExport::GCodeExport() : output_stream(&std::cout), currentPosition(0, 0, MM2INT(20)), layer_nr(0), relative_extrusion(false) { *output_stream << std::fixed; @@ -102,7 +100,7 @@ void GCodeExport::preSetup(const size_t start_extruder) { new_line = "\r\n"; } - else + else { new_line = "\n"; } @@ -119,8 +117,8 @@ void GCodeExport::setInitialAndBuildVolumeTemps(const unsigned int start_extrude const ExtruderTrain& train = scene.extruders[extruder_nr]; const Temperature print_temp_0 = train.settings.get("material_print_temperature_layer_0"); - const Temperature print_temp_here = (print_temp_0 != 0)? print_temp_0 : train.settings.get("material_print_temperature"); - const Temperature temp = (extruder_nr == start_extruder_nr)? print_temp_here : train.settings.get("material_standby_temperature"); + const Temperature print_temp_here = (print_temp_0 != 0) ? print_temp_0 : train.settings.get("material_print_temperature"); + const Temperature temp = (extruder_nr == start_extruder_nr) ? print_temp_here : train.settings.get("material_standby_temperature"); setInitialTemp(extruder_nr, temp); } @@ -142,25 +140,25 @@ const std::string GCodeExport::flavorToString(const EGCodeFlavor& flavor) const { switch (flavor) { - case EGCodeFlavor::BFB: - return "BFB"; - case EGCodeFlavor::MACH3: - return "Mach3"; - case EGCodeFlavor::MAKERBOT: - return "Makerbot"; - case EGCodeFlavor::ULTIGCODE: - return "UltiGCode"; - case EGCodeFlavor::MARLIN_VOLUMATRIC: - return "Marlin(Volumetric)"; - case EGCodeFlavor::GRIFFIN: - return "Griffin"; - case EGCodeFlavor::REPETIER: - return "Repetier"; - case EGCodeFlavor::REPRAP: - return "RepRap"; - case EGCodeFlavor::MARLIN: - default: - return "Marlin"; + case EGCodeFlavor::BFB: + return "BFB"; + case EGCodeFlavor::MACH3: + return "Mach3"; + case EGCodeFlavor::MAKERBOT: + return "Makerbot"; + case EGCodeFlavor::ULTIGCODE: + return "UltiGCode"; + case EGCodeFlavor::MARLIN_VOLUMATRIC: + return "Marlin(Volumetric)"; + case EGCodeFlavor::GRIFFIN: + return "Griffin"; + case EGCodeFlavor::REPETIER: + return "Repetier"; + case EGCodeFlavor::REPRAP: + return "RepRap"; + case EGCodeFlavor::MARLIN: + default: + return "Marlin"; } } @@ -182,7 +180,7 @@ std::string GCodeExport::getFileHeader(const std::vector& extruder_is_used for (size_t extr_nr = 0; extr_nr < extruder_count; extr_nr++) { - if (!extruder_is_used[extr_nr]) + if (! extruder_is_used[extr_nr]) { continue; } @@ -214,9 +212,9 @@ std::string GCodeExport::getFileHeader(const std::vector& extruder_is_used prefix << ";PRINT.GROUPS:" << Application::getInstance().current_slice->scene.mesh_groups.size() << new_line; - if (total_bounding_box.min.x > total_bounding_box.max.x) //We haven't encountered any movement (yet). This probably means we're command-line slicing. + if (total_bounding_box.min.x > total_bounding_box.max.x) // We haven't encountered any movement (yet). This probably means we're command-line slicing. { - //Put some small default in there. + // Put some small default in there. total_bounding_box.min = Point3(0, 0, 0); total_bounding_box.max = Point3(10, 10, 10); } @@ -231,11 +229,11 @@ std::string GCodeExport::getFileHeader(const std::vector& extruder_is_used break; default: prefix << ";FLAVOR:" << flavorToString(flavor) << new_line; - prefix << ";TIME:" << ((print_time)? static_cast(*print_time) : 6666) << new_line; + prefix << ";TIME:" << ((print_time) ? static_cast(*print_time) : 6666) << new_line; if (flavor == EGCodeFlavor::ULTIGCODE) { - prefix << ";MATERIAL:" << ((filament_used.size() >= 1)? static_cast(filament_used[0]) : 6666) << new_line; - prefix << ";MATERIAL2:" << ((filament_used.size() >= 2)? static_cast(filament_used[1]) : 0) << new_line; + prefix << ";MATERIAL:" << ((filament_used.size() >= 1) ? static_cast(filament_used[0]) : 6666) << new_line; + prefix << ";MATERIAL2:" << ((filament_used.size() >= 2) ? static_cast(filament_used[1]) : 0) << new_line; prefix << ";NOZZLE_DIAMETER:" << Application::getInstance().current_slice->scene.extruders[0].settings.get("machine_nozzle_size") << new_line; } @@ -254,7 +252,7 @@ std::string GCodeExport::getFileHeader(const std::vector& extruder_is_used { prefix << filament_used[i] / (1000 * extruder_attr[i].filament_area) << "m"; } - else //Use volumetric filament used. + else // Use volumetric filament used. { prefix << filament_used[i] << "mm3"; } @@ -279,7 +277,8 @@ std::string GCodeExport::getFileHeader(const std::vector& extruder_is_used } -void GCodeExport::setLayerNr(unsigned int layer_nr_) { +void GCodeExport::setLayerNr(unsigned int layer_nr_) +{ layer_nr = layer_nr_; } @@ -315,14 +314,14 @@ void GCodeExport::setFlavor(EGCodeFlavor flavor) this->flavor = flavor; if (flavor == EGCodeFlavor::MACH3) { - for(int n=0; nscene.extruders[current_extruder].settings; - if (!extruder_settings.get("machine_firmware_retract")) + if (! extruder_settings.get("machine_firmware_retract")) { // no E values are changed to perform a retraction extrusion_amount -= extruder_attr[current_extruder].retraction_e_amount_at_e_start; // subtract the increment in E which was used for the first unretraction instead of extrusion extrusion_amount += extruder_attr[current_extruder].retraction_e_amount_current; // add the decrement in E which the filament is behind on extrusion due to the last retraction @@ -466,7 +465,7 @@ std::vector GCodeExport::getTotalPrintTimePerFeature() double GCodeExport::getSumTotalPrintTimes() { double sum = 0.0; - for(double item : getTotalPrintTimePerFeature()) + for (double item : getTotalPrintTimePerFeature()) { sum += item; } @@ -475,11 +474,11 @@ double GCodeExport::getSumTotalPrintTimes() void GCodeExport::resetTotalPrintTimeAndFilament() { - for(size_t i = 0; i < total_print_times.size(); i++) + for (size_t i = 0; i < total_print_times.size(); i++) { total_print_times[i] = 0.0; } - for(unsigned int e=0; e estimates = estimateCalculator.calculate(); - for(size_t i = 0; i < estimates.size(); i++) + for (size_t i = 0; i < estimates.size(); i++) { total_print_times[i] += estimates[i]; } @@ -528,39 +527,39 @@ void GCodeExport::writeTypeComment(const PrintFeatureType& type) { switch (type) { - case PrintFeatureType::OuterWall: - *output_stream << ";TYPE:WALL-OUTER" << new_line; - break; - case PrintFeatureType::InnerWall: - *output_stream << ";TYPE:WALL-INNER" << new_line; - break; - case PrintFeatureType::Skin: - *output_stream << ";TYPE:SKIN" << new_line; - break; - case PrintFeatureType::Support: - *output_stream << ";TYPE:SUPPORT" << new_line; - break; - case PrintFeatureType::SkirtBrim: - *output_stream << ";TYPE:SKIRT" << new_line; - break; - case PrintFeatureType::Infill: - *output_stream << ";TYPE:FILL" << new_line; - break; - case PrintFeatureType::SupportInfill: - *output_stream << ";TYPE:SUPPORT" << new_line; - break; - case PrintFeatureType::SupportInterface: - *output_stream << ";TYPE:SUPPORT-INTERFACE" << new_line; - break; - case PrintFeatureType::PrimeTower: - *output_stream << ";TYPE:PRIME-TOWER" << new_line; - break; - case PrintFeatureType::MoveCombing: - case PrintFeatureType::MoveRetraction: - case PrintFeatureType::NoneType: - case PrintFeatureType::NumPrintFeatureTypes: - // do nothing - break; + case PrintFeatureType::OuterWall: + *output_stream << ";TYPE:WALL-OUTER" << new_line; + break; + case PrintFeatureType::InnerWall: + *output_stream << ";TYPE:WALL-INNER" << new_line; + break; + case PrintFeatureType::Skin: + *output_stream << ";TYPE:SKIN" << new_line; + break; + case PrintFeatureType::Support: + *output_stream << ";TYPE:SUPPORT" << new_line; + break; + case PrintFeatureType::SkirtBrim: + *output_stream << ";TYPE:SKIRT" << new_line; + break; + case PrintFeatureType::Infill: + *output_stream << ";TYPE:FILL" << new_line; + break; + case PrintFeatureType::SupportInfill: + *output_stream << ";TYPE:SUPPORT" << new_line; + break; + case PrintFeatureType::SupportInterface: + *output_stream << ";TYPE:SUPPORT-INTERFACE" << new_line; + break; + case PrintFeatureType::PrimeTower: + *output_stream << ";TYPE:PRIME-TOWER" << new_line; + break; + case PrintFeatureType::MoveCombing: + case PrintFeatureType::MoveRetraction: + case PrintFeatureType::NoneType: + case PrintFeatureType::NumPrintFeatureTypes: + // do nothing + break; } } @@ -594,7 +593,7 @@ void GCodeExport::writeExtrusionMode(bool set_relative_extrusion_mode) void GCodeExport::resetExtrusionValue() { - if (!relative_extrusion) + if (! relative_extrusion) { *output_stream << "G92 " << extruder_attr[current_extruder].extruderCharacter << "0" << new_line; } @@ -647,25 +646,25 @@ void GCodeExport::writeMoveBFB(const int x, const int y, const int z, const Velo { if (std::isinf(extrusion_mm3_per_mm)) { - logError("Extrusion rate is infinite!"); + spdlog::error("Extrusion rate is infinite!"); assert(false && "Infinite extrusion move!"); std::exit(1); } if (std::isnan(extrusion_mm3_per_mm)) { - logError("Extrusion rate is not a number!"); + spdlog::error("Extrusion rate is not a number!"); assert(false && "NaN extrusion move!"); std::exit(1); } double extrusion_per_mm = mm3ToE(extrusion_mm3_per_mm); - Point gcode_pos = getGcodePos(x,y, current_extruder); + Point gcode_pos = getGcodePos(x, y, current_extruder); - //For Bits From Bytes machines, we need to handle this completely differently. As they do not use E values but RPM values. + // For Bits From Bytes machines, we need to handle this completely differently. As they do not use E values but RPM values. float fspeed = speed * 60; float rpm = extrusion_per_mm * speed * 60; - const float mm_per_rpm = 4.0; //All BFB machines have 4mm per RPM extrusion. + const float mm_per_rpm = 4.0; // All BFB machines have 4mm per RPM extrusion. rpm /= mm_per_rpm; if (rpm > 0) { @@ -673,36 +672,36 @@ void GCodeExport::writeMoveBFB(const int x, const int y, const int z, const Velo { if (currentSpeed != double(rpm)) { - //fprintf(f, "; %f e-per-mm %d mm-width %d mm/s\n", extrusion_per_mm, lineWidth, speed); - //fprintf(f, "M108 S%0.1f\r\n", rpm); - *output_stream << "M108 S" << PrecisionedDouble{1, rpm} << new_line; + // fprintf(f, "; %f e-per-mm %d mm-width %d mm/s\n", extrusion_per_mm, lineWidth, speed); + // fprintf(f, "M108 S%0.1f\r\n", rpm); + *output_stream << "M108 S" << PrecisionedDouble{ 1, rpm } << new_line; currentSpeed = double(rpm); } - //Add M101 or M201 to enable the proper extruder. + // Add M101 or M201 to enable the proper extruder. *output_stream << "M" << int((current_extruder + 1) * 100 + 1) << new_line; extruder_attr[current_extruder].retraction_e_amount_current = 0.0; } - //Fix the speed by the actual RPM we are asking, because of rounding errors we cannot get all RPM values, but we have a lot more resolution in the feedrate value. - // (Trick copied from KISSlicer, thanks Jonathan) + // Fix the speed by the actual RPM we are asking, because of rounding errors we cannot get all RPM values, but we have a lot more resolution in the feedrate value. + // (Trick copied from KISSlicer, thanks Jonathan) fspeed *= (rpm / (roundf(rpm * 100) / 100)); - //Increase the extrusion amount to calculate the amount of filament used. - Point3 diff = Point3(x,y,z) - getPosition(); - + // Increase the extrusion amount to calculate the amount of filament used. + Point3 diff = Point3(x, y, z) - getPosition(); + current_e_value += extrusion_per_mm * diff.vSizeMM(); } else { - //If we are not extruding, check if we still need to disable the extruder. This causes a retraction due to auto-retraction. - if (!extruder_attr[current_extruder].retraction_e_amount_current) + // If we are not extruding, check if we still need to disable the extruder. This causes a retraction due to auto-retraction. + if (! extruder_attr[current_extruder].retraction_e_amount_current) { *output_stream << "M103" << new_line; extruder_attr[current_extruder].retraction_e_amount_current = 1.0; // 1.0 used as stub; BFB doesn't use the actual retraction amount; it performs retraction on the firmware automatically } } - *output_stream << "G1 X" << MMtoStream{gcode_pos.X} << " Y" << MMtoStream{gcode_pos.Y} << " Z" << MMtoStream{z}; - *output_stream << " F" << PrecisionedDouble{1, fspeed} << new_line; - + *output_stream << "G1 X" << MMtoStream{ gcode_pos.X } << " Y" << MMtoStream{ gcode_pos.Y } << " Z" << MMtoStream{ z }; + *output_stream << " F" << PrecisionedDouble{ 1, fspeed } << new_line; + currentPosition = Point3(x, y, z); estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value)), speed, feature); } @@ -718,8 +717,8 @@ void GCodeExport::writeTravel(const coord_t x, const coord_t y, const coord_t z, assert(speed < 1000 && speed > 1); // normal F values occurring in UM2 gcode (this code should not be compiled for release) assert(currentPosition != no_point3); assert(Point3(x, y, z) != no_point3); - assert((Point3(x,y,z) - currentPosition).vSize() < MM2INT(1000)); // no crazy positions (this code should not be compiled for release) -#endif //ASSERT_INSANE_OUTPUT + assert((Point3(x, y, z) - currentPosition).vSize() < MM2INT(1000)); // no crazy positions (this code should not be compiled for release) +#endif // ASSERT_INSANE_OUTPUT const PrintFeatureType travel_move_type = extruder_attr[current_extruder].retraction_e_amount_current ? PrintFeatureType::MoveRetraction : PrintFeatureType::MoveCombing; const int display_width = extruder_attr[current_extruder].retraction_e_amount_current ? MM2INT(0.2) : MM2INT(0.1); @@ -741,27 +740,27 @@ void GCodeExport::writeExtrusion(const coord_t x, const coord_t y, const coord_t assert(speed < 1000 && speed > 1); // normal F values occurring in UM2 gcode (this code should not be compiled for release) assert(currentPosition != no_point3); assert(Point3(x, y, z) != no_point3); - assert((Point3(x,y,z) - currentPosition).vSize() < MM2INT(1000)); // no crazy positions (this code should not be compiled for release) + assert((Point3(x, y, z) - currentPosition).vSize() < MM2INT(1000)); // no crazy positions (this code should not be compiled for release) assert(extrusion_mm3_per_mm >= 0.0); -#endif //ASSERT_INSANE_OUTPUT +#endif // ASSERT_INSANE_OUTPUT #ifdef DEBUG if (std::isinf(extrusion_mm3_per_mm)) { - logError("Extrusion rate is infinite!"); + spdlog::error("Extrusion rate is infinite!"); assert(false && "Infinite extrusion move!"); std::exit(1); } if (std::isnan(extrusion_mm3_per_mm)) { - logError("Extrusion rate is not a number!"); + spdlog::error("Extrusion rate is not a number!"); assert(false && "NaN extrusion move!"); std::exit(1); } if (extrusion_mm3_per_mm < 0.0) { - logWarning("Warning! Negative extrusion move!\n"); + spdlog::warn("Warning! Negative extrusion move!\n"); } #endif @@ -772,14 +771,14 @@ void GCodeExport::writeExtrusion(const coord_t x, const coord_t y, const coord_t writeZhopEnd(); } - const Point3 diff = Point3(x,y,z) - currentPosition; + const Point3 diff = Point3(x, y, z) - currentPosition; const double diff_length = diff.vSizeMM(); writeUnretractionAndPrime(); - //flow rate compensation + // flow rate compensation double extrusion_offset = 0; - if(diff_length) + if (diff_length) { extrusion_offset = speed * extrusion_mm3_per_mm * extrusion_offset_factor; if (extrusion_offset > max_extrusion_offset) @@ -805,25 +804,25 @@ void GCodeExport::writeFXYZE(const Velocity& speed, const coord_t x, const coord { if (currentSpeed != speed) { - *output_stream << " F" << PrecisionedDouble{1, speed * 60}; + *output_stream << " F" << PrecisionedDouble{ 1, speed * 60 }; currentSpeed = speed; } Point gcode_pos = getGcodePos(x, y, current_extruder); total_bounding_box.include(Point3(gcode_pos.X, gcode_pos.Y, z)); - *output_stream << " X" << MMtoStream{gcode_pos.X} << " Y" << MMtoStream{gcode_pos.Y}; + *output_stream << " X" << MMtoStream{ gcode_pos.X } << " Y" << MMtoStream{ gcode_pos.Y }; if (z != currentPosition.z) { - *output_stream << " Z" << MMtoStream{z}; + *output_stream << " Z" << MMtoStream{ z }; } if (e + current_e_offset != current_e_value) { - const double output_e = (relative_extrusion)? e + current_e_offset - current_e_value : e + current_e_offset; - *output_stream << " " << extruder_attr[current_extruder].extruderCharacter << PrecisionedDouble{5, output_e}; + const double output_e = (relative_extrusion) ? e + current_e_offset - current_e_value : e + current_e_offset; + *output_stream << " " << extruder_attr[current_extruder].extruderCharacter << PrecisionedDouble{ 5, output_e }; } *output_stream << new_line; - + currentPosition = Point3(x, y, z); current_e_value = e; estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(x), INT2MM(y), INT2MM(z), eToMm(e)), speed, feature); @@ -840,11 +839,12 @@ void GCodeExport::writeUnretractionAndPrime() if (extruder_settings.get("machine_firmware_retract")) { // note that BFB is handled differently *output_stream << "G11" << new_line; - //Assume default UM2 retraction settings. + // Assume default UM2 retraction settings. if (prime_volume != 0) { - const double output_e = (relative_extrusion)? prime_volume_e : current_e_value; - *output_stream << "G1 F" << PrecisionedDouble{1, extruder_attr[current_extruder].last_retraction_prime_speed * 60} << " " << extruder_attr[current_extruder].extruderCharacter << PrecisionedDouble{5, output_e} << new_line; + const double output_e = (relative_extrusion) ? prime_volume_e : current_e_value; + *output_stream << "G1 F" << PrecisionedDouble{ 1, extruder_attr[current_extruder].last_retraction_prime_speed * 60 } << " " << extruder_attr[current_extruder].extruderCharacter << PrecisionedDouble{ 5, output_e } + << new_line; currentSpeed = extruder_attr[current_extruder].last_retraction_prime_speed; } estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value)), 25.0, PrintFeatureType::MoveRetraction); @@ -852,23 +852,24 @@ void GCodeExport::writeUnretractionAndPrime() else { current_e_value += extruder_attr[current_extruder].retraction_e_amount_current; - const double output_e = (relative_extrusion)? extruder_attr[current_extruder].retraction_e_amount_current + prime_volume_e : current_e_value; - *output_stream << "G1 F" << PrecisionedDouble{1, extruder_attr[current_extruder].last_retraction_prime_speed * 60} << " " << extruder_attr[current_extruder].extruderCharacter << PrecisionedDouble{5, output_e} << new_line; + const double output_e = (relative_extrusion) ? extruder_attr[current_extruder].retraction_e_amount_current + prime_volume_e : current_e_value; + *output_stream << "G1 F" << PrecisionedDouble{ 1, extruder_attr[current_extruder].last_retraction_prime_speed * 60 } << " " << extruder_attr[current_extruder].extruderCharacter << PrecisionedDouble{ 5, output_e } << new_line; currentSpeed = extruder_attr[current_extruder].last_retraction_prime_speed; estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value)), currentSpeed, PrintFeatureType::MoveRetraction); } } else if (prime_volume != 0.0) { - const double output_e = (relative_extrusion)? prime_volume_e : current_e_value; - *output_stream << "G1 F" << PrecisionedDouble{1, extruder_attr[current_extruder].last_retraction_prime_speed * 60} << " " << extruder_attr[current_extruder].extruderCharacter; - *output_stream << PrecisionedDouble{5, output_e} << new_line; + const double output_e = (relative_extrusion) ? prime_volume_e : current_e_value; + *output_stream << "G1 F" << PrecisionedDouble{ 1, extruder_attr[current_extruder].last_retraction_prime_speed * 60 } << " " << extruder_attr[current_extruder].extruderCharacter; + *output_stream << PrecisionedDouble{ 5, output_e } << new_line; currentSpeed = extruder_attr[current_extruder].last_retraction_prime_speed; estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value)), currentSpeed, PrintFeatureType::NoneType); } extruder_attr[current_extruder].prime_volume = 0.0; - - if (getCurrentExtrudedVolume() > 10000.0 && flavor != EGCodeFlavor::BFB && flavor != EGCodeFlavor::MAKERBOT) //According to https://github.com/Ultimaker/CuraEngine/issues/14 having more then 21m of extrusion causes inaccuracies. So reset it every 10m, just to be sure. + + if (getCurrentExtrudedVolume() > 10000.0 && flavor != EGCodeFlavor::BFB + && flavor != EGCodeFlavor::MAKERBOT) // According to https://github.com/Ultimaker/CuraEngine/issues/14 having more then 21m of extrusion causes inaccuracies. So reset it every 10m, just to be sure. { resetExtrusionValue(); } @@ -882,11 +883,11 @@ void GCodeExport::writeRetraction(const RetractionConfig& config, bool force, bo { ExtruderTrainAttributes& extr_attr = extruder_attr[current_extruder]; - if(flavor == EGCodeFlavor::BFB) //BitsFromBytes does automatic retraction. + if (flavor == EGCodeFlavor::BFB) // BitsFromBytes does automatic retraction. { - if(extruder_switch) + if (extruder_switch) { - if(!extr_attr.retraction_e_amount_current) + if (! extr_attr.retraction_e_amount_current) { *output_stream << "M103" << new_line; } @@ -898,7 +899,7 @@ void GCodeExport::writeRetraction(const RetractionConfig& config, bool force, bo double old_retraction_e_amount = extr_attr.retraction_e_amount_current; double new_retraction_e_amount = mmToE(config.distance); double retraction_diff_e_amount = old_retraction_e_amount - new_retraction_e_amount; - if(std::abs(retraction_diff_e_amount) < 0.000001) + if (std::abs(retraction_diff_e_amount) < 0.000001) { return; } @@ -906,50 +907,52 @@ void GCodeExport::writeRetraction(const RetractionConfig& config, bool force, bo { // handle retraction limitation double current_extruded_volume = getCurrentExtrudedVolume(); std::deque& extruded_volume_at_previous_n_retractions = extr_attr.extruded_volume_at_previous_n_retractions; - while (extruded_volume_at_previous_n_retractions.size() > config.retraction_count_max && !extruded_volume_at_previous_n_retractions.empty()) + while (extruded_volume_at_previous_n_retractions.size() > config.retraction_count_max && ! extruded_volume_at_previous_n_retractions.empty()) { // extruder switch could have introduced data which falls outside the retraction window // also the retraction_count_max could have changed between the last retraction and this extruded_volume_at_previous_n_retractions.pop_back(); } - if(!force && config.retraction_count_max <= 0) + if (! force && config.retraction_count_max <= 0) { return; } - if(!force && extruded_volume_at_previous_n_retractions.size() == config.retraction_count_max - && current_extruded_volume < extruded_volume_at_previous_n_retractions.back() + config.retraction_extrusion_window * extr_attr.filament_area) + if (! force && extruded_volume_at_previous_n_retractions.size() == config.retraction_count_max + && current_extruded_volume < extruded_volume_at_previous_n_retractions.back() + config.retraction_extrusion_window * extr_attr.filament_area) { return; } extruded_volume_at_previous_n_retractions.push_front(current_extruded_volume); - if(extruded_volume_at_previous_n_retractions.size() == config.retraction_count_max + 1) + if (extruded_volume_at_previous_n_retractions.size() == config.retraction_count_max + 1) { extruded_volume_at_previous_n_retractions.pop_back(); } } const Settings& extruder_settings = Application::getInstance().current_slice->scene.extruders[current_extruder].settings; - if(extruder_settings.get("machine_firmware_retract")) + if (extruder_settings.get("machine_firmware_retract")) { - if(extruder_switch && extr_attr.retraction_e_amount_current) + if (extruder_switch && extr_attr.retraction_e_amount_current) { - return; + return; } *output_stream << "G10"; - if(extruder_switch && flavor == EGCodeFlavor::REPETIER) + if (extruder_switch && flavor == EGCodeFlavor::REPETIER) { *output_stream << " S1"; } *output_stream << new_line; - //Assume default UM2 retraction settings. - estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value + retraction_diff_e_amount)), 25, PrintFeatureType::MoveRetraction); // TODO: hardcoded values! + // Assume default UM2 retraction settings. + estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value + retraction_diff_e_amount)), + 25, + PrintFeatureType::MoveRetraction); // TODO: hardcoded values! } else { - double speed = ((retraction_diff_e_amount < 0.0)? config.speed : extr_attr.last_retraction_prime_speed); + double speed = ((retraction_diff_e_amount < 0.0) ? config.speed : extr_attr.last_retraction_prime_speed); current_e_value += retraction_diff_e_amount; - const double output_e = (relative_extrusion)? retraction_diff_e_amount : current_e_value; - *output_stream << "G1 F" << PrecisionedDouble{1, speed * 60} << " " << extr_attr.extruderCharacter << PrecisionedDouble{5, output_e} << new_line; + const double output_e = (relative_extrusion) ? retraction_diff_e_amount : current_e_value; + *output_stream << "G1 F" << PrecisionedDouble{ 1, speed * 60 } << " " << extr_attr.extruderCharacter << PrecisionedDouble{ 5, output_e } << new_line; currentSpeed = speed; estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value)), currentSpeed, PrintFeatureType::MoveRetraction); extr_attr.last_retraction_prime_speed = config.primeSpeed; @@ -959,7 +962,7 @@ void GCodeExport::writeRetraction(const RetractionConfig& config, bool force, bo extr_attr.prime_volume += config.prime_volume; } -void GCodeExport::writeZhopStart(const coord_t hop_height, Velocity speed/*= 0*/) +void GCodeExport::writeZhopStart(const coord_t hop_height, Velocity speed /*= 0*/) { if (hop_height > 0) { @@ -970,13 +973,13 @@ void GCodeExport::writeZhopStart(const coord_t hop_height, Velocity speed/*= 0*/ } is_z_hopped = hop_height; currentSpeed = speed; - *output_stream << "G1 F" << PrecisionedDouble{1, speed * 60} << " Z" << MMtoStream{current_layer_z + is_z_hopped} << new_line; + *output_stream << "G1 F" << PrecisionedDouble{ 1, speed * 60 } << " Z" << MMtoStream{ current_layer_z + is_z_hopped } << new_line; total_bounding_box.includeZ(current_layer_z + is_z_hopped); assert(speed > 0.0 && "Z hop speed should be positive."); } } -void GCodeExport::writeZhopEnd(Velocity speed/*= 0*/) +void GCodeExport::writeZhopEnd(Velocity speed /*= 0*/) { if (is_z_hopped) { @@ -988,7 +991,7 @@ void GCodeExport::writeZhopEnd(Velocity speed/*= 0*/) is_z_hopped = 0; currentPosition.z = current_layer_z; currentSpeed = speed; - *output_stream << "G1 F" << PrecisionedDouble{1, speed * 60} << " Z" << MMtoStream{current_layer_z} << new_line; + *output_stream << "G1 F" << PrecisionedDouble{ 1, speed * 60 } << " Z" << MMtoStream{ current_layer_z } << new_line; assert(speed > 0.0 && "Z hop speed should be positive."); } } @@ -1015,7 +1018,7 @@ void GCodeExport::startExtruder(const size_t new_extruder) const std::string start_code = Application::getInstance().current_slice->scene.extruders[new_extruder].settings.get("machine_extruder_start_code"); - if(!start_code.empty()) + if (! start_code.empty()) { if (relative_extrusion) { @@ -1033,7 +1036,7 @@ void GCodeExport::startExtruder(const size_t new_extruder) Application::getInstance().communication->setExtruderForSend(Application::getInstance().current_slice->scene.extruders[new_extruder]); Application::getInstance().communication->sendCurrentPosition(getPositionXY()); - //Change the Z position so it gets re-written again. We do not know if the switch code modified the Z position. + // Change the Z position so it gets re-written again. We do not know if the switch code modified the Z position. currentPosition.z += 1; setExtruderFanNumber(new_extruder); @@ -1047,7 +1050,7 @@ void GCodeExport::switchExtruder(size_t new_extruder, const RetractionConfig& re } const Settings& old_extruder_settings = Application::getInstance().current_slice->scene.extruders[current_extruder].settings; - if(old_extruder_settings.get("retraction_enable")) + if (old_extruder_settings.get("retraction_enable")) { constexpr bool force = true; constexpr bool extruder_switch = true; @@ -1063,7 +1066,7 @@ void GCodeExport::switchExtruder(size_t new_extruder, const RetractionConfig& re const std::string end_code = old_extruder_settings.get("machine_extruder_end_code"); - if(!end_code.empty()) + if (! end_code.empty()) { if (relative_extrusion) { @@ -1106,7 +1109,7 @@ void GCodeExport::writePrimeTrain(const Velocity& travel_speed) // but the frontend currently doesn't support a value function of an extruder setting depending on an fdmprinter setting, // which is needed to automatically ignore the prime position for the printer when blob is disabled Point3 prime_pos(extruder_settings.get("extruder_prime_pos_x"), extruder_settings.get("extruder_prime_pos_y"), extruder_settings.get("extruder_prime_pos_z")); - if (!extruder_settings.get("extruder_prime_pos_abs")) + if (! extruder_settings.get("extruder_prime_pos_abs")) { // currentPosition.z can be already z hopped prime_pos += Point3(currentPosition.x, currentPosition.y, current_layer_z); @@ -1117,11 +1120,11 @@ void GCodeExport::writePrimeTrain(const Velocity& travel_speed) if (flavor == EGCodeFlavor::GRIFFIN) { bool should_correct_z = false; - + std::string command = "G280"; - if (!extruder_settings.get("prime_blob_enable")) + if (! extruder_settings.get("prime_blob_enable")) { - command += " S1"; // use S1 to disable prime blob + command += " S1"; // use S1 to disable prime blob should_correct_z = true; } *output_stream << command << new_line; @@ -1134,7 +1137,7 @@ void GCodeExport::writePrimeTrain(const Velocity& travel_speed) { // Can't output via 'writeTravel', since if this is needed, the value saved for 'current height' will not be correct. // For similar reasons, this isn't written to the front-end via command-socket. - *output_stream << "G0 Z" << MMtoStream{getPositionZ()} << new_line; + *output_stream << "G0 Z" << MMtoStream{ getPositionZ() } << new_line; } } else @@ -1160,11 +1163,11 @@ void GCodeExport::writeFanCommand(double speed) { return; } - if(flavor == EGCodeFlavor::MAKERBOT) + if (flavor == EGCodeFlavor::MAKERBOT) { - if(speed >= 50) + if (speed >= 50) { - *output_stream << "M126 T0" << new_line; //Makerbot cannot PWM the fan speed... + *output_stream << "M126 T0" << new_line; // Makerbot cannot PWM the fan speed... } else { @@ -1174,7 +1177,7 @@ void GCodeExport::writeFanCommand(double speed) else if (speed > 0) { const bool should_scale_zero_to_one = Application::getInstance().current_slice->scene.settings.get("machine_scale_fan_speed_zero_to_one"); - *output_stream << "M106 S" << PrecisionedDouble{(should_scale_zero_to_one ? 2u : 1u), (should_scale_zero_to_one ? speed : speed * 255) / 100}; + *output_stream << "M106 S" << PrecisionedDouble{ (should_scale_zero_to_one ? 2u : 1u), (should_scale_zero_to_one ? speed : speed * 255) / 100 }; if (fan_number) { *output_stream << " P" << fan_number; @@ -1198,7 +1201,7 @@ void GCodeExport::writeTemperatureCommand(const size_t extruder, const Temperatu { const ExtruderTrain& extruder_train = Application::getInstance().current_slice->scene.extruders[extruder]; - if (!extruder_train.settings.get("machine_nozzle_temp_enabled")) + if (! extruder_train.settings.get("machine_nozzle_temp_enabled")) { return; } @@ -1230,14 +1233,14 @@ void GCodeExport::writeTemperatureCommand(const size_t extruder, const Temperatu } } - if ((!wait || extruder_attr[extruder].waited_for_temperature) && extruder_attr[extruder].currentTemperature == temperature) + if ((! wait || extruder_attr[extruder].waited_for_temperature) && extruder_attr[extruder].currentTemperature == temperature) { return; } if (wait && flavor != EGCodeFlavor::MAKERBOT) { - if(flavor == EGCodeFlavor::MARLIN) + if (flavor == EGCodeFlavor::MARLIN) { *output_stream << "M105" << new_line; // get temperatures from the last update, the M109 will not let get the target temperature } @@ -1256,15 +1259,15 @@ void GCodeExport::writeTemperatureCommand(const size_t extruder, const Temperatu #ifdef ASSERT_INSANE_OUTPUT assert(temperature >= 0); #endif // ASSERT_INSANE_OUTPUT - *output_stream << " S" << PrecisionedDouble{1, temperature} << new_line; + *output_stream << " S" << PrecisionedDouble{ 1, temperature } << new_line; if (extruder != current_extruder && always_write_active_tool) { - //Some firmwares (ie Smoothieware) change tools every time a "T" command is read - even on a M104 line, so we need to switch back to the active tool. + // Some firmwares (ie Smoothieware) change tools every time a "T" command is read - even on a M104 line, so we need to switch back to the active tool. *output_stream << "T" << current_extruder << new_line; } if (wait && flavor == EGCodeFlavor::MAKERBOT) { - //Makerbot doesn't use M109 for heat-and-wait. Instead, use M104 and then wait using M116. + // Makerbot doesn't use M109 for heat-and-wait. Instead, use M104 and then wait using M116. *output_stream << "M116" << new_line; } extruder_attr[extruder].currentTemperature = temperature; @@ -1279,26 +1282,26 @@ void GCodeExport::writeBedTemperatureCommand(const Temperature& temperature, con bool wrote_command = false; if (wait) { - if(bed_temperature != temperature) //Not already at the desired temperature. + if (bed_temperature != temperature) // Not already at the desired temperature. { - if(flavor == EGCodeFlavor::MARLIN) + if (flavor == EGCodeFlavor::MARLIN) { *output_stream << "M140 S"; // set the temperature, it will be used as target temperature from M105 - *output_stream << PrecisionedDouble{1, temperature} << new_line; + *output_stream << PrecisionedDouble{ 1, temperature } << new_line; *output_stream << "M105" << new_line; } } *output_stream << "M190 S"; wrote_command = true; } - else if(bed_temperature != temperature) + else if (bed_temperature != temperature) { *output_stream << "M140 S"; wrote_command = true; } - if(wrote_command) + if (wrote_command) { - *output_stream << PrecisionedDouble{1, temperature} << new_line; + *output_stream << PrecisionedDouble{ 1, temperature } << new_line; } bed_temperature = temperature; } @@ -1307,7 +1310,7 @@ void GCodeExport::writeBuildVolumeTemperatureCommand(const Temperature& temperat { if (flavor == EGCodeFlavor::ULTIGCODE || flavor == EGCodeFlavor::GRIFFIN) { - //Ultimaker printers don't support build volume temperature commands. + // Ultimaker printers don't support build volume temperature commands. return; } if (wait) @@ -1318,32 +1321,32 @@ void GCodeExport::writeBuildVolumeTemperatureCommand(const Temperature& temperat { *output_stream << "M141 S"; } - *output_stream << PrecisionedDouble{1, temperature} << new_line; + *output_stream << PrecisionedDouble{ 1, temperature } << new_line; } void GCodeExport::writePrintAcceleration(const Acceleration& acceleration) { switch (getFlavor()) { - case EGCodeFlavor::REPETIER: - if (current_print_acceleration != acceleration) - { - *output_stream << "M201 X" << PrecisionedDouble{0, acceleration} << " Y" << PrecisionedDouble{0, acceleration} << new_line; - } - break; - case EGCodeFlavor::REPRAP: - if (current_print_acceleration != acceleration) - { - *output_stream << "M204 P" << PrecisionedDouble{0, acceleration} << new_line; - } - break; - default: - // MARLIN, etc. only have one acceleration for both print and travel - if (current_print_acceleration != acceleration) - { - *output_stream << "M204 S" << PrecisionedDouble{0, acceleration} << new_line; - } - break; + case EGCodeFlavor::REPETIER: + if (current_print_acceleration != acceleration) + { + *output_stream << "M201 X" << PrecisionedDouble{ 0, acceleration } << " Y" << PrecisionedDouble{ 0, acceleration } << new_line; + } + break; + case EGCodeFlavor::REPRAP: + if (current_print_acceleration != acceleration) + { + *output_stream << "M204 P" << PrecisionedDouble{ 0, acceleration } << new_line; + } + break; + default: + // MARLIN, etc. only have one acceleration for both print and travel + if (current_print_acceleration != acceleration) + { + *output_stream << "M204 S" << PrecisionedDouble{ 0, acceleration } << new_line; + } + break; } current_print_acceleration = acceleration; estimateCalculator.setAcceleration(acceleration); @@ -1353,22 +1356,22 @@ void GCodeExport::writeTravelAcceleration(const Acceleration& acceleration) { switch (getFlavor()) { - case EGCodeFlavor::REPETIER: - if (current_travel_acceleration != acceleration) - { - *output_stream << "M202 X" << PrecisionedDouble{0, acceleration} << " Y" << PrecisionedDouble{0, acceleration} << new_line; - } - break; - case EGCodeFlavor::REPRAP: - if (current_travel_acceleration != acceleration) - { - *output_stream << "M204 T" << PrecisionedDouble{0, acceleration} << new_line; - } - break; - default: - // MARLIN, etc. only have one acceleration for both print and travel - writePrintAcceleration(acceleration); - break; + case EGCodeFlavor::REPETIER: + if (current_travel_acceleration != acceleration) + { + *output_stream << "M202 X" << PrecisionedDouble{ 0, acceleration } << " Y" << PrecisionedDouble{ 0, acceleration } << new_line; + } + break; + case EGCodeFlavor::REPRAP: + if (current_travel_acceleration != acceleration) + { + *output_stream << "M204 T" << PrecisionedDouble{ 0, acceleration } << new_line; + } + break; + default: + // MARLIN, etc. only have one acceleration for both print and travel + writePrintAcceleration(acceleration); + break; } current_travel_acceleration = acceleration; estimateCalculator.setAcceleration(acceleration); @@ -1380,15 +1383,15 @@ void GCodeExport::writeJerk(const Velocity& jerk) { switch (getFlavor()) { - case EGCodeFlavor::REPETIER: - *output_stream << "M207 X" << PrecisionedDouble{2, jerk} << new_line; - break; - case EGCodeFlavor::REPRAP: - *output_stream << "M566 X" << PrecisionedDouble{2, jerk * 60} << " Y" << PrecisionedDouble{2, jerk * 60} << new_line; - break; - default: - *output_stream << "M205 X" << PrecisionedDouble{2, jerk} << " Y" << PrecisionedDouble{2, jerk} << new_line; - break; + case EGCodeFlavor::REPETIER: + *output_stream << "M207 X" << PrecisionedDouble{ 2, jerk } << new_line; + break; + case EGCodeFlavor::REPRAP: + *output_stream << "M566 X" << PrecisionedDouble{ 2, jerk * 60 } << " Y" << PrecisionedDouble{ 2, jerk * 60 } << new_line; + break; + default: + *output_stream << "M205 X" << PrecisionedDouble{ 2, jerk } << " Y" << PrecisionedDouble{ 2, jerk } << new_line; + break; } current_jerk = jerk; estimateCalculator.setMaxXyJerk(jerk); @@ -1401,12 +1404,12 @@ void GCodeExport::finalize(const char* endCode) writeCode(endCode); int64_t print_time = getSumTotalPrintTimes(); int mat_0 = getTotalFilamentUsed(0); - log("Print time (s): %d\n", print_time); - log("Print time (hr|min|s): %dh %dm %ds\n", int(print_time / 60 / 60), int((print_time / 60) % 60), int(print_time % 60)); - log("Filament (mm^3): %d\n", mat_0); - for(int n=1; n 0) - log("Filament%d: %d\n", n + 1, int(getTotalFilamentUsed(n))); + spdlog::info("Filament {}: {}", n + 1, int(getTotalFilamentUsed(n))); output_stream->flush(); } @@ -1468,4 +1471,3 @@ void GCodeExport::setSliceUUID(const std::string& slice_uuid) } } // namespace cura - diff --git a/src/infill.cpp b/src/infill.cpp index 9a164350db..48e7c3016a 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -1,27 +1,28 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include //For std::sort. #include #include +#include + #include "WallToolPaths.h" #include "infill.h" #include "infill/GyroidInfill.h" #include "infill/ImageBasedDensityProvider.h" -#include "infill/NoZigZagConnectorProcessor.h" #include "infill/LightningGenerator.h" +#include "infill/NoZigZagConnectorProcessor.h" #include "infill/SierpinskiFill.h" #include "infill/SierpinskiFillProvider.h" #include "infill/SubDivCube.h" #include "infill/UniformDensityProvider.h" #include "sliceDataStorage.h" -#include "utils/logoutput.h" #include "utils/PolygonConnector.h" -#include "utils/polygonUtils.h" #include "utils/PolylineStitcher.h" #include "utils/Simplify.h" #include "utils/UnionFind.h" +#include "utils/polygonUtils.h" /*! * Function which returns the scanline_idx for a given x coordinate @@ -54,7 +55,7 @@ Polygons Infill::generateWallToolPaths(std::vector& toolpath Polygons inner_contour; if (wall_line_count > 0) { - constexpr coord_t wall_0_inset = 0; //Don't apply any outer wall inset for these. That's just for the outer wall. + constexpr coord_t wall_0_inset = 0; // Don't apply any outer wall inset for these. That's just for the outer wall. WallToolPaths wall_toolpaths(outer_contour, line_width, wall_line_count, wall_0_inset, settings); wall_toolpaths.pushToolPaths(toolpaths); inner_contour = wall_toolpaths.getInnerContour(); @@ -66,36 +67,35 @@ Polygons Infill::generateWallToolPaths(std::vector& toolpath return inner_contour; } -void Infill::generate(std::vector& toolpaths, Polygons& result_polygons, Polygons& result_lines, const Settings& settings, const SierpinskiFillProvider* cross_fill_provider, const LightningLayer* lightning_trees, const SliceMeshStorage* mesh) +void Infill::generate(std::vector& toolpaths, + Polygons& result_polygons, + Polygons& result_lines, + const Settings& settings, + const SierpinskiFillProvider* cross_fill_provider, + const LightningLayer* lightning_trees, + const SliceMeshStorage* mesh) { if (outer_contour.empty()) { return; } - inner_contour = - generateWallToolPaths(toolpaths, outer_contour, wall_line_count, infill_line_width, infill_overlap, settings); - - //Apply a half-line-width offset if the pattern prints partly alongside the walls, to get an area that we can simply print the centreline alongside the edge. - //The lines along the edge must lie next to the border, not on it. - //This makes those algorithms a lot simpler. - if (pattern == EFillMethod::ZIG_ZAG //Zig-zag prints the zags along the walls. - || (zig_zaggify && (pattern == EFillMethod::LINES //Zig-zaggified infill patterns print their zags along the walls. - || pattern == EFillMethod::TRIANGLES - || pattern == EFillMethod::GRID - || pattern == EFillMethod::CUBIC - || pattern == EFillMethod::TETRAHEDRAL - || pattern == EFillMethod::QUARTER_CUBIC - || pattern == EFillMethod::TRIHEXAGON - || pattern == EFillMethod::GYROID - || pattern == EFillMethod::CROSS - || pattern == EFillMethod::CROSS_3D)) - || infill_multiplier % 2 == 0) //Multiplied infill prints loops of infill, partly along the walls, if even. For odd multipliers >1 it gets offset by the multiply algorithm itself. + inner_contour = generateWallToolPaths(toolpaths, outer_contour, wall_line_count, infill_line_width, infill_overlap, settings); + + // Apply a half-line-width offset if the pattern prints partly alongside the walls, to get an area that we can simply print the centreline alongside the edge. + // The lines along the edge must lie next to the border, not on it. + // This makes those algorithms a lot simpler. + if (pattern == EFillMethod::ZIG_ZAG // Zig-zag prints the zags along the walls. + || (zig_zaggify + && (pattern == EFillMethod::LINES // Zig-zaggified infill patterns print their zags along the walls. + || pattern == EFillMethod::TRIANGLES || pattern == EFillMethod::GRID || pattern == EFillMethod::CUBIC || pattern == EFillMethod::TETRAHEDRAL || pattern == EFillMethod::QUARTER_CUBIC || pattern == EFillMethod::TRIHEXAGON + || pattern == EFillMethod::GYROID || pattern == EFillMethod::CROSS || pattern == EFillMethod::CROSS_3D)) + || infill_multiplier % 2 == 0) // Multiplied infill prints loops of infill, partly along the walls, if even. For odd multipliers >1 it gets offset by the multiply algorithm itself. { // Get gaps beforehand (that are caused when the 1/2 line width inset is done after this): // (Note that we give it a _full_ line width here, because unlike the old situation this can produce walls that are actually smaller than that.) constexpr coord_t gap_wall_count = 1; // Only need one wall here, less even, in a sense. - constexpr coord_t wall_0_inset = 0; //Don't apply any outer wall inset for these. That's just for the outer wall. + constexpr coord_t wall_0_inset = 0; // Don't apply any outer wall inset for these. That's just for the outer wall. WallToolPaths wall_toolpaths(inner_contour, infill_line_width, gap_wall_count, wall_0_inset, settings); std::vector gap_fill_paths = wall_toolpaths.getToolPaths(); @@ -114,10 +114,10 @@ void Infill::generate(std::vector& toolpaths, Polygons& resu { path.add(junction.p); } - if(path.polygonLength() >= infill_line_width * 4) //Don't fill gaps that are very small (with paths less than 2 line widths long, 4 back and forth). + if (path.polygonLength() >= infill_line_width * 4) // Don't fill gaps that are very small (with paths less than 2 line widths long, 4 back and forth). { gap_filled_areas.add(path); - if(fill_gaps) + if (fill_gaps) { thin_walls_only.push_back(extrusion); } @@ -136,7 +136,7 @@ void Infill::generate(std::vector& toolpaths, Polygons& resu } inner_contour = Simplify(max_resolution, max_deviation, 0).polygon(inner_contour); - if(infill_multiplier > 1) + if (infill_multiplier > 1) { bool zig_zaggify_real = zig_zaggify; if (infill_multiplier % 2 == 0) @@ -155,7 +155,7 @@ void Infill::generate(std::vector& toolpaths, Polygons& resu else { //_generate may clear() the generated_result_lines, but this is an output variable that may contain data before we start. - //So make sure we provide it with a Polygons that is safe to clear and only add stuff to result_lines. + // So make sure we provide it with a Polygons that is safe to clear and only add stuff to result_lines. Polygons generated_result_polygons; Polygons generated_result_lines; _generate(toolpaths, generated_result_polygons, generated_result_lines, settings, cross_fill_provider, lightning_trees, mesh); @@ -166,10 +166,7 @@ void Infill::generate(std::vector& toolpaths, Polygons& resu { // remove too small polygons coord_t snap_distance = infill_line_width * 2; // polygons with a span of max 1 * nozzle_size are too small - auto it = std::remove_if(result_polygons.begin(), result_polygons.end(), [snap_distance](PolygonRef poly) - { - return poly.shorterThan(snap_distance); - }); + auto it = std::remove_if(result_polygons.begin(), result_polygons.end(), [snap_distance](PolygonRef poly) { return poly.shorterThan(snap_distance); }); result_polygons.erase(it, result_polygons.end()); PolygonConnector connector(infill_line_width); @@ -183,12 +180,20 @@ void Infill::generate(std::vector& toolpaths, Polygons& resu } } -void Infill::_generate(std::vector& toolpaths, Polygons& result_polygons, Polygons& result_lines, const Settings& settings, const SierpinskiFillProvider* cross_fill_provider, const LightningLayer * lightning_trees, const SliceMeshStorage* mesh) +void Infill::_generate(std::vector& toolpaths, + Polygons& result_polygons, + Polygons& result_lines, + const Settings& settings, + const SierpinskiFillProvider* cross_fill_provider, + const LightningLayer* lightning_trees, + const SliceMeshStorage* mesh) { - if (inner_contour.empty()) return; - if (line_distance == 0) return; + if (inner_contour.empty()) + return; + if (line_distance == 0) + return; - switch(pattern) + switch (pattern) { case EFillMethod::GRID: generateGridInfill(result_lines); @@ -218,18 +223,18 @@ void Infill::_generate(std::vector& toolpaths, Polygons& res generateZigZagInfill(result_lines, line_distance, fill_angle); break; case EFillMethod::CUBICSUBDIV: - if (!mesh) + if (! mesh) { - logError("Cannot generate Cubic Subdivision infill without a mesh!\n"); + spdlog::error("Cannot generate Cubic Subdivision infill without a mesh!"); break; } generateCubicSubDivInfill(result_lines, *mesh); break; case EFillMethod::CROSS: case EFillMethod::CROSS_3D: - if (!cross_fill_provider) + if (! cross_fill_provider) { - logError("Cannot generate Cross infill without a cross fill provider!\n"); + spdlog::error("Cannot generate Cross infill without a cross fill provider!\n"); break; } generateCrossInfill(*cross_fill_provider, result_polygons, result_lines); @@ -242,13 +247,13 @@ void Infill::_generate(std::vector& toolpaths, Polygons& res generateLightningInfill(lightning_trees, result_lines); break; default: - logError("Fill pattern has unknown value.\n"); + spdlog::error("Fill pattern has unknown value.\n"); break; } if (connect_lines) { - //The list should be empty because it will be again filled completely. Otherwise might have double lines. + // The list should be empty because it will be again filled completely. Otherwise might have double lines. assert(result_lines.empty()); result_lines.clear(); connectLines(result_lines); @@ -257,8 +262,7 @@ void Infill::_generate(std::vector& toolpaths, Polygons& res Simplify simplifier(max_resolution, max_deviation, 0); result_polygons = simplifier.polygon(result_polygons); - if(!skip_line_stitching && (zig_zaggify || - pattern == EFillMethod::CROSS || pattern == EFillMethod::CROSS_3D || pattern == EFillMethod::CUBICSUBDIV || pattern == EFillMethod::GYROID || pattern == EFillMethod::ZIG_ZAG)) + if (! skip_line_stitching && (zig_zaggify || pattern == EFillMethod::CROSS || pattern == EFillMethod::CROSS_3D || pattern == EFillMethod::CUBICSUBDIV || pattern == EFillMethod::GYROID || pattern == EFillMethod::ZIG_ZAG)) { // don't stich for non-zig-zagged line infill types Polygons stitched_lines; PolylineStitcher::stitch(result_lines, stitched_lines, result_polygons, infill_line_width); @@ -275,7 +279,7 @@ void Infill::multiplyInfill(Polygons& result_polygons, Polygons& result_lines) } bool odd_multiplier = infill_multiplier % 2 == 1; - coord_t offset = (odd_multiplier)? infill_line_width : infill_line_width / 2; + coord_t offset = (odd_multiplier) ? infill_line_width : infill_line_width / 2; // Get the first offset these are mirrored from the original center line Polygons result; @@ -314,13 +318,13 @@ void Infill::multiplyInfill(Polygons& result_polygons, Polygons& result_lines) } // Remove the original center lines when there are an even number of lines required. - if (!odd_multiplier) + if (! odd_multiplier) { result_polygons.clear(); result_lines.clear(); } result_polygons.add(result); - if (!zig_zaggify) + if (! zig_zaggify) { for (PolygonRef poly : result_polygons) { // make polygons into polylines @@ -346,7 +350,7 @@ void Infill::generateGyroidInfill(Polygons& result_lines, Polygons& result_polyg void Infill::generateLightningInfill(const LightningLayer* trees, Polygons& result_lines) { // Don't need to support areas smaller than line width, as they are always within radius: - if(std::abs(inner_contour.area()) < infill_line_width || ! trees) + if (std::abs(inner_contour.area()) < infill_line_width || ! trees) { return; } @@ -359,19 +363,19 @@ void Infill::generateConcentricInfill(std::vector& toolpaths Polygons current_inset = inner_contour; Simplify simplifier(settings); - while(true) + while (true) { - //If line_distance is 0, start from the same contour as the previous line, except where the previous line closed up the shape. - //So we add the whole nominal line width first (to allow lines to be closer together than 1 line width if the line distance is smaller) and then subtract line_distance. + // If line_distance is 0, start from the same contour as the previous line, except where the previous line closed up the shape. + // So we add the whole nominal line width first (to allow lines to be closer together than 1 line width if the line distance is smaller) and then subtract line_distance. current_inset = current_inset.offset(infill_line_width - line_distance); - current_inset = simplifier.polygon(current_inset); //Many insets lead to increasingly detailed shapes. Simplify to speed up processing. - if(current_inset.area() < min_area) //So small that it's inconsequential. Stop here. + current_inset = simplifier.polygon(current_inset); // Many insets lead to increasingly detailed shapes. Simplify to speed up processing. + if (current_inset.area() < min_area) // So small that it's inconsequential. Stop here. { break; } - constexpr size_t inset_wall_count = 1; //1 wall at a time. - constexpr coord_t wall_0_inset = 0; //Don't apply any outer wall inset for these. That's just for the outer wall. + constexpr size_t inset_wall_count = 1; // 1 wall at a time. + constexpr coord_t wall_0_inset = 0; // Don't apply any outer wall inset for these. That's just for the outer wall. WallToolPaths wall_toolpaths(current_inset, infill_line_width, inset_wall_count, wall_0_inset, settings); const std::vector inset_paths = wall_toolpaths.getToolPaths(); toolpaths.insert(toolpaths.end(), inset_paths.begin(), inset_paths.end()); @@ -468,10 +472,10 @@ void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provid void Infill::addLineInfill(Polygons& result, const PointMatrix& rotation_matrix, const int scanline_min_idx, const int line_distance, const AABB boundary, std::vector>& cut_list, coord_t shift) { - assert(!connect_lines && "connectLines() should add the infill lines, not addLineInfill"); + assert(! connect_lines && "connectLines() should add the infill lines, not addLineInfill"); unsigned int scanline_idx = 0; - for(coord_t x = scanline_min_idx * line_distance + shift; x < boundary.max.X; x += line_distance) + for (coord_t x = scanline_min_idx * line_distance + shift; x < boundary.max.X; x += line_distance) { if (scanline_idx >= cut_list.size()) { @@ -479,7 +483,7 @@ void Infill::addLineInfill(Polygons& result, const PointMatrix& rotation_matrix, } std::vector& crossings = cut_list[scanline_idx]; std::sort(crossings.begin(), crossings.end()); // sort by increasing Y coordinates - for(unsigned int crossing_idx = 0; crossing_idx + 1 < crossings.size(); crossing_idx += 2) + for (unsigned int crossing_idx = 0; crossing_idx + 1 < crossings.size(); crossing_idx += 2) { if (crossings[crossing_idx + 1] - crossings[crossing_idx] < infill_line_width / 5) { // segment is too short to create infill @@ -520,15 +524,15 @@ void Infill::generateZigZagInfill(Polygons& result, const coord_t line_distance, generateLinearBasedInfill(result, line_distance, rotation_matrix, zigzag_processor, connected_zigzags, shift); } -/* +/* * algorithm: * 1. for each line segment of each polygon: * store the intersections of that line segment with all scanlines in a mapping (vector of vectors) from scanline to intersections * (zigzag): add boundary segments to result * 2. for each scanline: - * sort the associated intersections + * sort the associated intersections * and connect them using the even-odd rule - * + * * rough explanation of the zigzag algorithm: * while walking around (each) polygon (1.) * if polygon intersects with even scanline @@ -536,21 +540,21 @@ void Infill::generateZigZagInfill(Polygons& result, const coord_t line_distance, * when polygon intersects with a scanline again * stop boundary segment (stop adding segments to the [result]) * (see infill/ZigzagConnectorProcessor.h for actual implementation details) - * - * + * + * * we call the areas between two consecutive scanlines a 'scansegment'. * Scansegment x is the area between scanline x and scanline x+1 - * Edit: the term scansegment is wrong, since I call a boundary segment leaving from an even scanline to the left as belonging to an even scansegment, + * Edit: the term scansegment is wrong, since I call a boundary segment leaving from an even scanline to the left as belonging to an even scansegment, * while I also call a boundary segment leaving from an even scanline toward the right as belonging to an even scansegment. */ void Infill::generateLinearBasedInfill(Polygons& result, const int line_distance, const PointMatrix& rotation_matrix, ZigzagConnectorProcessor& zigzag_connector_processor, const bool connected_zigzags, coord_t extra_shift) { - if (line_distance == 0 || inner_contour.empty()) //No infill to generate (0% density) or no area to generate it in. + if (line_distance == 0 || inner_contour.empty()) // No infill to generate (0% density) or no area to generate it in. { return; } - Polygons outline = inner_contour; //Make a copy. We'll be rotating this outline to make intersections always horizontal, for better performance. + Polygons outline = inner_contour; // Make a copy. We'll be rotating this outline to make intersections always horizontal, for better performance. outline.applyMatrix(rotation_matrix); coord_t shift = extra_shift + this->shift; @@ -570,28 +574,29 @@ void Infill::generateLinearBasedInfill(Polygons& result, const int line_distance std::vector> cut_list(line_count); // mapping from scanline to all intersections with polygon segments - //When we find crossings, keep track of which crossing belongs to which scanline and to which polygon line segment. - //Then we can later join two crossings together to form lines and still know what polygon line segments that infill line connected to. + // When we find crossings, keep track of which crossing belongs to which scanline and to which polygon line segment. + // Then we can later join two crossings together to form lines and still know what polygon line segments that infill line connected to. struct Crossing { - Crossing(Point coordinate, size_t polygon_index, size_t vertex_index): coordinate(coordinate), polygon_index(polygon_index), vertex_index(vertex_index) {}; + Crossing(Point coordinate, size_t polygon_index, size_t vertex_index) : coordinate(coordinate), polygon_index(polygon_index), vertex_index(vertex_index){}; Point coordinate; size_t polygon_index; size_t vertex_index; - bool operator <(const Crossing& other) const //Crossings will be ordered by their Y coordinate so that they get ordered along the scanline. + bool operator<(const Crossing& other) const // Crossings will be ordered by their Y coordinate so that they get ordered along the scanline. { return coordinate.Y < other.coordinate.Y; } }; - std::vector> crossings_per_scanline; //For each scanline, a list of crossings. + std::vector> crossings_per_scanline; // For each scanline, a list of crossings. const int min_scanline_index = computeScanSegmentIdx(boundary.min.X - shift, line_distance) + 1; const int max_scanline_index = computeScanSegmentIdx(boundary.max.X - shift, line_distance) + 1; crossings_per_scanline.resize(max_scanline_index - min_scanline_index); - if (connect_lines) { - crossings_on_line.resize(outline.size()); //One for each polygon. + if (connect_lines) + { + crossings_on_line.resize(outline.size()); // One for each polygon. } - for(size_t poly_idx = 0; poly_idx < outline.size(); poly_idx++) + for (size_t poly_idx = 0; poly_idx < outline.size(); poly_idx++) { PolygonRef poly = outline[poly_idx]; if (connect_lines) @@ -601,16 +606,16 @@ void Infill::generateLinearBasedInfill(Polygons& result, const int line_distance Point p0 = poly.back(); zigzag_connector_processor.registerVertex(p0); // always adds the first point to ZigzagConnectorProcessorEndPieces::first_zigzag_connector when using a zigzag infill type - for(size_t point_idx = 0; point_idx < poly.size(); point_idx++) + for (size_t point_idx = 0; point_idx < poly.size(); point_idx++) { Point p1 = poly[point_idx]; if (p1.X == p0.X) { - zigzag_connector_processor.registerVertex(p1); + zigzag_connector_processor.registerVertex(p1); // TODO: how to make sure it always adds the shortest line? (in order to prevent overlap with the zigzag connectors) // note: this is already a problem for normal infill, but hasn't really bothered anyone so far. p0 = p1; - continue; + continue; } int scanline_idx0; @@ -619,7 +624,7 @@ void Infill::generateLinearBasedInfill(Polygons& result, const int line_distance // in case the next segment moves back from that scanline either 2 or 0 scanline-boundary intersections are created // otherwise only 1 will be created, counting as an actual intersection int direction = 1; - if (p0.X < p1.X) + if (p0.X < p1.X) { scanline_idx0 = computeScanSegmentIdx(p0.X - shift, line_distance) + 1; // + 1 cause we don't cross the scanline of the first scan segment scanline_idx1 = computeScanSegmentIdx(p1.X - shift, line_distance); // -1 cause the vertex point is handled in the next segment (or not in the case which looks like >) @@ -631,7 +636,7 @@ void Infill::generateLinearBasedInfill(Polygons& result, const int line_distance scanline_idx1 = computeScanSegmentIdx(p1.X - shift, line_distance) + 1; // + 1 cause we don't cross the scanline of the first scan segment } - for(int scanline_idx = scanline_idx0; scanline_idx != scanline_idx1 + direction; scanline_idx += direction) + for (int scanline_idx = scanline_idx0; scanline_idx != scanline_idx1 + direction; scanline_idx += direction) { int x = scanline_idx * line_distance + shift; int y = p1.Y + (p0.Y - p1.Y) * (x - p1.X) / (p0.X - p1.X); @@ -646,8 +651,9 @@ void Infill::generateLinearBasedInfill(Polygons& result, const int line_distance } zigzag_connector_processor.registerPolyFinished(); } - - if (connect_lines) { + + if (connect_lines) + { // Gather all crossings per scanline and find out which crossings belong together, then store them in crossings_on_line. for (int scanline_index = min_scanline_index; scanline_index < max_scanline_index; scanline_index++) { @@ -681,7 +687,7 @@ void Infill::generateLinearBasedInfill(Polygons& result, const int line_distance } if (connected_zigzags && cut_list.size() == 1 && cut_list[0].size() <= 2) { - return; // don't add connection if boundary already contains whole outline! + return; // don't add connection if boundary already contains whole outline! } // We have to create our own lines when they are not created by the method connectLines. @@ -691,7 +697,7 @@ void Infill::generateLinearBasedInfill(Polygons& result, const int line_distance void Infill::connectLines(Polygons& result_lines) { - UnionFind connected_lines; //Keeps track of which lines are connected to which. + UnionFind connected_lines; // Keeps track of which lines are connected to which. for (const std::vector>& crossings_on_polygon : crossings_on_line) { for (const std::vector& crossings_on_polygon_segment : crossings_on_polygon) @@ -700,7 +706,7 @@ void Infill::connectLines(Polygons& result_lines) { if (connected_lines.find(infill_line) == (size_t)-1) { - connected_lines.add(infill_line); //Put every line in there as a separate set. + connected_lines.add(infill_line); // Put every line in there as a separate set. } } } @@ -715,8 +721,8 @@ void Infill::connectLines(Polygons& result_lines) } assert(crossings_on_line.size() > polygon_index && "crossings dimension should be bigger then polygon index"); std::vector>& crossings_on_polygon = crossings_on_line[polygon_index]; - InfillLineSegment* previous_crossing = nullptr; //The crossing that we should connect to. If nullptr, we have been skipping until we find the next crossing. - InfillLineSegment* previous_segment = nullptr; //The last segment we were connecting while drawing a line along the border. + InfillLineSegment* previous_crossing = nullptr; // The crossing that we should connect to. If nullptr, we have been skipping until we find the next crossing. + InfillLineSegment* previous_segment = nullptr; // The last segment we were connecting while drawing a line along the border. Point vertex_before = inner_contour_polygon.back(); for (size_t vertex_index = 0; vertex_index < inner_contour_polygon.size(); vertex_index++) { @@ -724,18 +730,20 @@ void Infill::connectLines(Polygons& result_lines) std::vector& crossings_on_polygon_segment = crossings_on_polygon[vertex_index]; Point vertex_after = inner_contour_polygon[vertex_index]; - //Sort crossings on every line by how far they are from their initial point. - std::sort(crossings_on_polygon_segment.begin(), crossings_on_polygon_segment.end(), - [&vertex_before, polygon_index, vertex_index](InfillLineSegment* left_hand_side, InfillLineSegment* right_hand_side) { - // Find the two endpoints that are relevant. - const Point left_hand_point = (left_hand_side->start_segment == vertex_index && left_hand_side->start_polygon == polygon_index) ? left_hand_side->start : left_hand_side->end; - const Point right_hand_point = (right_hand_side->start_segment == vertex_index && right_hand_side->start_polygon == polygon_index) ? right_hand_side->start : right_hand_side->end; - return vSize(left_hand_point - vertex_before) < vSize(right_hand_point - vertex_before); - }); + // Sort crossings on every line by how far they are from their initial point. + std::sort(crossings_on_polygon_segment.begin(), + crossings_on_polygon_segment.end(), + [&vertex_before, polygon_index, vertex_index](InfillLineSegment* left_hand_side, InfillLineSegment* right_hand_side) + { + // Find the two endpoints that are relevant. + const Point left_hand_point = (left_hand_side->start_segment == vertex_index && left_hand_side->start_polygon == polygon_index) ? left_hand_side->start : left_hand_side->end; + const Point right_hand_point = (right_hand_side->start_segment == vertex_index && right_hand_side->start_polygon == polygon_index) ? right_hand_side->start : right_hand_side->end; + return vSize(left_hand_point - vertex_before) < vSize(right_hand_point - vertex_before); + }); for (InfillLineSegment* crossing : crossings_on_polygon_segment) { - if (!previous_crossing) //If we're not yet drawing, then we have been trying to find the next vertex. We found it! Let's start drawing. + if (! previous_crossing) // If we're not yet drawing, then we have been trying to find the next vertex. We found it! Let's start drawing. { previous_crossing = crossing; previous_segment = crossing; @@ -743,16 +751,16 @@ void Infill::connectLines(Polygons& result_lines) else { const size_t crossing_handle = connected_lines.find(crossing); - assert (crossing_handle != (size_t)-1); + assert(crossing_handle != (size_t)-1); const size_t previous_crossing_handle = connected_lines.find(previous_crossing); - assert (previous_crossing_handle != (size_t)-1); - if (crossing_handle == previous_crossing_handle) //These two infill lines are already connected. Don't create a loop now. Continue connecting with the next crossing. + assert(previous_crossing_handle != (size_t)-1); + if (crossing_handle == previous_crossing_handle) // These two infill lines are already connected. Don't create a loop now. Continue connecting with the next crossing. { continue; } - //Join two infill lines together with a connecting line. - //Here the InfillLineSegments function as a linked list, so that they can easily be joined. + // Join two infill lines together with a connecting line. + // Here the InfillLineSegments function as a linked list, so that they can easily be joined. const Point previous_point = (previous_segment->start_segment == vertex_index && previous_segment->start_polygon == polygon_index) ? previous_segment->start : previous_segment->end; const Point next_point = (crossing->start_segment == vertex_index && crossing->start_polygon == polygon_index) ? crossing->start : crossing->end; InfillLineSegment* new_segment; @@ -771,7 +779,7 @@ void Infill::connectLines(Polygons& result_lines) } else { - new_segment = new InfillLineSegment(previous_point, vertex_index, polygon_index, next_point, vertex_index, polygon_index); //A connecting line between them. + new_segment = new InfillLineSegment(previous_point, vertex_index, polygon_index, next_point, vertex_index, polygon_index); // A connecting line between them. new_segment->previous = previous_segment; if (previous_segment->start_segment == vertex_index && previous_segment->start_polygon == polygon_index) { @@ -798,7 +806,7 @@ void Infill::connectLines(Polygons& result_lines) } } - //Upon going to the next vertex, if we're drawing, put an extra vertex in our infill lines. + // Upon going to the next vertex, if we're drawing, put an extra vertex in our infill lines. if (previous_crossing) { InfillLineSegment* new_segment; @@ -806,7 +814,7 @@ void Infill::connectLines(Polygons& result_lines) { if (previous_segment->start == vertex_after) { - //Edge case when an infill line ends directly on top of vertex_after: We skip the extra connecting line segment, as that would be 0-length. + // Edge case when an infill line ends directly on top of vertex_after: We skip the extra connecting line segment, as that would be 0-length. previous_segment = nullptr; previous_crossing = nullptr; } @@ -822,7 +830,7 @@ void Infill::connectLines(Polygons& result_lines) { if (previous_segment->end == vertex_after) { - //Edge case when an infill line ends directly on top of vertex_after: We skip the extra connecting line segment, as that would be 0-length. + // Edge case when an infill line ends directly on top of vertex_after: We skip the extra connecting line segment, as that would be 0-length. previous_segment = nullptr; previous_crossing = nullptr; } @@ -841,31 +849,31 @@ void Infill::connectLines(Polygons& result_lines) } } - //Save all lines, now connected, to the output. + // Save all lines, now connected, to the output. std::unordered_set completed_groups; for (InfillLineSegment* infill_line : connected_lines) { const size_t group = connected_lines.find(infill_line); - if (completed_groups.find(group) != completed_groups.end()) //We already completed this group. + if (completed_groups.find(group) != completed_groups.end()) // We already completed this group. { continue; } - //Find where the polyline ends by searching through previous and next lines. - //Note that the "previous" and "next" lines don't necessarily match up though, because the direction while connecting infill lines was not yet known. - Point previous_vertex = infill_line->start; //Take one side arbitrarily to start from. This variable indicates the vertex that connects to the previous line. + // Find where the polyline ends by searching through previous and next lines. + // Note that the "previous" and "next" lines don't necessarily match up though, because the direction while connecting infill lines was not yet known. + Point previous_vertex = infill_line->start; // Take one side arbitrarily to start from. This variable indicates the vertex that connects to the previous line. InfillLineSegment* current_infill_line = infill_line; - while (current_infill_line->next && current_infill_line->previous) //Until we reached an endpoint. + while (current_infill_line->next && current_infill_line->previous) // Until we reached an endpoint. { const Point next_vertex = (previous_vertex == current_infill_line->start) ? current_infill_line->end : current_infill_line->start; - current_infill_line = (previous_vertex == current_infill_line->start) ? current_infill_line->next : current_infill_line->previous; + current_infill_line = (previous_vertex == current_infill_line->start) ? current_infill_line->next : current_infill_line->previous; previous_vertex = next_vertex; } - //Now go along the linked list of infill lines and output the infill lines to the actual result. + // Now go along the linked list of infill lines and output the infill lines to the actual result. InfillLineSegment* old_line = current_infill_line; - const Point first_vertex = (!current_infill_line->previous) ? current_infill_line->start : current_infill_line->end; - previous_vertex = (!current_infill_line->previous) ? current_infill_line->end : current_infill_line->start; + const Point first_vertex = (! current_infill_line->previous) ? current_infill_line->start : current_infill_line->end; + previous_vertex = (! current_infill_line->previous) ? current_infill_line->end : current_infill_line->start; current_infill_line = (first_vertex == current_infill_line->start) ? current_infill_line->next : current_infill_line->previous; PolygonRef result_line = result_lines.newPoly(); result_line.add(first_vertex); @@ -873,9 +881,9 @@ void Infill::connectLines(Polygons& result_lines) delete old_line; while (current_infill_line) { - old_line = current_infill_line; //We'll delete this after we've traversed to the next line. - const Point next_vertex = (previous_vertex == current_infill_line->start) ? current_infill_line->end : current_infill_line->start; //Opposite side of the line. - current_infill_line = (previous_vertex == current_infill_line->start) ? current_infill_line->next : current_infill_line->previous; + old_line = current_infill_line; // We'll delete this after we've traversed to the next line. + const Point next_vertex = (previous_vertex == current_infill_line->start) ? current_infill_line->end : current_infill_line->start; // Opposite side of the line. + current_infill_line = (previous_vertex == current_infill_line->start) ? current_infill_line->next : current_infill_line->previous; result_line.add(next_vertex); previous_vertex = next_vertex; delete old_line; @@ -885,9 +893,9 @@ void Infill::connectLines(Polygons& result_lines) } } -bool Infill::InfillLineSegment::operator ==(const InfillLineSegment& other) const +bool Infill::InfillLineSegment::operator==(const InfillLineSegment& other) const { return start == other.start && end == other.end; } -}//namespace cura +} // namespace cura diff --git a/src/infill/ImageBasedDensityProvider.cpp b/src/infill/ImageBasedDensityProvider.cpp index db08992c48..0bbb6532f1 100644 --- a/src/infill/ImageBasedDensityProvider.cpp +++ b/src/infill/ImageBasedDensityProvider.cpp @@ -1,17 +1,17 @@ -//Copyright (c) 2017 Tim Kuipers -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #define STBI_FAILURE_USERMSG // enable user friendly bug messages for STB lib #define STB_IMAGE_IMPLEMENTATION // needed in order to enable the implementation of libs/std_image.h +#include #include #include "infill/ImageBasedDensityProvider.h" #include "infill/SierpinskiFill.h" #include "utils/AABB3D.h" -#include "utils/logoutput.h" -namespace cura { +namespace cura +{ static constexpr bool diagonal = true; static constexpr bool straight = false; @@ -22,14 +22,14 @@ ImageBasedDensityProvider::ImageBasedDensityProvider(const std::string filename, int img_x, img_y, img_z; // stbi requires pointer to int rather than to coord_t image = stbi_load(filename.c_str(), &img_x, &img_y, &img_z, desired_channel_count); image_size = Point3(img_x, img_y, img_z); - if (!image) + if (! image) { const char* reason = "[unknown reason]"; if (stbi_failure_reason()) { reason = stbi_failure_reason(); } - logError("Cannot load image %s: '%s'.\n", filename.c_str(), reason); + spdlog::error("Cannot load image {}: {}", filename, reason); std::exit(-1); } { // compute aabb @@ -64,8 +64,8 @@ ImageBasedDensityProvider::~ImageBasedDensityProvider() float ImageBasedDensityProvider::operator()(const AABB3D& query_cube) const { AABB query_box(Point(query_cube.min.x, query_cube.min.y), Point(query_cube.max.x, query_cube.max.y)); - Point img_min = (query_box.min - print_aabb.min - Point(1,1)) * image_size.x / (print_aabb.max.X - print_aabb.min.X); - Point img_max = (query_box.max - print_aabb.min + Point(1,1)) * image_size.y / (print_aabb.max.Y - print_aabb.min.Y); + Point img_min = (query_box.min - print_aabb.min - Point(1, 1)) * image_size.x / (print_aabb.max.X - print_aabb.min.X); + Point img_max = (query_box.max - print_aabb.min + Point(1, 1)) * image_size.y / (print_aabb.max.Y - print_aabb.min.Y); long total_lightness = 0; int value_count = 0; for (int x = std::max((coord_t)0, img_min.X); x <= std::min((coord_t)image_size.x - 1, img_max.X); x++) diff --git a/src/infill/SierpinskiFill.cpp b/src/infill/SierpinskiFill.cpp index 1f586e8cb4..b345493044 100644 --- a/src/infill/SierpinskiFill.cpp +++ b/src/infill/SierpinskiFill.cpp @@ -1,6 +1,5 @@ -//Copyright (c) 2017 Tim Kuipers -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include "infill/SierpinskiFill.h" @@ -9,14 +8,16 @@ #include // function #include // next, prev +#include + #include "infill/ImageBasedDensityProvider.h" #include "infill/UniformDensityProvider.h" #include "utils/AABB3D.h" -#include "utils/logoutput.h" -#include "utils/polygon.h" #include "utils/SVG.h" +#include "utils/polygon.h" -namespace cura { +namespace cura +{ static constexpr bool diagonal = true; static constexpr bool straight = false; @@ -26,12 +27,12 @@ static constexpr float allowed_length_error = .01; static constexpr bool deep_debug_checking = false; SierpinskiFill::SierpinskiFill(const DensityProvider& density_provider, const AABB aabb, int max_depth, const coord_t line_width, bool dithering) -: dithering(dithering) -, constraint_error_diffusion(dithering) -, density_provider(density_provider) -, aabb(aabb) -, line_width(line_width) -, max_depth(max_depth) + : dithering(dithering) + , constraint_error_diffusion(dithering) + , density_provider(density_provider) + , aabb(aabb) + , line_width(line_width) + , max_depth(max_depth) { createTree(); @@ -41,7 +42,12 @@ SierpinskiFill::SierpinskiFill(const DensityProvider& density_provider, const AA { if (node->getValueError() < -allowed_length_error) { - logError("Node is subdivided without the appropriate value! value_error: %f from base %f el: %f er: %f, while the realized_length = %f\n", node->getValueError(), node->requested_length, node->error_left, node->error_right, node->realized_length); + spdlog::error("Node is subdivided without the appropriate value! value_error: {} from base {} el: {} er: {}, while the realized_length = {}", + node->getValueError(), + node->requested_length, + node->error_left, + node->error_right, + node->realized_length); assert(false); } } @@ -79,31 +85,31 @@ void SierpinskiFill::createTree() void SierpinskiFill::createTree(SierpinskiTriangle& sub_root) { - if (sub_root.depth < max_depth) //We need to subdivide. + if (sub_root.depth < max_depth) // We need to subdivide. { SierpinskiTriangle& t = sub_root; Point middle = (t.a + t.b) / 2; - //At each subdivision we divide the triangle in two. - //Figure out which sort of triangle each child will be: + // At each subdivision we divide the triangle in two. + // Figure out which sort of triangle each child will be: SierpinskiTriangle::SierpinskiDirection first_dir, second_dir; - switch(t.dir) + switch (t.dir) { - default: - case SierpinskiTriangle::SierpinskiDirection::AB_TO_BC: - first_dir = SierpinskiTriangle::SierpinskiDirection::AC_TO_BC; - second_dir = SierpinskiTriangle::SierpinskiDirection::AC_TO_AB; - break; - case SierpinskiTriangle::SierpinskiDirection::AC_TO_AB: - first_dir = SierpinskiTriangle::SierpinskiDirection::AB_TO_BC; - second_dir = SierpinskiTriangle::SierpinskiDirection::AC_TO_BC; - break; - case SierpinskiTriangle::SierpinskiDirection::AC_TO_BC: - first_dir = SierpinskiTriangle::SierpinskiDirection::AB_TO_BC; - second_dir = SierpinskiTriangle::SierpinskiDirection::AC_TO_AB; - break; + default: + case SierpinskiTriangle::SierpinskiDirection::AB_TO_BC: + first_dir = SierpinskiTriangle::SierpinskiDirection::AC_TO_BC; + second_dir = SierpinskiTriangle::SierpinskiDirection::AC_TO_AB; + break; + case SierpinskiTriangle::SierpinskiDirection::AC_TO_AB: + first_dir = SierpinskiTriangle::SierpinskiDirection::AB_TO_BC; + second_dir = SierpinskiTriangle::SierpinskiDirection::AC_TO_BC; + break; + case SierpinskiTriangle::SierpinskiDirection::AC_TO_BC: + first_dir = SierpinskiTriangle::SierpinskiDirection::AB_TO_BC; + second_dir = SierpinskiTriangle::SierpinskiDirection::AC_TO_AB; + break; } - sub_root.children.emplace_back(middle, t.a, t.straight_corner, first_dir, !t.straight_corner_is_left, t.depth + 1); - sub_root.children.emplace_back(middle, t.straight_corner, t.b, second_dir, !t.straight_corner_is_left, t.depth + 1); + sub_root.children.emplace_back(middle, t.a, t.straight_corner, first_dir, ! t.straight_corner_is_left, t.depth + 1); + sub_root.children.emplace_back(middle, t.straight_corner, t.b, second_dir, ! t.straight_corner_is_left, t.depth + 1); for (SierpinskiTriangle& child : t.children) { createTree(child); @@ -117,7 +123,7 @@ void SierpinskiFill::createTreeStatistics(SierpinskiTriangle& triangle) float short_length = .5 * vSizeMM(ac); float long_length = .5 * vSizeMM(triangle.b - triangle.a); triangle.area = area; - triangle.realized_length = (triangle.dir == SierpinskiTriangle::SierpinskiDirection::AC_TO_BC)? long_length : short_length; + triangle.realized_length = (triangle.dir == SierpinskiTriangle::SierpinskiDirection::AC_TO_BC) ? long_length : short_length; for (SierpinskiTriangle& child : triangle.children) { createTreeStatistics(child); @@ -153,22 +159,25 @@ void SierpinskiFill::createLowerBoundSequence() { sequence.emplace_front(&root); - if (deep_debug_checking) debugCheck(); + if (deep_debug_checking) + debugCheck(); for (int iteration = 0; iteration < 999; iteration++) { bool change = false; change |= subdivideAll(); - if (deep_debug_checking) debugCheck(); + if (deep_debug_checking) + debugCheck(); if (constraint_error_diffusion) { change |= bubbleUpConstraintErrors(); - if (deep_debug_checking) debugCheck(); + if (deep_debug_checking) + debugCheck(); } - if (!change) + if (! change) { - logDebug("Finished after %i iterations, with a max depth of %i.\n", iteration + 1, max_depth); + spdlog::debug("Finished after {} iterations, with a max depth of {}.", iteration + 1, max_depth); break; } } @@ -202,16 +211,11 @@ bool SierpinskiFill::subdivideAll() // so then the range will be two long rather than one. std::list::iterator begin = it; std::list::iterator end = std::next(it); - if ( - triangle.dir == SierpinskiTriangle::SierpinskiDirection::AC_TO_AB - && end != sequence.end() - ) + if (triangle.dir == SierpinskiTriangle::SierpinskiDirection::AC_TO_AB && end != sequence.end()) { continue; // don't subdivide these two triangles just yet, wait till next iteration } - if (triangle.dir == SierpinskiTriangle::SierpinskiDirection::AB_TO_BC - && begin != sequence.begin() - ) + if (triangle.dir == SierpinskiTriangle::SierpinskiDirection::AB_TO_BC && begin != sequence.begin()) { begin = std::prev(it); assert((*begin)->depth == triangle.depth || isConstrainedBackward(it)); @@ -224,14 +228,10 @@ bool SierpinskiFill::subdivideAll() // Don't check for constraining in between the cells in the range; // the range is defined as the range of triangles which are constraining each other simultaneously. - if (node->depth == max_depth) //Never subdivide beyond maximum depth. + if (node->depth == max_depth) // Never subdivide beyond maximum depth. continue; float total_subdiv_error = getSubdivisionError(begin, end); - if ( - !node->children.empty() - && total_subdiv_error >= 0 - && !is_constrained - ) + if (! node->children.empty() && total_subdiv_error >= 0 && ! is_constrained) { bool redistribute_errors = true; subdivide(begin, end, redistribute_errors); @@ -257,14 +257,11 @@ bool SierpinskiFill::bubbleUpConstraintErrors() float unresolvable_error = triangle.getValueError(); - //If constrained in one direction, resolve the error in the other direction only. - //If constrained in both directions, divide the error equally over both directions. + // If constrained in one direction, resolve the error in the other direction only. + // If constrained in both directions, divide the error equally over both directions. bool is_constrained_forward = isConstrainedForward(it); bool is_constrained_backward = isConstrainedBackward(it); - if ( - unresolvable_error > allowed_length_error && - (is_constrained_forward || is_constrained_backward) - ) + if (unresolvable_error > allowed_length_error && (is_constrained_forward || is_constrained_backward)) { if (is_constrained_forward && is_constrained_backward) { @@ -272,7 +269,8 @@ bool SierpinskiFill::bubbleUpConstraintErrors() unresolvable_error *= .5; // disperse half of the error forward and the other half backward } - if (deep_debug_checking) debugCheck(); + if (deep_debug_checking) + debugCheck(); if (is_constrained_forward) { SierpinskiTriangle* next = *std::next(it); @@ -289,7 +287,8 @@ bool SierpinskiFill::bubbleUpConstraintErrors() { redistributed_anything = true; } - if (deep_debug_checking) debugCheck(); + if (deep_debug_checking) + debugCheck(); } } } @@ -299,7 +298,8 @@ bool SierpinskiFill::bubbleUpConstraintErrors() std::list::iterator SierpinskiFill::subdivide(std::list::iterator begin, std::list::iterator end, bool redistribute_errors) { - if (redistribute_errors && deep_debug_checking) debugCheck(); + if (redistribute_errors && deep_debug_checking) + debugCheck(); if (redistribute_errors) { // move left-over errors bool distribute_subdivision_errors = true; @@ -309,16 +309,16 @@ std::list::iterator SierpinskiFill::subdivi SierpinskiTriangle* last = *std::prev(end); (*begin)->children.front().error_left += first->error_left; (*std::prev(end))->children.back().error_right += last->error_right; - } - if (redistribute_errors && deep_debug_checking) debugCheck(false); + if (redistribute_errors && deep_debug_checking) + debugCheck(false); std::list::iterator first_child_it = std::prev(begin); // the actual subdivision for (std::list::iterator it = begin; it != end; ++it) { SierpinskiTriangle* node = *it; - assert(!node->children.empty() && "cannot subdivide node with no children!"); + assert(! node->children.empty() && "cannot subdivide node with no children!"); for (SierpinskiTriangle& child : node->children) { sequence.insert(begin, &child); @@ -329,7 +329,8 @@ std::list::iterator SierpinskiFill::subdivi std::list::iterator last_child_it = std::prev(begin); sequence.erase(begin, end); - if (redistribute_errors && deep_debug_checking) debugCheck(false); + if (redistribute_errors && deep_debug_checking) + debugCheck(false); if (redistribute_errors) { // make positive errors in children well balanced @@ -337,7 +338,8 @@ std::list::iterator SierpinskiFill::subdivi balanceErrors(first_child_it, std::next(last_child_it)); } - if (redistribute_errors && deep_debug_checking) debugCheck(); + if (redistribute_errors && deep_debug_checking) + debugCheck(); return last_child_it; } @@ -356,7 +358,7 @@ void SierpinskiFill::redistributeLeftoverErrors(std::list:: SierpinskiTriangle* next = *std::next(it); if (std::abs(node->error_right + next->error_left) > allowed_length_error) { - logWarning("Nodes aren't balanced! er: %f next el: %f\n", node->error_right, next->error_left); + spdlog::warn("Nodes aren't balanced! er: {} next el: {}", node->error_right, next->error_left); assert(false); } float exchange = node->error_right; @@ -372,13 +374,13 @@ void SierpinskiFill::redistributeLeftoverErrors(std::list:: for (auto it = begin; it != end; ++it) { SierpinskiTriangle* node = *it; - total_superfluous_error += (distribute_subdivision_errors)? node->getSubdivisionError() : node->getValueError(); + total_superfluous_error += (distribute_subdivision_errors) ? node->getSubdivisionError() : node->getValueError(); } if (total_superfluous_error < allowed_length_error) { // there is no significant left-over error if (distribute_subdivision_errors && total_superfluous_error < -allowed_length_error) { - logWarning("redistributeLeftoverErrors shouldn't be called if the node isn't to be subdivided. Total error: %f\n", total_superfluous_error); + spdlog::warn("RedistributeLeftoverErrors shouldn't be called if the node isn't to be subdivided. Total error: {}", total_superfluous_error); assert(false); } return; @@ -427,10 +429,7 @@ void SierpinskiFill::balanceErrors(std::listgetValueError() < nodes[b]->getValueError(); - }); + std::sort(order.begin(), order.end(), [&nodes](int a, int b) { return nodes[a]->getValueError() < nodes[b]->getValueError(); }); // add error to children with too low value float added = 0; @@ -469,11 +468,11 @@ void SierpinskiFill::balanceErrors(std::list %f\n", total_remaining_value_error, added); + spdlog::warn("total_remaining: {} should be > {}", total_remaining_value_error, added); assert(false); } - if (std::abs(total_remaining_value_error) < .0001) //Error is insignificant. + if (std::abs(total_remaining_value_error) < .0001) // Error is insignificant. { return; } @@ -491,7 +490,7 @@ void SierpinskiFill::balanceErrors(std::list allowed_length_error) { - logWarning("Redistribution didn't distribute well!! added %f subtracted %f\n", added, subtracted); + spdlog::warn("Redistribution didn't distribute well!! added {} subtracted {}", added, subtracted); assert(false); } @@ -531,23 +530,18 @@ void SierpinskiFill::diffuseError() float boundary = (triangle.realized_length + triangle.total_child_realized_length) * .5f; - float nodal_value = ((use_errors_in_dithering)? triangle.getErroredValue() : triangle.requested_length); + float nodal_value = ((use_errors_in_dithering) ? triangle.getErroredValue() : triangle.requested_length); float boundary_error = nodal_value - boundary + error; std::list::iterator begin = it; std::list::iterator end = std::next(it); - if ( - triangle.dir == SierpinskiTriangle::SierpinskiDirection::AC_TO_AB - && end != sequence.end() - ) + if (triangle.dir == SierpinskiTriangle::SierpinskiDirection::AC_TO_AB && end != sequence.end()) { pair_constrained_nodes++; continue; // don't subdivide these two triangles just yet, wait till next iteration } - if (triangle.dir == SierpinskiTriangle::SierpinskiDirection::AB_TO_BC - && begin != sequence.begin() - ) + if (triangle.dir == SierpinskiTriangle::SierpinskiDirection::AB_TO_BC && begin != sequence.begin()) { begin = std::prev(it); assert((*begin)->depth == triangle.depth || isConstrainedBackward(it)); @@ -564,12 +558,9 @@ void SierpinskiFill::diffuseError() break; } } - if (!is_constrained) + if (! is_constrained) unconstrained_nodes++; - if (!is_constrained - && boundary_error >= 0 - && !triangle.children.empty() - ) + if (! is_constrained && boundary_error >= 0 && ! triangle.children.empty()) { subdivided_nodes++; it = subdivide(begin, end, false); @@ -582,7 +573,7 @@ void SierpinskiFill::diffuseError() error += nodal_value - triangle.realized_length; } } - logDebug("pair_constrained_nodes: %i, constrained_nodes: %i, unconstrained_nodes: %i, subdivided_nodes: %i\n", pair_constrained_nodes, constrained_nodes, unconstrained_nodes, subdivided_nodes); + spdlog::debug("pair_constrained_nodes: {}, constrained_nodes: {}, unconstrained_nodes: {}, subdivided_nodes: {}", pair_constrained_nodes, constrained_nodes, unconstrained_nodes, subdivided_nodes); } bool SierpinskiFill::isConstrainedBackward(std::list::iterator it) @@ -614,8 +605,6 @@ float SierpinskiFill::getSubdivisionError(std::list::iterat } - - void SierpinskiFill::debugOutput(SVG& svg) { svg.writePolygon(aabb.toPolygon(), SVG::Color::RED); @@ -634,19 +623,19 @@ void SierpinskiFill::debugOutput(SVG& svg) SierpinskiFill::Edge SierpinskiFill::SierpinskiTriangle::getFromEdge() { Edge ret; - switch(dir) + switch (dir) { - case SierpinskiDirection::AB_TO_BC: - ret = Edge{a, b}; - break; - case SierpinskiDirection::AC_TO_AB: - ret = Edge{straight_corner, a}; - break; - case SierpinskiDirection::AC_TO_BC: - ret = Edge{straight_corner, a}; - break; + case SierpinskiDirection::AB_TO_BC: + ret = Edge{ a, b }; + break; + case SierpinskiDirection::AC_TO_AB: + ret = Edge{ straight_corner, a }; + break; + case SierpinskiDirection::AC_TO_BC: + ret = Edge{ straight_corner, a }; + break; } - if (!straight_corner_is_left) + if (! straight_corner_is_left) { std::swap(ret.l, ret.r); } @@ -656,19 +645,19 @@ SierpinskiFill::Edge SierpinskiFill::SierpinskiTriangle::getFromEdge() SierpinskiFill::Edge SierpinskiFill::SierpinskiTriangle::getToEdge() { Edge ret; - switch(dir) + switch (dir) { - case SierpinskiDirection::AB_TO_BC: - ret = Edge{straight_corner, b}; - break; - case SierpinskiDirection::AC_TO_AB: - ret = Edge{b, a}; - break; - case SierpinskiDirection::AC_TO_BC: - ret = Edge{straight_corner, b}; - break; + case SierpinskiDirection::AB_TO_BC: + ret = Edge{ straight_corner, b }; + break; + case SierpinskiDirection::AC_TO_AB: + ret = Edge{ b, a }; + break; + case SierpinskiDirection::AC_TO_BC: + ret = Edge{ straight_corner, b }; + break; } - if (!straight_corner_is_left) + if (! straight_corner_is_left) { std::swap(ret.l, ret.r); } @@ -704,17 +693,17 @@ Polygon SierpinskiFill::generateCross() const { SierpinskiTriangle& triangle = *max_level_it; Point edge_middle = triangle.a + triangle.b + triangle.straight_corner; - switch(triangle.dir) + switch (triangle.dir) { - case SierpinskiTriangle::SierpinskiDirection::AB_TO_BC: - edge_middle -= triangle.a; - break; - case SierpinskiTriangle::SierpinskiDirection::AC_TO_AB: - edge_middle -= triangle.straight_corner; - break; - case SierpinskiTriangle::SierpinskiDirection::AC_TO_BC: - edge_middle -= triangle.a; - break; + case SierpinskiTriangle::SierpinskiDirection::AB_TO_BC: + edge_middle -= triangle.a; + break; + case SierpinskiTriangle::SierpinskiDirection::AC_TO_AB: + edge_middle -= triangle.straight_corner; + break; + case SierpinskiTriangle::SierpinskiDirection::AC_TO_BC: + edge_middle -= triangle.a; + break; } ret.add(edge_middle / 2); } @@ -722,16 +711,15 @@ Polygon SierpinskiFill::generateCross() const float realized_length = INT2MM(ret.polygonLength()); float requested_length = root.requested_length; float error = (realized_length - requested_length) / requested_length; - logDebug("realized_length: %f, requested_length: %f :: %f% error\n", realized_length, requested_length, .01 * static_cast(10000 * error)); + spdlog::debug("realized_length: {}, requested_length: {} :: {}% error", realized_length, requested_length, .01 * static_cast(10000 * error)); return ret; } Polygon SierpinskiFill::generateCross(coord_t z, coord_t min_dist_to_side, coord_t pocket_size) const { - Polygon ret; - std::function get_edge_crossing_location = [z, min_dist_to_side](const coord_t period, const Edge e) + std::function get_edge_crossing_location = [z, min_dist_to_side](const coord_t period, const Edge e) { coord_t from_l = z % (period * 2); if (from_l > period) @@ -807,19 +795,18 @@ Polygon SierpinskiFill::generateCross(coord_t z, coord_t min_dist_to_side, coord { return ret; } - } void SierpinskiFill::debugCheck(bool check_subdivision) { if (std::abs(sequence.front()->error_left) > allowed_length_error) { - logWarning("First node has error left!\n"); + spdlog::warn("First node has error left!"); assert(false); } if (std::abs(sequence.back()->error_right) > allowed_length_error) { - logWarning("Last node has error right!\n"); + spdlog::warn("Last node has error right!"); assert(false); } @@ -834,12 +821,12 @@ void SierpinskiFill::debugCheck(bool check_subdivision) if (std::abs(node->error_right + next->error_left) > allowed_length_error) { - logWarning("Consecutive nodes in fractal don't have the same error! er: %f , nel: %f\n", node->error_right, next->error_left); + spdlog::warn("Consecutive nodes in fractal don't have the same error! er: {} , nel: {}", node->error_right, next->error_left); assert(false); } if (check_subdivision && node->getValueError() < -allowed_length_error) { - logWarning("Fractal node shouldn't have been subdivided!\n"); + spdlog::warn("Fractal node shouldn't have been subdivided!"); assert(false); } } diff --git a/src/infill/SierpinskiFillProvider.cpp b/src/infill/SierpinskiFillProvider.cpp index 508e9281cf..908c482d7e 100644 --- a/src/infill/SierpinskiFillProvider.cpp +++ b/src/infill/SierpinskiFillProvider.cpp @@ -1,12 +1,12 @@ -//Copyright (C) 2017 Tim Kuipers -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher + +#include #include "infill/ImageBasedDensityProvider.h" -#include "infill/UniformDensityProvider.h" #include "infill/SierpinskiFillProvider.h" +#include "infill/UniformDensityProvider.h" #include "utils/AABB3D.h" -#include "utils/logoutput.h" #include "utils/math.h" #include "utils/polygon.h" @@ -18,16 +18,16 @@ constexpr bool SierpinskiFillProvider::get_constructor; constexpr bool SierpinskiFillProvider::use_dithering; SierpinskiFillProvider::SierpinskiFillProvider(const AABB3D aabb_3d, coord_t min_line_distance, const coord_t line_width) -: fractal_config(getFractalConfig(aabb_3d, min_line_distance)) -, density_provider(new UniformDensityProvider((float)line_width / min_line_distance)) -, fill_pattern_for_all_layers(std::in_place, *density_provider, fractal_config.aabb, fractal_config.depth, line_width, use_dithering) + : fractal_config(getFractalConfig(aabb_3d, min_line_distance)) + , density_provider(new UniformDensityProvider((float)line_width / min_line_distance)) + , fill_pattern_for_all_layers(std::in_place, *density_provider, fractal_config.aabb, fractal_config.depth, line_width, use_dithering) { } SierpinskiFillProvider::SierpinskiFillProvider(const AABB3D aabb_3d, coord_t min_line_distance, coord_t line_width, std::string cross_subdisivion_spec_image_file) -: fractal_config(getFractalConfig(aabb_3d, min_line_distance)) -, density_provider(new ImageBasedDensityProvider(cross_subdisivion_spec_image_file, aabb_3d.flatten())) -, fill_pattern_for_all_layers(std::in_place, *density_provider, fractal_config.aabb, fractal_config.depth, line_width, use_dithering) + : fractal_config(getFractalConfig(aabb_3d, min_line_distance)) + , density_provider(new ImageBasedDensityProvider(cross_subdisivion_spec_image_file, aabb_3d.flatten())) + , fill_pattern_for_all_layers(std::in_place, *density_provider, fractal_config.aabb, fractal_config.depth, line_width, use_dithering) { } @@ -47,7 +47,7 @@ Polygon SierpinskiFillProvider::generate(EFillMethod pattern, coord_t z, coord_t else { Polygon ret; - logError("Different density sierpinski fill for different layers is not implemented yet!\n"); + spdlog::error("Different density sierpinski fill for different layers is not implemented yet!"); std::exit(-1); return ret; } @@ -85,9 +85,8 @@ SierpinskiFillProvider::FractalConfig SierpinskiFillProvider::getFractalConfig(c Point radius(aabb_size / 2, aabb_size / 2); AABB aabb(model_middle - radius, model_middle + radius); - return FractalConfig{depth, aabb}; + return FractalConfig{ depth, aabb }; } - } // namespace cura diff --git a/src/main.cpp b/src/main.cpp index 2228c0141e..bcfd39d9f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,36 +1,38 @@ -//Copyright (c) 2018 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include //To change the formatting of std::cerr. #include //For floating point exceptions. #if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) - #include //For setpriority. +#include //For setpriority. #endif + +#include + #include "Application.h" -#include "utils/logoutput.h" namespace cura { -//Signal handler for a "floating point exception", which can also be integer division by zero errors. +// Signal handler for a "floating point exception", which can also be integer division by zero errors. void signal_FPE(int n) { (void)n; - logError("Arithmetic exception.\n"); + spdlog::error("Arithmetic exception."); exit(1); } -}//namespace cura +} // namespace cura -int main(int argc, char **argv) +int main(int argc, char** argv) { #if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) - //Lower the process priority on linux and mac. On windows this is done on process creation from the GUI. + // Lower the process priority on linux and mac. On windows this is done on process creation from the GUI. setpriority(PRIO_PROCESS, 0, 10); #endif #ifndef DEBUG - //Register the exception handling for arithmetic exceptions, this prevents the "something went wrong" dialog on windows to pop up on a division by zero. + // Register the exception handling for arithmetic exceptions, this prevents the "something went wrong" dialog on windows to pop up on a division by zero. signal(SIGFPE, cura::signal_FPE); #endif std::cerr << std::boolalpha; diff --git a/src/mesh.cpp b/src/mesh.cpp index 41381f12c2..82a651a9cf 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -1,9 +1,10 @@ -//Copyright (c) 2018 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher + +#include #include "mesh.h" #include "utils/floatpoint.h" -#include "utils/logoutput.h" namespace cura { @@ -15,20 +16,14 @@ const int vertex_meld_distance = MM2INT(0.03); */ static inline uint32_t pointHash(const Point3& p) { - return ((p.x + vertex_meld_distance/2) / vertex_meld_distance) ^ (((p.y + vertex_meld_distance/2) / vertex_meld_distance) << 10) ^ (((p.z + vertex_meld_distance/2) / vertex_meld_distance) << 20); + return ((p.x + vertex_meld_distance / 2) / vertex_meld_distance) ^ (((p.y + vertex_meld_distance / 2) / vertex_meld_distance) << 10) ^ (((p.z + vertex_meld_distance / 2) / vertex_meld_distance) << 20); } -Mesh::Mesh(Settings& parent) -: settings(parent) -, has_disconnected_faces(false) -, has_overlapping_faces(false) +Mesh::Mesh(Settings& parent) : settings(parent), has_disconnected_faces(false), has_overlapping_faces(false) { } -Mesh::Mesh() -: settings() -, has_disconnected_faces(false) -, has_overlapping_faces(false) +Mesh::Mesh() : settings(), has_disconnected_faces(false), has_overlapping_faces(false) { } @@ -37,7 +32,8 @@ void Mesh::addFace(Point3& v0, Point3& v1, Point3& v2) int vi0 = findIndexOfVertex(v0); int vi1 = findIndexOfVertex(v1); int vi2 = findIndexOfVertex(v2); - if (vi0 == vi1 || vi1 == vi2 || vi0 == vi2) return; // the face has two vertices which get assigned the same location. Don't add the face. + if (vi0 == vi1 || vi1 == vi2 || vi0 == vi2) + return; // the face has two vertices which get assigned the same location. Don't add the face. int idx = faces.size(); // index of face to be added faces.emplace_back(); @@ -63,7 +59,7 @@ void Mesh::finish() vertex_hash_map.clear(); // For each face, store which other face is connected with it. - for(unsigned int i=0; i("infill_mesh") && !settings.get("cutting_mesh") && !settings.get("anti_overhang_mesh"); + return ! settings.get("infill_mesh") && ! settings.get("cutting_mesh") && ! settings.get("anti_overhang_mesh"); } - + int Mesh::findIndexOfVertex(const Point3& v) { uint32_t hash = pointHash(v); - for(unsigned int idx = 0; idx < vertex_hash_map[hash].size(); idx++) + for (unsigned int idx = 0; idx < vertex_hash_map[hash].size(); idx++) { if ((vertices[vertex_hash_map[hash][idx]].p - v).testLength(vertex_meld_distance)) { @@ -122,9 +118,9 @@ int Mesh::findIndexOfVertex(const Point3& v) } vertex_hash_map[hash].push_back(vertices.size()); vertices.emplace_back(v); - + aabb.include(v); - + return vertices.size() - 1; } @@ -155,38 +151,41 @@ See the normalized normal FPoint3 v0 = vertices[idx1].p - vertices[idx0].p; -// the normals below are abnormally directed! : these normals all point counterclockwise (viewed from idx1 to idx0) from the face, irrespective of the direction of the face. + // the normals below are abnormally directed! : these normals all point counterclockwise (viewed from idx1 to idx0) from the face, irrespective of the direction of the face. FPoint3 n0 = FPoint3(vertices[notFaceVertexIdx].p - vertices[idx0].p).cross(v0); if (n0.vSize() <= 0) { - cura::logDebug("Face %i has zero area!", notFaceIdx); + spdlog::debug("Face {} has zero area!", notFaceIdx); } double smallestAngle = 1000; // more then 2 PI (impossible angle) @@ -209,8 +208,8 @@ int Mesh::getFaceIdxWithPoints(int idx0, int idx1, int notFaceIdx, int notFaceVe for (int candidateFace : candidateFaces) { int candidateVertex; - {// find third vertex belonging to the face (besides idx0 and idx1) - for (candidateVertex = 0; candidateVertex<3; candidateVertex++) + { // find third vertex belonging to the face (besides idx0 and idx1) + for (candidateVertex = 0; candidateVertex < 3; candidateVertex++) if (faces[candidateFace].vertex_index[candidateVertex] != idx0 && faces[candidateFace].vertex_index[candidateVertex] != idx1) break; } @@ -221,14 +220,15 @@ int Mesh::getFaceIdxWithPoints(int idx0, int idx1, int notFaceIdx, int notFaceVe double dot = n0 * n1; double det = n * n0.cross(n1); double angle = std::atan2(det, dot); - if (angle < 0) angle += 2*M_PI; // 0 <= angle < 2* M_PI + if (angle < 0) + angle += 2 * M_PI; // 0 <= angle < 2* M_PI if (angle == 0) { - cura::logDebug("Overlapping faces: face %i and face %i.\n", notFaceIdx, candidateFace); - if (!has_overlapping_faces) + spdlog::debug("Overlapping faces: face {} and face {}.", notFaceIdx, candidateFace); + if (! has_overlapping_faces) { - cura::logWarning("Mesh has overlapping faces!\n"); + spdlog::warn("Mesh has overlapping faces!"); } has_overlapping_faces = true; } @@ -240,14 +240,14 @@ int Mesh::getFaceIdxWithPoints(int idx0, int idx1, int notFaceIdx, int notFaceVe } if (bestIdx < 0) { - cura::logDebug("Couldn't find face connected to face %i.\n", notFaceIdx); - if (!has_disconnected_faces) + spdlog::debug("Couldn't find face connected to face {}.", notFaceIdx); + if (! has_disconnected_faces) { - cura::logWarning("Mesh has disconnected faces!\n"); + spdlog::warn("Mesh has disconnected faces!"); } has_disconnected_faces = true; } return bestIdx; } -}//namespace cura +} // namespace cura diff --git a/src/progress/Progress.cpp b/src/progress/Progress.cpp index 4568089372..62687044c6 100644 --- a/src/progress/Progress.cpp +++ b/src/progress/Progress.cpp @@ -1,18 +1,19 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include -#include "progress/Progress.h" +#include + #include "Application.h" //To get the communication channel to send progress through. #include "communication/Communication.h" //To send progress through the communication channel. +#include "progress/Progress.h" #include "utils/gettime.h" -#include "utils/logoutput.h" -namespace cura { - -double Progress::times [] = -{ +namespace cura +{ + +double Progress::times[] = { 0.0, // START = 0, 5.269, // SLICING = 1, 1.533, // PARTS = 2, @@ -59,7 +60,7 @@ void Progress::messageProgress(Progress::Stage stage, int progress_in_stage, int float percentage = calcOverallProgress(stage, float(progress_in_stage) / float(progress_in_stage_max)); Application::getInstance().communication->sendProgress(percentage); - logProgress(names[(int)stage].c_str(), progress_in_stage, progress_in_stage_max, percentage); + // logProgress(names[(int)stage].c_str(), progress_in_stage, progress_in_stage_max, percentage); FIXME: use different sink } void Progress::messageProgressStage(Progress::Stage stage, TimeKeeper* time_keeper) @@ -68,7 +69,7 @@ void Progress::messageProgressStage(Progress::Stage stage, TimeKeeper* time_keep { if ((int)stage > 0) { - log("Progress: %s accomplished in %5.3fs\n", names[(int)stage - 1].c_str(), time_keeper->restart()); + spdlog::info("Progress: {} accomplished in {:3}s", names[(int)stage - 1], time_keeper->restart()); } else { @@ -77,7 +78,7 @@ void Progress::messageProgressStage(Progress::Stage stage, TimeKeeper* time_keep if ((int)stage < (int)Stage::FINISH) { - log("Starting %s...\n", names[(int)stage].c_str()); + spdlog::info("Starting {}...", names[(int)stage]); } } } diff --git a/src/settings/FlowTempGraph.cpp b/src/settings/FlowTempGraph.cpp index ed9433d3de..700b9cbdf3 100644 --- a/src/settings/FlowTempGraph.cpp +++ b/src/settings/FlowTempGraph.cpp @@ -1,15 +1,16 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include "settings/FlowTempGraph.h" -#include "utils/logoutput.h" + +#include namespace cura { double FlowTempGraph::getTemp(const double flow, const Temperature material_print_temperature, const bool flow_dependent_temperature) const { - if (!flow_dependent_temperature || data.size() == 0) + if (! flow_dependent_temperature || data.size() == 0) { return material_print_temperature; } @@ -19,7 +20,7 @@ double FlowTempGraph::getTemp(const double flow, const Temperature material_prin } if (flow < data.front().flow) { - logWarning("Warning! Flow too low!\n"); // TODO + spdlog::warn("Warning! Flow too low!"); return data.front().temp; } const Datum* last_datum = &data.front(); @@ -33,8 +34,8 @@ double FlowTempGraph::getTemp(const double flow, const Temperature material_prin last_datum = &datum; } - logWarning("Warning! Flow too high!\n"); // TODO + spdlog::warn("Warning! Flow too high!"); return data.back().temp; } -} //namespace cura +} // namespace cura diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index 770db7a51e..add349eb05 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -1,13 +1,19 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include #include -#include -#include // ostringstream #include // regex parsing for temp flow graph +#include // ostringstream +#include #include //Parsing strings (stod, stoul). +#include + +#include "Application.h" //To get the extruders. +#include "BeadingStrategy/BeadingStrategyFactory.h" +#include "ExtruderTrain.h" +#include "Slice.h" #include "settings/EnumSettings.h" #include "settings/FlowTempGraph.h" #include "settings/Settings.h" @@ -17,37 +23,33 @@ #include "settings/types/Ratio.h" //For ratio settings and percentages. #include "settings/types/Temperature.h" //For temperature settings. #include "settings/types/Velocity.h" //For velocity settings. -#include "Application.h" //To get the extruders. -#include "ExtruderTrain.h" -#include "Slice.h" #include "utils/FMatrix4x3.h" -#include "utils/logoutput.h" #include "utils/string.h" //For Escaped. -#include "BeadingStrategy/BeadingStrategyFactory.h" namespace cura { Settings::Settings() { - parent = nullptr; //Needs to be properly initialised because we check against this if the parent is not set. + parent = nullptr; // Needs to be properly initialised because we check against this if the parent is not set. } void Settings::add(const std::string& key, const std::string value) { - if (settings.find(key) != settings.end()) //Already exists. + if (settings.find(key) != settings.end()) // Already exists. { settings[key] = value; } - else //New setting. + else // New setting. { settings.emplace(key, value); } } -template<> std::string Settings::get(const std::string& key) const +template<> +std::string Settings::get(const std::string& key) const { - //If this settings base has a setting value for it, look that up. + // If this settings base has a setting value for it, look that up. if (settings.find(key) != settings.end()) { return settings.at(key); @@ -64,26 +66,30 @@ template<> std::string Settings::get(const std::string& key) const return parent->get(key); } - logError("Trying to retrieve setting with no value given: '%s'\n", key.c_str()); + spdlog::error("Trying to retrieve setting with no value given: {}", key); std::exit(2); } -template<> double Settings::get(const std::string& key) const +template<> +double Settings::get(const std::string& key) const { return atof(get(key).c_str()); } -template<> size_t Settings::get(const std::string& key) const +template<> +size_t Settings::get(const std::string& key) const { return std::stoul(get(key).c_str()); } -template<> int Settings::get(const std::string& key) const +template<> +int Settings::get(const std::string& key) const { return atoi(get(key).c_str()); } -template<> bool Settings::get(const std::string& key) const +template<> +bool Settings::get(const std::string& key) const { const std::string& value = get(key); if (value == "on" || value == "yes" || value == "true" || value == "True") @@ -94,7 +100,8 @@ template<> bool Settings::get(const std::string& key) const return num != 0; } -template<> ExtruderTrain& Settings::get(const std::string& key) const +template<> +ExtruderTrain& Settings::get(const std::string& key) const { int extruder_nr = std::atoi(get(key).c_str()); if (extruder_nr < 0) @@ -104,67 +111,77 @@ template<> ExtruderTrain& Settings::get(const std::string& key) return Application::getInstance().current_slice->scene.extruders[extruder_nr]; } -template<> LayerIndex Settings::get(const std::string& key) const +template<> +LayerIndex Settings::get(const std::string& key) const { - return std::atoi(get(key).c_str()) - 1; //For the user we display layer numbers starting from 1, but we start counting from 0. Still it may be negative for Raft layers. + return std::atoi(get(key).c_str()) - 1; // For the user we display layer numbers starting from 1, but we start counting from 0. Still it may be negative for Raft layers. } -template<> coord_t Settings::get(const std::string& key) const +template<> +coord_t Settings::get(const std::string& key) const { - return MM2INT(get(key)); //The settings are all in millimetres, but we need to interpret them as microns. + return MM2INT(get(key)); // The settings are all in millimetres, but we need to interpret them as microns. } -template<> AngleRadians Settings::get(const std::string& key) const +template<> +AngleRadians Settings::get(const std::string& key) const { - return get(key) * M_PI / 180; //The settings are all in degrees, but we need to interpret them as radians. + return get(key) * M_PI / 180; // The settings are all in degrees, but we need to interpret them as radians. } -template<> AngleDegrees Settings::get(const std::string& key) const +template<> +AngleDegrees Settings::get(const std::string& key) const { return get(key); } -template<> Temperature Settings::get(const std::string& key) const +template<> +Temperature Settings::get(const std::string& key) const { return get(key); } -template<> Velocity Settings::get(const std::string& key) const +template<> +Velocity Settings::get(const std::string& key) const { return get(key); } -template<> Ratio Settings::get(const std::string& key) const +template<> +Ratio Settings::get(const std::string& key) const { - return get(key) / 100.0; //The settings are all in percentages, but we need to interpret them as radians. + return get(key) / 100.0; // The settings are all in percentages, but we need to interpret them as radians. } -template<> Duration Settings::get(const std::string& key) const +template<> +Duration Settings::get(const std::string& key) const { return get(key); } -template<> DraftShieldHeightLimitation Settings::get(const std::string& key) const +template<> +DraftShieldHeightLimitation Settings::get(const std::string& key) const { const std::string& value = get(key); if (value == "limited") { return DraftShieldHeightLimitation::LIMITED; } - else //if (value == "full") or default. + else // if (value == "full") or default. { return DraftShieldHeightLimitation::FULL; } } -template<> FlowTempGraph Settings::get(const std::string& key) const +template<> +FlowTempGraph Settings::get(const std::string& key) const { std::string value_string = get(key); FlowTempGraph result; if (value_string.empty()) { - return result; //Empty at this point. + return result; // Empty at this point. } /* Match with: * - the last opening bracket '[' @@ -175,14 +192,14 @@ template<> FlowTempGraph Settings::get(const std::string& key) co */ std::regex regex("(\\[([^,\\[]*),([^,\\]]*)\\])"); - //Default constructor = end-of-sequence: + // Default constructor = end-of-sequence: std::regex_token_iterator rend; - const int submatches[] = {1, 2, 3}; //Match whole pair, first number and second number of a pair. + const int submatches[] = { 1, 2, 3 }; // Match whole pair, first number and second number of a pair. std::regex_token_iterator match_iter(value_string.begin(), value_string.end(), regex, submatches); while (match_iter != rend) { - match_iter++; //Match the whole pair. + match_iter++; // Match the whole pair. if (match_iter == rend) { break; @@ -197,39 +214,41 @@ template<> FlowTempGraph Settings::get(const std::string& key) co } catch (const std::invalid_argument& e) { - logError("Couldn't read 2D graph element [%s,%s] in setting '%s'. Ignored.\n", first_substring.c_str(), second_substring.c_str(), key.c_str()); + spdlog::error("Couldn't read 2D graph element [{},{}] in setting {}. Ignored.", first_substring, second_substring, key); } } return result; } -template<> FMatrix4x3 Settings::get(const std::string& key) const +template<> +FMatrix4x3 Settings::get(const std::string& key) const { const std::string value_string = get(key); FMatrix4x3 result; if (value_string.empty()) { - return result; //Standard matrix ([[1,0,0], [0,1,0], [0,0,1]]). + return result; // Standard matrix ([[1,0,0], [0,1,0], [0,0,1]]). } - std::string num("([^,\\] ]*)"); //Match with anything but the next ',' ']' or space and capture the match. - std::ostringstream row; //Match with "[num,num,num]" and ignore whitespace. + std::string num("([^,\\] ]*)"); // Match with anything but the next ',' ']' or space and capture the match. + std::ostringstream row; // Match with "[num,num,num]" and ignore whitespace. row << "\\s*\\[\\s*" << num << "\\s*,\\s*" << num << "\\s*,\\s*" << num << "\\s*\\]\\s*"; - std::ostringstream matrix; //Match with "[row,row,row]" and ignore whitespace. + std::ostringstream matrix; // Match with "[row,row,row]" and ignore whitespace. matrix << "\\s*\\[\\s*" << row.str() << "\\s*,\\s*" << row.str() << "\\s*,\\s*" << row.str() << "\\]\\s*"; std::regex point_matrix_regex(matrix.str()); - std::cmatch sub_matches; //Same as std::match_results cm; + std::cmatch sub_matches; // Same as std::match_results cm; std::regex_match(value_string.c_str(), sub_matches, point_matrix_regex); - if (sub_matches.size() != 10) //One match for the whole string, nine for the cells. + if (sub_matches.size() != 10) // One match for the whole string, nine for the cells. { - logWarning("Mesh transformation matrix could not be parsed!\n\tFormat should be [[f,f,f], [f,f,f], [f,f,f]] allowing whitespace anywhere in between.\n\tWhile what was given was \"%s\".\n", value_string.c_str()); - return result; //Standard matrix ([[1,0,0], [0,1,0], [0,0,1]]). + spdlog::warn("Mesh transformation matrix could not be parsed!"); + spdlog::debug("Format should be [[f,f,f], [f,f,f], [f,f,f]] allowing whitespace anywhere in between. While what was given was {}", value_string); + return result; // Standard matrix ([[1,0,0], [0,1,0], [0,0,1]]). } - size_t sub_match_index = 1; //Skip the first because the first submatch is the whole string. + size_t sub_match_index = 1; // Skip the first because the first submatch is the whole string. for (size_t x = 0; x < 3; x++) { for (size_t y = 0; y < 3; y++) @@ -243,10 +262,11 @@ template<> FMatrix4x3 Settings::get(const std::string& key) const return result; } -template<> EGCodeFlavor Settings::get(const std::string& key) const +template<> +EGCodeFlavor Settings::get(const std::string& key) const { const std::string& value = get(key); - //I wish that switch statements worked for std::string... + // I wish that switch statements worked for std::string... if (value == "Griffin") { return EGCodeFlavor::GRIFFIN; @@ -279,11 +299,12 @@ template<> EGCodeFlavor Settings::get(const std::string& key) cons { return EGCodeFlavor::REPRAP; } - //Default: + // Default: return EGCodeFlavor::MARLIN; } -template<> EFillMethod Settings::get(const std::string& key) const +template<> +EFillMethod Settings::get(const std::string& key) const { const std::string& value = get(key); if (value == "lines") @@ -342,13 +363,14 @@ template<> EFillMethod Settings::get(const std::string& key) const { return EFillMethod::LIGHTNING; } - else //Default. + else // Default. { return EFillMethod::NONE; } } -template<> EPlatformAdhesion Settings::get(const std::string& key) const +template<> +EPlatformAdhesion Settings::get(const std::string& key) const { const std::string& value = get(key); if (value == "brim") @@ -363,13 +385,14 @@ template<> EPlatformAdhesion Settings::get(const std::string& { return EPlatformAdhesion::NONE; } - else //Default. + else // Default. { return EPlatformAdhesion::SKIRT; } } -template<> ESupportType Settings::get(const std::string& key) const +template<> +ESupportType Settings::get(const std::string& key) const { const std::string& value = get(key); if (value == "everywhere") @@ -380,13 +403,14 @@ template<> ESupportType Settings::get(const std::string& key) cons { return ESupportType::PLATFORM_ONLY; } - else //Default. + else // Default. { return ESupportType::NONE; } } -template<> ESupportStructure Settings::get(const std::string& key) const +template<> +ESupportStructure Settings::get(const std::string& key) const { const std::string& value = get(key); if (value == "normal") @@ -397,21 +421,22 @@ template<> ESupportStructure Settings::get(const std::string& { return ESupportStructure::TREE; } - else //Default. + else // Default. { return ESupportStructure::NORMAL; } } -template<> EZSeamType Settings::get(const std::string& key) const +template<> +EZSeamType Settings::get(const std::string& key) const { const std::string& value = get(key); if (value == "random") { return EZSeamType::RANDOM; } - else if (value == "back") //It's called 'back' internally because originally this was intended to allow the user to put the seam in the back of the object where it's less visible. + else if (value == "back") // It's called 'back' internally because originally this was intended to allow the user to put the seam in the back of the object where it's less visible. { return EZSeamType::USER_SPECIFIED; } @@ -419,13 +444,14 @@ template<> EZSeamType Settings::get(const std::string& key) const { return EZSeamType::SHARPEST_CORNER; } - else //Default. + else // Default. { return EZSeamType::SHORTEST; } } -template<> EZSeamCornerPrefType Settings::get(const std::string& key) const +template<> +EZSeamCornerPrefType Settings::get(const std::string& key) const { const std::string& value = get(key); if (value == "z_seam_corner_inner") @@ -444,13 +470,14 @@ template<> EZSeamCornerPrefType Settings::get(const std::s { return EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_WEIGHTED; } - else //Default. + else // Default. { return EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE; } } -template<> ESurfaceMode Settings::get(const std::string& key) const +template<> +ESurfaceMode Settings::get(const std::string& key) const { const std::string& value = get(key); if (value == "surface") @@ -461,37 +488,40 @@ template<> ESurfaceMode Settings::get(const std::string& key) cons { return ESurfaceMode::BOTH; } - else //Default. + else // Default. { return ESurfaceMode::NORMAL; } } -template<> FillPerimeterGapMode Settings::get(const std::string& key) const +template<> +FillPerimeterGapMode Settings::get(const std::string& key) const { if (get(key) == "everywhere") { return FillPerimeterGapMode::EVERYWHERE; } - else //Default. + else // Default. { return FillPerimeterGapMode::NOWHERE; } } -template<> BuildPlateShape Settings::get(const std::string& key) const +template<> +BuildPlateShape Settings::get(const std::string& key) const { if (get(key) == "elliptic") { return BuildPlateShape::ELLIPTIC; } - else //Default. + else // Default. { return BuildPlateShape::RECTANGULAR; } } -template<> CombingMode Settings::get(const std::string& key) const +template<> +CombingMode Settings::get(const std::string& key) const { const std::string& value = get(key); if (value == "off") @@ -510,25 +540,27 @@ template<> CombingMode Settings::get(const std::string& key) const { return CombingMode::INFILL; } - else //Default. + else // Default. { return CombingMode::ALL; } } -template<> SupportDistPriority Settings::get(const std::string& key) const +template<> +SupportDistPriority Settings::get(const std::string& key) const { if (get(key) == "z_overrides_xy") { return SupportDistPriority::Z_OVERRIDES_XY; } - else //Default. + else // Default. { return SupportDistPriority::XY_OVERRIDES_Z; } } -template<> SlicingTolerance Settings::get(const std::string& key) const +template<> +SlicingTolerance Settings::get(const std::string& key) const { const std::string& value = get(key); if (value == "inclusive") @@ -539,26 +571,28 @@ template<> SlicingTolerance Settings::get(const std::string& k { return SlicingTolerance::EXCLUSIVE; } - else //Default. + else // Default. { return SlicingTolerance::MIDDLE; } } -template<> InsetDirection Settings::get(const std::string& key) const +template<> +InsetDirection Settings::get(const std::string& key) const { const std::string& value = get(key); - if(value == "outside_in") + if (value == "outside_in") { return InsetDirection::OUTSIDE_IN; } - else //Default. + else // Default. { return InsetDirection::INSIDE_OUT; } } -template<> std::vector Settings::get>(const std::string& key) const +template<> +std::vector Settings::get>(const std::string& key) const { const std::string& value_string = get(key); @@ -580,7 +614,7 @@ template<> std::vector Settings::get>(const std::str { std::string elements = list_contents_match.str(1); std::regex element_regex(R"(\s*([+-]?[0-9]*\.?[0-9]+)\s*,?)"); - std::regex_token_iterator rend; //Default constructor gets the end-of-sequence iterator. + std::regex_token_iterator rend; // Default constructor gets the end-of-sequence iterator. std::regex_token_iterator match_iter(elements.begin(), elements.end(), element_regex, 0); while (match_iter != rend) @@ -592,29 +626,31 @@ template<> std::vector Settings::get>(const std::str } catch (const std::invalid_argument& e) { - logError("Couldn't read floating point value (%s) in setting '%s'. Ignored.\n", value.c_str(), key.c_str()); + spdlog::error("Couldn't read floating point value ({}) in setting {}. Ignored.", value, key); } } } return result; } -template<> std::vector Settings::get>(const std::string& key) const +template<> +std::vector Settings::get>(const std::string& key) const { std::vector values_doubles = get>(key); std::vector values_ints; values_ints.reserve(values_doubles.size()); for (double value : values_doubles) { - values_ints.push_back(std::round(value)); //Round to nearest integer. + values_ints.push_back(std::round(value)); // Round to nearest integer. } return values_ints; } -template<> std::vector Settings::get>(const std::string& key) const +template<> +std::vector Settings::get>(const std::string& key) const { std::vector values_doubles = get>(key); - return std::vector(values_doubles.begin(), values_doubles.end()); //Cast them to AngleDegrees. + return std::vector(values_doubles.begin(), values_doubles.end()); // Cast them to AngleDegrees. } const std::string Settings::getAllSettingsString() const @@ -623,7 +659,7 @@ const std::string Settings::getAllSettingsString() const for (const std::pair pair : settings) { char buffer[4096]; - snprintf(buffer, 4096, " -s %s=\"%s\"", pair.first.c_str(), Escaped{pair.second.c_str()}.str); + snprintf(buffer, 4096, " -s %s=\"%s\"", pair.first.c_str(), Escaped{ pair.second.c_str() }.str); sstream << buffer; } return sstream.str(); @@ -651,10 +687,9 @@ std::string Settings::getWithoutLimiting(const std::string& key) const } else { - logError("Trying to retrieve setting with no value given: '%s'\n", key.c_str()); + spdlog::error("Trying to retrieve setting with no value given: {}", key); std::exit(2); } } -}//namespace cura - +} // namespace cura diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index c6d741e5d2..89deea7c09 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -1,33 +1,31 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher + +#include #include "Application.h" //To get settings. #include "ExtruderTrain.h" #include "FffProcessor.h" //To create a mesh group with if none is provided. -#include "raft.h" #include "Slice.h" -#include "sliceDataStorage.h" +#include "infill/DensityProvider.h" // for destructor #include "infill/LightningGenerator.h" #include "infill/SierpinskiFillProvider.h" #include "infill/SubDivCube.h" // For the destructor -#include "infill/DensityProvider.h" // for destructor +#include "raft.h" +#include "sliceDataStorage.h" #include "utils/math.h" //For PI. -#include "utils/logoutput.h" namespace cura { -SupportStorage::SupportStorage() -: generated(false) -, layer_nr_max_filled_layer(-1) -, cross_fill_provider(nullptr) +SupportStorage::SupportStorage() : generated(false), layer_nr_max_filled_layer(-1), cross_fill_provider(nullptr) { } SupportStorage::~SupportStorage() { - supportLayers.clear(); + supportLayers.clear(); if (cross_fill_provider) { delete cross_fill_provider; @@ -85,7 +83,7 @@ void SliceLayer::getOutlines(Polygons& result, bool external_polys_only) const { result.add(part.outline.outerPolygon()); } - else + else { result.add(part.print_outline); } @@ -93,13 +91,13 @@ void SliceLayer::getOutlines(Polygons& result, bool external_polys_only) const } SliceMeshStorage::SliceMeshStorage(Mesh* mesh, const size_t slice_layer_count) -: settings(mesh->settings) -, mesh_name(mesh->mesh_name) -, layer_nr_max_filled_layer(0) -, bounding_box(mesh->getAABB()) -, base_subdiv_cube(nullptr) -, cross_fill_provider(nullptr) -, lightning_generator(nullptr) + : settings(mesh->settings) + , mesh_name(mesh->mesh_name) + , layer_nr_max_filled_layer(0) + , bounding_box(mesh->getAABB()) + , base_subdiv_cube(nullptr) + , cross_fill_provider(nullptr) + , lightning_generator(nullptr) { layers.resize(slice_layer_count); } @@ -122,8 +120,7 @@ SliceMeshStorage::~SliceMeshStorage() bool SliceMeshStorage::getExtruderIsUsed(const size_t extruder_nr) const { - if (settings.get("anti_overhang_mesh") - || settings.get("support_mesh")) + if (settings.get("anti_overhang_mesh") || settings.get("support_mesh")) { // object is not printed as object, but as support. return false; } @@ -138,8 +135,7 @@ bool SliceMeshStorage::getExtruderIsUsed(const size_t extruder_nr) const return false; } } - if (settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL - && settings.get("wall_0_extruder_nr").extruder_nr == extruder_nr) + if (settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && settings.get("wall_0_extruder_nr").extruder_nr == extruder_nr) { return true; } @@ -147,8 +143,7 @@ bool SliceMeshStorage::getExtruderIsUsed(const size_t extruder_nr) const { return true; } - if ((settings.get("wall_line_count") > 1 || settings.get("alternate_extra_perimeter")) - && settings.get("wall_x_extruder_nr").extruder_nr == extruder_nr) + if ((settings.get("wall_line_count") > 1 || settings.get("alternate_extra_perimeter")) && settings.get("wall_x_extruder_nr").extruder_nr == extruder_nr) { return true; } @@ -174,8 +169,7 @@ bool SliceMeshStorage::getExtruderIsUsed(const size_t extruder_nr, const LayerIn { return false; } - if (settings.get("anti_overhang_mesh") - || settings.get("support_mesh")) + if (settings.get("anti_overhang_mesh") || settings.get("support_mesh")) { // object is not printed as object, but as support. return false; } @@ -184,23 +178,20 @@ bool SliceMeshStorage::getExtruderIsUsed(const size_t extruder_nr, const LayerIn { for (const SliceLayerPart& part : layer.parts) { - if ((part.hasWallAtInsetIndex(0)) || !part.spiral_wall.empty()) + if ((part.hasWallAtInsetIndex(0)) || ! part.spiral_wall.empty()) { return true; } for (const SkinPart& skin_part : part.skin_parts) { - if (!skin_part.inset_paths.empty()) + if (! skin_part.inset_paths.empty()) { return true; } } } } - if (settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL - && settings.get("wall_0_extruder_nr").extruder_nr == extruder_nr - && layer.openPolyLines.size() > 0 - ) + if (settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && settings.get("wall_0_extruder_nr").extruder_nr == extruder_nr && layer.openPolyLines.size() > 0) { return true; } @@ -230,7 +221,7 @@ bool SliceMeshStorage::getExtruderIsUsed(const size_t extruder_nr, const LayerIn { for (const SkinPart& skin_part : part.skin_parts) { - if (!skin_part.skin_fill.empty()) + if (! skin_part.skin_fill.empty()) { return true; } @@ -243,7 +234,7 @@ bool SliceMeshStorage::getExtruderIsUsed(const size_t extruder_nr, const LayerIn { for (const SkinPart& skin_part : part.skin_parts) { - if (!skin_part.roofing_fill.empty()) + if (! skin_part.roofing_fill.empty()) { return true; } @@ -255,7 +246,7 @@ bool SliceMeshStorage::getExtruderIsUsed(const size_t extruder_nr, const LayerIn bool SliceMeshStorage::isPrinted() const { - return !settings.get("infill_mesh") && !settings.get("cutting_mesh") && !settings.get("anti_overhang_mesh"); + return ! settings.get("infill_mesh") && ! settings.get("cutting_mesh") && ! settings.get("anti_overhang_mesh"); } Point SliceMeshStorage::getZSeamHint() const @@ -284,11 +275,11 @@ std::vector SliceDataStorage::initializeWipeConfigs() } SliceDataStorage::SliceDataStorage() -: print_layer_count(0) -, wipe_config_per_extruder(initializeWipeConfigs()) -, retraction_config_per_extruder(initializeRetractionConfigs()) -, extruder_switch_retraction_config_per_extruder(initializeRetractionConfigs()) -, max_print_height_second_to_last_extruder(-1) + : print_layer_count(0) + , wipe_config_per_extruder(initializeWipeConfigs()) + , retraction_config_per_extruder(initializeRetractionConfigs()) + , extruder_switch_retraction_config_per_extruder(initializeRetractionConfigs()) + , max_print_height_second_to_last_extruder(-1) { const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; Point3 machine_max(mesh_group_settings.get("machine_width"), mesh_group_settings.get("machine_depth"), mesh_group_settings.get("machine_height")); @@ -314,23 +305,23 @@ Polygons SliceDataStorage::getLayerOutlines(const LayerIndex layer_nr, const boo { std::vector parts = raftOutline.splitIntoParts(); Polygons result; - for (PolygonsPart& part : parts) + for (PolygonsPart& part : parts) { result.add(part.outerPolygon()); } return result; } - else + else { return raftOutline; } } - else + else { return Polygons(); } } - else + else { Polygons total; if (layer_nr >= 0) @@ -359,7 +350,7 @@ Polygons SliceDataStorage::getLayerOutlines(const LayerIndex layer_nr, const boo if (include_support) { const SupportLayer& support_layer = support.supportLayers[std::max(LayerIndex(0), layer_nr)]; - if (support.generated) + if (support.generated) { for (const SupportInfillPart& support_infill_part : support_layer.support_infill_parts) { @@ -387,26 +378,26 @@ std::vector SliceDataStorage::getExtrudersUsed() const const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; const EPlatformAdhesion adhesion_type = mesh_group_settings.get("adhesion_type"); - if(adhesion_type == EPlatformAdhesion::SKIRT || adhesion_type == EPlatformAdhesion::BRIM) + if (adhesion_type == EPlatformAdhesion::SKIRT || adhesion_type == EPlatformAdhesion::BRIM) { - for(size_t extruder_nr = 0; extruder_nr < Application::getInstance().current_slice->scene.extruders.size(); extruder_nr++) + for (size_t extruder_nr = 0; extruder_nr < Application::getInstance().current_slice->scene.extruders.size(); extruder_nr++) { - if(!skirt_brim[extruder_nr].empty()) + if (! skirt_brim[extruder_nr].empty()) { ret[extruder_nr] = true; } } } - else if(adhesion_type == EPlatformAdhesion::RAFT) + else if (adhesion_type == EPlatformAdhesion::RAFT) { ret[mesh_group_settings.get("raft_base_extruder_nr").extruder_nr] = true; const size_t num_interface_layers = mesh_group_settings.get("raft_interface_extruder_nr").settings.get("raft_interface_layers"); - if(num_interface_layers > 0) + if (num_interface_layers > 0) { ret[mesh_group_settings.get("raft_interface_extruder_nr").extruder_nr] = true; } const size_t num_surface_layers = mesh_group_settings.get("raft_surface_extruder_nr").settings.get("raft_surface_layers"); - if(num_surface_layers > 0) + if (num_surface_layers > 0) { ret[mesh_group_settings.get("raft_surface_extruder_nr").extruder_nr] = true; } @@ -463,44 +454,44 @@ std::vector SliceDataStorage::getExtrudersUsed(const LayerIndex layer_nr) include_helper_parts = false; } } - else if(layer_nr > 0 || adhesion_type == EPlatformAdhesion::RAFT) + else if (layer_nr > 0 || adhesion_type == EPlatformAdhesion::RAFT) { // only include adhesion only for layers where platform adhesion actually occurs // i.e. layers < 0 are for raft, layer 0 is for brim/skirt include_adhesion = false; } - if(include_adhesion) + if (include_adhesion) { - if(layer_nr == 0 && (adhesion_type == EPlatformAdhesion::SKIRT || adhesion_type == EPlatformAdhesion::BRIM)) + if (layer_nr == 0 && (adhesion_type == EPlatformAdhesion::SKIRT || adhesion_type == EPlatformAdhesion::BRIM)) { - for(size_t extruder_nr = 0; extruder_nr < extruders.size(); ++extruder_nr) + for (size_t extruder_nr = 0; extruder_nr < extruders.size(); ++extruder_nr) { - if(!skirt_brim[extruder_nr].empty()) + if (! skirt_brim[extruder_nr].empty()) { ret[extruder_nr] = true; } } } - if(adhesion_type == EPlatformAdhesion::RAFT) + if (adhesion_type == EPlatformAdhesion::RAFT) { const LayerIndex raft_layers = Raft::getTotalExtraLayers(); - if(layer_nr == -raft_layers) //Base layer. + if (layer_nr == -raft_layers) // Base layer. { ret[mesh_group_settings.get("raft_base_extruder_nr").extruder_nr] = true; - //When using a raft, all prime blobs need to be on the lowest layer (the build plate). - for(size_t extruder_nr = 0; extruder_nr < extruders.size(); ++extruder_nr) + // When using a raft, all prime blobs need to be on the lowest layer (the build plate). + for (size_t extruder_nr = 0; extruder_nr < extruders.size(); ++extruder_nr) { - if(extruders[extruder_nr].settings.get("prime_blob_enable")) + if (extruders[extruder_nr].settings.get("prime_blob_enable")) { ret[extruder_nr] = true; } } } - else if(layer_nr == -raft_layers + 1) //Interface layer. + else if (layer_nr == -raft_layers + 1) // Interface layer. { ret[mesh_group_settings.get("raft_interface_extruder_nr").extruder_nr] = true; } - else if(layer_nr < -static_cast(Raft::getFillerLayerCount())) //Any of the surface layers. + else if (layer_nr < -static_cast(Raft::getFillerLayerCount())) // Any of the surface layers. { ret[mesh_group_settings.get("raft_surface_extruder_nr").extruder_nr] = true; } @@ -514,26 +505,26 @@ std::vector SliceDataStorage::getExtrudersUsed(const LayerIndex layer_nr) // support if (layer_nr < int(support.supportLayers.size())) { - const SupportLayer& support_layer = support.supportLayers[std::max(LayerIndex(0), layer_nr)]; //Below layer 0, it's the same as layer 0 (even though it's not stored here). + const SupportLayer& support_layer = support.supportLayers[std::max(LayerIndex(0), layer_nr)]; // Below layer 0, it's the same as layer 0 (even though it's not stored here). if (layer_nr == 0) { - if (!support_layer.support_infill_parts.empty()) + if (! support_layer.support_infill_parts.empty()) { ret[mesh_group_settings.get("support_extruder_nr_layer_0").extruder_nr] = true; } } else { - if (!support_layer.support_infill_parts.empty()) + if (! support_layer.support_infill_parts.empty()) { ret[mesh_group_settings.get("support_infill_extruder_nr").extruder_nr] = true; } } - if (!support_layer.support_bottom.empty()) + if (! support_layer.support_bottom.empty()) { ret[mesh_group_settings.get("support_bottom_extruder_nr").extruder_nr] = true; } - if (!support_layer.support_roof.empty()) + if (! support_layer.support_roof.empty()) { ret[mesh_group_settings.get("support_roof_extruder_nr").extruder_nr] = true; } @@ -569,32 +560,32 @@ Polygon SliceDataStorage::getMachineBorder(bool adhesion_offset) const const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; Polygon border{}; - switch(mesh_group_settings.get("machine_shape")) + switch (mesh_group_settings.get("machine_shape")) + { + case BuildPlateShape::ELLIPTIC: { - case BuildPlateShape::ELLIPTIC: + // Construct an ellipse to approximate the build volume. + const coord_t width = machine_size.max.x - machine_size.min.x; + const coord_t depth = machine_size.max.y - machine_size.min.y; + constexpr unsigned int circle_resolution = 50; + for (unsigned int i = 0; i < circle_resolution; i++) { - //Construct an ellipse to approximate the build volume. - const coord_t width = machine_size.max.x - machine_size.min.x; - const coord_t depth = machine_size.max.y - machine_size.min.y; - constexpr unsigned int circle_resolution = 50; - for (unsigned int i = 0; i < circle_resolution; i++) - { - const double angle = M_PI * 2 * i / circle_resolution; - border.emplace_back(machine_size.getMiddle().x + std::cos(angle) * width / 2, - machine_size.getMiddle().y + std::sin(angle) * depth / 2); - } - break; + const double angle = M_PI * 2 * i / circle_resolution; + border.emplace_back(machine_size.getMiddle().x + std::cos(angle) * width / 2, machine_size.getMiddle().y + std::sin(angle) * depth / 2); } - case BuildPlateShape::RECTANGULAR: - default: - border = machine_size.flatten().toPolygon(); - break; + break; } - if (!adhesion_offset) { + case BuildPlateShape::RECTANGULAR: + default: + border = machine_size.flatten().toPolygon(); + break; + } + if (! adhesion_offset) + { return border; } - coord_t adhesion_size = 0; //Make sure there is enough room for the platform adhesion around support. + coord_t adhesion_size = 0; // Make sure there is enough room for the platform adhesion around support. const ExtruderTrain& base_train = mesh_group_settings.get("raft_base_extruder_nr"); const ExtruderTrain& interface_train = mesh_group_settings.get("raft_interface_extruder_nr"); const ExtruderTrain& surface_train = mesh_group_settings.get("raft_surface_extruder_nr"); @@ -603,7 +594,7 @@ Polygon SliceDataStorage::getMachineBorder(bool adhesion_offset) const const std::vector is_extruder_used = getExtrudersUsed(); for (size_t extruder_nr = 0; extruder_nr < Application::getInstance().current_slice->scene.extruders.size(); extruder_nr++) { - if (extruder_nr == skirt_brim_train.extruder_nr || !is_extruder_used[extruder_nr]) //Unused extruders and the primary adhesion extruder don't generate an extra skirt line. + if (extruder_nr == skirt_brim_train.extruder_nr || ! is_extruder_used[extruder_nr]) // Unused extruders and the primary adhesion extruder don't generate an extra skirt line. { continue; } @@ -612,31 +603,24 @@ Polygon SliceDataStorage::getMachineBorder(bool adhesion_offset) const } switch (mesh_group_settings.get("adhesion_type")) { - case EPlatformAdhesion::BRIM: - adhesion_size = skirt_brim_train.settings.get("skirt_brim_line_width") - * skirt_brim_train.settings.get("initial_layer_line_width_factor") - * skirt_brim_train.settings.get("brim_line_count") + extra_skirt_line_width; - break; - case EPlatformAdhesion::RAFT: - adhesion_size = std::max({ - base_train.settings.get("raft_margin"), - interface_train.settings.get("raft_margin"), - surface_train.settings.get("raft_margin") - }); - break; - case EPlatformAdhesion::SKIRT: - adhesion_size = skirt_brim_train.settings.get("skirt_gap") - + skirt_brim_train.settings.get("skirt_brim_line_width") - * skirt_brim_train.settings.get("initial_layer_line_width_factor") - * skirt_brim_train.settings.get("skirt_line_count") - + extra_skirt_line_width; - break; - case EPlatformAdhesion::NONE: - adhesion_size = 0; - break; - default: //Also use 0. - log("Unknown platform adhesion type! Please implement the width of the platform adhesion here."); - break; + case EPlatformAdhesion::BRIM: + adhesion_size = + skirt_brim_train.settings.get("skirt_brim_line_width") * skirt_brim_train.settings.get("initial_layer_line_width_factor") * skirt_brim_train.settings.get("brim_line_count") + extra_skirt_line_width; + break; + case EPlatformAdhesion::RAFT: + adhesion_size = std::max({ base_train.settings.get("raft_margin"), interface_train.settings.get("raft_margin"), surface_train.settings.get("raft_margin") }); + break; + case EPlatformAdhesion::SKIRT: + adhesion_size = skirt_brim_train.settings.get("skirt_gap") + + skirt_brim_train.settings.get("skirt_brim_line_width") * skirt_brim_train.settings.get("initial_layer_line_width_factor") * skirt_brim_train.settings.get("skirt_line_count") + + extra_skirt_line_width; + break; + case EPlatformAdhesion::NONE: + adhesion_size = 0; + break; + default: // Also use 0. + spdlog::info("Unknown platform adhesion type! Please implement the width of the platform adhesion here."); + break; } return border.offset(-adhesion_size)[0]; } @@ -645,7 +629,7 @@ Polygon SliceDataStorage::getMachineBorder(bool adhesion_offset) const void SupportLayer::excludeAreasFromSupportInfillAreas(const Polygons& exclude_polygons, const AABB& exclude_polygons_boundary_box) { // record the indexes that need to be removed and do that after - std::list to_remove_part_indices; // LIFO for removing + std::list to_remove_part_indices; // LIFO for removing unsigned int part_count_to_check = support_infill_parts.size(); // note that support_infill_parts.size() changes during the computation below for (size_t part_idx = 0; part_idx < part_count_to_check; ++part_idx) @@ -653,7 +637,7 @@ void SupportLayer::excludeAreasFromSupportInfillAreas(const Polygons& exclude_po SupportInfillPart& support_infill_part = support_infill_parts[part_idx]; // if the areas don't overlap, do nothing - if (!exclude_polygons_boundary_box.hit(support_infill_part.outline_boundary_box)) + if (! exclude_polygons_boundary_box.hit(support_infill_part.outline_boundary_box)) { continue; } @@ -688,7 +672,7 @@ void SupportLayer::excludeAreasFromSupportInfillAreas(const Polygons& exclude_po } // remove the ones that need to be removed (LIFO) - while (!to_remove_part_indices.empty()) + while (! to_remove_part_indices.empty()) { const size_t remove_idx = to_remove_part_indices.back(); to_remove_part_indices.pop_back(); diff --git a/src/slicer.cpp b/src/slicer.cpp index 372047cf1f..cc8e63df8c 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -1,20 +1,21 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher -#include #include // remove_if +#include + +#include -#include "settings/AdaptiveLayerHeights.h" #include "Application.h" #include "Slice.h" -#include "slicer.h" +#include "settings/AdaptiveLayerHeights.h" #include "settings/EnumSettings.h" #include "settings/types/LayerIndex.h" -#include "utils/gettime.h" -#include "utils/ThreadPool.h" -#include "utils/logoutput.h" +#include "slicer.h" #include "utils/Simplify.h" #include "utils/SparsePointGridInclusive.h" +#include "utils/ThreadPool.h" +#include "utils/gettime.h" namespace cura @@ -26,24 +27,23 @@ constexpr int max_stitch1 = MM2INT(10.0); //!< maximal distance stitched between void SlicerLayer::makeBasicPolygonLoops(Polygons& open_polylines) { - for(size_t start_segment_idx = 0; start_segment_idx < segments.size(); start_segment_idx++) + for (size_t start_segment_idx = 0; start_segment_idx < segments.size(); start_segment_idx++) { - if (!segments[start_segment_idx].addedToPolygon) + if (! segments[start_segment_idx].addedToPolygon) { makeBasicPolygonLoop(open_polylines, start_segment_idx); } } - //Clear the segmentList to save memory, it is no longer needed after this point. + // Clear the segmentList to save memory, it is no longer needed after this point. segments.clear(); } void SlicerLayer::makeBasicPolygonLoop(Polygons& open_polylines, const size_t start_segment_idx) { - Polygon poly; poly.add(segments[start_segment_idx].start); - for (int segment_idx = start_segment_idx; segment_idx != -1; ) + for (int segment_idx = start_segment_idx; segment_idx != -1;) { SlicerSegment& segment = segments[segment_idx]; poly.add(segment.end); @@ -104,11 +104,10 @@ int SlicerLayer::getNextSegmentIdx(const SlicerSegment& segment, const size_t st { // segment ended at vertex - const std::vector &faces_to_try = segment.endVertex->connected_faces; + const std::vector& faces_to_try = segment.endVertex->connected_faces; for (int face_to_try : faces_to_try) { - const int result_segment_idx = - tryFaceNextSegmentIdx(segment, face_to_try, start_segment_idx); + const int result_segment_idx = tryFaceNextSegmentIdx(segment, face_to_try, start_segment_idx); if (result_segment_idx == static_cast(start_segment_idx)) { return start_segment_idx; @@ -139,7 +138,7 @@ void SlicerLayer::stitch(Polygons& open_polylines) connectOpenPolylinesImpl(open_polylines, max_stitch1, max_stitch1, allow_reverse); } -const SlicerLayer::Terminus SlicerLayer::Terminus::INVALID_TERMINUS{~static_cast(0U)}; +const SlicerLayer::Terminus SlicerLayer::Terminus::INVALID_TERMINUS{ ~static_cast(0U) }; bool SlicerLayer::PossibleStitch::operator<(const PossibleStitch& other) const { @@ -154,7 +153,7 @@ bool SlicerLayer::PossibleStitch::operator<(const PossibleStitch& other) const } // better if in order instead of reversed - if (!in_order() && other.in_order()) + if (! in_order() && other.in_order()) { return true; } @@ -185,11 +184,7 @@ bool SlicerLayer::PossibleStitch::operator<(const PossibleStitch& other) const return false; } -std::priority_queue -SlicerLayer::findPossibleStitches( - const Polygons& open_polylines, - coord_t max_dist, coord_t cell_size, - bool allow_reverse) const +std::priority_queue SlicerLayer::findPossibleStitches(const Polygons& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) const { std::priority_queue stitch_queue; @@ -214,19 +209,20 @@ SlicerLayer::findPossibleStitches( }; // Used to find nearby end points within a fixed maximum radius - SparsePointGrid grid_ends(cell_size); + SparsePointGrid grid_ends(cell_size); // Used to find nearby start points within a fixed maximum radius - SparsePointGrid grid_starts(cell_size); + SparsePointGrid grid_starts(cell_size); // populate grids // Inserts the ends of all polylines into the grid (does not // insert the starts of the polylines). - for(unsigned int polyline_0_idx = 0; polyline_0_idx < open_polylines.size(); polyline_0_idx++) + for (unsigned int polyline_0_idx = 0; polyline_0_idx < open_polylines.size(); polyline_0_idx++) { ConstPolygonRef polyline_0 = open_polylines[polyline_0_idx]; - if (polyline_0.size() < 1) continue; + if (polyline_0.size() < 1) + continue; StitchGridVal grid_val; grid_val.polyline_idx = polyline_0_idx; @@ -237,11 +233,12 @@ SlicerLayer::findPossibleStitches( // Inserts the start of all polylines into the grid. if (allow_reverse) { - for(unsigned int polyline_0_idx = 0; polyline_0_idx < open_polylines.size(); polyline_0_idx++) + for (unsigned int polyline_0_idx = 0; polyline_0_idx < open_polylines.size(); polyline_0_idx++) { ConstPolygonRef polyline_0 = open_polylines[polyline_0_idx]; - if (polyline_0.size() < 1) continue; + if (polyline_0.size() < 1) + continue; StitchGridVal grid_val; grid_val.polyline_idx = polyline_0_idx; @@ -251,11 +248,12 @@ SlicerLayer::findPossibleStitches( } // search for nearby end points - for(unsigned int polyline_1_idx = 0; polyline_1_idx < open_polylines.size(); polyline_1_idx++) + for (unsigned int polyline_1_idx = 0; polyline_1_idx < open_polylines.size(); polyline_1_idx++) { ConstPolygonRef polyline_1 = open_polylines[polyline_1_idx]; - if (polyline_1.size() < 1) continue; + if (polyline_1.size() < 1) + continue; std::vector nearby_ends; @@ -271,8 +269,8 @@ SlicerLayer::findPossibleStitches( { PossibleStitch poss_stitch; poss_stitch.dist2 = dist2; - poss_stitch.terminus_0 = Terminus{nearby_end.polyline_idx, true}; - poss_stitch.terminus_1 = Terminus{polyline_1_idx, false}; + poss_stitch.terminus_0 = Terminus{ nearby_end.polyline_idx, true }; + poss_stitch.terminus_1 = Terminus{ polyline_1_idx, false }; stitch_queue.push(poss_stitch); } } @@ -297,8 +295,8 @@ SlicerLayer::findPossibleStitches( { PossibleStitch poss_stitch; poss_stitch.dist2 = dist2; - poss_stitch.terminus_0 = Terminus{nearby_end.polyline_idx, true}; - poss_stitch.terminus_1 = Terminus{polyline_1_idx, true}; + poss_stitch.terminus_0 = Terminus{ nearby_end.polyline_idx, true }; + poss_stitch.terminus_1 = Terminus{ polyline_1_idx, true }; stitch_queue.push(poss_stitch); } } @@ -306,8 +304,7 @@ SlicerLayer::findPossibleStitches( // Check for stitches that append polyline_1 onto polyline_0 // by reversing order of polyline_0. These are stitches that // use the start of polyline_0 and the start of polyline_1. - std::vector nearby_starts = - grid_starts.getNearby(polyline_1[0], max_dist); + std::vector nearby_starts = grid_starts.getNearby(polyline_1[0], max_dist); for (const auto& nearby_start : nearby_starts) { // Disallow stitching with self with same end point @@ -322,8 +319,8 @@ SlicerLayer::findPossibleStitches( { PossibleStitch poss_stitch; poss_stitch.dist2 = dist2; - poss_stitch.terminus_0 = Terminus{nearby_start.polyline_idx, false}; - poss_stitch.terminus_1 = Terminus{polyline_1_idx, false}; + poss_stitch.terminus_0 = Terminus{ nearby_start.polyline_idx, false }; + poss_stitch.terminus_1 = Terminus{ polyline_1_idx, false }; stitch_queue.push(poss_stitch); } } @@ -333,9 +330,7 @@ SlicerLayer::findPossibleStitches( return stitch_queue; } -void SlicerLayer::planPolylineStitch( - const Polygons& open_polylines, - Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const +void SlicerLayer::planPolylineStitch(const Polygons& open_polylines, Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const { size_t polyline_0_idx = terminus_0.getPolylineIdx(); size_t polyline_1_idx = terminus_1.getPolylineIdx(); @@ -350,13 +345,14 @@ void SlicerLayer::planPolylineStitch( // back of both polylines // we can reverse either one and then append onto the other // reverse the smaller polyline - if (open_polylines[polyline_0_idx].size() < - open_polylines[polyline_1_idx].size()) + if (open_polylines[polyline_0_idx].size() < open_polylines[polyline_1_idx].size()) { - std::swap(terminus_0,terminus_1); + std::swap(terminus_0, terminus_1); } reverse[1] = true; - } else { + } + else + { // back of 0, front of 1 // already in order, nothing to do } @@ -367,17 +363,16 @@ void SlicerLayer::planPolylineStitch( { // front of 0, back of 1 // in order if we swap 0 and 1 - std::swap(terminus_0,terminus_1); + std::swap(terminus_0, terminus_1); } else { // front of both polylines // we can reverse either one and then prepend to the other // reverse the smaller polyline - if (open_polylines[polyline_0_idx].size() > - open_polylines[polyline_1_idx].size()) + if (open_polylines[polyline_0_idx].size() > open_polylines[polyline_1_idx].size()) { - std::swap(terminus_0,terminus_1); + std::swap(terminus_0, terminus_1); } reverse[0] = true; } @@ -390,42 +385,37 @@ void SlicerLayer::joinPolylines(PolygonRef& polyline_0, PolygonRef& polyline_1, { // reverse polyline_0 size_t size_0 = polyline_0.size(); - for (size_t idx = 0U; idx != size_0/2; ++idx) + for (size_t idx = 0U; idx != size_0 / 2; ++idx) { - std::swap(polyline_0[idx], polyline_0[size_0-1-idx]); + std::swap(polyline_0[idx], polyline_0[size_0 - 1 - idx]); } } if (reverse[1]) { // reverse polyline_1 by adding in reverse order - for(int poly_idx = polyline_1.size() - 1; poly_idx >= 0; poly_idx--) + for (int poly_idx = polyline_1.size() - 1; poly_idx >= 0; poly_idx--) polyline_0.add(polyline_1[poly_idx]); } else { // append polyline_1 onto polyline_0 - for(Point& p : polyline_1) + for (Point& p : polyline_1) polyline_0.add(p); } polyline_1.clear(); } -SlicerLayer::TerminusTrackingMap::TerminusTrackingMap(Terminus::Index end_idx) : - m_terminus_old_to_cur_map(end_idx) +SlicerLayer::TerminusTrackingMap::TerminusTrackingMap(Terminus::Index end_idx) : m_terminus_old_to_cur_map(end_idx) { // Initialize map to everything points to itself since nothing has moved yet. for (size_t idx = 0U; idx != end_idx; ++idx) { - m_terminus_old_to_cur_map[idx] = Terminus{idx}; + m_terminus_old_to_cur_map[idx] = Terminus{ idx }; } m_terminus_cur_to_old_map = m_terminus_old_to_cur_map; } -void SlicerLayer::TerminusTrackingMap::updateMap( - size_t num_terms, - const Terminus *cur_terms, const Terminus *next_terms, - size_t num_removed_terms, - const Terminus *removed_cur_terms) +void SlicerLayer::TerminusTrackingMap::updateMap(size_t num_terms, const Terminus* cur_terms, const Terminus* next_terms, size_t num_removed_terms, const Terminus* removed_cur_terms) { // save old locations std::vector old_terms(num_terms); @@ -446,8 +436,7 @@ void SlicerLayer::TerminusTrackingMap::updateMap( // remove next locations that no longer exist for (size_t rem_idx = 0U; rem_idx != num_removed_terms; ++rem_idx) { - m_terminus_cur_to_old_map[removed_cur_terms[rem_idx].asIndex()] = - Terminus::INVALID_TERMINUS; + m_terminus_cur_to_old_map[removed_cur_terms[rem_idx].asIndex()] = Terminus::INVALID_TERMINUS; } } @@ -455,15 +444,14 @@ void SlicerLayer::connectOpenPolylinesImpl(Polygons& open_polylines, coord_t max { // below code closes smallest gaps first - std::priority_queue stitch_queue = - findPossibleStitches(open_polylines, max_dist, cell_size, allow_reverse); + std::priority_queue stitch_queue = findPossibleStitches(open_polylines, max_dist, cell_size, allow_reverse); static const Terminus INVALID_TERMINUS = Terminus::INVALID_TERMINUS; Terminus::Index terminus_end_idx = Terminus::endIndexFromPolylineEndIndex(open_polylines.size()); // Keeps track of how polyline end point locations move around TerminusTrackingMap terminus_tracking_map(terminus_end_idx); - while (!stitch_queue.empty()) + while (! stitch_queue.empty()) { // Get the next best stitch PossibleStitch next_stitch; @@ -495,8 +483,7 @@ void SlicerLayer::connectOpenPolylinesImpl(Polygons& open_polylines, coord_t max PolygonRef polyline_0 = open_polylines[best_polyline_0_idx]; polygons.add(polyline_0); polyline_0.clear(); - Terminus cur_terms[2] = {{best_polyline_0_idx, false}, - {best_polyline_0_idx, true}}; + Terminus cur_terms[2] = { { best_polyline_0_idx, false }, { best_polyline_0_idx, true } }; for (size_t idx = 0U; idx != 2U; ++idx) { terminus_tracking_map.markRemoved(cur_terms[idx]); @@ -520,37 +507,30 @@ void SlicerLayer::connectOpenPolylinesImpl(Polygons& open_polylines, coord_t max joinPolylines(polyline_0, polyline_1, reverse); // update terminus_tracking_map - Terminus cur_terms[4] = {{best_polyline_0_idx, false}, - {best_polyline_0_idx, true}, - {best_polyline_1_idx, false}, - {best_polyline_1_idx, true}}; - Terminus next_terms[4] = {{best_polyline_0_idx, false}, - INVALID_TERMINUS, - INVALID_TERMINUS, - {best_polyline_0_idx, true}}; + Terminus cur_terms[4] = { { best_polyline_0_idx, false }, { best_polyline_0_idx, true }, { best_polyline_1_idx, false }, { best_polyline_1_idx, true } }; + Terminus next_terms[4] = { { best_polyline_0_idx, false }, INVALID_TERMINUS, INVALID_TERMINUS, { best_polyline_0_idx, true } }; if (reverse[0]) { - std::swap(next_terms[0],next_terms[1]); + std::swap(next_terms[0], next_terms[1]); } if (reverse[1]) { - std::swap(next_terms[2],next_terms[3]); + std::swap(next_terms[2], next_terms[3]); } // cur_terms -> next_terms has movement map // best_polyline_1 is always removed - terminus_tracking_map.updateMap(4U, cur_terms, next_terms, - 2U, &cur_terms[2]); + terminus_tracking_map.updateMap(4U, cur_terms, next_terms, 2U, &cur_terms[2]); } } void SlicerLayer::stitch_extensive(Polygons& open_polylines) { - //For extensive stitching find 2 open polygons that are touching 2 closed polygons. - // Then find the shortest path over this polygon that can be used to connect the open polygons, - // And generate a path over this shortest bit to link up the 2 open polygons. - // (If these 2 open polygons are the same polygon, then the final result is a closed polyon) + // For extensive stitching find 2 open polygons that are touching 2 closed polygons. + // Then find the shortest path over this polygon that can be used to connect the open polygons, + // And generate a path over this shortest bit to link up the 2 open polygons. + // (If these 2 open polygons are the same polygon, then the final result is a closed polyon) - while(1) + while (1) { unsigned int best_polyline_1_idx = -1; unsigned int best_polyline_2_idx = -1; @@ -560,10 +540,11 @@ void SlicerLayer::stitch_extensive(Polygons& open_polylines) best_result.pointIdxA = -1; best_result.pointIdxB = -1; - for(unsigned int polyline_1_idx = 0; polyline_1_idx < open_polylines.size(); polyline_1_idx++) + for (unsigned int polyline_1_idx = 0; polyline_1_idx < open_polylines.size(); polyline_1_idx++) { PolygonRef polyline_1 = open_polylines[polyline_1_idx]; - if (polyline_1.size() < 1) continue; + if (polyline_1.size() < 1) + continue; { GapCloserResult res = findPolygonGapCloser(polyline_1[0], polyline_1.back()); @@ -575,10 +556,11 @@ void SlicerLayer::stitch_extensive(Polygons& open_polylines) } } - for(unsigned int polyline_2_idx = 0; polyline_2_idx < open_polylines.size(); polyline_2_idx++) + for (unsigned int polyline_2_idx = 0; polyline_2_idx < open_polylines.size(); polyline_2_idx++) { PolygonRef polyline_2 = open_polylines[polyline_2_idx]; - if (polyline_2.size() < 1 || polyline_1_idx == polyline_2_idx) continue; + if (polyline_2.size() < 1 || polyline_1_idx == polyline_2_idx) + continue; GapCloserResult res = findPolygonGapCloser(polyline_1[0], polyline_2.back()); if (res.len > 0 && res.len < best_result.len) @@ -602,9 +584,9 @@ void SlicerLayer::stitch_extensive(Polygons& open_polylines) else if (best_result.AtoB) { PolygonRef poly = polygons.newPoly(); - for(unsigned int j = best_result.pointIdxA; j != best_result.pointIdxB; j = (j + 1) % polygons[best_result.polygonIdx].size()) + for (unsigned int j = best_result.pointIdxA; j != best_result.pointIdxB; j = (j + 1) % polygons[best_result.polygonIdx].size()) poly.add(polygons[best_result.polygonIdx][j]); - for(unsigned int j = open_polylines[best_polyline_1_idx].size() - 1; int(j) >= 0; j--) + for (unsigned int j = open_polylines[best_polyline_1_idx].size() - 1; int(j) >= 0; j--) poly.add(open_polylines[best_polyline_1_idx][j]); open_polylines[best_polyline_1_idx].clear(); } @@ -612,7 +594,7 @@ void SlicerLayer::stitch_extensive(Polygons& open_polylines) { unsigned int n = polygons.size(); polygons.add(open_polylines[best_polyline_1_idx]); - for(unsigned int j = best_result.pointIdxB; j != best_result.pointIdxA; j = (j + 1) % polygons[best_result.polygonIdx].size()) + for (unsigned int j = best_result.pointIdxB; j != best_result.pointIdxA; j = (j + 1) % polygons[best_result.polygonIdx].size()) polygons[n].add(polygons[best_result.polygonIdx][j]); open_polylines[best_polyline_1_idx].clear(); } @@ -621,26 +603,26 @@ void SlicerLayer::stitch_extensive(Polygons& open_polylines) { if (best_result.pointIdxA == best_result.pointIdxB) { - for(unsigned int n=0; n= 0; n--) + for (unsigned int n = poly.size() - 1; int(n) >= 0; n--) open_polylines[best_polyline_2_idx].add(poly[n]); - for(unsigned int n=0; n= 0; n--) + for (unsigned int n = open_polylines[best_polyline_1_idx].size() - 1; int(n) >= 0; n--) open_polylines[best_polyline_2_idx].add(open_polylines[best_polyline_1_idx][n]); open_polylines[best_polyline_1_idx].clear(); } @@ -670,13 +652,15 @@ GapCloserResult SlicerLayer::findPolygonGapCloser(Point ip0, Point ip1) if (ret.pointIdxA == ret.pointIdxB) { - //Connection points are on the same line segment. + // Connection points are on the same line segment. ret.len = vSize(ip0 - ip1); - }else{ - //Find out if we have should go from A to B or the other way around. + } + else + { + // Find out if we have should go from A to B or the other way around. Point p0 = polygons[ret.polygonIdx][ret.pointIdxA]; int64_t lenA = vSize(p0 - ip0); - for(unsigned int i = ret.pointIdxA; i != ret.pointIdxB; i = (i + 1) % polygons[ret.polygonIdx].size()) + for (unsigned int i = ret.pointIdxA; i != ret.pointIdxB; i = (i + 1) % polygons[ret.polygonIdx].size()) { Point p1 = polygons[ret.polygonIdx][i]; lenA += vSize(p0 - p1); @@ -686,7 +670,7 @@ GapCloserResult SlicerLayer::findPolygonGapCloser(Point ip0, Point ip1) p0 = polygons[ret.polygonIdx][ret.pointIdxB]; int64_t lenB = vSize(p0 - ip1); - for(unsigned int i = ret.pointIdxB; i != ret.pointIdxA; i = (i + 1) % polygons[ret.polygonIdx].size()) + for (unsigned int i = ret.pointIdxB; i != ret.pointIdxA; i = (i + 1) % polygons[ret.polygonIdx].size()) { Point p1 = polygons[ret.polygonIdx][i]; lenB += vSize(p0 - p1); @@ -698,7 +682,9 @@ GapCloserResult SlicerLayer::findPolygonGapCloser(Point ip0, Point ip1) { ret.AtoB = true; ret.len = lenA; - }else{ + } + else + { ret.AtoB = false; ret.len = lenB; } @@ -709,14 +695,14 @@ GapCloserResult SlicerLayer::findPolygonGapCloser(Point ip0, Point ip1) ClosePolygonResult SlicerLayer::findPolygonPointClosestTo(Point input) { ClosePolygonResult ret; - for(unsigned int n=0; n 1) @@ -777,12 +763,12 @@ void SlicerLayer::makePolygons(const Mesh* mesh) } } - //Remove all the tiny polygons, or polygons that are not closed. As they do not contribute to the actual print. + // Remove all the tiny polygons, or polygons that are not closed. As they do not contribute to the actual print. const coord_t snap_distance = std::max(mesh->settings.get("minimum_polygon_circumference"), static_cast(1)); auto it = std::remove_if(polygons.begin(), polygons.end(), [snap_distance](PolygonRef poly) { return poly.shorterThan(snap_distance); }); polygons.erase(it, polygons.end()); - //Finally optimize all the polygons. Every point removed saves time in the long run. + // Finally optimize all the polygons. Every point removed saves time in the long run. polygons = Simplify(mesh->settings).polygon(polygons); polygons.removeDegenerateVerts(); // remove verts connected to overlapping line segments @@ -794,172 +780,161 @@ void SlicerLayer::makePolygons(const Mesh* mesh) openPolylines.removeDegenerateVertsPolyline(); } -Slicer::Slicer(Mesh* i_mesh, const coord_t thickness, const size_t slice_layer_count, - bool use_variable_layer_heights, std::vector* adaptive_layers) - : mesh(i_mesh) +Slicer::Slicer(Mesh* i_mesh, const coord_t thickness, const size_t slice_layer_count, bool use_variable_layer_heights, std::vector* adaptive_layers) : mesh(i_mesh) { const SlicingTolerance slicing_tolerance = mesh->settings.get("slicing_tolerance"); - const coord_t initial_layer_thickness = - Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height_0"); + const coord_t initial_layer_thickness = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height_0"); assert(slice_layer_count > 0); TimeKeeper slice_timer; - layers = - buildLayersWithHeight(slice_layer_count, slicing_tolerance, initial_layer_thickness, thickness, - use_variable_layer_heights, adaptive_layers); + layers = buildLayersWithHeight(slice_layer_count, slicing_tolerance, initial_layer_thickness, thickness, use_variable_layer_heights, adaptive_layers); std::vector> zbbox = buildZHeightsForFaces(*mesh); buildSegments(*mesh, zbbox, slicing_tolerance, layers); - log("slice of mesh took %.3f seconds\n", slice_timer.restart()); + spdlog::info("slice of mesh took {:3} seconds", slice_timer.restart()); makePolygons(*i_mesh, slicing_tolerance, layers); - log("slice make polygons took %.3f seconds\n", slice_timer.restart()); + spdlog::info("slice make polygons took {:3} seconds", slice_timer.restart()); } -void Slicer::buildSegments -( - const Mesh& mesh, - const std::vector> &zbbox, - const SlicingTolerance& slicing_tolerance, - std::vector& layers -) +void Slicer::buildSegments(const Mesh& mesh, const std::vector>& zbbox, const SlicingTolerance& slicing_tolerance, std::vector& layers) { - cura::parallel_for(layers, [&](auto layer_it) - { - SlicerLayer& layer = *layer_it; - const int32_t& z = layer.z; - layer.segments.reserve(100); - - // loop over all mesh faces - for (unsigned int mesh_idx = 0; mesh_idx < mesh.faces.size(); mesh_idx++) - { - if ((z < zbbox[mesh_idx].first) || (z > zbbox[mesh_idx].second)) - { - continue; - } - - // get all vertices per face - const MeshFace& face = mesh.faces[mesh_idx]; - const MeshVertex& v0 = mesh.vertices[face.vertex_index[0]]; - const MeshVertex& v1 = mesh.vertices[face.vertex_index[1]]; - const MeshVertex& v2 = mesh.vertices[face.vertex_index[2]]; - - // get all vertices represented as 3D point - Point3 p0 = v0.p; - Point3 p1 = v1.p; - Point3 p2 = v2.p; - - // Compensate for points exactly on the slice-boundary, except for 'inclusive', which already handles this correctly. - if (slicing_tolerance != SlicingTolerance::INCLUSIVE) - { - p0.z += static_cast(p0.z == z); - p1.z += static_cast(p1.z == z); - p2.z += static_cast(p2.z == z); - } - - SlicerSegment s; - s.endVertex = nullptr; - int end_edge_idx = -1; - - /* - Now see if the triangle intersects the layer, and if so, where. - - Edge cases are important here: - - If all three vertices of the triangle are exactly on the layer, - don't count the triangle at all, because if the model is - watertight, there will be adjacent triangles on all 3 sides that - are not flat on the layer. - - If two of the vertices are exactly on the layer, only count the - triangle if the last vertex is going up. We can't count both - upwards and downwards triangles here, because if the model is - manifold there will always be an adjacent triangle that is going - the other way and you'd get double edges. You would also get one - layer too many if the total model height is an exact multiple of - the layer thickness. Between going up and going down, we need to - choose the triangles going up, because otherwise the first layer - of where the model starts will be empty and the model will float - in mid-air. We'd much rather let the last layer be empty in that - case. - - If only one of the vertices is exactly on the layer, the - intersection between the triangle and the plane would be a point. - We can't print points and with a manifold model there would be - line segments adjacent to the point on both sides anyway, so we - need to discard this 0-length line segment then. - - Vertices in ccw order if look from outside. - */ - - if (p0.z < z && p1.z > z && p2.z > z) // 1_______2 - { // \ / - s = project2D(p0, p2, p1, z); //------------- z - end_edge_idx = 0; // \ / - } // 0 - - else if (p0.z > z && p1.z <= z && p2.z <= z) // 0 - { // / \ . - s = project2D(p0, p1, p2, z); //------------- z - end_edge_idx = 2; // / \ . - if (p2.z == z) // 1_______2 - { - s.endVertex = &v2; - } - } - - else if (p1.z < z && p0.z > z && p2.z > z) // 0_______2 - { // \ / - s = project2D(p1, p0, p2, z); //------------- z - end_edge_idx = 1; // \ / - } // 1 - - else if (p1.z > z && p0.z <= z && p2.z <= z) // 1 - { // / \ . - s = project2D(p1, p2, p0, z); //------------- z - end_edge_idx = 0; // / \ . - if (p0.z == z) // 0_______2 - { - s.endVertex = &v0; - } - } - - else if (p2.z < z && p1.z > z && p0.z > z) // 0_______1 - { // \ / - s = project2D(p2, p1, p0, z); //------------- z - end_edge_idx = 2; // \ / - } // 2 - - else if (p2.z > z && p1.z <= z && p0.z <= z) // 2 - { // / \ . - s = project2D(p2, p0, p1, z); //------------- z - end_edge_idx = 1; // / \ . - if (p1.z == z) // 0_______1 - { - s.endVertex = &v1; - } - } - else - { - //Not all cases create a segment, because a point of a face could create just a dot, and two touching faces - // on the slice would create two segments - continue; - } - - // store the segments per layer - layer.face_idx_to_segment_idx.insert(std::make_pair(mesh_idx, layer.segments.size())); - s.faceIndex = mesh_idx; - s.endOtherFaceIdx = face.connected_face_index[end_edge_idx]; - s.addedToPolygon = false; - layer.segments.push_back(s); - } - }); + cura::parallel_for(layers, + [&](auto layer_it) + { + SlicerLayer& layer = *layer_it; + const int32_t& z = layer.z; + layer.segments.reserve(100); + + // loop over all mesh faces + for (unsigned int mesh_idx = 0; mesh_idx < mesh.faces.size(); mesh_idx++) + { + if ((z < zbbox[mesh_idx].first) || (z > zbbox[mesh_idx].second)) + { + continue; + } + + // get all vertices per face + const MeshFace& face = mesh.faces[mesh_idx]; + const MeshVertex& v0 = mesh.vertices[face.vertex_index[0]]; + const MeshVertex& v1 = mesh.vertices[face.vertex_index[1]]; + const MeshVertex& v2 = mesh.vertices[face.vertex_index[2]]; + + // get all vertices represented as 3D point + Point3 p0 = v0.p; + Point3 p1 = v1.p; + Point3 p2 = v2.p; + + // Compensate for points exactly on the slice-boundary, except for 'inclusive', which already handles this correctly. + if (slicing_tolerance != SlicingTolerance::INCLUSIVE) + { + p0.z += static_cast(p0.z == z); + p1.z += static_cast(p1.z == z); + p2.z += static_cast(p2.z == z); + } + + SlicerSegment s; + s.endVertex = nullptr; + int end_edge_idx = -1; + + /* + Now see if the triangle intersects the layer, and if so, where. + + Edge cases are important here: + - If all three vertices of the triangle are exactly on the layer, + don't count the triangle at all, because if the model is + watertight, there will be adjacent triangles on all 3 sides that + are not flat on the layer. + - If two of the vertices are exactly on the layer, only count the + triangle if the last vertex is going up. We can't count both + upwards and downwards triangles here, because if the model is + manifold there will always be an adjacent triangle that is going + the other way and you'd get double edges. You would also get one + layer too many if the total model height is an exact multiple of + the layer thickness. Between going up and going down, we need to + choose the triangles going up, because otherwise the first layer + of where the model starts will be empty and the model will float + in mid-air. We'd much rather let the last layer be empty in that + case. + - If only one of the vertices is exactly on the layer, the + intersection between the triangle and the plane would be a point. + We can't print points and with a manifold model there would be + line segments adjacent to the point on both sides anyway, so we + need to discard this 0-length line segment then. + - Vertices in ccw order if look from outside. + */ + + if (p0.z < z && p1.z > z && p2.z > z) // 1_______2 + { // \ / + s = project2D(p0, p2, p1, z); //------------- z + end_edge_idx = 0; // \ / + } // 0 + + else if (p0.z > z && p1.z <= z && p2.z <= z) // 0 + { // / \ . + s = project2D(p0, p1, p2, z); //------------- z + end_edge_idx = 2; // / \ . + if (p2.z == z) // 1_______2 + { + s.endVertex = &v2; + } + } + + else if (p1.z < z && p0.z > z && p2.z > z) // 0_______2 + { // \ / + s = project2D(p1, p0, p2, z); //------------- z + end_edge_idx = 1; // \ / + } // 1 + + else if (p1.z > z && p0.z <= z && p2.z <= z) // 1 + { // / \ . + s = project2D(p1, p2, p0, z); //------------- z + end_edge_idx = 0; // / \ . + if (p0.z == z) // 0_______2 + { + s.endVertex = &v0; + } + } + + else if (p2.z < z && p1.z > z && p0.z > z) // 0_______1 + { // \ / + s = project2D(p2, p1, p0, z); //------------- z + end_edge_idx = 2; // \ / + } // 2 + + else if (p2.z > z && p1.z <= z && p0.z <= z) // 2 + { // / \ . + s = project2D(p2, p0, p1, z); //------------- z + end_edge_idx = 1; // / \ . + if (p1.z == z) // 0_______1 + { + s.endVertex = &v1; + } + } + else + { + // Not all cases create a segment, because a point of a face could create just a dot, and two touching faces + // on the slice would create two segments + continue; + } + + // store the segments per layer + layer.face_idx_to_segment_idx.insert(std::make_pair(mesh_idx, layer.segments.size())); + s.faceIndex = mesh_idx; + s.endOtherFaceIdx = face.connected_face_index[end_edge_idx]; + s.addedToPolygon = false; + layer.segments.push_back(s); + } + }); } -std::vector Slicer::buildLayersWithHeight(size_t slice_layer_count, SlicingTolerance slicing_tolerance, - coord_t initial_layer_thickness, coord_t thickness, bool use_variable_layer_heights, - const std::vector* adaptive_layers) +std::vector + Slicer::buildLayersWithHeight(size_t slice_layer_count, SlicingTolerance slicing_tolerance, coord_t initial_layer_thickness, coord_t thickness, bool use_variable_layer_heights, const std::vector* adaptive_layers) { std::vector layers_res; @@ -996,12 +971,9 @@ std::vector Slicer::buildLayersWithHeight(size_t slice_layer_count, void Slicer::makePolygons(Mesh& mesh, SlicingTolerance slicing_tolerance, std::vector& layers) { - cura::parallel_for(layers, [&mesh](auto layer_it) - { - layer_it->makePolygons(&mesh); - }); + cura::parallel_for(layers, [&mesh](auto layer_it) { layer_it->makePolygons(&mesh); }); - switch(slicing_tolerance) + switch (slicing_tolerance) { case SlicingTolerance::INCLUSIVE: for (unsigned int layer_nr = 0; layer_nr + 1 < layers.size(); layer_nr++) @@ -1022,12 +994,9 @@ void Slicer::makePolygons(Mesh& mesh, SlicingTolerance slicing_tolerance, std::v ; } - size_t layer_apply_initial_xy_offset = 0; - if (layers.size() > 0 && layers[0].polygons.size() == 0 - && !mesh.settings.get("support_mesh") - && !mesh.settings.get("anti_overhang_mesh") - && !mesh.settings.get("cutting_mesh") - && !mesh.settings.get("infill_mesh")) + size_t layer_apply_initial_xy_offset = 0; + if (layers.size() > 0 && layers[0].polygons.size() == 0 && ! mesh.settings.get("support_mesh") && ! mesh.settings.get("anti_overhang_mesh") && ! mesh.settings.get("cutting_mesh") + && ! mesh.settings.get("infill_mesh")) { layer_apply_initial_xy_offset = 1; } @@ -1036,14 +1005,16 @@ void Slicer::makePolygons(Mesh& mesh, SlicingTolerance slicing_tolerance, std::v const coord_t xy_offset = mesh.settings.get("xy_offset"); const coord_t xy_offset_0 = mesh.settings.get("xy_offset_layer_0"); - cura::parallel_for(0, layers.size(), [&layers, layer_apply_initial_xy_offset, xy_offset, xy_offset_0](size_t layer_nr) - { - const coord_t xy_offset_local = (layer_nr <= layer_apply_initial_xy_offset) ? xy_offset_0 : xy_offset; - if (xy_offset_local != 0) - { - layers[layer_nr].polygons = layers[layer_nr].polygons.offset(xy_offset_local, ClipperLib::JoinType::jtRound); - } - }); + cura::parallel_for(0, + layers.size(), + [&layers, layer_apply_initial_xy_offset, xy_offset, xy_offset_0](size_t layer_nr) + { + const coord_t xy_offset_local = (layer_nr <= layer_apply_initial_xy_offset) ? xy_offset_0 : xy_offset; + if (xy_offset_local != 0) + { + layers[layer_nr].polygons = layers[layer_nr].polygons.offset(xy_offset_local, ClipperLib::JoinType::jtRound); + } + }); mesh.expandXY(xy_offset); } @@ -1053,9 +1024,9 @@ std::vector> Slicer::buildZHeightsForFaces(const Mes { std::vector> zHeights; zHeights.reserve(mesh.faces.size()); - for(const auto& face : mesh.faces) + for (const auto& face : mesh.faces) { - //const MeshFace& face = mesh.faces[mesh_idx]; + // const MeshFace& face = mesh.faces[mesh_idx]; const MeshVertex& v0 = mesh.vertices[face.vertex_index[0]]; const MeshVertex& v1 = mesh.vertices[face.vertex_index[1]]; const MeshVertex& v2 = mesh.vertices[face.vertex_index[2]]; @@ -1098,8 +1069,8 @@ SlicerSegment Slicer::project2D(const Point3& p0, const Point3& p1, const Point3 seg.start.X = interpolate(z, p0.z, p1.z, p0.x, p1.x); seg.start.Y = interpolate(z, p0.z, p1.z, p0.y, p1.y); - seg.end .X = interpolate(z, p0.z, p2.z, p0.x, p2.x); - seg.end .Y = interpolate(z, p0.z, p2.z, p0.y, p2.y); + seg.end.X = interpolate(z, p0.z, p2.z, p0.x, p2.x); + seg.end.Y = interpolate(z, p0.z, p2.z, p0.y, p2.y); return seg; } @@ -1113,4 +1084,4 @@ coord_t Slicer::interpolate(const coord_t x, const coord_t x0, const coord_t x1, } -}//namespace cura +} // namespace cura diff --git a/src/support.cpp b/src/support.cpp index a6f407c86a..9d5841cff3 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -1,17 +1,16 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include // sqrt, round -#include // pair #include #include // ifstream.good() +#include // pair + +#include #include "Application.h" //To get settings. #include "ExtruderTrain.h" #include "Slice.h" -#include "slicer.h" -#include "sliceDataStorage.h" -#include "support.h" #include "infill.h" #include "infill/ImageBasedDensityProvider.h" #include "infill/SierpinskiFillProvider.h" @@ -20,8 +19,10 @@ #include "settings/EnumSettings.h" //For EFillMethod. #include "settings/types/Angle.h" //To compute overhang distance from the angle. #include "settings/types/Ratio.h" +#include "sliceDataStorage.h" +#include "slicer.h" +#include "support.h" #include "utils/ThreadPool.h" -#include "utils/logoutput.h" #include "utils/math.h" namespace cura @@ -29,11 +30,16 @@ namespace cura bool AreaSupport::handleSupportModifierMesh(SliceDataStorage& storage, const Settings& mesh_settings, const Slicer* slicer) { - if (!mesh_settings.get("anti_overhang_mesh") && !mesh_settings.get("support_mesh")) + if (! mesh_settings.get("anti_overhang_mesh") && ! mesh_settings.get("support_mesh")) { return false; } - enum ModifierType { ANTI_OVERHANG, SUPPORT_DROP_DOWN, SUPPORT_VANILLA }; + enum ModifierType + { + ANTI_OVERHANG, + SUPPORT_DROP_DOWN, + SUPPORT_VANILLA + }; ModifierType modifier_type = (mesh_settings.get("anti_overhang_mesh")) ? ANTI_OVERHANG : ((mesh_settings.get("support_mesh_drop_down")) ? SUPPORT_DROP_DOWN : SUPPORT_VANILLA); for (unsigned int layer_nr = 0; layer_nr < slicer->layers.size(); layer_nr++) { @@ -175,7 +181,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) // no early-out for this function; it needs to initialize the [infill_area_per_combine_per_density] float layer_skip_count = 8; // skip every so many layers as to ignore small gaps in the model making computation more easy - size_t gradual_support_step_layer_count = round_divide(gradual_support_step_height, mesh_group_settings.get("layer_height")); //The difference in layer count between consecutive density infill areas. + size_t gradual_support_step_layer_count = round_divide(gradual_support_step_height, mesh_group_settings.get("layer_height")); // The difference in layer count between consecutive density infill areas. // make gradual_support_step_height divisable by layer_skip_count const float n_skip_steps_per_gradual_step = std::max(1.0f, std::ceil(gradual_support_step_layer_count / layer_skip_count)); // only decrease layer_skip_count to make it a divisor of gradual_support_step_layer_count @@ -304,12 +310,12 @@ void AreaSupport::combineSupportInfillLayers(SliceDataStorage& storage) layers and some at non-divisible layers. Those layers would then miss each other. */ size_t min_layer = combine_layers_amount - 1; - min_layer -= min_layer % combine_layers_amount; // Round upwards to the nearest layer divisible by infill_sparse_combine. + min_layer -= min_layer % combine_layers_amount; // Round upwards to the nearest layer divisible by infill_sparse_combine. size_t max_layer = total_layer_count < storage.support.supportLayers.size() ? total_layer_count : storage.support.supportLayers.size(); max_layer = max_layer - 1; - max_layer -= max_layer % combine_layers_amount; // Round downwards to the nearest layer divisible by infill_sparse_combine. + max_layer -= max_layer % combine_layers_amount; // Round downwards to the nearest layer divisible by infill_sparse_combine. - for (size_t layer_idx = min_layer; layer_idx <= max_layer; layer_idx += combine_layers_amount) //Skip every few layers, but extrude more. + for (size_t layer_idx = min_layer; layer_idx <= max_layer; layer_idx += combine_layers_amount) // Skip every few layers, but extrude more. { if (layer_idx >= storage.support.supportLayers.size()) { @@ -343,7 +349,7 @@ void AreaSupport::combineSupportInfillLayers(SliceDataStorage& storage) Polygons result; for (SupportInfillPart& lower_layer_part : lower_layer.support_infill_parts) { - if (!part.outline_boundary_box.hit(lower_layer_part.outline_boundary_box)) + if (! part.outline_boundary_box.hit(lower_layer_part.outline_boundary_box)) { continue; } @@ -405,14 +411,13 @@ void AreaSupport::cleanup(SliceDataStorage& storage) for (const Polygons& infill_area_this_combine_this_density : infill_area_per_combine_this_density) { // remove small areas which were introduced by rounding errors in comparing the same area on two consecutive layer - if (!infill_area_this_combine_this_density.empty() - && infill_area_this_combine_this_density.area() > support_line_width * support_line_width) + if (! infill_area_this_combine_this_density.empty() && infill_area_this_combine_this_density.area() > support_line_width * support_line_width) { can_be_removed = false; break; } } - if (!can_be_removed) + if (! can_be_removed) { // break outer loop break; } @@ -448,40 +453,40 @@ Polygons AreaSupport::join(const SliceDataStorage& storage, const Polygons& supp if (conical_support) { const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; - //Don't go outside the build volume. + // Don't go outside the build volume. Polygons machine_volume_border; switch (mesh_group_settings.get("machine_shape")) { - case BuildPlateShape::ELLIPTIC: + case BuildPlateShape::ELLIPTIC: + { + // Construct an ellipse to approximate the build volume. + const coord_t width = storage.machine_size.max.x - storage.machine_size.min.x; + const coord_t depth = storage.machine_size.max.y - storage.machine_size.min.y; + Polygon border_circle; + constexpr unsigned int circle_resolution = 50; + for (unsigned int i = 0; i < circle_resolution; i++) { - //Construct an ellipse to approximate the build volume. - const coord_t width = storage.machine_size.max.x - storage.machine_size.min.x; - const coord_t depth = storage.machine_size.max.y - storage.machine_size.min.y; - Polygon border_circle; - constexpr unsigned int circle_resolution = 50; - for (unsigned int i = 0; i < circle_resolution; i++) - { - const AngleRadians angle = TAU * i / circle_resolution; - const Point3 machine_middle = storage.machine_size.getMiddle(); - const coord_t x = machine_middle.x + cos(angle) * width / 2; - const coord_t y = machine_middle.y + sin(angle) * depth / 2; - border_circle.emplace_back(x, y); - } - machine_volume_border.add(border_circle); - break; + const AngleRadians angle = TAU * i / circle_resolution; + const Point3 machine_middle = storage.machine_size.getMiddle(); + const coord_t x = machine_middle.x + cos(angle) * width / 2; + const coord_t y = machine_middle.y + sin(angle) * depth / 2; + border_circle.emplace_back(x, y); } - case BuildPlateShape::RECTANGULAR: - default: - machine_volume_border.add(storage.machine_size.flatten().toPolygon()); - break; + machine_volume_border.add(border_circle); + break; + } + case BuildPlateShape::RECTANGULAR: + default: + machine_volume_border.add(storage.machine_size.flatten().toPolygon()); + break; } - coord_t adhesion_size = 0; //Make sure there is enough room for the platform adhesion around support. + coord_t adhesion_size = 0; // Make sure there is enough room for the platform adhesion around support. const ExtruderTrain& skirt_brim_extruder = mesh_group_settings.get("skirt_brim_extruder_nr"); coord_t extra_skirt_line_width = 0; const std::vector is_extruder_used = storage.getExtrudersUsed(); for (size_t extruder_nr = 0; extruder_nr < Application::getInstance().current_slice->scene.extruders.size(); extruder_nr++) { - if (extruder_nr == skirt_brim_extruder.extruder_nr || !is_extruder_used[extruder_nr]) //Unused extruders and the primary adhesion extruder don't generate an extra skirt line. + if (extruder_nr == skirt_brim_extruder.extruder_nr || ! is_extruder_used[extruder_nr]) // Unused extruders and the primary adhesion extruder don't generate an extra skirt line. { continue; } @@ -490,41 +495,36 @@ Polygons AreaSupport::join(const SliceDataStorage& storage, const Polygons& supp } switch (mesh_group_settings.get("adhesion_type")) { - case EPlatformAdhesion::BRIM: - adhesion_size = - skirt_brim_extruder.settings.get("brim_width") - + skirt_brim_extruder.settings.get("skirt_brim_line_width") - * skirt_brim_extruder.settings.get("brim_line_count") - * skirt_brim_extruder.settings.get("initial_layer_line_width_factor") - + extra_skirt_line_width; - break; - case EPlatformAdhesion::RAFT: - { - adhesion_size = std::max({ - mesh_group_settings.get("raft_base_extruder_nr").settings.get("raft_margin"), - mesh_group_settings.get("raft_interface_extruder_nr").settings.get("raft_margin"), - mesh_group_settings.get("raft_surface_extruder_nr").settings.get("raft_margin") - }); - break; - } - case EPlatformAdhesion::SKIRT: - adhesion_size = skirt_brim_extruder.settings.get("skirt_gap") + skirt_brim_extruder.settings.get("skirt_brim_line_width") * skirt_brim_extruder.settings.get("initial_layer_line_width_factor") * skirt_brim_extruder.settings.get("skirt_line_count") + extra_skirt_line_width; - break; - case EPlatformAdhesion::NONE: - adhesion_size = 0; - break; - default: //Also use 0. - log("Unknown platform adhesion type! Please implement the width of the platform adhesion here."); - break; + case EPlatformAdhesion::BRIM: + adhesion_size = skirt_brim_extruder.settings.get("brim_width") + + skirt_brim_extruder.settings.get("skirt_brim_line_width") * skirt_brim_extruder.settings.get("brim_line_count") * skirt_brim_extruder.settings.get("initial_layer_line_width_factor") + + extra_skirt_line_width; + break; + case EPlatformAdhesion::RAFT: + { + adhesion_size = std::max({ mesh_group_settings.get("raft_base_extruder_nr").settings.get("raft_margin"), + mesh_group_settings.get("raft_interface_extruder_nr").settings.get("raft_margin"), + mesh_group_settings.get("raft_surface_extruder_nr").settings.get("raft_margin") }); + break; + } + case EPlatformAdhesion::SKIRT: + adhesion_size = skirt_brim_extruder.settings.get("skirt_gap") + + skirt_brim_extruder.settings.get("skirt_brim_line_width") * skirt_brim_extruder.settings.get("initial_layer_line_width_factor") * skirt_brim_extruder.settings.get("skirt_line_count") + + extra_skirt_line_width; + break; + case EPlatformAdhesion::NONE: + adhesion_size = 0; + break; + default: // Also use 0. + spdlog::info("Unknown platform adhesion type! Please implement the width of the platform adhesion here."); + break; } machine_volume_border = machine_volume_border.offset(-adhesion_size); const coord_t conical_smallest_breadth = infill_settings.get("support_conical_min_width"); Polygons insetted = supportLayer_up.offset(-conical_smallest_breadth / 2); Polygons small_parts = supportLayer_up.difference(insetted.offset(conical_smallest_breadth / 2 + 20)); - joined = supportLayer_this.unionPolygons(supportLayer_up.offset(conical_support_offset)) - .unionPolygons(small_parts) - .intersection(machine_volume_border); + joined = supportLayer_this.unionPolygons(supportLayer_up.offset(conical_support_offset)).unionPolygons(small_parts).intersection(machine_volume_border); } else { @@ -534,8 +534,7 @@ Polygons AreaSupport::join(const SliceDataStorage& storage, const Polygons& supp const coord_t join_distance = infill_settings.get("support_join_distance"); if (join_distance > 0) { - joined = joined.offset(join_distance) - .offset(-join_distance); + joined = joined.offset(join_distance).offset(-join_distance); } // remove jagged line pieces introduced by unioning separate overhang areas for consectuive layers @@ -626,8 +625,7 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage) Settings* bottom_settings = &storage.meshes[mesh_idx].settings; if (mesh.settings.get("support_mesh")) { - if ((mesh.settings.get("support_mesh_drop_down") && support_meshes_drop_down_handled) || - (!mesh.settings.get("support_mesh_drop_down") && support_meshes_handled) ) + if ((mesh.settings.get("support_mesh_drop_down") && support_meshes_drop_down_handled) || (! mesh.settings.get("support_mesh_drop_down") && support_meshes_handled)) { // handle all support_mesh and support_mesh_drop_down areas only once continue; } @@ -661,7 +659,7 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage) } } - for (unsigned int layer_idx = 0; layer_idx < storage.print_layer_count ; layer_idx++) + for (unsigned int layer_idx = 0; layer_idx < storage.print_layer_count; layer_idx++) { Polygons& support_areas = global_support_areas_per_layer[layer_idx]; support_areas = support_areas.unionPolygons(); @@ -696,7 +694,7 @@ void AreaSupport::precomputeCrossInfillTree(SliceDataStorage& storage) const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; const ExtruderTrain& infill_extruder = mesh_group_settings.get("support_infill_extruder_nr"); const EFillMethod& support_pattern = infill_extruder.settings.get("support_pattern"); - if((support_pattern == EFillMethod::CROSS || support_pattern == EFillMethod::CROSS_3D) && infill_extruder.settings.get("support_line_distance") > 0) + if ((support_pattern == EFillMethod::CROSS || support_pattern == EFillMethod::CROSS_3D) && infill_extruder.settings.get("support_line_distance") > 0) { AABB3D aabb; for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++) @@ -725,13 +723,14 @@ void AreaSupport::precomputeCrossInfillTree(SliceDataStorage& storage) std::ifstream cross_fs(cross_subdisivion_spec_image_file.c_str()); if (cross_subdisivion_spec_image_file != "" && cross_fs.good()) { - storage.support.cross_fill_provider = new SierpinskiFillProvider(aabb, infill_extruder.settings.get("support_line_distance"), infill_extruder.settings.get("support_line_width"), cross_subdisivion_spec_image_file); + storage.support.cross_fill_provider = + new SierpinskiFillProvider(aabb, infill_extruder.settings.get("support_line_distance"), infill_extruder.settings.get("support_line_width"), cross_subdisivion_spec_image_file); } else { - if(cross_subdisivion_spec_image_file != "") + if (cross_subdisivion_spec_image_file != "") { - logError("Cannot find density image \'%s\'.", cross_subdisivion_spec_image_file.c_str()); + spdlog::error("Cannot find density image: {}.", cross_subdisivion_spec_image_file); } storage.support.cross_fill_provider = new SierpinskiFillProvider(aabb, infill_extruder.settings.get("support_line_distance"), infill_extruder.settings.get("support_line_width")); } @@ -740,35 +739,35 @@ void AreaSupport::precomputeCrossInfillTree(SliceDataStorage& storage) void AreaSupport::generateOverhangAreasForMesh(SliceDataStorage& storage, SliceMeshStorage& mesh) { - if (!mesh.settings.get("support_enable") && !mesh.settings.get("support_mesh")) + if (! mesh.settings.get("support_enable") && ! mesh.settings.get("support_mesh")) { return; } - //Fill the overhang areas with emptiness first, even if it's a support mesh, so that we can request the areas. + // Fill the overhang areas with emptiness first, even if it's a support mesh, so that we can request the areas. mesh.full_overhang_areas.resize(storage.print_layer_count); for (size_t layer_idx = 0; layer_idx < storage.print_layer_count; layer_idx++) { mesh.overhang_areas.emplace_back(); } - //Don't generate overhang areas for support meshes. They are dropped down automatically if desired. + // Don't generate overhang areas for support meshes. They are dropped down automatically if desired. const bool is_support_modifier = mesh.settings.get("support_mesh"); if (is_support_modifier) { return; } - //Don't generate overhang areas if the Z distance is higher than the objects we're generating support for. + // Don't generate overhang areas if the Z distance is higher than the objects we're generating support for. const coord_t layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("layer_height"); const coord_t z_distance_top = mesh.settings.get("support_top_distance"); - const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + 1; //Support must always be 1 layer below overhang. + const size_t z_distance_top_layers = round_up_divide(z_distance_top, layer_height) + 1; // Support must always be 1 layer below overhang. if (z_distance_top_layers + 1 > storage.print_layer_count) { return; } - //Generate points and lines of overhang (for corners pointing downwards, since they don't have an area to support but still need supporting). + // Generate points and lines of overhang (for corners pointing downwards, since they don't have an area to support but still need supporting). const coord_t max_supported_diameter = mesh.settings.get("support_tower_maximum_supported_diameter"); const bool use_towers = mesh.settings.get("support_use_towers") && max_supported_diameter > 0; if (use_towers) @@ -776,13 +775,15 @@ void AreaSupport::generateOverhangAreasForMesh(SliceDataStorage& storage, SliceM AreaSupport::detectOverhangPoints(storage, mesh); } - //Generate the actual areas and store them in the mesh. - cura::parallel_for(1, storage.print_layer_count, [&](const size_t layer_idx) - { - std::pair basic_and_full_overhang = computeBasicAndFullOverhang(storage, mesh, layer_idx); - mesh.overhang_areas[layer_idx] = basic_and_full_overhang.first; //Store the results. - mesh.full_overhang_areas[layer_idx] = basic_and_full_overhang.second; - }); + // Generate the actual areas and store them in the mesh. + cura::parallel_for(1, + storage.print_layer_count, + [&](const size_t layer_idx) + { + std::pair basic_and_full_overhang = computeBasicAndFullOverhang(storage, mesh, layer_idx); + mesh.overhang_areas[layer_idx] = basic_and_full_overhang.first; // Store the results. + mesh.full_overhang_areas[layer_idx] = basic_and_full_overhang.second; + }); } /* @@ -796,19 +797,25 @@ void AreaSupport::generateOverhangAreasForMesh(SliceDataStorage& storage, SliceM * * for support buildplate only: purge all support not connected to build plate */ -void AreaSupport::generateSupportAreasForMesh(SliceDataStorage& storage, const Settings& infill_settings, const Settings& roof_settings, const Settings& bottom_settings, const size_t mesh_idx, const size_t layer_count, std::vector& support_areas) +void AreaSupport::generateSupportAreasForMesh(SliceDataStorage& storage, + const Settings& infill_settings, + const Settings& roof_settings, + const Settings& bottom_settings, + const size_t mesh_idx, + const size_t layer_count, + std::vector& support_areas) { SliceMeshStorage& mesh = storage.meshes[mesh_idx]; const ESupportStructure support_structure = mesh.settings.get("support_structure"); const bool is_support_mesh_place_holder = mesh.settings.get("support_mesh"); // whether this mesh has empty SliceMeshStorage and this function is now called to only generate support for all support meshes - if ((!mesh.settings.get("support_enable") || support_structure != ESupportStructure::NORMAL) && !is_support_mesh_place_holder) + if ((! mesh.settings.get("support_enable") || support_structure != ESupportStructure::NORMAL) && ! is_support_mesh_place_holder) { return; } const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; const ESupportType support_type = mesh_group_settings.get("support_type"); - if (support_type == ESupportType::NONE && !is_support_mesh_place_holder) + if (support_type == ESupportType::NONE && ! is_support_mesh_place_holder) { return; } @@ -822,7 +829,7 @@ void AreaSupport::generateSupportAreasForMesh(SliceDataStorage& storage, const S return; } - //Compute the areas that are disallowed by the X/Y distance. + // Compute the areas that are disallowed by the X/Y distance. std::vector xy_disallowed_per_layer; xy_disallowed_per_layer.resize(layer_count); std::vector sloped_areas_per_layer; @@ -833,7 +840,7 @@ void AreaSupport::generateSupportAreasForMesh(SliceDataStorage& storage, const S const coord_t xy_distance_overhang = infill_settings.get("support_xy_distance_overhang"); const bool use_xy_distance_overhang = infill_settings.get("support_xy_overrides_z") == SupportDistPriority::Z_OVERRIDES_XY; // whether to use a different xy distance at overhangs const AngleRadians angle = ((mesh.settings.get("support_roof_enable")) ? roof_settings : infill_settings).get("support_angle"); - const double tan_angle = tan(angle) - 0.01; // the XY-component of the supportAngle + const double tan_angle = tan(angle) - 0.01; // the XY-component of the supportAngle constexpr bool no_support = false; constexpr bool no_prime_tower = false; const coord_t support_line_width = mesh_group_settings.get("support_infill_extruder_nr").settings.get("support_line_width"); @@ -841,75 +848,79 @@ void AreaSupport::generateSupportAreasForMesh(SliceDataStorage& storage, const S const coord_t sloped_area_detection_width = 10 + static_cast(layer_thickness / std::tan(sloped_areas_angle)) / 2; xy_disallowed_per_layer[0] = storage.getLayerOutlines(0, no_support, no_prime_tower).offset(xy_distance); - cura::parallel_for(1, layer_count, [&](const size_t layer_idx) - { - const Polygons outlines = storage.getLayerOutlines(layer_idx, no_support, no_prime_tower); - - // Build sloped areas. We need this for the stair-stepping later on. - // Specifically, sloped areass are used in 'moveUpFromModel' to prevent a stair step happening over an area where there isn't a slope. - // This part here only concerns the slope between two layers. This will be post-processed later on (see the other parallel loop below). - sloped_areas_per_layer[layer_idx] = - // Take the outer areas of the previous layer, where the outer areas are (mostly) just _inside_ the shape. - storage.getLayerOutlines(layer_idx - 1, no_support, no_prime_tower).tubeShape(sloped_area_detection_width, 10) - // Intersect those with the outer areas of the current layer, where the outer areas are (mostly) _outside_ the shape. - // This will detect every slope (and some/most vertical walls) between those two layers. - .intersection(outlines.tubeShape(10, sloped_area_detection_width)) - // Do an opening operation so we're not stuck with tiny patches. - // The later offset is extended with the line-width, so all patches are merged together if there's less than a line-width between them. - .offset(-10).offset(10 + sloped_area_detection_width); - // The sloped areas are now ready to be post-processed. - - if (!is_support_mesh_place_holder) - { // don't compute overhang for support meshes - if (use_xy_distance_overhang) //Z overrides XY distance. - { - // we also want to use the min XY distance when the support is resting on a sloped surface so we calculate the area of the - // layer below that protrudes beyond the current layer's area and combine it with the current layer's overhang disallowed area - - Polygons larger_area_below; // the areas in the layer below that protrude beyond the area of the current layer - if (layer_idx > 1) - { - // shrink a little so that areas that only protrude very slightly are ignored - larger_area_below = mesh.layers[layer_idx - 1].getOutlines().difference(mesh.layers[layer_idx].getOutlines()).offset(-layer_thickness / 10); - - if (larger_area_below.size()) - { - // if the layer below protrudes sufficiently such that a normal support at xy_distance could be placed there, - // we don't want to use the min XY distance in that area and so we remove the wide area from larger_area_below - - // assume that a minimal support structure would be one line spaced at xy_distance from the model (verified by experiment) - - const coord_t limit_distance = xy_distance + support_line_width; - - // area_beyond_limit is the portion of the layer below's outline that lies further away from the current layer's outline than limit_distance - Polygons area_beyond_limit = mesh.layers[layer_idx - 1].getOutlines().difference(mesh.layers[layer_idx].getOutlines().offset(limit_distance)); - - if (area_beyond_limit.size()) - { - // expand area_beyond_limit so that the inner hole fills in all the way back to the current layer's outline - // and use that to remove the regions in larger_area_below that should not use min XY because the regions are - // wide enough for a normal support to be placed there - larger_area_below = larger_area_below.difference(area_beyond_limit.offset(limit_distance + 10)); - } - } - } - - //Compute the areas that are too close to the model. - Polygons xy_overhang_disallowed = mesh.overhang_areas[layer_idx].offset(z_distance_top * tan_angle); - Polygons xy_non_overhang_disallowed = outlines.difference(mesh.overhang_areas[layer_idx].unionPolygons(larger_area_below).offset(xy_distance)).offset(xy_distance); - xy_disallowed_per_layer[layer_idx] = xy_overhang_disallowed.unionPolygons(xy_non_overhang_disallowed.unionPolygons(outlines.offset(xy_distance_overhang))); - } - } - if (is_support_mesh_place_holder || !use_xy_distance_overhang) - { - xy_disallowed_per_layer[layer_idx] = outlines.offset(xy_distance); - } - }); + cura::parallel_for(1, + layer_count, + [&](const size_t layer_idx) + { + const Polygons outlines = storage.getLayerOutlines(layer_idx, no_support, no_prime_tower); + + // Build sloped areas. We need this for the stair-stepping later on. + // Specifically, sloped areass are used in 'moveUpFromModel' to prevent a stair step happening over an area where there isn't a slope. + // This part here only concerns the slope between two layers. This will be post-processed later on (see the other parallel loop below). + sloped_areas_per_layer[layer_idx] = + // Take the outer areas of the previous layer, where the outer areas are (mostly) just _inside_ the shape. + storage.getLayerOutlines(layer_idx - 1, no_support, no_prime_tower) + .tubeShape(sloped_area_detection_width, 10) + // Intersect those with the outer areas of the current layer, where the outer areas are (mostly) _outside_ the shape. + // This will detect every slope (and some/most vertical walls) between those two layers. + .intersection(outlines.tubeShape(10, sloped_area_detection_width)) + // Do an opening operation so we're not stuck with tiny patches. + // The later offset is extended with the line-width, so all patches are merged together if there's less than a line-width between them. + .offset(-10) + .offset(10 + sloped_area_detection_width); + // The sloped areas are now ready to be post-processed. + + if (! is_support_mesh_place_holder) + { // don't compute overhang for support meshes + if (use_xy_distance_overhang) // Z overrides XY distance. + { + // we also want to use the min XY distance when the support is resting on a sloped surface so we calculate the area of the + // layer below that protrudes beyond the current layer's area and combine it with the current layer's overhang disallowed area + + Polygons larger_area_below; // the areas in the layer below that protrude beyond the area of the current layer + if (layer_idx > 1) + { + // shrink a little so that areas that only protrude very slightly are ignored + larger_area_below = mesh.layers[layer_idx - 1].getOutlines().difference(mesh.layers[layer_idx].getOutlines()).offset(-layer_thickness / 10); + + if (larger_area_below.size()) + { + // if the layer below protrudes sufficiently such that a normal support at xy_distance could be placed there, + // we don't want to use the min XY distance in that area and so we remove the wide area from larger_area_below + + // assume that a minimal support structure would be one line spaced at xy_distance from the model (verified by experiment) + + const coord_t limit_distance = xy_distance + support_line_width; + + // area_beyond_limit is the portion of the layer below's outline that lies further away from the current layer's outline than limit_distance + Polygons area_beyond_limit = mesh.layers[layer_idx - 1].getOutlines().difference(mesh.layers[layer_idx].getOutlines().offset(limit_distance)); + + if (area_beyond_limit.size()) + { + // expand area_beyond_limit so that the inner hole fills in all the way back to the current layer's outline + // and use that to remove the regions in larger_area_below that should not use min XY because the regions are + // wide enough for a normal support to be placed there + larger_area_below = larger_area_below.difference(area_beyond_limit.offset(limit_distance + 10)); + } + } + } + + // Compute the areas that are too close to the model. + Polygons xy_overhang_disallowed = mesh.overhang_areas[layer_idx].offset(z_distance_top * tan_angle); + Polygons xy_non_overhang_disallowed = outlines.difference(mesh.overhang_areas[layer_idx].unionPolygons(larger_area_below).offset(xy_distance)).offset(xy_distance); + xy_disallowed_per_layer[layer_idx] = xy_overhang_disallowed.unionPolygons(xy_non_overhang_disallowed.unionPolygons(outlines.offset(xy_distance_overhang))); + } + } + if (is_support_mesh_place_holder || ! use_xy_distance_overhang) + { + xy_disallowed_per_layer[layer_idx] = outlines.offset(xy_distance); + } + }); std::vector tower_roofs; Polygons stair_removal; // polygons to subtract from support because of stair-stepping - const bool is_support_mesh_nondrop_place_holder = is_support_mesh_place_holder && !mesh.settings.get("support_mesh_drop_down"); + const bool is_support_mesh_nondrop_place_holder = is_support_mesh_place_holder && ! mesh.settings.get("support_mesh_drop_down"); const bool is_support_mesh_drop_down_place_holder = is_support_mesh_place_holder && mesh.settings.get("support_mesh_drop_down"); const coord_t bottom_stair_step_width = std::max(static_cast(0), mesh.settings.get("support_bottom_stair_step_width")); @@ -952,27 +963,31 @@ void AreaSupport::generateSupportAreasForMesh(SliceDataStorage& storage, const S // but only in chunks of `bottom_stair_step_layer_count` steps, since, within such a chunk, // the order of execution is important. // Unless thinking about optimization & threading, you can just think of this as a single for-loop. - cura::parallel_for(1, layer_count, [&](const size_t layer_idx) - { - // Add the sloped areas together for each stair of the stair stepping. - // Start a new stair every modulo bottom_stair_step_layer_count steps. - if (layer_idx % bottom_stair_step_layer_count != 1) + cura::parallel_for( + 1, + layer_count, + [&](const size_t layer_idx) { - sloped_areas_per_layer[layer_idx] = sloped_areas_per_layer[layer_idx].unionPolygons(sloped_areas_per_layer[layer_idx - 1]); - } - }, bottom_stair_step_layer_count); + // Add the sloped areas together for each stair of the stair stepping. + // Start a new stair every modulo bottom_stair_step_layer_count steps. + if (layer_idx % bottom_stair_step_layer_count != 1) + { + sloped_areas_per_layer[layer_idx] = sloped_areas_per_layer[layer_idx].unionPolygons(sloped_areas_per_layer[layer_idx - 1]); + } + }, + bottom_stair_step_layer_count); } for (size_t layer_idx = layer_count - 1 - layer_z_distance_top; layer_idx != static_cast(-1); layer_idx--) { Polygons layer_this = mesh.full_overhang_areas[layer_idx + layer_z_distance_top]; - if (extension_offset && !is_support_mesh_place_holder) + if (extension_offset && ! is_support_mesh_place_holder) { layer_this = layer_this.offset(extension_offset); } - if (use_towers && !is_support_mesh_place_holder) + if (use_towers && ! is_support_mesh_place_holder) { // handle straight walls AreaSupport::handleWallStruts(infill_settings, layer_this); @@ -984,7 +999,7 @@ void AreaSupport::generateSupportAreasForMesh(SliceDataStorage& storage, const S { // join with support from layer up const Polygons empty; const Polygons* layer_above = (layer_idx < support_areas.size()) ? &support_areas[layer_idx + 1] : ∅ - const Polygons model_mesh_on_layer = (layer_idx > 0) && !is_support_mesh_nondrop_place_holder ? storage.getLayerOutlines(layer_idx, no_support, no_prime_tower) : empty; + const Polygons model_mesh_on_layer = (layer_idx > 0) && ! is_support_mesh_nondrop_place_holder ? storage.getLayerOutlines(layer_idx, no_support, no_prime_tower) : empty; if (is_support_mesh_nondrop_place_holder) { layer_above = ∅ @@ -1010,7 +1025,7 @@ void AreaSupport::generateSupportAreasForMesh(SliceDataStorage& storage, const S constexpr bool no_support = false; constexpr bool no_prime_tower = false; const bool has_model_below = storage.getLayerOutlines(layer_idx - tower_top_layer_count - bottom_empty_layer_count, no_support, no_prime_tower).inside(middle); - if (has_support_above && !has_model_below) + if (has_support_above && ! has_model_below) { Polygons tiny_tower_here; tiny_tower_here.add(poly); @@ -1062,7 +1077,7 @@ void AreaSupport::generateSupportAreasForMesh(SliceDataStorage& storage, const S conical_support_offset = (tan(-conical_support_angle) - 0.01) * layer_thickness; } const bool conical_support = infill_settings.get("support_conical_enabled") && conical_support_angle != 0; - for (unsigned int layer_idx = 1 ; layer_idx < storage.support.supportLayers.size() ; layer_idx++) + for (unsigned int layer_idx = 1; layer_idx < storage.support.supportLayers.size(); layer_idx++) { const Polygons& layer = support_areas[layer_idx]; @@ -1083,7 +1098,6 @@ void AreaSupport::generateSupportAreasForMesh(SliceDataStorage& storage, const S // | :.. <== : |__ // .\___ :.... // - } touching_buildplate = layer.intersection(touching_buildplate); // from bottom to top, support areas can only decrease! @@ -1092,22 +1106,22 @@ void AreaSupport::generateSupportAreasForMesh(SliceDataStorage& storage, const S } } - //Enforce top Z distance. + // Enforce top Z distance. if (layer_z_distance_top > 1) { // this is performed after the main support generation loop above, because it affects the joining of polygons // if this would be performed in the main loop then some support would not have been generated under the overhangs and consequently no support is generated for that, // meaning almost no support would be generated in some cases which definitely need support. - const int max_checking_layer_idx = std::max(0, - std::min(static_cast(storage.support.supportLayers.size()), - static_cast(layer_count - (layer_z_distance_top - 1)))); - - cura::parallel_for(0, max_checking_layer_idx, [&](const size_t layer_idx) - { - constexpr bool no_support = false; - constexpr bool no_prime_tower = false; - support_areas[layer_idx] = support_areas[layer_idx].difference(storage.getLayerOutlines(layer_idx + layer_z_distance_top - 1, no_support, no_prime_tower)); - }); + const int max_checking_layer_idx = std::max(0, std::min(static_cast(storage.support.supportLayers.size()), static_cast(layer_count - (layer_z_distance_top - 1)))); + + cura::parallel_for(0, + max_checking_layer_idx, + [&](const size_t layer_idx) + { + constexpr bool no_support = false; + constexpr bool no_prime_tower = false; + support_areas[layer_idx] = support_areas[layer_idx].difference(storage.getLayerOutlines(layer_idx + layer_z_distance_top - 1, no_support, no_prime_tower)); + }); } for (size_t layer_idx = support_areas.size() - 1; layer_idx != static_cast(std::max(-1, storage.support.layer_nr_max_filled_layer)); layer_idx--) @@ -1122,52 +1136,59 @@ void AreaSupport::generateSupportAreasForMesh(SliceDataStorage& storage, const S storage.support.generated = true; } -void AreaSupport::moveUpFromModel(const SliceDataStorage& storage, Polygons& stair_removal, Polygons& sloped_areas, Polygons& support_areas, const size_t layer_idx, const size_t bottom_empty_layer_count, const size_t bottom_stair_step_layer_count, const coord_t support_bottom_stair_step_width) +void AreaSupport::moveUpFromModel(const SliceDataStorage& storage, + Polygons& stair_removal, + Polygons& sloped_areas, + Polygons& support_areas, + const size_t layer_idx, + const size_t bottom_empty_layer_count, + const size_t bottom_stair_step_layer_count, + const coord_t support_bottom_stair_step_width) { -// The idea behind support bottom stairs: -// -// LEGEND: -// A: support resting on model -// x: stair step width -// C: to be removed from support until the next stair step = intersection between model below and A offset by x -// -// ALGORITHM RESULT -// -// ########################### ########################### . -// support support . -// ########################### ┐ ########################### . -// AAAAxxxxxxxxxxxxxx │ . -// CCCCCCCCCCCC │ ____ ############### . -// | \ : │ | \ . -// |____\ : ├> stair step height |____\ ############### . -// | \ : │ | \ . -// |______\ : │ |______\ ############### . -// | \ : │ | \ . -// |________\ : │ |________\ ############### . -// |model \: │ |model \ . -// |__________\############### ┘ |__________\############### . -// | \ | \ . -// |____________\ |____________\ . -// -// -// -// -// for more horizontal surface, the stepping is (partly) negated -// -// ############################################################################ -// support -// ############################################################################ ┐ -// AAAAAxxxxxxxxxxxxx │ -// CCCCCCCCCCCCCCCCCC########################################################## │ >>>>>>>>> result only applies stair step to first layer(s) of what woud normally be the stair step -// ^^--..__ │ -// ^^--..__####################################################### ├> stair step height -// ⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺ ^^--..__ │ -// ^^--..__####################################### │ -// ⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺ ^^--..__ │ -// ^^--..__####################### │ -// ⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺^^--..__ │ -// ^^--..__####### ┘ -// ⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺ + // The idea behind support bottom stairs: + // + // LEGEND: + // A: support resting on model + // x: stair step width + // C: to be removed from support until the next stair step = intersection between model below and A offset by x + // + // ALGORITHM RESULT + // + // ########################### ########################### . + // support support . + // ########################### ┐ ########################### . + // AAAAxxxxxxxxxxxxxx │ . + // CCCCCCCCCCCC │ ____ ############### . + // | \ : │ | \ . + // |____\ : ├> stair step height |____\ ############### . + // | \ : │ | \ . + // |______\ : │ |______\ ############### . + // | \ : │ | \ . + // |________\ : │ |________\ ############### . + // |model \: │ |model \ . + // |__________\############### ┘ |__________\############### . + // | \ | \ . + // |____________\ |____________\ . + // + // + // + // + // for more horizontal surface, the stepping is (partly) negated + // + // ############################################################################ + // support + // ############################################################################ ┐ + // AAAAAxxxxxxxxxxxxx │ + // CCCCCCCCCCCCCCCCCC########################################################## │ >>>>>>>>> result only applies stair step to first layer(s) of what woud normally be the stair step + // ^^--..__ │ + // ^^--..__####################################################### ├> stair step height + // ⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺ ^^--..__ │ + // ^^--..__####################################### │ + // ⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺ ^^--..__ │ + // ^^--..__####################### │ + // ⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺^^--..__ │ + // ^^--..__####### ┘ + // ⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺ if (layer_idx < bottom_empty_layer_count) { return; @@ -1227,13 +1248,13 @@ std::pair AreaSupport::computeBasicAndFullOverhang(const Sli Polygons supportLayer_supportee = mesh.layers[layer_idx].getOutlines(); constexpr bool no_support = false; constexpr bool no_prime_tower = false; - Polygons supportLayer_supporter = storage.getLayerOutlines(layer_idx-1, no_support, no_prime_tower); + Polygons supportLayer_supporter = storage.getLayerOutlines(layer_idx - 1, no_support, no_prime_tower); const coord_t layer_height = mesh.settings.get("layer_height"); const AngleRadians support_angle = mesh.settings.get("support_angle"); - const double tan_angle = tan(support_angle) - 0.01; //The X/Y component of the support angle. 0.01 to make 90 degrees work too. - const coord_t max_dist_from_lower_layer = tan_angle * layer_height; //Maximum horizontal distance that can be bridged. - Polygons supportLayer_supported = supportLayer_supporter.offset(max_dist_from_lower_layer); + const double tan_angle = tan(support_angle) - 0.01; // The X/Y component of the support angle. 0.01 to make 90 degrees work too. + const coord_t max_dist_from_lower_layer = tan_angle * layer_height; // Maximum horizontal distance that can be bridged. + Polygons supportLayer_supported = supportLayer_supporter.offset(max_dist_from_lower_layer); Polygons basic_overhang = supportLayer_supportee.difference(supportLayer_supported); const SupportLayer& support_layer = storage.support.supportLayers[layer_idx]; @@ -1246,12 +1267,12 @@ std::pair AreaSupport::computeBasicAndFullOverhang(const Sli basic_overhang = basic_overhang.difference(merged_polygons); } -// Polygons support_extension = basic_overhang.offset(max_dist_from_lower_layer); -// support_extension = support_extension.intersection(supportLayer_supported); -// support_extension = support_extension.intersection(supportLayer_supportee); -// -// Polygons overhang = basic_overhang.unionPolygons(support_extension); -// presumably the computation above is slower than the one below + // Polygons support_extension = basic_overhang.offset(max_dist_from_lower_layer); + // support_extension = support_extension.intersection(supportLayer_supported); + // support_extension = support_extension.intersection(supportLayer_supportee); + // + // Polygons overhang = basic_overhang.unionPolygons(support_extension); + // presumably the computation above is slower than the one below Polygons overhang_extented = basic_overhang.offset(max_dist_from_lower_layer + MM2INT(0.1)); // +0.1mm for easier joining with support from layer above Polygons full_overhang = overhang_extented.intersection(supportLayer_supportee); @@ -1262,7 +1283,7 @@ std::pair AreaSupport::computeBasicAndFullOverhang(const Sli void AreaSupport::detectOverhangPoints(const SliceDataStorage& storage, SliceMeshStorage& mesh) { const ExtruderTrain& infill_extruder = mesh.settings.get("support_infill_extruder_nr"); - const coord_t offset = - infill_extruder.settings.get("support_line_width") / 2; + const coord_t offset = -infill_extruder.settings.get("support_line_width") / 2; const coord_t max_tower_supported_diameter = mesh.settings.get("support_tower_maximum_supported_diameter"); const coord_t max_tower_supported_area = max_tower_supported_diameter * max_tower_supported_diameter; @@ -1276,13 +1297,13 @@ void AreaSupport::detectOverhangPoints(const SliceDataStorage& storage, SliceMes if (part.outline.outerPolygon().area() < max_tower_supported_area) { const SliceLayer& layer_below = mesh.layers[layer_idx - 1]; - if (!layer_below.getOutlines().intersection(part.outline).empty()) + if (! layer_below.getOutlines().intersection(part.outline).empty()) { continue; } const Polygons overhang = part.outline.offset(offset).difference(storage.support.supportLayers[layer_idx].anti_overhang); - if (!overhang.empty()) + if (! overhang.empty()) { mesh.overhang_points[layer_idx].push_back(overhang); } @@ -1292,17 +1313,9 @@ void AreaSupport::detectOverhangPoints(const SliceDataStorage& storage, SliceMes } - -void AreaSupport::handleTowers( - const Settings& settings, - Polygons& supportLayer_this, - std::vector& towerRoofs, - std::vector>& overhang_points, - LayerIndex layer_idx, - size_t layer_count -) +void AreaSupport::handleTowers(const Settings& settings, Polygons& supportLayer_this, std::vector& towerRoofs, std::vector>& overhang_points, LayerIndex layer_idx, size_t layer_count) { - LayerIndex layer_overhang_point = layer_idx + 1; //Start tower 1 layer below overhang point. + LayerIndex layer_overhang_point = layer_idx + 1; // Start tower 1 layer below overhang point. if (layer_overhang_point >= static_cast(layer_count) - 1) { return; @@ -1312,7 +1325,7 @@ void AreaSupport::handleTowers( if (overhang_points_here.size() > 0) { { // make sure we have the lowest point (make polys empty if they have small parts below) - if (layer_overhang_point < static_cast(layer_count) && !overhang_points[layer_overhang_point - 1].empty()) + if (layer_overhang_point < static_cast(layer_count) && ! overhang_points[layer_overhang_point - 1].empty()) { const coord_t max_tower_supported_diameter = settings.get("support_tower_maximum_supported_diameter"); std::vector& overhang_points_below = overhang_points[layer_overhang_point - 1]; @@ -1373,7 +1386,7 @@ void AreaSupport::handleWallStruts(const Settings& settings, Polygons& supportLa int best_length2 = -1; for (unsigned int i = 0; i < poly.size(); i++) { - int length2 = vSize2(poly[i] - poly[(i+1) % poly.size()]); + int length2 = vSize2(poly[i] - poly[(i + 1) % poly.size()]); if (length2 > best_length2) { best = i; @@ -1387,18 +1400,18 @@ void AreaSupport::handleWallStruts(const Settings& settings, Polygons& supportLa } // an estimate of the width of the area - int width = sqrt( poly.area() * poly.area() / best_length2 ); // sqrt (a^2 / l^2) instead of a / sqrt(l^2) + int width = sqrt(poly.area() * poly.area() / best_length2); // sqrt (a^2 / l^2) instead of a / sqrt(l^2) // add square tower (strut) in the middle of the wall if (width < max_tower_supported_diameter) { - Point mid = (poly[best] + poly[(best+1) % poly.size()] ) / 2; + Point mid = (poly[best] + poly[(best + 1) % poly.size()]) / 2; Polygons struts; PolygonRef strut = struts.newPoly(); - strut.add(mid + Point( tower_diameter / 2, tower_diameter / 2)); - strut.add(mid + Point(-tower_diameter / 2, tower_diameter / 2)); + strut.add(mid + Point(tower_diameter / 2, tower_diameter / 2)); + strut.add(mid + Point(-tower_diameter / 2, tower_diameter / 2)); strut.add(mid + Point(-tower_diameter / 2, -tower_diameter / 2)); - strut.add(mid + Point( tower_diameter / 2, -tower_diameter / 2)); + strut.add(mid + Point(tower_diameter / 2, -tower_diameter / 2)); supportLayer_this = supportLayer_this.unionPolygons(struts); } } @@ -1409,18 +1422,18 @@ void AreaSupport::generateSupportBottom(SliceDataStorage& storage, const SliceMe { const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; const coord_t layer_height = mesh_group_settings.get("layer_height"); - const size_t bottom_layer_count = round_divide(mesh.settings.get("support_bottom_height"), layer_height); //Number of layers in support bottom. + const size_t bottom_layer_count = round_divide(mesh.settings.get("support_bottom_height"), layer_height); // Number of layers in support bottom. if (bottom_layer_count <= 0) { return; } - const coord_t z_distance_bottom = round_up_divide(mesh.settings.get("support_bottom_distance"), layer_height); //Number of layers between support bottom and model. - const size_t skip_layer_count = std::max(uint64_t(1), round_divide(mesh.settings.get("support_interface_skip_height"), layer_height)); //Resolution of generating support bottoms above model. + const coord_t z_distance_bottom = round_up_divide(mesh.settings.get("support_bottom_distance"), layer_height); // Number of layers between support bottom and model. + const size_t skip_layer_count = std::max(uint64_t(1), round_divide(mesh.settings.get("support_interface_skip_height"), layer_height)); // Resolution of generating support bottoms above model. const coord_t bottom_line_width = mesh_group_settings.get("support_bottom_extruder_nr").settings.get("support_bottom_line_width"); const coord_t bottom_outline_offset = mesh_group_settings.get("support_bottom_extruder_nr").settings.get("support_bottom_offset"); - const size_t scan_count = std::max(size_t(1), (bottom_layer_count - 1) / skip_layer_count); //How many measurements to take to generate bottom areas. - const float z_skip = std::max(1.0f, float(bottom_layer_count - 1) / float(scan_count)); //How many layers to skip between measurements. Using float for better spread, but this is later rounded. + const size_t scan_count = std::max(size_t(1), (bottom_layer_count - 1) / skip_layer_count); // How many measurements to take to generate bottom areas. + const float z_skip = std::max(1.0f, float(bottom_layer_count - 1) / float(scan_count)); // How many layers to skip between measurements. Using float for better spread, but this is later rounded. const double minimum_bottom_area = mesh.settings.get("minimum_bottom_area"); std::vector& support_layers = storage.support.supportLayers; @@ -1442,24 +1455,24 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh { const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; const coord_t layer_height = mesh_group_settings.get("layer_height"); - const size_t roof_layer_count = round_divide(mesh.settings.get("support_roof_height"), layer_height); //Number of layers in support roof. + const size_t roof_layer_count = round_divide(mesh.settings.get("support_roof_height"), layer_height); // Number of layers in support roof. if (roof_layer_count <= 0) { return; } - const coord_t z_distance_top = round_up_divide(mesh.settings.get("support_top_distance"), layer_height); //Number of layers between support roof and model. - const size_t skip_layer_count = std::max(uint64_t(1), round_divide(mesh.settings.get("support_interface_skip_height"), layer_height)); //Resolution of generating support roof below model. + const coord_t z_distance_top = round_up_divide(mesh.settings.get("support_top_distance"), layer_height); // Number of layers between support roof and model. + const size_t skip_layer_count = std::max(uint64_t(1), round_divide(mesh.settings.get("support_interface_skip_height"), layer_height)); // Resolution of generating support roof below model. const coord_t roof_line_width = mesh_group_settings.get("support_roof_extruder_nr").settings.get("support_roof_line_width"); const coord_t roof_outline_offset = mesh_group_settings.get("support_roof_extruder_nr").settings.get("support_roof_offset"); - const size_t scan_count = std::max(size_t(1), (roof_layer_count - 1) / skip_layer_count); //How many measurements to take to generate roof areas. - const float z_skip = std::max(1.0f, float(roof_layer_count - 1) / float(scan_count)); //How many layers to skip between measurements. Using float for better spread, but this is later rounded. + const size_t scan_count = std::max(size_t(1), (roof_layer_count - 1) / skip_layer_count); // How many measurements to take to generate roof areas. + const float z_skip = std::max(1.0f, float(roof_layer_count - 1) / float(scan_count)); // How many layers to skip between measurements. Using float for better spread, but this is later rounded. const double minimum_roof_area = mesh.settings.get("minimum_roof_area"); std::vector& support_layers = storage.support.supportLayers; for (LayerIndex layer_idx = 0; layer_idx < static_cast(support_layers.size() - z_distance_top); layer_idx++) { - const LayerIndex top_layer_idx_above = std::min(static_cast(support_layers.size() - 1), layer_idx + roof_layer_count + z_distance_top); //Maximum layer of the model that generates support roof. + const LayerIndex top_layer_idx_above = std::min(static_cast(support_layers.size() - 1), layer_idx + roof_layer_count + z_distance_top); // Maximum layer of the model that generates support roof. Polygons mesh_outlines; for (float layer_idx_above = top_layer_idx_above; layer_idx_above > layer_idx + z_distance_top; layer_idx_above -= z_skip) { @@ -1475,11 +1488,11 @@ void AreaSupport::generateSupportInterfaceLayer(Polygons& support_areas, const P { Polygons model = colliding_mesh_outlines.unionPolygons(); interface_polygons = support_areas.intersection(model); - interface_polygons = interface_polygons.offset(safety_offset).intersection(support_areas); //Make sure we don't generate any models that are not printable. + interface_polygons = interface_polygons.offset(safety_offset).intersection(support_areas); // Make sure we don't generate any models that are not printable. if (outline_offset != 0) { interface_polygons = interface_polygons.offset(outline_offset); - if (outline_offset > 0) //The interface might exceed the area of the normal support. + if (outline_offset > 0) // The interface might exceed the area of the normal support. { interface_polygons = interface_polygons.intersection(support_areas); } @@ -1491,4 +1504,4 @@ void AreaSupport::generateSupportInterfaceLayer(Polygons& support_areas, const P support_areas = support_areas.difference(interface_polygons); } -}//namespace cura +} // namespace cura diff --git a/src/utils/AABB.cpp b/src/utils/AABB.cpp index e3747753f3..1d6fab5e0f 100644 --- a/src/utils/AABB.cpp +++ b/src/utils/AABB.cpp @@ -1,33 +1,29 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher -#include #include "utils/AABB.h" -#include "utils/polygon.h" //To create the AABB of a polygon. #include "utils/linearAlg2D.h" +#include "utils/polygon.h" //To create the AABB of a polygon. +#include namespace cura { -AABB::AABB() -: min(POINT_MAX, POINT_MAX), max(POINT_MIN, POINT_MIN) +AABB::AABB() : min(POINT_MAX, POINT_MAX), max(POINT_MIN, POINT_MIN) { } -AABB::AABB(const Point& min, const Point& max) -: min(min), max(max) +AABB::AABB(const Point& min, const Point& max) : min(min), max(max) { } -AABB::AABB(const Polygons& polys) -: min(POINT_MAX, POINT_MAX), max(POINT_MIN, POINT_MIN) +AABB::AABB(const Polygons& polys) : min(POINT_MAX, POINT_MAX), max(POINT_MIN, POINT_MIN) { calculate(polys); } -AABB::AABB(ConstPolygonRef poly) -: min(POINT_MAX, POINT_MAX), max(POINT_MIN, POINT_MIN) +AABB::AABB(ConstPolygonRef poly) : min(POINT_MAX, POINT_MAX), max(POINT_MIN, POINT_MIN) { calculate(poly); } @@ -41,27 +37,22 @@ coord_t AABB::distanceSquared(const Point& p) const { const Point a = Point(max.X, min.Y); const Point b = Point(min.X, max.Y); - return (contains(p) ? -1 : 1) * - std::min({ - LinearAlg2D::getDist2FromLineSegment(min, a, p), - LinearAlg2D::getDist2FromLineSegment(a, max, p), - LinearAlg2D::getDist2FromLineSegment(max, b, p), - LinearAlg2D::getDist2FromLineSegment(b, min, p) - }); + return (contains(p) ? -1 : 1) + * std::min({ LinearAlg2D::getDist2FromLineSegment(min, a, p), LinearAlg2D::getDist2FromLineSegment(a, max, p), LinearAlg2D::getDist2FromLineSegment(max, b, p), LinearAlg2D::getDist2FromLineSegment(b, min, p) }); } coord_t AABB::distanceSquared(const AABB& other) const { return std::min({ - distanceSquared(other.min), - other.distanceSquared(min), - distanceSquared(other.max), - other.distanceSquared(max), - distanceSquared(Point(other.max.X, other.min.Y)), - other.distanceSquared(Point(max.X, min.Y)), - distanceSquared(Point(other.min.X, other.max.Y)), - other.distanceSquared(Point(min.X, max.Y)), - }); + distanceSquared(other.min), + other.distanceSquared(min), + distanceSquared(other.max), + other.distanceSquared(max), + distanceSquared(Point(other.max.X, other.min.Y)), + other.distanceSquared(Point(max.X, min.Y)), + distanceSquared(Point(other.min.X, other.max.Y)), + other.distanceSquared(Point(min.X, max.Y)), + }); } void AABB::calculate(const Polygons& polys) @@ -94,32 +85,45 @@ bool AABB::contains(const Point& point) const bool AABB::contains(const AABB& other) const { - if (area() < 0) { return false; } - if (other.area() < 0) { return true; } + if (area() < 0) + { + return false; + } + if (other.area() < 0) + { + return true; + } return other.min.X >= min.X && other.max.X <= max.X && other.min.Y >= min.Y && other.max.Y <= max.Y; } coord_t AABB::area() const { - if (max.X < min.X || max.Y < min.Y) { return -1; } // Do the unititialized check explicitly, so there aren't any problems with over/underflow and POINT_MAX/POINT_MIN. + if (max.X < min.X || max.Y < min.Y) + { + return -1; + } // Do the unititialized check explicitly, so there aren't any problems with over/underflow and POINT_MAX/POINT_MIN. return (max.X - min.X) * (max.Y - min.Y); } bool AABB::hit(const AABB& other) const { - if (max.X < other.min.X) return false; - if (min.X > other.max.X) return false; - if (max.Y < other.min.Y) return false; - if (min.Y > other.max.Y) return false; + if (max.X < other.min.X) + return false; + if (min.X > other.max.X) + return false; + if (max.Y < other.min.Y) + return false; + if (min.Y > other.max.Y) + return false; return true; } void AABB::include(Point point) { - min.X = std::min(min.X,point.X); - min.Y = std::min(min.Y,point.Y); - max.X = std::max(max.X,point.X); - max.Y = std::max(max.Y,point.Y); + min.X = std::min(min.X, point.X); + min.Y = std::min(min.Y, point.Y); + max.X = std::max(max.X, point.X); + max.Y = std::max(max.Y, point.Y); } void AABB::include(const AABB other) @@ -153,5 +157,4 @@ Polygon AABB::toPolygon() const return ret; } -}//namespace cura - +} // namespace cura diff --git a/src/utils/ExtrusionSegment.cpp b/src/utils/ExtrusionSegment.cpp index 64b7ea8ae3..72a007bc67 100644 --- a/src/utils/ExtrusionSegment.cpp +++ b/src/utils/ExtrusionSegment.cpp @@ -1,9 +1,10 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include "utils/ExtrusionSegment.h" -#include "utils/logoutput.h" +#include + #include "utils/macros.h" namespace cura @@ -20,7 +21,7 @@ Polygons ExtrusionSegment::toPolygons(bool reduced) const Point vec = to.p - from.p; const coord_t vec_length = vSize(vec); - if (vec_length <= 0) //Don't even output the endcaps. + if (vec_length <= 0) // Don't even output the endcaps. { return ret; } @@ -28,25 +29,25 @@ Polygons ExtrusionSegment::toPolygons(bool reduced) PolygonRef poly = ret.newPoly(); const float delta_r = 0.5f * std::abs(from.w - to.w); const float vec_length_fixed = std::max(delta_r, static_cast(vec_length)); - float alpha = std::acos(delta_r / vec_length_fixed); //Angle between the slope along the edge of the polygon (due to varying line width) and the centerline. + float alpha = std::acos(delta_r / vec_length_fixed); // Angle between the slope along the edge of the polygon (due to varying line width) and the centerline. if (to.w > from.w) { alpha = M_PI - alpha; } - assert(alpha > - M_PI - 0.0001); + assert(alpha > -M_PI - 0.0001); assert(alpha < M_PI + 0.0001); - if(alpha <= -M_PI || alpha >= M_PI) + if (alpha <= -M_PI || alpha >= M_PI) { - RUN_ONCE(logWarning("Line joint slope is out of bounds (should be between -pi and +pi): %f", alpha)); + spdlog::warn("Line joint slope is out of bounds (should be between -pi and +pi): {}", alpha); } - + float dir = std::atan(vec.Y / static_cast(vec.X)); if (vec.X < 0) { dir += M_PI; } - //Draw the endcap on the "from" vertex's end. + // Draw the endcap on the "from" vertex's end. { poly.emplace_back(from.p + Point(from.w / 2 * cos(alpha + dir), from.w / 2 * sin(alpha + dir))); @@ -63,7 +64,7 @@ Polygons ExtrusionSegment::toPolygons(bool reduced) end_a += a_step; } - //Draw the endcap. + // Draw the endcap. for (float a = start_a; a <= end_a; a += a_step) { poly.emplace_back(from.p + Point(from.w / 2 * cos(a), from.w / 2 * sin(a))); @@ -71,9 +72,9 @@ Polygons ExtrusionSegment::toPolygons(bool reduced) poly.emplace_back(from.p + Point(from.w / 2 * cos(2 * M_PI - alpha + dir), from.w / 2 * sin(2 * M_PI - alpha + dir))); } - //Draw the endcap on the "to" vertex's end. + // Draw the endcap on the "to" vertex's end. { - poly.emplace_back(to.p + Point(to.w / 2 * cos(2 * M_PI - alpha + dir), to.w / 2 * sin(2 * M_PI - alpha + dir))); //Also draws the main diagonal from the "from" vertex to the "to" vertex! + poly.emplace_back(to.p + Point(to.w / 2 * cos(2 * M_PI - alpha + dir), to.w / 2 * sin(2 * M_PI - alpha + dir))); // Also draws the main diagonal from the "from" vertex to the "to" vertex! float start_a = 2 * M_PI; while (start_a > alpha + dir) @@ -82,12 +83,14 @@ Polygons ExtrusionSegment::toPolygons(bool reduced) } if (reduced) { - //If reduced, we'll go the other way around the circle, drawing the other half. - //The rounding at the ends works slightly different then. + // If reduced, we'll go the other way around the circle, drawing the other half. + // The rounding at the ends works slightly different then. start_a += a_step; } - float end_a = -2 * M_PI; while (end_a < 2 * M_PI - alpha + dir) end_a += a_step; + float end_a = -2 * M_PI; + while (end_a < 2 * M_PI - alpha + dir) + end_a += a_step; if (reduced) { end_a -= a_step; @@ -97,10 +100,10 @@ Polygons ExtrusionSegment::toPolygons(bool reduced) end_a -= 2 * M_PI; } - //Draw the endcap. + // Draw the endcap. if (reduced) { - for (float a = end_a; a >= start_a; a -= a_step) //Go in the opposite direction. + for (float a = end_a; a >= start_a; a -= a_step) // Go in the opposite direction. { poly.emplace_back(to.p + Point(to.w / 2 * cos(a), to.w / 2 * sin(a))); } @@ -114,7 +117,7 @@ Polygons ExtrusionSegment::toPolygons(bool reduced) } poly.emplace_back(to.p + Point(to.w / 2 * cos(alpha + dir), to.w / 2 * sin(alpha + dir))); - //The other main diagonal from the "to" vertex to the "from" vertex is implicit in the closing of the polygon. + // The other main diagonal from the "to" vertex to the "from" vertex is implicit in the closing of the polygon. } #ifdef DEBUG @@ -123,13 +126,12 @@ Polygons ExtrusionSegment::toPolygons(bool reduced) assert(p.X < 0x3FFFFFFFFFFFFFFFLL); assert(p.Y < 0x3FFFFFFFFFFFFFFFLL); } -#endif //DEBUG +#endif // DEBUG return ret; } - std::vector ExtrusionSegment::discretize(coord_t step_size) { Point a = from.p; @@ -148,4 +150,4 @@ std::vector ExtrusionSegment::discretize(coord_t step_size) return discretized; } -}//namespace cura +} // namespace cura diff --git a/src/utils/SVG.cpp b/src/utils/SVG.cpp index 39003ee520..c6959c4810 100644 --- a/src/utils/SVG.cpp +++ b/src/utils/SVG.cpp @@ -1,41 +1,54 @@ -//Copyright (c) 2017 Tim Kuipers -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include +#include + +#include "utils/ExtrusionLine.h" +#include "utils/SVG.h" #include "utils/floatpoint.h" -#include "utils/logoutput.h" #include "utils/polygon.h" -#include "utils/SVG.h" -#include "utils/ExtrusionLine.h" - -namespace cura { +namespace cura +{ std::string SVG::toString(Color color) const { switch (color) { - case SVG::Color::BLACK: return "black"; - case SVG::Color::WHITE: return "white"; - case SVG::Color::GRAY: return "gray"; - case SVG::Color::RED: return "red"; - case SVG::Color::BLUE: return "blue"; - case SVG::Color::GREEN: return "green"; - case SVG::Color::LIME: return "lime"; - case SVG::Color::ORANGE: return "orange"; - case SVG::Color::MAGENTA: return "magenta"; - case SVG::Color::YELLOW: return "yellow"; - case SVG::Color::NONE: return "none"; - default: return "black"; + case SVG::Color::BLACK: + return "black"; + case SVG::Color::WHITE: + return "white"; + case SVG::Color::GRAY: + return "gray"; + case SVG::Color::RED: + return "red"; + case SVG::Color::BLUE: + return "blue"; + case SVG::Color::GREEN: + return "green"; + case SVG::Color::LIME: + return "lime"; + case SVG::Color::ORANGE: + return "orange"; + case SVG::Color::MAGENTA: + return "magenta"; + case SVG::Color::YELLOW: + return "yellow"; + case SVG::Color::NONE: + return "none"; + default: + return "black"; } } std::string SVG::toString(const ColorObject& color) const { - if (color.is_enum) return toString(color.color); + if (color.is_enum) + return toString(color.color); else { std::ostringstream ss; @@ -46,27 +59,21 @@ std::string SVG::toString(const ColorObject& color) const SVG::SVG(std::string filename, AABB aabb, Point canvas_size, ColorObject background) -: SVG(filename, aabb, std::min(double(canvas_size.X - canvas_size.X / 5 * 2) / (aabb.max.X - aabb.min.X), double(canvas_size.Y - canvas_size.Y / 5) / (aabb.max.Y - aabb.min.Y)), canvas_size, background) + : SVG(filename, aabb, std::min(double(canvas_size.X - canvas_size.X / 5 * 2) / (aabb.max.X - aabb.min.X), double(canvas_size.Y - canvas_size.Y / 5) / (aabb.max.Y - aabb.min.Y)), canvas_size, background) { } -SVG::SVG(std::string filename, AABB aabb, double scale, ColorObject background) -: SVG(filename, aabb, scale, (aabb.max - aabb.min) * scale, background) +SVG::SVG(std::string filename, AABB aabb, double scale, ColorObject background) : SVG(filename, aabb, scale, (aabb.max - aabb.min) * scale, background) { } -SVG::SVG(std::string filename, AABB aabb, double scale, Point canvas_size, ColorObject background) -: aabb(aabb) -, aabb_size(aabb.max - aabb.min) -, canvas_size(canvas_size) -, scale(scale) -, background(background) +SVG::SVG(std::string filename, AABB aabb, double scale, Point canvas_size, ColorObject background) : aabb(aabb), aabb_size(aabb.max - aabb.min), canvas_size(canvas_size), scale(scale), background(background) { output_is_html = strcmp(filename.c_str() + strlen(filename.c_str()) - 4, "html") == 0; out = fopen(filename.c_str(), "w"); - if(!out) + if (! out) { - logError("The file %s could not be opened for writing.",filename.c_str()); + spdlog::error("The file %s could not be opened for writing.", filename); } if (output_is_html) { @@ -77,21 +84,20 @@ SVG::SVG(std::string filename, AABB aabb, double scale, Point canvas_size, Color fprintf(out, "\n"); } fprintf(out, "\n"); - fprintf(out," \n", layer_nr ); - - if (!background.is_enum || background.color != Color::NONE) + fprintf(out, " xmlns=\"http://www.w3.org/2000/svg\"\n"); + fprintf(out, " xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"\n"); + fprintf(out, " height=\"%f\"\n", scale * (aabb.max.Y - aabb.min.Y)); + fprintf(out, " width=\"%f\"\n", scale * (aabb.max.X - aabb.min.X)); + fprintf(out, " version=\"1.1\">\n"); + fprintf(out, " \n", layer_nr); + + if (! background.is_enum || background.color != Color::NONE) { fprintf(out, "\n", toString(background).c_str()); } - } SVG::~SVG() @@ -114,10 +120,10 @@ void SVG::nextLayer() { fprintf(out, " \n"); layer_nr++; - fprintf(out," \n", layer_nr ); + fprintf(out, " \n", layer_nr); } Point SVG::transform(const Point& p) const @@ -127,7 +133,7 @@ Point SVG::transform(const Point& p) const FPoint3 SVG::transformF(const Point& p) const { - return FPoint3((p.X - aabb.min.X) * scale, (p.Y-aabb.min.Y) * scale, 0.0); + return FPoint3((p.X - aabb.min.X) * scale, (p.Y - aabb.min.Y) * scale, 0.0); } void SVG::writeComment(const std::string& comment) const @@ -159,23 +165,23 @@ void SVG::writeAreas(const Polygons& polygons, const ColorObject color, const Co void SVG::writeAreas(ConstPolygonRef polygon, const ColorObject color, const ColorObject outline_color, const float stroke_width) const { - fprintf(out,"\n"); //The end of the polygon tag. + fprintf(out, "\" />\n"); // The end of the polygon tag. } void SVG::writePoint(const Point& p, const bool write_coords, const float size, const ColorObject color) const { FPoint3 pf = transformF(p); - fprintf(out, "\n",pf.x, pf.y, size, toString(color).c_str()); - + fprintf(out, "\n", pf.x, pf.y, size, toString(color).c_str()); + if (write_coords) { - fprintf(out, "%lli,%lli\n",pf.x, pf.y, p.X, p.Y); + fprintf(out, "%lli,%lli\n", pf.x, pf.y, p.X, p.Y); } } @@ -189,7 +195,7 @@ void SVG::writePoints(ConstPolygonRef poly, const bool write_coords, const float void SVG::writePoints(const Polygons& polygons, const bool write_coords, const float size, const ColorObject color) const { - for(const ConstPolygonRef& poly : polygons) + for (const ConstPolygonRef& poly : polygons) { writePoints(poly, write_coords, size, color); } @@ -197,19 +203,19 @@ void SVG::writePoints(const Polygons& polygons, const bool write_coords, const f void SVG::writeLines(const std::vector& polyline, const ColorObject color) const { - if(polyline.size() <= 1) //Need at least 2 points. + if (polyline.size() <= 1) // Need at least 2 points. { return; } - - FPoint3 transformed = transformF(polyline[0]); //Element 0 must exist due to the check above. - fprintf(out,"\n"); //Write the end of the tag. + fprintf(out, "\" />\n"); // Write the end of the tag. } void SVG::writeLine(const Point& a, const Point& b, const ColorObject color, const float stroke_width) const @@ -244,13 +250,13 @@ void SVG::writeDashedLine(const Point& a, const Point& b, ColorObject color) con { FPoint3 fa = transformF(a); FPoint3 fb = transformF(b); - fprintf(out,"\n",fa.x,fa.y,fb.x,fb.y,toString(color).c_str()); + fprintf(out, "\n", fa.x, fa.y, fb.x, fb.y, toString(color).c_str()); } void SVG::writeText(const Point& p, const std::string& txt, const ColorObject color, const float font_size) const { FPoint3 pf = transformF(p); - fprintf(out, "%s\n",pf.x, pf.y, font_size, toString(color).c_str(), txt.c_str()); + fprintf(out, "%s\n", pf.x, pf.y, font_size, toString(color).c_str(), txt.c_str()); } void SVG::writePolygons(const Polygons& polys, const ColorObject color, const float stroke_width) const @@ -319,9 +325,11 @@ void SVG::writePolyline(ConstPolygonRef poly, const ColorObject color, const flo if (color.color == Color::RAINBOW) { int g = (i * 255 * 11 / size) % (255 * 2); - if (g > 255) g = 255 * 2 - g; + if (g > 255) + g = 255 * 2 - g; int b = (i * 255 * 5 / size) % (255 * 2); - if (b > 255) b = 255 * 2 - b; + if (b > 255) + b = 255 * 2 - b; writeLineRGB(p0, p1, i * 255 / size, g, b, stroke_width); } else @@ -335,7 +343,7 @@ void SVG::writePolyline(ConstPolygonRef poly, const ColorObject color, const flo void SVG::writePaths(const std::vector& paths, const ColorObject color, const float width_factor) const { - for(const VariableWidthLines& lines : paths) + for (const VariableWidthLines& lines : paths) { writeLines(lines, color, width_factor); } @@ -343,7 +351,7 @@ void SVG::writePaths(const std::vector& paths, const ColorOb void SVG::writeLines(const VariableWidthLines& lines, const ColorObject color, const float width_factor) const { - for(const ExtrusionLine& line : lines) + for (const ExtrusionLine& line : lines) { writeLine(line, color, width_factor); } @@ -351,20 +359,20 @@ void SVG::writeLines(const VariableWidthLines& lines, const ColorObject color, c void SVG::writeLine(const ExtrusionLine& line, const ColorObject color, const float width_factor) const { - constexpr float minimum_line_width = 10; //Always have some width, otherwise some lines become completely invisible. - if(line.junctions.empty()) //Only draw lines that have at least 2 junctions, otherwise they are degenerate. + constexpr float minimum_line_width = 10; // Always have some width, otherwise some lines become completely invisible. + if (line.junctions.empty()) // Only draw lines that have at least 2 junctions, otherwise they are degenerate. { return; } ExtrusionJunction start_vertex = line.junctions[0]; - for(size_t index = 1; index < line.junctions.size(); ++index) + for (size_t index = 1; index < line.junctions.size(); ++index) { ExtrusionJunction end_vertex = line.junctions[index]; - //Compute the corners of the trapezoid for this variable-width line segment. + // Compute the corners of the trapezoid for this variable-width line segment. const Point direction_vector = end_vertex.p - start_vertex.p; const Point direction_left = turn90CCW(direction_vector); - const Point direction_right = -direction_left; //Opposite of left. + const Point direction_right = -direction_left; // Opposite of left. const FPoint3 start_left = transformF(start_vertex.p + normal(direction_left, std::max(minimum_line_width, start_vertex.w * width_factor))); const FPoint3 start_right = transformF(start_vertex.p + normal(direction_right, std::max(minimum_line_width, start_vertex.w * width_factor))); const FPoint3 end_left = transformF(end_vertex.p + normal(direction_left, std::max(minimum_line_width, end_vertex.w * width_factor))); @@ -372,24 +380,24 @@ void SVG::writeLine(const ExtrusionLine& line, const ColorObject color, const fl fprintf(out, "\n", toString(color).c_str(), start_left.x, start_left.y, start_right.x, start_right.y, end_right.x, end_right.y, end_left.x, end_left.y); - start_vertex = end_vertex; //For the next line segment. + start_vertex = end_vertex; // For the next line segment. } } void SVG::writeCoordinateGrid(const coord_t grid_size, const Color color, const float stroke_width, const float font_size) const { - constexpr float dist_from_edge = 0.05; //As fraction of image width or height. + constexpr float dist_from_edge = 0.05; // As fraction of image width or height. const coord_t min_x = aabb.min.X - (aabb.min.X % grid_size); const coord_t min_y = aabb.min.Y - (aabb.min.Y % grid_size); - for(coord_t x = min_x; x < aabb.max.X; x += grid_size) + for (coord_t x = min_x; x < aabb.max.X; x += grid_size) { writeLine(Point(x, aabb.min.Y), Point(x, aabb.max.Y), color, stroke_width); std::stringstream ss; ss << INT2MM(x); writeText(Point(x, aabb.min.Y + (aabb.max.Y - aabb.min.Y) * dist_from_edge), ss.str(), color, font_size); } - for(coord_t y = min_y; y < aabb.max.Y; y += grid_size) + for (coord_t y = min_y; y < aabb.max.Y; y += grid_size) { writeLine(Point(aabb.min.X, y), Point(aabb.max.Y, y), color, stroke_width); std::stringstream ss; diff --git a/src/utils/VoronoiUtils.cpp b/src/utils/VoronoiUtils.cpp index 8a860e682f..fb2fa42d13 100644 --- a/src/utils/VoronoiUtils.cpp +++ b/src/utils/VoronoiUtils.cpp @@ -1,21 +1,22 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher -#include #include +#include + +#include -#include "utils/linearAlg2D.h" -#include "utils/logoutput.h" #include "utils/VoronoiUtils.h" +#include "utils/linearAlg2D.h" -namespace cura +namespace cura { Point VoronoiUtils::p(const vd_t::vertex_type* node) { const double x = node->x(); const double y = node->y(); - return Point(x + 0.5 - (x < 0), y + 0.5 - (y < 0)); //Round to nearest integer coordinates. + return Point(x + 0.5 - (x < 0), y + 0.5 - (y < 0)); // Round to nearest integer coordinates. } bool VoronoiUtils::isSourcePoint(Point p, const vd_t::cell_type& cell, const std::vector& points, const std::vector& segments, coord_t snap_dist) @@ -47,26 +48,26 @@ coord_t VoronoiUtils::getDistance(Point p, const vd_t::cell_type& cell, const st Point VoronoiUtils::getSourcePoint(const vd_t::cell_type& cell, const std::vector& points, const std::vector& segments) { assert(cell.contains_point()); - if(!cell.contains_point()) + if (! cell.contains_point()) { - logWarning("Voronoi cell doesn't contain a source point!"); + spdlog::warn("Voronoi cell doesn't contain a source point!"); } switch (cell.source_category()) { - case boost::polygon::SOURCE_CATEGORY_SINGLE_POINT: - return points[cell.source_index()]; - break; - case boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT: - assert(cell.source_index() - points.size() < segments.size()); - return segments[cell.source_index() - points.size()].to(); - break; - case boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT: - assert(cell.source_index() - points.size() < segments.size()); - return segments[cell.source_index() - points.size()].from(); - break; - default: - assert(false && "getSourcePoint should only be called on point cells!\n"); - break; + case boost::polygon::SOURCE_CATEGORY_SINGLE_POINT: + return points[cell.source_index()]; + break; + case boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT: + assert(cell.source_index() - points.size() < segments.size()); + return segments[cell.source_index() - points.size()].to(); + break; + case boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT: + assert(cell.source_index() - points.size() < segments.size()); + return segments[cell.source_index() - points.size()].from(); + break; + default: + assert(false && "getSourcePoint should only be called on point cells!\n"); + break; } return points[cell.source_index()]; } @@ -74,30 +75,30 @@ Point VoronoiUtils::getSourcePoint(const vd_t::cell_type& cell, const std::vecto PolygonsPointIndex VoronoiUtils::getSourcePointIndex(const vd_t::cell_type& cell, const std::vector& points, const std::vector& segments) { assert(cell.contains_point()); - if(!cell.contains_point()) + if (! cell.contains_point()) { - logWarning("Voronoi cell doesn't contain a source point!"); + spdlog::warn("Voronoi cell doesn't contain a source point!"); } assert(cell.source_category() != boost::polygon::SOURCE_CATEGORY_SINGLE_POINT); switch (cell.source_category()) { - case boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT: - { - assert(cell.source_index() - points.size() < segments.size()); - PolygonsPointIndex ret = segments[cell.source_index() - points.size()]; - ++ret; - return ret; - break; - } - case boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT: - { - assert(cell.source_index() - points.size() < segments.size()); - return segments[cell.source_index() - points.size()]; - break; - } - default: - assert(false && "getSourcePoint should only be called on point cells!\n"); - break; + case boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT: + { + assert(cell.source_index() - points.size() < segments.size()); + PolygonsPointIndex ret = segments[cell.source_index() - points.size()]; + ++ret; + return ret; + break; + } + case boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT: + { + assert(cell.source_index() - points.size() < segments.size()); + return segments[cell.source_index() - points.size()]; + break; + } + default: + assert(false && "getSourcePoint should only be called on point cells!\n"); + break; } PolygonsPointIndex ret = segments[cell.source_index() - points.size()]; return ++ret; @@ -106,9 +107,9 @@ PolygonsPointIndex VoronoiUtils::getSourcePointIndex(const vd_t::cell_type& cell const VoronoiUtils::Segment& VoronoiUtils::getSourceSegment(const vd_t::cell_type& cell, const std::vector& points, const std::vector& segments) { assert(cell.contains_segment()); - if(!cell.contains_segment()) + if (! cell.contains_segment()) { - logWarning("Voronoi cell doesn't contain a source segment!"); + spdlog::warn("Voronoi cell doesn't contain a source segment!"); } return segments[cell.source_index() - points.size()]; } @@ -128,24 +129,24 @@ std::vector VoronoiUtils::discretizeParabola(const Point& p, const Segmen const coord_t sx = dot(as, ab) / ab_size; const coord_t ex = dot(ae, ab) / ab_size; const coord_t sxex = ex - sx; - + const Point ap = p - a; const coord_t px = dot(ap, ab) / ab_size; - + const Point pxx = LinearAlg2D::getClosestOnLine(p, a, b); const Point ppxx = pxx - p; const coord_t d = vSize(ppxx); const PointMatrix rot = PointMatrix(turn90CCW(ppxx)); - + if (d == 0) { discretized.emplace_back(s); discretized.emplace_back(e); return discretized; } - + const float marking_bound = atan(transitioning_angle * 0.5); - coord_t msx = - marking_bound * d; // projected marking_start + coord_t msx = -marking_bound * d; // projected marking_start coord_t mex = marking_bound * d; // projected marking_end const coord_t marking_start_end_h = msx * msx / (2 * d) + d / 2; Point marking_start = rot.unapply(Point(msx, marking_start_end_h)) + pxx; @@ -156,27 +157,27 @@ std::vector VoronoiUtils::discretizeParabola(const Point& p, const Segmen std::swap(marking_start, marking_end); std::swap(msx, mex); } - + bool add_marking_start = msx * dir > (sx - px) * dir && msx * dir < (ex - px) * dir; bool add_marking_end = mex * dir > (sx - px) * dir && mex * dir < (ex - px) * dir; const Point apex = rot.unapply(Point(0, d / 2)) + pxx; bool add_apex = (sx - px) * dir < 0 && (ex - px) * dir > 0; - assert(!(add_marking_start && add_marking_end) || add_apex); - if(add_marking_start && add_marking_end && !add_apex) + assert(! (add_marking_start && add_marking_end) || add_apex); + if (add_marking_start && add_marking_end && ! add_apex) { - logWarning("Failing to discretize parabola! Must add an apex or one of the endpoints."); + spdlog::warn("Failing to discretize parabola! Must add an apex or one of the endpoints."); } - + const coord_t step_count = static_cast(static_cast(std::abs(ex - sx)) / approximate_step_size + 0.5); - + discretized.emplace_back(s); for (coord_t step = 1; step < step_count; step++) { const coord_t x = sx + sxex * step / step_count - px; const coord_t y = x * x / (2 * d) + d / 2; - + if (add_marking_start && msx * dir < x * dir) { discretized.emplace_back(marking_start); @@ -185,7 +186,7 @@ std::vector VoronoiUtils::discretizeParabola(const Point& p, const Segmen if (add_apex && x * dir > 0) { discretized.emplace_back(apex); - add_apex = false; // only add the apex just before the + add_apex = false; // only add the apex just before the } if (add_marking_end && mex * dir < x * dir) { @@ -267,7 +268,7 @@ void VoronoiUtils::discretize(const Point& point, const Segment& segment, const // Adjust max_dist parameter in the transformed space. const coord_t max_dist_transformed = max_dist * max_dist * segment_length2; - while (!point_stack.empty()) + while (! point_stack.empty()) { const Point new_(point_stack.top(), parabolaY(point_stack.top(), rot_x, rot_y)); const Point new_vec = new_ - cur; @@ -317,4 +318,4 @@ double VoronoiUtils::getPointProjection(const Point& point, const Segment& segme return static_cast(vec_dot) / sqr_segment_length; } -}//namespace cura +} // namespace cura diff --git a/src/utils/logoutput.cpp b/src/utils/logoutput.cpp deleted file mode 100644 index b26bfebb01..0000000000 --- a/src/utils/logoutput.cpp +++ /dev/null @@ -1,108 +0,0 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. - -#include -#include -#include - -#include "utils/logoutput.h" - -namespace cura { - -static int verbose_level; -static bool progressLogging; -static std::mutex log_mutex; - -void increaseVerboseLevel() -{ - verbose_level++; -} - -void enableProgressLogging() -{ - progressLogging = true; -} - -void logError(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - { - std::unique_lock lock(log_mutex); - fprintf(stderr, "[ERROR] "); - vfprintf(stderr, fmt, args); - fflush(stderr); - } - va_end(args); -} - -void logWarning(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - { - std::unique_lock lock(log_mutex); - fprintf(stderr, "[WARNING] "); - vfprintf(stderr, fmt, args); - fflush(stderr); - } - va_end(args); -} - -void logAlways(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - { - std::unique_lock lock(log_mutex); - vfprintf(stderr, fmt, args); - fflush(stderr); - } - va_end(args); -} - -void log(const char* fmt, ...) -{ - va_list args; - if (verbose_level < 1) - return; - - va_start(args, fmt); - { - std::unique_lock lock(log_mutex); - vfprintf(stderr, fmt, args); - fflush(stderr); - } - va_end(args); -} - -void logDebug(const char* fmt, ...) -{ - va_list args; - if (verbose_level < 2) - { - return; - } - va_start(args, fmt); - { - std::unique_lock lock(log_mutex); - fprintf(stderr, "[DEBUG] "); - vfprintf(stderr, fmt, args); - fflush(stderr); - } - va_end(args); -} - -void logProgress(const char* type, int value, int maxValue, float percent) -{ - if (!progressLogging) - return; - - { - std::unique_lock lock(log_mutex); - fprintf(stderr, "Progress:%s:%i:%i \t%f%%\n", type, value, maxValue, percent); - fflush(stderr); - } -} - -}//namespace cura diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index b7ac657095..9a7c8e05f5 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -1,26 +1,26 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include #include #include #include +#include "infill.h" +#include "utils/SparsePointGridInclusive.h" #include "utils/linearAlg2D.h" #include "utils/polygonUtils.h" -#include "utils/SparsePointGridInclusive.h" -#include "utils/logoutput.h" -#include "infill.h" #ifdef DEBUG #include "utils/AABB.h" #include "utils/SVG.h" +#include #endif namespace cura { -const std::function PolygonUtils::no_penalty_function = [](Point){ return 0; }; +const std::function PolygonUtils::no_penalty_function = [](Point) { return 0; }; int64_t PolygonUtils::segmentLength(PolygonsPointIndex start, PolygonsPointIndex end) { @@ -69,7 +69,7 @@ void PolygonUtils::spreadDots(PolygonsPointIndex start, PolygonsPointIndex end, Point p0p1 = p1 - p0; int64_t p0p1_length = vSize(p0p1); - for ( ; dist_past_vert_to_insert_point < p0p1_length && n_points_generated < n_dots_in_between; dist_past_vert_to_insert_point += wipe_point_dist) + for (; dist_past_vert_to_insert_point < p0p1_length && n_points_generated < n_dots_in_between; dist_past_vert_to_insert_point += wipe_point_dist) { result.emplace_back(p0 + normal(p0p1, dist_past_vert_to_insert_point), vert.point_idx, poly); n_points_generated++; @@ -106,7 +106,8 @@ std::vector PolygonUtils::spreadDotsArea(const Polygons& polygons, coord_ } for (coord_t y = a.Y - (a.Y % grid_size) - grid_size; y < b.Y; y += grid_size) { - if (y < a.Y) continue; + if (y < a.Y) + continue; result.emplace_back(a.X, y); } } @@ -120,15 +121,9 @@ bool PolygonUtils::lineSegmentPolygonsIntersection(const Point& a, const Point& Point coll; coord_t closest_dist2 = within_max_dist2; - const auto processOnIntersect = - [&result, &closest_dist2, &a, &b, &coll](const Point& p_start, const Point& p_end) + const auto processOnIntersect = [&result, &closest_dist2, &a, &b, &coll](const Point& p_start, const Point& p_end) { - if - ( - LinearAlg2D::lineLineIntersection(a, b, p_start, p_end, coll) && - LinearAlg2D::pointIsProjectedBeyondLine(coll, p_start, p_end) == 0 && - LinearAlg2D::pointIsProjectedBeyondLine(coll, a, b) == 0 - ) + if (LinearAlg2D::lineLineIntersection(a, b, p_start, p_end, coll) && LinearAlg2D::pointIsProjectedBeyondLine(coll, p_start, p_end) == 0 && LinearAlg2D::pointIsProjectedBeyondLine(coll, a, b) == 0) { const coord_t dist2 = vSize2(b - coll); if (dist2 < closest_dist2) @@ -210,7 +205,7 @@ Point PolygonUtils::getBoundaryPointWithOffset(ConstPolygonRef poly, unsigned in Point PolygonUtils::moveInsideDiagonally(ClosestPolygonPoint point_on_boundary, int64_t inset) { - if (!point_on_boundary.isValid()) + if (! point_on_boundary.isValid()) { return no_point; } @@ -232,28 +227,35 @@ unsigned int PolygonUtils::moveOutside(const Polygons& polygons, Point& from, in return moveInside(polygons, from, -distance, maxDist2); } -ClosestPolygonPoint PolygonUtils::moveInside2(const Polygons& polygons, Point& from, const int distance, const int64_t max_dist2, const Polygons* loc_to_line_polygons, const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) +ClosestPolygonPoint PolygonUtils::moveInside2(const Polygons& polygons, + Point& from, + const int distance, + const int64_t max_dist2, + const Polygons* loc_to_line_polygons, + const LocToLineGrid* loc_to_line_grid, + const std::function& penalty_function) { std::optional closest_polygon_point; if (loc_to_line_grid) { closest_polygon_point = findClose(from, *loc_to_line_polygons, *loc_to_line_grid, penalty_function); } - if (!closest_polygon_point) + if (! closest_polygon_point) { closest_polygon_point = findClosest(from, polygons, penalty_function); } return _moveInside2(*closest_polygon_point, distance, from, max_dist2); } -ClosestPolygonPoint PolygonUtils::moveInside2(const Polygons& loc_to_line_polygons, ConstPolygonRef polygon, Point& from, const int distance, const int64_t max_dist2, const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) +ClosestPolygonPoint + PolygonUtils::moveInside2(const Polygons& loc_to_line_polygons, ConstPolygonRef polygon, Point& from, const int distance, const int64_t max_dist2, const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) { std::optional closest_polygon_point; if (loc_to_line_grid) { closest_polygon_point = findClose(from, loc_to_line_polygons, *loc_to_line_grid, penalty_function); } - if (!closest_polygon_point) + if (! closest_polygon_point) { closest_polygon_point = findClosest(from, polygon, penalty_function); } @@ -262,7 +264,7 @@ ClosestPolygonPoint PolygonUtils::moveInside2(const Polygons& loc_to_line_polygo ClosestPolygonPoint PolygonUtils::_moveInside2(const ClosestPolygonPoint& closest_polygon_point, const int distance, Point& from, const int64_t max_dist2) { - if (!closest_polygon_point.isValid()) + if (! closest_polygon_point.isValid()) { return ClosestPolygonPoint(); // stub with invalid indices to signify we haven't found any } @@ -310,12 +312,12 @@ unsigned int PolygonUtils::moveInside(const Polygons& polygons, Point& from, int ConstPolygonRef poly = polygons[poly_idx]; if (poly.size() < 2) continue; - Point p0 = poly[poly.size()-2]; + Point p0 = poly[poly.size() - 2]; Point p1 = poly.back(); // because we compare with vSize2 here (no division by zero), we also need to compare by vSize2 inside the loop // to avoid integer rounding edge cases bool projected_p_beyond_prev_segment = dot(p1 - p0, from - p0) >= vSize2(p1 - p0); - for(const Point& p2 : poly) + for (const Point& p2 : poly) { // X = A + Normal(B-A) * (((B-A) dot (P-A)) / VSize(B-A)); // = A + (B-A) * ((B-A) dot (P-A)) / VSize2(B-A); @@ -326,9 +328,9 @@ unsigned int PolygonUtils::moveInside(const Polygons& polygons, Point& from, int Point ab = b - a; Point ap = p - a; int64_t ab_length2 = vSize2(ab); - if(ab_length2 <= 0) //A = B, i.e. the input polygon had two adjacent points on top of each other. + if (ab_length2 <= 0) // A = B, i.e. the input polygon had two adjacent points on top of each other. { - p1 = p2; //Skip only one of the points. + p1 = p2; // Skip only one of the points. continue; } int64_t dot_prod = dot(ab, ap); @@ -344,7 +346,10 @@ unsigned int PolygonUtils::moveInside(const Polygons& polygons, Point& from, int { bestDist2 = dist2; bestPoly = poly_idx; - if (distance == 0) { ret = x; } + if (distance == 0) + { + ret = x; + } else { Point inward_dir = turn90CCW(normal(ab, MM2INT(10.0)) + normal(p1 - p0, MM2INT(10.0))); // inward direction irrespective of sign of [distance] @@ -379,7 +384,10 @@ unsigned int PolygonUtils::moveInside(const Polygons& polygons, Point& from, int { bestDist2 = dist2; bestPoly = poly_idx; - if (distance == 0) { ret = x; } + if (distance == 0) + { + ret = x; + } else { Point inward_dir = turn90CCW(normal(ab, distance)); // inward or outward depending on the sign of [distance] @@ -400,7 +408,7 @@ unsigned int PolygonUtils::moveInside(const Polygons& polygons, Point& from, int } else { -// from = from; // original point stays unaltered. It is already inside by enough distance + // from = from; // original point stays unaltered. It is already inside by enough distance } return bestPoly; } @@ -412,10 +420,10 @@ unsigned int PolygonUtils::moveInside(const Polygons& polygons, Point& from, int return NO_INDEX; } -//Version that works on single PolygonRef. +// Version that works on single PolygonRef. unsigned int PolygonUtils::moveInside(const ConstPolygonRef polygon, Point& from, int distance, int64_t maxDist2) { - //TODO: This is copied from the moveInside of Polygons. + // TODO: This is copied from the moveInside of Polygons. /* We'd like to use this function as subroutine in moveInside(Polygons...), but then we'd need to recompute the distance of the point to the polygon, which @@ -435,7 +443,7 @@ unsigned int PolygonUtils::moveInside(const ConstPolygonRef polygon, Point& from // because we compare with vSize2 here (no division by zero), we also need to compare by vSize2 inside the loop // to avoid integer rounding edge cases bool projected_p_beyond_prev_segment = dot(p1 - p0, from - p0) >= vSize2(p1 - p0); - for(const Point& p2 : polygon) + for (const Point& p2 : polygon) { // X = A + Normal(B-A) * (((B-A) dot (P-A)) / VSize(B-A)); // = A + (B-A) * ((B-A) dot (P-A)) / VSize2(B-A); @@ -446,9 +454,9 @@ unsigned int PolygonUtils::moveInside(const ConstPolygonRef polygon, Point& from Point ab = b - a; Point ap = p - a; int64_t ab_length2 = vSize2(ab); - if(ab_length2 <= 0) //A = B, i.e. the input polygon had two adjacent points on top of each other. + if (ab_length2 <= 0) // A = B, i.e. the input polygon had two adjacent points on top of each other. { - p1 = p2; //Skip only one of the points. + p1 = p2; // Skip only one of the points. continue; } int64_t dot_prod = dot(ab, ap); @@ -538,7 +546,7 @@ Point PolygonUtils::moveOutside(const ClosestPolygonPoint& cpp, const int distan Point PolygonUtils::moveInside(const ClosestPolygonPoint& cpp, const int distance) { - if (!cpp.isValid()) + if (! cpp.isValid()) { return no_point; } @@ -582,15 +590,27 @@ Point PolygonUtils::moveInside(const ClosestPolygonPoint& cpp, const int distanc } } -ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside(const Polygons& polygons, Point& from, int preferred_dist_inside, int64_t max_dist2, const Polygons* loc_to_line_polygons, const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) +ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside(const Polygons& polygons, + Point& from, + int preferred_dist_inside, + int64_t max_dist2, + const Polygons* loc_to_line_polygons, + const LocToLineGrid* loc_to_line_grid, + const std::function& penalty_function) { const ClosestPolygonPoint closest_polygon_point = moveInside2(polygons, from, preferred_dist_inside, max_dist2, loc_to_line_polygons, loc_to_line_grid, penalty_function); return ensureInsideOrOutside(polygons, from, closest_polygon_point, preferred_dist_inside, loc_to_line_polygons, loc_to_line_grid, penalty_function); } -ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside(const Polygons& polygons, Point& from, const ClosestPolygonPoint& closest_polygon_point, int preferred_dist_inside, const Polygons* loc_to_line_polygons, const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) +ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside(const Polygons& polygons, + Point& from, + const ClosestPolygonPoint& closest_polygon_point, + int preferred_dist_inside, + const Polygons* loc_to_line_polygons, + const LocToLineGrid* loc_to_line_grid, + const std::function& penalty_function) { - if (!closest_polygon_point.isValid()) + if (! closest_polygon_point.isValid()) { return ClosestPolygonPoint(); // we couldn't move inside } @@ -672,10 +692,10 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside(const Polygons& polygons svg.writeComment("Location computed to be inside the black polygon"); svg.writePoint(inside.location, true, 5, SVG::Color::RED); } - catch(...) + catch (...) { } - logError("Clipper::offset failed. See generated debug.html!\n\tBlack is original\n\tBlue is offsetted polygon\n"); + spdlog::error("Clipper::offset failed. See generated debug.html! Black is original Blue is offsetted polygon"); #endif return ClosestPolygonPoint(); } @@ -689,7 +709,7 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside(const Polygons& polygons void PolygonUtils::walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_result, ClosestPolygonPoint& poly2_result) { - if (!poly1_result.isValid() || !poly2_result.isValid()) + if (! poly1_result.isValid() || ! poly2_result.isValid()) { return; } @@ -717,7 +737,7 @@ void PolygonUtils::walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_re } // check surrounding verts in order to prevent local optima like the following: - //o o + // o o // \.....| // \_.-'| // \---| @@ -725,17 +745,17 @@ void PolygonUtils::walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_re // o o >> should find connection here coord_t best_distance2 = vSize2(poly1_result.p() - poly2_result.p()); auto check_neighboring_vert = [&best_distance2](ConstPolygonRef from_poly, ConstPolygonRef to_poly, ClosestPolygonPoint& from_poly_result, ClosestPolygonPoint& to_poly_result, bool vertex_after) + { + const Point after_poly2_result = to_poly[(to_poly_result.point_idx + vertex_after) % to_poly.size()]; + const ClosestPolygonPoint poly1_after_poly2_result = findNearestClosest(after_poly2_result, from_poly, from_poly_result.point_idx); + const coord_t poly1_after_poly2_result_dist2 = vSize2(poly1_after_poly2_result.p() - after_poly2_result); + if (poly1_after_poly2_result_dist2 < best_distance2) { - const Point after_poly2_result = to_poly[(to_poly_result.point_idx + vertex_after) % to_poly.size()]; - const ClosestPolygonPoint poly1_after_poly2_result = findNearestClosest(after_poly2_result, from_poly, from_poly_result.point_idx); - const coord_t poly1_after_poly2_result_dist2 = vSize2(poly1_after_poly2_result.p() - after_poly2_result); - if (poly1_after_poly2_result_dist2 < best_distance2) - { - from_poly_result = poly1_after_poly2_result; - to_poly_result.location = after_poly2_result; - best_distance2 = poly1_after_poly2_result_dist2; - } - }; + from_poly_result = poly1_after_poly2_result; + to_poly_result.location = after_poly2_result; + best_distance2 = poly1_after_poly2_result_dist2; + } + }; check_neighboring_vert(poly1, poly2, poly1_result, poly2_result, false); check_neighboring_vert(poly1, poly2, poly1_result, poly2_result, true); check_neighboring_vert(poly2, poly1, poly2_result, poly1_result, false); @@ -748,7 +768,7 @@ void PolygonUtils::walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_re ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, ConstPolygonRef polygon, int start_idx) { ClosestPolygonPoint forth = findNearestClosest(from, polygon, start_idx, 1); - if (!forth.isValid()) + if (! forth.isValid()) { return forth; // stop computation } @@ -784,7 +804,7 @@ ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, ConstPolygonRef const Point& p1 = polygon[p1_idx]; const Point& p2 = polygon[p2_idx]; - Point closest_here = LinearAlg2D::getClosestOnLineSegment(from, p1 ,p2); + Point closest_here = LinearAlg2D::getClosestOnLineSegment(from, p1, p2); int64_t dist = vSize2(from - closest_here); if (dist < closestDist) { @@ -830,9 +850,10 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point from, const Polygons& polygo for (unsigned int ply = 0; ply < polygons.size(); ply++) { ConstPolygonRef poly = polygons[ply]; - if (poly.size() == 0) continue; + if (poly.size() == 0) + continue; ClosestPolygonPoint closest_here = findClosest(from, poly, penalty_function); - if (!closest_here.isValid()) + if (! closest_here.isValid()) { continue; } @@ -860,15 +881,16 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point from, ConstPolygonRef polygo int64_t closestDist2_score = vSize2(from - best) + penalty_function(best); int bestPos = 0; - for (unsigned int p = 0; p= polygon.size()) p2_idx = 0; + unsigned int p2_idx = p + 1; + if (p2_idx >= polygon.size()) + p2_idx = 0; const Point& p2 = polygon[p2_idx]; - Point closest_here = LinearAlg2D::getClosestOnLineSegment(from, p1 ,p2); + Point closest_here = LinearAlg2D::getClosestOnLineSegment(from, p1, p2); int64_t dist2_score = vSize2(from - closest_here) + penalty_function(closest_here); if (dist2_score < closestDist2_score) { @@ -934,7 +956,6 @@ std::unique_ptr PolygonUtils::createLocToLineGrid(const Polygons& { ret->insert(PolygonsPointIndex(&polygons, poly_idx, point_idx)); } - } return ret; } @@ -943,16 +964,12 @@ std::unique_ptr PolygonUtils::createLocToLineGrid(const Polygons& * The current implementation can check the same line segment multiple times, * since the same line segment can occur in multiple cells if it it longer than * the cell size of the SparsePointGridInclusive. - * + * * We could skip the duplication by keeping a vector of vectors of bools. */ -std::optional PolygonUtils::findClose( - Point from, const Polygons& polygons, - const LocToLineGrid& loc_to_line, - const std::function& penalty_function) +std::optional PolygonUtils::findClose(Point from, const Polygons& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function) { - std::vector near_lines = - loc_to_line.getNearby(from, loc_to_line.getCellSize()); + std::vector near_lines = loc_to_line.getNearby(from, loc_to_line.getCellSize()); Point best(0, 0); @@ -964,7 +981,7 @@ std::optional PolygonUtils::findClose( const Point& p1 = poly[point_poly_index.point_idx]; const Point& p2 = poly[(point_poly_index.point_idx + 1) % poly.size()]; - Point closest_here = LinearAlg2D::getClosestOnLineSegment(from, p1 ,p2); + Point closest_here = LinearAlg2D::getClosestOnLineSegment(from, p1, p2); int64_t dist2_score = vSize2(from - closest_here) + penalty_function(closest_here); if (dist2_score < closest_dist2_score) { @@ -983,10 +1000,7 @@ std::optional PolygonUtils::findClose( } } -std::vector> PolygonUtils::findClose( - ConstPolygonRef from, const Polygons& destination, - const LocToLineGrid& destination_loc_to_line, - const std::function& penalty_function) +std::vector> PolygonUtils::findClose(ConstPolygonRef from, const Polygons& destination, const LocToLineGrid& destination_loc_to_line, const std::function& penalty_function) { std::vector> ret; int p0_idx = from.size() - 1; @@ -1021,14 +1035,13 @@ std::vector> PolygonUtils::f bool PolygonUtils::getNextPointWithDistance(Point from, int64_t dist, ConstPolygonRef poly, int start_idx, int poly_start_idx, GivenDistPoint& result) { - Point prev_poly_point = poly[(start_idx + poly_start_idx) % poly.size()]; for (unsigned int prev_idx = start_idx; prev_idx < poly.size(); prev_idx++) { int next_idx = (prev_idx + 1 + poly_start_idx) % poly.size(); // last checked segment is between last point in poly and poly[0]... const Point& next_poly_point = poly[next_idx]; - if ( !shorterThen(next_poly_point - from, dist) ) + if (! shorterThen(next_poly_point - from, dist)) { /* * x r @@ -1056,7 +1069,8 @@ bool PolygonUtils::getNextPointWithDistance(Point from, int64_t dist, ConstPolyg result.location = middle; result.pos = prev_idx; return true; - } else + } + else { prev_poly_point = next_poly_point; continue; @@ -1067,14 +1081,13 @@ bool PolygonUtils::getNextPointWithDistance(Point from, int64_t dist, ConstPolyg Point px = dot(pf, pn) / vSize(pn) * pn / vSize(pn); Point xf = pf - px; - if (!shorterThen(xf, dist)) // line lies wholly further than pn + if (! shorterThen(xf, dist)) // line lies wholly further than pn { prev_poly_point = next_poly_point; continue; - } - int64_t xr_dist = std::sqrt(dist*dist - vSize2(xf)); // inverse Pythagoras + int64_t xr_dist = std::sqrt(dist * dist - vSize2(xf)); // inverse Pythagoras if (vSize(pn - px) - xr_dist < 1) // r lies beyond n { @@ -1100,7 +1113,7 @@ ClosestPolygonPoint PolygonUtils::walk(const ClosestPolygonPoint& from, coord_t Point last_vertex = from.p(); Point next_vertex; size_t last_point_idx = from.point_idx; - for (size_t point_idx = from.point_idx + 1; ; point_idx++) + for (size_t point_idx = from.point_idx + 1;; point_idx++) { if (point_idx == poly.size()) { @@ -1108,7 +1121,8 @@ ClosestPolygonPoint PolygonUtils::walk(const ClosestPolygonPoint& from, coord_t } next_vertex = poly[point_idx]; distance -= vSize(last_vertex - next_vertex); - if (distance <= 0) break; + if (distance <= 0) + break; last_vertex = next_vertex; last_point_idx = point_idx; } @@ -1141,10 +1155,7 @@ std::optional PolygonUtils::getNextParallelIntersection(con coord_t prev_projected = 0; for (unsigned int next_point_nr = 0; next_point_nr < poly.size(); next_point_nr++) { - const unsigned int next_point_idx = - forward ? - (start.point_idx + 1 + next_point_nr) % poly.size() - : (static_cast(start.point_idx) - next_point_nr + poly.size()) % poly.size(); // cast in order to accomodate subtracting + const unsigned int next_point_idx = forward ? (start.point_idx + 1 + next_point_nr) % poly.size() : (static_cast(start.point_idx) - next_point_nr + poly.size()) % poly.size(); // cast in order to accomodate subtracting const Point next_vert = poly[next_point_idx]; const Point so = next_vert - s; const coord_t projected = dot(shift, so) / dist; @@ -1190,21 +1201,19 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const Point from, const Point PolygonsPointIndex result; - std::function process_elem_func = - [transformed_from, transformed_to, &transformation_matrix, &result, &ret] - (const PolygonsPointIndex& line_start) - { - Point p0 = transformation_matrix.apply(line_start.p()); - Point p1 = transformation_matrix.apply(line_start.next().p()); + std::function process_elem_func = [transformed_from, transformed_to, &transformation_matrix, &result, &ret](const PolygonsPointIndex& line_start) + { + Point p0 = transformation_matrix.apply(line_start.p()); + Point p1 = transformation_matrix.apply(line_start.next().p()); - if (LinearAlg2D::lineSegmentsCollide(transformed_from, transformed_to, p0, p1)) - { - result = line_start; - ret = true; - return false; - } - return true; - }; + if (LinearAlg2D::lineSegmentsCollide(transformed_from, transformed_to, p0, p1)) + { + result = line_start; + ret = true; + return false; + } + return true; + }; loc_to_line.processLine(std::make_pair(from, to), process_elem_func); if (collision_result) @@ -1217,7 +1226,7 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const Point from, const Point bool PolygonUtils::polygonCollidesWithLineSegment(ConstPolygonRef poly, const Point& transformed_startPoint, const Point& transformed_endPoint, PointMatrix transformation_matrix) { Point p0 = transformation_matrix.apply(poly.back()); - for(Point p1_ : poly) + for (Point p1_ : poly) { Point p1 = transformation_matrix.apply(p1_); if (LinearAlg2D::lineSegmentsCollide(transformed_startPoint, transformed_endPoint, p0, p1)) @@ -1244,7 +1253,10 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, const P { for (ConstPolygonRef poly : polys) { - if (poly.size() == 0) { continue; } + if (poly.size() == 0) + { + continue; + } if (PolygonUtils::polygonCollidesWithLineSegment(poly, transformed_startPoint, transformed_endPoint, transformation_matrix)) { return true; @@ -1257,9 +1269,9 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, const P bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, const Point& startPoint, const Point& endPoint) { - if(endPoint == startPoint) + if (endPoint == startPoint) { - return false; //Zero-length line segments never collide. + return false; // Zero-length line segments never collide. } Point diff = endPoint - startPoint; @@ -1280,17 +1292,17 @@ bool PolygonUtils::polygonsIntersect(const ConstPolygonRef& poly_a, const ConstP bool PolygonUtils::polygonOutlinesAdjacent(const ConstPolygonRef inner_poly, const ConstPolygonRef outer_poly, const coord_t max_gap) { - //Heuristic check if their AABBs are near first. + // Heuristic check if their AABBs are near first. AABB inner_aabb(inner_poly); AABB outer_aabb(outer_poly); - inner_aabb.max += Point(max_gap, max_gap); //Expand one of them by way of a "distance" by checking intersection with the expanded rectangle. + inner_aabb.max += Point(max_gap, max_gap); // Expand one of them by way of a "distance" by checking intersection with the expanded rectangle. inner_aabb.min -= Point(max_gap, max_gap); - if (!inner_aabb.hit(outer_aabb)) + if (! inner_aabb.hit(outer_aabb)) { return false; } - //Heuristic says they are near. Now check for real. + // Heuristic says they are near. Now check for real. const coord_t max_gap2 = max_gap * max_gap; const unsigned outer_poly_size = outer_poly.size(); for (unsigned line_index = 0; line_index < outer_poly_size; ++line_index) @@ -1313,8 +1325,7 @@ void PolygonUtils::findAdjacentPolygons(std::vector& adjacent_poly_ind // given a polygon, and a vector of polygons, return a vector containing the indices of the polygons that are adjacent to the given polygon for (unsigned poly_idx = 0; poly_idx < possible_adjacent_polys.size(); ++poly_idx) { - if (polygonOutlinesAdjacent(poly, *possible_adjacent_polys[poly_idx], max_gap) || - polygonOutlinesAdjacent(*possible_adjacent_polys[poly_idx], poly, max_gap)) + if (polygonOutlinesAdjacent(poly, *possible_adjacent_polys[poly_idx], max_gap) || polygonOutlinesAdjacent(*possible_adjacent_polys[poly_idx], poly, max_gap)) { adjacent_poly_indices.push_back(poly_idx); } @@ -1327,31 +1338,31 @@ double PolygonUtils::relativeHammingDistance(const Polygons& poly_a, const Polyg const double area_b = std::abs(poly_b.area()); const double total_area = area_a + area_b; - //If the total area is 0.0, we'd get a division by zero. Instead, only return 0.0 if they are exactly equal. + // If the total area is 0.0, we'd get a division by zero. Instead, only return 0.0 if they are exactly equal. constexpr bool borders_allowed = true; - if(total_area == 0.0) + if (total_area == 0.0) { - for(const ConstPolygonRef& polygon_a : poly_a) + for (const ConstPolygonRef& polygon_a : poly_a) { - for(Point point : polygon_a) + for (Point point : polygon_a) { - if(!poly_b.inside(point, borders_allowed)) + if (! poly_b.inside(point, borders_allowed)) { return 1.0; } } } - for(const ConstPolygonRef& polygon_b : poly_b) + for (const ConstPolygonRef& polygon_b : poly_b) { - for(Point point : polygon_b) + for (Point point : polygon_b) { - if(!poly_a.inside(point, borders_allowed)) + if (! poly_a.inside(point, borders_allowed)) { return 1.0; } } } - return 0.0; //All points are inside the other polygon, regardless of where the vertices are along the edges. + return 0.0; // All points are inside the other polygon, regardless of where the vertices are along the edges. } const Polygons symmetric_difference = poly_a.xorPolygons(poly_b); @@ -1456,7 +1467,7 @@ void PolygonUtils::fixSelfIntersections(const coord_t epsilon, Polygons& thiss) const Point vec = LinearAlg2D::pointIsLeftOfLine(other, a, b) > 0 ? b - a : a - b; const coord_t len = vSize(vec); pt.X += (-vec.Y * move_dist) / len; - pt.Y += ( vec.X * move_dist) / len; + pt.Y += (vec.X * move_dist) / len; } } } @@ -1465,4 +1476,4 @@ void PolygonUtils::fixSelfIntersections(const coord_t epsilon, Polygons& thiss) ClipperLib::SimplifyPolygons(thiss.paths); } -}//namespace cura +} // namespace cura diff --git a/src/utils/socket.cpp b/src/utils/socket.cpp index 8538c088b9..8e6c7a722e 100644 --- a/src/utils/socket.cpp +++ b/src/utils/socket.cpp @@ -1,5 +1,5 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher #include #include @@ -7,19 +7,20 @@ #ifdef _WIN32 #include #else -#include +#include +#include #include +#include #include -#include -#include #endif +#include + #include "utils/socket.h" -#include "utils/logoutput.h" namespace cura { - + #ifdef _WIN32 bool wsaStartupDone = false; #endif @@ -29,11 +30,11 @@ ClientSocket::ClientSocket() sockfd = -1; #ifdef _WIN32 - if (!wsaStartupDone) + if (! wsaStartupDone) { WSADATA wsaData; memset(&wsaData, 0, sizeof(WSADATA)); - //WSAStartup needs to be called on windows before sockets can be used. Request version 1.1, which is supported on windows 98 and higher. + // WSAStartup needs to be called on windows before sockets can be used. Request version 1.1, which is supported on windows 98 and higher. WSAStartup(MAKEWORD(1, 1), &wsaData); wsaStartupDone = true; } @@ -44,8 +45,8 @@ void ClientSocket::connectTo(std::string host, int port) { struct sockaddr_in serv_addr; sockfd = socket(AF_INET, SOCK_STREAM, 0); - - memset(&serv_addr, '0', sizeof(serv_addr)); + + memset(&serv_addr, '0', sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); serv_addr.sin_addr.s_addr = inet_addr(host.c_str()); @@ -79,7 +80,7 @@ void ClientSocket::sendAll(const void* data, int length) if (sockfd == -1) return; const char* ptr = static_cast(data); - while(length > 0) + while (length > 0) { int n = send(sockfd, ptr, length, 0); if (n <= 0) @@ -111,7 +112,7 @@ void ClientSocket::recvAll(void* data, int length) if (sockfd == -1) return; char* ptr = static_cast(data); - while(length > 0) + while (length > 0) { int n = recv(sockfd, ptr, length, 0); if (n == 0) @@ -121,7 +122,7 @@ void ClientSocket::recvAll(void* data, int length) } if (n < 0) { - cura::logError("ClientSocket::recvAll error..."); + spdlog::error("ClientSocket::recvAll error..."); close(); return; } @@ -142,4 +143,4 @@ void ClientSocket::close() sockfd = -1; } -}//namespace cura \ No newline at end of file +} // namespace cura \ No newline at end of file