diff --git a/.clang-format b/.clang-format index 0e6ea30..1ae60dc 100644 --- a/.clang-format +++ b/.clang-format @@ -95,6 +95,7 @@ PenaltyBreakString: 600 PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 50 PenaltyReturnTypeOnItsOwnLine: 300 +PenaltyIndentedWhitespace: 10 PointerAlignment: Right ReflowComments: true SortIncludes: false diff --git a/CMakeLists.txt b/CMakeLists.txt index 63ff7f1..93b2c9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -616,7 +616,6 @@ if(SLIC3R_BUILD_TESTS) endif() -# Resources install target, configure fhs.hpp on UNIX if (WIN32) install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources") elseif (SLIC3R_FHS) @@ -636,10 +635,10 @@ elseif (SLIC3R_FHS) ) endforeach() install(DIRECTORY ${SLIC3R_RESOURCES_DIR}/udev/ DESTINATION lib/udev/rules.d) + target_compile_definitions(QIDISlicer PUBLIC SLIC3R_FHS SLIC3R_FHS_RESOURCES="${SLIC3R_FHS_RESOURCES}") else () install(FILES src/platform/unix/QIDISlicer.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/resources/applications) install(FILES src/platform/unix/QIDIGcodeviewer.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/resources/applications) install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources") endif () -configure_file(src/platform/unix/fhs.hpp.in ${LIBDIR_BIN}/platform/unix/fhs.hpp) diff --git a/src/CLI/CLI.hpp b/src/CLI/CLI.hpp new file mode 100644 index 0000000..f5a7f4b --- /dev/null +++ b/src/CLI/CLI.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include +#include + +#include "libslic3r/Model.hpp" +#include "CLI_DynamicPrintConfig.hpp" + +#ifdef SLIC3R_GUI +#include "slic3r/GUI/GUI_Init.hpp" +#endif + +namespace Slic3r::CLI +{ + // struct which is filled from comand line input + struct Data + { + Data(); + + CLI_DynamicPrintConfig input_config; + CLI_DynamicPrintConfig overrides_config; + CLI_DynamicPrintConfig transform_config; + CLI_DynamicPrintConfig misc_config; + CLI_DynamicPrintConfig actions_config; + + std::vector input_files; + + bool empty() { + return input_files.empty() + && input_config.empty() + && overrides_config.empty() + && transform_config.empty() + && actions_config.empty(); + } + }; + + // Implemented in PrintHelp.cpp + + void print_help(bool include_print_options = false, PrinterTechnology printer_technology = ptAny); + + // Implemented in Setup.cpp + + bool setup(Data& cli, int argc, char** argv); + + // Implemented in LoadPrintData.cpp + + PrinterTechnology get_printer_technology(const DynamicConfig& config); + bool load_print_data(std::vector& models, + DynamicPrintConfig& print_config, + PrinterTechnology& printer_technology, + Data& cli); + bool is_needed_post_processing(const DynamicPrintConfig& print_config); + + // Implemented in ProcessTransform.cpp + + bool process_transform(Data& cli, const DynamicPrintConfig& print_config, std::vector& models); + + // Implemented in ProcessActions.cpp + + bool has_full_config_from_profiles(const Data& cli); + bool process_profiles_sharing(const Data& cli); + bool process_actions(Data& cli, const DynamicPrintConfig& print_config, std::vector& models); + + // Implemented in GuiParams.cpp +#ifdef SLIC3R_GUI + // set data for init GUI parameters + // and return state of start_gui + bool init_gui_params(GUI::GUI_InitParams& gui_params, int argc, char** argv, Data& cli); + int start_gui_with_params(GUI::GUI_InitParams& params); + int start_as_gcode_viewer(GUI::GUI_InitParams& gui_params); +#endif + +} diff --git a/src/CLI/CLI_DynamicPrintConfig.hpp b/src/CLI/CLI_DynamicPrintConfig.hpp new file mode 100644 index 0000000..48aa947 --- /dev/null +++ b/src/CLI/CLI_DynamicPrintConfig.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include "libslic3r/Config.hpp" + +namespace Slic3r::CLI +{ +enum class Type +{ + Input, + Overrides, + Transformations, + Misc, + Actions, + Undef +}; + +class CLI_DynamicPrintConfig : public DynamicPrintConfig +{ +public: + CLI_DynamicPrintConfig() {} + CLI_DynamicPrintConfig(Type type, const ConfigDef* config_def) : + m_type (type), + m_config_def (config_def) {} + CLI_DynamicPrintConfig(const CLI_DynamicPrintConfig& other) : + DynamicPrintConfig(other), + m_type (other.type()), + m_config_def (other.def()) {} + + // Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here. + const ConfigDef* def() const override { return m_config_def; } + + // Verify whether the opt_key has not been obsoleted or renamed. + // Both opt_key and value may be modified by handle_legacy(). + // If the opt_key is no more valid in this version of Slic3r, opt_key is cleared by handle_legacy(). + // handle_legacy() is called internally by set_deserialize(). + void handle_legacy(t_config_option_key& opt_key, std::string& value) const override { + if (m_type == Type::Overrides) + DynamicPrintConfig::handle_legacy(opt_key, value); + } + + Type type() const { return m_type; } + +private: + Type m_type { Type::Undef }; + const ConfigDef* m_config_def { nullptr }; +}; +} diff --git a/src/CLI/GuiParams.cpp b/src/CLI/GuiParams.cpp new file mode 100644 index 0000000..2870922 --- /dev/null +++ b/src/CLI/GuiParams.cpp @@ -0,0 +1,144 @@ +#include + +#include +#include +#include + +#include "CLI.hpp" + +#ifdef SLIC3R_GUI + +namespace Slic3r::CLI { + +bool init_gui_params(GUI::GUI_InitParams& gui_params, int argc, char** argv, Data& cli) +{ + bool start_gui = false; + + gui_params.argc = argc; + gui_params.argv = argv; + gui_params.input_files = cli.input_files; + + if (cli.misc_config.has("opengl-aa")) { + start_gui = true; + gui_params.opengl_aa = true; + } + + // are we starting as gcodeviewer ? + if (cli.actions_config.has("gcodeviewer")) { + start_gui = true; + gui_params.start_as_gcodeviewer = true; + } +#ifndef _WIN32 + else { + // On Unix systems, the qidi-slicer binary may be symlinked to give the application a different meaning. + gui_params.start_as_gcodeviewer = boost::algorithm::iends_with(boost::filesystem::path(argv[0]).filename().string(), "gcodeviewer"); + } +#endif // _WIN32 + +#if !SLIC3R_OPENGL_ES + if (cli.misc_config.has("opengl-version")) { + const Semver opengl_minimum = Semver(3, 2, 0); + const std::string opengl_version_str = cli.misc_config.opt_string("opengl-version"); + boost::optional semver = Semver::parse(opengl_version_str); + if (semver.has_value() && (*semver) >= opengl_minimum) { + std::pair& version = gui_params.opengl_version; + version.first = semver->maj(); + version.second = semver->min(); + if (std::find(Slic3r::GUI::OpenGLVersions::core.begin(), Slic3r::GUI::OpenGLVersions::core.end(), std::make_pair(version.first, version.second)) == Slic3r::GUI::OpenGLVersions::core.end()) { + version = { 0, 0 }; + boost::nowide::cerr << "Required OpenGL version " << opengl_version_str << " not recognized.\n Option 'opengl-version' ignored." << std::endl; + } + } + else + boost::nowide::cerr << "Required OpenGL version " << opengl_version_str << " is invalid. Must be greater than or equal to " << + opengl_minimum.to_string() << "\n Option 'opengl-version' ignored." << std::endl; + start_gui = true; + } + + if (cli.misc_config.has("opengl-compatibility")) { + start_gui = true; + gui_params.opengl_compatibility_profile = true; + // reset version as compatibility profile always take the highest version + // supported by the graphic card + gui_params.opengl_version = std::make_pair(0, 0); + } + + if (cli.misc_config.has("opengl-debug")) { + start_gui = true; + gui_params.opengl_debug = true; + } +#endif // SLIC3R_OPENGL_ES + + if (cli.misc_config.has("delete-after-load")) { + gui_params.delete_after_load = true; + } + + if (!gui_params.start_as_gcodeviewer && !cli.input_config.has("load")) { + // Read input file(s) if any and check if can start GcodeViewer + if (cli.input_files.size() == 1 && is_gcode_file(cli.input_files[0]) && boost::filesystem::exists(cli.input_files[0])) + gui_params.start_as_gcodeviewer = true; + } + + if (has_full_config_from_profiles(cli)) { + gui_params.selected_presets = Slic3r::GUI::CLISelectedProfiles{ cli.input_config.opt_string("print-profile"), + cli.input_config.opt_string("printer-profile") , + cli.input_config.option("material-profile")->values }; + } + + if (!cli.overrides_config.empty()) + gui_params.extra_config = cli.overrides_config; + + if (cli.input_config.has("load")) + gui_params.load_configs = cli.input_config.option("load")->values; + + for (const std::string& file : cli.input_files) { + if (boost::starts_with(file, "qidislicer://")) { + gui_params.start_downloader = true; + gui_params.download_url = file; + break; + } + } + + return start_gui; +} + +int start_gui_with_params(GUI::GUI_InitParams& params) +{ +#if !defined(_WIN32) && !defined(__APPLE__) + // likely some linux / unix system + const char* display = boost::nowide::getenv("DISPLAY"); + // const char *wayland_display = boost::nowide::getenv("WAYLAND_DISPLAY"); + //if (! ((display && *display) || (wayland_display && *wayland_display))) { + if (!(display && *display)) { + // DISPLAY not set. + boost::nowide::cerr << "DISPLAY not set, GUI mode not available." << std::endl << std::endl; + print_help(false); + // Indicate an error. + return 1; + } +#endif // some linux / unix system + return Slic3r::GUI::GUI_Run(params); +} + +int start_as_gcode_viewer(GUI::GUI_InitParams& gui_params) +{ + if (gui_params.input_files.size() > 1) { + boost::nowide::cerr << "You can open only one .gcode file at a time in GCodeViewer" << std::endl; + return 1; + } + + if (!gui_params.input_files.empty()) { + const std::string& file = gui_params.input_files[0]; + if (!is_gcode_file(file) || !boost::filesystem::exists(file)) { + boost::nowide::cerr << "Input file isn't a .gcode file or doesn't exist. GCodeViewer can't be start." << std::endl; + return 1; + } + } + + return start_gui_with_params(gui_params); +} + +} +#else // SLIC3R_GUI + // If there is no GUI, we shall ignore the parameters. Remove them from the list. +#endif // SLIC3R_GUI \ No newline at end of file diff --git a/src/CLI/LoadPrintData.cpp b/src/CLI/LoadPrintData.cpp new file mode 100644 index 0000000..f74aa42 --- /dev/null +++ b/src/CLI/LoadPrintData.cpp @@ -0,0 +1,259 @@ +#include +#include +#include +#include + +#include +#include +#include + +#include "libslic3r/libslic3r.h" +#include "libslic3r/Config.hpp" +#include "libslic3r/GCode/PostProcessor.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/FileReader.hpp" + +#include "CLI/CLI.hpp" +#include "CLI/ProfilesSharingUtils.hpp" + +namespace Slic3r::CLI { + +PrinterTechnology get_printer_technology(const DynamicConfig &config) +{ + const ConfigOptionEnum *opt = config.option>("printer_technology"); + return (opt == nullptr) ? ptUnknown : opt->value; +} + +// may be "validate_and_apply_printer_technology" will be better? +static bool can_apply_printer_technology(PrinterTechnology& printer_technology, const PrinterTechnology& other_printer_technology) +{ + if (printer_technology == ptUnknown) { + printer_technology = other_printer_technology; + return true; + } + + bool invalid_other_pt = printer_technology != other_printer_technology && other_printer_technology != ptUnknown; + + if (invalid_other_pt) + boost::nowide::cerr << "Mixing configurations for FFF and SLA technologies" << std::endl; + + return !invalid_other_pt; +} + +static void print_config_substitutions(const ConfigSubstitutions& config_substitutions, const std::string& file) +{ + if (config_substitutions.empty()) + return; + boost::nowide::cout << "The following configuration values were substituted when loading \" << file << \":\n"; + for (const ConfigSubstitution& subst : config_substitutions) + boost::nowide::cout << "\tkey = \"" << subst.opt_def->opt_key << "\"\t loaded = \"" << subst.old_value << "\tsubstituted = \"" << subst.new_value->serialize() << "\"\n"; +} + +static bool load_print_config(DynamicPrintConfig &print_config, PrinterTechnology& printer_technology, const Data& cli) +{ + // first of all load configuration from "--load" if any + + if (cli.input_config.has("load")) { + + const std::vector& load_configs = cli.input_config.option("load")->values; + ForwardCompatibilitySubstitutionRule config_substitution_rule = cli.misc_config.option>("config_compatibility")->value; + + // load config files supplied via --load + for (auto const& file : load_configs) { + if (!boost::filesystem::exists(file)) { + if (cli.misc_config.has("ignore_nonexistent_config") && cli.misc_config.opt_bool("ignore_nonexistent_config")) { + continue; + } + else { + boost::nowide::cerr << "No such file: " << file << std::endl; + return false; + } + } + DynamicPrintConfig config; + ConfigSubstitutions config_substitutions; + try { + config_substitutions = config.load(file, config_substitution_rule); + } + catch (std::exception& ex) { + boost::nowide::cerr << "Error while reading config file \"" << file << "\": " << ex.what() << std::endl; + return false; + } + + if (!can_apply_printer_technology(printer_technology, get_printer_technology(config))) + return false; + + print_config_substitutions(config_substitutions, file); + + config.normalize_fdm(); + print_config.apply(config); + } + } + + // than apply other options from full print config if any is provided by prifiles set + + if (has_full_config_from_profiles(cli)) { + DynamicPrintConfig config; + // load config from profiles set + std::string errors = Slic3r::load_full_print_config(cli.input_config.opt_string("print-profile"), + cli.input_config.option("material-profile")->values, + cli.input_config.opt_string("printer-profile"), + config, printer_technology); + if (!errors.empty()) { + boost::nowide::cerr << "Error while loading config from profiles: " << errors << std::endl; + return false; + } + + if (!can_apply_printer_technology(printer_technology, get_printer_technology(config))) + return false; + + config.normalize_fdm(); + + // config is applied with print_config loaded before + config += std::move(print_config); + print_config = std::move(config); + } + + return true; +} + +static bool process_input_files(std::vector& models, DynamicPrintConfig& print_config, PrinterTechnology& printer_technology, Data& cli) +{ + for (const std::string& file : cli.input_files) { + if (boost::starts_with(file, "qidislicer://")) { + continue; + } + if (!boost::filesystem::exists(file)) { + boost::nowide::cerr << "No such file: " << file << std::endl; + return false; + } + + Model model; + try { + if (has_full_config_from_profiles(cli) || !FileReader::is_project_file(file)) { + // we have full banch of options from profiles set + // so, just load a geometry + model = FileReader::load_model(file); + } + else { + // load model and configuration from the file + DynamicPrintConfig config; + ConfigSubstitutionContext config_substitutions_ctxt(cli.misc_config.option>("config_compatibility")->value); + boost::optional qidislicer_generator_version; + + //FIXME should we check the version here? // | Model::LoadAttribute::CheckVersion ? + model = FileReader::load_model_with_config(file, &config, &config_substitutions_ctxt, qidislicer_generator_version, FileReader::LoadAttribute::AddDefaultInstances); + + if (!can_apply_printer_technology(printer_technology, get_printer_technology(config))) + return false; + + print_config_substitutions(config_substitutions_ctxt.substitutions, file); + + // config is applied with print_config loaded before + config += std::move(print_config); + print_config = std::move(config); + } + + // If model for slicing is loaded from 3mf file, then its geometry has to be used and arrange couldn't be apply for this model. + if (FileReader::is_project_file(file) && + (!cli.transform_config.has("dont_arrange") || !cli.transform_config.opt_bool("dont_arrange"))) { + //So, check a state of "dont_arrange" parameter and set it to true, if its value is false. + cli.transform_config.set_key_value("dont_arrange", new ConfigOptionBool(true)); + } + } + catch (std::exception& e) { + boost::nowide::cerr << file << ": " << e.what() << std::endl; + return false; + } + if (model.objects.empty()) { + boost::nowide::cerr << "Error: file is empty: " << file << std::endl; + continue; + } + models.push_back(model); + } + + return true; +} + +static bool finalize_print_config(DynamicPrintConfig& print_config, PrinterTechnology& printer_technology, const Data& cli) +{ + // Apply command line options to a more specific DynamicPrintConfig which provides normalize() + // (command line options override --load files or congiguration which is loaded prom profiles) + print_config.apply(cli.overrides_config, true); + // Normalizing after importing the 3MFs / AMFs + print_config.normalize_fdm(); + + if (printer_technology == ptUnknown) + printer_technology = cli.actions_config.has("export_sla") ? ptSLA : ptFFF; + print_config.option>("printer_technology", true)->value = printer_technology; + + // Initialize full print configs for both the FFF and SLA technologies. + FullPrintConfig fff_print_config; + SLAFullPrintConfig sla_print_config; + + // Synchronize the default parameters and the ones received on the command line. + if (printer_technology == ptFFF) { + fff_print_config.apply(print_config, true); + print_config.apply(fff_print_config, true); + } + else { + assert(printer_technology == ptSLA); + sla_print_config.output_filename_format.value = "[input_filename_base].sl1"; + + // The default bed shape should reflect the default display parameters + // and not the fff defaults. + double w = sla_print_config.display_width.getFloat(); + double h = sla_print_config.display_height.getFloat(); + sla_print_config.bed_shape.values = { Vec2d(0, 0), Vec2d(w, 0), Vec2d(w, h), Vec2d(0, h) }; + + sla_print_config.apply(print_config, true); + print_config.apply(sla_print_config, true); + } + + // validate print configuration + std::string validity = print_config.validate(); + if (!validity.empty()) { + boost::nowide::cerr << "Error: The composite configation is not valid: " << validity << std::endl; + return false; + } + + return true; +} + +bool load_print_data(std::vector& models, + DynamicPrintConfig& print_config, + PrinterTechnology& printer_technology, + Data& cli) +{ + if (!load_print_config(print_config, printer_technology, cli)) + return false; + + if (!process_input_files(models, print_config, printer_technology, cli)) + return false; + + if (!finalize_print_config(print_config, printer_technology, cli)) + return false; + + return true; +} + +bool is_needed_post_processing(const DynamicPrintConfig& print_config) +{ + if (print_config.has("post_process")) { + const std::vector& post_process = print_config.opt("post_process")->values; + if (!post_process.empty()) { + boost::nowide::cout << "\nA post-processing script has been detected in the config data:\n\n"; + for (const std::string& s : post_process) { + boost::nowide::cout << "> " << s << "\n"; + } + boost::nowide::cout << "\nContinue(Y/N) ? "; + char in; + boost::nowide::cin >> in; + if (in != 'Y' && in != 'y') + return true; + } + } + + return false; +} + +} \ No newline at end of file diff --git a/src/CLI/PrintHelp.cpp b/src/CLI/PrintHelp.cpp new file mode 100644 index 0000000..004ce39 --- /dev/null +++ b/src/CLI/PrintHelp.cpp @@ -0,0 +1,180 @@ +#include + +#include +#include +#include +#include + +#include "CLI.hpp" + +namespace Slic3r::CLI { + +static void print_help(const ConfigDef& config_def, bool show_defaults, std::function filter = [](const ConfigOptionDef &){ return true; }) +{ + + // prepare a function for wrapping text + auto wrap = [](const std::string& text, size_t line_length) -> std::string { + std::istringstream words(text); + std::ostringstream wrapped; + std::string word; + + if (words >> word) { + wrapped << word; + size_t space_left = line_length - word.length(); + while (words >> word) { + if (space_left < word.length() + 1) { + wrapped << '\n' << word; + space_left = line_length - word.length(); + } + else { + wrapped << ' ' << word; + space_left -= word.length() + 1; + } + } + } + return wrapped.str(); + }; + + // List of opt_keys that should be hidden from the CLI help. + const std::vector silent_options = { "webdev", "single_instance_on_url" }; + + // get the unique categories + std::set categories; + for (const auto& opt : config_def.options) { + const ConfigOptionDef& def = opt.second; + if (filter(def)) + categories.insert(def.category); + } + + for (const std::string& category : categories) { + if (category != "") { + boost::nowide::cout << category << ":" << std::endl; + } + else if (categories.size() > 1) { + boost::nowide::cout << "Misc options:" << std::endl; + } + + for (const auto& opt : config_def.options) { + const ConfigOptionDef& def = opt.second; + if (def.category != category || def.cli == ConfigOptionDef::nocli || !filter(def)) + continue; + + if (std::find(silent_options.begin(), silent_options.end(), opt.second.opt_key) != silent_options.end()) + continue; + + // get all possible variations: --foo, --foobar, -f... + std::vector cli_args = def.cli_args(opt.first); + if (cli_args.empty()) + continue; + + for (auto& arg : cli_args) { + arg.insert(0, (arg.size() == 1) ? "-" : "--"); + if (def.type == coFloat || def.type == coInt || def.type == coFloatOrPercent + || def.type == coFloats || def.type == coInts) { + arg += " N"; + } + else if (def.type == coPoint) { + arg += " X,Y"; + } + else if (def.type == coPoint3) { + arg += " X,Y,Z"; + } + else if (def.type == coString || def.type == coStrings) { + arg += " ABCD"; + } + } + + // left: command line options + const std::string cli = boost::algorithm::join(cli_args, ", "); + boost::nowide::cout << " " << std::left << std::setw(20) << cli; + + // right: option description + std::string descr = def.tooltip; + bool show_defaults_this = show_defaults || def.opt_key == "config_compatibility"; + if (show_defaults_this && def.default_value && def.type != coBool + && (def.type != coString || !def.default_value->serialize().empty())) { + descr += " ("; + if (!def.sidetext.empty()) { + descr += def.sidetext + ", "; + } + else if (def.enum_def && def.enum_def->has_values()) { + descr += boost::algorithm::join(def.enum_def->values(), ", ") + "; "; + } + descr += "default: " + def.default_value->serialize() + ")"; + } + + // wrap lines of description + descr = wrap(descr, 80); + std::vector lines; + boost::split(lines, descr, boost::is_any_of("\n")); + + // if command line options are too long, print description in new line + for (size_t i = 0; i < lines.size(); ++i) { + if (i == 0 && cli.size() > 19) + boost::nowide::cout << std::endl; + if (i > 0 || cli.size() > 19) + boost::nowide::cout << std::string(21, ' '); + boost::nowide::cout << lines[i] << std::endl; + } + } + } +} + +void print_help(bool include_print_options/* = false*/, PrinterTechnology printer_technology/* = ptAny*/) +{ + boost::nowide::cout + << SLIC3R_BUILD_ID << " " << "based on Slic3r" +#ifdef SLIC3R_GUI + << " (with GUI support)" +#else /* SLIC3R_GUI */ + << " (without GUI support)" +#endif /* SLIC3R_GUI */ + << std::endl + << "https://github.com/qiditech/QIDISlicer" << std::endl << std::endl + << "Usage: qidi-slicer [ INPUT ] [ OPTIONS ] [ ACTIONS ] [ TRANSFORM ] [ file.stl ... ]" << std::endl; + + boost::nowide::cout + << std::endl + << "Input:" << std::endl; + print_help(cli_input_config_def, false); + + boost::nowide::cout + << std::endl + << "Note: To load configuration from profiles, you need to set whole banch of presets" << std::endl; + + boost::nowide::cout + << std::endl + << "Actions:" << std::endl; + print_help(cli_actions_config_def, false); + + boost::nowide::cout + << std::endl + << "Transform options:" << std::endl; + print_help(cli_transform_config_def, false); + + boost::nowide::cout + << std::endl + << "Other options:" << std::endl; + print_help(cli_misc_config_def, false); + + boost::nowide::cout + << std::endl + << "Print options are processed in the following order:" << std::endl + << "\t1) Config keys from the command line, for example --fill-pattern=stars" << std::endl + << "\t (highest priority, overwrites everything below)" << std::endl + << "\t2) Config files loaded with --load" << std::endl + << "\t3) Config values loaded from 3mf files" << std::endl; + + if (include_print_options) { + boost::nowide::cout << std::endl; + print_help(print_config_def, true, [printer_technology](const ConfigOptionDef& def) + { return printer_technology == ptAny || def.printer_technology == ptAny || printer_technology == def.printer_technology; }); + } + else { + boost::nowide::cout + << std::endl + << "Run --help-fff / --help-sla to see the full listing of print options." << std::endl; + } +} + +} \ No newline at end of file diff --git a/src/CLI/ProcessActions.cpp b/src/CLI/ProcessActions.cpp new file mode 100644 index 0000000..14dd7ec --- /dev/null +++ b/src/CLI/ProcessActions.cpp @@ -0,0 +1,421 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libslic3r/libslic3r.h" +#if !SLIC3R_OPENGL_ES +#include +#endif // !SLIC3R_OPENGL_ES +#include "libslic3r/Config.hpp" +#include "libslic3r/Geometry.hpp" +#include "libslic3r/GCode/PostProcessor.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/Preset.hpp" +#include +#include "libslic3r/Print.hpp" +#include "libslic3r/SLAPrint.hpp" +#include "libslic3r/Format/AMF.hpp" +#include "libslic3r/Format/3mf.hpp" +#include "libslic3r/Format/STL.hpp" +#include "libslic3r/Format/OBJ.hpp" +#include "libslic3r/Format/SL1.hpp" +#include "libslic3r/miniz_extension.hpp" +#include "libslic3r/PNGReadWrite.hpp" +#include "libslic3r/MultipleBeds.hpp" +#include "libslic3r/BuildVolume.hpp" + +#include "CLI/CLI.hpp" +#include "CLI/ProfilesSharingUtils.hpp" + +#define STB_IMAGE_RESIZE_IMPLEMENTATION +#include "stb_image_resize2.h" + +namespace Slic3r::CLI { + +static bool has_profile_sharing_action(const Data& cli) +{ + return cli.actions_config.has("query-printer-models") || cli.actions_config.has("query-print-filament-profiles"); +} + +bool has_full_config_from_profiles(const Data& cli) +{ + const DynamicPrintConfig& input = cli.input_config; + return !has_profile_sharing_action(cli) && + (input.has("print-profile") && !input.opt_string("print-profile").empty() || + input.has("material-profile") && !input.option("material-profile")->values.empty() || + input.has("printer-profile") && !input.opt_string("printer-profile").empty()); +} + +bool process_profiles_sharing(const Data& cli) +{ + if (!has_profile_sharing_action(cli)) + return false; + + std::string ret; + + if (cli.actions_config.has("query-printer-models")) { + ret = Slic3r::get_json_printer_models(get_printer_technology(cli.overrides_config)); + } + else if (cli.actions_config.has("query-print-filament-profiles")) { + if (cli.input_config.has("printer-profile") && !cli.input_config.opt_string("printer-profile").empty()) { + const std::string printer_profile = cli.input_config.opt_string("printer-profile"); + ret = Slic3r::get_json_print_filament_profiles(printer_profile); + if (ret.empty()) { + boost::nowide::cerr << "query-print-filament-profiles error: Printer profile '" << printer_profile << + "' wasn't found among installed printers." << std::endl << + "Or the request can be wrong." << std::endl; + return true; + } + } + else { + boost::nowide::cerr << "query-print-filament-profiles error: This action requires set 'printer-profile' option" << std::endl; + return true; + } + } + + if (ret.empty()) { + boost::nowide::cerr << "Wrong request" << std::endl; + return true; + } + + // use --output when available + + if (cli.misc_config.has("output")) { + std::string cmdline_param = cli.misc_config.opt_string("output"); + // if we were supplied a directory, use it and append our automatically generated filename + boost::filesystem::path cmdline_path(cmdline_param); + boost::filesystem::path proposed_path = boost::filesystem::path(Slic3r::resources_dir()) / "out.json"; + if (boost::filesystem::is_directory(cmdline_path)) + proposed_path = (cmdline_path / proposed_path.filename()); + else if (cmdline_path.extension().empty()) + proposed_path = cmdline_path.replace_extension("json"); + else + proposed_path = cmdline_path; + const std::string file = proposed_path.string(); + + boost::nowide::ofstream c; + c.open(file, std::ios::out | std::ios::trunc); + c << ret << std::endl; + c.close(); + + boost::nowide::cout << "Output for your request is written into " << file << std::endl; + } + else + printf("%s", ret.c_str()); + + return true; +} + +namespace IO { + enum ExportFormat : int { + OBJ, + STL, + // SVG, + TMF, + Gcode + }; +} + +static std::string output_filepath(const Model& model, IO::ExportFormat format, const std::string& cmdline_param) +{ + std::string ext; + switch (format) { + case IO::OBJ: ext = ".obj"; break; + case IO::STL: ext = ".stl"; break; + case IO::TMF: ext = ".3mf"; break; + default: assert(false); break; + }; + auto proposed_path = boost::filesystem::path(model.propose_export_file_name_and_path(ext)); + // use --output when available + if (!cmdline_param.empty()) { + // if we were supplied a directory, use it and append our automatically generated filename + boost::filesystem::path cmdline_path(cmdline_param); + if (boost::filesystem::is_directory(cmdline_path)) + proposed_path = cmdline_path / proposed_path.filename(); + else + proposed_path = cmdline_path; + } + return proposed_path.string(); +} + +static bool export_models(std::vector& models, IO::ExportFormat format, const std::string& cmdline_param) +{ + for (Model& model : models) { + const std::string path = output_filepath(model, format, cmdline_param); + bool success = false; + switch (format) { + case IO::OBJ: success = Slic3r::store_obj(path.c_str(), &model); break; + case IO::STL: success = Slic3r::store_stl(path.c_str(), &model, true); break; + case IO::TMF: success = Slic3r::store_3mf(path.c_str(), &model, nullptr, false); break; + default: assert(false); break; + } + if (success) + std::cout << "File exported to " << path << std::endl; + else { + std::cerr << "File export to " << path << " failed" << std::endl; + return false; + } + } + return true; +} + + +static ThumbnailData resize_and_crop(const std::vector& data, int width, int height, int width_new, int height_new) { + ThumbnailData th; + + float scale_x = float(width_new) / width; + float scale_y = float(height_new) / height; + float scale = std::max(scale_x, scale_y); // Choose the larger scale to fill the box + int resized_width = int(width * scale); + int resized_height = int(height * scale); + + std::vector resized_rgba(resized_width * resized_height * 4); + stbir_resize_uint8_linear(data.data(), width, height, 4 * width, + resized_rgba.data(), resized_width, resized_height, 4 * resized_width, + STBIR_RGBA); + + th.set(width_new, height_new); + int crop_x = (resized_width - width_new) / 2; + int crop_y = (resized_height - height_new) / 2; + + for (int y = 0; y < height_new; ++y) { + std::memcpy(th.pixels.data() + y * width_new * 4, + resized_rgba.data() + ((y + crop_y) * resized_width + crop_x) * 4, + width_new * 4); + } + return th; +} + + +static std::function get_thumbnail_generator_cli(const std::string& filename) +{ + if (boost::iends_with(filename, ".3mf")) { + return [filename](const ThumbnailsParams& params) { + ThumbnailsList list_out; + + mz_zip_archive archive; + mz_zip_zero_struct(&archive); + + if (!open_zip_reader(&archive, filename)) + return list_out; + mz_uint num_entries = mz_zip_reader_get_num_files(&archive); + mz_zip_archive_file_stat stat; + + int index = mz_zip_reader_locate_file(&archive, "Metadata/thumbnail.png", nullptr, 0); + if (index < 0 || !mz_zip_reader_file_stat(&archive, index, &stat)) + return list_out; + std::string buffer; + buffer.resize(int(stat.m_uncomp_size)); + mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, buffer.data(), (size_t)stat.m_uncomp_size, 0); + if (res == 0) + return list_out; + close_zip_reader(&archive); + + std::vector data; + unsigned width = 0; + unsigned height = 0; + png::decode_png(buffer, data, width, height); + + { + // Flip the image vertically so it matches the convention in Thumbnails generator. + const int row_size = width * 4; // Each pixel is 4 bytes (RGBA) + std::vector temp_row(row_size); + for (int i = 0; i < height / 2; ++i) { + unsigned char* top_row = &data[i * row_size]; + unsigned char* bottom_row = &data[(height - i - 1) * row_size]; + std::copy(bottom_row, bottom_row + row_size, temp_row.begin()); + std::copy(top_row, top_row + row_size, bottom_row); + std::copy(temp_row.begin(), temp_row.end(), top_row); + } + } + + for (const Vec2d& size : params.sizes) { + Point isize(size); + list_out.push_back(resize_and_crop(data, width, height, isize.x(), isize.y())); + } + return list_out; + }; + } + + return [](const ThumbnailsParams&) ->ThumbnailsList { return {}; }; +} + +static void update_instances_outside_state(Model& model, const DynamicPrintConfig& config) +{ + Pointfs bed_shape = dynamic_cast(config.option("bed_shape"))->values; + BuildVolume build_volume(bed_shape, config.opt_float("max_print_height")); + s_multiple_beds.update_build_volume(BoundingBoxf(bed_shape)); + model.update_print_volume_state(build_volume); +} + +bool process_actions(Data& cli, const DynamicPrintConfig& print_config, std::vector& models) +{ + DynamicPrintConfig& actions = cli.actions_config; + DynamicPrintConfig& transform = cli.transform_config; + + // doesn't need any aditional input + + if (actions.has("help")) { + print_help(); + } + if (actions.has("help_fff")) { + print_help(true, ptFFF); + } + if (actions.has("help_sla")) { + print_help(true, ptSLA); + } + + if (actions.has("info")) { + if (models.empty()) { + boost::nowide::cerr << "error: cannot show info for empty models." << std::endl; + return 1; + } + // --info works on unrepaired model + for (Model& model : models) { + model.add_default_instances(); + model.print_info(); + } + } + + if (actions.has("save")) { + //FIXME check for mixing the FFF / SLA parameters. + // or better save fff_print_config vs. sla_print_config + print_config.save(actions.opt_string("save")); + } + + if (models.empty() && (actions.has("export_stl") || actions.has("export_obj") || actions.has("export_3mf"))) { + boost::nowide::cerr << "error: cannot export empty models." << std::endl; + return 1; + } + + const std::string output = cli.misc_config.has("output") ? cli.misc_config.opt_string("output") : ""; + + if (actions.has("export_stl")) { + for (auto& model : models) + model.add_default_instances(); + if (!export_models(models, IO::STL, output)) + return 1; + } + if (actions.has("export_obj")) { + for (auto& model : models) + model.add_default_instances(); + if (!export_models(models, IO::OBJ, output)) + return 1; + } + if (actions.has("export_3mf")) { + if (!export_models(models, IO::TMF, output)) + return 1; + } + + if (actions.has("slice") || actions.has("export_gcode") || actions.has("export_sla")) { + PrinterTechnology printer_technology = Preset::printer_technology(print_config); + if (actions.has("export_gcode") && printer_technology == ptSLA) { + boost::nowide::cerr << "error: cannot export G-code for an FFF configuration" << std::endl; + return 1; + } + else if (actions.has("export_sla") && printer_technology == ptFFF) { + boost::nowide::cerr << "error: cannot export SLA slices for a SLA configuration" << std::endl; + return 1; + } + + const Vec2crd gap{ s_multiple_beds.get_bed_gap() }; + arr2::ArrangeBed bed = arr2::to_arrange_bed(get_bed_shape(print_config), gap); + arr2::ArrangeSettings arrange_cfg; + arrange_cfg.set_distance_from_objects(min_object_distance(print_config)); + + for (Model& model : models) { + // If all objects have defined instances, their relative positions will be + // honored when printing (they will be only centered, unless --dont-arrange + // is supplied); if any object has no instances, it will get a default one + // and all instances will be rearranged (unless --dont-arrange is supplied). + if (!transform.has("dont_arrange") || !transform.opt_bool("dont_arrange")) { + if (transform.has("center")) { + Vec2d c = transform.option("center")->value; + arrange_objects(model, arr2::InfiniteBed{ scaled(c) }, arrange_cfg); + } + else + arrange_objects(model, bed, arrange_cfg); + } + + Print fff_print; + SLAPrint sla_print; + sla_print.set_status_callback( [](const PrintBase::SlicingStatus& s) { + if (s.percent >= 0) { // FIXME: is this sufficient? + printf("%3d%s %s\n", s.percent, "% =>", s.text.c_str()); + std::fflush(stdout); + } + }); + + PrintBase* print = (printer_technology == ptFFF) ? static_cast(&fff_print) : static_cast(&sla_print); + if (printer_technology == ptFFF) { + for (auto* mo : model.objects) + fff_print.auto_assign_extruders(mo); + } + + update_instances_outside_state(model, print_config); + MultipleBedsUtils::with_single_bed_model_fff(model, 0, [&print, &model, &print_config]() + { + print->apply(model, print_config); + }); + + std::string err = print->validate(); + if (!err.empty()) { + boost::nowide::cerr << err << std::endl; + return 1; + } + + std::string outfile = output; + + if (print->empty()) + boost::nowide::cout << "Nothing to print for " << outfile << " . Either the print is empty or no object is fully inside the print volume." << std::endl; + else + try { + std::string outfile_final; + print->process(); + if (printer_technology == ptFFF) { + // The outfile is processed by a PlaceholderParser. + const std::string input_file = fff_print.model().objects.empty() ? "" : fff_print.model().objects.front()->input_file; + outfile = fff_print.export_gcode(outfile, nullptr, get_thumbnail_generator_cli(input_file)); + outfile_final = fff_print.print_statistics().finalize_output_path(outfile); + } + else { + outfile = sla_print.output_filepath(outfile); + // We need to finalize the filename beforehand because the export function sets the filename inside the zip metadata + outfile_final = sla_print.print_statistics().finalize_output_path(outfile); + sla_print.export_print(outfile_final); + } + if (outfile != outfile_final) { + if (Slic3r::rename_file(outfile, outfile_final)) { + boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl; + return false; + } + outfile = outfile_final; + } + // Run the post-processing scripts if defined. + run_post_process_scripts(outfile, fff_print.full_print_config()); + boost::nowide::cout << "Slicing result exported to " << outfile << std::endl; + } + catch (const std::exception& ex) { + boost::nowide::cerr << ex.what() << std::endl; + return false; + } + + } + } + + return true; +} + +} \ No newline at end of file diff --git a/src/CLI/ProcessTransform.cpp b/src/CLI/ProcessTransform.cpp new file mode 100644 index 0000000..8029a74 --- /dev/null +++ b/src/CLI/ProcessTransform.cpp @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libslic3r/libslic3r.h" +#if !SLIC3R_OPENGL_ES +#include +#endif // !SLIC3R_OPENGL_ES +#include "libslic3r/Config.hpp" +#include "libslic3r/Geometry.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/ModelProcessing.hpp" +#include "libslic3r/CutUtils.hpp" +#include +#include "libslic3r/MultipleBeds.hpp" + +#include "CLI.hpp" + +namespace Slic3r::CLI { + +bool process_transform(Data& cli, const DynamicPrintConfig& print_config, std::vector& models) +{ + DynamicPrintConfig& transform = cli.transform_config; + DynamicPrintConfig& actions = cli.actions_config; + + const Vec2crd gap{ s_multiple_beds.get_bed_gap() }; + arr2::ArrangeBed bed = arr2::to_arrange_bed(get_bed_shape(print_config), gap); + arr2::ArrangeSettings arrange_cfg; + if (transform.has("merge") || transform.has("duplicate")) + arrange_cfg.set_distance_from_objects(min_object_distance(print_config)); + + if (transform.has("merge")) { + Model m; + + for (auto& model : models) + for (ModelObject* o : model.objects) + m.add_object(*o); + // Rearrange instances unless --dont-arrange is supplied + if (!transform.has("dont_arrange") && !transform.opt_bool("dont_arrange")) { + m.add_default_instances(); + if (actions.has("slice")) + arrange_objects(m, bed, arrange_cfg); + else + arrange_objects(m, arr2::InfiniteBed{}, arrange_cfg);//?????? + } + models.clear(); + models.emplace_back(std::move(m)); + } + + if (transform.has("duplicate")) { + for (auto& model : models) { + const bool all_objects_have_instances = std::none_of( + model.objects.begin(), model.objects.end(), + [](ModelObject* o) { return o->instances.empty(); } + ); + + int dups = transform.opt_int("duplicate"); + if (!all_objects_have_instances) model.add_default_instances(); + + try { + if (dups > 1) { + // if all input objects have defined position(s) apply duplication to the whole model + duplicate(model, size_t(dups), bed, arrange_cfg); + } + else { + arrange_objects(model, bed, arrange_cfg); + } + } + catch (std::exception& ex) { + boost::nowide::cerr << "error: " << ex.what() << std::endl; + return false; + } + } + } + if (transform.has("duplicate_grid")) { + std::vector& ints = transform.option("duplicate_grid")->values; + const int x = ints.size() > 0 ? ints.at(0) : 1; + const int y = ints.size() > 1 ? ints.at(1) : 1; + const double distance = print_config.opt_float("duplicate_distance"); + for (auto& model : models) + model.duplicate_objects_grid(x, y, (distance > 0) ? distance : 6); // TODO: this is not the right place for setting a default + } + + if (transform.has("center")) { + for (auto& model : models) { + model.add_default_instances(); + // this affects instances: + model.center_instances_around_point(transform.option("center")->value); + // this affects volumes: + //FIXME Vojtech: Who knows why the complete model should be aligned with Z as a single rigid body? + //model.align_to_ground(); + BoundingBoxf3 bbox; + for (ModelObject* model_object : model.objects) + // We are interested into the Z span only, therefore it is sufficient to measure the bounding box of the 1st instance only. + bbox.merge(model_object->instance_bounding_box(0, false)); + for (ModelObject* model_object : model.objects) + for (ModelInstance* model_instance : model_object->instances) + model_instance->set_offset(Z, model_instance->get_offset(Z) - bbox.min.z()); + } + } + + if (transform.has("align_xy")) { + const Vec2d& p = transform.option("align_xy")->value; + for (auto& model : models) { + BoundingBoxf3 bb = model.bounding_box_exact(); + // this affects volumes: + model.translate(-(bb.min.x() - p.x()), -(bb.min.y() - p.y()), -bb.min.z()); + } + } + + if (transform.has("rotate")) { + for (auto& model : models) + for (auto& o : model.objects) + // this affects volumes: + o->rotate(Geometry::deg2rad(transform.opt_float("rotate")), Z); + } + if (transform.has("rotate_x")) { + for (auto& model : models) + for (auto& o : model.objects) + // this affects volumes: + o->rotate(Geometry::deg2rad(transform.opt_float("rotate_x")), X); + } + if (transform.has("rotate_y")) { + for (auto& model : models) + for (auto& o : model.objects) + // this affects volumes: + o->rotate(Geometry::deg2rad(transform.opt_float("rotate_y")), Y); + } + + if (transform.has("scale")) { + for (auto& model : models) + for (auto& o : model.objects) + // this affects volumes: + o->scale(transform.get_abs_value("scale", 1)); + } + if (transform.has("scale_to_fit")) { + const Vec3d& opt = transform.opt("scale_to_fit")->value; + if (opt.x() <= 0 || opt.y() <= 0 || opt.z() <= 0) { + boost::nowide::cerr << "--scale-to-fit requires a positive volume" << std::endl; + return false; + } + for (auto& model : models) + for (auto& o : model.objects) + // this affects volumes: + o->scale_to_fit(opt); + } + + if (transform.has("cut")) { + std::vector new_models; + const Vec3d plane_center = transform.opt_float("cut") * Vec3d::UnitZ(); + for (auto& model : models) { + Model new_model; + model.translate(0, 0, -model.bounding_box_exact().min.z()); // align to z = 0 + size_t num_objects = model.objects.size(); + for (size_t i = 0; i < num_objects; ++i) { + ModelObject* mo = model.objects.front(); + const Vec3d cut_center_offset = plane_center - mo->instances[0]->get_offset(); + Cut cut(mo, 0, Geometry::translation_transform(cut_center_offset), + ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::PlaceOnCutUpper); + auto cut_objects = cut.perform_with_plane(); + for (ModelObject* obj : cut_objects) + new_model.add_object(*obj); + model.delete_object(size_t(0)); + } + new_models.push_back(new_model); + } + + // TODO: copy less stuff around using pointers + models = new_models; + + if (actions.empty()) { + // cutting transformations are setting an "export" action. + actions.set_key_value("export_stl", new ConfigOptionBool(true)); + } + } + + if (transform.has("split")) { + for (Model& model : models) { + size_t num_objects = model.objects.size(); + for (size_t i = 0; i < num_objects; ++i) { + ModelObjectPtrs new_objects; + ModelProcessing::split(model.objects.front(), &new_objects); + model.delete_object(size_t(0)); + } + } + } + + // All transforms have been dealt with. Now ensure that the objects are on bed. + // (Unless the user said otherwise.) + if (!transform.has("ensure_on_bed") || transform.opt_bool("ensure_on_bed")) + for (auto& model : models) + for (auto& o : model.objects) + o->ensure_on_bed(); + + return true; +} + +} \ No newline at end of file diff --git a/src/CLI/ProfilesSharingUtils.cpp b/src/CLI/ProfilesSharingUtils.cpp new file mode 100644 index 0000000..822972f --- /dev/null +++ b/src/CLI/ProfilesSharingUtils.cpp @@ -0,0 +1,584 @@ +#include "ProfilesSharingUtils.hpp" +#include "libslic3r/Utils.hpp" +#include "libslic3r/format.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/PresetBundle.hpp" +#include "libslic3r/Utils/DirectoriesUtils.hpp" +#include "libslic3r/Utils/JsonUtils.hpp" +#include "libslic3r/BuildVolume.hpp" + +#include + +namespace Slic3r { + +static bool load_preset_bundle_from_datadir(PresetBundle& preset_bundle) +{ + AppConfig app_config = AppConfig(AppConfig::EAppMode::Editor); + if (!app_config.exists()) { + BOOST_LOG_TRIVIAL(error) << "Configuration wasn't found. Check your 'datadir' value."; + return false; + } + + if (std::string error = app_config.load(); !error.empty()) { + BOOST_LOG_TRIVIAL(error) << Slic3r::format("Error parsing QIDISlicer config file, it is probably corrupted. " + "Try to manually delete the file to recover from the error. Your user profiles will not be affected." + "\n%1%\n%2%", app_config.config_path(), error); + return false; + } + + // just checking for existence of Slic3r::data_dir is not enough : it may be an empty directory + // supplied as argument to --datadir; in that case we should still run the wizard + preset_bundle.setup_directories(); + + std::string delayed_error_load_presets; + // Suppress the '- default -' presets. + preset_bundle.set_default_suppressed(app_config.get_bool("no_defaults")); + try { + auto preset_substitutions = preset_bundle.load_presets(app_config, ForwardCompatibilitySubstitutionRule::EnableSystemSilent); + if (!preset_substitutions.empty()) { + BOOST_LOG_TRIVIAL(error) << "Some substitutions are found during loading presets."; + return false; + } + + // Post-process vendor map to delete non-installed models/varians + + VendorMap& vendors = preset_bundle.vendors; + for (auto& [vendor_id, vendor_profile] : vendors) { + std::vector models; + + for (auto& printer_model : vendor_profile.models) { + std::vector variants; + + for (const auto& variant : printer_model.variants) { + // check if printer model with variant is intalled + if (app_config.get_variant(vendor_id, printer_model.id, variant.name)) + variants.push_back(variant); + } + + if (!variants.empty()) { + if (printer_model.variants.size() != variants.size()) + printer_model.variants = variants; + models.push_back(printer_model); + } + } + + if (!models.empty()) { + if (vendor_profile.models.size() != models.size()) + vendor_profile.models = models; + } + } + } + catch (const std::exception& ex) { + BOOST_LOG_TRIVIAL(error) << ex.what(); + return false; + } + + return true; +} + +namespace pt = boost::property_tree; +/* +struct PrinterAttr_ +{ + std::string model_name; + std::string variant; +}; + +static std::string get_printer_profiles(const VendorProfile* vendor_profile, + const PresetBundle* preset_bundle, + const PrinterAttr_& printer_attr) +{ + for (const auto& printer_model : vendor_profile->models) { + if (printer_model.name != printer_attr.model_name) + continue; + + for (const auto& variant : printer_model.variants) + if (variant.name == printer_attr.variant) + { + pt::ptree data_node; + data_node.put("printer_model", printer_model.name); + data_node.put("printer_variant", printer_attr.variant); + + pt::ptree printer_profiles_node; + for (const Preset& printer_preset : preset_bundle->printers) { + if (printer_preset.vendor->id == vendor_profile->id && + printer_preset.is_visible && // ??? + printer_preset.config.opt_string("printer_model") == printer_model.id && + printer_preset.config.opt_string("printer_variant") == printer_attr.variant) { + pt::ptree profile_node; + profile_node.put("", printer_preset.name); + printer_profiles_node.push_back(std::make_pair("", profile_node)); + } + } + data_node.add_child("printer_profiles", printer_profiles_node); + + // Serialize the tree into JSON and return it. + return write_json_with_post_process(data_node); + } + } + + return ""; +} + +std::string get_json_printer_profiles(const std::string& printer_model_name, const std::string& printer_variant) +{ + if (!is_datadir()) + return ""; + + PrinterAttr_ printer_attr({printer_model_name, printer_variant}); + + PresetBundle preset_bundle; + if (!load_preset_bundle_from_datadir(preset_bundle)) + return ""; + + const VendorMap& vendors = preset_bundle.vendors; + for (const auto& [vendor_id, vendor] : vendors) { + std::string out = get_printer_profiles(&vendor, &preset_bundle, printer_attr); + if (!out.empty()) + return out; + } + + return ""; +} +*/ + +struct PrinterAttr +{ + std::string vendor_id; + std::string model_id; + std::string variant_name; +}; + +static bool is_compatible_preset(const Preset& printer_preset, const PrinterAttr& attr) +{ + return printer_preset.vendor->id == attr.vendor_id && + printer_preset.config.opt_string("printer_model") == attr.model_id && + printer_preset.config.opt_string("printer_variant") == attr.variant_name; +} + +static void add_profile_node(pt::ptree& printer_profiles_node, const Preset& printer_preset) +{ + pt::ptree profile_node; + + const DynamicPrintConfig& config = printer_preset.config; + + int extruders_cnt = printer_preset.printer_technology() == ptSLA ? 0 : + config.option("nozzle_diameter")->values.size(); + + profile_node.put("name", printer_preset.name); + if (extruders_cnt > 0) + profile_node.put("extruders_cnt", extruders_cnt); + + const double max_print_height = config.opt_float("max_print_height"); + const ConfigOptionPoints& bed_shape = *config.option("bed_shape"); + + BuildVolume build_volume = BuildVolume { bed_shape.values, max_print_height }; + BoundingBoxf bb = build_volume.bounding_volume2d(); + + Vec2d origin_pt; + if (build_volume.type() == BuildVolume::Type::Circle) { + origin_pt = build_volume.bed_center(); + } + else { + origin_pt = to_2d(-1 * build_volume.bounding_volume().min); + } + std::string origin = Slic3r::format("[%1%, %2%]", is_approx(origin_pt.x(), 0.) ? 0 : origin_pt.x(), + is_approx(origin_pt.y(), 0.) ? 0 : origin_pt.y()); + + pt::ptree bed_node; + bed_node.put("type", build_volume.type_name()); + bed_node.put("width", bb.max.x() - bb.min.x()); + bed_node.put("height", bb.max.y() - bb.min.y()); + bed_node.put("origin", origin); + bed_node.put("max_print_height", max_print_height); + + profile_node.add_child("bed", bed_node); + + printer_profiles_node.push_back(std::make_pair("", profile_node)); +} + +static void get_printer_profiles_node(pt::ptree& printer_profiles_node, + pt::ptree& user_printer_profiles_node, + const PrinterPresetCollection& printer_presets, + const PrinterAttr& attr) +{ + printer_profiles_node.clear(); + user_printer_profiles_node.clear(); + + for (const Preset& printer_preset : printer_presets) { + if (!printer_preset.is_visible) + continue; + + if (printer_preset.is_user()) { + const Preset* parent_preset = printer_presets.get_preset_parent(printer_preset); + if (parent_preset && is_compatible_preset(*parent_preset, attr)) + add_profile_node(user_printer_profiles_node, printer_preset); + } + else if (is_compatible_preset(printer_preset, attr)) + add_profile_node(printer_profiles_node, printer_preset); + } +} + +static void add_printer_models(pt::ptree& vendor_node, + const VendorProfile* vendor_profile, + PrinterTechnology printer_technology, + const PrinterPresetCollection& printer_presets) +{ + for (const auto& printer_model : vendor_profile->models) { + if (printer_technology != ptUnknown && printer_model.technology != printer_technology) + continue; + + pt::ptree variants_node; + pt::ptree printer_profiles_node; + pt::ptree user_printer_profiles_node; + + if (printer_model.technology == ptSLA) { + PrinterAttr attr({ vendor_profile->id, printer_model.id, "default" }); + + get_printer_profiles_node(printer_profiles_node, user_printer_profiles_node, printer_presets, attr); + if (printer_profiles_node.empty() && user_printer_profiles_node.empty()) + continue; + } + else { + for (const auto& variant : printer_model.variants) { + + PrinterAttr attr({ vendor_profile->id, printer_model.id, variant.name }); + + get_printer_profiles_node(printer_profiles_node, user_printer_profiles_node, printer_presets, attr); + if (printer_profiles_node.empty() && user_printer_profiles_node.empty()) + continue; + + pt::ptree variant_node; + variant_node.put("name", variant.name); + variant_node.add_child("printer_profiles", printer_profiles_node); + if (!user_printer_profiles_node.empty()) + variant_node.add_child("user_printer_profiles", user_printer_profiles_node); + + variants_node.push_back(std::make_pair("", variant_node)); + } + + if (variants_node.empty()) + continue; + } + + pt::ptree data_node; + data_node.put("id", printer_model.id); + data_node.put("name", printer_model.name); + data_node.put("technology", printer_model.technology == ptFFF ? "FFF" : "SLA"); + + if (!variants_node.empty()) + data_node.add_child("variants", variants_node); + else { + data_node.add_child("printer_profiles", printer_profiles_node); + if (!user_printer_profiles_node.empty()) + data_node.add_child("user_printer_profiles", user_printer_profiles_node); + } + + data_node.put("vendor_name", vendor_profile->name); + data_node.put("vendor_id", vendor_profile->id); + + vendor_node.push_back(std::make_pair("", data_node)); + } +} + +static void add_undef_printer_models(pt::ptree& vendor_node, + PrinterTechnology printer_technology, + const PrinterPresetCollection& printer_presets) +{ + for (auto pt : { ptFFF, ptSLA }) { + if (printer_technology != ptUnknown && printer_technology != pt) + continue; + + pt::ptree printer_profiles_node; + for (const Preset& preset : printer_presets) { + if (!preset.is_visible || preset.printer_technology() != pt || + preset.vendor || printer_presets.get_preset_parent(preset)) + continue; + + add_profile_node(printer_profiles_node, preset); + } + + if (!printer_profiles_node.empty()) { + pt::ptree data_node; + data_node.put("id", ""); + data_node.put("technology", pt == ptFFF ? "FFF" : "SLA"); + data_node.add_child("printer_profiles", printer_profiles_node); + data_node.put("vendor_name", ""); + data_node.put("vendor_id", ""); + + vendor_node.push_back(std::make_pair("", data_node)); + } + } +} + +std::string get_json_printer_models(PrinterTechnology printer_technology) +{ + PresetBundle preset_bundle; + if (!load_preset_bundle_from_datadir(preset_bundle)) + return ""; + + pt::ptree vendor_node; + + const VendorMap& vendors_map = preset_bundle.vendors; + for (const auto& [vendor_id, vendor] : vendors_map) + add_printer_models(vendor_node, &vendor, printer_technology, preset_bundle.printers); + + // add printers with no vendor information + add_undef_printer_models(vendor_node, printer_technology, preset_bundle.printers); + + pt::ptree root; + root.add_child("printer_models", vendor_node); + + // Serialize the tree into JSON and return it. + return write_json_with_post_process(root); +} + +static std::string get_installed_print_and_filament_profiles(const PresetBundle* preset_bundle, const Preset* printer_preset) +{ + PrinterTechnology printer_technology = printer_preset->printer_technology(); + + pt::ptree print_profiles; + pt::ptree user_print_profiles; + + const PresetWithVendorProfile printer_preset_with_vendor_profile = preset_bundle->printers.get_preset_with_vendor_profile(*printer_preset); + + const PresetCollection& print_presets = printer_technology == ptFFF ? preset_bundle->prints : preset_bundle->sla_prints; + const PresetCollection& material_presets = printer_technology == ptFFF ? preset_bundle->filaments : preset_bundle->sla_materials; + const std::string material_node_name = printer_technology == ptFFF ? "filament_profiles" : "sla_material_profiles"; + + for (auto print_preset : print_presets) { + + const PresetWithVendorProfile print_preset_with_vendor_profile = print_presets.get_preset_with_vendor_profile(print_preset); + + if (is_compatible_with_printer(print_preset_with_vendor_profile, printer_preset_with_vendor_profile)) + { + pt::ptree materials_profile_node; + pt::ptree user_materials_profile_node; + + for (auto material_preset : material_presets) { + + // ?! check visible and no-template presets only + if (!material_preset.is_visible || (material_preset.vendor && material_preset.vendor->templates_profile)) + continue; + + const PresetWithVendorProfile material_preset_with_vendor_profile = material_presets.get_preset_with_vendor_profile(material_preset); + + if (is_compatible_with_printer(material_preset_with_vendor_profile, printer_preset_with_vendor_profile) && + is_compatible_with_print(material_preset_with_vendor_profile, print_preset_with_vendor_profile, printer_preset_with_vendor_profile)) { + pt::ptree material_node; + material_node.put("", material_preset.name); + if (material_preset.is_user()) + user_materials_profile_node.push_back(std::make_pair("", material_node)); + else + materials_profile_node.push_back(std::make_pair("", material_node)); + } + } + + pt::ptree print_profile_node; + print_profile_node.put("name", print_preset.name); + print_profile_node.add_child(material_node_name, materials_profile_node); + if (!user_materials_profile_node.empty()) + print_profile_node.add_child("user_" + material_node_name, user_materials_profile_node); + + if (print_preset.is_user()) + user_print_profiles.push_back(std::make_pair("", print_profile_node)); + else + print_profiles.push_back(std::make_pair("", print_profile_node)); + } + } + + if (print_profiles.empty() && user_print_profiles.empty()) + return ""; + + pt::ptree tree; + tree.put("printer_profile", printer_preset->name); + tree.add_child("print_profiles", print_profiles); + if (!user_print_profiles.empty()) + tree.add_child("user_print_profiles", user_print_profiles); + + // Serialize the tree into JSON and return it. + return write_json_with_post_process(tree); +} + +std::string get_json_print_filament_profiles(const std::string& printer_profile) +{ + PresetBundle preset_bundle; + if (load_preset_bundle_from_datadir(preset_bundle)) { + const Preset* preset = preset_bundle.printers.find_preset(printer_profile, false, false); + if (preset) + return get_installed_print_and_filament_profiles(&preset_bundle, preset); + } + + return ""; +} + +// Helper function for FS +bool load_full_print_config(const std::string& print_preset_name, const std::string& filament_preset_name, const std::string& printer_preset_name, DynamicPrintConfig& config) +{ + PresetBundle preset_bundle; + if (!load_preset_bundle_from_datadir(preset_bundle)){ + BOOST_LOG_TRIVIAL(error) << Slic3r::format("Failed to load data from the datadir '%1%'.", data_dir()); + return false; + } + + config = {}; + config.apply(FullPrintConfig::defaults()); + + bool is_failed{ false }; + + if (const Preset* print_preset = preset_bundle.prints.find_preset(print_preset_name)) + config.apply_only(print_preset->config, print_preset->config.keys()); + else { + BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Print profile '%1%' wasn't found.", print_preset_name); + is_failed |= true; + } + + if (const Preset* filament_preset = preset_bundle.filaments.find_preset(filament_preset_name)) + config.apply_only(filament_preset->config, filament_preset->config.keys()); + else { + BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Filament profile '%1%' wasn't found.", filament_preset_name); + is_failed |= true; + } + + if (const Preset* printer_preset = preset_bundle.printers.find_preset(printer_preset_name)) + config.apply_only(printer_preset->config, printer_preset->config.keys()); + else { + BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Printer profile '%1%' wasn't found.", printer_preset_name); + is_failed |= true; + } + + return !is_failed; +} + +// Helper function for load full config from installed presets by profile names +std::string load_full_print_config(const std::string& print_preset_name, + const std::vector& material_preset_names_in, + const std::string& printer_preset_name, + DynamicPrintConfig& config, + PrinterTechnology printer_technology /*= ptUnknown*/) +{ + // check entered profile names + + if (print_preset_name.empty() || + material_preset_names_in.empty() || + printer_preset_name.empty()) + return "Request is not completed. All of Print/Material/Printer profiles have to be entered"; + + // check preset bundle + + PresetBundle preset_bundle; + if (!load_preset_bundle_from_datadir(preset_bundle)) + return Slic3r::format("Failed to load data from the datadir '%1%'.", data_dir()); + + // check existance of required profiles + + std::string errors; + + const Preset* printer_preset = preset_bundle.printers.find_preset(printer_preset_name); + if (!printer_preset) + errors += "\n" + Slic3r::format("Printer profile '%1%' wasn't found.", printer_preset_name); + else if (printer_technology == ptUnknown) + printer_technology = printer_preset->printer_technology(); + else if (printer_technology != printer_preset->printer_technology()) + errors += "\n" + std::string("Printer technology of the selected printer preset is differs with required printer technology"); + + PresetCollection& print_presets = printer_technology == ptFFF ? preset_bundle.prints : preset_bundle.sla_prints; + + const Preset* print_preset = print_presets.find_preset(print_preset_name); + if (!print_preset) + errors += "\n" + Slic3r::format("Print profile '%1%' wasn't found.", print_preset_name); + + PresetCollection& material_presets = printer_technology == ptFFF ? preset_bundle.filaments : preset_bundle.sla_materials; + + auto check_material = [&material_presets] (const std::string& name, std::string& errors) -> void { + const Preset* material_preset = material_presets.find_preset(name); + if (!material_preset) + errors += "\n" + Slic3r::format("Material profile '%1%' wasn't found.", name); + }; + + check_material(material_preset_names_in.front(), errors); + if (material_preset_names_in.size() > 1) { + for (size_t idx = 1; idx < material_preset_names_in.size(); idx++) { + if (material_preset_names_in[idx] != material_preset_names_in.front()) + check_material(material_preset_names_in[idx], errors); + } + } + + if (!errors.empty()) + return errors; + + // check and update list of material presets + + std::vector material_preset_names = material_preset_names_in; + + if (printer_technology == ptSLA && material_preset_names.size() > 1) { + BOOST_LOG_TRIVIAL(warning) << "Note: More than one sla material profiles were entered. Extras material profiles will be ignored."; + material_preset_names.resize(1); + } + + if (printer_technology == ptFFF) { + const int extruders_count = int(static_cast(printer_preset->config.option("nozzle_diameter"))->values.size()); + if (extruders_count > int(material_preset_names.size())) { + BOOST_LOG_TRIVIAL(warning) << "Note: Less than needed filament profiles were entered. Missed filament profiles will be filled with first material."; + material_preset_names.reserve(extruders_count); + for (int i = extruders_count - material_preset_names.size(); i > 0; i--) + material_preset_names.push_back(material_preset_names.front()); + } + else if (extruders_count < int(material_preset_names.size())) { + BOOST_LOG_TRIVIAL(warning) << "Note: More than needed filament profiles were entered. Extras filament profiles will be ignored."; + material_preset_names.resize(extruders_count); + } + } + + // check profiles compatibility + + const PresetWithVendorProfile printer_preset_with_vendor_profile = preset_bundle.printers.get_preset_with_vendor_profile(*printer_preset); + const PresetWithVendorProfile print_preset_with_vendor_profile = print_presets.get_preset_with_vendor_profile(*print_preset); + + if (!is_compatible_with_printer(print_preset_with_vendor_profile, printer_preset_with_vendor_profile)) + errors += "\n" + Slic3r::format("Print profile '%1%' is not compatible with printer profile %2%.", print_preset_name, printer_preset_name); + + auto check_material_preset_compatibility = [&material_presets, printer_preset_name, print_preset_name, printer_preset_with_vendor_profile, print_preset_with_vendor_profile] + (const std::string& name, std::string& errors) -> void { + const Preset* material_preset = material_presets.find_preset(name); + const PresetWithVendorProfile material_preset_with_vendor_profile = material_presets.get_preset_with_vendor_profile(*material_preset); + + if (!is_compatible_with_printer(material_preset_with_vendor_profile, printer_preset_with_vendor_profile)) + errors += "\n" + Slic3r::format("Material profile '%1%' is not compatible with printer profile %2%.", name, printer_preset_name); + + if (!is_compatible_with_print(material_preset_with_vendor_profile, print_preset_with_vendor_profile, printer_preset_with_vendor_profile)) + errors += "\n" + Slic3r::format("Material profile '%1%' is not compatible with print profile %2%.", name, print_preset_name); + }; + + check_material_preset_compatibility(material_preset_names.front(), errors); + if (material_preset_names.size() > 1) { + for (size_t idx = 1; idx < material_preset_names.size(); idx++) { + if (material_preset_names[idx] != material_preset_names.front()) + check_material_preset_compatibility(material_preset_names[idx], errors); + } + } + + if (!errors.empty()) + return errors; + + // get full print configuration + + preset_bundle.printers.select_preset_by_name(printer_preset_name, true); + print_presets.select_preset_by_name(print_preset_name, true); + if (printer_technology == ptSLA) + material_presets.select_preset_by_name(material_preset_names.front(), true); + else if (printer_technology == ptFFF) { + auto& extruders_filaments = preset_bundle.extruders_filaments; + extruders_filaments.clear(); + for (size_t i = 0; i < material_preset_names.size(); ++i) + extruders_filaments.emplace_back(ExtruderFilaments(&preset_bundle.filaments, i, material_preset_names[i])); + if (extruders_filaments.size() == 1) + preset_bundle.filaments.select_preset_by_name(material_preset_names[0], false); + } + + config = preset_bundle.full_config(); + + return ""; +} + +} // namespace Slic3r diff --git a/src/CLI/ProfilesSharingUtils.hpp b/src/CLI/ProfilesSharingUtils.hpp new file mode 100644 index 0000000..42336d2 --- /dev/null +++ b/src/CLI/ProfilesSharingUtils.hpp @@ -0,0 +1,29 @@ +#ifndef slic3r_ProfilesSharingUtils_hpp_ +#define slic3r_ProfilesSharingUtils_hpp_ + +#include +#include "libslic3r/Config.hpp" + +namespace Slic3r { + +std::string get_json_printer_models(PrinterTechnology printer_technology); +//std::string get_json_printer_profiles(const std::string& printer_model, const std::string& printer_variant); +std::string get_json_print_filament_profiles(const std::string& printer_profile); + +class DynamicPrintConfig; +bool load_full_print_config(const std::string& print_preset, const std::string& filament_preset, const std::string& printer_preset, DynamicPrintConfig& out_config); + +// Load full print config into config +// Return value is always error string if any exists +// Note, that all appearing warnings are added into BOOST_LOG +// When printer_technology is set, then it will be compared with printer technology of the printer_profile and return the error, when they aren't the same +std::string load_full_print_config( const std::string& print_preset_name, + const std::vector& material_preset_names, + const std::string& printer_preset_name, + DynamicPrintConfig& config, + PrinterTechnology printer_technology = ptUnknown); + + +} // namespace Slic3r + +#endif // slic3r_ProfilesSharingUtils_hpp_ diff --git a/src/CLI/Run.cpp b/src/CLI/Run.cpp new file mode 100644 index 0000000..5fac7a2 --- /dev/null +++ b/src/CLI/Run.cpp @@ -0,0 +1,54 @@ +#include "../QIDISlicer.hpp" +#include "CLI.hpp" + +namespace Slic3r::CLI { + +int run(int argc, char** argv) +{ + Data cli; + if (!setup(cli, argc, argv)) + return 1; + + if (process_profiles_sharing(cli)) + return 1; + + bool start_gui = cli.empty() || (cli.actions_config.empty() && !cli.transform_config.has("cut")); + PrinterTechnology printer_technology = get_printer_technology(cli.overrides_config); + DynamicPrintConfig print_config = {}; + std::vector models; + +#ifdef SLIC3R_GUI + GUI::GUI_InitParams gui_params; + start_gui |= init_gui_params(gui_params, argc, argv, cli); + + if (gui_params.start_as_gcodeviewer) + return start_as_gcode_viewer(gui_params); +#endif + + if (!load_print_data(models, print_config, printer_technology, cli)) + return 1; + + if (!start_gui && is_needed_post_processing(print_config)) + return 0; + + if (!process_transform(cli, print_config, models)) + return 1; + + if (!process_actions(cli, print_config, models)) + return 1; + + if (start_gui) { +#ifdef SLIC3R_GUI + return start_gui_with_params(gui_params); +#else + // No GUI support. Just print out a help. + print_help(false); + // If started without a parameter, consider it to be OK, otherwise report an error code (no action etc). + return (argc == 0) ? 0 : 1; +#endif + } + + return 0; +} + +} \ No newline at end of file diff --git a/src/CLI/Setup.cpp b/src/CLI/Setup.cpp new file mode 100644 index 0000000..746c8ac --- /dev/null +++ b/src/CLI/Setup.cpp @@ -0,0 +1,337 @@ +#include +#include +#include +#include +#include +#include + +#include "libslic3r/libslic3r.h" +#include "libslic3r/Config.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Platform.hpp" +#include "libslic3r/Utils.hpp" +#include "libslic3r/Thread.hpp" +#include "libslic3r/BlacklistedLibraryCheck.hpp" +#include "libslic3r/Utils/DirectoriesUtils.hpp" + +#include "CLI.hpp" + +#ifdef SLIC3R_GUI +#include "slic3r/Utils/ServiceConfig.hpp" +#endif /* SLIC3R_GUI */ + + +namespace Slic3r::CLI { + +Data::Data() +{ + input_config = CLI_DynamicPrintConfig(Type::Input, &cli_input_config_def); + overrides_config = CLI_DynamicPrintConfig(Type::Overrides, &print_config_def); + transform_config = CLI_DynamicPrintConfig(Type::Transformations, &cli_transform_config_def); + misc_config = CLI_DynamicPrintConfig(Type::Misc, &cli_misc_config_def); + actions_config = CLI_DynamicPrintConfig(Type::Actions, &cli_actions_config_def); +} + +using opts_map = std::map >; + +static opts_map get_opts_map(const Data& data) +{ + opts_map ret; + + for (const CLI_DynamicPrintConfig* config : { &data.input_config , + &data.overrides_config, + &data.transform_config, + &data.misc_config , + &data.actions_config }) + { + for (const auto& oit : config->def()->options) + for (const std::string& t : oit.second.cli_args(oit.first)) + ret[t] = { oit.first , config->type()}; + } + + return ret; +} + +static CLI_DynamicPrintConfig* get_config(Data& data, Type type) +{ + for (CLI_DynamicPrintConfig* config : { &data.input_config , + &data.overrides_config, + &data.transform_config, + &data.misc_config , + &data.actions_config }) + { + if (type == config->type()) + return config; + } + + assert(false); + return nullptr; +} + +static bool read(Data& data, int argc, const char* const argv[]) +{ + // cache the CLI option => opt_key mapping + opts_map opts = get_opts_map(data); + + bool parse_options = true; + for (int i = 1; i < argc; ++i) { + std::string token = argv[i]; + // Store non-option arguments in the provided vector. + if (!parse_options || !boost::starts_with(token, "-")) { + data.input_files.push_back(token); + continue; + } +#ifdef __APPLE__ + if (boost::starts_with(token, "-psn_")) + // OSX launcher may add a "process serial number", for example "-psn_0_989382" to the command line. + // While it is supposed to be dropped since OSX 10.9, we will rather ignore it. + continue; +#endif /* __APPLE__ */ + // Stop parsing tokens as options when -- is supplied. + if (token == "--") { + parse_options = false; + continue; + } + // Remove leading dashes (one or two). + token.erase(token.begin(), token.begin() + (boost::starts_with(token, "--") ? 2 : 1)); + // Read value when supplied in the --key=value form. + std::string value; + { + size_t equals_pos = token.find("="); + if (equals_pos != std::string::npos) { + value = token.substr(equals_pos + 1); + token.erase(equals_pos); + } + } + // Look for the cli -> option mapping. + auto it = opts.find(token); + bool no = false; + if (it == opts.end()) { + // Remove the "no-" prefix used to negate boolean options. + std::string yes_token; + if (boost::starts_with(token, "no-")) { + yes_token = token.substr(3); + it = opts.find(yes_token); + no = true; + } + if (it == opts.end()) { + boost::nowide::cerr << "Unknown option --" << token.c_str() << std::endl; + return false; + } + if (no) + token = yes_token; + } + + const auto& [opt_key, type] = it->second; + + CLI_DynamicPrintConfig* config = get_config(data, type); + const ConfigOptionDef* optdef = config->option_def(opt_key); + assert(optdef); + + // If the option type expects a value and it was not already provided, + // look for it in the next token. + if (value.empty() && optdef->type != coBool && optdef->type != coBools) { + if (i == argc - 1) { + boost::nowide::cerr << "No value supplied for --" << token.c_str() << std::endl; + return false; + } + value = argv[++i]; + } + + if (no) { + assert(optdef->type == coBool || optdef->type == coBools); + if (!value.empty()) { + boost::nowide::cerr << "Boolean options negated by the --no- prefix cannot have a value." << std::endl; + return false; + } + } + + // Store the option value. + const bool existing = config->has(opt_key); + ConfigOption* opt_base = existing ? config->option(opt_key) : optdef->create_default_option(); + if (!existing) + config->set_key_value(opt_key, opt_base); + ConfigOptionVectorBase* opt_vector = opt_base->is_vector() ? static_cast(opt_base) : nullptr; + if (opt_vector) { + if (!existing) + // remove the default values + opt_vector->clear(); + // Vector values will be chained. Repeated use of a parameter will append the parameter or parameters + // to the end of the value. + if (opt_base->type() == coBools && value.empty()) + static_cast(opt_base)->values.push_back(!no); + else + // Deserialize any other vector value (ConfigOptionInts, Floats, Percents, Points) the same way + // they get deserialized from an .ini file. For ConfigOptionStrings, that means that the C-style unescape + // will be applied for values enclosed in quotes, while values non-enclosed in quotes are left to be + // unescaped by the calling shell. + opt_vector->deserialize(value, true); + } + else if (opt_base->type() == coBool) { + if (value.empty()) + static_cast(opt_base)->value = !no; + else + opt_base->deserialize(value); + } + else if (opt_base->type() == coString) { + // Do not unescape single string values, the unescaping is left to the calling shell. + static_cast(opt_base)->value = value; + } + else { + // Just bail out if the configuration value is not understood. + ConfigSubstitutionContext context(ForwardCompatibilitySubstitutionRule::Disable); + // Any scalar value of a type different from Bool and String. + if (!config->set_deserialize_nothrow(opt_key, value, context, false)) { + boost::nowide::cerr << "Invalid value supplied for --" << token.c_str() << std::endl; + return false; + } + } + } + + // normalize override options + if (!data.overrides_config.empty()) + data.overrides_config.normalize_fdm(); + + if (!data.misc_config.has("config_compatibility")) { + // "config_compatibility" can be used during the loading configuration + // So, if this option wasn't set, then initialise it from default value + const ConfigOptionDef* optdef = cli_misc_config_def.get("config_compatibility"); + ConfigOption* opt_with_def_value = optdef->create_default_option(); + if (opt_with_def_value) + data.misc_config.set_key_value("config_compatibility", opt_with_def_value); + } + + return true; +} + +static bool setup_common() +{ + // Mark the main thread for the debugger and for runtime checks. + set_current_thread_name("slic3r_main"); + // Save the thread ID of the main thread. + save_main_thread_id(); + +#ifdef __WXGTK__ + // On Linux, wxGTK has no support for Wayland, and the app crashes on + // startup if gtk3 is used. This env var has to be set explicitly to + // instruct the window manager to fall back to X server mode. + ::setenv("GDK_BACKEND", "x11", /* replace */ true); + + ::setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", /* replace */ false); + ::setenv("WEBKIT_DISABLE_DMABUF_RENDERER", "1", /* replace */ false); +#endif + + // Switch boost::filesystem to utf8. + try { + boost::nowide::nowide_filesystem(); + } + catch (const std::runtime_error& ex) { + std::string caption = std::string(SLIC3R_APP_NAME) + " Error"; + std::string text = std::string("An error occured while setting up locale.\n") + ( +#if !defined(_WIN32) && !defined(__APPLE__) + // likely some linux system + "You may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n" +#endif + SLIC3R_APP_NAME " will now terminate.\n\n") + ex.what(); +#if defined(_WIN32) && defined(SLIC3R_GUI) + MessageBoxA(NULL, text.c_str(), caption.c_str(), MB_OK | MB_ICONERROR); +#endif + boost::nowide::cerr << text.c_str() << std::endl; + return false; + } + + { + Slic3r::set_logging_level(1); + const char* loglevel = boost::nowide::getenv("SLIC3R_LOGLEVEL"); + if (loglevel != nullptr) { + if (loglevel[0] >= '0' && loglevel[0] <= '9' && loglevel[1] == 0) + set_logging_level(loglevel[0] - '0'); + else + boost::nowide::cerr << "Invalid SLIC3R_LOGLEVEL environment variable: " << loglevel << std::endl; + } + } + + // Detect the operating system flavor after SLIC3R_LOGLEVEL is set. + detect_platform(); + +#ifdef WIN32 + if (BlacklistedLibraryCheck::get_instance().perform_check()) { + std::wstring text = L"Following DLLs have been injected into the QIDISlicer process:\n\n"; + text += BlacklistedLibraryCheck::get_instance().get_blacklisted_string(); + text += L"\n\n" + L"QIDISlicer is known to not run correctly with these DLLs injected. " + L"We suggest stopping or uninstalling these services if you experience " + L"crashes or unexpected behaviour while using QIDISlicer.\n" + L"For example, ASUS Sonic Studio injects a Nahimic driver, which makes QIDISlicer " + L"to crash on a secondary monitor, see QIDISlicer github issue #5573"; + MessageBoxW(NULL, text.c_str(), L"Warning"/*L"Incopatible library found"*/, MB_OK); + } +#endif + + // See Invoking qidi-slicer from $PATH environment variable crashes #5542 + // boost::filesystem::path path_to_binary = boost::filesystem::system_complete(argv[0]); + boost::filesystem::path path_to_binary = boost::dll::program_location(); + + // Path from the Slic3r binary to its resources. +#ifdef __APPLE__ + // The application is packed in the .dmg archive as 'Slic3r.app/Contents/MacOS/Slic3r' + // The resources are packed to 'Slic3r.app/Contents/Resources' + boost::filesystem::path path_resources = boost::filesystem::canonical(path_to_binary).parent_path() / "../Resources"; +#elif defined _WIN32 + // The application is packed in the .zip archive in the root, + // The resources are packed to 'resources' + // Path from Slic3r binary to resources: + boost::filesystem::path path_resources = path_to_binary.parent_path() / "resources"; +#elif defined SLIC3R_FHS + // The application is packaged according to the Linux Filesystem Hierarchy Standard + // Resources are set to the 'Architecture-independent (shared) data', typically /usr/share or /usr/local/share + boost::filesystem::path path_resources = SLIC3R_FHS_RESOURCES; +#else + // The application is packed in the .tar.bz archive (or in AppImage) as 'bin/slic3r', + // The resources are packed to 'resources' + // Path from Slic3r binary to resources: + boost::filesystem::path path_resources = boost::filesystem::canonical(path_to_binary).parent_path() / "../resources"; +#endif + + set_resources_dir(path_resources.string()); + set_var_dir((path_resources / "icons").string()); + set_local_dir((path_resources / "localization").string()); + set_sys_shapes_dir((path_resources / "shapes").string()); + set_custom_gcodes_dir((path_resources / "custom_gcodes").string()); + + return true; +} + +bool setup(Data& cli, int argc, char** argv) +{ + if (!setup_common()) + return false; + + if (!read(cli, argc, argv)) { + // Separate error message reported by the CLI parser from the help. + boost::nowide::cerr << std::endl; + print_help(); + return false; + } + + if (cli.misc_config.has("loglevel")) + { + int loglevel = cli.misc_config.opt_int("loglevel"); + if (loglevel != 0) + set_logging_level(loglevel); + } + + if (cli.misc_config.has("threads")) + thread_count = cli.misc_config.opt_int("threads"); + + set_data_dir(cli.misc_config.has("datadir") ? cli.misc_config.opt_string("datadir") : get_default_datadir()); + +#ifdef SLIC3R_GUI + if (cli.misc_config.has("webdev")) { + Utils::ServiceConfig::instance().set_webdev_enabled(cli.misc_config.opt_bool("webdev")); + } +#endif + return true; +} + +} \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d0596cf..5306346 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,10 +18,12 @@ if (SLIC3R_ENABLE_FORMAT_STEP) add_subdirectory(occt_wrapper) endif () +add_subdirectory(slic3r-arrange) +add_subdirectory(slic3r-arrange-wrapper) +add_subdirectory(libseqarrange) + if (SLIC3R_GUI) add_subdirectory(libvgcode) - add_subdirectory(slic3r-arrange) - add_subdirectory(slic3r-arrange-wrapper) if(WIN32) message(STATUS "WXWIN environment set to: $ENV{WXWIN}") @@ -95,12 +97,38 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/QIDISlicer.rc.in ${CMAKE configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/QIDISlicer-gcodeviewer.rc.in ${CMAKE_CURRENT_BINARY_DIR}/QIDISlicer-gcodeviewer.rc @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/QIDISlicer.manifest.in ${CMAKE_CURRENT_BINARY_DIR}/QIDISlicer.manifest @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/osx/Info.plist.in ${CMAKE_CURRENT_BINARY_DIR}/Info.plist @ONLY) -if (WIN32) - add_library(QIDISlicer SHARED QIDISlicer.cpp QIDISlicer.hpp) -else () - add_executable(QIDISlicer QIDISlicer.cpp QIDISlicer.hpp) + +set(SLIC3R_CLI_SOURCES + QIDISlicer.hpp + CLI/CLI.hpp + CLI/CLI_DynamicPrintConfig.hpp + CLI/PrintHelp.cpp + CLI/Setup.cpp + CLI/LoadPrintData.cpp + CLI/ProcessTransform.cpp + CLI/ProcessActions.cpp + CLI/Run.cpp + CLI/ProfilesSharingUtils.cpp + CLI/ProfilesSharingUtils.hpp +) +if (SLIC3R_GUI) + list(APPEND SLIC3R_CLI_SOURCES + CLI/GuiParams.cpp + ) endif () +if (WIN32) + add_library(QIDISlicer SHARED QIDISlicer.cpp ${SLIC3R_CLI_SOURCES}) +else () + add_executable(QIDISlicer QIDISlicer.cpp ${SLIC3R_CLI_SOURCES}) +endif () + +foreach(_source IN ITEMS ${SLIC3R_CLI_SOURCES}) + get_filename_component(_source_path "${_source}" PATH) + string(REPLACE "/" "\\" _group_path "${_source_path}") + source_group("${_group_path}" FILES "${_source}") +endforeach() + if (MINGW) target_link_options(QIDISlicer PUBLIC "-Wl,-allow-multiple-definition") set_target_properties(QIDISlicer PROPERTIES PREFIX "") @@ -111,39 +139,38 @@ if (NOT WIN32 AND NOT APPLE) set_target_properties(QIDISlicer PROPERTIES OUTPUT_NAME "qidi-slicer") endif () -target_link_libraries(QIDISlicer libslic3r libcereal slic3r-arrange-wrapper) +target_link_libraries(QIDISlicer PRIVATE libslic3r libcereal slic3r-arrange-wrapper libseqarrange stb_image) if (APPLE) # add_compile_options(-stdlib=libc++) # add_definitions(-DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_NO_CXX11_RVALUE_REFERENCES -DBOOST_THREAD_USES_MOVE) # -liconv: boost links to libiconv by default - target_link_libraries(QIDISlicer "-liconv -framework IOKit" "-framework CoreFoundation" -lc++) + target_link_libraries(QIDISlicer PRIVATE "-liconv -framework IOKit" "-framework CoreFoundation" -lc++) elseif (MSVC) # Manifest is provided through QIDISlicer.rc, don't generate your own. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO") else () # Boost on Raspberry-Pi does not link to pthreads explicitely. - target_link_libraries(QIDISlicer ${CMAKE_DL_LIBS} -lstdc++ Threads::Threads) + target_link_libraries(QIDISlicer PRIVATE ${CMAKE_DL_LIBS} -lstdc++ Threads::Threads) endif () # Add the Slic3r GUI library, libcurl, OpenGL and GLU libraries. if (SLIC3R_GUI) -# target_link_libraries(QIDISlicer ws2_32 uxtheme setupapi libslic3r_gui ${wxWidgets_LIBRARIES}) -target_link_libraries(QIDISlicer libslic3r_gui) + target_link_libraries(QIDISlicer PRIVATE libslic3r_gui) if (MSVC) # Generate debug symbols even in release mode. target_link_options(QIDISlicer PUBLIC "$<$:/DEBUG>") - target_link_libraries(QIDISlicer user32.lib Setupapi.lib) + target_link_libraries(QIDISlicer PRIVATE user32.lib Setupapi.lib) elseif (MINGW) - target_link_libraries(QIDISlicer ws2_32 uxtheme setupapi) + target_link_libraries(QIDISlicer PRIVATE ws2_32 uxtheme setupapi) elseif (APPLE) - target_link_libraries(QIDISlicer "-framework OpenGL") + target_link_libraries(QIDISlicer PRIVATE "-framework OpenGL") else () - target_link_libraries(QIDISlicer -ldl) + target_link_libraries(QIDISlicer PRIVATE -ldl) endif () if (WIN32) find_library(PSAPI_LIB NAMES Psapi) - target_link_libraries(QIDISlicer ${PSAPI_LIB}) + target_link_libraries(QIDISlicer PRIVATE ${PSAPI_LIB}) endif () endif () diff --git a/src/QIDISlicer.cpp b/src/QIDISlicer.cpp index 9fa95d2..ded67ee 100644 --- a/src/QIDISlicer.cpp +++ b/src/QIDISlicer.cpp @@ -25,1157 +25,18 @@ #include #include #include -#include +#include + //B64 #include "nlohmann/json.hpp" #include #include #include -#include -#include -#include -#include -#include -#include -#include - -#include "unix/fhs.hpp" // Generated by CMake from ../platform/unix/fhs.hpp.in #include "libslic3r/libslic3r.h" -#if !SLIC3R_OPENGL_ES -#include -#endif // !SLIC3R_OPENGL_ES -#include "libslic3r/Config.hpp" -#include "libslic3r/Geometry.hpp" -#include "libslic3r/GCode/PostProcessor.hpp" -#include "libslic3r/Model.hpp" -#include "libslic3r/CutUtils.hpp" -#include -#include "libslic3r/Platform.hpp" -#include "libslic3r/Print.hpp" -#include "libslic3r/SLAPrint.hpp" -#include "libslic3r/TriangleMesh.hpp" -#include "libslic3r/Format/AMF.hpp" -#include "libslic3r/Format/3mf.hpp" -#include "libslic3r/Format/STL.hpp" -#include "libslic3r/Format/OBJ.hpp" -#include "libslic3r/Format/SL1.hpp" -#include "libslic3r/miniz_extension.hpp" -#include "libslic3r/PNGReadWrite.hpp" -#include "libslic3r/Utils.hpp" -#include "libslic3r/Thread.hpp" -#include "libslic3r/BlacklistedLibraryCheck.hpp" -#include "libslic3r/ProfilesSharingUtils.hpp" -#include "libslic3r/Utils/DirectoriesUtils.hpp" -#include "libslic3r/MultipleBeds.hpp" #include "QIDISlicer.hpp" -#ifdef SLIC3R_GUI - #include "slic3r/GUI/GUI_Init.hpp" - #include "slic3r/Utils/ServiceConfig.hpp" -#endif /* SLIC3R_GUI */ - -using namespace Slic3r; - -static PrinterTechnology get_printer_technology(const DynamicConfig &config) -{ - const ConfigOptionEnum *opt = config.option>("printer_technology"); - return (opt == nullptr) ? ptUnknown : opt->value; -} - -int CLI::run(int argc, char **argv) -{ - // Mark the main thread for the debugger and for runtime checks. - set_current_thread_name("slic3r_main"); - // Save the thread ID of the main thread. - save_main_thread_id(); - -#ifdef __WXGTK__ - // On Linux, wxGTK has no support for Wayland, and the app crashes on - // startup if gtk3 is used. This env var has to be set explicitly to - // instruct the window manager to fall back to X server mode. - ::setenv("GDK_BACKEND", "x11", /* replace */ true); - - // https://github.com/prusa3d/PrusaSlicer/issues/12969 - ::setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", /* replace */ false); - ::setenv("WEBKIT_DISABLE_DMABUF_RENDERER", "1", /* replace */ false); -#endif - - // Switch boost::filesystem to utf8. - try { - boost::nowide::nowide_filesystem(); - } catch (const std::runtime_error& ex) { - std::string caption = std::string(SLIC3R_APP_NAME) + " Error"; - std::string text = std::string("An error occured while setting up locale.\n") + ( -#if !defined(_WIN32) && !defined(__APPLE__) - // likely some linux system - "You may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n" -#endif - SLIC3R_APP_NAME " will now terminate.\n\n") + ex.what(); - #if defined(_WIN32) && defined(SLIC3R_GUI) - if (m_actions.empty()) - // Empty actions means Slicer is executed in the GUI mode. Show a GUI message. - MessageBoxA(NULL, text.c_str(), caption.c_str(), MB_OK | MB_ICONERROR); - #endif - boost::nowide::cerr << text.c_str() << std::endl; - return 1; - } - - if (! this->setup(argc, argv)) - return 1; - - m_extra_config.apply(m_config, true); - m_extra_config.normalize_fdm(); - - PrinterTechnology printer_technology = get_printer_technology(m_config); - - bool start_gui = m_actions.empty() && - // cutting transformations are setting an "export" action. - std::find(m_transforms.begin(), m_transforms.end(), "cut") == m_transforms.end() && - std::find(m_transforms.begin(), m_transforms.end(), "cut_x") == m_transforms.end() && - std::find(m_transforms.begin(), m_transforms.end(), "cut_y") == m_transforms.end(); - bool start_downloader = false; - bool delete_after_load = false; - std::string download_url; - bool start_as_gcodeviewer = -#ifdef _WIN32 - false; -#else - // On Unix systems, the qidi-slicer binary may be symlinked to give the application a different meaning. - boost::algorithm::iends_with(boost::filesystem::path(argv[0]).filename().string(), "gcodeviewer"); -#endif // _WIN32 - - const std::vector &load_configs = m_config.option("load", true)->values; - const ForwardCompatibilitySubstitutionRule config_substitution_rule = m_config.option>("config_compatibility", true)->value; - - // load config files supplied via --load - for (auto const &file : load_configs) { - if (! boost::filesystem::exists(file)) { - if (m_config.opt_bool("ignore_nonexistent_config")) { - continue; - } else { - boost::nowide::cerr << "No such file: " << file << std::endl; - return 1; - } - } - DynamicPrintConfig config; - ConfigSubstitutions config_substitutions; - try { - config_substitutions = config.load(file, config_substitution_rule); - } catch (std::exception &ex) { - boost::nowide::cerr << "Error while reading config file \"" << file << "\": " << ex.what() << std::endl; - return 1; - } - if (! config_substitutions.empty()) { - boost::nowide::cout << "The following configuration values were substituted when loading \" << file << \":\n"; - for (const ConfigSubstitution &subst : config_substitutions) - boost::nowide::cout << "\tkey = \"" << subst.opt_def->opt_key << "\"\t loaded = \"" << subst.old_value << "\tsubstituted = \"" << subst.new_value->serialize() << "\"\n"; - } - config.normalize_fdm(); - PrinterTechnology other_printer_technology = get_printer_technology(config); - if (printer_technology == ptUnknown) { - printer_technology = other_printer_technology; - } else if (printer_technology != other_printer_technology && other_printer_technology != ptUnknown) { - boost::nowide::cerr << "Mixing configurations for FFF and SLA technologies" << std::endl; - return 1; - } - m_print_config.apply(config); - } - - bool has_config_from_profiles = m_profiles_sharing.empty() && - (!m_config.opt_string("print-profile").empty() || - !m_config.option("material-profile")->values.empty() || - !m_config.opt_string("printer-profile").empty() ); - if (has_config_from_profiles && !check_and_load_input_profiles(printer_technology)) - return 1; - -#ifdef SLIC3R_GUI - if (m_config.has("webdev")) { - Utils::ServiceConfig::instance().set_webdev_enabled(m_config.opt_bool("webdev")); - } - std::vector::iterator it; - bool opengl_aa = false; - it = std::find(m_actions.begin(), m_actions.end(), "opengl-aa"); - if (it != m_actions.end()) { - start_gui = true; - opengl_aa = true; - m_actions.erase(it); - } -#if SLIC3R_OPENGL_ES - // are we starting as gcodeviewer ? - for (auto it = m_actions.begin(); it != m_actions.end(); ++it) { - if (*it == "gcodeviewer") { - start_gui = true; - start_as_gcodeviewer = true; - m_actions.erase(it); - break; - } - } -#else - std::pair opengl_version = { 0, 0 }; - bool opengl_debug = false; - bool opengl_compatibility_profile = false; - - // search for special keys into command line parameters - it = std::find(m_actions.begin(), m_actions.end(), "gcodeviewer"); - if (it != m_actions.end()) { - start_gui = true; - start_as_gcodeviewer = true; - m_actions.erase(it); - } - - it = std::find(m_actions.begin(), m_actions.end(), "opengl-version"); - if (it != m_actions.end()) { - const Semver opengl_minimum = Semver(3,2,0); - const std::string opengl_version_str = m_config.opt_string("opengl-version"); - boost::optional semver = Semver::parse(opengl_version_str); - if (semver.has_value() && (*semver) >= opengl_minimum ) { - opengl_version.first = semver->maj(); - opengl_version.second = semver->min(); - if (std::find(Slic3r::GUI::OpenGLVersions::core.begin(), Slic3r::GUI::OpenGLVersions::core.end(), std::make_pair(opengl_version.first, opengl_version.second)) == Slic3r::GUI::OpenGLVersions::core.end()) { - opengl_version = { 0, 0 }; - boost::nowide::cerr << "Required OpenGL version " << opengl_version_str << " not recognized.\n Option 'opengl-version' ignored." << std::endl; - } - } else - boost::nowide::cerr << "Required OpenGL version " << opengl_version_str << " is invalid. Must be greater than or equal to " << - opengl_minimum.to_string() << "\n Option 'opengl-version' ignored." << std::endl; - start_gui = true; - m_actions.erase(it); - } - - it = std::find(m_actions.begin(), m_actions.end(), "opengl-compatibility"); - if (it != m_actions.end()) { - start_gui = true; - opengl_compatibility_profile = true; - // reset version as compatibility profile always take the highest version - // supported by the graphic card - opengl_version = std::make_pair(0, 0); - m_actions.erase(it); - } - - it = std::find(m_actions.begin(), m_actions.end(), "opengl-debug"); - if (it != m_actions.end()) { - start_gui = true; - opengl_debug = true; - m_actions.erase(it); - } -#endif // SLIC3R_OPENGL_ES -#else // SLIC3R_GUI - // If there is no GUI, we shall ignore the parameters. Remove them from the list. - for (const std::string& s : { "opengl-version", "opengl-compatibility", "opengl-debug", "opengl-aa", "gcodeviewer" }) { - auto it = std::find(m_actions.cbegin(), m_actions.cend(), s); - if (it != m_actions.end()) { - boost::nowide::cerr << "Parameter '" << s << "' is ignored, this QIDISlicer build is CLI only." << std::endl; - m_actions.erase(it); - } - } -#endif // SLIC3R_GUI - - - // Read input file(s) if any. - for (const std::string& file : m_input_files) - if (is_gcode_file(file) && boost::filesystem::exists(file)) { - start_as_gcodeviewer = true; - break; - } - if (!start_as_gcodeviewer) { - for (const std::string& file : m_input_files) { - if (boost::starts_with(file, "qidislicer://")) { - start_downloader = true; - download_url = file; - continue; - } - if (!boost::filesystem::exists(file)) { - boost::nowide::cerr << "No such file: " << file << std::endl; - exit(1); - } - Model model; - try { - if (has_config_from_profiles) - model = Model::read_from_file(file, nullptr, nullptr, Model::LoadAttribute::AddDefaultInstances); - else { - // When loading an AMF or 3MF, config is imported as well, including the printer technology. - DynamicPrintConfig config; - ConfigSubstitutionContext config_substitutions(config_substitution_rule); - //FIXME should we check the version here? // | Model::LoadAttribute::CheckVersion ? - model = Model::read_from_file(file, &config, &config_substitutions, Model::LoadAttribute::AddDefaultInstances); - PrinterTechnology other_printer_technology = get_printer_technology(config); - if (printer_technology == ptUnknown) { - printer_technology = other_printer_technology; - } - else if (printer_technology != other_printer_technology && other_printer_technology != ptUnknown) { - boost::nowide::cerr << "Mixing configurations for FFF and SLA technologies" << std::endl; - return 1; - } - if (! config_substitutions.substitutions.empty()) { - boost::nowide::cout << "The following configuration values were substituted when loading \" << file << \":\n"; - for (const ConfigSubstitution& subst : config_substitutions.substitutions) - boost::nowide::cout << "\tkey = \"" << subst.opt_def->opt_key << "\"\t loaded = \"" << subst.old_value << "\tsubstituted = \"" << subst.new_value->serialize() << "\"\n"; - } - // config is applied to m_print_config before the current m_config values. - config += std::move(m_print_config); - m_print_config = std::move(config); - } - - // If model for slicing is loaded from 3mf file, then its geometry has to be used and arrange couldn't be apply for this model. - if ((boost::algorithm::iends_with(file, ".3mf") || boost::algorithm::iends_with(file, ".zip")) && !m_config.opt_bool("dont_arrange")) { - //So, check a state of "dont_arrange" parameter and set it to true, if its value is false. - m_config.set_key_value("dont_arrange", new ConfigOptionBool(true)); - } - } - catch (std::exception& e) { - boost::nowide::cerr << file << ": " << e.what() << std::endl; - return 1; - } - if (model.objects.empty()) { - boost::nowide::cerr << "Error: file is empty: " << file << std::endl; - continue; - } - m_models.push_back(model); - } - } - - if (!start_gui) { - const auto* post_process = m_print_config.opt("post_process"); - if (post_process != nullptr && !post_process->values.empty()) { - boost::nowide::cout << "\nA post-processing script has been detected in the config data:\n\n"; - for (const auto& s : post_process->values) { - boost::nowide::cout << "> " << s << "\n"; - } - boost::nowide::cout << "\nContinue(Y/N) ? "; - char in; - boost::nowide::cin >> in; - if (in != 'Y' && in != 'y') - return 0; - } - } - - // Apply command line options to a more specific DynamicPrintConfig which provides normalize() - // (command line options override --load files) - m_print_config.apply(m_extra_config, true); - // Normalizing after importing the 3MFs / AMFs - m_print_config.normalize_fdm(); - - if (printer_technology == ptUnknown) - printer_technology = std::find(m_actions.begin(), m_actions.end(), "export_sla") == m_actions.end() ? ptFFF : ptSLA; - m_print_config.option>("printer_technology", true)->value = printer_technology; - - // Initialize full print configs for both the FFF and SLA technologies. - FullPrintConfig fff_print_config; - SLAFullPrintConfig sla_print_config; - - // Synchronize the default parameters and the ones received on the command line. - if (printer_technology == ptFFF) { - fff_print_config.apply(m_print_config, true); - m_print_config.apply(fff_print_config, true); - } else { - assert(printer_technology == ptSLA); - sla_print_config.output_filename_format.value = "[input_filename_base].sl1"; - - // The default bed shape should reflect the default display parameters - // and not the fff defaults. - double w = sla_print_config.display_width.getFloat(); - double h = sla_print_config.display_height.getFloat(); - sla_print_config.bed_shape.values = { Vec2d(0, 0), Vec2d(w, 0), Vec2d(w, h), Vec2d(0, h) }; - - sla_print_config.apply(m_print_config, true); - m_print_config.apply(sla_print_config, true); - } - - { - std::string validity = m_print_config.validate(); - if (! validity.empty()) { - boost::nowide::cerr << "Error: The composite configation is not valid: " << validity << std::endl; - return 1; - } - } - - // Loop through transform options. - bool user_center_specified = false; - - const Vec2crd gap{s_multiple_beds.get_bed_gap()}; - arr2::ArrangeBed bed = arr2::to_arrange_bed(get_bed_shape(m_print_config), gap); - arr2::ArrangeSettings arrange_cfg; - arrange_cfg.set_distance_from_objects(min_object_distance(m_print_config)); - - for (auto const &opt_key : m_transforms) { - if (opt_key == "merge") { - Model m; - for (auto &model : m_models) - for (ModelObject *o : model.objects) - m.add_object(*o); - // Rearrange instances unless --dont-arrange is supplied - if (! m_config.opt_bool("dont_arrange")) { - m.add_default_instances(); - if (this->has_print_action()) - arrange_objects(m, bed, arrange_cfg); - else - arrange_objects(m, arr2::InfiniteBed{}, arrange_cfg); - } - m_models.clear(); - m_models.emplace_back(std::move(m)); - } else if (opt_key == "duplicate") { - for (auto &model : m_models) { - const bool all_objects_have_instances = std::none_of( - model.objects.begin(), model.objects.end(), - [](ModelObject* o){ return o->instances.empty(); } - ); - - int dups = m_config.opt_int("duplicate"); - if (!all_objects_have_instances) model.add_default_instances(); - - try { - if (dups > 1) { - // if all input objects have defined position(s) apply duplication to the whole model - duplicate(model, size_t(dups), bed, arrange_cfg); - } else { - arrange_objects(model, bed, arrange_cfg); - } - } catch (std::exception &ex) { - boost::nowide::cerr << "error: " << ex.what() << std::endl; - return 1; - } - } - } else if (opt_key == "duplicate_grid") { - std::vector &ints = m_config.option("duplicate_grid")->values; - const int x = ints.size() > 0 ? ints.at(0) : 1; - const int y = ints.size() > 1 ? ints.at(1) : 1; - const double distance = fff_print_config.duplicate_distance.value; - for (auto &model : m_models) - model.duplicate_objects_grid(x, y, (distance > 0) ? distance : 6); // TODO: this is not the right place for setting a default - } else if (opt_key == "center") { - user_center_specified = true; - for (auto &model : m_models) { - model.add_default_instances(); - // this affects instances: - model.center_instances_around_point(m_config.option("center")->value); - // this affects volumes: - //FIXME Vojtech: Who knows why the complete model should be aligned with Z as a single rigid body? - //model.align_to_ground(); - BoundingBoxf3 bbox; - for (ModelObject *model_object : model.objects) - // We are interested into the Z span only, therefore it is sufficient to measure the bounding box of the 1st instance only. - bbox.merge(model_object->instance_bounding_box(0, false)); - for (ModelObject *model_object : model.objects) - for (ModelInstance *model_instance : model_object->instances) - model_instance->set_offset(Z, model_instance->get_offset(Z) - bbox.min.z()); - } - } else if (opt_key == "align_xy") { - const Vec2d &p = m_config.option("align_xy")->value; - for (auto &model : m_models) { - BoundingBoxf3 bb = model.bounding_box_exact(); - // this affects volumes: - model.translate(-(bb.min.x() - p.x()), -(bb.min.y() - p.y()), -bb.min.z()); - } - } else if (opt_key == "dont_arrange") { - // do nothing - this option alters other transform options - } else if (opt_key == "ensure_on_bed") { - // do nothing, the value is used later - } else if (opt_key == "rotate") { - for (auto &model : m_models) - for (auto &o : model.objects) - // this affects volumes: - o->rotate(Geometry::deg2rad(m_config.opt_float(opt_key)), Z); - } else if (opt_key == "rotate_x") { - for (auto &model : m_models) - for (auto &o : model.objects) - // this affects volumes: - o->rotate(Geometry::deg2rad(m_config.opt_float(opt_key)), X); - } else if (opt_key == "rotate_y") { - for (auto &model : m_models) - for (auto &o : model.objects) - // this affects volumes: - o->rotate(Geometry::deg2rad(m_config.opt_float(opt_key)), Y); - } else if (opt_key == "scale") { - for (auto &model : m_models) - for (auto &o : model.objects) - // this affects volumes: - o->scale(m_config.get_abs_value(opt_key, 1)); - } else if (opt_key == "scale_to_fit") { - const Vec3d &opt = m_config.opt(opt_key)->value; - if (opt.x() <= 0 || opt.y() <= 0 || opt.z() <= 0) { - boost::nowide::cerr << "--scale-to-fit requires a positive volume" << std::endl; - return 1; - } - for (auto &model : m_models) - for (auto &o : model.objects) - // this affects volumes: - o->scale_to_fit(opt); - } else if (opt_key == "cut" || opt_key == "cut_x" || opt_key == "cut_y") { - std::vector new_models; - for (auto &model : m_models) { - model.translate(0, 0, -model.bounding_box_exact().min.z()); // align to z = 0 - size_t num_objects = model.objects.size(); - for (size_t i = 0; i < num_objects; ++ i) { - -#if 0 - if (opt_key == "cut_x") { - o->cut(X, m_config.opt_float("cut_x"), &out); - } else if (opt_key == "cut_y") { - o->cut(Y, m_config.opt_float("cut_y"), &out); - } else if (opt_key == "cut") { - o->cut(Z, m_config.opt_float("cut"), &out); - } -#else -// model.objects.front()->cut(0, m_config.opt_float("cut"), ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::FlipLower); - Cut cut(model.objects.front(), 0, Geometry::translation_transform(m_config.opt_float("cut") * Vec3d::UnitZ()), - ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::PlaceOnCutUpper); - auto cut_objects = cut.perform_with_plane(); - for (ModelObject* obj : cut_objects) - model.add_object(*obj); -#endif - model.delete_object(size_t(0)); - } - } - - // TODO: copy less stuff around using pointers - m_models = new_models; - - if (m_actions.empty()) - m_actions.push_back("export_stl"); - } -#if 0 - else if (opt_key == "cut_grid") { - std::vector new_models; - for (auto &model : m_models) { - TriangleMesh mesh = model.mesh(); - mesh.repair(); - - std::vector meshes = mesh.cut_by_grid(m_config.option("cut_grid")->value); - size_t i = 0; - for (TriangleMesh* m : meshes) { - Model out; - auto o = out.add_object(); - o->add_volume(*m); - o->input_file += "_" + std::to_string(i++); - delete m; - } - } - - // TODO: copy less stuff around using pointers - m_models = new_models; - - if (m_actions.empty()) - m_actions.push_back("export_stl"); - } -#endif - else if (opt_key == "split") { - for (Model &model : m_models) { - size_t num_objects = model.objects.size(); - for (size_t i = 0; i < num_objects; ++ i) { - ModelObjectPtrs new_objects; - model.objects.front()->split(&new_objects); - model.delete_object(size_t(0)); - } - } - } else if (opt_key == "repair") { - // Models are repaired by default. - //for (auto &model : m_models) - // model.repair(); - - } else if (opt_key == "delete-after-load") { - delete_after_load = true; - } else { - boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl; - return 1; - } - } - - // All transforms have been dealt with. Now ensure that the objects are on bed. - // (Unless the user said otherwise.) - if (m_config.opt_bool("ensure_on_bed")) - for (auto &model : m_models) - for (auto &o : model.objects) - o->ensure_on_bed(); - - // loop through action options - for (auto const &opt_key : m_actions) { - if (opt_key == "help") { - this->print_help(); - } else if (opt_key == "help_fff") { - this->print_help(true, ptFFF); - } else if (opt_key == "help_sla") { - this->print_help(true, ptSLA); - } else if (opt_key == "save") { - //FIXME check for mixing the FFF / SLA parameters. - // or better save fff_print_config vs. sla_print_config - m_print_config.save(m_config.opt_string("save")); - } else if (opt_key == "info") { - // --info works on unrepaired model - for (Model &model : m_models) { - model.add_default_instances(); - model.print_info(); - } - } else if (opt_key == "export_stl") { - for (auto &model : m_models) - model.add_default_instances(); - if (! this->export_models(IO::STL)) - return 1; - } else if (opt_key == "export_obj") { - for (auto &model : m_models) - model.add_default_instances(); - if (! this->export_models(IO::OBJ)) - return 1; - } else if (opt_key == "export_3mf") { - if (! this->export_models(IO::TMF)) - return 1; - } else if (opt_key == "export_gcode" || opt_key == "export_sla" || opt_key == "slice") { - if (opt_key == "export_gcode" && printer_technology == ptSLA) { - boost::nowide::cerr << "error: cannot export G-code for an FFF configuration" << std::endl; - return 1; - } else if (opt_key == "export_sla" && printer_technology == ptFFF) { - boost::nowide::cerr << "error: cannot export SLA slices for a SLA configuration" << std::endl; - return 1; - } - // Make a copy of the model if the current action is not the last action, as the model may be - // modified by the centering and such. - Model model_copy; - bool make_copy = &opt_key != &m_actions.back(); - for (Model &model_in : m_models) { - if (make_copy) - model_copy = model_in; - Model &model = make_copy ? model_copy : model_in; - // If all objects have defined instances, their relative positions will be - // honored when printing (they will be only centered, unless --dont-arrange - // is supplied); if any object has no instances, it will get a default one - // and all instances will be rearranged (unless --dont-arrange is supplied). - std::string outfile = m_config.opt_string("output"); - Print fff_print; - SLAPrint sla_print; - sla_print.set_status_callback( - [](const PrintBase::SlicingStatus& s) - { - if(s.percent >= 0) { // FIXME: is this sufficient? - printf("%3d%s %s\n", s.percent, "% =>", s.text.c_str()); - std::fflush(stdout); - } - }); - - PrintBase *print = (printer_technology == ptFFF) ? static_cast(&fff_print) : static_cast(&sla_print); - if (! m_config.opt_bool("dont_arrange")) { - if (user_center_specified) { - Vec2d c = m_config.option("center")->value; - arrange_objects(model, arr2::InfiniteBed{scaled(c)}, arrange_cfg); - } else - arrange_objects(model, bed, arrange_cfg); - } - if (printer_technology == ptFFF) { - for (auto* mo : model.objects) - fff_print.auto_assign_extruders(mo); - } - print->apply(model, m_print_config); - std::string err = print->validate(); - if (! err.empty()) { - boost::nowide::cerr << err << std::endl; - return 1; - } - if (print->empty()) - boost::nowide::cout << "Nothing to print for " << outfile << " . Either the print is empty or no object is fully inside the print volume." << std::endl; - else - try { - std::string outfile_final; - print->process(); - if (printer_technology == ptFFF) { - - - - - - std::function thumbnail_generator_cli; - if (!fff_print.model().objects.empty() && boost::iends_with(fff_print.model().objects.front()->input_file, ".3mf")) { - std::string filename = fff_print.model().objects.front()->input_file; - thumbnail_generator_cli = [filename](const ThumbnailsParams&) { - ThumbnailsList list_out; - - mz_zip_archive archive; - mz_zip_zero_struct(&archive); - - if (!open_zip_reader(&archive, filename)) - return list_out; - mz_uint num_entries = mz_zip_reader_get_num_files(&archive); - mz_zip_archive_file_stat stat; - - int index = mz_zip_reader_locate_file(&archive, "Metadata/thumbnail.png", nullptr, 0); - if (index < 0 || !mz_zip_reader_file_stat(&archive, index, &stat)) - return list_out; - std::string buffer; - buffer.resize(int(stat.m_uncomp_size)); - mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, buffer.data(), (size_t)stat.m_uncomp_size, 0); - if (res == 0) - return list_out; - close_zip_reader(&archive); - - std::vector data; - unsigned width = 0; - unsigned height = 0; - png::decode_png(buffer, data, width, height); - - { - // Flip the image vertically so it matches the convention in Thumbnails generator. - const int row_size = width * 4; // Each pixel is 4 bytes (RGBA) - std::vector temp_row(row_size); - for (int i = 0; i < height / 2; ++i) { - unsigned char* top_row = &data[i * row_size]; - unsigned char* bottom_row = &data[(height - i - 1) * row_size]; - std::copy(bottom_row, bottom_row + row_size, temp_row.begin()); - std::copy(top_row, top_row + row_size, bottom_row); - std::copy(temp_row.begin(), temp_row.end(), top_row); - } - } - - ThumbnailData th; - th.set(width, height); - th.pixels = data; - list_out.push_back(th); - return list_out; - }; - } - - - - - // The outfile is processed by a PlaceholderParser. - outfile = fff_print.export_gcode(outfile, nullptr, thumbnail_generator_cli); - outfile_final = fff_print.print_statistics().finalize_output_path(outfile); - } else { - outfile = sla_print.output_filepath(outfile); - // We need to finalize the filename beforehand because the export function sets the filename inside the zip metadata - outfile_final = sla_print.print_statistics().finalize_output_path(outfile); - sla_print.export_print(outfile_final); - } - if (outfile != outfile_final) { - if (Slic3r::rename_file(outfile, outfile_final)) { - boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl; - return 1; - } - outfile = outfile_final; - } - // Run the post-processing scripts if defined. - run_post_process_scripts(outfile, fff_print.full_print_config()); - boost::nowide::cout << "Slicing result exported to " << outfile << std::endl; - } catch (const std::exception &ex) { - boost::nowide::cerr << ex.what() << std::endl; - return 1; - } -/* - print.center = ! m_config.has("center") - && ! m_config.has("align_xy") - && ! m_config.opt_bool("dont_arrange"); - print.set_model(model); - - // start chronometer - typedef std::chrono::high_resolution_clock clock_; - typedef std::chrono::duration > second_; - std::chrono::time_point t0{ clock_::now() }; - - const std::string outfile = this->output_filepath(model, IO::Gcode); - try { - print.export_gcode(outfile); - } catch (std::runtime_error &e) { - boost::nowide::cerr << e.what() << std::endl; - return 1; - } - boost::nowide::cout << "G-code exported to " << outfile << std::endl; - - // output some statistics - double duration { std::chrono::duration_cast(clock_::now() - t0).count() }; - boost::nowide::cout << std::fixed << std::setprecision(0) - << "Done. Process took " << (duration/60) << " minutes and " - << std::setprecision(3) - << std::fmod(duration, 60.0) << " seconds." << std::endl - << std::setprecision(2) - << "Filament required: " << print.total_used_filament() << "mm" - << " (" << print.total_extruded_volume()/1000 << "cm3)" << std::endl; -*/ - } - } else { - boost::nowide::cerr << "error: option not supported yet: " << opt_key << std::endl; - return 1; - } - } - - if (processed_profiles_sharing()) - return 1; - - if (start_gui) { -#ifdef SLIC3R_GUI - #if !defined(_WIN32) && !defined(__APPLE__) - // likely some linux / unix system - const char *display = boost::nowide::getenv("DISPLAY"); - // const char *wayland_display = boost::nowide::getenv("WAYLAND_DISPLAY"); - //if (! ((display && *display) || (wayland_display && *wayland_display))) { - if (! (display && *display)) { - // DISPLAY not set. - boost::nowide::cerr << "DISPLAY not set, GUI mode not available." << std::endl << std::endl; - this->print_help(false); - // Indicate an error. - return 1; - } - #endif // some linux / unix system - Slic3r::GUI::GUI_InitParams params; - params.argc = argc; - params.argv = argv; - params.load_configs = load_configs; - params.extra_config = std::move(m_extra_config); - params.input_files = std::move(m_input_files); - if (has_config_from_profiles && params.input_files.empty()) { - params.selected_presets = Slic3r::GUI::CLISelectedProfiles{ m_config.opt_string("print-profile"), - m_config.opt_string("printer-profile") , - m_config.option("material-profile")->values }; - } - params.start_as_gcodeviewer = start_as_gcodeviewer; - params.start_downloader = start_downloader; - params.download_url = download_url; - params.delete_after_load = delete_after_load; - params.opengl_aa = opengl_aa; -#if !SLIC3R_OPENGL_ES - params.opengl_version = opengl_version; - params.opengl_debug = opengl_debug; - params.opengl_compatibiity_profile = opengl_compatibility_profile; -#endif // !SLIC3R_OPENGL_ES - return Slic3r::GUI::GUI_Run(params); -#else // SLIC3R_GUI - // No GUI support. Just print out a help. - this->print_help(false); - // If started without a parameter, consider it to be OK, otherwise report an error code (no action etc). - return (argc == 0) ? 0 : 1; -#endif // SLIC3R_GUI - } - - return 0; -} - -bool CLI::setup(int argc, char **argv) -{ - { - Slic3r::set_logging_level(1); - const char *loglevel = boost::nowide::getenv("SLIC3R_LOGLEVEL"); - if (loglevel != nullptr) { - if (loglevel[0] >= '0' && loglevel[0] <= '9' && loglevel[1] == 0) - set_logging_level(loglevel[0] - '0'); - else - boost::nowide::cerr << "Invalid SLIC3R_LOGLEVEL environment variable: " << loglevel << std::endl; - } - } - - // Detect the operating system flavor after SLIC3R_LOGLEVEL is set. - detect_platform(); - -#ifdef WIN32 - // Notify user that a blacklisted DLL was injected into QIDISlicer process (for example Nahimic, see GH #5573). - // We hope that if a DLL is being injected into a QIDISlicer process, it happens at the very start of the application, - // thus we shall detect them now. - if (BlacklistedLibraryCheck::get_instance().perform_check()) { - std::wstring text = L"Following DLLs have been injected into the QIDISlicer process:\n\n"; - text += BlacklistedLibraryCheck::get_instance().get_blacklisted_string(); - text += L"\n\n" - L"QIDISlicer is known to not run correctly with these DLLs injected. " - L"We suggest stopping or uninstalling these services if you experience " - L"crashes or unexpected behaviour while using QIDISlicer.\n" - L"For example, ASUS Sonic Studio injects a Nahimic driver, which makes QIDISlicer " - L"to crash on a secondary monitor, see QIDISlicer github issue #5573"; - MessageBoxW(NULL, text.c_str(), L"Warning"/*L"Incopatible library found"*/, MB_OK); - } -#endif - - // See Invoking qidi-slicer from $PATH environment variable crashes #5542 - // boost::filesystem::path path_to_binary = boost::filesystem::system_complete(argv[0]); - boost::filesystem::path path_to_binary = boost::dll::program_location(); - - // Path from the Slic3r binary to its resources. -#ifdef __APPLE__ - // The application is packed in the .dmg archive as 'Slic3r.app/Contents/MacOS/Slic3r' - // The resources are packed to 'Slic3r.app/Contents/Resources' - boost::filesystem::path path_resources = boost::filesystem::canonical(path_to_binary).parent_path() / "../Resources"; -#elif defined _WIN32 - // The application is packed in the .zip archive in the root, - // The resources are packed to 'resources' - // Path from Slic3r binary to resources: - boost::filesystem::path path_resources = path_to_binary.parent_path() / "resources"; -#elif defined SLIC3R_FHS - // The application is packaged according to the Linux Filesystem Hierarchy Standard - // Resources are set to the 'Architecture-independent (shared) data', typically /usr/share or /usr/local/share - boost::filesystem::path path_resources = SLIC3R_FHS_RESOURCES; -#else - // The application is packed in the .tar.bz archive (or in AppImage) as 'bin/slic3r', - // The resources are packed to 'resources' - // Path from Slic3r binary to resources: - boost::filesystem::path path_resources = boost::filesystem::canonical(path_to_binary).parent_path() / "../resources"; -#endif - - set_resources_dir(path_resources.string()); - set_var_dir((path_resources / "icons").string()); - set_local_dir((path_resources / "localization").string()); - set_sys_shapes_dir((path_resources / "shapes").string()); - set_custom_gcodes_dir((path_resources / "custom_gcodes").string()); - - // Parse all command line options into a DynamicConfig. - // If any option is unsupported, print usage and abort immediately. - t_config_option_keys opt_order; - if (! m_config.read_cli(argc, argv, &m_input_files, &opt_order)) { - // Separate error message reported by the CLI parser from the help. - boost::nowide::cerr << std::endl; - this->print_help(); - return false; - } - // Parse actions and transform options. - for (auto const &opt_key : opt_order) { - if (cli_actions_config_def.has(opt_key)) - m_actions.emplace_back(opt_key); - else if (cli_transform_config_def.has(opt_key)) - m_transforms.emplace_back(opt_key); - else if (cli_profiles_sharing_config_def.has(opt_key)) - m_profiles_sharing.emplace_back(opt_key); - } - - { - const ConfigOptionInt *opt_loglevel = m_config.opt("loglevel"); - if (opt_loglevel != 0) - set_logging_level(opt_loglevel->value); - } - - { - const ConfigOptionInt *opt_threads = m_config.opt("threads"); - if (opt_threads != nullptr) - thread_count = opt_threads->value; - } - - //FIXME Validating at this stage most likely does not make sense, as the config is not fully initialized yet. - std::string validity = m_config.validate(); - - // Initialize with defaults. - for (const t_optiondef_map *options : { &cli_actions_config_def.options - , &cli_transform_config_def.options - , &cli_profiles_sharing_config_def.options - , &cli_misc_config_def.options }) - for (const t_optiondef_map::value_type &optdef : *options) - m_config.option(optdef.first, true); - - if (std::string provided_datadir = m_config.opt_string("datadir"); provided_datadir.empty()) { - set_data_dir(get_default_datadir()); - } else - set_data_dir(provided_datadir); - - //FIXME Validating at this stage most likely does not make sense, as the config is not fully initialized yet. - if (!validity.empty()) { - boost::nowide::cerr << "error: " << validity << std::endl; - return false; - } - - return true; -} - -void CLI::print_help(bool include_print_options, PrinterTechnology printer_technology) const -{ - //B7 - boost::nowide::cout - << SLIC3R_BUILD_ID << " " -#ifdef SLIC3R_GUI - << " (with GUI support)" -#else /* SLIC3R_GUI */ - << " (without GUI support)" -#endif /* SLIC3R_GUI */ - << std::endl - << "Usage: qidi-slicer [ ACTIONS ] [ TRANSFORM ] [ OPTIONS ] [ file.stl ... ]" << std::endl - << std::endl - << "Actions:" << std::endl; - cli_actions_config_def.print_cli_help(boost::nowide::cout, false); - cli_profiles_sharing_config_def.print_cli_help(boost::nowide::cout, false); - - boost::nowide::cout - << std::endl - << "Transform options:" << std::endl; - cli_transform_config_def.print_cli_help(boost::nowide::cout, false); - - boost::nowide::cout - << std::endl - << "Other options:" << std::endl; - cli_misc_config_def.print_cli_help(boost::nowide::cout, false); - - //boost::nowide::cout - // << std::endl - // << "Profiles sharing options:" << std::endl; - // cli_profiles_sharing_config_def.print_cli_help(boost::nowide::cout, false); - - boost::nowide::cout - << std::endl - << "Print options are processed in the following order:" << std::endl - << "\t1) Config keys from the command line, for example --fill-pattern=stars" << std::endl - << "\t (highest priority, overwrites everything below)" << std::endl - << "\t2) Config files loaded with --load" << std::endl - << "\t3) Config values loaded from amf or 3mf files" << std::endl; - - if (include_print_options) { - boost::nowide::cout << std::endl; - print_config_def.print_cli_help(boost::nowide::cout, true, [printer_technology](const ConfigOptionDef &def) - { return printer_technology == ptAny || def.printer_technology == ptAny || printer_technology == def.printer_technology; }); - } else { - boost::nowide::cout - << std::endl - << "Run --help-fff / --help-sla to see the full listing of print options." << std::endl; - } -} - -bool CLI::export_models(IO::ExportFormat format) -{ - for (Model &model : m_models) { - const std::string path = this->output_filepath(model, format); - bool success = false; - switch (format) { - case IO::OBJ: success = Slic3r::store_obj(path.c_str(), &model); break; - case IO::STL: success = Slic3r::store_stl(path.c_str(), &model, true); break; - case IO::TMF: success = Slic3r::store_3mf(path.c_str(), &model, nullptr, false); break; - default: assert(false); break; - } - if (success) - std::cout << "File exported to " << path << std::endl; - else { - std::cerr << "File export to " << path << " failed" << std::endl; - return false; - } - } - return true; -} - -std::string CLI::output_filepath(const Model &model, IO::ExportFormat format) const -{ - std::string ext; - switch (format) { - case IO::OBJ: ext = ".obj"; break; - case IO::STL: ext = ".stl"; break; - case IO::TMF: ext = ".3mf"; break; - default: assert(false); break; - }; - auto proposed_path = boost::filesystem::path(model.propose_export_file_name_and_path(ext)); - // use --output when available - std::string cmdline_param = m_config.opt_string("output"); - if (! cmdline_param.empty()) { - // if we were supplied a directory, use it and append our automatically generated filename - boost::filesystem::path cmdline_path(cmdline_param); - if (boost::filesystem::is_directory(cmdline_path)) - proposed_path = cmdline_path / proposed_path.filename(); - else - proposed_path = cmdline_path; - } - return proposed_path.string(); -} - -std::set query_options = { - "printer-profile" -}; - -bool CLI::processed_profiles_sharing() -{ - if (m_profiles_sharing.empty()) { -#if 0 // fsFIXME !!! just for the test - Slic3r::DynamicPrintConfig config = {}; - bool was_loaded = Slic3r::load_full_print_config("0.20mm QUALITY @MINI", "QIDIment PLA", "Original QIDI MINI & MINI+", config); - return true; -#else - return false; -#endif - } - - std::string ret; - for (auto const& opt_key : m_profiles_sharing) { - if (query_options.find(opt_key) != query_options.end()) - continue; - if (opt_key == "query-printer-models") { - ret = Slic3r::get_json_printer_models(get_printer_technology(m_config)); - } -/* - else if (opt_key == "query-printer-profiles") { - if (!m_config.has("printer_model") || !m_config.has("printer_variant")) { - boost::nowide::cerr << "error in '" << opt_key << "' : this action requires set 'printer-model' and 'printer-variant' options" << std::endl; - break; - } - ret = Slic3r::get_json_printer_profiles(m_config.opt_string("printer_model"), m_config.opt_string("printer_variant")); - - if (ret.empty()) - boost::nowide::cerr << "Printer_model '" << m_config.opt_string("printer_model") << - "' with printer_variant '" << m_config.opt_string("printer_variant") << - "' wasn't found among installed printers." << std::endl << - "Or the request can be wrong." << std::endl; - } -*/ - else if (opt_key == "query-print-filament-profiles") { - if (!m_config.has("printer-profile")) { - boost::nowide::cerr << "error: this action requires set printer-preset option" << opt_key << std::endl; - break; - } - ret = Slic3r::get_json_print_filament_profiles(m_config.opt_string("printer-profile")); - - if (ret.empty()) - boost::nowide::cerr << "Printer profile '" << m_config.opt_string("printer-profile") << - "' wasn't found among installed printers." << std::endl << - "Or the request can be wrong." << std::endl; - } - else { - boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl; - break; - } - } - - // use --output when available - - std::string cmdline_param = m_config.opt_string("output"); - if (cmdline_param.empty()) { - if (ret.empty()) - boost::nowide::cerr << "Wrong request" << std::endl; - else - printf("%s", ret.c_str()); - } - else { - // if we were supplied a directory, use it and append our automatically generated filename - boost::filesystem::path cmdline_path(cmdline_param); - boost::filesystem::path proposed_path = boost::filesystem::path(Slic3r::resources_dir()) / "out.json"; - if (boost::filesystem::is_directory(cmdline_path)) - proposed_path = (cmdline_path / proposed_path.filename()); - else if (cmdline_path.extension().empty()) - proposed_path = cmdline_path.replace_extension("json"); - else - proposed_path = cmdline_path; - const std::string file = proposed_path.string(); - - boost::nowide::ofstream c; - c.open(file, std::ios::out | std::ios::trunc); - c << ret << std::endl; - c.close(); - - boost::nowide::cout << "Output for your request is written into " << file << std::endl; - } - - return true; -} - -bool CLI::check_and_load_input_profiles(PrinterTechnology& printer_technology) -{ - Slic3r::DynamicPrintConfig config = {}; - std::string ret = Slic3r::load_full_print_config(m_config.opt_string("print-profile"), - m_config.option("material-profile")->values, - m_config.opt_string("printer-profile"), - config, printer_technology); - if (!ret.empty()) { - boost::nowide::cerr << ret << std::endl; - return false; - } - - config.normalize_fdm(); - - PrinterTechnology other_printer_technology = get_printer_technology(config); - if (printer_technology == ptUnknown) - printer_technology = other_printer_technology; - else if (printer_technology != other_printer_technology && other_printer_technology != ptUnknown) { - boost::nowide::cerr << "Mixing configurations for FFF and SLA technologies" << std::endl; - return false; - } - - m_print_config.apply(config); - - return true; -} - // __has_feature() is used later for Clang, this is for compatibility with other compilers (such as GCC and MSVC) #ifndef __has_feature # define __has_feature(x) 0 @@ -1221,12 +82,12 @@ extern "C" { for (size_t i = 0; i < argc; ++ i) argv_ptrs[i] = argv_narrow[i].data(); // Call the UTF8 main. - return CLI().run(argc, argv_ptrs.data()); + return Slic3r::CLI::run(argc, argv_ptrs.data()); } } #else /* _MSC_VER */ int main(int argc, char **argv) { - return CLI().run(argc, argv); + return Slic3r::CLI::run(argc, argv); } #endif /* _MSC_VER */ diff --git a/src/QIDISlicer.hpp b/src/QIDISlicer.hpp index 2df4ae4..302666a 100644 --- a/src/QIDISlicer.hpp +++ b/src/QIDISlicer.hpp @@ -1,51 +1,9 @@ #ifndef SLIC3R_HPP #define SLIC3R_HPP -#include "libslic3r/Config.hpp" -#include "libslic3r/Model.hpp" - -namespace Slic3r { - -namespace IO { - enum ExportFormat : int { - OBJ, - STL, - // SVG, - TMF, - Gcode - }; -} - -class CLI { -public: +namespace Slic3r::CLI +{ int run(int argc, char **argv); - -private: - DynamicPrintAndCLIConfig m_config; - DynamicPrintConfig m_print_config; - DynamicPrintConfig m_extra_config; - std::vector m_input_files; - std::vector m_actions; - std::vector m_transforms; - std::vector m_profiles_sharing; - std::vector m_models; - - bool setup(int argc, char **argv); - - /// Prints usage of the CLI. - void print_help(bool include_print_options = false, PrinterTechnology printer_technology = ptAny) const; - - /// Exports loaded models to a file of the specified format, according to the options affecting output filename. - bool export_models(IO::ExportFormat format); - - bool has_print_action() const { return m_config.opt_bool("export_gcode") || m_config.opt_bool("export_sla"); } - bool processed_profiles_sharing(); - - bool check_and_load_input_profiles(PrinterTechnology& printer_technology); - - std::string output_filepath(const Model &model, IO::ExportFormat format) const; -}; - } #endif diff --git a/src/libseqarrange/CMakeLists.txt b/src/libseqarrange/CMakeLists.txt new file mode 100644 index 0000000..df3ab7e --- /dev/null +++ b/src/libseqarrange/CMakeLists.txt @@ -0,0 +1,35 @@ +find_package(Z3 REQUIRED) +slic3r_remap_configs("z3::libz3" RelWithDebInfo Release) + + + +add_library(libseqarrange STATIC src/seq_interface.cpp src/seq_preprocess.cpp src/seq_sequential.cpp src/seq_utilities.cpp) +target_include_directories(libseqarrange PUBLIC include PRIVATE src ) +target_link_libraries(libseqarrange PUBLIC libslic3r PRIVATE z3::libz3) + +add_executable(sequential_decimator src/sequential_decimator.cpp) +target_include_directories(sequential_decimator PRIVATE include) +target_link_libraries(sequential_decimator PRIVATE libseqarrange) + + + + + +if (SLIC3R_BUILD_TESTS) + find_package(Catch2 3.8 REQUIRED) + + add_executable(libseqarrange_tests test/qidiparts.cpp test/seq_test_polygon.cpp test/seq_test_sequential.cpp test/seq_test_preprocess.cpp test/seq_test_interface.cpp) + target_include_directories(libseqarrange_tests PRIVATE src ) + target_link_libraries(libseqarrange_tests PRIVATE Catch2::Catch2WithMain libseqarrange) + + set(_catch_args "exclude:[NotWorking] exclude:[Slow]") + list(APPEND _catch_args "${CATCH_EXTRA_ARGS}") + add_test(NAME libseqarrange_tests + COMMAND libseqarrange_tests ${_catch_args} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +endif() + + + + diff --git a/src/libseqarrange/include/libseqarrange/seq_interface.hpp b/src/libseqarrange/include/libseqarrange/seq_interface.hpp new file mode 100644 index 0000000..2123a5a --- /dev/null +++ b/src/libseqarrange/include/libseqarrange/seq_interface.hpp @@ -0,0 +1,204 @@ +#ifndef __SEQ_INTERFACE_HPP__ +#define __SEQ_INTERFACE_HPP__ + + +/*----------------------------------------------------------------*/ + +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Geometry/ConvexHull.hpp" + +/*----------------------------------------------------------------*/ + +using namespace Slic3r; + + +/*----------------------------------------------------------------*/ + +namespace Sequential +{ + class ObjectTooLargeException : public std::runtime_error { public: explicit ObjectTooLargeException(const std::string& msg) : std::runtime_error(msg) {}}; + + + +/*----------------------------------------------------------------*/ + +struct PrinterGeometry +{ + // must be convex; for best performance a rectangle is recommended + Slic3r::Polygon plate; + + // at least height 0 (corresponding to nozzle) must be present in convex_heights + std::set convex_heights; + std::set box_heights; + + // , at least one polygon must be present for height 0 + std::map > extruder_slices; + + bool convert_Geometry2PlateBounds(Slic3r::BoundingBox &plate_bounding_box, Slic3r::Polygon &plate_bounding_polygon) const; +}; + + +/*----------------------------------------------------------------*/ + +enum DecimationPrecision +{ + SEQ_DECIMATION_PRECISION_UNDEFINED, + SEQ_DECIMATION_PRECISION_LOW, + SEQ_DECIMATION_PRECISION_HIGH +}; + + +/*----------------------------------------------------------------*/ + +struct SolverConfiguration +{ + SolverConfiguration(); + SolverConfiguration(const PrinterGeometry &printer_geometry); + + void set_DecimationPrecision(DecimationPrecision decimation_precision); + void set_ObjectGroupSize(int object_group_size); + + void setup(const PrinterGeometry &printer_geometry); + + static double convert_DecimationPrecision2Tolerance(DecimationPrecision decimation_precision); + + int bounding_box_size_optimization_step; + int minimum_bounding_box_size; + + Slic3r::BoundingBox plate_bounding_box; + Slic3r::Polygon plate_bounding_polygon; + + int max_refines; + + int object_group_size; + int fixed_object_grouping_limit; + int temporal_spread; + + DecimationPrecision decimation_precision; + std::string optimization_timeout; +}; + + +/*----------------------------------------------------------------*/ + +struct ObjectToPrint +{ + int id = 0; + bool glued_to_next = false; /* the next object must be scheduled right after this object */ + coord_t total_height = 0; + std::vector> pgns_at_height; +}; + + +struct ScheduledObject { + ScheduledObject(int _id, coord_t _x, coord_t _y) + : id(_id) + , x(_x) + , y(_y) { /* */ } + + int id = 0; + coord_t x, y; +}; + + +struct ScheduledPlate { + std::vector scheduled_objects; +}; + + +/*----------------------------------------------------------------*/ +/* + This is the recommended interface for checking sequential printability. + + Returns true if objects are sequentially printable according to their + ordering in the input vector and the arrangement on the plate specified + by the schedule. Printable means that the extruder never hits printed + objects during printing. Otherwise returns false. + + Please see the corresponding example of usage (seq_test_interface.cpp) + + Note: The function always succeeds, does not throw any exception. +*/ + +bool check_ScheduledObjectsForSequentialPrintability(const SolverConfiguration &solver_configuration, + const PrinterGeometry &printer_geometry, + const std::vector &objects_to_print, + const std::vector &scheduled_plates); + +/* + This is a variant of the interface for checking sequential printability. + + If not sequentially printable returns a pair of object IDs that are in conflict, + that is, when the second object is printed the extruder will collide with the + first object. The returned conflict is not necessarily the first collision to + occur when printing the object according to the given input schedule. + + Note: The function always succeeds, does not throw any exception. + */ +std::optional > check_ScheduledObjectsForSequentialConflict(const SolverConfiguration &solver_configuration, + const PrinterGeometry &printer_geometry, + const std::vector &objects_to_print, + const std::vector &scheduled_plates); + + +/*----------------------------------------------------------------*/ +/* + This is the recommended interface for sequential scheduling/arranging. + + Please see the corresponding example of usage (seq_test_interface.cpp) + + Note: The function should succeed except the case when there is an + object that does not fit on the plate and in the case when the solver + is unable to scedule even single object on the plate. The latter case + is detected by timeout and should not normally happen. These failures + are reported via exceptions. + + The trans_bed_glue parameter should be set to false when scheduling + all objects. If only objects on a separate bed are scheduled, then + trans_bed_glue should be set to true when there is an object on the + previous bed that is temporally glued to the first scheduled object. + In such a case, the first object will be scheduled as first temporally. +*/ + +std::vector schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver_configuration, + const PrinterGeometry &printer_geometry, + const std::vector &objects_to_print, + std::function progress_callback = [](int progress){}); + +void schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver_configuration, + const PrinterGeometry &printer_geometry, + const std::vector &objects_to_print, + std::vector &scheduled_plates, + std::function progress_callback = [](int progress){}); + + +/*----------------------------------------------------------------*/ +/* + The following interface is for more internal use. + */ + +int schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver_configuration, + const std::vector &objects_to_print, + std::vector &scheduled_plates, + std::function progress_callback = [](int progress){}); + +void setup_ExtruderUnreachableZones(const SolverConfiguration &solver_configuration, + std::vector > &convex_unreachable_zones, + std::vector > &box_unreachable_zones); + +int schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver_configuration, + const std::vector &objects_to_print, + const std::vector > &convex_unreachable_zones, + const std::vector > &box_unreachable_zones, + std::vector &scheduled_plates, + std::function progress_callback = [](int progress){}); + + +/*----------------------------------------------------------------*/ + +} // namespace Sequential + + +/*----------------------------------------------------------------*/ + +#endif /* __SEQ_INTERFACE_HPP__ */ diff --git a/src/libseqarrange/src/seq_defs.hpp b/src/libseqarrange/src/seq_defs.hpp new file mode 100644 index 0000000..32a9b9b --- /dev/null +++ b/src/libseqarrange/src/seq_defs.hpp @@ -0,0 +1,73 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2025 + * + * File: seq_defs.h + * + * Definitions of useful macros. + */ +/*================================================================*/ + +#ifndef __SEQ_DEFS_HPP__ +#define __SEQ_DEFS_HPP__ + +/*----------------------------------------------------------------*/ + +#include +#include + +#include +#include +#include + + +/*----------------------------------------------------------------*/ + + +using namespace std; + +#define SEQ_UNUSED(x) + +//#define DEBUG +//#define PROFILE + +typedef wchar_t wchar; + +typedef std::basic_string string; +typedef std::vector strings_vector; +typedef std::set strings_set; + + +/*----------------------------------------------------------------*/ + +extern const string INDENT; + +/*----------------------------------------------------------------*/ + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) +#define DFR(x,y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y))) +#define ABS(x) (((x) < 0) ? -(x) : (x)) +#define SGN(x) (((x) < 0) ? -(-1) : ((x) > 0) ? 1 : 0) + + +/*----------------------------------------------------------------*/ + +#ifdef DEBUG + #define ASSERT(condition) \ + { \ + if (!(condition)) \ + { \ + printf("ASSERT: assertion failed (file: %s, line:%d).\n", __FILE__, __LINE__); \ + fflush(NULL); \ + exit(-1); \ + } \ + } +#else + #define ASSERT(condition) +#endif /* DEBUG */ + + +/*----------------------------------------------------------------*/ + +#endif /* __SEQ_DEFS_HPP__ */ diff --git a/src/libseqarrange/src/seq_interface.cpp b/src/libseqarrange/src/seq_interface.cpp new file mode 100644 index 0000000..c35b391 --- /dev/null +++ b/src/libseqarrange/src/seq_interface.cpp @@ -0,0 +1,1350 @@ +#include "seq_defs.hpp" + +#include "seq_sequential.hpp" +#include "seq_preprocess.hpp" +#include "libseqarrange/seq_interface.hpp" + + +/*----------------------------------------------------------------*/ + +namespace Sequential +{ + + + + +/*----------------------------------------------------------------*/ + +const int SEQ_OBJECT_GROUP_SIZE = 4; +const int SEQ_FIXED_OBJECT_GROUPING_LIMIT = 64; +const int SEQ_SCHEDULING_TEMPORAL_SPREAD = 16; + +const int SEQ_BOUNDING_BOX_SIZE_OPTIMIZATION_STEP = 4; +const int SEQ_MINIMUM_BOUNDING_BOX_SIZE = 16; + +const int SEQ_MAX_REFINES = 2; + + +/*----------------------------------------------------------------*/ + +enum PrinterType +{ + SEQ_PRINTER_TYPE_UNDEFINED, + SEQ_PRINTER_TYPE_QIDI_MINI, + SEQ_PRINTER_TYPE_QIDI_MK3S, + SEQ_PRINTER_TYPE_QIDI_MK4, + SEQ_PRINTER_TYPE_QIDI_XL +}; + + +const int SEQ_QIDI_MK3S_X_SIZE = 2500; +const int SEQ_QIDI_MK3S_Y_SIZE = 2100; + +const coord_t SEQ_QIDI_MK3S_NOZZLE_LEVEL = 0; +const coord_t SEQ_QIDI_MK3S_EXTRUDER_LEVEL = 2000000; +const coord_t SEQ_QIDI_MK3S_HOSE_LEVEL = 18000000; +const coord_t SEQ_QIDI_MK3S_GANTRY_LEVEL = 26000000; + +const int SEQ_QIDI_MK4_X_SIZE = 2500; +const int SEQ_QIDI_MK4_Y_SIZE = 2100; + +const coord_t SEQ_QIDI_MK4_NOZZLE_LEVEL = 0; +const coord_t SEQ_QIDI_MK4_EXTRUDER_LEVEL = 2000000; +const coord_t SEQ_QIDI_MK4_HOSE_LEVEL = 18000000; +const coord_t SEQ_QIDI_MK4_GANTRY_LEVEL = 26000000; + +const int SEQ_QIDI_XL_X_SIZE = 3600; +const int SEQ_QIDI_XL_Y_SIZE = 3600; + +const coord_t SEQ_QIDI_XL_NOZZLE_LEVEL = 0; +const coord_t SEQ_QIDI_XL_EXTRUDER_LEVEL = 2000000; +const coord_t SEQ_QIDI_XL_HOSE_LEVEL = 18000000; +const coord_t SEQ_QIDI_XL_GANTRY_LEVEL = 26000000; + + +/*----------------------------------------------------------------*/ + +bool PrinterGeometry::convert_Geometry2PlateBounds(Slic3r::BoundingBox &plate_bounding_box, Slic3r::Polygon &plate_bounding_polygon) const +{ + BoundingBox plate_box = get_extents(plate); + + if (fabs(plate.area() - plate_box.polygon().area()) > EPSILON) + { + for (unsigned int i = 0; i < plate.points.size(); ++i) + { + plate_bounding_polygon.points.insert(plate_bounding_polygon.points.begin() + i, Point(plate.points[i].x() / SEQ_SLICER_SCALE_FACTOR, + plate.points[i].y() / SEQ_SLICER_SCALE_FACTOR)); + } + plate_bounding_polygon.make_counter_clockwise(); + return false; + } + else + { + plate_bounding_box = BoundingBox({ plate_box.min.x() / SEQ_SLICER_SCALE_FACTOR, plate_box.min.y() / SEQ_SLICER_SCALE_FACTOR }, + { plate_box.max.x() / SEQ_SLICER_SCALE_FACTOR, plate_box.max.y() / SEQ_SLICER_SCALE_FACTOR }); + + return true; + } +} + + +/*----------------------------------------------------------------*/ + +SolverConfiguration::SolverConfiguration() + : bounding_box_size_optimization_step(SEQ_BOUNDING_BOX_SIZE_OPTIMIZATION_STEP) + , minimum_bounding_box_size(SEQ_MINIMUM_BOUNDING_BOX_SIZE) + , max_refines(SEQ_MAX_REFINES) + , object_group_size(SEQ_OBJECT_GROUP_SIZE) + , fixed_object_grouping_limit(SEQ_FIXED_OBJECT_GROUPING_LIMIT) + , temporal_spread(SEQ_SCHEDULING_TEMPORAL_SPREAD) + , decimation_precision(SEQ_DECIMATION_PRECISION_LOW) + , optimization_timeout(SEQ_Z3_SOLVER_TIMEOUT) +{ + /* nothing */ +} + + +SolverConfiguration::SolverConfiguration(const PrinterGeometry &printer_geometry) + : bounding_box_size_optimization_step(SEQ_BOUNDING_BOX_SIZE_OPTIMIZATION_STEP) + , minimum_bounding_box_size(SEQ_MINIMUM_BOUNDING_BOX_SIZE) + , max_refines(SEQ_MAX_REFINES) + , object_group_size(SEQ_OBJECT_GROUP_SIZE) + , fixed_object_grouping_limit(SEQ_FIXED_OBJECT_GROUPING_LIMIT) + , temporal_spread(SEQ_SCHEDULING_TEMPORAL_SPREAD) + , decimation_precision(SEQ_DECIMATION_PRECISION_LOW) + , optimization_timeout(SEQ_Z3_SOLVER_TIMEOUT) +{ + setup(printer_geometry); +} + + +double SolverConfiguration::convert_DecimationPrecision2Tolerance(DecimationPrecision decimation_precision) +{ + switch (decimation_precision) + { + case SEQ_DECIMATION_PRECISION_UNDEFINED: + { + return SEQ_DECIMATION_TOLERANCE_VALUE_UNDEFINED; + break; + } + case SEQ_DECIMATION_PRECISION_LOW: + { + return SEQ_DECIMATION_TOLERANCE_VALUE_HIGH; + break; + } + case SEQ_DECIMATION_PRECISION_HIGH: + { + return SEQ_DECIMATION_TOLERANCE_VALUE_LOW; + break; + } + default: + { + break; + } + } + return SEQ_DECIMATION_TOLERANCE_VALUE_UNDEFINED; +} + + +void SolverConfiguration::setup(const PrinterGeometry &printer_geometry) +{ + printer_geometry.convert_Geometry2PlateBounds(plate_bounding_box, plate_bounding_polygon); +} + + +void SolverConfiguration::set_DecimationPrecision(DecimationPrecision _decimation_precision) +{ + decimation_precision = _decimation_precision; +} + + +void SolverConfiguration::set_ObjectGroupSize(int _object_group_size) +{ + object_group_size = _object_group_size; +} + + +/*----------------------------------------------------------------*/ + + +bool check_ScheduledObjectsForSequentialPrintability(const SolverConfiguration &solver_configuration, + const PrinterGeometry &printer_geometry, + const std::vector &objects_to_print, + const std::vector &scheduled_plates) +{ + if (check_ScheduledObjectsForSequentialConflict(solver_configuration, + printer_geometry, + objects_to_print, + scheduled_plates)) + { + return false; + } + return true; +} + + +std::optional > check_ScheduledObjectsForSequentialConflict(const SolverConfiguration &solver_configuration, + const PrinterGeometry &printer_geometry, + const std::vector &objects_to_print, + const std::vector &scheduled_plates) +{ + std::vector polygons; + std::vector > unreachable_polygons; + + std::map flat_index_map; + + for (unsigned int i = 0; i < objects_to_print.size(); ++i) + { + std::vector convex_level_polygons; + std::vector box_level_polygons; + + std::vector > extruder_convex_level_polygons; + std::vector > extruder_box_level_polygons; + + std::vector scale_down_unreachable_polygons; + + flat_index_map[objects_to_print[i].id] = i; + + Polygon scale_down_object_polygon; + + prepare_ExtruderPolygons(solver_configuration, + printer_geometry, + objects_to_print[i], + convex_level_polygons, + box_level_polygons, + extruder_convex_level_polygons, + extruder_box_level_polygons, + false); + + prepare_ObjectPolygons(solver_configuration, + convex_level_polygons, + box_level_polygons, + extruder_convex_level_polygons, + extruder_box_level_polygons, + scale_down_object_polygon, + scale_down_unreachable_polygons); + + unreachable_polygons.push_back(scale_down_unreachable_polygons); + polygons.push_back(scale_down_object_polygon); + } + + for (const auto& scheduled_plate: scheduled_plates) + { + int time = SEQ_GROUND_PRESENCE_TIME; + + std::vector plate_polygons; + std::vector > plate_unreachable_polygons; + + std::vector dec_values_X; + std::vector dec_values_Y; + std::vector dec_values_T; + + for (const auto& scheduled_object: scheduled_plate.scheduled_objects) + { + const auto& flat_index = flat_index_map.find(scheduled_object.id)->second; + + assert(!objects_to_print[flat_index].pgns_at_height.empty()); + + /* + if (!check_PolygonPositionWithinPlate(solver_configuration, + SEQ_SLICER_SCALE_FACTOR, + scheduled_object.x, + scheduled_object.y, + objects_to_print[flat_index].pgns_at_height[0].second)) + { + #ifdef DEBUG + { + printf("Object placed outside plate.\n"); + } + #endif + return false; + } + */ + + plate_polygons.push_back(polygons[flat_index]); + plate_unreachable_polygons.push_back(unreachable_polygons[flat_index]); + + dec_values_X.push_back(scaleDown_CoordinateForSequentialSolver(scheduled_object.x)); + dec_values_Y.push_back(scaleDown_CoordinateForSequentialSolver(scheduled_object.y)); + + time += 2 * solver_configuration.temporal_spread * solver_configuration.object_group_size; + dec_values_T.push_back(Rational(time)); + } + + #ifdef DEBUG + { + printf("Point check ...\n"); + } + #endif + + if (auto conflict = check_PointsOutsidePolygons(dec_values_X, + dec_values_Y, + dec_values_T, + plate_polygons, + plate_unreachable_polygons)) + { + return std::pair(scheduled_plate.scheduled_objects[conflict.value().first].id, scheduled_plate.scheduled_objects[conflict.value().second].id); + } + #ifdef DEBUG + { + printf("Point check ... finished\n"); + } + #endif + + #ifdef DEBUG + { + printf("Line check ...\n"); + } + #endif + + if (auto conflict = check_PolygonLineIntersections(dec_values_X, + dec_values_Y, + dec_values_T, + plate_polygons, + plate_unreachable_polygons)) + { + return std::pair(scheduled_plate.scheduled_objects[conflict.value().first].id, scheduled_plate.scheduled_objects[conflict.value().second].id); + } + #ifdef DEBUG + { + printf("Line check ... finished\n"); + } + #endif + } + #ifdef DEBUG + { + printf("Seems to be printable (you can try physically).\n"); + } + #endif + + return {}; +} + + +/*----------------------------------------------------------------*/ + +std::vector schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver_configuration, + const PrinterGeometry &printer_geometry, + const std::vector &objects_to_print, + std::function progress_callback) +{ + std::vector scheduled_plates; + + schedule_ObjectsForSequentialPrint(solver_configuration, + printer_geometry, + objects_to_print, + scheduled_plates, + progress_callback); + return scheduled_plates; +} + + +bool is_scheduled(int i, const std::vector &decided_polygons) +{ + for (unsigned int j = 0; j < decided_polygons.size(); ++j) + { + if (decided_polygons[j] == i) + { + return true; + } + } + return false; +} + + +void schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver_configuration, + const PrinterGeometry &printer_geometry, + const std::vector &objects_to_print, + std::vector &scheduled_plates, + std::function progress_callback) +{ + #ifdef PROFILE + clock_t start, finish; + start = clock(); + #endif + + #ifdef DEBUG + { + printf("Sequential scheduling/arranging ...\n"); + } + #endif + + std::map original_index_map; + std::vector solvable_objects; + + #ifdef DEBUG + { + printf(" Preparing objects ...\n"); + } + #endif + + for (unsigned int i = 0; i < objects_to_print.size(); ++i) + { + std::vector convex_level_polygons; + std::vector box_level_polygons; + + std::vector > extruder_convex_level_polygons; + std::vector > extruder_box_level_polygons; + + SolvableObject solvable_object; + original_index_map[i] = objects_to_print[i].id; + + prepare_ExtruderPolygons(solver_configuration, + printer_geometry, + objects_to_print[i], + convex_level_polygons, + box_level_polygons, + extruder_convex_level_polygons, + extruder_box_level_polygons, + true); + + prepare_ObjectPolygons(solver_configuration, + convex_level_polygons, + box_level_polygons, + extruder_convex_level_polygons, + extruder_box_level_polygons, + solvable_object.polygon, + solvable_object.unreachable_polygons); + + solvable_object.id = objects_to_print[i].id; + solvable_object.lepox_to_next = objects_to_print[i].glued_to_next; + + solvable_objects.push_back(solvable_object); + } + + std::vector remaining_polygons; + std::vector decided_polygons; + + std::vector poly_positions_X; + std::vector poly_positions_Y; + std::vector times_T; + + #ifdef DEBUG + { + printf(" Preparing objects ... finished\n"); + } + #endif + + int progress_object_phases_done = 0; + int progress_object_phases_total = SEQ_MAKE_EXTRA_PROGRESS((objects_to_print.size() * SEQ_PROGRESS_PHASES_PER_OBJECT)); + + bool trans_bed_lepox = false; + + do + { + ScheduledPlate scheduled_plate; + + decided_polygons.clear(); + remaining_polygons.clear(); + + #ifdef DEBUG + { + printf(" Object scheduling/arranging ...\n"); + } + #endif + + bool optimized; + + optimized = optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(solver_configuration, + poly_positions_X, + poly_positions_Y, + times_T, + solvable_objects, + trans_bed_lepox, + decided_polygons, + remaining_polygons, + progress_object_phases_done, + progress_object_phases_total, + progress_callback); + + #ifdef DEBUG + { + printf(" Object scheduling/arranging ... finished\n"); + } + #endif + + if (optimized) + { + #ifdef DEBUG + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + printf(" [ID:%d,RID:%d] x:%.3f, y:%.3f (t:%.3f)\n", + original_index_map[decided_polygons[i]], + decided_polygons[i], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double(), + times_T[decided_polygons[i]].as_double()); + } + printf("Remaining polygons: %ld\n", remaining_polygons.size()); + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + printf(" ID:%d\n", original_index_map[remaining_polygons[i]]); + } + } + #endif + + bool split = false; + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + if (solvable_objects[i].lepox_to_next && !is_scheduled(i + 1, decided_polygons)) + { + split = true; + break; + } + } + if (split) + { + trans_bed_lepox = true; + #ifdef DEBUG + { + printf("Lopoxed group split, implies trans-bed lepox\n"); + } + #endif + } + else + { + trans_bed_lepox = false; + } + std::map scheduled_polygons; + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + scheduled_polygons.insert(std::pair(times_T[decided_polygons[i]].as_double(), decided_polygons[i])); + } + + for (const auto& scheduled_polygon: scheduled_polygons) + { + coord_t X, Y; + + scaleUp_PositionForSlicer(poly_positions_X[scheduled_polygon.second], + poly_positions_Y[scheduled_polygon.second], + X, + Y); + const auto& original_index = original_index_map.find(scheduled_polygon.second); + + scheduled_plate.scheduled_objects.push_back(ScheduledObject(original_index->second, X, Y)); + } + } + else + { + #ifdef DEBUG + { + printf("Polygon sequential schedule optimization FAILED.\n"); + } + #endif + + throw std::runtime_error("COMPLETE SCHEDULING FAILURE (UNABLE TO SCHEDULE EVEN SINGLE OBJECT)"); + } + #ifdef PROFILE + { + finish = clock(); + } + #endif + + #ifdef PROFILE + { + printf("Intermediate CPU time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + std::vector next_solvable_objects; + + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + next_solvable_objects.push_back(solvable_objects[remaining_polygons[i]]); + } + solvable_objects = next_solvable_objects; + + std::map next_original_index_map; + + for (unsigned int index = 0; index < solvable_objects.size(); ++index) + { + next_original_index_map[index] = original_index_map[remaining_polygons[index]]; + } + original_index_map = next_original_index_map; + + scheduled_plates.push_back(scheduled_plate); + } + while (!remaining_polygons.empty()); + + progress_callback(SEQ_PROGRESS_RANGE); + + #ifdef PROFILE + { + finish = clock(); + } + #endif + + #ifdef DEBUG + { + printf("Sequential scheduling/arranging ... finished\n"); + } + #endif + + #ifdef PROFILE + { + printf("Total CPU time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif +} + + +/*----------------------------------------------------------------*/ + +int schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver_configuration, + const std::vector &objects_to_print, + std::vector &scheduled_plates, + std::function progress_callback) +{ + #ifdef PROFILE + clock_t start, finish; + start = clock(); + #endif + + #ifdef DEBUG + { + printf("Sequential scheduling/arranging ...\n"); + } + #endif + + PrinterType printer_type = SEQ_PRINTER_TYPE_QIDI_MK3S; + + std::vector solvable_objects; + std::map original_index_map; + + #ifdef DEBUG + { + printf(" Preparing objects ...\n"); + } + #endif + + for (unsigned int i = 0; i < objects_to_print.size(); ++i) + { + Polygon nozzle_polygon; + Polygon extruder_polygon; + Polygon hose_polygon; + Polygon gantry_polygon; + + original_index_map[i] = objects_to_print[i].id; + + for (unsigned int j = 0; j < objects_to_print[i].pgns_at_height.size(); ++j) + { + coord_t height = objects_to_print[i].pgns_at_height[j].first; + + if (!objects_to_print[i].pgns_at_height[j].second.points.empty()) + { + Polygon decimated_polygon; + + if (solver_configuration.decimation_precision != SEQ_DECIMATION_PRECISION_UNDEFINED) + { + decimate_PolygonForSequentialSolver(solver_configuration, + objects_to_print[i].pgns_at_height[j].second, + decimated_polygon, + true); + } + else + { + decimated_polygon = objects_to_print[i].pgns_at_height[j].second; + decimated_polygon.make_counter_clockwise(); + } + if (!check_PolygonSizeFitToPlate(solver_configuration, SEQ_SLICER_SCALE_FACTOR, decimated_polygon)) + { + #ifdef DEBUG + { + printf("Object too large to fit onto plate [ID:%d RID:%d].\n", original_index_map[i], i); + } + #endif + return -1; + } + + switch (printer_type) + { + case SEQ_PRINTER_TYPE_QIDI_MK3S: + { + switch (height) + { + case SEQ_QIDI_MK3S_NOZZLE_LEVEL: // nozzle + { + nozzle_polygon = decimated_polygon; + break; + } + case SEQ_QIDI_MK3S_EXTRUDER_LEVEL: // extruder + { + extruder_polygon = decimated_polygon; + break; + } + case SEQ_QIDI_MK3S_HOSE_LEVEL: // hose + { + hose_polygon = decimated_polygon; + break; + } + case SEQ_QIDI_MK3S_GANTRY_LEVEL: // gantry + { + gantry_polygon = decimated_polygon; + break; + } + default: + { + throw std::runtime_error("UNSUPPORTED POLYGON HEIGHT"); + break; + } + } + break; + } + case SEQ_PRINTER_TYPE_QIDI_MK4: + { + switch (height) + { + case SEQ_QIDI_MK4_NOZZLE_LEVEL: // nozzle + { + nozzle_polygon = decimated_polygon; + break; + } + case SEQ_QIDI_MK4_EXTRUDER_LEVEL: // extruder + { + extruder_polygon = decimated_polygon; + break; + } + case SEQ_QIDI_MK4_HOSE_LEVEL: // hose + { + hose_polygon = decimated_polygon; + break; + } + case SEQ_QIDI_MK4_GANTRY_LEVEL: // gantry + { + gantry_polygon = decimated_polygon; + break; + } + default: + { + throw std::runtime_error("UNSUPPORTED POLYGON HEIGHT"); + break; + } + } + break; + } + case SEQ_PRINTER_TYPE_QIDI_XL: + { + switch (height) + { + case SEQ_QIDI_XL_NOZZLE_LEVEL: // nozzle + { + nozzle_polygon = decimated_polygon; + break; + } + case SEQ_QIDI_XL_EXTRUDER_LEVEL: // extruder + { + extruder_polygon = decimated_polygon; + break; + } + case SEQ_QIDI_XL_HOSE_LEVEL: // hose (no hose in XL) + { + hose_polygon = decimated_polygon; + break; + } + case SEQ_QIDI_XL_GANTRY_LEVEL: // gantry + { + gantry_polygon = decimated_polygon; + break; + } + default: + { + throw std::runtime_error("UNSUPPORTED POLYGON HEIGHT"); + break; + } + } + break; + } + default: + { + throw std::runtime_error("UNSUPPORTED PRINTER TYPE"); + break; + } + } + } + } + SolvableObject solvable_object; + + scaleDown_PolygonForSequentialSolver(nozzle_polygon, solvable_object.polygon); + + std::vector convex_level_polygons; + convex_level_polygons.push_back(nozzle_polygon); + convex_level_polygons.push_back(extruder_polygon); + std::vector box_level_polygons; + box_level_polygons.push_back(hose_polygon); + box_level_polygons.push_back(gantry_polygon); + + std::vector scale_down_unreachable_polygons; + + switch (printer_type) + { + case SEQ_PRINTER_TYPE_QIDI_MK3S: + { + prepare_UnreachableZonePolygons(solver_configuration, + convex_level_polygons, + box_level_polygons, + SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_MK3S, + SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_MK3S, + solvable_object.unreachable_polygons); + break; + } + case SEQ_PRINTER_TYPE_QIDI_MK4: + { + prepare_UnreachableZonePolygons(solver_configuration, + convex_level_polygons, + box_level_polygons, + SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_MK4, + SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_MK4, + solvable_object.unreachable_polygons); + break; + } + case SEQ_PRINTER_TYPE_QIDI_XL: + { + prepare_UnreachableZonePolygons(solver_configuration, + convex_level_polygons, + box_level_polygons, + SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_XL, + SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_XL, + solvable_object.unreachable_polygons); + break; + } + default: + { + throw std::runtime_error("UNSUPPORTED PRINTER TYPE"); + break; + } + } + + solvable_object.id = objects_to_print[i].id; + solvable_object.lepox_to_next = objects_to_print[i].glued_to_next; + + solvable_objects.push_back(solvable_object); + } + + std::vector remaining_polygons; + std::vector decided_polygons; + + /* + for (unsigned int index = 0; index < solvable_objects.size(); ++index) + { + polygon_index_map.push_back(index); + } + */ + + std::vector poly_positions_X; + std::vector poly_positions_Y; + std::vector times_T; + + #ifdef DEBUG + { + printf(" Preparing objects ... finished\n"); + } + #endif + + int progress_object_phases_done = 0; + int progress_object_phases_total = SEQ_MAKE_EXTRA_PROGRESS((objects_to_print.size() * SEQ_PROGRESS_PHASES_PER_OBJECT)); + + bool trans_bed_lepox = false; + + do + { + ScheduledPlate scheduled_plate; + + decided_polygons.clear(); + remaining_polygons.clear(); + + #ifdef DEBUG + { + printf(" Object scheduling/arranging ...\n"); + } + #endif + + bool optimized; + + optimized = optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(solver_configuration, + poly_positions_X, + poly_positions_Y, + times_T, + solvable_objects, + trans_bed_lepox, + decided_polygons, + remaining_polygons, + progress_object_phases_done, + progress_object_phases_total, + progress_callback); + + #ifdef DEBUG + { + printf(" Object scheduling/arranging ... finished\n"); + } + #endif + + if (optimized) + { + #ifdef DEBUG + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + printf(" [ID:%d,RID:%d] x:%.3f, y:%.3f (t:%.3f)\n", + original_index_map[decided_polygons[i]], + decided_polygons[i], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double(), + times_T[decided_polygons[i]].as_double()); + } + printf("Remaining polygons: %ld\n", remaining_polygons.size()); + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + printf(" ID:%d\n", original_index_map[remaining_polygons[i]]); + } + } + #endif + + bool split = false; + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + if (solvable_objects[i].lepox_to_next && !is_scheduled(i + 1, decided_polygons)) + { + split = true; + break; + } + } + if (split) + { + trans_bed_lepox = true; + #ifdef DEBUG + { + printf("Lopoxed group split, implies trans-bed lepox\n"); + } + #endif + } + else + { + trans_bed_lepox = false; + } + std::map scheduled_polygons; + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + scheduled_polygons.insert(std::pair(times_T[decided_polygons[i]].as_double(), decided_polygons[i])); + } + + for (const auto& scheduled_polygon: scheduled_polygons) + { + coord_t X, Y; + + scaleUp_PositionForSlicer(poly_positions_X[scheduled_polygon.second], + poly_positions_Y[scheduled_polygon.second], + X, + Y); + const auto& original_index = original_index_map.find(scheduled_polygon.second); + + scheduled_plate.scheduled_objects.push_back(ScheduledObject(original_index->second, X, Y)); + } + } + else + { + #ifdef DEBUG + { + printf("Polygon sequential schedule optimization FAILED.\n"); + } + #endif + return -2; + } + #ifdef PROFILE + { + finish = clock(); + } + #endif + + #ifdef PROFILE + { + printf("Intermediate CPU time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + std::vector next_solvable_objects; + + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + next_solvable_objects.push_back(solvable_objects[i]); + } + solvable_objects = next_solvable_objects; + std::map next_original_index_map; + + for (unsigned int index = 0; index < solvable_objects.size(); ++index) + { + next_original_index_map[index] = original_index_map[remaining_polygons[index]]; + } + original_index_map = next_original_index_map; + + scheduled_plates.push_back(scheduled_plate); + } + while (!remaining_polygons.empty()); + + progress_callback(SEQ_PROGRESS_RANGE); + + #ifdef PROFILE + { + finish = clock(); + } + #endif + + #ifdef DEBUG + { + printf("Sequential scheduling/arranging ... finished\n"); + } + #endif + + #ifdef PROFILE + { + printf("Total CPU time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + return 0; +} + + +void setup_ExtruderUnreachableZones(const SolverConfiguration &solver_configuration, + std::vector > &convex_unreachable_zones, + std::vector > &box_unreachable_zones) +{ + PrinterType printer_type = SEQ_PRINTER_TYPE_QIDI_MK3S; + + switch (printer_type) + { + case SEQ_PRINTER_TYPE_QIDI_MK3S: + { + convex_unreachable_zones = SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_MK3S; + box_unreachable_zones = SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_MK3S; + break; + } + case SEQ_PRINTER_TYPE_QIDI_MK4: + { + convex_unreachable_zones = SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_MK4; + box_unreachable_zones = SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_MK4; + break; + } + case SEQ_PRINTER_TYPE_QIDI_XL: + { + convex_unreachable_zones = SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_XL; + box_unreachable_zones = SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_XL; + break; + } + default: + { + throw std::runtime_error("UNSUPPORTED PRINTER TYPE"); + break; + } + } +} + + +int schedule_ObjectsForSequentialPrint(const SolverConfiguration &solver_configuration, + const std::vector &objects_to_print, + const std::vector > &convex_unreachable_zones, + const std::vector > &box_unreachable_zones, + std::vector &scheduled_plates, + std::function progress_callback) +{ + #ifdef PROFILE + clock_t start, finish; + start = clock(); + #endif + + #ifdef DEBUG + { + printf("Sequential scheduling/arranging ...\n"); + } + #endif + + std::vector solvable_objects; + std::map original_index_map; + + #ifdef DEBUG + { + printf(" Preparing objects ...\n"); + } + #endif + + for (unsigned int i = 0; i < objects_to_print.size(); ++i) + { + Polygon nozzle_polygon; + Polygon extruder_polygon; + Polygon hose_polygon; + Polygon gantry_polygon; + + original_index_map[i] = objects_to_print[i].id; + + int ht = 0; + + for (unsigned int j = 0; j < objects_to_print[i].pgns_at_height.size(); ++j) + { + if (!objects_to_print[i].pgns_at_height[j].second.points.empty()) + { + Polygon decimated_polygon; + + if (solver_configuration.decimation_precision != SEQ_DECIMATION_PRECISION_UNDEFINED) + { + decimate_PolygonForSequentialSolver(solver_configuration, + objects_to_print[i].pgns_at_height[j].second, + decimated_polygon, + true); + } + else + { + decimated_polygon = objects_to_print[i].pgns_at_height[j].second; + decimated_polygon.make_counter_clockwise(); + } + + if (!check_PolygonSizeFitToPlate(solver_configuration, SEQ_SLICER_SCALE_FACTOR, decimated_polygon)) + { + #ifdef DEBUG + { + printf("Object too large to fit onto plate [ID:%d RID:%d].\n", original_index_map[i], i); + } + #endif + return -1; + } + + switch (ht) + { + case 0: // nozzle + { + nozzle_polygon = decimated_polygon; + break; + } + case 1: // extruder + { + extruder_polygon = decimated_polygon; + break; + } + case 2: // hose + { + hose_polygon = decimated_polygon; + break; + } + case 3: // gantry + { + gantry_polygon = decimated_polygon; + break; + } + default: + { + throw std::runtime_error("UNSUPPORTED POLYGON HEIGHT"); + break; + } + } + } + ++ht; + } + SolvableObject solvable_object; + + scaleDown_PolygonForSequentialSolver(nozzle_polygon, solvable_object.polygon); + + std::vector convex_level_polygons; + convex_level_polygons.push_back(nozzle_polygon); + convex_level_polygons.push_back(extruder_polygon); + + std::vector box_level_polygons; + box_level_polygons.push_back(hose_polygon); + box_level_polygons.push_back(gantry_polygon); + + std::vector scale_down_unreachable_polygons; + + prepare_UnreachableZonePolygons(solver_configuration, + convex_level_polygons, + box_level_polygons, + convex_unreachable_zones, + box_unreachable_zones, + solvable_object.unreachable_polygons); + + solvable_object.id = objects_to_print[i].id; + solvable_object.lepox_to_next = objects_to_print[i].glued_to_next; + + solvable_objects.push_back(solvable_object); + } + + std::vector remaining_polygons; + std::vector decided_polygons; + + std::vector poly_positions_X; + std::vector poly_positions_Y; + std::vector times_T; + + #ifdef DEBUG + { + printf(" Preparing objects ... finished\n"); + } + #endif + + int progress_object_phases_done = 0; + int progress_object_phases_total = SEQ_MAKE_EXTRA_PROGRESS((objects_to_print.size() * SEQ_PROGRESS_PHASES_PER_OBJECT)); + + bool trans_bed_lepox = false; + + do + { + ScheduledPlate scheduled_plate; + + decided_polygons.clear(); + remaining_polygons.clear(); + + #ifdef DEBUG + { + printf(" Object scheduling/arranging ...\n"); + } + #endif + + bool optimized; + + optimized = optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(solver_configuration, + poly_positions_X, + poly_positions_Y, + times_T, + solvable_objects, + trans_bed_lepox, + decided_polygons, + remaining_polygons, + progress_object_phases_done, + progress_object_phases_total, + progress_callback); + + + #ifdef DEBUG + { + printf(" Object scheduling/arranging ... finished\n"); + } + #endif + + if (optimized) + { + #ifdef DEBUG + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + printf(" [ID:%d,RID:%d] x:%.3f, y:%.3f (t:%.3f)\n", + original_index_map[decided_polygons[i]], + decided_polygons[i], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double(), + times_T[decided_polygons[i]].as_double()); + } + printf("Remaining polygons: %ld\n", remaining_polygons.size()); + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + printf(" ID:%d\n", original_index_map[remaining_polygons[i]]); + } + } + #endif + + bool split = false; + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + if (solvable_objects[i].lepox_to_next && !is_scheduled(i + 1, decided_polygons)) + { + split = true; + break; + } + } + if (split) + { + trans_bed_lepox = true; + #ifdef DEBUG + { + printf("Lopoxed group split, implies trans-bed lepox\n"); + } + #endif + } + else + { + trans_bed_lepox = false; + } + std::map scheduled_polygons; + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + scheduled_polygons.insert(std::pair(times_T[decided_polygons[i]].as_double(), decided_polygons[i])); + } + + for (const auto& scheduled_polygon: scheduled_polygons) + { + coord_t X, Y; + + scaleUp_PositionForSlicer(poly_positions_X[scheduled_polygon.second], + poly_positions_Y[scheduled_polygon.second], + X, + Y); + const auto& original_index = original_index_map.find(scheduled_polygon.second); + + scheduled_plate.scheduled_objects.push_back(ScheduledObject(original_index->second, X, Y)); + } + } + else + { + #ifdef DEBUG + { + printf("Polygon sequential schedule optimization FAILED.\n"); + } + #endif + return -2; + } + #ifdef PROFILE + { + finish = clock(); + } + #endif + + #ifdef PROFILE + { + printf("Intermediate CPU time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + std::vector next_solvable_objects; + + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + next_solvable_objects.push_back(solvable_objects[i]); + } + solvable_objects = next_solvable_objects; + std::map next_original_index_map; + + for (unsigned int index = 0; index < solvable_objects.size(); ++index) + { + next_original_index_map[index] = original_index_map[remaining_polygons[index]]; + } + original_index_map = next_original_index_map; + + scheduled_plates.push_back(scheduled_plate); + } + while (!remaining_polygons.empty()); + + progress_callback(SEQ_PROGRESS_RANGE); + + #ifdef PROFILE + { + finish = clock(); + } + #endif + + #ifdef DEBUG + { + printf("Sequential scheduling/arranging ... finished\n"); + } + #endif + + #ifdef PROFILE + { + printf("Total CPU time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + return 0; +} + +/*----------------------------------------------------------------*/ + +} // namespace Sequential diff --git a/src/libseqarrange/src/seq_preprocess.cpp b/src/libseqarrange/src/seq_preprocess.cpp new file mode 100644 index 0000000..1512b1c --- /dev/null +++ b/src/libseqarrange/src/seq_preprocess.cpp @@ -0,0 +1,1221 @@ +#include "seq_defs.hpp" + +#include "libslic3r/Geometry.hpp" +#include "libslic3r/ClipperUtils.hpp" + +#include "seq_preprocess.hpp" +#include "libseqarrange/seq_interface.hpp" + + +/*----------------------------------------------------------------*/ + +using namespace std; +using namespace Slic3r; +//using namespace ClipperLib; + + +/*----------------------------------------------------------------*/ + +namespace Sequential +{ + + + +/*----------------------------------------------------------------*/ + +// These are only approximate values for M3S, TODO: measure MK3S for true values +const std::vector SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK3S = +{ + { + {-500000, -500000}, + {500000, -500000}, + {500000, 500000}, + {-500000, 500000} + } +}; + + +// TODO: measure MK3S for true values +const std::vector SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK3S = +{ + { + {-2000000, -10000000}, + {2000000, -10000000}, + {2000000, 2000000}, + {-2000000, 2000000} + } +}; + + +// TODO: measure MK3S for true values +const std::vector SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK3S = +{ + { + {-1000000, 500000}, + {1000000, 500000}, + {1000000, -250000000}, + {-1000000, -250000000} + } +}; + + +// TODO: measure MK3S for true values +const std::vector SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK3S = +{ + { + {-250000000, 2000000}, + {250000000, 2000000}, + {250000000, 2100000}, + {-250000000, 2100000} + } +}; + + +// TODO: measure MK3S for true values +const std::vector > SEQ_UNREACHABLE_POLYGON_ALL_LEVELS_MK3S = +{ + SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK3S, + SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK3S, + SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK3S, + SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK3S +}; + + +const std::vector > SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_MK3S = +{ + SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK3S, + SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK3S +}; + + +const std::vector > SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_MK3S = +{ + SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK3S, + SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK3S +}; + + +/*----------------------------------------------------------------*/ + +// Nozzle height range: 0.00mm-4.9mm +const std::vector SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK4 = +{ + { + /* hand tailored */ + { -5000000, -5000000}, + { 5000000, -5000000}, + { 5000000, 5000000}, + { -5000000, 5000000} + + /* original from decimator + { -3 728 158, -1 611 789}, + { -468 223, -4 034 578}, + { 2 543 938, -2 732 339}, + { 3 259 933, -2 422 789}, + { 3 728 160, 1 611 785}, + { 468 227, 4 034 579}, + { -1 666 062, 3 111 867}, + { -3 259 931, 2 422 789}, + */ + } +}; + +// Extruder height range: 4.9mm-13.0mm +const std::vector SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK4 = +{ + { /* fan - hand tailored */ + { -10000000, -21000000}, + { 37000000, -21000000}, + { 37000000, 44000000}, + { -10000000, 44000000} + + /* fan - original from decimator + { 87952801, 3665480}, + { 103166346, -1375028}, + { 105384145, -1136906}, + { 107137556, 241781}, + { 107889619, 2905295}, + { 102396166, 55454515}, + { 101386126, 58737097}, + { 93 053 422, 62777197}, + { 87 447 788, 59999636}, + { 70 782 970, 28440457}, + + // nozzle + { -29 076 068, 18 872 356}, + { -29 001 876, 18 872 356}, + { -29 001 876, 18 952 646}, + { -29076068, 18952646}, + + */ + }, + { /* body - hand tailored */ + {-40000000, -45000000}, + { 38000000, -45000000}, + { 38000000, 20000000}, + {-40000000, 20000000} + + /* body - original from decimator + { -68105202, -14269412}, + { -62019977, -20740757}, + { -37145411, -25968391}, + { -23949432, -25968391}, + { 919905, -20740757}, + { 3102334, -16781961}, + { 8275483, 3033496}, + { -130845, 26409612}, + { -20142759, 38793397}, + { -62268386, 38793397}, + { -67090122, 17070789}, + + // nozzle + { -29076068, 18872356}, + { -29001876, 18872356}, + { -29001876, 18952646}, + { -29076068, 18952646}, + */ + } +}; + + +// Gantry height range: 13.0mm-15.0mm +const std::vector SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK4 = +{ + { + /* hand tailored */ + { -350000000, -4000000}, + { 350000000, -4000000}, + { 350000000, -14000000}, + { -350000000, -14000000} + + /* original from decimator + { -206972968, -12664471}, + { -206470468, -13167301} + { 164374531, -13167301}, + { 164877031, -12664471}, + { 164877031, -5630724}, + { 164374531, -5128674}, + { -206470468, -5128674}, + { -206972968, -5630724}, + + nozzle + { -29111351, 18877954}, + { -29022835, 18841825}, + { -28966594, 18940523}, + { -29040014, 18983178}, + */ + } +}; + + +// Hose height range: 15.0mm-infinity (the hose is the last) +const std::vector SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK4 = +{ + { + /* rigid hose - hand tailored */ + { -12000000, -350000000}, + { 9000000, -350000000}, + { 9000000, -39000000}, + { -12000000, -39000000} + + /* original from decimator + { -40942228, -22802359}, + { -38008017, -64681679}, + { -23603700, -65215173}, + { -20135995, -20401563}, + { -28933517, 21680323}, + + // nozzle + { -29111351, 18877954}, + { -29022835, 18841825}, + { -28966594, 18940523}, + { -29040014, 18983178}, + */ + }, + { + /* flexible hose - hand tailored */ + { -12000000, -350000000}, + { 250000000, -350000000}, + { 250000000, -82000000}, + { -12000000, -82000000} + } +}; + + +const std::vector > SEQ_UNREACHABLE_POLYGON_ALL_LEVELS_MK4 = +{ + SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK4, + SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK4, + SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK4, + SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK4 +}; + + +const std::vector > SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_MK4 = +{ + SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK4, + SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK4 +}; + + +const std::vector > SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_MK4 = +{ + SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK4, + SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK4 +}; + + +/*----------------------------------------------------------------*/ + +// TODO: Measure XL for true values +const std::vector SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_XL = +{ + { + {-500000, -500000}, + {500000, -500000}, + {500000, 500000}, + {-500000, 500000} + } +}; + + +// TODO: Measure XL for true values +const std::vector SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_XL = +{ + { + {-2000000, -10000000}, + {2000000, -10000000}, + {2000000, 2000000}, + {-2000000, 2000000} + } +}; + + +// TODO: Measure XL for true values +const std::vector SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_XL = +{ + { + {-1000000, 500000}, + {1000000, 500000}, + {1000000, -250000000}, + {-1000000, -250000000} + } +}; + + +// TODO: Measure XL for true values +const std::vector SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_XL = +{ + { + {-250000000, 2000000}, + {250000000, 2000000}, + {250000000, 2100000}, + {-250000000, 2100000} + } +}; + + +const std::vector > SEQ_UNREACHABLE_POLYGON_ALL_LEVELS_XL = +{ + SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_XL, + SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_XL, + SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_XL, + SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_XL +}; + + +const std::vector > SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_XL = +{ + SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_XL, + SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_XL +}; + + +const std::vector > SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_XL = +{ + SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_XL, + SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_XL +}; + + +/*----------------------------------------------------------------*/ + +Rational scaleDown_CoordinateForSequentialSolver(coord_t x) +{ + Rational scale_down_x(x, SEQ_SLICER_SCALE_FACTOR); + scale_down_x.normalize(); + + return scale_down_x; +} + + +void scaleDown_PolygonForSequentialSolver(const Slic3r::Polygon &polygon, + Slic3r::Polygon &scale_down_polygon) +{ + scaleDown_PolygonForSequentialSolver(SEQ_SLICER_SCALE_FACTOR, polygon, scale_down_polygon); +} + + +void scaleDown_PolygonForSequentialSolver(coord_t scale_factor, + const Slic3r::Polygon &polygon, + Slic3r::Polygon &scale_down_polygon) +{ + for (unsigned int i = 0; i < polygon.points.size(); ++i) + { + scale_down_polygon.points.insert(scale_down_polygon.points.begin() + i, Point(polygon.points[i].x() / scale_factor, polygon.points[i].y() / scale_factor)); + } + scale_down_polygon.make_counter_clockwise(); +} + + +Slic3r::Polygon scaleDown_PolygonForSequentialSolver(coord_t scale_factor, const Slic3r::Polygon &polygon) +{ + Slic3r::Polygon scale_down_polygon; + + for (unsigned int i = 0; i < polygon.points.size(); ++i) + { + scale_down_polygon.points.insert(scale_down_polygon.points.begin() + i, Point(polygon.points[i].x() / scale_factor, polygon.points[i].y() / scale_factor)); + } + scale_down_polygon.make_counter_clockwise(); + + return scale_down_polygon; +} + + +void scaleUp_PositionForSlicer(const Rational &position_X, + const Rational &position_Y, + coord_t &scaled_position_X, + coord_t &scaled_position_Y) +{ + scaleUp_PositionForSlicer(SEQ_SLICER_SCALE_FACTOR, position_X, position_Y, scaled_position_X, scaled_position_Y); +} + + +void scaleUp_PositionForSlicer(coord_t scale_factor, + const Rational &position_X, + const Rational &position_Y, + coord_t &scaled_position_X, + coord_t &scaled_position_Y) +{ + scaled_position_X = (position_X.normalize() * scale_factor).as_int64(); + scaled_position_Y = (position_Y.normalize() * scale_factor).as_int64(); +} + + + +void scaleUp_PositionForSlicer(double position_X, double position_Y, coord_t &scaled_position_X, coord_t &scaled_position_Y) +{ + scaleUp_PositionForSlicer(SEQ_SLICER_SCALE_FACTOR, position_X, position_Y, scaled_position_X, scaled_position_Y); +} + + +void scaleUp_PositionForSlicer(coord_t scale_factor, + double position_X, + double position_Y, + coord_t &scaled_position_X, + coord_t &scaled_position_Y) +{ + scaled_position_X = scale_factor * position_X; + scaled_position_Y = scale_factor * position_Y; +} + + +Slic3r::Polygon scaleUp_PolygonForSlicer(const Slic3r::Polygon &polygon) +{ + return scaleUp_PolygonForSlicer(SEQ_SLICER_SCALE_FACTOR, polygon); +} + + +Slic3r::Polygon scaleUp_PolygonForSlicer(coord_t scale_factor, const Slic3r::Polygon &polygon) +{ + Slic3r::Polygon poly = polygon; + + for (unsigned int i = 0; i < poly.points.size(); ++i) + { + poly.points[i] = Slic3r::Point(poly.points[i].x() * scale_factor, poly.points[i].y() * scale_factor); + } + + return poly; +} + + +Slic3r::Polygon scaleUp_PolygonForSlicer(const Polygon &polygon, double x_pos, double y_pos) +{ + return scaleUp_PolygonForSlicer(SEQ_SLICER_SCALE_FACTOR, polygon, x_pos, y_pos); +} + + +Slic3r::Polygon scaleUp_PolygonForSlicer(coord_t scale_factor, const Polygon &polygon, double x_pos, double y_pos) +{ + Slic3r::Polygon poly = polygon; + + for (unsigned int i = 0; i < poly.points.size(); ++i) + { + poly.points[i] = Point(poly.points[i].x() * scale_factor + x_pos * scale_factor, + poly.points[i].y() * scale_factor + y_pos * scale_factor); + } + + return poly; +} + + +void ground_PolygonByBoundingBox(Slic3r::Polygon &polygon) +{ + BoundingBox polygon_box = get_extents(polygon); + + for (unsigned int i = 0; i < polygon.points.size(); ++i) + { + polygon.points[i] -= polygon_box.min; + } +} + + +void ground_PolygonByFirstPoint(Slic3r::Polygon &polygon) +{ + Point first = polygon.points[0]; + for (unsigned int i = 0; i < polygon.points.size(); ++i) + { + polygon.points[i] -= first; + } +} + + +void shift_Polygon(Slic3r::Polygon &polygon, coord_t x_offset, coord_t y_offset) +{ + Point offset(x_offset, y_offset); + + shift_Polygon(polygon, offset); +} + + +void shift_Polygon(Slic3r::Polygon &polygon, const Slic3r::Point &offset) +{ + for (unsigned int i = 0; i < polygon.points.size(); ++i) + { + polygon.points[i] += offset; + } +} + + +/*----------------------------------------------------------------*/ + +Polygon transform_UpsideDown(const SolverConfiguration &solver_configuration, const Polygon &polygon) +{ + return transform_UpsideDown(solver_configuration, SEQ_SLICER_SCALE_FACTOR, polygon); +} + + +Polygon transform_UpsideDown(const SolverConfiguration &solver_configuration, coord_t scale_factor, const Polygon &polygon) +{ + Polygon poly = polygon; + + for (unsigned int i = 0; i < poly.points.size(); ++i) + { + poly.points[i] = Point(poly.points[i].x(), + (coord_t)((solver_configuration.plate_bounding_box.max.y() - solver_configuration.plate_bounding_box.min.y()) * scale_factor - poly.points[i].y())); + } + + return poly; +} + + +void transform_UpsideDown(const SolverConfiguration &solver_configuration, const coord_t &scaled_x_pos, const coord_t &scaled_y_pos, coord_t &transformed_x_pos, coord_t &transformed_y_pos) +{ + transform_UpsideDown(solver_configuration, SEQ_SLICER_SCALE_FACTOR, scaled_x_pos, scaled_y_pos, transformed_x_pos, transformed_y_pos); +} + + +void transform_UpsideDown(const SolverConfiguration &solver_configuration, coord_t scale_factor, const coord_t &scaled_x_pos, const coord_t &scaled_y_pos, coord_t &transformed_x_pos, coord_t &transformed_y_pos) +{ + transformed_x_pos = scaled_x_pos; + transformed_y_pos = (solver_configuration.plate_bounding_box.max.y() - solver_configuration.plate_bounding_box.min.y()) * scale_factor - scaled_y_pos; +} + + +/*----------------------------------------------------------------*/ + +void grow_PolygonForContainedness(coord_t center_x, coord_t center_y, Slic3r::Polygon &polygon) +{ + for (unsigned int i = 0; i < polygon.points.size(); ++i) + { + polygon.points[i] *= SEQ_POLYGON_DECIMATION_GROW_FACTOR; + } + + BoundingBox polygon_box = get_extents(polygon); + + coord_t shift_x = ((polygon_box.min.x() + polygon_box.max.x()) / 2) - center_x; + coord_t shift_y = ((polygon_box.min.y() + polygon_box.max.y()) / 2) - center_y; + + for (unsigned int i = 0; i < polygon.points.size(); ++i) + { + polygon.points[i] -= Point(shift_x, shift_y); + } +} + + +void decimate_PolygonForSequentialSolver(const SolverConfiguration &solver_configuration, + const Slic3r::Polygon &polygon, + Slic3r::Polygon &decimated_polygon, + bool extra_safety) +{ + double DP_tolerance = SolverConfiguration::convert_DecimationPrecision2Tolerance(solver_configuration.decimation_precision); + + decimate_PolygonForSequentialSolver(DP_tolerance, polygon, decimated_polygon, extra_safety); +} + + +void decimate_PolygonForSequentialSolver(double DP_tolerance, + const Slic3r::Polygon &polygon, + Slic3r::Polygon &decimated_polygon, + bool extra_safety) +{ + decimated_polygon = polygon; + decimated_polygon.make_counter_clockwise(); + + decimated_polygon.douglas_peucker(DP_tolerance); + + BoundingBox polygon_box = get_extents(polygon); + + coord_t center_x = (polygon_box.min.x() + polygon_box.max.x()) / 2; + coord_t center_y = (polygon_box.min.y() + polygon_box.max.y()) / 2; + + if (decimated_polygon.points.size() >= 4) + { + while (true) + { + grow_PolygonForContainedness(center_x, center_y, decimated_polygon); + + bool contains = true; + for (unsigned int i = 0; i < polygon.points.size(); ++i) + { + if (!decimated_polygon.contains(polygon.points[i])) + { + contains = false; + break; + } + } + + if (contains) + { + if (extra_safety) + { + grow_PolygonForContainedness(center_x, center_y, decimated_polygon); + } + break; + } + } + } + else + { + BoundingBox polygon_box = get_extents(polygon); + + decimated_polygon = { { polygon_box.min.x(), polygon_box.min.y() }, + { polygon_box.max.x(), polygon_box.min.y() }, + { polygon_box.max.x(), polygon_box.max.y() }, + { polygon_box.min.x(), polygon_box.max.y() } }; + } + + #ifdef DEBUG + { + printf("Comparison: %ld, %ld\n", polygon.points.size(), decimated_polygon.points.size()); + } + #endif +} + + +void extend_PolygonConvexUnreachableZone(const SolverConfiguration &SEQ_UNUSED(solver_configuration), + const Slic3r::Polygon &polygon, + const std::vector &extruder_polygons, + std::vector &unreachable_polygons) +{ + if (!polygon.points.empty()) + { + Slic3r::ClipperLib::Paths paths; + + for (unsigned int i = 0; i < extruder_polygons.size(); ++i) + { + ClipperLib::MinkowskiSum(extruder_polygons[i].points, polygon.points, paths, true); + + for (unsigned int j = 0; j < paths.size(); ++j) + { + unreachable_polygons.push_back(Polygon(paths[j])); + } + } + } +} + + +void extend_PolygonBoxUnreachableZone(const SolverConfiguration &SEQ_UNUSED(solver_configuration), + const Slic3r::Polygon &polygon, + const std::vector &extruder_polygons, + std::vector &unreachable_polygons) +{ + if (!polygon.points.empty()) + { + BoundingBox polygon_box = get_extents(polygon); + + for (unsigned int i = 0; i < extruder_polygons.size(); ++i) + { + BoundingBox extruder_box = get_extents(extruder_polygons[i]); + + coord_t min_x = polygon_box.min.x() + extruder_box.min.x(); + coord_t min_y = polygon_box.min.y() + extruder_box.min.y(); + + coord_t max_x = polygon_box.max.x() + extruder_box.max.x(); + coord_t max_y = polygon_box.max.y() + extruder_box.max.y(); + + unreachable_polygons.push_back(Polygon({ { min_x, min_y }, + { max_x, min_y }, + { max_x, max_y }, + { min_x, max_y } })); + } + } +} + + +void prepare_ExtruderPolygons(const SolverConfiguration &solver_configuration, + const PrinterGeometry &printer_geometry, + const ObjectToPrint &object_to_print, + std::vector &convex_level_polygons, + std::vector &box_level_polygons, + std::vector > &extruder_convex_level_polygons, + std::vector > &extruder_box_level_polygons, + bool extra_safety) +{ + for (unsigned int j = 0; j < object_to_print.pgns_at_height.size(); ++j) + { + coord_t height = object_to_print.pgns_at_height[j].first; + + if (!object_to_print.pgns_at_height[j].second.points.empty()) + { + Polygon decimated_polygon; + + if (solver_configuration.decimation_precision != SEQ_DECIMATION_PRECISION_UNDEFINED) + { + decimate_PolygonForSequentialSolver(solver_configuration, + object_to_print.pgns_at_height[j].second, + decimated_polygon, + extra_safety); + } + else + { + decimated_polygon = object_to_print.pgns_at_height[j].second; + decimated_polygon.make_counter_clockwise(); + } + + if (!check_PolygonSizeFitToPlate(solver_configuration, SEQ_SLICER_SCALE_FACTOR, decimated_polygon)) + { + #ifdef DEBUG + { + printf("Object too large to fit onto plate.\n"); + } + #endif + throw ObjectTooLargeException("OBJECT TOO LARGE"); + } + + if (printer_geometry.convex_heights.find(height) != printer_geometry.convex_heights.end()) + { + std::map >::const_iterator extruder_slice = printer_geometry.extruder_slices.find(height); + assert(extruder_slice != printer_geometry.extruder_slices.end()); + + convex_level_polygons.push_back(decimated_polygon); + extruder_convex_level_polygons.push_back(extruder_slice->second); + } + else if (printer_geometry.box_heights.find(height) != printer_geometry.box_heights.end()) + { + std::map >::const_iterator extruder_slice = printer_geometry.extruder_slices.find(height); + assert(extruder_slice != printer_geometry.extruder_slices.end()); + + box_level_polygons.push_back(decimated_polygon); + extruder_box_level_polygons.push_back(extruder_slice->second); + } + else + { + throw std::runtime_error("MISMATCH BETWEEN OBJECT AND PRINTER SLICE HEIGHTS."); + } + } + } +} + + +void prepare_ObjectPolygons(const SolverConfiguration &solver_configuration, + const std::vector &convex_level_polygons, + const std::vector &box_level_polygons, + const std::vector > &extruder_convex_level_polygons, + const std::vector > &extruder_box_level_polygons, + Slic3r::Polygon &object_polygon, + std::vector &unreachable_polygons) +{ + prepare_UnreachableZonePolygons(solver_configuration, + convex_level_polygons, + box_level_polygons, + extruder_convex_level_polygons, + extruder_box_level_polygons, + unreachable_polygons); + + assert(convex_level_polygons.size() >= 1); + Polygon raw_polygon = convex_level_polygons[0]; + + scaleDown_PolygonForSequentialSolver(raw_polygon, + object_polygon); + object_polygon.make_counter_clockwise(); +} + + +void prepare_UnreachableZonePolygons(const SolverConfiguration &solver_configuration, + const Slic3r::Polygon &polygon, + const std::vector > &extruder_convex_level_polygons, + const std::vector > &extruder_box_level_polygons, + std::vector &unreachable_polygons) +{ + std::vector > scaled_unreachable_polygons; + + for (unsigned int i = 0; i < extruder_convex_level_polygons.size(); ++i) + { + std::vector scaled_level_unreachable_polygons; + extend_PolygonConvexUnreachableZone(solver_configuration, + polygon, + extruder_convex_level_polygons[i], + scaled_level_unreachable_polygons); + scaled_unreachable_polygons.push_back(scaled_level_unreachable_polygons); + } + + for (unsigned int i = 0; i < extruder_box_level_polygons.size(); ++i) + { + std::vector scaled_level_unreachable_polygons; + extend_PolygonBoxUnreachableZone(solver_configuration, + polygon, + extruder_box_level_polygons[i], + scaled_level_unreachable_polygons); + scaled_unreachable_polygons.push_back(scaled_level_unreachable_polygons); + } + scaled_unreachable_polygons = simplify_UnreachableZonePolygons(scaled_unreachable_polygons); + + for (unsigned int i = 0; i < scaled_unreachable_polygons.size(); ++i) + { + for (unsigned int j = 0; j < scaled_unreachable_polygons[i].size(); ++j) + { + Polygon scale_down_polygon; + + scaleDown_PolygonForSequentialSolver(scaled_unreachable_polygons[i][j], + scale_down_polygon); + scale_down_polygon.make_counter_clockwise(); + unreachable_polygons.push_back(scale_down_polygon); + } + } +} + + +void prepare_UnreachableZonePolygons(const SolverConfiguration &solver_configuration, + const std::vector &convex_level_polygons, + const std::vector &box_level_polygons, + const std::vector > &extruder_convex_level_polygons, + const std::vector > &extruder_box_level_polygons, + std::vector &unreachable_polygons) +{ + std::vector > scaled_unreachable_polygons; + assert(extruder_convex_level_polygons.size() == convex_level_polygons.size()); + + for (unsigned int i = 0; i < extruder_convex_level_polygons.size(); ++i) + { + std::vector scaled_level_unreachable_polygons; + extend_PolygonConvexUnreachableZone(solver_configuration, + convex_level_polygons[i], + extruder_convex_level_polygons[i], + scaled_level_unreachable_polygons); + scaled_unreachable_polygons.push_back(scaled_level_unreachable_polygons); + } + assert(extruder_box_level_polygons.size() == box_level_polygons.size()); + + for (unsigned int i = 0; i < extruder_box_level_polygons.size(); ++i) + { + std::vector scaled_level_unreachable_polygons; + extend_PolygonBoxUnreachableZone(solver_configuration, + box_level_polygons[i], + extruder_box_level_polygons[i], + scaled_level_unreachable_polygons); + scaled_unreachable_polygons.push_back(scaled_level_unreachable_polygons); + } + scaled_unreachable_polygons = simplify_UnreachableZonePolygons(scaled_unreachable_polygons); + + for (unsigned int i = 0; i < scaled_unreachable_polygons.size(); ++i) + { + for (unsigned int j = 0; j < scaled_unreachable_polygons[i].size(); ++j) + { + Polygon scale_down_polygon; + + scaleDown_PolygonForSequentialSolver(scaled_unreachable_polygons[i][j], + scale_down_polygon); + scale_down_polygon.make_counter_clockwise(); + unreachable_polygons.push_back(scale_down_polygon); + } + } +} + + +bool check_PolygonSizeFitToPlate(const SolverConfiguration &solver_configuration, const Slic3r::Polygon &polygon) +{ + BoundingBox polygon_box = get_extents(polygon); + + if (solver_configuration.plate_bounding_polygon.points.size() == 0) + { + coord_t x_size = polygon_box.max.x() - polygon_box.min.x(); + if (x_size > (solver_configuration.plate_bounding_box.max.x() - solver_configuration.plate_bounding_box.min.x())) + { + return false; + } + + coord_t y_size = polygon_box.max.y() - polygon_box.min.y(); + if (y_size > (solver_configuration.plate_bounding_box.max.y() - solver_configuration.plate_bounding_box.min.y())) + { + return false; + } + } + else + { + BoundingBox plate_box = get_extents(solver_configuration.plate_bounding_polygon); + + coord_t x_size = polygon_box.max.x() - polygon_box.min.x(); + if (x_size > (plate_box.max.x() - plate_box.min.x())) + { + return false; + } + + coord_t y_size = polygon_box.max.y() - polygon_box.min.y(); + if (y_size > (plate_box.max.y() - plate_box.min.y())) + { + return false; + } + } + return true; +} + +bool check_PolygonPositionWithinPlate(const SolverConfiguration &solver_configuration, coord_t x, coord_t y, const Slic3r::Polygon &polygon) +{ + BoundingBox polygon_box = get_extents(polygon); + + if (solver_configuration.plate_bounding_polygon.points.size() == 0) + { + if (x + polygon_box.min.x() < solver_configuration.plate_bounding_box.min.x() || x + polygon_box.max.x() > solver_configuration.plate_bounding_box.max.x()) + { + return false; + } + if (y + polygon_box.min.y() < solver_configuration.plate_bounding_box.min.y() || y + polygon_box.max.y() > solver_configuration.plate_bounding_box.max.y()) + { + return false; + } + } + else + { + if ( contains(solver_configuration.plate_bounding_polygon, Point(x + polygon_box.min.x(), y + polygon_box.min.y())) + && contains(solver_configuration.plate_bounding_polygon, Point(x + polygon_box.max.x(), y + polygon_box.min.y())) + && contains(solver_configuration.plate_bounding_polygon, Point(x + polygon_box.max.x(), y + polygon_box.max.y())) + && contains(solver_configuration.plate_bounding_polygon, Point(x + polygon_box.min.x(), y + polygon_box.max.y()))) + { + return true; + } + else + { + return false; + } + } + return true; +} + + +bool check_PolygonSizeFitToPlate(const SolverConfiguration &solver_configuration, coord_t scale_factor, const Slic3r::Polygon &polygon) +{ + BoundingBox polygon_box = get_extents(polygon); + + if (solver_configuration.plate_bounding_polygon.points.size() == 0) + { + coord_t x_size = polygon_box.max.x() - polygon_box.min.x(); + if (x_size > (solver_configuration.plate_bounding_box.max.x() - solver_configuration.plate_bounding_box.min.x()) * scale_factor) + { + return false; + } + coord_t y_size = polygon_box.max.y() - polygon_box.min.y(); + if (y_size > (solver_configuration.plate_bounding_box.max.x() - solver_configuration.plate_bounding_box.min.x()) * scale_factor) + { + return false; + } + } + else + { + BoundingBox plate_box = get_extents(solver_configuration.plate_bounding_polygon); + + coord_t x_size = polygon_box.max.x() - polygon_box.min.x(); + if (x_size > (plate_box.max.x() - plate_box.min.x()) * scale_factor) + { + return false; + } + + coord_t y_size = polygon_box.max.y() - polygon_box.min.y(); + if (y_size > (plate_box.max.y() - plate_box.min.y()) * scale_factor) + { + return false; + } + } + + return true; +} + + +bool check_PolygonPositionWithinPlate(const SolverConfiguration &solver_configuration, coord_t scale_factor, coord_t x, coord_t y, const Slic3r::Polygon &polygon) +{ + BoundingBox polygon_box = get_extents(polygon); + + #ifdef DEBUG + { + printf("x: %d,%d\n", polygon_box.min.x() + x, polygon_box.max.x() + x); + printf("y: %d,%d\n", polygon_box.min.y() + y, polygon_box.max.y() + y); + printf("X: %d\n", (solver_configuration.plate_bounding_box.max.x() - solver_configuration.plate_bounding_box.min.x()) * scale_factor); + printf("Y: %d\n", (solver_configuration.plate_bounding_box.max.y() - solver_configuration.plate_bounding_box.min.x()) * scale_factor); + } + #endif + + if (solver_configuration.plate_bounding_polygon.points.size() == 0) + { + if (x + polygon_box.min.x() < solver_configuration.plate_bounding_box.min.x() * scale_factor || x + polygon_box.max.x() > solver_configuration.plate_bounding_box.max.x() * scale_factor) + { + return false; + } + if (y + polygon_box.min.y() < solver_configuration.plate_bounding_box.min.y() * scale_factor || y + polygon_box.max.y() > solver_configuration.plate_bounding_box.max.y() * scale_factor) + { + return false; + } + } + else + { + Polygon plate_polygon = solver_configuration.plate_bounding_polygon; + + for (unsigned int i = 0; i < plate_polygon.points.size(); ++i) + { + plate_polygon.points[i] *= scale_factor; + } + if ( contains(plate_polygon, Point(x + polygon_box.min.x(), y + polygon_box.min.y())) + && contains(plate_polygon, Point(x + polygon_box.max.x(), y + polygon_box.min.y())) + && contains(plate_polygon, Point(x + polygon_box.max.x(), y + polygon_box.max.y())) + && contains(plate_polygon, Point(x + polygon_box.min.x(), y + polygon_box.max.y()))) + { + return true; + } + else + { + return false; + } + } + return true; +} + + +/*----------------------------------------------------------------*/ + +bool check_PolygonConsumation(const std::vector &polygons, const std::vector &consumer_polygons) +{ + std::vector polygons_to_clip; + std::vector next_polygons_to_clip; + + polygons_to_clip = polygons; + + for (unsigned int poly_cons = 0; poly_cons < consumer_polygons.size(); ++poly_cons) + { + for (unsigned int clip_poly = 0; clip_poly < polygons_to_clip.size(); ++clip_poly) + { + Slic3r::Polygons clip_result; + clip_result = diff(polygons_to_clip[clip_poly], consumer_polygons[poly_cons]); + + for (const auto& clipped_polygon: clip_result) + { + next_polygons_to_clip.push_back(clipped_polygon); + } + } + polygons_to_clip = next_polygons_to_clip; + } + + if (polygons_to_clip.empty()) + { + return true; + } + return false; +} + + +std::vector > simplify_UnreachableZonePolygons(const std::vector > &unreachable_polygons) +{ + std::vector > simplified_unreachable_polygons; + + for (unsigned int i = 0; i < unreachable_polygons.size(); ++i) + { + bool consumed = false; + + for (unsigned int j = 0; j < unreachable_polygons.size(); ++j) + { + if (i != j) + { + double area_i = calc_PolygonUnreachableZoneArea(unreachable_polygons[i]); + double area_j = calc_PolygonUnreachableZoneArea(unreachable_polygons[j]); + + if (area_j > area_i) + { + if (check_PolygonConsumation(unreachable_polygons[i], unreachable_polygons[j])) + { + #ifdef DEBUG + { + printf("Consumed: %d vs %d\n", i, j); + } + #endif + consumed = true; + break; + } + } + } + } + if (!consumed) + { + simplified_unreachable_polygons.push_back(unreachable_polygons[i]); + } + } + + return simplified_unreachable_polygons; +} + + +void glue_LowObjects(std::vector &solvable_objects) +{ + int low = 0; + + for (unsigned int i = 0; i < solvable_objects.size(); ++i) + { + double polygon_area = calc_PolygonArea(solvable_objects[i].polygon); + double unreachable_area = calc_PolygonUnreachableZoneArea(solvable_objects[i].polygon, solvable_objects[i].unreachable_polygons); + + if (2 * polygon_area > unreachable_area) + { + if (++low >= 2) + { + assert(i > 0); + solvable_objects[i-1].lepox_to_next = true; + low = 1; + } + } + else + { + low = 0; + } + } +} + + +/*----------------------------------------------------------------*/ + +double calc_PolygonArea(const Slic3r::Polygon &polygon) +{ + Polygons overlapping_polygons; + + overlapping_polygons.push_back(polygon); + ExPolygons union_polygons = union_ex(overlapping_polygons); + + double area = 0; + for (const auto& union_polygon: union_polygons) + { + area += union_polygon.area(); + } + + return area; +} + + + +double calc_PolygonUnreachableZoneArea(const std::vector &unreachable_polygons) +{ + Polygons overlapping_polygons; + + for (const auto& unreachable_polygon: unreachable_polygons) + { + overlapping_polygons.push_back(unreachable_polygon); + } + ExPolygons union_polygons = union_ex(overlapping_polygons); + + double area = 0; + for (const auto& union_polygon: union_polygons) + { + area += union_polygon.area(); + } + + return area; +} + + +double calc_PolygonUnreachableZoneArea(const Slic3r::Polygon &polygon, + const std::vector &unreachable_polygons) +{ + Polygons overlapping_polygons; + + overlapping_polygons.push_back(polygon); + for (const auto& unreachable_polygon: unreachable_polygons) + { + overlapping_polygons.push_back(unreachable_polygon); + } + ExPolygons union_polygons = union_ex(overlapping_polygons); + + double area = 0; + for (const auto& union_polygon: union_polygons) + { + area += union_polygon.area(); + } + + return area; +} + + +double calc_PolygonArea(const std::vector &polygons) +{ + double area = 0; + + for (const auto &polygon: polygons) + { + area += calc_PolygonArea(polygon); + } + return area; +} + + +double calc_PolygonArea(const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons) +{ + double area = 0; + + for (unsigned int i = 0; i < fixed.size(); ++i) + { + area += calc_PolygonArea(polygons[i]); + } + for (unsigned int i = 0; i < undecided.size(); ++i) + { + area += calc_PolygonArea(polygons[i]); + } + + return area; +} + + +double calc_PolygonUnreachableZoneArea(const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + assert(polygons.size() == unreachable_polygons.size()); + double area = 0; + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + area += calc_PolygonUnreachableZoneArea(polygons[i], unreachable_polygons[i]); + } + + return area; +} + + +/*----------------------------------------------------------------*/ + +} // namespace Sequential + diff --git a/src/libseqarrange/src/seq_preprocess.hpp b/src/libseqarrange/src/seq_preprocess.hpp new file mode 100644 index 0000000..aeb2bcf --- /dev/null +++ b/src/libseqarrange/src/seq_preprocess.hpp @@ -0,0 +1,223 @@ +#ifndef __SEQ_PREPROCESS_HPP__ +#define __SEQ_PREPROCESS_HPP__ + + +/*----------------------------------------------------------------*/ + +#include "seq_sequential.hpp" + + +/*----------------------------------------------------------------*/ + +namespace Sequential +{ + + +/*----------------------------------------------------------------*/ + +const coord_t SEQ_SLICER_SCALE_FACTOR = 100000; +const double SEQ_POLYGON_DECIMATION_GROW_FACTOR = 1.005; + + +/*----------------------------------------------------------------*/ + +struct ObjectToPrint; + + +/*----------------------------------------------------------------*/ + +extern const std::vector SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK3S; +extern const std::vector SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK3S; +extern const std::vector SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK3S; +extern const std::vector SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK3S; + +extern const std::vector > SEQ_UNREACHABLE_POLYGON_ALL_LEVELS_MK3S; +extern const std::vector > SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_MK3S; +extern const std::vector > SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_MK3S; + + +extern const std::vector SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK4; +extern const std::vector SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK4; +extern const std::vector SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK4; +extern const std::vector SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK4; + +extern const std::vector > SEQ_UNREACHABLE_POLYGON_ALL_LEVELS_MK4; +extern const std::vector > SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_MK4; +extern const std::vector > SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_MK4; + +extern const std::vector SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_XL; +extern const std::vector SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_XL; +extern const std::vector SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_XL; +extern const std::vector SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_XL; + +extern const std::vector > SEQ_UNREACHABLE_POLYGON_ALL_LEVELS_XL; +extern const std::vector > SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_XL; +extern const std::vector > SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_XL; + + +/*----------------------------------------------------------------*/ + +Rational scaleDown_CoordinateForSequentialSolver(coord_t x); + +void scaleDown_PolygonForSequentialSolver(const Slic3r::Polygon &polygon, + Slic3r::Polygon &scaled_polygon); + +void scaleDown_PolygonForSequentialSolver(coord_t scale_factor, + const Slic3r::Polygon &polygon, + Slic3r::Polygon &scaled_polygon); + +Slic3r::Polygon scaleDown_PolygonForSequentialSolver(coord_t scale_factor, const Slic3r::Polygon &polygon); + + +void scaleUp_PositionForSlicer(const Rational &position_X, + const Rational &position_Y, + coord_t &scaled_position_X, + coord_t &scaled_position_Y); + +void scaleUp_PositionForSlicer(coord_t scale_factor, + const Rational &position_X, + const Rational &position_Y, + coord_t &scaled_position_X, + coord_t &scaled_position_Y); + +void scaleUp_PositionForSlicer(double position_X, + double position_Y, + coord_t &scaled_position_X, + coord_t &scaled_position_Y); + +void scaleUp_PositionForSlicer(coord_t scale_factor, + double position_X, + double position_Y, + coord_t &scaled_position_X, + coord_t &scaled_position_Y); + +Slic3r::Polygon scaleUp_PolygonForSlicer(const Slic3r::Polygon &polygon); +Slic3r::Polygon scaleUp_PolygonForSlicer(coord_t scale_factor, const Slic3r::Polygon &polygon); + +Slic3r::Polygon scaleUp_PolygonForSlicer(const Slic3r::Polygon &polygon, double x_pos, double y_pos); +Slic3r::Polygon scaleUp_PolygonForSlicer(coord_t scale_factor, const Slic3r::Polygon &polygon, double x_pos, double y_pos); + +void ground_PolygonByBoundingBox(Slic3r::Polygon &polygon); +void ground_PolygonByFirstPoint(Slic3r::Polygon &polygon); + +void shift_Polygon(Slic3r::Polygon &polygon, coord_t x_offset, coord_t y_offset); +void shift_Polygon(Slic3r::Polygon &polygon, const Slic3r::Point &offset); + + +/*----------------------------------------------------------------*/ + +Slic3r::Polygon transform_UpsideDown(const SolverConfiguration &solver_configuration, const Slic3r::Polygon &polygon); +Slic3r::Polygon transform_UpsideDown(const SolverConfiguration &solver_configuration, coord_t scale_factor, const Slic3r::Polygon &polygon); + +void transform_UpsideDown(const SolverConfiguration &solver_configuration, + const coord_t &scaled_x_pos, + const coord_t &scaled_y_pos, + coord_t &transformed_x_pos, + coord_t &transformed_y_pos); + +void transform_UpsideDown(const SolverConfiguration &solver_configuration, + coord_t scale_factor, + const coord_t &scaled_x_pos, + const coord_t &scaled_y_pos, + coord_t &transformed_x_pos, + coord_t &transformed_y_pos); + + +/*----------------------------------------------------------------*/ + +void grow_PolygonForContainedness(coord_t center_x, coord_t center_y, Slic3r::Polygon &polygon); + +void decimate_PolygonForSequentialSolver(const SolverConfiguration &solver_configuration, + const Slic3r::Polygon &polygon, + Slic3r::Polygon &scale_down_polygon, + bool extra_safety); + +void decimate_PolygonForSequentialSolver(double DP_tolerance, + const Slic3r::Polygon &polygon, + Slic3r::Polygon &decimated_polygon, + bool extra_safety); + +void extend_PolygonConvexUnreachableZone(const SolverConfiguration &solver_configuration, + const Slic3r::Polygon &polygon, + const std::vector &extruder_polygons, + std::vector &unreachable_polygons); + +void extend_PolygonBoxUnreachableZone(const SolverConfiguration &solver_configuration, + const Slic3r::Polygon &polygon, + const std::vector &extruder_polygons, + std::vector &unreachable_polygons); + +void extend_PolygonBoxUnreachableZone(const SolverConfiguration &solver_configuration, + const Slic3r::Polygon &polygon, + const std::vector &extruder_polygons, + std::vector &unreachable_polygons); + +void prepare_ExtruderPolygons(const SolverConfiguration &solver_configuration, + const PrinterGeometry &printer_geometry, + const ObjectToPrint &object_to_print, + std::vector &convex_level_polygons, + std::vector &box_level_polygons, + std::vector > &extruder_convex_level_polygons, + std::vector > &extruder_box_level_polygons, + bool extra_safety); + +void prepare_ObjectPolygons(const SolverConfiguration &solver_configuration, + const std::vector &convex_level_polygons, + const std::vector &box_level_polygons, + const std::vector > &extruder_convex_level_polygons, + const std::vector > &extruder_box_level_polygons, + Slic3r::Polygon &object_polygon, + std::vector &unreachable_polygons); + +void prepare_UnreachableZonePolygons(const SolverConfiguration &solver_configuration, + const Slic3r::Polygon &polygon, + const std::vector > &extruder_convex_level_polygons, + const std::vector > &extruder_box_level_polygons, + std::vector &unreachable_polygons); + +void prepare_UnreachableZonePolygons(const SolverConfiguration &solver_configuration, + const std::vector &convex_level_polygons, + const std::vector &box_level_polygons, + const std::vector > &extruder_convex_level_polygons, + const std::vector > &extruder_box_level_polygons, + std::vector &unreachable_polygons); + +bool check_PolygonSizeFitToPlate(const SolverConfiguration &solver_configuration, const Slic3r::Polygon &polygon); +bool check_PolygonPositionWithinPlate(const SolverConfiguration &solver_configuration, coord_t x, coord_t y, const Slic3r::Polygon &polygon); + +bool check_PolygonSizeFitToPlate(const SolverConfiguration &solver_configuration, coord_t scale_factor, const Slic3r::Polygon &polygon); +bool check_PolygonPositionWithinPlate(const SolverConfiguration &solver_configuration, coord_t scale_factor, coord_t x, coord_t y, const Slic3r::Polygon &polygon); + +/*----------------------------------------------------------------*/ + +bool check_PolygonConsumation(const std::vector &polygons, const std::vector &consumer_polygons); +std::vector > simplify_UnreachableZonePolygons(const std::vector > &unreachable_polygons); + +void glue_LowObjects(std::vector &solvable_ojects); + + +/*----------------------------------------------------------------*/ + +double calc_PolygonArea(const Slic3r::Polygon &polygon); + +double calc_PolygonUnreachableZoneArea(const std::vector &unreachable_polygons); +double calc_PolygonUnreachableZoneArea(const Slic3r::Polygon &polygon, + const std::vector &unreachable_polygons); + +double calc_PolygonArea(const std::vector &polygons); +double calc_PolygonArea(const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons); + +double calc_PolygonUnreachableZoneArea(const std::vector &polygons, + const std::vector > &unreachable_polygons); + + +/*----------------------------------------------------------------*/ + +} // namespace Sequential + + +/*----------------------------------------------------------------*/ + +#endif /* __SEQ_PREPROCESS_HPP__ */ diff --git a/src/libseqarrange/src/seq_sequential.cpp b/src/libseqarrange/src/seq_sequential.cpp new file mode 100644 index 0000000..c553a1e --- /dev/null +++ b/src/libseqarrange/src/seq_sequential.cpp @@ -0,0 +1,11678 @@ +#include +#include + +#include "seq_defs.hpp" + +#include "seq_sequential.hpp" +#include "seq_preprocess.hpp" + + +/*----------------------------------------------------------------*/ + +using namespace std; +using namespace Slic3r; + + +/*----------------------------------------------------------------*/ + +namespace Sequential +{ + + +/*----------------------------------------------------------------*/ + +int hidden_var_cnt = 0; + + +/*----------------------------------------------------------------*/ + +void introduce_DecisionBox(z3::solver &Solver, + const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + int box_size_x, + int box_size_y) +{ + Solver.add(dec_var_X >= 0); + Solver.add(dec_var_X <= box_size_x); + Solver.add(dec_var_Y >= 0); + Solver.add(dec_var_Y <= box_size_y); +} + + +void assume_DecisionBox(const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + int box_size_x, + int box_size_y, + z3::expr_vector &box_constraints) +{ + box_constraints.push_back(dec_var_X >= 0); + box_constraints.push_back(dec_var_X <= box_size_x); + box_constraints.push_back(dec_var_Y >= 0); + box_constraints.push_back(dec_var_Y <= box_size_y); +} + + +void introduce_BedBoundingBox(z3::solver &Solver, + const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + const Slic3r::Polygon &polygon, + int box_size_x, + int box_size_y) +{ + BoundingBox box = get_extents(polygon); + + Solver.add(dec_var_X + box.min.x() >= 0); + Solver.add(dec_var_X + box.max.x() <= box_size_x); + + Solver.add(dec_var_Y + box.min.y() >= 0); + Solver.add(dec_var_Y + box.max.y() <= box_size_y); +} + + +void assume_BedBoundingBox(const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + const Slic3r::Polygon &polygon, + int box_size_x, + int box_size_y, + z3::expr_vector &bounding_constraints) +{ + BoundingBox box = get_extents(polygon); + + bounding_constraints.push_back(dec_var_X + box.min.x() >= 0); + bounding_constraints.push_back(dec_var_X + box.max.x() <= box_size_x); + + bounding_constraints.push_back(dec_var_Y + box.min.y() >= 0); + bounding_constraints.push_back(dec_var_Y + box.max.y() <= box_size_y); +} + + + + + + +void introduce_BedBoundingBox(z3::solver &Solver, + const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + const Slic3r::Polygon &polygon, + int box_min_x, + int box_min_y, + int box_max_x, + int box_max_y) +{ + BoundingBox box = get_extents(polygon); + + Solver.add(dec_var_X + box.min.x() >= box_min_x); + Solver.add(dec_var_X + box.max.x() <= box_max_x); + + Solver.add(dec_var_Y + box.min.y() >= box_min_y); + Solver.add(dec_var_Y + box.max.y() <= box_max_y); +} + + +void assume_BedBoundingBox(const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + const Slic3r::Polygon &polygon, + int box_min_x, + int box_min_y, + int box_max_x, + int box_max_y, + z3::expr_vector &bounding_constraints) +{ + BoundingBox box = get_extents(polygon); + + bounding_constraints.push_back(dec_var_X + box.min.x() >= box_min_x); + bounding_constraints.push_back(dec_var_X + box.max.x() <= box_max_x); + + bounding_constraints.push_back(dec_var_Y + box.min.y() >= box_min_y); + bounding_constraints.push_back(dec_var_Y + box.max.y() <= box_max_y); +} + + +void assume_BedBoundingPolygon(z3::context &Context, + const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + const Slic3r::Polygon &polygon, + const Slic3r::Polygon &bed_bounding_polygon, + z3::expr_vector &bounding_constraints) +{ + BoundingBox box = get_extents(polygon); + + #ifdef DEBUG + { + printf("Polygon box: [%d,%d] [%d,%d]\n", box.min.x(), box.min.y(), box.max.x(), box.max.y()); + + printf("Bed bounding polygon: %ld\n", bed_bounding_polygon.points.size()); + for (unsigned int i = 0; i < bed_bounding_polygon.points.size(); ++i) + { + printf("[%d,%d] ", bed_bounding_polygon.points[i].x(), bed_bounding_polygon.points[i].y()); + } + printf("\n"); + } + #endif + + assume_PointInsidePolygon(Context, + dec_var_X + box.min.x(), + dec_var_Y + box.min.y(), + bed_bounding_polygon, + bounding_constraints); + + assume_PointInsidePolygon(Context, + dec_var_X + box.max.x(), + dec_var_Y + box.min.y(), + bed_bounding_polygon, + bounding_constraints); + + assume_PointInsidePolygon(Context, + dec_var_X + box.max.x(), + dec_var_Y + box.max.y(), + bed_bounding_polygon, + bounding_constraints); + + assume_PointInsidePolygon(Context, + dec_var_X + box.min.x(), + dec_var_Y + box.max.y(), + bed_bounding_polygon, + bounding_constraints); +} + + +void introduce_BedBoundingBox(z3::solver &Solver, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &polygons, + int box_size_x, + int box_size_y) +{ + for (unsigned int i = 0; i < polygons.size(); ++i) + { + BoundingBox box = get_extents(polygons[i]); + + Solver.add(dec_vars_X[i] + box.min.x() >= 0); + Solver.add(dec_vars_X[i] + box.max.x() <= box_size_x); + + Solver.add(dec_vars_Y[i] + box.min.y() >= 0); + Solver.add(dec_vars_Y[i] + box.max.y() <= box_size_y); + } +} + + +void assume_BedBoundingBox(const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &polygons, + int box_size_x, + int box_size_y, + z3::expr_vector &bounding_constraints) +{ + for (unsigned int i = 0; i < polygons.size(); ++i) + { + BoundingBox box = get_extents(polygons[i]); + + bounding_constraints.push_back(dec_vars_X[i] + box.min.x() >= 0); + bounding_constraints.push_back(dec_vars_X[i] + box.max.x() <= box_size_x); + + bounding_constraints.push_back(dec_vars_Y[i] + box.min.y() >= 0); + bounding_constraints.push_back(dec_vars_Y[i] + box.max.y() <= box_size_y); + } +} + + +void introduce_BedBoundingBox(z3::solver &Solver, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &polygons, + int box_min_x, + int box_min_y, + int box_max_x, + int box_max_y) +{ + for (unsigned int i = 0; i < polygons.size(); ++i) + { + BoundingBox box = get_extents(polygons[i]); + + Solver.add(dec_vars_X[i] + box.min.x() >= box_min_x); + Solver.add(dec_vars_X[i] + box.max.x() <= box_max_x); + + Solver.add(dec_vars_Y[i] + box.min.y() >= box_min_y); + Solver.add(dec_vars_Y[i] + box.max.y() <= box_max_y); + } +} + + +void assume_BedBoundingBox_(const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &polygons, + int box_min_x, + int box_min_y, + int box_max_x, + int box_max_y, + z3::expr_vector &bounding_constraints) +{ + for (unsigned int i = 0; i < polygons.size(); ++i) + { + BoundingBox box = get_extents(polygons[i]); + + bounding_constraints.push_back(dec_vars_X[i] + box.min.x() >= box_min_x); + bounding_constraints.push_back(dec_vars_X[i] + box.max.x() <= box_max_x); + + bounding_constraints.push_back(dec_vars_Y[i] + box.min.y() >= box_min_y); + bounding_constraints.push_back(dec_vars_Y[i] + box.max.y() <= box_max_y); + } +} + + +void assume_ConsequentialObjectPresence(z3::context &Context, + const z3::expr_vector &dec_vars_T, + const std::vector &present, + const std::vector &missing, + z3::expr_vector &presence_constraints) +{ + for (unsigned int i = 0; i < present.size(); ++i) + { + presence_constraints.push_back(dec_vars_T[present[i]] > Context.real_val(SEQ_TEMPORAL_PRESENCE_THRESHOLD)); + } + + for (unsigned int i = 0; i < missing.size(); ++i) + { + presence_constraints.push_back(dec_vars_T[missing[i]] < Context.real_val(SEQ_TEMPORAL_ABSENCE_THRESHOLD)); + } +} + + +void introduce_TemporalOrdering(z3::solver &Solver, + z3::context &SEQ_UNUSED(Context), + const z3::expr_vector &dec_vars_T, + int temporal_spread, + const std::vector &polygons) +{ + if (!polygons.empty()) + { + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + Solver.add(dec_vars_T[i] > dec_vars_T[j] + temporal_spread || dec_vars_T[i] + temporal_spread < dec_vars_T[j]); + } + } + } +} + + +void introduce_SequentialTemporalOrderingAgainstFixed(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + int temporal_spread, + const std::vector &SEQ_UNUSED(polygons)) +{ + if (!undecided.empty()) + { + for (unsigned int i = 0; i < undecided.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < undecided.size(); ++j) + { + Solver.add(dec_vars_T[undecided[i]] > dec_vars_T[undecided[j]] + temporal_spread || dec_vars_T[undecided[i]] + temporal_spread < dec_vars_T[undecided[j]]); + } + } + } + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + for (unsigned int j = 0; j < fixed.size(); ++j) + { + Solver.add( dec_vars_T[undecided[i]] > Context.real_val(dec_values_T[fixed[j]].numerator, dec_values_T[fixed[j]].denominator) + temporal_spread + || dec_vars_T[undecided[i]] + temporal_spread < Context.real_val(dec_values_T[fixed[j]].numerator, dec_values_T[fixed[j]].denominator)); + } + } + + #ifdef DEBUG + { + printf("Origo\n"); + for (unsigned int i = 0; i < fixed.size(); ++i) + { + printf("%.3f\n", dec_values_T[fixed[i]].as_double()); + } + } + #endif +} + + +void introduce_ConsequentialTemporalOrderingAgainstFixed(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + int temporal_spread, + const std::vector &SEQ_UNUSED(polygons)) +{ + if (!undecided.empty()) + { + for (unsigned int i = 0; i < undecided.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < undecided.size(); ++j) + { + Solver.add(dec_vars_T[undecided[i]] > dec_vars_T[undecided[j]] + temporal_spread || dec_vars_T[undecided[i]] + temporal_spread < dec_vars_T[undecided[j]]); + } + } + } + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + for (unsigned int j = 0; j < fixed.size(); ++j) + { + Solver.add( dec_vars_T[undecided[i]] > Context.real_val(dec_values_T[fixed[j]].numerator, dec_values_T[fixed[j]].denominator) + temporal_spread + || dec_vars_T[undecided[i]] + temporal_spread < Context.real_val(dec_values_T[fixed[j]].numerator, dec_values_T[fixed[j]].denominator)); + } + } + + #ifdef DEBUG + { + printf("Origo\n"); + for (unsigned int i = 0; i < fixed.size(); ++i) + { + printf("%.3f\n", dec_values_T[fixed[i]].as_double()); + } + } + #endif +} + + +bool is_undecided(int i, const std::vector &undecided) +{ + for (unsigned int j = 0; j < undecided.size(); ++j) + { + if (undecided[j] == i) + { + return true; + } + } + return false; +} + + +bool is_fixed(int i, const std::vector &fixed) +{ + for (unsigned int j = 0; j < fixed.size(); ++j) + { + if (fixed[j] == i) + { + return true; + } + } + return false; +} + + +bool is_targeted_by_undecided(int i, const std::vector &fixed, const std::vector &lepox_to_next) +{ + return (i > 0 && lepox_to_next[i - 1] && is_undecided(i - 1, fixed)); +} + + +bool is_targeted_by_fixed(int i, const std::vector &fixed, const std::vector &lepox_to_next) +{ + return (i > 0 && lepox_to_next[i - 1] && is_fixed(i - 1, fixed)); +} + + +void introduce_ConsequentialTemporalLepoxAgainstFixed(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + int temporal_spread, + const std::vector &SEQ_UNUSED(polygons), + const std::vector &lepox_to_next, + bool trans_bed_lepox) +{ + #ifdef DEBUG + { + if (trans_bed_lepox) + { + printf("Trans bed lepox.\n"); + } + printf("Undecided:\n"); + for (unsigned int i = 0; i < undecided.size(); ++i) + { + printf("%d", undecided[i]); + if (lepox_to_next[undecided[i]]) + { + printf("-> "); + } + printf(" "); + } + printf("\n"); + + printf("Fixed:\n"); + for (unsigned int i = 0; i < fixed.size(); ++i) + { + printf("%d", fixed[i]); + if (lepox_to_next[fixed[i]]) + { + printf("-> "); + } + printf(" "); + } + printf("\n"); + } + #endif + + /* Bed --> Bed */ + if (trans_bed_lepox) + { + if (is_undecided(0, undecided)) + { + #ifdef DEBUG + { + printf("Bed --> Bed: undecided 0 first\n"); + } + #endif + for (unsigned int j = 1; j < undecided.size(); ++j) + { + //Solver.add(dec_vars_T[0] + temporal_spread < dec_vars_T[undecided[j]]); + Solver.add(dec_vars_T[undecided[j]] < 0 || dec_vars_T[0] + temporal_spread < dec_vars_T[undecided[j]]); + } + } + else if (is_fixed(0, fixed)) + { + #ifdef DEBUG + { + printf("Bed --> Bed: fixed 0 still first\n"); + } + #endif + for (unsigned int j = 0; j < undecided.size(); ++j) + { + //Solver.add(Context.real_val(dec_values_T[0].numerator, dec_values_T[0].denominator) + temporal_spread < dec_vars_T[undecided[j]]); + Solver.add(dec_vars_T[undecided[j]] < 0 || Context.real_val(dec_values_T[0].numerator, dec_values_T[0].denominator) + temporal_spread < dec_vars_T[undecided[j]]); + } + } + else + { + // should not happen + assert(false); + } + } + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + if (lepox_to_next[undecided[i]]) + { + int next_i = undecided[i] + 1; + + /* Undecided --> Undecided */ + if (is_undecided(next_i, undecided)) + { + #ifdef DEBUG + { + printf("Undecided --> Undecided: %d --> %d standard\n", undecided[i], next_i); + } + #endif + //Solver.add(dec_vars_T[undecided[i]] + temporal_spread < dec_vars_T[next_i] && dec_vars_T[undecided[i]] + temporal_spread + temporal_spread / 2 > dec_vars_T[next_i]); + Solver.add((dec_vars_T[undecided[i]] < 0 || dec_vars_T[next_i] < 0) || dec_vars_T[undecided[i]] + temporal_spread < dec_vars_T[next_i] && dec_vars_T[undecided[i]] + temporal_spread + temporal_spread / 2 > dec_vars_T[next_i]); + } + /* Undecided --> missing */ + else + { + #ifdef DEBUG + { + printf("Undecided --> Undecided: %d missing\n", undecided[i]); + } + #endif + for (unsigned int j = 0; j < undecided.size(); ++j) + { + if (i != j) + { + //Solver.add(dec_vars_T[undecided[j]] + temporal_spread < dec_vars_T[undecided[i]]); + Solver.add(dec_vars_T[undecided[j]] < 0 || dec_vars_T[undecided[j]] + temporal_spread < dec_vars_T[undecided[i]]); + } + } + for (unsigned int j = 0; j < fixed.size(); ++j) + { + //Solver.add(Context.real_val(dec_values_T[fixed[j]].numerator, dec_values_T[fixed[j]].denominator) + temporal_spread < dec_vars_T[undecided[i]]); + Solver.add(dec_vars_T[undecided[i]] < 0 || Context.real_val(dec_values_T[fixed[j]].numerator, dec_values_T[fixed[j]].denominator) + temporal_spread < dec_vars_T[undecided[i]]); + } + } + } + } + for (unsigned int i = 0; i < fixed.size(); ++i) + { + if (lepox_to_next[fixed[i]]) + { + int next_i = fixed[i] + 1; + + /* Fixed --> Undecided */ + if (is_undecided(next_i, undecided)) + { + #ifdef DEBUG + { + printf("Fixed --> Undecided: %d --> %d standard\n", fixed[i], next_i); + } + #endif + /* + Solver.add( Context.real_val(dec_values_T[fixed[i]].numerator, dec_values_T[fixed[i]].denominator) + temporal_spread < dec_vars_T[next_i] + && Context.real_val(dec_values_T[fixed[i]].numerator, dec_values_T[fixed[i]].denominator) + temporal_spread + temporal_spread / 2 > dec_vars_T[next_i]); + */ + Solver.add(dec_vars_T[next_i] < 0 || ( Context.real_val(dec_values_T[fixed[i]].numerator, dec_values_T[fixed[i]].denominator) + temporal_spread < dec_vars_T[next_i] + && Context.real_val(dec_values_T[fixed[i]].numerator, dec_values_T[fixed[i]].denominator) + temporal_spread + temporal_spread / 2 > dec_vars_T[next_i])); + } + /* Fixed --> Fixed */ + else if (is_fixed(next_i, fixed)) + { + #ifdef DEBUG + { + printf("All out of the link: %d --> %d\n", fixed[i], next_i); + } + #endif + for (unsigned int j = 0; j < undecided.size(); ++j) + { + /* + Solver.add( Context.real_val(dec_values_T[fixed[i]].numerator, dec_values_T[fixed[i]].denominator) > dec_vars_T[undecided[j]] + temporal_spread + || Context.real_val(dec_values_T[next_i].numerator, dec_values_T[next_i].denominator) + temporal_spread < dec_vars_T[undecided[j]]); + */ + Solver.add(dec_vars_T[undecided[j]] < 0 || ( Context.real_val(dec_values_T[fixed[i]].numerator, dec_values_T[fixed[i]].denominator) > dec_vars_T[undecided[j]] + temporal_spread + || Context.real_val(dec_values_T[next_i].numerator, dec_values_T[next_i].denominator) + temporal_spread < dec_vars_T[undecided[j]])); + } + } + } + } + + #ifdef DEBUG + { + printf("Origo\n"); + for (unsigned int i = 0; i < fixed.size(); ++i) + { + printf("%.3f\n", dec_values_T[fixed[i]].as_double()); + } + } + #endif +} + + +/*----------------------------------------------------------------*/ + +void introduce_LineNonIntersection(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Line &line2) +{ + introduce_LineNonIntersection_implicit(Solver, + Context, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + line1, + dec_var_X2, + dec_var_Y2, + dec_var_T2, + line2); +} + + +void introduce_SequentialLineNonIntersection(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2) +{ + introduce_SequentialLineNonIntersection_implicit(Solver, + Context, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + dec_var_t1, + line1, + dec_var_X2, + dec_var_Y2, + dec_var_T2, + dec_var_t2, + line2); +} + + +void introduce_ConsequentialLineNonIntersection(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2) +{ + introduce_ConsequentialLineNonIntersection_implicit(Solver, + Context, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + dec_var_t1, + line1, + dec_var_X2, + dec_var_Y2, + dec_var_T2, + dec_var_t2, + line2); +} + + +void introduce_LineNonIntersection_implicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Line &line2) +{ + Point point; + + if (line1.intersection_infinite(line2, &point)) + { + int v1x = line1.b.x() - line1.a.x(); + int v1y = line1.b.y() - line1.a.y(); + + int v2x = line2.b.x() - line2.a.x(); + int v2y = line2.b.y() - line2.a.y(); + + #ifdef DEBUG + { + printf("adding constraint iota: [%d, %d, %d, %d] [%d, %d, %d, %d]\n", line1.a.x(), line1.a.y(), line1.b.x(), line1.b.y(), + line2.a.x(), line2.a.y(), line2.b.x(), line2.b.y()); + } + #endif + + Solver.add((dec_var_X1 + line1.a.x() + v1x * dec_var_T1) == (dec_var_X2 + line2.a.x() + v2x * dec_var_T2)); + Solver.add((dec_var_Y1 + line1.a.y() + v1y * dec_var_T1) == (dec_var_Y2 + line2.a.y() + v2y * dec_var_T2)); + + Solver.add( dec_var_T1 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_T1 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX) + || dec_var_T2 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_T2 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX)); + } +} + + +void introduce_SequentialLineNonIntersection_implicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2) +{ + Point point; + + if (line1.intersection_infinite(line2, &point)) + { + int v1x = line1.b.x() - line1.a.x(); + int v1y = line1.b.y() - line1.a.y(); + + int v2x = line2.b.x() - line2.a.x(); + int v2y = line2.b.y() - line2.a.y(); + + #ifdef DEBUG + { + printf("adding constraint seq: [%d, %d, %d, %d] [%d, %d, %d, %d]\n", line1.a.x(), line1.a.y(), line1.b.x(), line1.b.y(), + line2.a.x(), line2.a.y(), line2.b.x(), line2.b.y()); + } + #endif + + Solver.add((dec_var_X1 + line1.a.x() + v1x * dec_var_t1) == (dec_var_X2 + line2.a.x() + v2x * dec_var_t2)); + Solver.add((dec_var_Y1 + line1.a.y() + v1y * dec_var_t1) == (dec_var_Y2 + line2.a.y() + v2y * dec_var_t2)); + +// Solver.add(dec_var_T1 < dec_var_T2 || dec_var_t1 < 0 || dec_var_t1 > 1 || dec_var_t2 < 0 || dec_var_t2 > 1); + Solver.add( dec_var_T1 < dec_var_T2 + || dec_var_t1 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_t1 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX) + || dec_var_t2 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_t2 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX)); + } +} + + +void introduce_ConsequentialLineNonIntersection_implicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2) +{ + Point point; + + if (line1.intersection_infinite(line2, &point)) + { + int v1x = line1.b.x() - line1.a.x(); + int v1y = line1.b.y() - line1.a.y(); + + int v2x = line2.b.x() - line2.a.x(); + int v2y = line2.b.y() - line2.a.y(); + + #ifdef DEBUG + { + printf("adding constraint seq: [%d, %d, %d, %d] [%d, %d, %d, %d]\n", line1.a.x(), line1.a.y(), line1.b.x(), line1.b.y(), + line2.a.x(), line2.a.y(), line2.b.x(), line2.b.y()); + } + #endif + + Solver.add((dec_var_X1 + line1.a.x() + v1x * dec_var_t1) == (dec_var_X2 + line2.a.x() + v2x * dec_var_t2)); + Solver.add((dec_var_Y1 + line1.a.y() + v1y * dec_var_t1) == (dec_var_Y2 + line2.a.y() + v2y * dec_var_t2)); + +// Solver.add(dec_var_T1 < dec_var_T2 || dec_var_t1 < 0 || dec_var_t1 > 1 || dec_var_t2 < 0 || dec_var_t2 > 1); + Solver.add( dec_var_T1 < 0 + || dec_var_T2 < 0 + || dec_var_T1 < dec_var_T2 + || dec_var_t1 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_t1 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX) + || dec_var_t2 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_t2 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX)); + } +} + + +void introduce_LineNonIntersection_explicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Line &line2) +{ + Point point; + if (line1.intersection_infinite(line2, &point)) + { + int v1x = line1.b.x() - line1.a.x(); + int v1y = line1.b.y() - line1.a.y(); + + int v2x = line2.b.x() - line2.a.x(); + int v2y = line2.b.y() - line2.a.y(); + + if (abs(v2x) > 0) + { + int coef_T1 = v1y * v2x - v1x * v2y; + int d1 = v2x * line1.a.y() - v2x * line2.a.y() - v2y * line1.a.x() + v2y * line2.a.x(); + + int coef_X1 = -v2y; + int coef_Y1 = v2x; + + int coef_X2 = v2y; + int coef_Y2 = -v2x; + + Solver.add( ((coef_X1 * dec_var_X1) + + (coef_Y1 * dec_var_Y1) + + (coef_X2 * dec_var_X2) + + (coef_Y2 * dec_var_Y2) + + (coef_T1 * dec_var_T1) + + d1) == 0); + + int d2 = line1.a.x() - line2.a.x(); + + Solver.add( (dec_var_X1 + - dec_var_X2 + + v1x * dec_var_T1 + - v2x * dec_var_T2 + + d2) == 0); + + Solver.add( dec_var_T1 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_T1 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX) + || dec_var_T2 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_T2 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX)); + } + else + { + if (abs(v2y) > 0) + { + int coef_T2 = v1y * v2x - v1x * v2y; + int d1 = v2y * line1.a.x() - v2y * line2.a.x() - v2x * line1.a.y() + v2x * line2.a.y(); + + int coef_X1 = v2y; + int coef_Y1 = -v2x; + + int coef_X2 = -v2y; + int coef_Y2 = v2x; + + Solver.add( ((coef_X1 * dec_var_X1) + + (coef_Y1 * dec_var_Y1) + + (coef_X2 * dec_var_X2) + + (coef_Y2 * dec_var_Y2) + + (coef_T2 * dec_var_T2) + + d1) == 0); + + int d2 = line1.a.y() - line2.a.y(); + + Solver.add( (dec_var_Y1 + - dec_var_Y2 + + v1y * dec_var_T1 + - v2y* dec_var_T2 + + d2) == 0); + + Solver.add( dec_var_T1 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_T1 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX) + || dec_var_T2 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_T2 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX)); + } + else + { + /* intersection not possible, the second line is empty */ + assert(false); + } + } + } +} + + + +void introduce_LineNonIntersectionAgainstFixedLine(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Line &line2) +{ + introduce_LineNonIntersectionAgainstFixedLine_implicit(Solver, + Context, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + line1, + dec_value_X2, + dec_value_Y2, + dec_var_T2, + line2); +} + + +void introduce_SequentialLineNonIntersectionAgainstFixedLine(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2) +{ + introduce_SequentialLineNonIntersectionAgainstFixedLine_implicit(Solver, + Context, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + dec_var_t1, + line1, + dec_value_X2, + dec_value_Y2, + dec_value_T2, + dec_var_t2, + line2); +} + + +void introduce_SequentialFixedLineNonIntersectionAgainstLine(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const Rational &dec_value_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2) +{ + introduce_SequentialFixedLineNonIntersectionAgainstLine_implicit(Solver, + Context, + dec_value_X1, + dec_value_Y1, + dec_value_T1, + dec_var_t1, + line1, + dec_var_X2, + dec_var_Y2, + dec_var_T2, + dec_var_t2, + line2); +} + + +void introduce_ConsequentialLineNonIntersectionAgainstFixedLine(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2) +{ + introduce_ConsequentialLineNonIntersectionAgainstFixedLine_implicit(Solver, + Context, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + dec_var_t1, + line1, + dec_value_X2, + dec_value_Y2, + dec_value_T2, + dec_var_t2, + line2); +} + + +void introduce_ConsequentialFixedLineNonIntersectionAgainstLine(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const Rational &dec_value_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2) +{ + introduce_ConsequentialFixedLineNonIntersectionAgainstLine_implicit(Solver, + Context, + dec_value_X1, + dec_value_Y1, + dec_value_T1, + dec_var_t1, + line1, + dec_var_X2, + dec_var_Y2, + dec_var_T2, + dec_var_t2, + line2); +} + + +void introduce_LineNonIntersectionAgainstFixedLine_implicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Line &line2) +{ + Point point; + + if (line1.intersection_infinite(line2, &point)) + { + int v1x = line1.b.x() - line1.a.x(); + int v1y = line1.b.y() - line1.a.y(); + + int v2x = line2.b.x() - line2.a.x(); + int v2y = line2.b.y() - line2.a.y(); + + #ifdef DEBUG + { + printf("adding constraint alpha [%d, %d, %d, %d] [%d, %d, %d, %d]\n", line1.a.x(), line1.a.y(), line1.b.x(), line1.b.y(), + line2.a.x(), line2.a.y(), line2.b.x(), line2.b.y()); + } + #endif + + Solver.add((dec_var_X1 + line1.a.x() + v1x * dec_var_T1) == (Context.real_val(dec_value_X2.numerator, dec_value_X2.denominator) + line2.a.x() + v2x * dec_var_T2)); + Solver.add((dec_var_Y1 + line1.a.y() + v1y * dec_var_T1) == (Context.real_val(dec_value_Y2.numerator, dec_value_Y2.denominator) + line2.a.y() + v2y * dec_var_T2)); + + Solver.add( dec_var_T1 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_T1 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX) + || dec_var_T2 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_T2 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX)); + } +} + + +void introduce_LineNonIntersectionAgainstFixedLine_explicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Line &line2) +{ + Point point; + if (line1.intersection_infinite(line2, &point)) + { + int v1x = line1.b.x() - line1.a.x(); + int v1y = line1.b.y() - line1.a.y(); + + int v2x = line2.b.x() - line2.a.x(); + int v2y = line2.b.y() - line2.a.y(); + + if (abs(v2x) > 0) + { + int coef_T1 = v1y * v2x - v1x * v2y; + int d1 = v2x * line1.a.y() - v2x * line2.a.y() - v2y * line1.a.x() + v2y * line2.a.x(); + + int coef_X1 = -v2y; + int coef_Y1 = v2x; + + int coef_X2 = v2y; + int coef_Y2 = -v2x; + + Solver.add( ((coef_X1 * dec_var_X1) + + (coef_Y1 * dec_var_Y1) + + (coef_X2 * Context.real_val(dec_value_X2.numerator, dec_value_X2.denominator)) + + (coef_Y2 * Context.real_val(dec_value_Y2.numerator, dec_value_Y2.denominator)) + + (coef_T1 * dec_var_T1) + + d1) == 0); + + int d2 = line1.a.x() - line2.a.x(); + + Solver.add( (dec_var_X1 + - Context.real_val(dec_value_X2.numerator, dec_value_X2.denominator) + + v1x * dec_var_T1 + - v2x * dec_var_T2 + + d2) == 0); + + Solver.add( dec_var_T1 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_T1 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX) + || dec_var_T2 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_T2 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX)); + } + else + { + if (abs(v2y) > 0) + { + int coef_T2 = v1y * v2x - v1x * v2y; + int d1 = v2y * line1.a.x() - v2y * line2.a.x() - v2x * line1.a.y() + v2x * line2.a.y(); + + int coef_X1 = v2y; + int coef_Y1 = -v2x; + + int coef_X2 = -v2y; + int coef_Y2 = v2x; + + Solver.add( ( (coef_X1 * dec_var_X1) + + (coef_Y1 * dec_var_Y1) + + (coef_X2 * Context.real_val(dec_value_X2.numerator, dec_value_X2.denominator)) + + (coef_Y2 * Context.real_val(dec_value_Y2.numerator, dec_value_Y2.denominator)) + + (coef_T2 * dec_var_T2) + + d1) == 0); + + int d2 = line1.a.y() - line2.a.y(); + + Solver.add( ( dec_var_Y1 + - Context.real_val(dec_value_Y2.numerator, dec_value_Y2.denominator) + + v1y * dec_var_T1 + - v2y* dec_var_T2 + + d2) == 0); + + Solver.add( dec_var_T1 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_T1 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX) + || dec_var_T2 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_T2 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX)); + } + else + { + /* intersection not possible, the second line is empty */ + assert(false); + } + } + } +} + + +void introduce_SequentialLineNonIntersectionAgainstFixedLine_implicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2) +{ + Point point; + + if (line1.intersection_infinite(line2, &point)) + { + int v1x = line1.b.x() - line1.a.x(); + int v1y = line1.b.y() - line1.a.y(); + + int v2x = line2.b.x() - line2.a.x(); + int v2y = line2.b.y() - line2.a.y(); + + #ifdef DEBUG + { + printf("adding constraint beta: [%d, %d, %d, %d] [%d, %d, %d, %d] (%.3f,%.3f,%.3f)\n", line1.a.x(), line1.a.y(), line1.b.x(), line1.b.y(), + line2.a.x(), line2.a.y(), line2.b.x(), line2.b.y(), dec_value_X2.as_double(), dec_value_Y2.as_double(), dec_value_T2.as_double()); + printf("v1: %d,%d v2:%d,%d\n", v1x, v1y, v2x, v2y); + } + #endif + + Solver.add((dec_var_X1 + line1.a.x() + v1x * dec_var_t1) == (Context.real_val(dec_value_X2.numerator, dec_value_X2.denominator) + line2.a.x() + v2x * dec_var_t2)); + Solver.add((dec_var_Y1 + line1.a.y() + v1y * dec_var_t1) == (Context.real_val(dec_value_Y2.numerator, dec_value_Y2.denominator) + line2.a.y() + v2y * dec_var_t2)); + + Solver.add( (dec_var_T1 < Context.real_val(dec_value_T2.numerator, dec_value_T2.denominator)) + || (dec_var_t1 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN)) + || (dec_var_t1 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX)) + || (dec_var_t2 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN)) + || (dec_var_t2 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX))); + } +} + + +void introduce_SequentialFixedLineNonIntersectionAgainstLine_implicit(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const Rational &dec_value_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2) +{ + Point point; + + if (line1.intersection_infinite(line2, &point)) + { + int v1x = line1.b.x() - line1.a.x(); + int v1y = line1.b.y() - line1.a.y(); + + int v2x = line2.b.x() - line2.a.x(); + int v2y = line2.b.y() - line2.a.y(); + + #ifdef DEBUG + { + printf("adding constraint gamma: [%d, %d, %d, %d] [%d, %d, %d, %d]\n", line1.a.x(), line1.a.y(), line1.b.x(), line1.b.y(), + line2.a.x(), line2.a.y(), line2.b.x(), line2.b.y()); + } + #endif + + Solver.add((Context.real_val(dec_value_X1.numerator, dec_value_X1.denominator) + line1.a.x() + v1x * dec_var_t1) == (dec_var_X2 + line2.a.x() + v2x * dec_var_t2)); + Solver.add((Context.real_val(dec_value_Y1.numerator, dec_value_Y1.denominator) + line1.a.y() + v1y * dec_var_t1) == (dec_var_Y2 + line2.a.y() + v2y * dec_var_t2)); + + Solver.add( Context.real_val(dec_value_T1.numerator, dec_value_T1.denominator) < dec_var_T2 + || dec_var_t1 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_t1 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX) + || dec_var_t2 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_t2 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX)); + } +} + + +void introduce_ConsequentialLineNonIntersectionAgainstFixedLine_implicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2) +{ + + if (dec_value_T2.is_Positive()) + { + Point point; + + if (line1.intersection_infinite(line2, &point)) + { + int v1x = line1.b.x() - line1.a.x(); + int v1y = line1.b.y() - line1.a.y(); + + int v2x = line2.b.x() - line2.a.x(); + int v2y = line2.b.y() - line2.a.y(); + + #ifdef DEBUG + { + printf("adding constraint beta: [%d, %d, %d, %d] [%d, %d, %d, %d] (%.3f,%.3f,%.3f)\n", line1.a.x(), line1.a.y(), line1.b.x(), line1.b.y(), + line2.a.x(), line2.a.y(), line2.b.x(), line2.b.y(), dec_value_X2.as_double(), dec_value_Y2.as_double(), dec_value_T2.as_double()); + printf("v1: %d,%d v2:%d,%d\n", v1x, v1y, v2x, v2y); + } + #endif + + Solver.add((dec_var_X1 + line1.a.x() + v1x * dec_var_t1) == (Context.real_val(dec_value_X2.numerator, dec_value_X2.denominator) + line2.a.x() + v2x * dec_var_t2)); + Solver.add((dec_var_Y1 + line1.a.y() + v1y * dec_var_t1) == (Context.real_val(dec_value_Y2.numerator, dec_value_Y2.denominator) + line2.a.y() + v2y * dec_var_t2)); + + Solver.add( dec_var_T1 < 0 + || (dec_var_T1 < Context.real_val(dec_value_T2.numerator, dec_value_T2.denominator)) + || (dec_var_t1 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN)) + || (dec_var_t1 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX)) + || (dec_var_t2 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN)) + || (dec_var_t2 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX))); + } + } +} + + +void introduce_ConsequentialFixedLineNonIntersectionAgainstLine_implicit(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const Rational &dec_value_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2) +{ + if (dec_value_T1.is_Positive()) + { + Point point; + + if (line1.intersection_infinite(line2, &point)) + { + int v1x = line1.b.x() - line1.a.x(); + int v1y = line1.b.y() - line1.a.y(); + + int v2x = line2.b.x() - line2.a.x(); + int v2y = line2.b.y() - line2.a.y(); + + #ifdef DEBUG + { + printf("adding constraint gamma: [%d, %d, %d, %d] [%d, %d, %d, %d]\n", line1.a.x(), line1.a.y(), line1.b.x(), line1.b.y(), + line2.a.x(), line2.a.y(), line2.b.x(), line2.b.y()); + } + #endif + + Solver.add((Context.real_val(dec_value_X1.numerator, dec_value_X1.denominator) + line1.a.x() + v1x * dec_var_t1) == (dec_var_X2 + line2.a.x() + v2x * dec_var_t2)); + Solver.add((Context.real_val(dec_value_Y1.numerator, dec_value_Y1.denominator) + line1.a.y() + v1y * dec_var_t1) == (dec_var_Y2 + line2.a.y() + v2y * dec_var_t2)); + + Solver.add( dec_var_T2 < 0 + || Context.real_val(dec_value_T1.numerator, dec_value_T1.denominator) < dec_var_T2 + || dec_var_t1 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_t1 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX) + || dec_var_t2 < Context.real_val(SEQ_INTERSECTION_REPULSION_MIN) + || dec_var_t2 > Context.real_val(SEQ_INTERSECTION_REPULSION_MAX)); + } + } +} + + +/*----------------------------------------------------------------*/ + +void introduce_PointInsideHalfPlane(z3::solver &Solver, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Line &halving_line) +{ + Vector normal = halving_line.normal(); + + Solver.add( (normal.x() * dec_var_X1) + + (normal.y() * dec_var_Y1) + - (normal.x() * dec_var_X2 + normal.x() * halving_line.a.x()) + - (normal.y() * dec_var_Y2 + normal.y() * halving_line.a.y()) < 0); +} + + +void introduce_PointOutsideHalfPlane(z3::solver &Solver, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Line &halving_line) +{ + Vector normal = halving_line.normal(); + + Solver.add( (normal.x() * dec_var_X1) + + (normal.y() * dec_var_Y1) + - (normal.x() * dec_var_X2 + normal.x() * halving_line.a.x()) + - (normal.y() * dec_var_Y2 + normal.y() * halving_line.a.y()) > 0); +} + + +void introduce_PointInsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Polygon &polygon) +{ + if (polygon.points.size() >= 3) + { + z3::expr in_conjunction(Context); + + for (Points::const_iterator point = polygon.points.begin(); point != polygon.points.end(); ++point) + { + Points::const_iterator next_point = point + 1; + if (next_point == polygon.points.end()) + { + next_point = polygon.points.begin(); + } + + Line line(*point, *next_point); + Vector normal = line.normal(); + + z3::expr inside_half_plane( (normal.x() * dec_var_X1) + + (normal.y() * dec_var_Y1) + - (normal.x() * dec_var_X2) + - (normal.x() * line.a.x()) + - (normal.y() * dec_var_Y2) + - (normal.y() * line.a.y()) < 0); + + if (point == polygon.points.begin()) + { + in_conjunction = inside_half_plane; + } + else + { + in_conjunction = in_conjunction && inside_half_plane; + } + } + + Solver.add(in_conjunction); + } +} + + +void assume_PointInsidePolygon(z3::context &Context, + const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + const Slic3r::Polygon &polygon, + z3::expr_vector &constraints) +{ + if (polygon.points.size() >= 3) + { + z3::expr in_conjunction(Context); + + for (Points::const_iterator point = polygon.points.begin(); point != polygon.points.end(); ++point) + { + Points::const_iterator next_point = point + 1; + if (next_point == polygon.points.end()) + { + next_point = polygon.points.begin(); + } + + Line line(*point, *next_point); + Vector normal = line.normal(); + + z3::expr inside_half_plane( (normal.x() * dec_var_X) + + (normal.y() * dec_var_Y) + - (normal.x() * line.a.x()) + - (normal.y() * line.a.y()) < 0); + + if (point == polygon.points.begin()) + { + in_conjunction = inside_half_plane; + } + else + { + in_conjunction = in_conjunction && inside_half_plane; + } + } + constraints.push_back(in_conjunction); + } +} + + +/*----------------------------------------------------------------*/ + +void introduce_PointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Polygon &polygon) +{ + if (polygon.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon.points.size(); ++p) + { + int np = (p + 1) % polygon.points.size(); + + Line line(polygon.points[p], polygon.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * dec_var_X1) + + (normal.y() * dec_var_Y1) + - (normal.x() * dec_var_X2) + - (normal.x() * line.a.x()) + - (normal.y() * dec_var_Y2) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } +} + + +void introduce_SequentialPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2) +{ + if (polygon2.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon2.points.size(); ++p) + { + int np = (p + 1) % polygon2.points.size(); + + Line line(polygon2.points[p], polygon2.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * dec_var_X1) + + (normal.y() * dec_var_Y1) + - (normal.x() * dec_var_X2) + - (normal.x() * line.a.x()) + - (normal.y() * dec_var_Y2) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = (dec_var_T1 < dec_var_T2) || outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } +} + + +void introduce_ConsequentialPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2) +{ + if (polygon2.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon2.points.size(); ++p) + { + int np = (p + 1) % polygon2.points.size(); + + Line line(polygon2.points[p], polygon2.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * dec_var_X1) + + (normal.y() * dec_var_Y1) + - (normal.x() * dec_var_X2) + - (normal.x() * line.a.x()) + - (normal.y() * dec_var_Y2) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = (dec_var_T1 < 0) || (dec_var_T2 < 0) || (dec_var_T1 < dec_var_T2) || outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } +} + + +void introduce_ShiftSequentialPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + int x, + int y, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2) +{ + if (polygon2.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon2.points.size(); ++p) + { + int np = (p + 1) % polygon2.points.size(); + + Line line(polygon2.points[p], polygon2.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * dec_var_X1) + (normal.x() * x) + + (normal.y() * dec_var_Y1) + (normal.y() * y) + - (normal.x() * dec_var_X2) + - (normal.x() * line.a.x()) + - (normal.y() * dec_var_Y2) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = (dec_var_T1 < dec_var_T2) || outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } +} + + +void introduce_ShiftConsequentialPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + int x, + int y, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2) +{ + if (polygon2.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon2.points.size(); ++p) + { + int np = (p + 1) % polygon2.points.size(); + + Line line(polygon2.points[p], polygon2.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * dec_var_X1) + (normal.x() * x) + + (normal.y() * dec_var_Y1) + (normal.y() * y) + - (normal.x() * dec_var_X2) + - (normal.x() * line.a.x()) + - (normal.y() * dec_var_Y2) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = (dec_var_T1 < 0) || (dec_var_T2 < 0) || (dec_var_T1 < dec_var_T2) || outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } +} + + +void introduce_FixedPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Polygon &polygon) +{ + if (polygon.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon.points.size(); ++p) + { + int np = (p + 1) % polygon.points.size(); + + Line line(polygon.points[p], polygon.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * Context.real_val(dec_value_X1.numerator, dec_value_X1.denominator)) + + (normal.y() * Context.real_val(dec_value_Y1.numerator, dec_value_Y1.denominator)) + - (normal.x() * dec_var_X2) + - (normal.x() * line.a.x()) + - (normal.y() * dec_var_Y2) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } +} + + +void introduce_SequentialFixedPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const Rational &dec_value_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon) +{ + if (polygon.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon.points.size(); ++p) + { + int np = (p + 1) % polygon.points.size(); + + Line line(polygon.points[p], polygon.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * Context.real_val(dec_value_X1.numerator, dec_value_X1.denominator)) + + (normal.y() * Context.real_val(dec_value_Y1.numerator, dec_value_Y1.denominator)) + - (normal.x() * dec_var_X2) + - (normal.x() * line.a.x()) + - (normal.y() * dec_var_Y2) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = (Context.real_val(dec_value_T1.numerator, dec_value_T1.denominator) < dec_var_T2) || outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } +} + + +void introduce_SequentialFixedPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon) +{ + if (polygon.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon.points.size(); ++p) + { + int np = (p + 1) % polygon.points.size(); + Line line(polygon.points[p], polygon.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * Context.real_val(dec_value_X1.numerator, dec_value_X1.denominator)) + + (normal.y() * Context.real_val(dec_value_Y1.numerator, dec_value_Y1.denominator)) + - (normal.x() * dec_var_X2) + - (normal.x() * line.a.x()) + - (normal.y() * dec_var_Y2) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = (dec_var_T1 < Context.real_val(dec_value_T2.numerator, dec_value_T2.denominator)) || outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } +} + + +void introduce_ConsequentialFixedPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const Rational &dec_value_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon) +{ + if (dec_value_T1.is_Positive()) + { + if (polygon.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon.points.size(); ++p) + { + int np = (p + 1) % polygon.points.size(); + + Line line(polygon.points[p], polygon.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * Context.real_val(dec_value_X1.numerator, dec_value_X1.denominator)) + + (normal.y() * Context.real_val(dec_value_Y1.numerator, dec_value_Y1.denominator)) + - (normal.x() * dec_var_X2) + - (normal.x() * line.a.x()) + - (normal.y() * dec_var_Y2) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = (dec_var_T2 < 0) || (Context.real_val(dec_value_T1.numerator, dec_value_T1.denominator) < dec_var_T2) || outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } + } +} + + +void introduce_ConsequentialFixedPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon) +{ + if (dec_value_T2.is_Positive()) + { + if (polygon.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon.points.size(); ++p) + { + int np = (p + 1) % polygon.points.size(); + Line line(polygon.points[p], polygon.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * Context.real_val(dec_value_X1.numerator, dec_value_X1.denominator)) + + (normal.y() * Context.real_val(dec_value_Y1.numerator, dec_value_Y1.denominator)) + - (normal.x() * dec_var_X2) + - (normal.x() * line.a.x()) + - (normal.y() * dec_var_Y2) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = (dec_var_T1 < 0) || (dec_var_T1 < Context.real_val(dec_value_T2.numerator, dec_value_T2.denominator)) || outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } + } +} + + +void introduce_PointOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Slic3r::Polygon &polygon) +{ + if (polygon.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon.points.size(); ++p) + { + int np = (p + 1) % polygon.points.size(); + + Line line(polygon.points[p], polygon.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * dec_var_X1) + + (normal.y() * dec_var_Y1) + - (normal.x() * Context.real_val(dec_value_X2.numerator, dec_value_X2.denominator)) + - (normal.x() * line.a.x()) + - (normal.y() * Context.real_val(dec_value_Y2.numerator, dec_value_Y2.denominator)) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } +} + + +void introduce_SequentialPointOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon) +{ + if (polygon.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon.points.size(); ++p) + { + int np = (p + 1) % polygon.points.size(); + + Line line(polygon.points[p], polygon.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * dec_var_X1) + + (normal.y() * dec_var_Y1) + - (normal.x() * Context.real_val(dec_value_X2.numerator, dec_value_X2.denominator)) + - (normal.x() * line.a.x()) + - (normal.y() * Context.real_val(dec_value_Y2.numerator, dec_value_Y2.denominator)) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = (dec_var_T1 < Context.real_val(dec_value_T2.numerator, dec_value_T2.denominator)) || outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } +} + + +void introduce_SequentialPointOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const Rational &dec_value_T1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon) +{ + if (polygon.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon.points.size(); ++p) + { + int np = (p + 1) % polygon.points.size(); + + Line line(polygon.points[p], polygon.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * dec_var_X1) + + (normal.y() * dec_var_Y1) + - (normal.x() * Context.real_val(dec_value_X2.numerator, dec_value_X2.denominator)) + - (normal.x() * line.a.x()) + - (normal.y() * Context.real_val(dec_value_Y2.numerator, dec_value_Y2.denominator)) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = (Context.real_val(dec_value_T1.numerator, dec_value_T1.denominator) < dec_var_T2) || outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } +} + + +void introduce_ConsequentialPointOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon) +{ + if (dec_value_T2.is_Positive()) + { + if (polygon.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon.points.size(); ++p) + { + int np = (p + 1) % polygon.points.size(); + + Line line(polygon.points[p], polygon.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * dec_var_X1) + + (normal.y() * dec_var_Y1) + - (normal.x() * Context.real_val(dec_value_X2.numerator, dec_value_X2.denominator)) + - (normal.x() * line.a.x()) + - (normal.y() * Context.real_val(dec_value_Y2.numerator, dec_value_Y2.denominator)) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = (dec_var_T1 < 0) || (dec_var_T1 < Context.real_val(dec_value_T2.numerator, dec_value_T2.denominator)) || outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } + } +} + + +void introduce_ConsequentialPointOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const Rational &dec_value_T1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon) +{ + if (dec_value_T1.is_Positive()) + { + if (polygon.points.size() >= 3) + { + z3::expr out_disjunction(Context); + + for (unsigned int p = 0; p < polygon.points.size(); ++p) + { + int np = (p + 1) % polygon.points.size(); + + Line line(polygon.points[p], polygon.points[np]); + Vector normal = line.normal(); + + z3::expr outside_half_plane( (normal.x() * dec_var_X1) + + (normal.y() * dec_var_Y1) + - (normal.x() * Context.real_val(dec_value_X2.numerator, dec_value_X2.denominator)) + - (normal.x() * line.a.x()) + - (normal.y() * Context.real_val(dec_value_Y2.numerator, dec_value_Y2.denominator)) + - (normal.y() * line.a.y()) > 0); + + if (p == 0) + { + out_disjunction = (dec_var_T2 < 0) || (Context.real_val(dec_value_T1.numerator, dec_value_T1.denominator) < dec_var_T2) || outside_half_plane; + } + else + { + out_disjunction = out_disjunction || outside_half_plane; + } + } + + Solver.add(out_disjunction); + } + } +} + +void introduce_PolygonLineNonIntersection(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const Slic3r::Polygon &polygon1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Polygon &polygon2) +{ + for (unsigned int p1 = 0; p1 < polygon1.points.size(); ++p1) + { + const Point &point1 = polygon1.points[p1]; + const Point &next_point1 = polygon1.points[(p1 + 1) % polygon1.points.size()]; + + for (unsigned int p2 = 0; p2 < polygon2.points.size(); ++p2) + { + const Point &point2 = polygon2.points[p2]; + const Point &next_point2 = polygon2.points[(p2 + 1) % polygon2.points.size()]; + + introduce_LineNonIntersection(Solver, + Context, + dec_var_X1, + dec_var_Y1, + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_var_X2, + dec_var_Y2, + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + } + } +} + + +void introduce_PolygonOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const Slic3r::Polygon &polygon1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Polygon &polygon2) +{ + for (unsigned int p1 = 0; p1 < polygon1.points.size(); ++p1) + { + const Point &point1 = polygon1.points[p1]; + + introduce_PointOutsidePolygon(Solver, + Context, + dec_var_X1 + point1.x(), + dec_var_Y1 + point1.y(), + dec_var_X2, + dec_var_Y2, + polygon2); + } + + for (unsigned int p2 = 0; p2 < polygon2.points.size(); ++p2) + { + const Point &point2 = polygon2.points[p2]; + + introduce_PointOutsidePolygon(Solver, + Context, + dec_var_X2 + point2.x(), + dec_var_Y2 + point2.y(), + dec_var_X1, + dec_var_Y1, + polygon1); + } +} + + +void introduce_PolygonOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const Slic3r::Polygon &polygon1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Slic3r::Polygon &polygon2) +{ + for (unsigned int p1 = 0; p1 < polygon1.points.size(); ++p1) + { + const Point &point1 = polygon1.points[p1]; + + introduce_PointOutsideFixedPolygon(Solver, + Context, + dec_var_X1 + point1.x(), + dec_var_Y1 + point1.y(), + dec_value_X2, + dec_value_Y2, + polygon2); + } + + for (unsigned int p2 = 0; p2 < polygon2.points.size(); ++p2) + { + const Point &point2 = polygon2.points[p2]; + + introduce_FixedPointOutsidePolygon(Solver, + Context, + dec_value_X2 + point2.x(), + dec_value_Y2 + point2.y(), + dec_var_X1, + dec_var_Y1, + polygon1); + } +} + + +void introduce_SequentialPolygonOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const Slic3r::Polygon &unreachable_polygon1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2, + const Slic3r::Polygon &unreachable_polygon2) +{ + std::vector _unreachable_polygons1; + _unreachable_polygons1.push_back(unreachable_polygon1); + + std::vector _unreachable_polygons2; + _unreachable_polygons2.push_back(unreachable_polygon2); + + introduce_SequentialPolygonOutsidePolygon(Solver, + Context, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + polygon1, + _unreachable_polygons1, + dec_var_X2, + dec_var_Y2, + dec_var_T2, + polygon2, + _unreachable_polygons2); +} + + +void introduce_SequentialPolygonOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const std::vector &unreachable_polygons1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2, + const std::vector &unreachable_polygons2) +{ +// Solver.add(dec_var_T1 < dec_var_T2); + + #ifdef DEBUG + { + printf("polygon1:\n"); + for (unsigned int p1 = 0; p1 < polygon1.points.size(); ++p1) + { + printf("[%d,%d] ", polygon1.points[p1].x(), polygon1.points[p1].y()); + } + printf("\n"); + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + printf("pro_polygon1 %d:\n", poly1); + for (unsigned int p1 = 0; p1 < unreachable_polygons1[poly1].points.size(); ++p1) + { + printf("[%d,%d] ", unreachable_polygons1[poly1].points[p1].x(), unreachable_polygons1[poly1].points[p1].y()); + } + printf("\n"); + } + printf("\n"); + + printf("polygon2:\n"); + for (unsigned int p2 = 0; p2 < polygon2.points.size(); ++p2) + { + printf("[%d,%d] ", polygon2.points[p2].x(), polygon2.points[p2].y()); + } + printf("\n"); + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + printf("pro_polygon2 %d:\n", poly2); + for (unsigned int p2 = 0; p2 < unreachable_polygons2[poly2].points.size(); ++p2) + { + printf("[%d,%d] ", unreachable_polygons2[poly2].points[p2].x(), unreachable_polygons2[poly2].points[p2].y()); + } + printf("\n"); + } + printf("\n"); + } + #endif + + + for (unsigned int p1 = 0; p1 < polygon1.points.size(); ++p1) + { + const Point &point1 = polygon1.points[p1]; + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + introduce_SequentialPointOutsidePolygon(Solver, + Context, + dec_var_X1 + point1.x(), + dec_var_Y1 + point1.y(), + dec_var_T1, + dec_var_X2, + dec_var_Y2, + dec_var_T2, + unreachable_polygons2[poly2]); + } + } + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + for (unsigned int p2 = 0; p2 < unreachable_polygons2[poly2].points.size(); ++p2) + { + const Point &pro_point2 = unreachable_polygons2[poly2].points[p2]; + + introduce_SequentialPointOutsidePolygon(Solver, + Context, + dec_var_X2 + pro_point2.x(), + dec_var_Y2 + pro_point2.y(), + dec_var_T1, + dec_var_X1, + dec_var_Y1, + dec_var_T2, + polygon1); + } + } + + for (unsigned int p2 = 0; p2 < polygon2.points.size(); ++p2) + { + const Point &point2 = polygon2.points[p2]; + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + /* + introduce_ShiftSequentialPointOutsidePolygon(Solver, + Context, + point2.x(), + point2.y(), + dec_var_X2, + dec_var_Y2, + dec_var_T2, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + polygon1); + unreachable_polygons1[poly1]); + */ + introduce_SequentialPointOutsidePolygon(Solver, + Context, + dec_var_X2 + point2.x(), + dec_var_Y2 + point2.y(), + dec_var_T2, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + unreachable_polygons1[poly1]); + } + } + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons1[poly1].points.size(); ++p1) + { + const Point &pro_point1 = unreachable_polygons1[poly1].points[p1]; + + introduce_SequentialPointOutsidePolygon(Solver, + Context, + dec_var_X1 + pro_point1.x(), + dec_var_Y1 + pro_point1.y(), + dec_var_T2, + dec_var_X2, + dec_var_Y2, + dec_var_T1, + polygon2); + } + } +/* + for (unsigned int p1 = 0; p1 < polygon1.points.size(); ++p1) + { + const Point &point1 = polygon1.points[p1]; + + introduce_PointOutsidePolygon(Solver, + Context, + dec_var_X1 + point1.x(), + dec_var_Y1 + point1.y(), + dec_var_X2, + dec_var_Y2, + polygon2); + } +*/ +/* + for (unsigned int p2 = 0; p2 < polygon2.points.size(); ++p2) + { + const Point &point2 = polygon2.points[p2]; + + introduce_PointOutsidePolygon(Solver, + Context, + dec_var_X2 + point2.x(), + dec_var_Y2 + point2.y(), + dec_var_X1, + dec_var_Y1, + polygon1); + } +*/ +} + + + +void introduce_SequentialPolygonOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const Slic3r::Polygon &unreachable_polygon1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon2, + const Slic3r::Polygon &unreachable_polygon2) +{ + std::vector _unreachable_polygons1; + _unreachable_polygons1.push_back(unreachable_polygon1); + + std::vector _unreachable_polygons2; + _unreachable_polygons2.push_back(unreachable_polygon2); + + introduce_SequentialPolygonOutsideFixedPolygon(Solver, + Context, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + polygon1, + _unreachable_polygons1, + dec_value_X2, + dec_value_Y2, + dec_value_T2, + polygon2, + _unreachable_polygons2); +} + + +void introduce_SequentialPolygonOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const std::vector &unreachable_polygons1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon2, + const std::vector &unreachable_polygons2) +{ + for (unsigned int p1 = 0; p1 < polygon1.points.size(); ++p1) + { + const Point &point1 = polygon1.points[p1]; + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + introduce_SequentialPointOutsideFixedPolygon(Solver, + Context, + dec_var_X1 + point1.x(), + dec_var_Y1 + point1.y(), + dec_var_T1, + dec_value_X2, + dec_value_Y2, + dec_value_T2, + unreachable_polygons2[poly2]); + } + } + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + for (unsigned int p2 = 0; p2 < unreachable_polygons2[poly2].points.size(); ++p2) + { + const Point &pro_point2 = unreachable_polygons2[poly2].points[p2]; + + introduce_SequentialFixedPointOutsidePolygon(Solver, + Context, + dec_value_X2 + pro_point2.x(), + dec_value_Y2 + pro_point2.y(), + dec_var_T1, + dec_var_X1, + dec_var_Y1, + dec_value_T2, + polygon1); + } + } + + for (unsigned int p2 = 0; p2 < polygon2.points.size(); ++p2) + { + const Point &point2 = polygon2.points[p2]; + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + introduce_SequentialFixedPointOutsidePolygon(Solver, + Context, + dec_value_X2 + point2.x(), + dec_value_Y2 + point2.y(), + dec_value_T2, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + unreachable_polygons1[poly1]); + } + } + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons1[poly1].points.size(); ++p1) + { + const Point &pro_point1 = unreachable_polygons1[poly1].points[p1]; + + introduce_SequentialPointOutsideFixedPolygon(Solver, + Context, + dec_var_X1 + pro_point1.x(), + dec_var_Y1 + pro_point1.y(), + dec_value_T2, + dec_value_X2, + dec_value_Y2, + dec_var_T1, + polygon2); + } + } + +/* + for (unsigned int p1 = 0; p1 < polygon1.points.size(); ++p1) + { + const Point &point1 = polygon1.points[p1]; + + introduce_PointOutsideFixedPolygon(Solver, + Context, + dec_var_X1 + point1.x(), + dec_var_Y1 + point1.y(), + dec_value_X2, + dec_value_Y2, + polygon2); + } + + for (unsigned int p2 = 0; p2 < polygon2.points.size(); ++p2) + { + const Point &point2 = polygon2.points[p2]; + + printf("c: %.3f, %.3f\n", dec_value_X2.as_double(), dec_value_Y2.as_double()); + printf(" %.3f, %.3f\n", (dec_value_X2 + point2.x()).as_double(), (dec_value_Y2 + point2.y()).as_double()); + + introduce_FixedPointOutsidePolygon(Solver, + Context, + dec_value_X2 + point2.x(), + dec_value_Y2 + point2.y(), + dec_var_X1, + dec_var_Y1, + polygon1); + } +*/ +} + + +void introduce_ConsequentialPolygonOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const Slic3r::Polygon &unreachable_polygon1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2, + const Slic3r::Polygon &unreachable_polygon2) +{ + std::vector _unreachable_polygons1; + _unreachable_polygons1.push_back(unreachable_polygon1); + + std::vector _unreachable_polygons2; + _unreachable_polygons2.push_back(unreachable_polygon2); + + introduce_ConsequentialPolygonOutsidePolygon(Solver, + Context, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + polygon1, + _unreachable_polygons1, + dec_var_X2, + dec_var_Y2, + dec_var_T2, + polygon2, + _unreachable_polygons2); +} + + +void introduce_ConsequentialPolygonOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const std::vector &unreachable_polygons1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2, + const std::vector &unreachable_polygons2) +{ + #ifdef DEBUG + { + printf("polygon1:\n"); + for (unsigned int p1 = 0; p1 < polygon1.points.size(); ++p1) + { + printf("[%d,%d] ", polygon1.points[p1].x(), polygon1.points[p1].y()); + } + printf("\n"); + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + printf("pro_polygon1 %d:\n", poly1); + for (unsigned int p1 = 0; p1 < unreachable_polygons1[poly1].points.size(); ++p1) + { + printf("[%d,%d] ", unreachable_polygons1[poly1].points[p1].x(), unreachable_polygons1[poly1].points[p1].y()); + } + printf("\n"); + } + printf("\n"); + + printf("polygon2:\n"); + for (unsigned int p2 = 0; p2 < polygon2.points.size(); ++p2) + { + printf("[%d,%d] ", polygon2.points[p2].x(), polygon2.points[p2].y()); + } + printf("\n"); + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + printf("pro_polygon2 %d:\n", poly2); + for (unsigned int p2 = 0; p2 < unreachable_polygons2[poly2].points.size(); ++p2) + { + printf("[%d,%d] ", unreachable_polygons2[poly2].points[p2].x(), unreachable_polygons2[poly2].points[p2].y()); + } + printf("\n"); + } + printf("\n"); + } + #endif + + + for (unsigned int p1 = 0; p1 < polygon1.points.size(); ++p1) + { + const Point &point1 = polygon1.points[p1]; + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + introduce_ConsequentialPointOutsidePolygon(Solver, + Context, + dec_var_X1 + point1.x(), + dec_var_Y1 + point1.y(), + dec_var_T1, + dec_var_X2, + dec_var_Y2, + dec_var_T2, + unreachable_polygons2[poly2]); + } + } + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + for (unsigned int p2 = 0; p2 < unreachable_polygons2[poly2].points.size(); ++p2) + { + const Point &pro_point2 = unreachable_polygons2[poly2].points[p2]; + + introduce_ConsequentialPointOutsidePolygon(Solver, + Context, + dec_var_X2 + pro_point2.x(), + dec_var_Y2 + pro_point2.y(), + dec_var_T1, + dec_var_X1, + dec_var_Y1, + dec_var_T2, + polygon1); + } + } + + for (unsigned int p2 = 0; p2 < polygon2.points.size(); ++p2) + { + const Point &point2 = polygon2.points[p2]; + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + introduce_ConsequentialPointOutsidePolygon(Solver, + Context, + dec_var_X2 + point2.x(), + dec_var_Y2 + point2.y(), + dec_var_T2, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + unreachable_polygons1[poly1]); + } + } + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons1[poly1].points.size(); ++p1) + { + const Point &pro_point1 = unreachable_polygons1[poly1].points[p1]; + + introduce_ConsequentialPointOutsidePolygon(Solver, + Context, + dec_var_X1 + pro_point1.x(), + dec_var_Y1 + pro_point1.y(), + dec_var_T2, + dec_var_X2, + dec_var_Y2, + dec_var_T1, + polygon2); + } + } +} + + +void introduce_ConsequentialPolygonExternalPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const Slic3r::Polygon &unreachable_polygon1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2, + const Slic3r::Polygon &unreachable_polygon2) +{ + std::vector _unreachable_polygons1; + _unreachable_polygons1.push_back(unreachable_polygon1); + + std::vector _unreachable_polygons2; + _unreachable_polygons2.push_back(unreachable_polygon2); + + introduce_ConsequentialPolygonExternalPolygon(Solver, + Context, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + polygon1, + _unreachable_polygons1, + dec_var_X2, + dec_var_Y2, + dec_var_T2, + polygon2, + _unreachable_polygons2); +} + + +void introduce_ConsequentialPolygonExternalPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const std::vector &unreachable_polygons1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2, + const std::vector &unreachable_polygons2) +{ + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + if (unreachable_polygons2[poly2].area() > polygon1.area()) + { + for (unsigned int p1 = 0; p1 < polygon1.points.size(); ++p1) + { + const Point &point1 = polygon1.points[p1]; + + introduce_ConsequentialPointOutsidePolygon(Solver, + Context, + dec_var_X1 + point1.x(), + dec_var_Y1 + point1.y(), + dec_var_T1, + dec_var_X2, + dec_var_Y2, + dec_var_T2, + unreachable_polygons2[poly2]); + } + } + } + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + if (unreachable_polygons2[poly2].area() < polygon1.area()) + { + for (unsigned int p2 = 0; p2 < unreachable_polygons2[poly2].points.size(); ++p2) + { + const Point &pro_point2 = unreachable_polygons2[poly2].points[p2]; + + introduce_ConsequentialPointOutsidePolygon(Solver, + Context, + dec_var_X2 + pro_point2.x(), + dec_var_Y2 + pro_point2.y(), + dec_var_T1, + dec_var_X1, + dec_var_Y1, + dec_var_T2, + polygon1); + } + } + } + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + if (unreachable_polygons1[poly1].area() > polygon2.area()) + { + for (unsigned int p2 = 0; p2 < polygon2.points.size(); ++p2) + { + const Point &point2 = polygon2.points[p2]; + + introduce_ConsequentialPointOutsidePolygon(Solver, + Context, + dec_var_X2 + point2.x(), + dec_var_Y2 + point2.y(), + dec_var_T2, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + unreachable_polygons1[poly1]); + } + } + } + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + if (unreachable_polygons1[poly1].area() < polygon2.area()) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons1[poly1].points.size(); ++p1) + { + const Point &pro_point1 = unreachable_polygons1[poly1].points[p1]; + + introduce_ConsequentialPointOutsidePolygon(Solver, + Context, + dec_var_X1 + pro_point1.x(), + dec_var_Y1 + pro_point1.y(), + dec_var_T2, + dec_var_X2, + dec_var_Y2, + dec_var_T1, + polygon2); + } + } + } +} + + +void introduce_ConsequentialPolygonOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const Slic3r::Polygon &unreachable_polygon1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon2, + const Slic3r::Polygon &unreachable_polygon2) +{ + std::vector _unreachable_polygons1; + _unreachable_polygons1.push_back(unreachable_polygon1); + + std::vector _unreachable_polygons2; + _unreachable_polygons2.push_back(unreachable_polygon2); + + introduce_ConsequentialPolygonOutsideFixedPolygon(Solver, + Context, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + polygon1, + _unreachable_polygons1, + dec_value_X2, + dec_value_Y2, + dec_value_T2, + polygon2, + _unreachable_polygons2); +} + + +void introduce_ConsequentialPolygonOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const std::vector &unreachable_polygons1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon2, + const std::vector &unreachable_polygons2) +{ + for (unsigned int p1 = 0; p1 < polygon1.points.size(); ++p1) + { + const Point &point1 = polygon1.points[p1]; + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + introduce_ConsequentialPointOutsideFixedPolygon(Solver, + Context, + dec_var_X1 + point1.x(), + dec_var_Y1 + point1.y(), + dec_var_T1, + dec_value_X2, + dec_value_Y2, + dec_value_T2, + unreachable_polygons2[poly2]); + } + } + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + for (unsigned int p2 = 0; p2 < unreachable_polygons2[poly2].points.size(); ++p2) + { + const Point &pro_point2 = unreachable_polygons2[poly2].points[p2]; + + introduce_ConsequentialFixedPointOutsidePolygon(Solver, + Context, + dec_value_X2 + pro_point2.x(), + dec_value_Y2 + pro_point2.y(), + dec_var_T1, + dec_var_X1, + dec_var_Y1, + dec_value_T2, + polygon1); + } + } + + for (unsigned int p2 = 0; p2 < polygon2.points.size(); ++p2) + { + const Point &point2 = polygon2.points[p2]; + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + introduce_ConsequentialFixedPointOutsidePolygon(Solver, + Context, + dec_value_X2 + point2.x(), + dec_value_Y2 + point2.y(), + dec_value_T2, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + unreachable_polygons1[poly1]); + } + } + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons1[poly1].points.size(); ++p1) + { + const Point &pro_point1 = unreachable_polygons1[poly1].points[p1]; + + introduce_ConsequentialPointOutsideFixedPolygon(Solver, + Context, + dec_var_X1 + pro_point1.x(), + dec_var_Y1 + pro_point1.y(), + dec_value_T2, + dec_value_X2, + dec_value_Y2, + dec_var_T1, + polygon2); + } + } +} + + + +void introduce_ConsequentialPolygonExternalFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const Slic3r::Polygon &unreachable_polygon1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon2, + const Slic3r::Polygon &unreachable_polygon2) +{ + std::vector _unreachable_polygons1; + _unreachable_polygons1.push_back(unreachable_polygon1); + + std::vector _unreachable_polygons2; + _unreachable_polygons2.push_back(unreachable_polygon2); + + introduce_ConsequentialPolygonExternalFixedPolygon(Solver, + Context, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + polygon1, + _unreachable_polygons1, + dec_value_X2, + dec_value_Y2, + dec_value_T2, + polygon2, + _unreachable_polygons2); +} + + +void introduce_ConsequentialPolygonExternalFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const std::vector &unreachable_polygons1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon2, + const std::vector &unreachable_polygons2) +{ + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + if (unreachable_polygons2[poly2].area() > polygon1.area()) + { + for (unsigned int p1 = 0; p1 < polygon1.points.size(); ++p1) + { + const Point &point1 = polygon1.points[p1]; + + introduce_ConsequentialPointOutsideFixedPolygon(Solver, + Context, + dec_var_X1 + point1.x(), + dec_var_Y1 + point1.y(), + dec_var_T1, + dec_value_X2, + dec_value_Y2, + dec_value_T2, + unreachable_polygons2[poly2]); + } + } + } + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons2.size(); ++poly2) + { + if (unreachable_polygons2[poly2].area() < polygon1.area()) + { + for (unsigned int p2 = 0; p2 < unreachable_polygons2[poly2].points.size(); ++p2) + { + const Point &pro_point2 = unreachable_polygons2[poly2].points[p2]; + + introduce_ConsequentialFixedPointOutsidePolygon(Solver, + Context, + dec_value_X2 + pro_point2.x(), + dec_value_Y2 + pro_point2.y(), + dec_var_T1, + dec_var_X1, + dec_var_Y1, + dec_value_T2, + polygon1); + } + } + } + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + if (unreachable_polygons1[poly1].area() > polygon2.area()) + { + for (unsigned int p2 = 0; p2 < polygon2.points.size(); ++p2) + { + const Point &point2 = polygon2.points[p2]; + + introduce_ConsequentialFixedPointOutsidePolygon(Solver, + Context, + dec_value_X2 + point2.x(), + dec_value_Y2 + point2.y(), + dec_value_T2, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + unreachable_polygons1[poly1]); + } + } + } + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons1.size(); ++poly1) + { + if (unreachable_polygons1[poly1].area() < polygon2.area()) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons1[poly1].points.size(); ++p1) + { + const Point &pro_point1 = unreachable_polygons1[poly1].points[p1]; + + introduce_ConsequentialPointOutsideFixedPolygon(Solver, + Context, + dec_var_X1 + pro_point1.x(), + dec_var_Y1 + pro_point1.y(), + dec_value_T2, + dec_value_X2, + dec_value_Y2, + dec_var_T1, + polygon2); + } + } + } +} + + +void introduce_ConsequentialPolygonExternalFixedGroupPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon, + const std::vector &unreachable_polygons, + const Rational &dec_value_group_min_T, + const Rational &dec_value_group_max_T, + const Slic3r::Polygon &group_polygon, + const std::vector &group_unreachable_polygons) +{ + for (unsigned int poly2 = 0; poly2 < group_unreachable_polygons.size(); ++poly2) + { + for (unsigned int p1 = 0; p1 < polygon.points.size(); ++p1) + { + const Point &point1 = polygon.points[p1]; + + introduce_ConsequentialPointOutsideFixedPolygon(Solver, + Context, + dec_var_X1 + point1.x(), + dec_var_Y1 + point1.y(), + dec_var_T1, + Rational(0), + Rational(0), + dec_value_group_min_T, + group_unreachable_polygons[poly2]); + } + } + + for (unsigned int poly2 = 0; poly2 < group_unreachable_polygons.size(); ++poly2) + { + for (unsigned int p2 = 0; p2 < group_unreachable_polygons[poly2].points.size(); ++p2) + { + const Point &pro_point2 = group_unreachable_polygons[poly2].points[p2]; + + introduce_ConsequentialFixedPointOutsidePolygon(Solver, + Context, + pro_point2.x(), + pro_point2.y(), + dec_var_T1, + dec_var_X1, + dec_var_Y1, + dec_value_group_min_T, + polygon); + } + } + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons.size(); ++poly1) + { + for (unsigned int p2 = 0; p2 < group_polygon.points.size(); ++p2) + { + const Point &point2 = group_polygon.points[p2]; + + introduce_ConsequentialFixedPointOutsidePolygon(Solver, + Context, + point2.x(), + point2.y(), + dec_value_group_max_T, + dec_var_X1, + dec_var_Y1, + dec_var_T1, + unreachable_polygons[poly1]); + } + } + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons.size(); ++poly1) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons[poly1].points.size(); ++p1) + { + const Point &pro_point1 = unreachable_polygons[poly1].points[p1]; + + introduce_ConsequentialPointOutsideFixedPolygon(Solver, + Context, + dec_var_X1 + pro_point1.x(), + dec_var_Y1 + pro_point1.y(), + dec_value_group_max_T, + Rational(0), + Rational(0), + dec_var_T1, + group_polygon); + } + } +} + + +/*----------------------------------------------------------------*/ + +void introduce_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &polygons) +{ + if (!polygons.empty()) + { + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + introduce_PolygonOutsidePolygon(Solver, + Context, + dec_vars_X[i], + dec_vars_Y[i], + polygons[i], + dec_vars_X[j], + dec_vars_Y[j], + polygons[j]); + } + } + } +} + + +void introduce_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &polygons, + const std::vector &unreachable_polygons) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + introduce_SequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + polygons, + _unreachable_polygons); +} + + +void introduce_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + if (!polygons.empty()) + { + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + introduce_SequentialPolygonOutsidePolygon(Solver, + Context, + dec_vars_X[i], + dec_vars_Y[i], + dec_vars_T[i], + polygons[i], + unreachable_polygons[i], + dec_vars_X[j], + dec_vars_Y[j], + dec_vars_T[j], + polygons[j], + unreachable_polygons[j]); + } + } + } +} + + +void introduce_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &polygons, + const std::vector &unreachable_polygons) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + introduce_ConsequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + polygons, + _unreachable_polygons); +} + + +void introduce_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + if (!polygons.empty()) + { + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + introduce_ConsequentialPolygonOutsidePolygon(Solver, + Context, + dec_vars_X[i], + dec_vars_Y[i], + dec_vars_T[i], + polygons[i], + unreachable_polygons[i], + dec_vars_X[j], + dec_vars_Y[j], + dec_vars_T[j], + polygons[j], + unreachable_polygons[j]); + } + } + } +} + + +void introduce_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons) +{ + if (!undecided.empty()) + { + for (unsigned int i = 0; i < undecided.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < undecided.size(); ++j) + { + introduce_PolygonOutsidePolygon(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + polygons[undecided[i]], + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + polygons[undecided[j]]); + } + } + } + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + for (unsigned int j = 0; j < fixed.size(); ++j) + { + introduce_PolygonOutsideFixedPolygon(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + polygons[undecided[i]], + dec_values_X[fixed[j]], + dec_values_Y[fixed[j]], + polygons[fixed[j]]); + } + } +} + + +void introduce_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector &unreachable_polygons) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + introduce_SequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + dec_values_X, + dec_values_Y, + dec_values_T, + fixed, + undecided, + polygons, + _unreachable_polygons); +} + + +void introduce_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + if (!undecided.empty()) + { + for (unsigned int i = 0; i < undecided.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < undecided.size(); ++j) + { + #ifdef DEBUG + { + printf("PoP: %d,%d\n", undecided[i], undecided[j]); + } + #endif + introduce_SequentialPolygonOutsidePolygon(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + polygons[undecided[i]], + unreachable_polygons[undecided[i]], + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + dec_vars_T[undecided[j]], + polygons[undecided[j]], + unreachable_polygons[undecided[j]]); + } + } + } + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + for (unsigned int j = 0; j < fixed.size(); ++j) + { + #ifdef DEBUG + { + printf("PoFP: %d,%d\n", undecided[i], fixed[j]); + } + #endif + introduce_SequentialPolygonOutsideFixedPolygon(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + polygons[undecided[i]], + unreachable_polygons[undecided[i]], + dec_values_X[fixed[j]], + dec_values_Y[fixed[j]], + dec_values_T[fixed[j]], + polygons[fixed[j]], + unreachable_polygons[fixed[j]]); + } + } +} + + +void introduce_ConsequentialPolygonWeakNonoverlapping(const SolverConfiguration &solver_configuration, + z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector &unreachable_polygons) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + introduce_ConsequentialPolygonWeakNonoverlapping(solver_configuration, + Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + dec_values_X, + dec_values_Y, + dec_values_T, + fixed, + undecided, + polygons, + _unreachable_polygons); +} + + +void introduce_ConsequentialPolygonWeakNonoverlapping(const SolverConfiguration &solver_configuration, + z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + if (!undecided.empty()) + { + for (unsigned int i = 0; i < undecided.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < undecided.size(); ++j) + { + #ifdef DEBUG + { + printf("PoP: %d,%d\n", undecided[i], undecided[j]); + } + #endif + introduce_ConsequentialPolygonExternalPolygon(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + polygons[undecided[i]], + unreachable_polygons[undecided[i]], + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + dec_vars_T[undecided[j]], + polygons[undecided[j]], + unreachable_polygons[undecided[j]]); + } + } + } + + if (fixed.size() < (unsigned int)solver_configuration.fixed_object_grouping_limit) + { + for (unsigned int i = 0; i < undecided.size(); ++i) + { + for (unsigned int j = 0; j < fixed.size(); ++j) + { + #ifdef DEBUG + { + printf("PoFP: %d,%d\n", undecided[i], fixed[j]); + } + #endif + introduce_ConsequentialPolygonExternalFixedPolygon(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + polygons[undecided[i]], + unreachable_polygons[undecided[i]], + dec_values_X[fixed[j]], + dec_values_Y[fixed[j]], + dec_values_T[fixed[j]], + polygons[fixed[j]], + unreachable_polygons[fixed[j]]); + } + } + } + else + { + for (unsigned int i = 0; i < undecided.size(); ++i) + { + for (unsigned int j = fixed.size() - (unsigned int)solver_configuration.fixed_object_grouping_limit; j < fixed.size(); ++j) + { + #ifdef DEBUG + { + printf("PoFP: %d,%d\n", undecided[i], fixed[j]); + } + #endif + introduce_ConsequentialPolygonExternalFixedPolygon(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + polygons[undecided[i]], + unreachable_polygons[undecided[i]], + dec_values_X[fixed[j]], + dec_values_Y[fixed[j]], + dec_values_T[fixed[j]], + polygons[fixed[j]], + unreachable_polygons[fixed[j]]); + } + } + + Slic3r::Polygons flat_polygons; + for (unsigned int i = 0; i < fixed.size() - (unsigned int)solver_configuration.fixed_object_grouping_limit; ++i) + { + Polygon fixed_polygon = polygons[fixed[i]]; + + for (unsigned int p = 0; p < fixed_polygon.points.size(); ++p) + { + fixed_polygon.points[p] += Point(dec_values_X[fixed[i]].as_double(), dec_values_Y[fixed[i]].as_double()); + } + flat_polygons.push_back(fixed_polygon); + } + + Slic3r::Polygons flat_unreachable_polygons; + for (unsigned int i = 0; i < fixed.size() - (unsigned int)solver_configuration.fixed_object_grouping_limit; ++i) + { + for (unsigned int j = 0; j < unreachable_polygons[fixed[i]].size(); ++j) + { + Polygon fixed_polygon = unreachable_polygons[fixed[i]][j]; + + for (unsigned int p = 0; p < fixed_polygon.points.size(); ++p) + { + fixed_polygon.points[p] += Point(dec_values_X[fixed[i]].as_double(), dec_values_Y[fixed[i]].as_double()); + } + flat_unreachable_polygons.push_back(fixed_polygon); + } + } + Polygon flat_hull = Slic3r::Geometry::convex_hull(flat_polygons); + Polygon flat_unreachable_hull = Slic3r::Geometry::convex_hull(flat_unreachable_polygons); + std::vector flat_unreachable_hulls; + flat_unreachable_hulls.push_back(flat_unreachable_hull); + + assert(!fixed.empty()); + Rational dec_value_flat_min_T = dec_values_T[fixed[0]]; + Rational dec_value_flat_max_T = dec_values_T[fixed[0]]; + + for (unsigned int i = 1; i < fixed.size() - (unsigned int)solver_configuration.fixed_object_grouping_limit; ++i) + { + if (dec_values_T[fixed[i]] < dec_value_flat_min_T) + { + dec_value_flat_min_T = dec_values_T[fixed[i]]; + } + if (dec_values_T[fixed[i]] > dec_value_flat_max_T) + { + dec_value_flat_max_T = dec_values_T[fixed[i]]; + } + } + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + #ifdef DEBUG + { + printf("PoGROUP: %d\n", undecided[i]); + } + #endif + + introduce_ConsequentialPolygonExternalFixedGroupPolygon(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + polygons[undecided[i]], + unreachable_polygons[undecided[i]], + dec_value_flat_min_T, + dec_value_flat_max_T, + flat_hull, + flat_unreachable_hulls); + } + } +} + + +void introduce_PolygonStrongNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &polygons) +{ + introduce_PolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + polygons); + + if (!polygons.empty()) + { + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + for (unsigned int p1 = 0; p1 < polygons[i].points.size(); ++p1) + { + const Point &point1 = polygons[i].points[p1]; + const Point &next_point1 = polygons[i].points[(p1 + 1) % polygons[i].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[j].points.size(); ++p2) + { + const Point &point2 = polygons[j].points[p2]; + const Point &next_point2 = polygons[j].points[(p2 + 1) % polygons[j].points.size()]; + + introduce_LineNonIntersection(Solver, + Context, + dec_vars_X[i], + dec_vars_Y[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_vars_X[j], + dec_vars_Y[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + } + } + } + } + } +} + + +bool lines_intersect_(coord_t ax, coord_t ay, coord_t ux, coord_t uy, coord_t bx, coord_t by, coord_t vx, coord_t vy) +{ + coord_t den = ux * vy - uy * vx; + coord_t num = vx * ay - vx * by - vy * ax + vy * bx; + + if (fabs(den) < EPSILON) + { + return false; + } + else + { + double t = (double)num / den; + + if (t < 0.0 || t > 1.0) + { + return false; + } + else + { + if (abs(vx) > 0) + { + double tt = (ax - bx + t * ux) / vx; + + if (tt < 0.0 || tt > 1.0) + { + return false; + } + else + { + #ifdef DEBUG + { + printf("t:%.6f\n", t); + printf("tt:%.6f\n", tt); + } + #endif + return true; + } + } + else + { + if (abs(vy) > 0) + { + double tt = (ay - by + t * uy) / vy; + + if (tt < 0.0 || tt > 1.0) + { + return false; + } + else + { + #ifdef DEBUG + { + printf("t:%.6f\n", t); + printf("tt2:%.6f\n", tt); + } + #endif + return true; + } + } + else + { + return false; + } + } + } + } + + return false; +} + + +bool lines_intersect(double ax, double ay, double ux, double uy, double bx, double by, double vx, double vy) +{ + double den = ux * vy - uy * vx; + double num = vx * ay - vx * by - vy * ax + vy * bx; + + if (fabs(den) < EPSILON) + { + return false; + } + else + { + double t = num / den; + + if (t < 0.0 || t > 1.0) + { + return false; + } + else + { + if (fabs(vx) > EPSILON) + { + double tt = (ax - bx + t * ux) / vx; + + if (tt < 0.0 || tt > 1.0) + { + return false; + } + else + { + #ifdef DEBUG + { + printf("t:%.6f\n", t); + printf("tt:%.6f\n", tt); + } + #endif + return true; + } + } + else + { + if (fabs(vy) > EPSILON) + { + double tt = (ay - by + t * uy) / vy; + + if (tt < 0.0 || tt > 1.0) + { + return false; + } + else + { + #ifdef DEBUG + { + printf("t:%.6f\n", t); + printf("tt2:%.6f\n", tt); + } + #endif + return true; + } + } + else + { + return false; + } + } + } + } + + return false; +} + + +bool lines_intersect_closed(double ax, double ay, double ux, double uy, double bx, double by, double vx, double vy) +{ + return lines_intersect(ax, ay, ux, uy, bx, by, vx, vy); +} + + +bool lines_intersect_open(double ax, double ay, double ux, double uy, double bx, double by, double vx, double vy) +{ + double den = ux * vy - uy * vx; + double num = vx * ay - vx * by - vy * ax + vy * bx; + + if (fabs(den) < EPSILON) + { + return false; + } + else + { + double t = num / den; + + if (t < EPSILON || t > 1.0 - EPSILON) + { + return false; + } + else + { + if (fabs(vx) > EPSILON) + { + double tt = (ax - bx + t * ux) / vx; + + if (tt < EPSILON || tt > 1.0 - EPSILON) + { + return false; + } + else + { + #ifdef DEBUG + { + printf("t:%.6f\n", t); + printf("tt:%.6f\n", tt); + } + #endif + return true; + } + } + else + { + if (fabs(vy) > EPSILON) + { + double tt = (ay - by + t * uy) / vy; + + if (tt < EPSILON || tt > 1.0 - EPSILON) + { + return false; + } + else + { + #ifdef DEBUG + { + printf("t:%.6f\n", t); + printf("tt2:%.6f\n", tt); + } + #endif + return true; + } + } + else + { + return false; + } + } + } + } + + return false; +} + + +bool refine_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &polygons) +{ + bool refined = false; + + assert(!polygons.empty()); + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + for (unsigned int p1 = 0; p1 < polygons[i].points.size(); ++p1) + { + const Point &point1 = polygons[i].points[p1]; + const Point &next_point1 = polygons[i].points[(p1 + 1) % polygons[i].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[j].points.size(); ++p2) + { + const Point &point2 = polygons[j].points[p2]; + const Point &next_point2 = polygons[j].points[(p2 + 1) % polygons[j].points.size()]; + + Vec2d intersection(0,0); + #ifdef DEBUG + { + /* + printf("testing: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + dec_values_X[i] + next_point1.x(), dec_values_Y[i] + next_point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + dec_values_X[j] + next_point2.x(), dec_values_Y[j] + next_point2.y()); + */ + } + #endif + + /* Seems not working, report an intersection even if there is none, using out own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + if (lines_intersect(dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + /* + printf("intersect: %d (%.3f,%.3f) - [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", hidden_var_cnt, intersection.x(), intersection.y(), + + dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + dec_values_X[i] + next_point1.x(), dec_values_Y[i] + next_point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + dec_values_X[j] + next_point2.x(), dec_values_Y[j] + next_point2.y()); + */ + } + #endif + + introduce_LineNonIntersection(Solver, + Context, + dec_vars_X[i], + dec_vars_Y[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_vars_X[j], + dec_vars_Y[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + return refined; +} + + +bool refine_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_values_X, + const z3::expr_vector &dec_values_Y, + const std::vector &polygons) +{ + bool refined = false; + + assert(!polygons.empty()); + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + for (unsigned int p1 = 0; p1 < polygons[i].points.size(); ++p1) + { + const Point &point1 = polygons[i].points[p1]; + const Point &next_point1 = polygons[i].points[(p1 + 1) % polygons[i].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[j].points.size(); ++p2) + { + const Point &point2 = polygons[j].points[p2]; + const Point &next_point2 = polygons[j].points[(p2 + 1) % polygons[j].points.size()]; + + Vec2d intersection(0, 0); + #ifdef DEBUG + { + printf("testing: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + /* Seems not working, report an intersection even if there is none, using out own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + if (lines_intersect(dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("intersect: %d (%.3f,%.3f) - [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", hidden_var_cnt, intersection.x(), intersection.y(), + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + introduce_LineNonIntersection(Solver, + Context, + dec_vars_X[i], + dec_vars_Y[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_vars_X[j], + dec_vars_Y[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + return refined; +} + + +bool refine_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &polygons) +{ + bool refined = false; + + assert(!polygons.empty()); + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + for (unsigned int p1 = 0; p1 < polygons[i].points.size(); ++p1) + { + const Point &point1 = polygons[i].points[p1]; + const Point &next_point1 = polygons[i].points[(p1 + 1) % polygons[i].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[j].points.size(); ++p2) + { + const Point &point2 = polygons[j].points[p2]; + const Point &next_point2 = polygons[j].points[(p2 + 1) % polygons[j].points.size()]; + + Vec2d intersection(0, 0); + #ifdef DEBUG + { + printf("testing mi: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + /* Seems not working, report an intersection even if there is none, using out own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + if (lines_intersect(dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("intersect: %d (%.3f,%.3f) - [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", hidden_var_cnt, intersection.x(), intersection.y(), + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + introduce_LineNonIntersection(Solver, + Context, + dec_vars_X[i], + dec_vars_Y[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_vars_X[j], + dec_vars_Y[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + return refined; +} + + +bool refine_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons) +{ + bool refined = false; + + assert(!polygons.empty()); + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + if (dec_values_T[i] > dec_values_T[j]) + { + for (unsigned int p1 = 0; p1 < polygons[i].points.size(); ++p1) + { + const Point &point1 = polygons[i].points[p1]; + const Point &next_point1 = polygons[i].points[(p1 + 1) % polygons[i].points.size()]; + + for (unsigned int p2 = 0; p2 < unreachable_polygons[j].points.size(); ++p2) + { + const Point &point2 = unreachable_polygons[j].points[p2]; + const Point &next_point2 = unreachable_polygons[j].points[(p2 + 1) % unreachable_polygons[j].points.size()]; + + #ifdef DEBUG + { + printf("testing ni %d %d (%d,%d): [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", i, j, p1, p2, + dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + dec_values_X[i] + next_point1.x(), dec_values_Y[i] + next_point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + dec_values_X[j] + next_point2.x(), dec_values_Y[j] + next_point2.y()); + } + #endif + + if (lines_intersect(dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + /* + printf("intersect: %d (%.3f,%.3f) - [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", hidden_var_cnt, intersection.x(), intersection.y(), + + dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + dec_values_X[i] + next_point1.x(), dec_values_Y[i] + next_point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + dec_values_X[j] + next_point2.x(), dec_values_Y[j] + next_point2.y()); + */ + } + #endif + + introduce_SequentialLineNonIntersection(Solver, + Context, + dec_vars_X[i], + dec_vars_Y[i], + dec_vars_T[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_vars_X[j], + dec_vars_Y[j], + dec_vars_T[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + else + { + if (dec_values_T[i] < dec_values_T[j]) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons[i].points.size(); ++p1) + { + const Point &point1 = unreachable_polygons[i].points[p1]; + const Point &next_point1 = unreachable_polygons[i].points[(p1 + 1) % unreachable_polygons[i].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[j].points.size(); ++p2) + { + const Point &point2 = polygons[j].points[p2]; + const Point &next_point2 = polygons[j].points[(p2 + 1) % polygons[j].points.size()]; + + #ifdef DEBUG + { + /* + printf("testing: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + dec_values_X[i] + next_point1.x(), dec_values_Y[i] + next_point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + dec_values_X[j] + next_point2.x(), dec_values_Y[j] + next_point2.y()); + */ + } + #endif + + if (lines_intersect(dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + /* + printf("intersect: %d (%.3f,%.3f) - [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", hidden_var_cnt, intersection.x(), intersection.y(), + + dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + dec_values_X[i] + next_point1.x(), dec_values_Y[i] + next_point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + dec_values_X[j] + next_point2.x(), dec_values_Y[j] + next_point2.y()); + */ + } + #endif + + introduce_SequentialLineNonIntersection(Solver, + Context, + dec_vars_X[j], + dec_vars_Y[j], + dec_vars_T[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point2, next_point2), + dec_vars_X[i], + dec_vars_Y[i], + dec_vars_T[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point1, next_point1)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + else + { + #ifdef DEBUG + { + printf("Time collision: %.3f, %.3f\n", dec_values_T[i], dec_values_T[j]); + } + #endif + assert(false); + } + } + } + } + return refined; +} + + +bool refine_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + return refine_SequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + dec_values_X, + dec_values_Y, + dec_values_T, + polygons, + _unreachable_polygons); +} + + +bool refine_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + bool refined = false; + + assert(!polygons.empty()); + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + if (dec_values_T[i] > dec_values_T[j]) + { + for (unsigned int p1 = 0; p1 < polygons[i].points.size(); ++p1) + { + const Point &point1 = polygons[i].points[p1]; + const Point &next_point1 = polygons[i].points[(p1 + 1) % polygons[i].points.size()]; + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons[j].size(); ++poly2) + { + #ifdef DEBUG + { + printf("temporal: %.3f %.3f [ij: %d,%d]\n", dec_values_T[i].as_double(), dec_values_T[j].as_double(), i, j); + printf("proto X1: %ld, %ld, %ld\n", unreachable_polygons.size(), unreachable_polygons[j].size(), unreachable_polygons[j][poly2].points.size()); + } + #endif + + for (unsigned int p2 = 0; p2 < unreachable_polygons[j][poly2].points.size(); ++p2) + { + const Point &point2 = unreachable_polygons[j][poly2].points[p2]; + const Point &next_point2 = unreachable_polygons[j][poly2].points[(p2 + 1) % unreachable_polygons[j][poly2].points.size()]; + + #ifdef DEBUG + { + printf("testing alpha %d %d (%d,%d): [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", i, j, p1, p2, + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + if (lines_intersect(dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("temps: [ij: %d,%d] [%.3f, %.3f]\n", i, j, + dec_values_T[i].as_double(), + dec_values_T[j].as_double()); + + printf("dec_values: [%.3f, %.3f] [%.3f,%.3f]\n", + dec_values_X[i].as_double(), + dec_values_Y[i].as_double(), + dec_values_X[j].as_double(), + dec_values_Y[j].as_double()); + + printf("intersect 1: %d [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + hidden_var_cnt, + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + introduce_SequentialLineNonIntersection(Solver, + Context, + dec_vars_X[i], + dec_vars_Y[i], + dec_vars_T[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_vars_X[j], + dec_vars_Y[j], + dec_vars_T[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + else + { + if (dec_values_T[i] < dec_values_T[j]) + { + for (unsigned int poly1 = 0; poly1 < unreachable_polygons[i].size(); ++poly1) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons[i][poly1].points.size(); ++p1) + { + #ifdef DEBUG + { + printf("proto2: %ld, %ld, %ld\n", unreachable_polygons.size(), unreachable_polygons[i].size(), unreachable_polygons[i][poly1].points.size()); + //getchar(); + } + #endif + + const Point &point1 = unreachable_polygons[i][poly1].points[p1]; + const Point &next_point1 = unreachable_polygons[i][poly1].points[(p1 + 1) % unreachable_polygons[i][poly1].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[j].points.size(); ++p2) + { + const Point &point2 = polygons[j].points[p2]; + const Point &next_point2 = polygons[j].points[(p2 + 1) % polygons[j].points.size()]; + + #ifdef DEBUG + { + printf("testing beta: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + if (lines_intersect(dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("temps: [ij: %d,%d] [%.3f, %.3f]\n", i, j, + dec_values_T[i].as_double(), + dec_values_T[j].as_double()); + + printf("dec_values: [%.3f, %.3f] [%.3f,%.3f]\n", + dec_values_X[i].as_double(), + dec_values_Y[i].as_double(), + dec_values_X[j].as_double(), + dec_values_Y[j].as_double()); + + printf("intersect 2: %d [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + hidden_var_cnt, + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + introduce_SequentialLineNonIntersection(Solver, + Context, + dec_vars_X[j], + dec_vars_Y[j], + dec_vars_T[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point2, next_point2), + dec_vars_X[i], + dec_vars_Y[i], + dec_vars_T[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point1, next_point1)); + hidden_var_cnt += 2; + + /* + introduce_SequentialLineNonIntersection(Solver, + Context, + dec_vars_X[i], + dec_vars_Y[i], + dec_vars_T[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point1, next_point1), + dec_vars_X[j], + dec_vars_Y[j], + dec_vars_T[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point2, next_point2)); + + */ + refined = true; + } + } + } + } + } + else + { + #ifdef DEBUG + { + printf("Time collision: %.3f, %.3f\n", dec_values_T[i].as_double(), dec_values_T[j].as_double()); + } + #endif + assert(false); + } + } + } + } + return refined; +} + + +bool refine_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons) +{ + bool refined = false; + + assert(!polygons.empty()); + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + if (dec_values_T[i] > dec_values_T[j]) + { + for (unsigned int p1 = 0; p1 < polygons[i].points.size(); ++p1) + { + const Point &point1 = polygons[i].points[p1]; + const Point &next_point1 = polygons[i].points[(p1 + 1) % polygons[i].points.size()]; + + for (unsigned int p2 = 0; p2 < unreachable_polygons[j].points.size(); ++p2) + { + const Point &point2 = unreachable_polygons[j].points[p2]; + const Point &next_point2 = unreachable_polygons[j].points[(p2 + 1) % unreachable_polygons[j].points.size()]; + + #ifdef DEBUG + { + printf("testing ni %d %d (%d,%d): [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", i, j, p1, p2, + dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + dec_values_X[i] + next_point1.x(), dec_values_Y[i] + next_point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + dec_values_X[j] + next_point2.x(), dec_values_Y[j] + next_point2.y()); + } + #endif + + if (lines_intersect(dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + /* + printf("intersect: %d (%.3f,%.3f) - [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", hidden_var_cnt, intersection.x(), intersection.y(), + + dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + dec_values_X[i] + next_point1.x(), dec_values_Y[i] + next_point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + dec_values_X[j] + next_point2.x(), dec_values_Y[j] + next_point2.y()); + */ + } + #endif + + introduce_ConsequentialLineNonIntersection(Solver, + Context, + dec_vars_X[i], + dec_vars_Y[i], + dec_vars_T[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_vars_X[j], + dec_vars_Y[j], + dec_vars_T[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + else + { + if (dec_values_T[i] < dec_values_T[j]) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons[i].points.size(); ++p1) + { + const Point &point1 = unreachable_polygons[i].points[p1]; + const Point &next_point1 = unreachable_polygons[i].points[(p1 + 1) % unreachable_polygons[i].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[j].points.size(); ++p2) + { + const Point &point2 = polygons[j].points[p2]; + const Point &next_point2 = polygons[j].points[(p2 + 1) % polygons[j].points.size()]; + + #ifdef DEBUG + { + printf("testing: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + dec_values_X[i] + next_point1.x(), dec_values_Y[i] + next_point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + dec_values_X[j] + next_point2.x(), dec_values_Y[j] + next_point2.y()); + } + #endif + + if (lines_intersect(dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + /* + printf("intersect: %d (%.3f,%.3f) - [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", hidden_var_cnt, intersection.x(), intersection.y(), + dec_values_X[i] + point1.x(), dec_values_Y[i] + point1.y(), + dec_values_X[i] + next_point1.x(), dec_values_Y[i] + next_point1.y(), + dec_values_X[j] + point2.x(), dec_values_Y[j] + point2.y(), + dec_values_X[j] + next_point2.x(), dec_values_Y[j] + next_point2.y()); + */ + } + #endif + + introduce_ConsequentialLineNonIntersection(Solver, + Context, + dec_vars_X[j], + dec_vars_Y[j], + dec_vars_T[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point2, next_point2), + dec_vars_X[i], + dec_vars_Y[i], + dec_vars_T[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point1, next_point1)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + else + { + #ifdef DEBUG + { + printf("Time collision: %.3f, %.3f\n", dec_values_T[i], dec_values_T[j]); + } + #endif + assert(false); + } + } + } + } + return refined; +} + + +bool refine_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + return refine_ConsequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + dec_values_X, + dec_values_Y, + dec_values_T, + polygons, + _unreachable_polygons); +} + + +bool refine_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + bool refined = false; + + assert(!polygons.empty()); + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + if (dec_values_T[i] > dec_values_T[j]) + { + for (unsigned int p1 = 0; p1 < polygons[i].points.size(); ++p1) + { + const Point &point1 = polygons[i].points[p1]; + const Point &next_point1 = polygons[i].points[(p1 + 1) % polygons[i].points.size()]; + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons[j].size(); ++poly2) + { + #ifdef DEBUG + { + printf("temporal: %.3f %.3f [ij: %d,%d]\n", dec_values_T[i].as_double(), dec_values_T[j].as_double(), i, j); + printf("proto X1: %ld, %ld, %ld\n", unreachable_polygons.size(), unreachable_polygons[j].size(), unreachable_polygons[j][poly2].points.size()); + //getchar(); + } + #endif + + for (unsigned int p2 = 0; p2 < unreachable_polygons[j][poly2].points.size(); ++p2) + { + const Point &point2 = unreachable_polygons[j][poly2].points[p2]; + const Point &next_point2 = unreachable_polygons[j][poly2].points[(p2 + 1) % unreachable_polygons[j][poly2].points.size()]; + + #ifdef DEBUG + { + printf("testing alpha %d %d (%d,%d): [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", i, j, p1, p2, + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + if (lines_intersect(dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("temps: [ij: %d,%d] [%.3f, %.3f]\n", i, j, + dec_values_T[i].as_double(), + dec_values_T[j].as_double()); + + printf("dec_values: [%.3f, %.3f] [%.3f,%.3f]\n", + dec_values_X[i].as_double(), + dec_values_Y[i].as_double(), + dec_values_X[j].as_double(), + dec_values_Y[j].as_double()); + + printf("intersect 1: %d [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + hidden_var_cnt, + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + introduce_ConsequentialLineNonIntersection(Solver, + Context, + dec_vars_X[i], + dec_vars_Y[i], + dec_vars_T[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_vars_X[j], + dec_vars_Y[j], + dec_vars_T[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + else + { + if (dec_values_T[i] < dec_values_T[j]) + { + for (unsigned int poly1 = 0; poly1 < unreachable_polygons[i].size(); ++poly1) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons[i][poly1].points.size(); ++p1) + { + #ifdef DEBUG + { + printf("proto2: %ld, %ld, %ld\n", unreachable_polygons.size(), unreachable_polygons[i].size(), unreachable_polygons[i][poly1].points.size()); + //getchar(); + } + #endif + + const Point &point1 = unreachable_polygons[i][poly1].points[p1]; + const Point &next_point1 = unreachable_polygons[i][poly1].points[(p1 + 1) % unreachable_polygons[i][poly1].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[j].points.size(); ++p2) + { + const Point &point2 = polygons[j].points[p2]; + const Point &next_point2 = polygons[j].points[(p2 + 1) % polygons[j].points.size()]; + + #ifdef DEBUG + { + printf("testing beta: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + if (lines_intersect(dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("temps: [ij: %d,%d] [%.3f, %.3f]\n", i, j, + dec_values_T[i].as_double(), + dec_values_T[j].as_double()); + + printf("dec_values: [%.3f, %.3f] [%.3f,%.3f]\n", + dec_values_X[i].as_double(), + dec_values_Y[i].as_double(), + dec_values_X[j].as_double(), + dec_values_Y[j].as_double()); + + printf("intersect 2: %d [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + hidden_var_cnt, + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + introduce_ConsequentialLineNonIntersection(Solver, + Context, + dec_vars_X[j], + dec_vars_Y[j], + dec_vars_T[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point2, next_point2), + dec_vars_X[i], + dec_vars_Y[i], + dec_vars_T[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point1, next_point1)); + hidden_var_cnt += 2; + + /* + introduce_SequentialLineNonIntersection(Solver, + Context, + dec_vars_X[i], + dec_vars_Y[i], + dec_vars_T[i], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point1, next_point1), + dec_vars_X[j], + dec_vars_Y[j], + dec_vars_T[j], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point2, next_point2)); + + */ + refined = true; + } + } + } + } + } + else + { + #ifdef DEBUG + { + printf("Time collision: %.3f, %.3f\n", dec_values_T[i].as_double(), dec_values_T[j].as_double()); + } + #endif + assert(false); + } + } + } + } + return refined; +} + + +/*----------------------------------------------------------------*/ + +void introduce_PolygonWeakNonoverlappingAgainstFixed(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_values_X, + const z3::expr_vector &dec_values_Y, + const std::vector &decided, + const std::vector &undecided, + const std::vector &polygons) +{ + if (!undecided.empty()) + { + for (unsigned int i = 0; i < undecided.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < undecided.size(); ++j) + { + introduce_PolygonOutsidePolygon(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + polygons[undecided[i]], + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + polygons[undecided[j]]); + } + } + } + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + for (unsigned int j = 0; j < decided.size(); ++j) + { + introduce_PolygonOutsidePolygon(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + polygons[undecided[i]], + dec_values_X[decided[j]], + dec_values_Y[decided[j]], + polygons[decided[j]]); + } + } +} + + +bool refine_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_values_X, + const z3::expr_vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons) +{ + bool refined = false; + + assert(!undecided.empty()); + for (unsigned int i = 0; i < undecided.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < undecided.size(); ++j) + { + for (unsigned int p1 = 0; p1 < polygons[undecided[i]].points.size(); ++p1) + { + const Point &point1 = polygons[undecided[i]].points[p1]; + const Point &next_point1 = polygons[undecided[i]].points[(p1 + 1) % polygons[undecided[i]].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[undecided[j]].points.size(); ++p2) + { + const Point &point2 = polygons[undecided[j]].points[p2]; + const Point &next_point2 = polygons[undecided[j]].points[(p2 + 1) % polygons[undecided[j]].points.size()]; + + Vec2d intersection (0, 0); + #ifdef DEBUG + { + /* + printf("testing: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[undecided[i]].as_double() + point1.x(), dec_values_Y[undecided[i]].as_double() + point1.y(), + dec_values_X[undecided[i]].as_double() + next_point1.x(), dec_values_Y[undecided[i]].as_double() + next_point1.y(), + dec_values_X[undecided[j]].as_double() + point2.x(), dec_values_Y[undecided[j]].as_double() + point2.y(), + dec_values_X[undecided[j]].as_double() + next_point2.x(), dec_values_Y[undecided[j]].as_double() + next_point2.y()); + */ + } + #endif + + /* Seems not working, report an intersection even if there is none, using our own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[undecided[i]] + point1.x(), dec_values_Y[undecided[i]] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[undecided[j]] + point2.x(), dec_values_Y[undecided[j]] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + if (lines_intersect(dec_values_X[undecided[i]].as_double() + point1.x(), dec_values_Y[undecided[i]].as_double() + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[undecided[j]].as_double() + point2.x(), dec_values_Y[undecided[j]].as_double() + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + /* + printf("intersect: %d (%.3f,%.3f) - [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", hidden_var_cnt, intersection.x(), intersection.y(), + dec_values_X[undecided[i]].as_double() + point1.x(), dec_values_Y[undecided[i]].as_double() + point1.y(), + dec_values_X[undecided[i]].as_double() + next_point1.x(), dec_values_Y[undecided[i]].as_double() + next_point1.y(), + dec_values_X[undecided[j]].as_double() + point2.x(), dec_values_Y[undecided[j]].as_double() + point2.y(), + dec_values_X[undecided[j]].as_double() + next_point2.x(), dec_values_Y[undecided[j]].as_double() + next_point2.y()); + */ + } + #endif + + introduce_LineNonIntersection(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + for (unsigned int j = 0; j < fixed.size(); ++j) + { + for (unsigned int p1 = 0; p1 < polygons[undecided[i]].points.size(); ++p1) + { + const Point &point1 = polygons[undecided[i]].points[p1]; + const Point &next_point1 = polygons[undecided[i]].points[(p1 + 1) % polygons[undecided[i]].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[fixed[j]].points.size(); ++p2) + { + const Point &point2 = polygons[fixed[j]].points[p2]; + const Point &next_point2 = polygons[fixed[j]].points[(p2 + 1) % polygons[fixed[j]].points.size()]; + + Vec2d intersection(0, 0); + #ifdef DEBUG + { + /* + printf("testing: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[undecided[i]].as_double() + point1.x(), dec_values_Y[undecided[i]].as_double() + point1.y(), + dec_values_X[undecided[i]].as_double() + next_point1.x(), dec_values_Y[undecided[i]].as_double() + next_point1.y(), + dec_values_X[fixed[j]].as_double() + point2.x(), dec_values_Y[fixed[j]].as_double() + point2.y(), + dec_values_X[fixed[j]].as_double() + next_point2.x(), dec_values_Y[fixed[j]].as_double() + next_point2.y()); + */ + } + #endif + + /* Seems not working, report an intersection even if there is none, using our own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[undecided[i]] + point1.x(), dec_values_Y[undecided[i]] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[fixed[j]] + point2.x(), dec_values_Y[fixed[j]] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + + if (lines_intersect(dec_values_X[undecided[i]].as_double() + point1.x(), dec_values_Y[undecided[i]].as_double() + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[fixed[j]].as_double() + point2.x(), dec_values_Y[fixed[j]].as_double() + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + /* + printf("intersect: %d (%.3f,%.3f) - [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", hidden_var_cnt, intersection.x(), intersection.y(), + dec_values_X[undecided[i]].as_double() + point1.x(), dec_values_Y[undecided[i]].as_double() + point1.y(), + dec_values_X[undecided[i]].as_double() + next_point1.x(), dec_values_Y[undecided[i]].as_double() + next_point1.y(), + dec_values_X[fixed[j]].as_double() + point2.x(), dec_values_Y[fixed[j]].as_double() + point2.y(), + dec_values_X[fixed[j]].as_double() + next_point2.x(), dec_values_Y[fixed[j]].as_double() + next_point2.y()); + */ + } + #endif + + introduce_LineNonIntersection(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_vars_X[fixed[j]], + dec_vars_Y[fixed[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + + return refined; +} + + +bool refine_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons) +{ + bool refined = false; + + #ifdef DEBUG + { + printf("Refining ***************************\n"); + } + #endif + assert(!undecided.empty()); + for (unsigned int i = 0; i < undecided.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < undecided.size(); ++j) + { + #ifdef DEBUG + { + printf("------------------------> Polygons: %d,%d\n", undecided[i], undecided[j]); + } + #endif + for (unsigned int p1 = 0; p1 < polygons[undecided[i]].points.size(); ++p1) + { + const Point &point1 = polygons[undecided[i]].points[p1]; + const Point &next_point1 = polygons[undecided[i]].points[(p1 + 1) % polygons[undecided[i]].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[undecided[j]].points.size(); ++p2) + { + const Point &point2 = polygons[undecided[j]].points[p2]; + const Point &next_point2 = polygons[undecided[j]].points[(p2 + 1) % polygons[undecided[j]].points.size()]; + + Vec2d intersection (0, 0); + #ifdef DEBUG + { + printf("%d,%d - %ld,%ld,%ld,%ld %ld,%ld,%ld,%ld\n", undecided[i], undecided[j], + dec_values_X[undecided[i]].numerator, + dec_values_X[undecided[i]].denominator, + dec_values_Y[undecided[i]].numerator, + dec_values_Y[undecided[i]].denominator, + dec_values_X[undecided[j]].numerator, + dec_values_X[undecided[j]].denominator, + dec_values_Y[undecided[j]].numerator, + dec_values_Y[undecided[j]].denominator); + + printf("point1: %d,%d,%d,%d\n", point1.x(), point1.y(), next_point1.x(), next_point1.y()); + printf("point2: %d,%d,%d,%d\n", point2.x(), point2.y(), next_point2.x(), next_point2.y()); + + printf("%ld,%ld\n", (dec_values_X[undecided[i]] + point1.x()).numerator, (dec_values_X[undecided[i]] + point1.x()).denominator); + printf("%ld,%ld\n", (dec_values_X[undecided[j]] + point1.x()).numerator, (dec_values_X[undecided[j]] + point1.x()).denominator); + + printf("testing gamma: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + (dec_values_X[undecided[j]] + next_point2.x()).as_double(), (dec_values_Y[undecided[j]] + next_point2.y()).as_double()); + } + #endif + + /* Seems not working, report an intersection even if there is none, using our own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[undecided[i]] + point1.x(), dec_values_Y[undecided[i]] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[undecided[j]] + point2.x(), dec_values_Y[undecided[j]] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + if (lines_intersect((dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("Intersecting: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + (dec_values_X[undecided[j]] + next_point2.x()).as_double(), (dec_values_Y[undecided[j]] + next_point2.y()).as_double()); + } + #endif + + introduce_LineNonIntersection(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + for (unsigned int j = 0; j < fixed.size(); ++j) + { + #ifdef DEBUG + { + printf("Fixo ------------------------> Polygons: %d,%d\n", undecided[i], fixed[j]); + } + #endif + for (unsigned int p1 = 0; p1 < polygons[undecided[i]].points.size(); ++p1) + { + const Point &point1 = polygons[undecided[i]].points[p1]; + const Point &next_point1 = polygons[undecided[i]].points[(p1 + 1) % polygons[undecided[i]].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[fixed[j]].points.size(); ++p2) + { + const Point &point2 = polygons[fixed[j]].points[p2]; + const Point &next_point2 = polygons[fixed[j]].points[(p2 + 1) % polygons[fixed[j]].points.size()]; + + Vec2d intersection(0, 0); + #ifdef DEBUG + { + printf("testing delta: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + (dec_values_X[fixed[j]] + next_point2.x()).as_double(), (dec_values_Y[fixed[j]] + next_point2.y()).as_double()); + } + #endif + + /* Seems not working, report an intersection even if there is none, using our own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[undecided[i]] + point1.x(), dec_values_Y[undecided[i]] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[fixed[j]] + point2.x(), dec_values_Y[fixed[j]] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + + if (lines_intersect((dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("Intersecting: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + (dec_values_X[fixed[j]] + next_point2.x()).as_double(), (dec_values_Y[fixed[j]] + next_point2.y()).as_double()); + } + #endif + + /* + introduce_LineNonIntersection(Solver, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point1, next_point1), + dec_vars_X[fixed[j]], + dec_vars_Y[fixed[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point2, next_point2)); + */ + introduce_LineNonIntersectionAgainstFixedLine(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_values_X[fixed[j]], + dec_values_Y[fixed[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + + return refined; +} + + +bool refine_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector &unreachable_polygons) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + return refine_SequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + dec_values_X, + dec_values_Y, + dec_values_T, + fixed, + undecided, + polygons, + _unreachable_polygons); +} + + +bool refine_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + bool refined = false; + + #ifdef DEBUG + { + printf("Refining *************************** alpha\n"); + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + printf("%d: %.3f,%.3f [%.3f]\n", + undecided[i], + dec_values_X[undecided[i]].as_double(), + dec_values_Y[undecided[i]].as_double(), + dec_values_T[undecided[i]].as_double()); + } + } + #endif + + assert(!undecided.empty()); + for (unsigned int i = 0; i < undecided.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < undecided.size(); ++j) + { + if (dec_values_T[undecided[i]] > dec_values_T[undecided[j]]) + { + #ifdef DEBUG + { + printf("------------------------> Polygons: %d,%d\n", undecided[i], undecided[j]); + } + #endif + for (unsigned int p1 = 0; p1 < polygons[undecided[i]].points.size(); ++p1) + { + const Point &point1 = polygons[undecided[i]].points[p1]; + const Point &next_point1 = polygons[undecided[i]].points[(p1 + 1) % polygons[undecided[i]].points.size()]; + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons[undecided[j]].size(); ++poly2) + { + for (unsigned int p2 = 0; p2 < unreachable_polygons[undecided[j]][poly2].points.size(); ++p2) + { + const Point &point2 = unreachable_polygons[undecided[j]][poly2].points[p2]; + const Point &next_point2 = unreachable_polygons[undecided[j]][poly2].points[(p2 + 1) % unreachable_polygons[undecided[j]][poly2].points.size()]; + + Vec2d intersection (0, 0); + #ifdef DEBUG + { + printf("%d,%d - %ld,%ld,%ld,%ld %ld,%ld,%ld,%ld\n", undecided[i], undecided[j], + dec_values_X[undecided[i]].numerator, + dec_values_X[undecided[i]].denominator, + dec_values_Y[undecided[i]].numerator, + dec_values_Y[undecided[i]].denominator, + dec_values_X[undecided[j]].numerator, + dec_values_X[undecided[j]].denominator, + dec_values_Y[undecided[j]].numerator, + dec_values_Y[undecided[j]].denominator); + + printf("point1: %d,%d,%d,%d\n", point1.x(), point1.y(), next_point1.x(), next_point1.y()); + printf("point2: %d,%d,%d,%d\n", point2.x(), point2.y(), next_point2.x(), next_point2.y()); + + printf("%ld,%ld\n", (dec_values_X[undecided[i]] + point1.x()).numerator, (dec_values_X[undecided[i]] + point1.x()).denominator); + printf("%ld,%ld\n", (dec_values_X[undecided[j]] + point2.x()).numerator, (dec_values_X[undecided[j]] + point2.x()).denominator); + + printf("testing epsilon: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + (dec_values_X[undecided[j]] + next_point2.x()).as_double(), (dec_values_Y[undecided[j]] + next_point2.y()).as_double()); + } + #endif + + /* Seems not working, report an intersection even if there is none, using our own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[undecided[i]] + point1.x(), dec_values_Y[undecided[i]] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[undecided[j]] + point2.x(), dec_values_Y[undecided[j]] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + if (lines_intersect((dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("Intersecting: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + (dec_values_X[undecided[j]] + next_point2.x()).as_double(), (dec_values_Y[undecided[j]] + next_point2.y()).as_double()); + } + #endif + + /* + introduce_LineNonIntersection(Solver, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point1, next_point1), + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point2, next_point2)); + */ + + introduce_SequentialLineNonIntersection(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + dec_vars_T[undecided[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + else + { + if (dec_values_T[undecided[i]] < dec_values_T[undecided[j]]) + { + #ifdef DEBUG + { + printf("------------------------> Polygons: %d,%d\n", undecided[i], undecided[j]); + } + #endif + for (unsigned int poly1 = 0; poly1 < unreachable_polygons[undecided[i]].size(); ++poly1) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons[undecided[i]][poly1].points.size(); ++p1) + { + const Point &point1 = unreachable_polygons[undecided[i]][poly1].points[p1]; + const Point &next_point1 = unreachable_polygons[undecided[i]][poly1].points[(p1 + 1) % unreachable_polygons[undecided[i]][poly1].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[undecided[j]].points.size(); ++p2) + { + const Point &point2 = polygons[undecided[j]].points[p2]; + const Point &next_point2 = polygons[undecided[j]].points[(p2 + 1) % polygons[undecided[j]].points.size()]; + + Vec2d intersection (0, 0); + #ifdef DEBUG + { + printf("%d,%d - %ld,%ld,%ld,%ld %ld,%ld,%ld,%ld\n", undecided[i], undecided[j], + dec_values_X[undecided[i]].numerator, + dec_values_X[undecided[i]].denominator, + dec_values_Y[undecided[i]].numerator, + dec_values_Y[undecided[i]].denominator, + dec_values_X[undecided[j]].numerator, + dec_values_X[undecided[j]].denominator, + dec_values_Y[undecided[j]].numerator, + dec_values_Y[undecided[j]].denominator); + + printf("point1: %d,%d,%d,%d\n", point1.x(), point1.y(), next_point1.x(), next_point1.y()); + printf("point2: %d,%d,%d,%d\n", point2.x(), point2.y(), next_point2.x(), next_point2.y()); + + printf("%ld,%ld\n", (dec_values_X[undecided[i]] + point1.x()).numerator, (dec_values_X[undecided[i]] + point1.x()).denominator); + printf("%ld,%ld\n", (dec_values_X[undecided[j]] + point2.x()).numerator, (dec_values_X[undecided[j]] + point2.x()).denominator); + + printf("testing iota: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + (dec_values_X[undecided[j]] + next_point2.x()).as_double(), (dec_values_Y[undecided[j]] + next_point2.y()).as_double()); + } + #endif + + /* Seems not working, report an intersection even if there is none, using our own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[undecided[i]] + point1.x(), dec_values_Y[undecided[i]] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[undecided[j]] + point2.x(), dec_values_Y[undecided[j]] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + if (lines_intersect((dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("Intersecting: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + (dec_values_X[undecided[j]] + next_point2.x()).as_double(), (dec_values_Y[undecided[j]] + next_point2.y()).as_double()); + } + #endif + + /* + introduce_LineNonIntersection(Solver, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point1, next_point1), + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point2, next_point2)); + */ + + #ifdef DEBUG + { + printf("Hidden var: %d\n", hidden_var_cnt); + } + #endif + introduce_SequentialLineNonIntersection(Solver, + Context, + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + dec_vars_T[undecided[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point2, next_point2), + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point1, next_point1)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + else + { + assert(false); + } + } + } + } + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + for (unsigned int j = 0; j < fixed.size(); ++j) + { + if (dec_values_T[undecided[i]] > dec_values_T[fixed[j]]) + { + #ifdef DEBUG + { + printf("Fixo iota ------------------------> Polygons: %d,%d\n", undecided[i], fixed[j]); + printf("Times iota: %.3f, %.3f\n", dec_values_T[undecided[i]].as_double(), dec_values_T[fixed[j]].as_double()); + } + #endif + + for (unsigned int p1 = 0; p1 < polygons[undecided[i]].points.size(); ++p1) + { + const Point &point1 = polygons[undecided[i]].points[p1]; + const Point &next_point1 = polygons[undecided[i]].points[(p1 + 1) % polygons[undecided[i]].points.size()]; + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons[fixed[j]].size(); ++poly2) + { + for (unsigned int p2 = 0; p2 < unreachable_polygons[fixed[j]][poly2].points.size(); ++p2) + { + const Point &point2 = unreachable_polygons[fixed[j]][poly2].points[p2]; + const Point &next_point2 = unreachable_polygons[fixed[j]][poly2].points[(p2 + 1) % unreachable_polygons[fixed[j]][poly2].points.size()]; + + Vec2d intersection(0, 0); + #ifdef DEBUG + { + /* + printf("testing kappa: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + (dec_values_X[fixed[j]] + next_point2.x()).as_double(), (dec_values_Y[fixed[j]] + next_point2.y()).as_double()); + */ + } + #endif + + /* Seems not working, report an intersection even if there is none, using our own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[undecided[i]] + point1.x(), dec_values_Y[undecided[i]] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[fixed[j]] + point2.x(), dec_values_Y[fixed[j]] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + + if (lines_intersect((dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("Intersecting: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + (dec_values_X[fixed[j]] + next_point2.x()).as_double(), (dec_values_Y[fixed[j]] + next_point2.y()).as_double()); + + printf("testing iota decs: [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[undecided[i]].as_double(), + dec_values_Y[undecided[i]].as_double(), + dec_values_X[fixed[j]].as_double(), + dec_values_Y[fixed[j]].as_double()); + } + #endif + + /* + introduce_LineNonIntersection(Solver, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point1, next_point1), + dec_vars_X[fixed[j]], + dec_vars_Y[fixed[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point2, next_point2)); + */ + #ifdef DEBUG + { + printf("Hidden var iota: %d\n", hidden_var_cnt); + } + #endif + /* + int hidden_var1 = hidden_var_cnt++; + int hidden_var2 = hidden_var_cnt++; + */ + introduce_SequentialLineNonIntersectionAgainstFixedLine(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_values_X[fixed[j]], + dec_values_Y[fixed[j]], + dec_values_T[fixed[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + refined = true; + } + } + } + } + } + else + { + if (dec_values_T[undecided[i]] < dec_values_T[fixed[j]]) + { + #ifdef DEBUG + { + printf("Times: %.3f, %.3f\n", dec_values_T[undecided[i]].as_double(), dec_values_T[fixed[j]].as_double()); + printf("Fixo kappa ------------------------> Polygons: %d,%d\n", undecided[i], fixed[j]); + } + #endif + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons[undecided[i]].size(); ++poly1) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons[undecided[i]][poly1].points.size(); ++p1) + { + const Point &point1 = unreachable_polygons[undecided[i]][poly1].points[p1]; + const Point &next_point1 = unreachable_polygons[undecided[i]][poly1].points[(p1 + 1) % unreachable_polygons[undecided[i]][poly1].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[fixed[j]].points.size(); ++p2) + { + const Point &point2 = polygons[fixed[j]].points[p2]; + const Point &next_point2 = polygons[fixed[j]].points[(p2 + 1) % polygons[fixed[j]].points.size()]; + + Vec2d intersection(0, 0); + #ifdef DEBUG + { + printf("testing lambda: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + (dec_values_X[fixed[j]] + next_point2.x()).as_double(), (dec_values_Y[fixed[j]] + next_point2.y()).as_double()); + + printf("testing kappa decs: [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[undecided[i]].as_double(), + dec_values_Y[undecided[i]].as_double(), + dec_values_X[fixed[j]].as_double(), + dec_values_Y[fixed[j]].as_double()); + } + #endif + + /* Seems not working, report an intersection even if there is none, using our own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[undecided[i]] + point1.x(), dec_values_Y[undecided[i]] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[fixed[j]] + point2.x(), dec_values_Y[fixed[j]] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + + if (lines_intersect((dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("Intersecting: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + (dec_values_X[fixed[j]] + next_point2.x()).as_double(), (dec_values_Y[fixed[j]] + next_point2.y()).as_double()); + } + #endif + + /* + introduce_LineNonIntersection(Solver, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point1, next_point1), + dec_vars_X[fixed[j]], + dec_vars_Y[fixed[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point2, next_point2)); + */ + #ifdef DEBUG + { + printf("Hidden var kappa: %d\n", hidden_var_cnt); + } + #endif + introduce_SequentialFixedLineNonIntersectionAgainstLine(Solver, + Context, + dec_values_X[fixed[j]], + dec_values_Y[fixed[j]], + dec_values_T[fixed[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point2, next_point2), + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point1, next_point1)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + else + { + #ifdef DEBUG + { + printf("Times: %.3f, %.3f (%d,%d)\n", dec_values_T[undecided[i]].as_double(), dec_values_T[fixed[j]].as_double(), undecided[i], fixed[j]); + cout.flush(); + } + #endif + assert(false); + } + } + } + } + + return refined; +} + + +bool refine_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector &unreachable_polygons) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + return refine_ConsequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + dec_values_X, + dec_values_Y, + dec_values_T, + fixed, + undecided, + polygons, + _unreachable_polygons); +} + + +bool refine_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + bool refined = false; + + #ifdef DEBUG + { + printf("Refining *************************** alpha\n"); + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + printf("%d: %.3f,%.3f [%.3f]\n", + undecided[i], + dec_values_X[undecided[i]].as_double(), + dec_values_Y[undecided[i]].as_double(), + dec_values_T[undecided[i]].as_double()); + } + } + #endif + + assert(!undecided.empty()); + for (unsigned int i = 0; i < undecided.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < undecided.size(); ++j) + { + if (dec_values_T[undecided[i]].is_Positive() && dec_values_T[undecided[j]].is_Positive() && dec_values_T[undecided[i]] > dec_values_T[undecided[j]]) + { + #ifdef DEBUG + { + printf("------------------------> Polygons: %d,%d\n", undecided[i], undecided[j]); + } + #endif + for (unsigned int p1 = 0; p1 < polygons[undecided[i]].points.size(); ++p1) + { + const Point &point1 = polygons[undecided[i]].points[p1]; + const Point &next_point1 = polygons[undecided[i]].points[(p1 + 1) % polygons[undecided[i]].points.size()]; + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons[undecided[j]].size(); ++poly2) + { + for (unsigned int p2 = 0; p2 < unreachable_polygons[undecided[j]][poly2].points.size(); ++p2) + { + const Point &point2 = unreachable_polygons[undecided[j]][poly2].points[p2]; + const Point &next_point2 = unreachable_polygons[undecided[j]][poly2].points[(p2 + 1) % unreachable_polygons[undecided[j]][poly2].points.size()]; + + Vec2d intersection (0, 0); + #ifdef DEBUG + { + printf("%d,%d - %ld,%ld,%ld,%ld %ld,%ld,%ld,%ld\n", undecided[i], undecided[j], + dec_values_X[undecided[i]].numerator, + dec_values_X[undecided[i]].denominator, + dec_values_Y[undecided[i]].numerator, + dec_values_Y[undecided[i]].denominator, + dec_values_X[undecided[j]].numerator, + dec_values_X[undecided[j]].denominator, + dec_values_Y[undecided[j]].numerator, + dec_values_Y[undecided[j]].denominator); + + printf("point1: %d,%d,%d,%d\n", point1.x(), point1.y(), next_point1.x(), next_point1.y()); + printf("point2: %d,%d,%d,%d\n", point2.x(), point2.y(), next_point2.x(), next_point2.y()); + + printf("%ld,%ld\n", (dec_values_X[undecided[i]] + point1.x()).numerator, (dec_values_X[undecided[i]] + point1.x()).denominator); + printf("%ld,%ld\n", (dec_values_X[undecided[j]] + point2.x()).numerator, (dec_values_X[undecided[j]] + point2.x()).denominator); + + printf("testing epsilon: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + (dec_values_X[undecided[j]] + next_point2.x()).as_double(), (dec_values_Y[undecided[j]] + next_point2.y()).as_double()); + } + #endif + + /* Seems not working, report an intersection even if there is none, using our own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[undecided[i]] + point1.x(), dec_values_Y[undecided[i]] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[undecided[j]] + point2.x(), dec_values_Y[undecided[j]] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + if (lines_intersect((dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("Intersecting: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + (dec_values_X[undecided[j]] + next_point2.x()).as_double(), (dec_values_Y[undecided[j]] + next_point2.y()).as_double()); + } + #endif + + /* + introduce_LineNonIntersection(Solver, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point1, next_point1), + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point2, next_point2)); + */ + + introduce_ConsequentialLineNonIntersection(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + dec_vars_T[undecided[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + else + { + if (dec_values_T[undecided[i]].is_Positive() && dec_values_T[undecided[j]].is_Positive() && dec_values_T[undecided[i]] < dec_values_T[undecided[j]]) + { + #ifdef DEBUG + { + printf("------------------------> Polygons: %d,%d\n", undecided[i], undecided[j]); + } + #endif + for (unsigned int poly1 = 0; poly1 < unreachable_polygons[undecided[i]].size(); ++poly1) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons[undecided[i]][poly1].points.size(); ++p1) + { + const Point &point1 = unreachable_polygons[undecided[i]][poly1].points[p1]; + const Point &next_point1 = unreachable_polygons[undecided[i]][poly1].points[(p1 + 1) % unreachable_polygons[undecided[i]][poly1].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[undecided[j]].points.size(); ++p2) + { + const Point &point2 = polygons[undecided[j]].points[p2]; + const Point &next_point2 = polygons[undecided[j]].points[(p2 + 1) % polygons[undecided[j]].points.size()]; + + Vec2d intersection (0, 0); + #ifdef DEBUG + { + printf("%d,%d - %ld,%ld,%ld,%ld %ld,%ld,%ld,%ld\n", undecided[i], undecided[j], + dec_values_X[undecided[i]].numerator, + dec_values_X[undecided[i]].denominator, + dec_values_Y[undecided[i]].numerator, + dec_values_Y[undecided[i]].denominator, + dec_values_X[undecided[j]].numerator, + dec_values_X[undecided[j]].denominator, + dec_values_Y[undecided[j]].numerator, + dec_values_Y[undecided[j]].denominator); + + printf("point1: %d,%d,%d,%d\n", point1.x(), point1.y(), next_point1.x(), next_point1.y()); + printf("point2: %d,%d,%d,%d\n", point2.x(), point2.y(), next_point2.x(), next_point2.y()); + + printf("%ld,%ld\n", (dec_values_X[undecided[i]] + point1.x()).numerator, (dec_values_X[undecided[i]] + point1.x()).denominator); + printf("%ld,%ld\n", (dec_values_X[undecided[j]] + point2.x()).numerator, (dec_values_X[undecided[j]] + point2.x()).denominator); + + printf("testing iota: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + (dec_values_X[undecided[j]] + next_point2.x()).as_double(), (dec_values_Y[undecided[j]] + next_point2.y()).as_double()); + } + #endif + + /* Seems not working, report an intersection even if there is none, using our own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[undecided[i]] + point1.x(), dec_values_Y[undecided[i]] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[undecided[j]] + point2.x(), dec_values_Y[undecided[j]] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + if (lines_intersect((dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("Intersecting: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[undecided[j]] + point2.x()).as_double(), (dec_values_Y[undecided[j]] + point2.y()).as_double(), + (dec_values_X[undecided[j]] + next_point2.x()).as_double(), (dec_values_Y[undecided[j]] + next_point2.y()).as_double()); + } + #endif + + /* + introduce_LineNonIntersection(Solver, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point1, next_point1), + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point2, next_point2)); + */ + + #ifdef DEBUG + { + printf("Hidden var: %d\n", hidden_var_cnt); + } + #endif + introduce_ConsequentialLineNonIntersection(Solver, + Context, + dec_vars_X[undecided[j]], + dec_vars_Y[undecided[j]], + dec_vars_T[undecided[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point2, next_point2), + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point1, next_point1)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + else + { + #ifdef DEBUG + { + printf("The pair is not effective: %d,%d\n", undecided[i], undecided[j]); + } + #endif + } + } + } + } + + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + for (unsigned int j = 0; j < fixed.size(); ++j) + { + if (dec_values_T[undecided[i]].is_Positive() && dec_values_T[fixed[j]].is_Positive() && dec_values_T[undecided[i]] > dec_values_T[fixed[j]]) + { + #ifdef DEBUG + { + printf("Fixo iota ------------------------> Polygons: %d,%d\n", undecided[i], fixed[j]); + printf("Times iota: %.3f, %.3f\n", dec_values_T[undecided[i]].as_double(), dec_values_T[fixed[j]].as_double()); + } + #endif + for (unsigned int p1 = 0; p1 < polygons[undecided[i]].points.size(); ++p1) + { + const Point &point1 = polygons[undecided[i]].points[p1]; + const Point &next_point1 = polygons[undecided[i]].points[(p1 + 1) % polygons[undecided[i]].points.size()]; + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons[fixed[j]].size(); ++poly2) + { + for (unsigned int p2 = 0; p2 < unreachable_polygons[fixed[j]][poly2].points.size(); ++p2) + { + const Point &point2 = unreachable_polygons[fixed[j]][poly2].points[p2]; + const Point &next_point2 = unreachable_polygons[fixed[j]][poly2].points[(p2 + 1) % unreachable_polygons[fixed[j]][poly2].points.size()]; + + Vec2d intersection(0, 0); + #ifdef DEBUG + { + /* + printf("testing kappa: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + (dec_values_X[fixed[j]] + next_point2.x()).as_double(), (dec_values_Y[fixed[j]] + next_point2.y()).as_double()); + */ + } + #endif + + /* Seems not working, report an intersection even if there is none, using our own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[undecided[i]] + point1.x(), dec_values_Y[undecided[i]] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[fixed[j]] + point2.x(), dec_values_Y[fixed[j]] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + + if (lines_intersect((dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("Intersecting: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + (dec_values_X[fixed[j]] + next_point2.x()).as_double(), (dec_values_Y[fixed[j]] + next_point2.y()).as_double()); + + printf("testing iota decs: [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[undecided[i]].as_double(), + dec_values_Y[undecided[i]].as_double(), + dec_values_X[fixed[j]].as_double(), + dec_values_Y[fixed[j]].as_double()); + } + #endif + + /* + introduce_LineNonIntersection(Solver, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point1, next_point1), + dec_vars_X[fixed[j]], + dec_vars_Y[fixed[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point2, next_point2)); + */ + #ifdef DEBUG + { + printf("Hidden var iota: %d\n", hidden_var_cnt); + } + #endif + /* + int hidden_var1 = hidden_var_cnt++; + int hidden_var2 = hidden_var_cnt++; + */ + introduce_ConsequentialLineNonIntersectionAgainstFixedLine(Solver, + Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point1, next_point1), + dec_values_X[fixed[j]], + dec_values_Y[fixed[j]], + dec_values_T[fixed[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point2, next_point2)); + hidden_var_cnt += 2; + refined = true; + } + } + } + } + } + else + { + if (dec_values_T[undecided[i]].is_Positive() && dec_values_T[fixed[j]].is_Positive() && dec_values_T[undecided[i]] < dec_values_T[fixed[j]]) + { + #ifdef DEBUG + { + printf("Times: %.3f, %.3f\n", dec_values_T[undecided[i]].as_double(), dec_values_T[fixed[j]].as_double()); + printf("Fixo kappa ------------------------> Polygons: %d,%d\n", undecided[i], fixed[j]); + } + #endif + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons[undecided[i]].size(); ++poly1) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons[undecided[i]][poly1].points.size(); ++p1) + { + const Point &point1 = unreachable_polygons[undecided[i]][poly1].points[p1]; + const Point &next_point1 = unreachable_polygons[undecided[i]][poly1].points[(p1 + 1) % unreachable_polygons[undecided[i]][poly1].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[fixed[j]].points.size(); ++p2) + { + const Point &point2 = polygons[fixed[j]].points[p2]; + const Point &next_point2 = polygons[fixed[j]].points[(p2 + 1) % polygons[fixed[j]].points.size()]; + + Vec2d intersection(0, 0); + #ifdef DEBUG + { + printf("testing lambda: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + (dec_values_X[fixed[j]] + next_point2.x()).as_double(), (dec_values_Y[fixed[j]] + next_point2.y()).as_double()); + + printf("testing kappa decs: [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[undecided[i]].as_double(), + dec_values_Y[undecided[i]].as_double(), + dec_values_X[fixed[j]].as_double(), + dec_values_Y[fixed[j]].as_double()); + } + #endif + + /* Seems not working, report an intersection even if there is none, using our own lines_intersect() instead + if (Slic3r::Geometry::segment_segment_intersection(Vec2d(dec_values_X[undecided[i]] + point1.x(), dec_values_Y[undecided[i]] + point1.y()), + Vec2d(next_point1.x() - point1.x(), next_point1.y() - point1.y()), + Vec2d(dec_values_X[fixed[j]] + point2.x(), dec_values_Y[fixed[j]] + point2.y()), + Vec2d(next_point2.x() - point2.x(), next_point2.y() - point2.y()), + intersection)) + */ + + if (lines_intersect((dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("Intersecting: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + (dec_values_X[undecided[i]] + point1.x()).as_double(), (dec_values_Y[undecided[i]] + point1.y()).as_double(), + (dec_values_X[undecided[i]] + next_point1.x()).as_double(), (dec_values_Y[undecided[i]] + next_point1.y()).as_double(), + (dec_values_X[fixed[j]] + point2.x()).as_double(), (dec_values_Y[fixed[j]] + point2.y()).as_double(), + (dec_values_X[fixed[j]] + next_point2.x()).as_double(), (dec_values_Y[fixed[j]] + next_point2.y()).as_double()); + } + #endif + + /* + introduce_LineNonIntersection(Solver, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point1, next_point1), + dec_vars_X[fixed[j]], + dec_vars_Y[fixed[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt++)).c_str())), + Line(point2, next_point2)); + */ + #ifdef DEBUG + { + printf("Hidden var kappa: %d\n", hidden_var_cnt); + } + #endif + introduce_ConsequentialFixedLineNonIntersectionAgainstLine(Solver, + Context, + dec_values_X[fixed[j]], + dec_values_Y[fixed[j]], + dec_values_T[fixed[j]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt)).c_str())), + Line(point2, next_point2), + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + dec_vars_T[undecided[i]], + z3::expr(Context.real_const(("hidden-var-" + to_string(hidden_var_cnt + 1)).c_str())), + Line(point1, next_point1)); + hidden_var_cnt += 2; + + refined = true; + } + } + } + } + } + else + { + #ifdef DEBUG + { + printf("Times: %.3f, %.3f (%d,%d)\n", dec_values_T[undecided[i]].as_double(), dec_values_T[fixed[j]].as_double(), undecided[i], fixed[j]); + cout.flush(); + } + #endif + + #ifdef DEBUG + { + printf("The pair is not effective: %d,%d\n", undecided[i], fixed[j]); + } + #endif + } + } + } + } + + return refined; +} + + +/*----------------------------------------------------------------*/ + +std::optional > check_PointsOutsidePolygons(const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + #ifdef DEBUG + { + printf("Levels U %zu,%zu\n", unreachable_polygons[0].size(), unreachable_polygons[1].size()); + + int c = 0; + string svg_filename = "collision_checking.svg"; + SVG checking_svg(svg_filename); + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + Polygon display_polygon = polygons[i]; + + for (unsigned int j = 0; j < display_polygon.points.size(); ++j) + { + display_polygon.points[j] = Point(SEQ_SVG_SCALE_FACTOR * (display_polygon.points[j].x() + dec_values_X[i].as_double()), + SEQ_SVG_SCALE_FACTOR * (display_polygon.points[j].y() + dec_values_Y[i].as_double())); + } + + string color; + + switch(c % 8) + { + case 0: + { + color = "green"; + break; + } + case 1: + { + color = "blue"; + break; + } + case 2: + { + color = "red"; + break; + } + case 3: + { + color = "grey"; + break; + } + case 4: + { + color = "cyan"; + break; + } + case 5: + { + color = "magenta"; + break; + } + case 6: + { + color = "yellow"; + break; + } + case 7: + { + color = "black"; + break; + } + case 8: + { + color = "indigo"; + break; + } + } + checking_svg.draw(display_polygon, color); + ++c; + } + for (unsigned int i = 0; i < unreachable_polygons.size(); ++i) + { + for (unsigned int k = 0; k < unreachable_polygons[i].size(); ++k) + { + Polygon display_polygon = unreachable_polygons[i][k]; + + for (unsigned int j = 0; j < display_polygon.points.size(); ++j) + { + display_polygon.points[j] = Point(SEQ_SVG_SCALE_FACTOR * (display_polygon.points[j].x() + dec_values_X[i].as_double()), + SEQ_SVG_SCALE_FACTOR * (display_polygon.points[j].y() + dec_values_Y[i].as_double())); + } + + string color; + + switch(c % 8) + { + case 0: + { + color = "green"; + break; + } + case 1: + { + color = "blue"; + break; + } + case 2: + { + color = "red"; + break; + } + case 3: + { + color = "grey"; + break; + } + case 4: + { + color = "cyan"; + break; + } + case 5: + { + color = "magenta"; + break; + } + case 6: + { + color = "yellow"; + break; + } + case 7: + { + color = "black"; + break; + } + case 8: + { + color = "indigo"; + break; + } + } + checking_svg.draw(display_polygon, color); + ++c; + } + } + checking_svg.Close(); + } + #endif + + if (!polygons.empty()) + { + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + if (dec_values_T[i] > dec_values_T[j]) + { + for (unsigned int p1 = 0; p1 < polygons[i].points.size(); ++p1) + { + const Point &point1 = polygons[i].points[p1]; + + #ifdef DEBUG + { + printf(">----------------\n"); + } + #endif + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons[j].size(); ++poly2) + { + if (unreachable_polygons[j][poly2].points.size() >= 3) + { + bool always_inside_halfplane = true; + + #ifdef DEBUG + { + printf("....\n"); + } + #endif + + for (unsigned int p2 = 0; p2 < unreachable_polygons[j][poly2].points.size(); ++p2) + { + const Point &point2 = unreachable_polygons[j][poly2].points[p2]; + const Point &next_point2 = unreachable_polygons[j][poly2].points[(p2 + 1) % unreachable_polygons[j][poly2].points.size()]; + + Line line(point2, next_point2); + Vector normal = line.normal(); + + double outside = (normal.x() * (dec_values_X[i].as_double() + point1.x())) + + (normal.y() * (dec_values_Y[i].as_double() + point1.y())) + - (normal.x() * dec_values_X[j].as_double()) + - (normal.x() * line.a.x()) + - (normal.y() * dec_values_Y[j].as_double()) + - (normal.y() * line.a.y()); + + #ifdef DEBUG + { + printf("Tested point: %d, %d\n", point1.x(), point1.y()); + printf("Point: %d, %d\n", point2.x(), point2.y()); + printf("Next point: %d, %d\n", next_point2.x(), next_point2.y()); + printf("X[i]: %.3f, Y[i]: %.3f, X[j]: %.3f, Y[j]: %.3f\n", dec_values_X[i].as_double(), dec_values_Y[i].as_double(), dec_values_X[j].as_double(), dec_values_Y[j].as_double()); + printf("Outside 1: %.3f\n", outside); + } + #endif + + if (outside > -EPSILON) + { + always_inside_halfplane = false; + break; + } + } + if (always_inside_halfplane) + { + return std::pair(j, i); + } + } + } + } + } + else if (dec_values_T[i] < dec_values_T[j]) + { + for (unsigned int p2 = 0; p2 < polygons[j].points.size(); ++p2) + { + const Point &point2 = polygons[j].points[p2]; + + #ifdef DEBUG + { + printf("<----------------\n"); + } + #endif + + for (unsigned int poly1 = 0; poly1 < unreachable_polygons[i].size(); ++poly1) + { + if (unreachable_polygons[i][poly1].points.size() >= 3) + { + bool always_inside_halfplane = true; + + #ifdef DEBUG + { + printf("....\n"); + } + #endif + + for (unsigned int p1 = 0; p1 < unreachable_polygons[i][poly1].points.size(); ++p1) + { + const Point &point1 = unreachable_polygons[i][poly1].points[p1]; + const Point &next_point1 = unreachable_polygons[i][poly1].points[(p1 + 1) % unreachable_polygons[i][poly1].points.size()]; + + Line line(point1, next_point1); + Vector normal = line.normal(); + + double outside = (normal.x() * (dec_values_X[j].as_double() + point2.x())) + + (normal.y() * (dec_values_Y[j].as_double() + point2.y())) + - (normal.x() * dec_values_X[i].as_double()) + - (normal.x() * line.a.x()) + - (normal.y() * dec_values_Y[i].as_double()) + - (normal.y() * line.a.y()); + + #ifdef DEBUG + { + printf("Tested point: %.3f, %.3f\n", dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y()); + printf("Point: %.3f, %.3f\n", point1.x() + dec_values_X[i].as_double(), point1.y() + dec_values_Y[i].as_double()); + printf("Next point: %.3f, %.3f\n", next_point1.x() + dec_values_X[i].as_double(), next_point1.y() + dec_values_Y[i].as_double()); + printf("X[i]: %.3f, Y[i]: %.3f, X[j]: %.3f, Y[j]: %.3f\n", dec_values_X[i].as_double(), dec_values_Y[i].as_double(), dec_values_X[j].as_double(), dec_values_Y[j].as_double()); + printf("Outside 2: %.3f\n", outside); + } + #endif + + if (outside > -EPSILON) + { + always_inside_halfplane = false; + break; + } + } + if (always_inside_halfplane) + { + return std::pair(i, j); + } + } + } + } + } + else + { + #ifdef DEBUG + { + printf("Time collision: %.3f, %.3f\n", dec_values_T[i].as_double(), dec_values_T[j].as_double()); + } + #endif + assert(false); + } + } + } + } + #ifdef DEBUG + { + printf("Points DONE !!!\n"); + } + #endif + + return {}; +} + + +std::optional > check_PolygonLineIntersections(const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + if (!polygons.empty()) + { + for (unsigned int i = 0; i < polygons.size() - 1; ++i) + { + for (unsigned int j = i + 1; j < polygons.size(); ++j) + { + if (dec_values_T[i] > dec_values_T[j]) + { + for (unsigned int p1 = 0; p1 < polygons[i].points.size(); ++p1) + { + const Point &point1 = polygons[i].points[p1]; + const Point &next_point1 = polygons[i].points[(p1 + 1) % polygons[i].points.size()]; + + for (unsigned int poly2 = 0; poly2 < unreachable_polygons[j].size(); ++poly2) + { + #ifdef DEBUG + { + printf("temporal: %.3f %.3f [ij: %d,%d]\n", dec_values_T[i].as_double(), dec_values_T[j].as_double(), i, j); + printf("proto X1: %ld, %ld, %ld\n", unreachable_polygons.size(), unreachable_polygons[j].size(), unreachable_polygons[j][poly2].points.size()); + } + #endif + + for (unsigned int p2 = 0; p2 < unreachable_polygons[j][poly2].points.size(); ++p2) + { + const Point &point2 = unreachable_polygons[j][poly2].points[p2]; + const Point &next_point2 = unreachable_polygons[j][poly2].points[(p2 + 1) % unreachable_polygons[j][poly2].points.size()]; + + #ifdef DEBUG + { + printf("testing alpha %d %d (%d,%d): [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", i, j, p1, p2, + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + if (lines_intersect_open(dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + + { + #ifdef DEBUG + { + printf("temps: [ij: %d,%d] [%.3f, %.3f]\n", i, j, + dec_values_T[i].as_double(), + dec_values_T[j].as_double()); + + printf("dec_values: [%.3f, %.3f] [%.3f,%.3f]\n", + dec_values_X[i].as_double(), + dec_values_Y[i].as_double(), + dec_values_X[j].as_double(), + dec_values_Y[j].as_double()); + + printf("intersect 1: %d [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + hidden_var_cnt, + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + return std::pair(j, i); + } + } + } + } + } + else + { + if (dec_values_T[i] < dec_values_T[j]) + { + for (unsigned int poly1 = 0; poly1 < unreachable_polygons[i].size(); ++poly1) + { + for (unsigned int p1 = 0; p1 < unreachable_polygons[i][poly1].points.size(); ++p1) + { + #ifdef DEBUG + { + printf("proto2: %ld, %ld, %ld\n", unreachable_polygons.size(), unreachable_polygons[i].size(), unreachable_polygons[i][poly1].points.size()); + } + #endif + + const Point &point1 = unreachable_polygons[i][poly1].points[p1]; + const Point &next_point1 = unreachable_polygons[i][poly1].points[(p1 + 1) % unreachable_polygons[i][poly1].points.size()]; + + for (unsigned int p2 = 0; p2 < polygons[j].points.size(); ++p2) + { + const Point &point2 = polygons[j].points[p2]; + const Point &next_point2 = polygons[j].points[(p2 + 1) % polygons[j].points.size()]; + + #ifdef DEBUG + { + printf("testing beta: [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + if (lines_intersect_open(dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + next_point1.x() - point1.x(), next_point1.y() - point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + next_point2.x() - point2.x(), next_point2.y() - point2.y())) + { + #ifdef DEBUG + { + printf("temps: [ij: %d,%d] [%.3f, %.3f]\n", i, j, + dec_values_T[i].as_double(), + dec_values_T[j].as_double()); + + printf("dec_values: [%.3f, %.3f] [%.3f,%.3f]\n", + dec_values_X[i].as_double(), + dec_values_Y[i].as_double(), + dec_values_X[j].as_double(), + dec_values_Y[j].as_double()); + + printf("intersect 2: %d [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f] [%.3f,%.3f]\n", + hidden_var_cnt, + dec_values_X[i].as_double() + point1.x(), dec_values_Y[i].as_double() + point1.y(), + dec_values_X[i].as_double() + next_point1.x(), dec_values_Y[i].as_double() + next_point1.y(), + dec_values_X[j].as_double() + point2.x(), dec_values_Y[j].as_double() + point2.y(), + dec_values_X[j].as_double() + next_point2.x(), dec_values_Y[j].as_double() + next_point2.y()); + } + #endif + + return std::pair(i, j); + } + } + } + } + } + else + { + #ifdef DEBUG + { + printf("Time collision: %.3f, %.3f\n", dec_values_T[i].as_double(), dec_values_T[j].as_double()); + } + #endif + assert(false); + } + } + } + } + } + + #ifdef DEBUG + { + printf("Lines DONE !!!\n"); + } + #endif + + return {}; +} + + +/*----------------------------------------------------------------*/ + +void extract_DecisionValuesFromModel(const z3::model &Model, + const string_map &dec_var_names_map, + std::vector &dec_values_X, + std::vector &dec_values_Y) +{ + for (unsigned int i = 0; i < Model.size(); ++i) + { + double value = Model.get_const_interp(Model[i]).as_double(); + + switch (Model[i].name().str()[0]) + { + case 'X': + { + string_map::const_iterator var_item = dec_var_names_map.find(Model[i].name().str()); + if (var_item != dec_var_names_map.end()) + { + dec_values_X[var_item->second] = value; + } + break; + } + case 'Y': + { + string_map::const_iterator var_item = dec_var_names_map.find(Model[i].name().str()); + if (var_item != dec_var_names_map.end()) + { + dec_values_Y[var_item->second] = value; + } + break; + } + default: + { + break; + } + } + } +} + + +void extract_DecisionValuesFromModel(const z3::model &Model, + z3::context &Context, + const string_map &dec_var_names_map, + z3::expr_vector &dec_values_X, + z3::expr_vector &dec_values_Y) +{ + z3::expr_vector unordered_values_X(Context); + z3::expr_vector unordered_values_Y(Context); + + std::map value_indices_X; + std::map value_indices_Y; + + for (unsigned int i = 0; i < Model.size(); ++i) + { + z3::expr value = Model.get_const_interp(Model[i]); + + #ifdef DEBUG + { + printf("extracted: %.3f (%s)\n", value.as_double(), Model[i].name().str().c_str()); + } + #endif + + switch (Model[i].name().str()[0]) + { + case 'X': + { + string_map::const_iterator var_item = dec_var_names_map.find(Model[i].name().str()); + if (var_item != dec_var_names_map.end()) + { + value_indices_X[var_item->second] = i; + unordered_values_X.push_back(z3::expr(Context.real_val(value.numerator().as_int64(), value.denominator().as_int64()))); + + #ifdef DEBUG + { + printf("saved: %.3f\n", unordered_values_X.back().as_double()); + } + #endif + } + break; + } + case 'Y': + { + string_map::const_iterator var_item = dec_var_names_map.find(Model[i].name().str()); + if (var_item != dec_var_names_map.end()) + { + value_indices_Y[var_item->second] = i; + unordered_values_Y.push_back(z3::expr(Context.real_val(value.numerator().as_int64(), value.denominator().as_int64()))); + + #ifdef DEBUG + { + printf("saved: %.3f\n", unordered_values_Y.back().as_double()); + } + #endif + } + break; + } + default: + { + break; + } + } + } + + dec_values_X.resize(0); + dec_values_Y.resize(0); + + for (std::map::const_iterator value = value_indices_X.begin(); value != value_indices_X.end(); ++value) + { + dec_values_X.push_back(unordered_values_X[value->second]); + } + for (std::map::const_iterator value = value_indices_Y.begin(); value != value_indices_Y.end(); ++value) + { + dec_values_Y.push_back(unordered_values_Y[value->second]); + } +} + + +void extract_DecisionValuesFromModel(const z3::model &Model, + const string_map &dec_var_names_map, + std::vector &dec_values_X, + std::vector &dec_values_Y) +{ + for (unsigned int i = 0; i < Model.size(); ++i) + { + z3::expr value = Model.get_const_interp(Model[i]); + + #ifdef DEBUG + { + printf("extracted: %.3f (%s)\n", value.as_double(), Model[i].name().str().c_str()); + } + #endif + + switch (Model[i].name().str()[0]) + { + case 'X': + { + string_map::const_iterator var_item = dec_var_names_map.find(Model[i].name().str()); + if (var_item != dec_var_names_map.end()) + { + #ifdef DEBUG + { + printf("saving X: %d <-- %.3f, %ld, %ld\n", var_item->second, value.as_double(), value.numerator().as_int64(), value.denominator().as_int64()); + } + #endif + //dec_values_X[var_item->second] = Rational(value.numerator().as_int64(), value.denominator().as_int64()); + dec_values_X[var_item->second] = Rational(value); + //dec_values_X[var_item->second] = value; + } + break; + } + case 'Y': + { + string_map::const_iterator var_item = dec_var_names_map.find(Model[i].name().str()); + if (var_item != dec_var_names_map.end()) + { + #ifdef DEBUG + { + printf("saving Y: %d <-- %.3f, %ld, %ld\n", var_item->second, value.as_double(), value.numerator().as_int64(), value.denominator().as_int64()); + } + #endif + //printf("saving: %d <-- %.3f\n", var_item->second, value.as_double()); + //dec_values_Y[var_item->second] = Rational(value.numerator().as_int64(), value.denominator().as_int64()); + dec_values_Y[var_item->second] = Rational(value); + } + break; + } + default: + { + break; + } + } + } +} + + +void extract_DecisionValuesFromModel(const z3::model &Model, + const string_map &dec_var_names_map, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T) +{ + for (unsigned int i = 0; i < Model.size(); ++i) + { + z3::expr value = Model.get_const_interp(Model[i]); + #ifdef DEBUG + { + printf("extracted: %.3f (%s)\n", value.as_double(), Model[i].name().str().c_str()); + } + #endif + + switch (Model[i].name().str()[0]) + { + case 'X': + { + string_map::const_iterator var_item = dec_var_names_map.find(Model[i].name().str()); + if (var_item != dec_var_names_map.end()) + { + #ifdef DEBUG + { + printf("saving X: %d <-- %.3f, %ld, %ld\n", var_item->second, value.as_double(), value.numerator().as_int64(), value.denominator().as_int64()); + } + #endif + //dec_values_X[var_item->second] = Rational(value.numerator().as_int64(), value.denominator().as_int64()); + dec_values_X[var_item->second] = Rational(value); + //dec_values_X[var_item->second] = value; + } + break; + } + case 'Y': + { + string_map::const_iterator var_item = dec_var_names_map.find(Model[i].name().str()); + if (var_item != dec_var_names_map.end()) + { + #ifdef DEBUG + { + printf("saving Y: %d <-- %.3f, %ld, %ld\n", var_item->second, value.as_double(), value.numerator().as_int64(), value.denominator().as_int64()); + } + #endif + //printf("saving: %d <-- %.3f\n", var_item->second, value.as_double()); + //dec_values_Y[var_item->second] = Rational(value.numerator().as_int64(), value.denominator().as_int64()); + dec_values_Y[var_item->second] = Rational(value); + } + break; + } + case 'T': + { + string_map::const_iterator var_item = dec_var_names_map.find(Model[i].name().str()); + if (var_item != dec_var_names_map.end()) + { + #ifdef DEBUG + { + printf("saving T: %d <-- %.3f, %ld, %ld\n", var_item->second, value.as_double(), value.numerator().as_int64(), value.denominator().as_int64()); + } + #endif + //printf("saving: %d <-- %.3f\n", var_item->second, value.as_double()); + //dec_values_T[var_item->second] = Rational(value.numerator().as_int64(), value.denominator().as_int64()); + dec_values_T[var_item->second] = Rational(value); + } + break; + } + default: + { + break; + } + } + } +} + + +void build_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + string_map &dec_var_names_map) +{ + for (unsigned int i = 0; i < polygons.size(); ++i) + { + string name = "X_pos-" + to_string(i); + + dec_vars_X.push_back(z3::expr(Context.real_const(name.c_str()))); + dec_var_names_map[name] = i; + } + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + string name = "Y_pos-" + to_string(i); + + dec_vars_Y.push_back(z3::expr(Context.real_const(name.c_str()))); + dec_var_names_map[name] = i; + } + + dec_values_X.resize(polygons.size(), 0.0); + dec_values_Y.resize(polygons.size(), 0.0); + + introduce_PolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + polygons); +} + + +void build_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_values_X, + z3::expr_vector &dec_values_Y, + string_map &dec_var_names_map) +{ + for (unsigned int i = 0; i < polygons.size(); ++i) + { + string name = "X_pos-" + to_string(i); + + dec_vars_X.push_back(z3::expr(Context.real_const(name.c_str()))); + dec_var_names_map[name] = i; + } + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + string name = "Y_pos-" + to_string(i); + + dec_vars_Y.push_back(z3::expr(Context.real_const(name.c_str()))); + dec_var_names_map[name] = i; + } + + dec_values_X.resize(polygons.size()); + dec_values_Y.resize(polygons.size()); + + introduce_PolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + polygons); +} + + +void build_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + string_map &dec_var_names_map) +{ + for (unsigned int i = 0; i < polygons.size(); ++i) + { + string name = "X_pos-" + to_string(i); + + dec_vars_X.push_back(z3::expr(Context.real_const(name.c_str()))); + dec_var_names_map[name] = i; + } + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + string name = "Y_pos-" + to_string(i); + + dec_vars_Y.push_back(z3::expr(Context.real_const(name.c_str()))); + dec_var_names_map[name] = i; + } + + introduce_PolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_values_X, + dec_values_Y, + fixed, + undecided, + polygons); +} + + +void build_SequentialWeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + const std::vector &unreachable_polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + string_map &dec_var_names_map) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + build_SequentialWeakPolygonNonoverlapping(Solver, + Context, + polygons, + _unreachable_polygons, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + dec_values_X, + dec_values_Y, + dec_values_T, + fixed, + undecided, + dec_var_names_map); +} + +void build_SequentialWeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + string_map &dec_var_names_map) +{ + for (unsigned int i = 0; i < polygons.size(); ++i) + { + string name = "X_pos-" + to_string(i); + + dec_vars_X.push_back(z3::expr(Context.real_const(name.c_str()))); + dec_var_names_map[name] = i; + } + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + string name = "Y_pos-" + to_string(i); + + dec_vars_Y.push_back(z3::expr(Context.real_const(name.c_str()))); + dec_var_names_map[name] = i; + } + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + string name = "T_time-" + to_string(i); + + dec_vars_T.push_back(z3::expr(Context.real_const(name.c_str()))); + dec_var_names_map[name] = i; + } + + introduce_SequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + dec_values_X, + dec_values_Y, + dec_values_T, + fixed, + undecided, + polygons, + unreachable_polygons); +} + + +void build_ConsequentialWeakPolygonNonoverlapping(const SolverConfiguration &solver_configuration, + z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + const std::vector &unreachable_polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + string_map &dec_var_names_map) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + build_ConsequentialWeakPolygonNonoverlapping(solver_configuration, + Solver, + Context, + polygons, + _unreachable_polygons, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + dec_values_X, + dec_values_Y, + dec_values_T, + fixed, + undecided, + dec_var_names_map); +} + + +void build_ConsequentialWeakPolygonNonoverlapping(const SolverConfiguration &solver_configuration, + z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + string_map &dec_var_names_map) +{ + for (unsigned int i = 0; i < polygons.size(); ++i) + { + string name = "X_pos-" + to_string(i); + + dec_vars_X.push_back(z3::expr(Context.real_const(name.c_str()))); + dec_var_names_map[name] = i; + } + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + string name = "Y_pos-" + to_string(i); + + dec_vars_Y.push_back(z3::expr(Context.real_const(name.c_str()))); + dec_var_names_map[name] = i; + } + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + string name = "T_time-" + to_string(i); + + dec_vars_T.push_back(z3::expr(Context.real_const(name.c_str()))); + dec_var_names_map[name] = i; + } + + introduce_ConsequentialPolygonWeakNonoverlapping(solver_configuration, + Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + dec_values_X, + dec_values_Y, + dec_values_T, + fixed, + undecided, + polygons, + unreachable_polygons); +} + + +bool optimize_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const string_map &dec_var_names_map, + const std::vector &polygons) +{ + + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + + int last_solvable_bounding_box_size = -1; + + // general plate polygons are currently not supported + assert(solver_configuration.plate_bounding_polygon.points.size() == 0); + + int maximum_bounding_box_size = MAX(solver_configuration.plate_bounding_box.max.x() - solver_configuration.plate_bounding_box.min.x(), + solver_configuration.plate_bounding_box.max.y() - solver_configuration.plate_bounding_box.min.y()); + + for (int bounding_box_size = maximum_bounding_box_size; bounding_box_size > solver_configuration.minimum_bounding_box_size; + bounding_box_size -= solver_configuration.bounding_box_size_optimization_step) + { + #ifdef DEBUG + { + printf("BB: %d\n", bounding_box_size); + } + #endif + z3::expr_vector bounding_box_assumptions(Context); + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + assume_BedBoundingBox(dec_vars_X[i], dec_vars_Y[i], polygons[i], bounding_box_size, bounding_box_size, bounding_box_assumptions); + } + + bool sat = false; + + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + sat = true; + break; + } + case z3::unsat: + { + sat = false; + break; + } + case z3::unknown: + { + sat = false; + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + dec_values_X, + dec_values_Y); + + while (true) + { + bool refined = refine_PolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_values_X, + dec_values_Y, + polygons); + + bool refined_sat = false; + + if (refined) + { + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + refined_sat = true; + break; + } + case z3::unsat: + { + refined_sat = false; + break; + } + case z3::unknown: + { + refined_sat = false; + break; + } + default: + { + break; + } + } + + if (refined_sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + dec_values_X, + dec_values_Y); + + #ifdef DEBUG + { + printf("Refined positions:\n"); + for (unsigned int i = 0; i < polygons.size(); ++i) + { + printf(" %.3f, %.3f\n", dec_values_X[i], dec_values_Y[i]); + } + } + #endif + } + else + { + break; + } + } + else + { + last_solvable_bounding_box_size = bounding_box_size; + break; + } + } + } + else + { + break; + } + } + if (last_solvable_bounding_box_size > 0) + { + return true; + } + + return false; +} + + +bool optimize_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_values_X, + z3::expr_vector &dec_values_Y, + const string_map &dec_var_names_map, + const std::vector &polygons) +{ + Z3_global_param_set("timeout", solver_configuration.optimization_timeout.c_str()); + int last_solvable_bounding_box_size = -1; + + // general plate polygons are currently not supported + assert(solver_configuration.plate_bounding_polygon.points.size() == 0); + + int maximum_bounding_box_size = MAX(solver_configuration.plate_bounding_box.max.x() - solver_configuration.plate_bounding_box.min.x(), + solver_configuration.plate_bounding_box.max.y() - solver_configuration.plate_bounding_box.min.y()); + + for (int bounding_box_size = maximum_bounding_box_size; bounding_box_size > solver_configuration.minimum_bounding_box_size; + bounding_box_size -= solver_configuration.bounding_box_size_optimization_step) + { + #ifdef DEBUG + { + printf("BB: %d\n", bounding_box_size); + } + #endif + z3::expr_vector bounding_box_assumptions(Context); + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + assume_BedBoundingBox(dec_vars_X[i], dec_vars_Y[i], polygons[i], bounding_box_size, bounding_box_size, bounding_box_assumptions); + } + + bool sat = false; + + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + sat = true; + break; + } + case z3::unsat: + { + sat = false; + break; + } + case z3::unknown: + { + sat = false; + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + Context, + dec_var_names_map, + dec_values_X, + dec_values_Y); + + while (true) + { + bool refined = refine_PolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_values_X, + dec_values_Y, + polygons); + + bool refined_sat = false; + + if (refined) + { + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + refined_sat = true; + break; + } + case z3::unsat: + { + refined_sat = false; + break; + } + case z3::unknown: + { + refined_sat = false; + break; + } + default: + { + break; + } + } + + if (refined_sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + Context, + dec_var_names_map, + dec_values_X, + dec_values_Y); + + #ifdef DEBUG + { + printf("Refined positions:\n"); + for (unsigned int i = 0; i < polygons.size(); ++i) + { + printf(" %.3f, %.3f\n", dec_values_X[i].as_double(), dec_values_Y[i].as_double()); + } + } + #endif + } + else + { + break; + } + } + else + { + last_solvable_bounding_box_size = bounding_box_size; + break; + } + } + } + else + { + break; + } + } + if (last_solvable_bounding_box_size > 0) + { + return true; + } + + return false; +} + + +bool optimize_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const string_map &dec_var_names_map, + const std::vector &polygons) +{ + + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + int last_solvable_bounding_box_size = -1; + + // general plate polygons are currently not supported + assert(solver_configuration.plate_bounding_polygon.points.size() == 0); + + int maximum_bounding_box_size = MAX(solver_configuration.plate_bounding_box.max.x() - solver_configuration.plate_bounding_box.min.x(), + solver_configuration.plate_bounding_box.max.y() - solver_configuration.plate_bounding_box.min.y()); + + for (int bounding_box_size = maximum_bounding_box_size; bounding_box_size > solver_configuration.minimum_bounding_box_size; + bounding_box_size -= solver_configuration.bounding_box_size_optimization_step) + { + #ifdef DEBUG + { + printf("BB: %d\n", bounding_box_size); + } + #endif + z3::expr_vector bounding_box_assumptions(Context); + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + assume_BedBoundingBox(dec_vars_X[i], dec_vars_Y[i], polygons[i], bounding_box_size, bounding_box_size, bounding_box_assumptions); + } + + bool sat = false; + + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + sat = true; + break; + } + case z3::unsat: + { + sat = false; + break; + } + case z3::unknown: + { + sat = false; + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + dec_values_X, + dec_values_Y); + + while (true) + { + bool refined = refine_PolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_values_X, + dec_values_Y, + polygons); + + bool refined_sat = false; + + if (refined) + { + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + refined_sat = true; + break; + } + case z3::unsat: + { + refined_sat = false; + break; + } + case z3::unknown: + { + refined_sat = false; + break; + } + default: + { + break; + } + } + + if (refined_sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + dec_values_X, + dec_values_Y); + + #ifdef DEBUG + { + printf("Refined positions:\n"); + for (unsigned int i = 0; i < polygons.size(); ++i) + { + printf(" %ld/%ld, %ld/%ld\n", dec_values_X[i].numerator, dec_values_X[i].denominator, dec_values_Y[i].numerator, dec_values_Y[i].denominator); + } + } + #endif + } + else + { + break; + } + } + else + { + last_solvable_bounding_box_size = bounding_box_size; + break; + } + } + } + else + { + break; + } + } + if (last_solvable_bounding_box_size > 0) + { + return true; + } + + return false; +} + + +/*----------------------------------------------------------------*/ + +bool optimize_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_values_X, + z3::expr_vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons) +{ + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + int last_solvable_bounding_box_size = -1; + + // general plate polygons are currently not supported + assert(solver_configuration.plate_bounding_polygon.points.size() == 0); + + int maximum_bounding_box_size = MAX(solver_configuration.plate_bounding_box.max.x() - solver_configuration.plate_bounding_box.min.x(), + solver_configuration.plate_bounding_box.max.y() - solver_configuration.plate_bounding_box.min.y()); + + for (int bounding_box_size = maximum_bounding_box_size; bounding_box_size > solver_configuration.minimum_bounding_box_size; + bounding_box_size -= solver_configuration.bounding_box_size_optimization_step) + { + #ifdef DEBUG + { + printf("BB: %d\n", bounding_box_size); + } + #endif + + z3::expr_vector bounding_box_assumptions(Context); + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + assume_BedBoundingBox(dec_vars_X[undecided[i]], dec_vars_Y[undecided[i]], polygons[undecided[i]], bounding_box_size, bounding_box_size, bounding_box_assumptions); + } + + bool sat = false; + + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + sat = true; + break; + } + case z3::unsat: + { + sat = false; + break; + } + case z3::unknown: + { + sat = false; + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + Context, + dec_var_names_map, + dec_values_X, + dec_values_Y); + + while (true) + { + bool refined = refine_PolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_values_X, + dec_values_Y, + fixed, + undecided, + polygons); + + bool refined_sat = false; + + if (refined) + { + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + refined_sat = true; + break; + } + case z3::unsat: + { + refined_sat = false; + break; + } + case z3::unknown: + { + refined_sat = false; + break; + } + default: + { + break; + } + } + + if (refined_sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + Context, + dec_var_names_map, + dec_values_X, + dec_values_Y); + + #ifdef DEBUG + { + printf("Refined positions:\n"); + for (unsigned int i = 0; i < undecided.size(); ++i) + { + printf(" %.3f, %.3f\n", dec_values_X[undecided[i]].as_double(), dec_values_Y[undecided[i]].as_double()); + } + } + #endif + } + else + { + break; + } + } + else + { + last_solvable_bounding_box_size = bounding_box_size; + break; + } + } + } + else + { + break; + } + } + if (last_solvable_bounding_box_size > 0) + { + return true; + } + + return false; +} + + +bool optimize_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons) +{ + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + int last_solvable_bounding_box_size = -1; + + std::vector local_dec_values_X = dec_values_X; + std::vector local_dec_values_Y = dec_values_Y; + + // general plate polygons are currently not supported + assert(solver_configuration.plate_bounding_polygon.points.size() == 0); + + int maximum_bounding_box_size = MAX(solver_configuration.plate_bounding_box.max.x() - solver_configuration.plate_bounding_box.min.x(), + solver_configuration.plate_bounding_box.max.y() - solver_configuration.plate_bounding_box.min.y()); + + for (int bounding_box_size = maximum_bounding_box_size; bounding_box_size > solver_configuration.minimum_bounding_box_size; + bounding_box_size -= solver_configuration.bounding_box_size_optimization_step) + { + #ifdef DEBUG + { + printf("BBX: %d\n", bounding_box_size); + } + #endif + + z3::expr_vector bounding_box_assumptions(Context); + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + assume_BedBoundingBox(dec_vars_X[undecided[i]], dec_vars_Y[undecided[i]], polygons[undecided[i]], bounding_box_size, bounding_box_size, bounding_box_assumptions); + } + + bool sat = false; + + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + sat = true; + break; + } + case z3::unsat: + { + sat = false; + break; + } + case z3::unknown: + { + sat = false; + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y); + + while (true) + { + bool refined = refine_PolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + local_dec_values_X, + local_dec_values_Y, + fixed, + undecided, + polygons); + + + if (refined) + { + bool refined_sat = false; + + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + refined_sat = true; + break; + } + case z3::unsat: + { + refined_sat = false; + break; + } + case z3::unknown: + { + refined_sat = false; + break; + } + default: + { + break; + } + } + + if (refined_sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y); + + #ifdef DEBUG + { + printf("Refined positions:\n"); + for (unsigned int i = 0; i < undecided.size(); ++i) + { + printf(" %ld/%ld, %ld/%ld\n", + local_dec_values_X[undecided[i]].numerator, + local_dec_values_X[undecided[i]].denominator, + local_dec_values_Y[undecided[i]].numerator, + local_dec_values_Y[undecided[i]].denominator); + } + } + #endif + } + else + { + break; + } + } + else + { + last_solvable_bounding_box_size = bounding_box_size; + + dec_values_X = local_dec_values_X; + dec_values_Y = local_dec_values_Y; + break; + } + } + } + else + { + break; + } + } + if (last_solvable_bounding_box_size > 0) + { + return true; + } + + return false; +} + + + +bool optimize_SequentialWeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector &unreachable_polygons) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + return optimize_SequentialWeakPolygonNonoverlapping(Solver, + Context, + solver_configuration, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + dec_values_X, + dec_values_Y, + dec_values_T, + fixed, + undecided, + dec_var_names_map, + polygons, + _unreachable_polygons); +} + + +bool optimize_SequentialWeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + + int last_solvable_bounding_box_size = -1; + + std::vector local_dec_values_X = dec_values_X; + std::vector local_dec_values_Y = dec_values_Y; + std::vector local_dec_values_T = dec_values_T; + + // general plate polygons are currently not supported + assert(solver_configuration.plate_bounding_polygon.points.size() == 0); + + int maximum_bounding_box_size = MAX(solver_configuration.plate_bounding_box.max.x() - solver_configuration.plate_bounding_box.min.x(), + solver_configuration.plate_bounding_box.max.y() - solver_configuration.plate_bounding_box.min.y()); + + for (int bounding_box_size = maximum_bounding_box_size; bounding_box_size > solver_configuration.minimum_bounding_box_size; + bounding_box_size -= solver_configuration.bounding_box_size_optimization_step) + { + #ifdef DEBUG + { + printf("BBX: %d\n", bounding_box_size); + } + #endif + + z3::expr_vector bounding_box_assumptions(Context); + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + assume_BedBoundingBox(dec_vars_X[undecided[i]], dec_vars_Y[undecided[i]], polygons[undecided[i]], bounding_box_size, bounding_box_size, bounding_box_assumptions); + } + + bool sat = false; + + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + sat = true; + break; + } + case z3::unsat: + { + sat = false; + break; + } + case z3::unknown: + { + sat = false; + break; + } + default: + { + break; + } + } + + if (sat) + { + #ifdef DEBUG + { + printf("First SAT\n"); + } + #endif + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T); + + while (true) + { + bool refined = refine_SequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T, + fixed, + undecided, + polygons, + unreachable_polygons); + + + if (refined) + { + bool refined_sat = false; + + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + refined_sat = true; + break; + } + case z3::unsat: + { + refined_sat = false; + break; + } + case z3::unknown: + { + refined_sat = false; + break; + } + default: + { + break; + } + } + + if (refined_sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T); + + #ifdef DEBUG + { + printf("Refined positions:\n"); + for (unsigned int i = 0; i < undecided.size(); ++i) + { + printf(" i:%d, undecided[i]:%d: %ld/%ld (%.3f), %ld/%ld (%.3f) [%ld/%ld (%.3f)]\n", + i, undecided[i], + local_dec_values_X[undecided[i]].numerator, + local_dec_values_X[undecided[i]].denominator, + local_dec_values_X[undecided[i]].as_double(), + local_dec_values_Y[undecided[i]].numerator, + local_dec_values_Y[undecided[i]].denominator, + local_dec_values_Y[undecided[i]].as_double(), + local_dec_values_T[undecided[i]].numerator, + local_dec_values_T[undecided[i]].denominator, + local_dec_values_T[undecided[i]].as_double()); + } + } + #endif + } + else + { + if (last_solvable_bounding_box_size > 0) + { + return true; + } + else + { + return false; + } + } + } + else + { + last_solvable_bounding_box_size = bounding_box_size; + + dec_values_X = local_dec_values_X; + dec_values_Y = local_dec_values_Y; + dec_values_T = local_dec_values_T; + break; + } + } + } + else + { + #ifdef DEBUG + { + printf("First UNSAT\n"); + } + #endif + if (last_solvable_bounding_box_size > 0) + { + return true; + } + else + { + return false; + } + } + } + return false; +} + + +bool optimize_SequentialWeakPolygonNonoverlappingCentered(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + + int last_solvable_bounding_box_size = -1; + + std::vector local_dec_values_X = dec_values_X; + std::vector local_dec_values_Y = dec_values_Y; + std::vector local_dec_values_T = dec_values_T; + + int box_min_x = solver_configuration.plate_bounding_box.min.x(); + int box_max_x = solver_configuration.plate_bounding_box.max.x(); + int box_min_y = solver_configuration.plate_bounding_box.min.y(); + int box_max_y = solver_configuration.plate_bounding_box.max.y(); + + while (box_min_x < box_max_x && box_min_y < box_max_y) + { + #ifdef DEBUG + { + printf("BBX: %d, %d, %d, %d\n", box_min_x, box_max_x, box_min_y, box_max_y); + } + #endif + + z3::expr_vector bounding_box_assumptions(Context); + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + assume_BedBoundingBox(dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + polygons[undecided[i]], + box_min_x, + box_min_y, + box_max_x, + box_max_y, + bounding_box_assumptions); + } + + bool sat = false; + + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + sat = true; + break; + } + case z3::unsat: + { + sat = false; + break; + } + case z3::unknown: + { + sat = false; + break; + } + default: + { + break; + } + } + + if (sat) + { + #ifdef DEBUG + { + printf("First SAT\n"); + } + #endif + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T); + + while (true) + { + bool refined = refine_SequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T, + fixed, + undecided, + polygons, + unreachable_polygons); + + + if (refined) + { + bool refined_sat = false; + + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + refined_sat = true; + break; + } + case z3::unsat: + { + refined_sat = false; + break; + } + case z3::unknown: + { + refined_sat = false; + break; + } + default: + { + break; + } + } + + if (refined_sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T); + + #ifdef DEBUG + { + printf("Refined positions:\n"); + for (unsigned int i = 0; i < undecided.size(); ++i) + { + printf(" i:%d, undecided[i]:%d: %ld/%ld (%.3f), %ld/%ld (%.3f) [%ld/%ld (%.3f)]\n", + i, undecided[i], + local_dec_values_X[undecided[i]].numerator, + local_dec_values_X[undecided[i]].denominator, + local_dec_values_X[undecided[i]].as_double(), + local_dec_values_Y[undecided[i]].numerator, + local_dec_values_Y[undecided[i]].denominator, + local_dec_values_Y[undecided[i]].as_double(), + local_dec_values_T[undecided[i]].numerator, + local_dec_values_T[undecided[i]].denominator, + local_dec_values_T[undecided[i]].as_double()); + } + } + #endif + } + else + { + if (last_solvable_bounding_box_size > 0) + { + return true; + } + else + { + return false; + } + } + } + else + { + last_solvable_bounding_box_size = box_max_x; + + dec_values_X = local_dec_values_X; + dec_values_Y = local_dec_values_Y; + dec_values_T = local_dec_values_T; + break; + } + } + } + else + { + #ifdef DEBUG + { + printf("First UNSAT\n"); + } + #endif + if (last_solvable_bounding_box_size > 0) + { + return true; + } + else + { + return false; + } + } + + + box_min_x += solver_configuration.bounding_box_size_optimization_step; + box_max_x -= solver_configuration.bounding_box_size_optimization_step; + + box_min_y += solver_configuration.bounding_box_size_optimization_step; + box_max_y -= solver_configuration.bounding_box_size_optimization_step; + + if (box_min_x >= box_max_x || box_min_y >= box_max_y) + { + break; + } + } + return false; +} + + +bool checkArea_SequentialWeakPolygonNonoverlapping(coord_t box_min_x, + coord_t box_min_y, + coord_t box_max_x, + coord_t box_max_y, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &SEQ_UNUSED(unreachable_polygons)) +{ + assert(box_max_x >= box_min_x && box_max_y >= box_min_y); + + double check_area = (box_max_x - box_min_x) * (box_max_y - box_min_y); + double polygon_area = calc_PolygonArea(fixed, undecided, polygons); + + #ifdef DEBUG + { + printf("Fast checkging for box: %d, %d, %d, %d\n", box_min_x, box_min_y, box_max_x, box_max_y); + printf("Check area: %.3f\n", check_area); + printf("Polygon area: %.3f\n", polygon_area); + } + #endif + + if (polygon_area - check_area > EPSILON) + { + return false; + } + + return true; +} + + +bool checkArea_SequentialWeakPolygonNonoverlapping(const Slic3r::Polygon &bounding_polygon, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + double polygon_area = calc_PolygonArea(fixed, undecided, polygons); + + #ifdef DEBUG + { + printf("Check area: %.3f\n", bounding_polygon.area()); + printf("Polygon area: %.3f\n", polygon_area); + } + #endif + + if (polygon_area - bounding_polygon.area() > EPSILON) + { + return false; + } + + return true; +} + + + +bool checkExtens_SequentialWeakPolygonNonoverlapping(coord_t box_min_x, + coord_t box_min_y, + coord_t box_max_x, + coord_t box_max_y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &SEQ_UNUSED(unreachable_polygons)) +{ + double min_X, max_X, min_Y, max_Y; + + if (!fixed.empty()) + { + BoundingBox polygon_box = get_extents(polygons[fixed[0]]); + + min_X = dec_values_X[fixed[0]].as_double() + polygon_box.min.x(); + min_Y = dec_values_Y[fixed[0]].as_double() + polygon_box.min.y(); + + max_X = dec_values_X[fixed[0]].as_double() + polygon_box.max.x(); + max_Y = dec_values_Y[fixed[0]].as_double() + polygon_box.max.y(); + + for (unsigned int i = 1; i < fixed.size(); ++i) + { + BoundingBox polygon_box = get_extents(polygons[fixed[i]]); + + double next_min_X = dec_values_X[fixed[i]].as_double() + polygon_box.min.x(); + + if (next_min_X < min_X) + { + min_X = next_min_X; + } + double next_min_Y = dec_values_Y[fixed[i]].as_double() + polygon_box.min.y(); + + if (next_min_Y < min_Y) + { + min_Y = next_min_Y; + } + + double next_max_X = dec_values_X[fixed[i]].as_double() + polygon_box.max.x(); + + if (next_max_X > max_X) + { + max_X = next_max_X; + } + double next_max_Y = dec_values_Y[fixed[i]].as_double() + polygon_box.max.y(); + + if (next_max_Y > max_Y) + { + max_Y = next_max_Y; + } + } + + #ifdef DEBUG + { + printf("Box:%d,%d,%d,%d\n", box_min_x, box_max_x, box_min_y, box_max_y); + printf("Fix:%.3f,%.3f,%.3f,%.3f\n", min_X, max_X, min_Y, max_Y); + } + #endif + + if (min_X < box_min_x || max_X > box_max_x || min_Y < box_min_y || max_Y > box_max_y) + { + return false; + } + } + return true; +} + + +bool optimize_SequentialWeakPolygonNonoverlappingBinaryCentered(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + coord_t &box_half_x_min, + coord_t &box_half_y_min, + coord_t &box_half_x_max, + coord_t &box_half_y_max, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector > &unreachable_polygons) +{ + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + + coord_t last_solvable_bounding_box_size = -1; + + std::vector local_dec_values_X = dec_values_X; + std::vector local_dec_values_Y = dec_values_Y; + std::vector local_dec_values_T = dec_values_T; + + coord_t half_x_min = box_half_x_min; + coord_t half_x_max = box_half_x_max; + + coord_t half_y_min = box_half_y_min;; + coord_t half_y_max = box_half_y_max; + + while (ABS(half_x_max - half_x_min) > 1 && ABS(half_y_max - half_y_min) > 1) + { + #ifdef DEBUG + { + printf("Halves: %d, %d, %d, %d\n", half_x_min, half_x_max, half_y_min, half_y_max); + } + #endif + + bool size_solvable = false; + + z3::expr_vector bounding_box_assumptions(Context); + + coord_t box_min_x = (half_x_max + half_x_min) / 2; + coord_t box_max_x = solver_configuration.plate_bounding_box.max.x() - box_min_x; + coord_t box_min_y = (half_y_max + half_y_min) / 2; + coord_t box_max_y = solver_configuration.plate_bounding_box.max.y() - box_min_y; + + #ifdef DEBUG + { + printf("BBX: %d, %d, %d, %d\n", box_min_x, box_max_x, box_min_y, box_max_y); + } + #endif + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + assume_BedBoundingBox(dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + polygons[undecided[i]], + box_min_x, + box_min_y, + box_max_x, + box_max_y, + bounding_box_assumptions); + } + + bool sat = false; + + if (checkArea_SequentialWeakPolygonNonoverlapping(box_min_x, + box_min_y, + box_max_x, + box_max_y, + fixed, + undecided, + polygons, + unreachable_polygons)) + { + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + sat = true; + break; + } + case z3::unsat: + { + sat = false; + break; + } + case z3::unknown: + { + sat = false; + break; + } + default: + { + break; + } + } + } + else + { + sat = false; + } + + if (sat) + { + #ifdef DEBUG + { + printf("First SAT\n"); + } + #endif + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T); + + while (true) + { + bool refined = refine_SequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T, + fixed, + undecided, + polygons, + unreachable_polygons); + + if (refined) + { + bool refined_sat = false; + + if (checkArea_SequentialWeakPolygonNonoverlapping(box_min_x, + box_min_y, + box_max_x, + box_max_y, + fixed, + undecided, + polygons, + unreachable_polygons)) + { + switch (Solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + refined_sat = true; + break; + } + case z3::unsat: + { + refined_sat = false; + break; + } + case z3::unknown: + { + refined_sat = false; + break; + } + default: + { + break; + } + } + } + else + { + refined_sat = false; + } + + if (refined_sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T); + + #ifdef DEBUG + { + printf("Refined positions:\n"); + for (unsigned int i = 0; i < undecided.size(); ++i) + { + printf(" i:%d, undecided[i]:%d: %ld/%ld (%.3f), %ld/%ld (%.3f) [%ld/%ld (%.3f)]\n", + i, undecided[i], + local_dec_values_X[undecided[i]].numerator, + local_dec_values_X[undecided[i]].denominator, + local_dec_values_X[undecided[i]].as_double(), + local_dec_values_Y[undecided[i]].numerator, + local_dec_values_Y[undecided[i]].denominator, + local_dec_values_Y[undecided[i]].as_double(), + local_dec_values_T[undecided[i]].numerator, + local_dec_values_T[undecided[i]].denominator, + local_dec_values_T[undecided[i]].as_double()); + } + } + #endif + } + else + { + size_solvable = false; + break; + } + } + else + { + last_solvable_bounding_box_size = box_max_x; + + dec_values_X = local_dec_values_X; + dec_values_Y = local_dec_values_Y; + dec_values_T = local_dec_values_T; + + size_solvable = true; + break; + } + } + } + else + { + #ifdef DEBUG + { + printf("First UNSAT\n"); + } + #endif + + if (last_solvable_bounding_box_size > 0) + { + size_solvable = false; + } + else + { + size_solvable = false; + } + } + + coord_t half_x_med = (half_x_max + half_x_min) / 2; + coord_t half_y_med = (half_y_max + half_y_min) / 2; + + if (size_solvable) + { + #ifdef DEBUG + { + printf("Solvable\n"); + } + #endif + half_x_min = half_x_med; + half_y_min = half_y_med; + } + else + { + #ifdef DEBUG + { + printf("Unsolvable\n"); + } + #endif + half_x_max = half_x_med; + half_y_max = half_y_med; + } + #ifdef DEBUG + { + printf("Halves augmented: X:[%d,%d] Y:[%d,%d]\n", half_x_min, half_x_max, half_y_min, half_y_max); + } + #endif + } + + if (last_solvable_bounding_box_size > 0) + { + box_half_x_max = half_x_max; + box_half_y_max = half_y_max; + + return true; + } + return false; +} + + +bool optimize_ConsequentialWeakPolygonNonoverlappingBinaryCentered(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + coord_t &box_half_x_min, + coord_t &box_half_y_min, + coord_t &box_half_x_max, + coord_t &box_half_y_max, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const z3::expr_vector &presence_constraints, + const ProgressRange &progress_range, + std::function progress_callback) +{ + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + + #ifdef DEBUG + { + printf("Progress range: %d -- %d\n", progress_range.progress_min, progress_range.progress_max); + } + #endif + + coord_t last_solvable_bounding_box_size = -1; + + std::vector local_dec_values_X = dec_values_X; + std::vector local_dec_values_Y = dec_values_Y; + std::vector local_dec_values_T = dec_values_T; + + coord_t half_x_min = box_half_x_min; + coord_t half_x_max = box_half_x_max; + + coord_t half_y_min = box_half_y_min; + coord_t half_y_max = box_half_y_max; + + int progress_total_estimation = MAX(1, std::log2(ABS(half_x_max - half_x_min))); + int progress = 0; + + while (ABS(half_x_max - half_x_min) > 1 && ABS(half_y_max - half_y_min) > 1) + { + #ifdef DEBUG + { + printf("Halves: %d, %d, %d, %d\n", half_x_min, half_x_max, half_y_min, half_y_max); + } + #endif + + bool size_solvable = false; + + z3::expr_vector bounding_box_assumptions(Context); + + coord_t box_x_size = half_x_max - half_x_min; + coord_t box_y_size = half_y_max - half_y_min; + + coord_t box_min_x = solver_configuration.plate_bounding_box.min.x() + box_x_size / 2; + coord_t box_max_x = solver_configuration.plate_bounding_box.max.x() - box_x_size / 2; + + coord_t box_min_y = solver_configuration.plate_bounding_box.min.y() + box_y_size / 2; + coord_t box_max_y = solver_configuration.plate_bounding_box.max.y() - box_y_size / 2; + + /* + coord_t box_min_x = (half_x_max + half_x_min) / 2; + coord_t box_max_x = solver_configuration.plate_bounding_box.max.x() - box_min_x; + coord_t box_min_y = (half_y_max + half_y_min) / 2; + coord_t box_max_y = solver_configuration.plate_bounding_box.max.y() - box_min_y; + */ + + #ifdef DEBUG + { + printf("BBX: %d, %d, %d, %d\n", box_min_x, box_max_x, box_min_y, box_max_y); + } + #endif + + z3::expr_vector complete_assumptions(Context); + + for (unsigned int i = 0; i < presence_constraints.size(); ++i) + { + complete_assumptions.push_back(presence_constraints[i]); + } + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + assume_BedBoundingBox(dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + polygons[undecided[i]], + box_min_x, + box_min_y, + box_max_x, + box_max_y, + complete_assumptions); + } + + bool sat = false; + + if (checkArea_SequentialWeakPolygonNonoverlapping(box_min_x, + box_min_y, + box_max_x, + box_max_y, + fixed, + undecided, + polygons, + unreachable_polygons)) + { + switch (Solver.check(complete_assumptions)) + { + case z3::sat: + { + sat = true; + break; + } + case z3::unsat: + { + sat = false; + break; + } + case z3::unknown: + { + sat = false; + break; + } + default: + { + break; + } + } + } + else + { + sat = false; + } + + if (sat) + { + #ifdef DEBUG + { + printf("First SAT\n"); + } + #endif + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T); + + int total_refines = 0; + + while (true) + { + bool refined = refine_ConsequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T, + fixed, + undecided, + polygons, + unreachable_polygons); + if (refined) + { + ++total_refines; + + bool refined_sat = false; + + if (total_refines < solver_configuration.max_refines) + { + if (checkArea_SequentialWeakPolygonNonoverlapping(box_min_x, + box_min_y, + box_max_x, + box_max_y, + fixed, + undecided, + polygons, + unreachable_polygons)) + { + switch (Solver.check(complete_assumptions)) + { + case z3::sat: + { + refined_sat = true; + break; + } + case z3::unsat: + { + refined_sat = false; + break; + } + case z3::unknown: + { + refined_sat = false; + break; + } + default: + { + break; + } + } + } + else + { + refined_sat = false; + } + } + + progress_callback(progress_range.progress_min + (progress_range.progress_max - progress_range.progress_min) * progress / progress_total_estimation); + + if (refined_sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T); + + #ifdef DEBUG + { + printf("Refined positions:\n"); + for (unsigned int i = 0; i < undecided.size(); ++i) + { + printf(" i:%d, undecided[i]:%d: %ld/%ld (%.3f), %ld/%ld (%.3f) [%ld/%ld (%.3f)]\n", + i, undecided[i], + local_dec_values_X[undecided[i]].numerator, + local_dec_values_X[undecided[i]].denominator, + local_dec_values_X[undecided[i]].as_double(), + local_dec_values_Y[undecided[i]].numerator, + local_dec_values_Y[undecided[i]].denominator, + local_dec_values_Y[undecided[i]].as_double(), + local_dec_values_T[undecided[i]].numerator, + local_dec_values_T[undecided[i]].denominator, + local_dec_values_T[undecided[i]].as_double()); + } + } + #endif + } + else + { + size_solvable = false; + break; + } + } + else + { + last_solvable_bounding_box_size = box_max_x; + + dec_values_X = local_dec_values_X; + dec_values_Y = local_dec_values_Y; + dec_values_T = local_dec_values_T; + + size_solvable = true; + break; + } + } + } + else + { + #ifdef DEBUG + { + printf("First UNSAT\n"); + } + #endif + + size_solvable = false; + } + + coord_t half_x_med = (half_x_max + half_x_min) / 2; + coord_t half_y_med = (half_y_max + half_y_min) / 2; + + if (size_solvable) + { + #ifdef DEBUG + { + printf("Solvable\n"); + } + #endif + half_x_min = half_x_med; + half_y_min = half_y_med; + } + else + { + #ifdef DEBUG + { + printf("Unsolvable\n"); + } + #endif + half_x_max = half_x_med; + half_y_max = half_y_med; + } + #ifdef DEBUG + { + printf("Halves augmented: X:[%d,%d] Y:[%d,%d]\n", half_x_min, half_x_max, half_y_min, half_y_max); + } + #endif + + progress = MIN(progress + 1, progress_total_estimation); + progress_callback(progress_range.progress_min + (progress_range.progress_max - progress_range.progress_min) * progress / progress_total_estimation); + } + progress_callback(progress_range.progress_max); + + if (last_solvable_bounding_box_size > 0) + { + box_half_x_max = half_x_max; + box_half_y_max = half_y_max; + + return true; + } + return false; +} + + +bool optimize_ConsequentialWeakPolygonNonoverlappingBinaryCentered(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + BoundingBox &inner_half_box, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const z3::expr_vector &presence_constraints, + const ProgressRange &progress_range, + std::function progress_callback) +{ + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + + #ifdef DEBUG + { + printf("Progress range: %d -- %d\n", progress_range.progress_min, progress_range.progress_max); + } + #endif + + bool solving_result = false; + + std::vector local_dec_values_X = dec_values_X; + std::vector local_dec_values_Y = dec_values_Y; + std::vector local_dec_values_T = dec_values_T; + + BoundingBox _inner_half_box = inner_half_box; + BoundingBox _outer_half_box = solver_configuration.plate_bounding_box; + + int progress_total_estimation = MAX(1, std::log2(1 + MAX(MAX(ABS(_outer_half_box.min.x() - _inner_half_box.min.x()), ABS(_outer_half_box.max.x() - _inner_half_box.max.x())), + MAX(ABS(_outer_half_box.min.y() - _inner_half_box.min.y()), ABS(_outer_half_box.max.y() - _inner_half_box.max.y()))))); + int progress = 0; + + while ( ABS(_outer_half_box.min.x() - _inner_half_box.min.x()) > 1 + || ABS(_outer_half_box.max.x() - _inner_half_box.max.x()) > 1 + || ABS(_outer_half_box.min.y() - _inner_half_box.min.y()) > 1 + || ABS(_outer_half_box.max.y() - _inner_half_box.max.y()) > 1) + { + + #ifdef DEBUG + { + printf("Diffs: %d,%d,%d,%d\n", ABS(_outer_half_box.min.x() - _inner_half_box.min.x()), + ABS(_outer_half_box.max.x() - _inner_half_box.max.x()), + ABS(_outer_half_box.min.y() - _inner_half_box.min.y()), + ABS(_outer_half_box.max.y() - _inner_half_box.max.y())); + + printf("Inner half box: %d, %d, %d, %d\n", _inner_half_box.min.x(), _inner_half_box.min.y(), _inner_half_box.max.x(), _inner_half_box.max.y()); + printf("Outer half box: %d, %d, %d, %d\n", _outer_half_box.min.x(), _outer_half_box.min.y(), _outer_half_box.max.x(), _outer_half_box.max.y()); + } + #endif + + bool size_solvable = false; + + coord_t box_min_x = (_outer_half_box.min.x() + _inner_half_box.min.x()) / 2; + coord_t box_max_x = (_outer_half_box.max.x() + _inner_half_box.max.x()) / 2; + + coord_t box_min_y = (_outer_half_box.min.y() + _inner_half_box.min.y()) / 2; + coord_t box_max_y = (_outer_half_box.max.y() + _inner_half_box.max.y()) / 2; + + #ifdef DEBUG + { + printf("BBX: %d, %d, %d, %d\n", box_min_x, box_max_x, box_min_y, box_max_y); + } + #endif + + z3::expr_vector complete_assumptions(Context); + + for (unsigned int i = 0; i < presence_constraints.size(); ++i) + { + complete_assumptions.push_back(presence_constraints[i]); + } + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + assume_BedBoundingBox(dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + polygons[undecided[i]], + box_min_x, + box_min_y, + box_max_x, + box_max_y, + complete_assumptions); + } + + bool sat = false; + + if (checkArea_SequentialWeakPolygonNonoverlapping(box_min_x, + box_min_y, + box_max_x, + box_max_y, + fixed, + undecided, + polygons, + unreachable_polygons)) + { + switch (Solver.check(complete_assumptions)) + { + case z3::sat: + { + sat = true; + break; + } + case z3::unsat: + { + sat = false; + break; + } + case z3::unknown: + { + sat = false; + break; + } + default: + { + break; + } + } + } + else + { + sat = false; + } + + if (sat) + { + #ifdef DEBUG + { + printf("First SAT\n"); + } + #endif + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T); + + int total_refines = 0; + + while (true) + { + bool refined = refine_ConsequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T, + fixed, + undecided, + polygons, + unreachable_polygons); + if (refined) + { + ++total_refines; + + bool refined_sat = false; + + if (total_refines < solver_configuration.max_refines) + { + if (checkArea_SequentialWeakPolygonNonoverlapping(box_min_x, + box_min_y, + box_max_x, + box_max_y, + fixed, + undecided, + polygons, + unreachable_polygons)) + { + switch (Solver.check(complete_assumptions)) + { + case z3::sat: + { + refined_sat = true; + break; + } + case z3::unsat: + { + refined_sat = false; + break; + } + case z3::unknown: + { + refined_sat = false; + break; + } + default: + { + break; + } + } + } + else + { + refined_sat = false; + } + } + + progress_callback(progress_range.progress_min + (progress_range.progress_max - progress_range.progress_min) * progress / progress_total_estimation); + + if (refined_sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T); + + #ifdef DEBUG + { + printf("Refined positions:\n"); + for (unsigned int i = 0; i < undecided.size(); ++i) + { + printf(" i:%d, undecided[i]:%d: %ld/%ld (%.3f), %ld/%ld (%.3f) [%ld/%ld (%.3f)]\n", + i, undecided[i], + local_dec_values_X[undecided[i]].numerator, + local_dec_values_X[undecided[i]].denominator, + local_dec_values_X[undecided[i]].as_double(), + local_dec_values_Y[undecided[i]].numerator, + local_dec_values_Y[undecided[i]].denominator, + local_dec_values_Y[undecided[i]].as_double(), + local_dec_values_T[undecided[i]].numerator, + local_dec_values_T[undecided[i]].denominator, + local_dec_values_T[undecided[i]].as_double()); + } + } + #endif + } + else + { + size_solvable = false; + break; + } + } + else + { + dec_values_X = local_dec_values_X; + dec_values_Y = local_dec_values_Y; + dec_values_T = local_dec_values_T; + + solving_result = size_solvable = true; + break; + } + } + } + else + { + #ifdef DEBUG + { + printf("First UNSAT\n"); + } + #endif + + size_solvable = false; + } + + BoundingBox med_half_box({box_min_x, box_min_y}, {box_max_x, box_max_y}); + + if (size_solvable) + { + #ifdef DEBUG + { + printf("Solvable\n"); + } + #endif + _outer_half_box = med_half_box; + } + else + { + #ifdef DEBUG + { + printf("Unsolvable\n"); + } + #endif + _inner_half_box = med_half_box; + } + + #ifdef DEBUG + { + printf("Augmented inner half box: %d, %d, %d, %d\n", _inner_half_box.min.x(), _inner_half_box.min.y(), _inner_half_box.max.x(), _inner_half_box.max.y()); + printf("Augmented outer half box: %d, %d, %d, %d\n", _outer_half_box.min.x(), _outer_half_box.min.y(), _outer_half_box.max.x(), _outer_half_box.max.y()); + } + #endif + + progress = MIN(progress + 1, progress_total_estimation); + progress_callback(progress_range.progress_min + (progress_range.progress_max - progress_range.progress_min) * progress / progress_total_estimation); + } + progress_callback(progress_range.progress_max); + + return solving_result; +} + + +bool optimize_ConsequentialWeakPolygonNonoverlappingBinaryCentered(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + Polygon &inner_half_polygon, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const z3::expr_vector &presence_constraints, + const ProgressRange &progress_range, + std::function progress_callback) +{ + assert(solver_configuration.plate_bounding_polygon.is_counter_clockwise()); + assert(solver_configuration.plate_bounding_polygon.points.size() > 0); + + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + + #ifdef DEBUG + { + printf("Progress range: %d -- %d\n", progress_range.progress_min, progress_range.progress_max); + } + #endif + + bool solving_result = false; + + std::vector local_dec_values_X = dec_values_X; + std::vector local_dec_values_Y = dec_values_Y; + std::vector local_dec_values_T = dec_values_T; + + assert(inner_half_polygon.points.size() == solver_configuration.plate_bounding_polygon.points.size()); + + Polygon _inner_half_polygon = inner_half_polygon; + Polygon _outer_half_polygon = solver_configuration.plate_bounding_polygon; + + assert(_inner_half_polygon.points.size() == _outer_half_polygon.points.size()); + + coord_t max_diff = ABS(_outer_half_polygon.points[0].x() - _inner_half_polygon.points[0].x()); + for (unsigned int i = 1; i < _outer_half_polygon.points.size(); ++i) + { + coord_t diff = ABS(_outer_half_polygon.points[i].x() - _inner_half_polygon.points[i].x()); + if (diff > max_diff) + { + max_diff = diff; + } + } + for (unsigned int i = 0; i < _outer_half_polygon.points.size(); ++i) + { + coord_t diff = ABS(_outer_half_polygon.points[i].y() - _inner_half_polygon.points[i].y()); + if (diff > max_diff) + { + max_diff = diff; + } + } + + int progress_total_estimation = MAX(1, std::log2(1 + max_diff)); + int progress = 0; + + while ([&_outer_half_polygon, &_inner_half_polygon] + { + for (unsigned int i = 0; i < _outer_half_polygon.points.size(); ++i) + { + + if ( ABS(_outer_half_polygon.points[i].x() - _inner_half_polygon.points[i].x()) > 1 + || ABS(_outer_half_polygon.points[i].y() - _inner_half_polygon.points[i].y()) > 1) + { + return true; + } + } + return false; + }()) + { + #ifdef DEBUG + { + printf("Diffs: "); + for (unsigned int i = 0; i < _outer_half_polygon.points.size(); ++i) + { + printf("[%d, %d] ", + ABS(_outer_half_polygon.points[i].x() - _inner_half_polygon.points[i].x()), + ABS(_outer_half_polygon.points[i].y() - _inner_half_polygon.points[i].y())); + } + printf("\n"); + + printf("Inner half polygon: "); + for (unsigned int i = 0; i < _inner_half_polygon.points.size(); ++i) + { + printf("[%d,%d] ", _inner_half_polygon.points[i].x(), _inner_half_polygon.points[i].y()); + } + printf("\n"); + + printf("Outer half polygon: "); + for (unsigned int i = 0; i < _outer_half_polygon.points.size(); ++i) + { + printf("[%d,%d] ", _outer_half_polygon.points[i].x(), _outer_half_polygon.points[i].y()); + } + printf("\n"); + } + #endif + + bool size_solvable = false; + + Polygon bounding_polygon; + + for (unsigned int i = 0; i < _outer_half_polygon.points.size(); ++i) + { + bounding_polygon.points.insert(bounding_polygon.points.begin() + i, Point((_outer_half_polygon[i].x() + _inner_half_polygon[i].x()) / 2, + (_outer_half_polygon[i].y() + _inner_half_polygon[i].y()) / 2)); + } + + #ifdef DEBUG + { + printf("BBX: "); + for (unsigned int i = 0; i < bounding_polygon.points.size(); ++i) + { + printf("[%d,%d] ", bounding_polygon.points[i].x(), bounding_polygon.points[i].y()); + } + printf("\n"); + } + #endif + + z3::expr_vector complete_assumptions(Context); + + for (unsigned int i = 0; i < presence_constraints.size(); ++i) + { + complete_assumptions.push_back(presence_constraints[i]); + } + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + assume_BedBoundingPolygon(Context, + dec_vars_X[undecided[i]], + dec_vars_Y[undecided[i]], + polygons[undecided[i]], + bounding_polygon, + complete_assumptions); + } + + bool sat = false; + + if (checkArea_SequentialWeakPolygonNonoverlapping(bounding_polygon, + fixed, + undecided, + polygons, + unreachable_polygons)) + { + switch (Solver.check(complete_assumptions)) + { + case z3::sat: + { + sat = true; + break; + } + case z3::unsat: + { + sat = false; + break; + } + case z3::unknown: + { + sat = false; + break; + } + default: + { + break; + } + } + } + else + { + sat = false; + } + + if (sat) + { + #ifdef DEBUG + { + printf("First SAT\n"); + } + #endif + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T); + + int total_refines = 0; + + while (true) + { + bool refined = refine_ConsequentialPolygonWeakNonoverlapping(Solver, + Context, + dec_vars_X, + dec_vars_Y, + dec_vars_T, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T, + fixed, + undecided, + polygons, + unreachable_polygons); + if (refined) + { + ++total_refines; + + bool refined_sat = false; + + if (total_refines < solver_configuration.max_refines) + { + if (checkArea_SequentialWeakPolygonNonoverlapping(bounding_polygon, + fixed, + undecided, + polygons, + unreachable_polygons)) + { + switch (Solver.check(complete_assumptions)) + { + case z3::sat: + { + refined_sat = true; + break; + } + case z3::unsat: + { + refined_sat = false; + break; + } + case z3::unknown: + { + refined_sat = false; + break; + } + default: + { + break; + } + } + } + else + { + refined_sat = false; + } + } + + progress_callback(progress_range.progress_min + (progress_range.progress_max - progress_range.progress_min) * progress / progress_total_estimation); + + if (refined_sat) + { + z3::model Model(Solver.get_model()); + + extract_DecisionValuesFromModel(Model, + dec_var_names_map, + local_dec_values_X, + local_dec_values_Y, + local_dec_values_T); + + #ifdef DEBUG + { + printf("Refined positions:\n"); + for (unsigned int i = 0; i < undecided.size(); ++i) + { + printf(" i:%d, undecided[i]:%d: %ld/%ld (%.3f), %ld/%ld (%.3f) [%ld/%ld (%.3f)]\n", + i, undecided[i], + local_dec_values_X[undecided[i]].numerator, + local_dec_values_X[undecided[i]].denominator, + local_dec_values_X[undecided[i]].as_double(), + local_dec_values_Y[undecided[i]].numerator, + local_dec_values_Y[undecided[i]].denominator, + local_dec_values_Y[undecided[i]].as_double(), + local_dec_values_T[undecided[i]].numerator, + local_dec_values_T[undecided[i]].denominator, + local_dec_values_T[undecided[i]].as_double()); + } + } + #endif + } + else + { + size_solvable = false; + break; + } + } + else + { + dec_values_X = local_dec_values_X; + dec_values_Y = local_dec_values_Y; + dec_values_T = local_dec_values_T; + + solving_result = size_solvable = true; + break; + } + } + } + else + { + #ifdef DEBUG + { + printf("First UNSAT\n"); + } + #endif + + size_solvable = false; + } + + if (size_solvable) + { + #ifdef DEBUG + { + printf("Solvable\n"); + } + #endif + _outer_half_polygon = bounding_polygon; + } + else + { + #ifdef DEBUG + { + printf("Unsolvable\n"); + } + #endif + _inner_half_polygon = bounding_polygon; + } + + #ifdef DEBUG + { + printf("Augmented half polygon: "); + for (unsigned int i = 0; i < _inner_half_polygon.points.size(); ++i) + { + printf("[%d,%d] ", _inner_half_polygon.points[i].x(), _inner_half_polygon.points[i].y()); + } + printf("\n"); + + printf("Augmented half polygon: "); + for (unsigned int i = 0; i < _outer_half_polygon.points.size(); ++i) + { + printf("[%d,%d] ", _outer_half_polygon.points[i].x(), _outer_half_polygon.points[i].y()); + } + printf("\n"); + } + #endif + + progress = MIN(progress + 1, progress_total_estimation); + progress_callback(progress_range.progress_min + (progress_range.progress_max - progress_range.progress_min) * progress / progress_total_estimation); + } + progress_callback(progress_range.progress_max); + + return solving_result; +} + + +/*----------------------------------------------------------------*/ + +void augment_TemporalSpread(const SolverConfiguration &solver_configuration, + std::vector &dec_values_T, + const std::vector &decided_polygons) +{ + std::map> sorted_polygons; + + #ifdef DEBUG + { + printf("Origo\n"); + for (unsigned int i = 0; i < dec_values_T.size(); ++i) + { + printf("%.3f\n", dec_values_T[i].as_double()); + } + } + #endif + + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + sorted_polygons[dec_values_T[decided_polygons[i]].as_double()] = decided_polygons[i]; + } + + int time = SEQ_GROUND_PRESENCE_TIME + 2 * solver_configuration.temporal_spread * solver_configuration.object_group_size; + + for (const auto& sorted_polygon: sorted_polygons) + { + dec_values_T[sorted_polygon.second] = Rational(time); + time += 2 * solver_configuration.temporal_spread * solver_configuration.object_group_size; + } + + #ifdef DEBUG + { + printf("Augment\n"); + for (unsigned int i = 0; i < dec_values_T.size(); ++i) + { + printf("%.3f\n", dec_values_T[i].as_double()); + } + } + #endif +} + + +bool optimize_SubglobalPolygonNonoverlapping(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const std::vector &polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons) +{ + vector undecided; + + decided_polygons.clear(); + remaining_polygons.clear(); + + dec_values_X.resize(polygons.size()); + dec_values_Y.resize(polygons.size()); + + for (unsigned int curr_polygon = 0; curr_polygon < polygons.size(); /* nothing */) + { + bool optimized = false; + + int remaining_polygon = 0; + for(int object_group_size = MIN((unsigned int)solver_configuration.object_group_size, polygons.size() - curr_polygon); object_group_size > 0; --object_group_size) + { + z3::context z_context; + z3::solver z_solver(z_context); + + z3::expr_vector local_dec_vars_X(z_context); + z3::expr_vector local_dec_vars_Y(z_context); + + vector local_values_X; + vector local_values_Y; + + local_values_X.resize(polygons.size()); + local_values_Y.resize(polygons.size()); + + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + #ifdef DEBUG + { + printf("Decided: %d %.3f, %.3f\n", decided_polygons[i], dec_values_X[decided_polygons[i]].as_double(), dec_values_Y[decided_polygons[i]].as_double()); + } + #endif + local_values_X[decided_polygons[i]] = dec_values_X[decided_polygons[i]]; + local_values_Y[decided_polygons[i]] = dec_values_Y[decided_polygons[i]]; + } + + string_map dec_var_names_map; + + undecided.clear(); + + for (int i = object_group_size - 1; i >= 0; --i) + { + undecided.push_back(curr_polygon + i + remaining_polygon); + } + + #ifdef DEBUG + { + printf("Undecided\n"); + for (unsigned int j = 0; j < undecided.size(); ++j) + { + printf(" %d\n", undecided[j]); + } + printf("Decided\n"); + for (unsigned int j = 0; j < decided_polygons.size(); ++j) + { + printf(" %d\n", decided_polygons[j]); + } + printf("Locals\n"); + for (unsigned int j = 0; j < polygons.size(); ++j) + { + printf("X: %ld,%ld Y: %ld,%ld \n", + local_values_X[j].numerator, + local_values_X[j].denominator, + local_values_Y[j].numerator, + local_values_Y[j].denominator); + } + } + #endif + + build_WeakPolygonNonoverlapping(z_solver, + z_context, + polygons, + local_dec_vars_X, + local_dec_vars_Y, + local_values_X, + local_values_Y, + decided_polygons, + undecided, + dec_var_names_map); + + #ifdef DEBUG + { + printf("%ld,%ld\n", local_values_X.size(), local_values_Y.size()); + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + printf("poly: %ld\n", polygons[i].points.size()); + for (unsigned int j = 0; j < polygons[i].points.size(); ++j) + { + printf(" %d,%d\n", polygons[i].points[j].x(), polygons[i].points[j].y()); + } + } + } + #endif + + optimized = optimize_WeakPolygonNonoverlapping(z_solver, + z_context, + solver_configuration, + local_dec_vars_X, + local_dec_vars_Y, + local_values_X, + local_values_Y, + decided_polygons, + undecided, + dec_var_names_map, + polygons); + + if (optimized) + { + for (unsigned int i = 0; i < undecided.size(); ++i) + { + dec_values_X[undecided[i]] = local_values_X[undecided[i]]; + dec_values_Y[undecided[i]] = local_values_Y[undecided[i]]; + decided_polygons.push_back(undecided[i]); + } + if (curr_polygon + solver_configuration.object_group_size < polygons.size()) + { + curr_polygon += solver_configuration.object_group_size; + } + else + { + return true; + } + break; + } + else + { + #ifdef DEBUG + { + printf("Remaining polygon: %d\n", curr_polygon + remaining_polygon); + } + #endif + remaining_polygons.push_back(undecided_polygons[curr_polygon + remaining_polygon++]); + } + } + if (!optimized) + { + if (curr_polygon <= 0) + { + return false; + } + else + { + if (curr_polygon + solver_configuration.object_group_size < polygons.size()) + { + curr_polygon += solver_configuration.object_group_size; + } + else + { + return true; + } + } + } + } + return true; +} + + +bool optimize_SubglobalSequentialPolygonNonoverlapping(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + return optimize_SubglobalSequentialPolygonNonoverlapping(solver_configuration, + dec_values_X, + dec_values_Y, + dec_values_T, + polygons, + _unreachable_polygons, + undecided_polygons, + decided_polygons, + remaining_polygons); +} + + +bool optimize_SubglobalSequentialPolygonNonoverlapping(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons) +{ + vector undecided; + + decided_polygons.clear(); + remaining_polygons.clear(); + + dec_values_X.resize(polygons.size()); + dec_values_Y.resize(polygons.size()); + dec_values_T.resize(polygons.size()); + + for (unsigned int curr_polygon = 0; curr_polygon < polygons.size(); /* nothing */) + { + bool optimized = false; + + int remaining_polygon = 0; + for(int object_group_size = MIN((unsigned int)solver_configuration.object_group_size, polygons.size() - curr_polygon); object_group_size > 0; --object_group_size) + { + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + + z3::context z_context; + z3::solver z_solver(z_context); + + z3::expr_vector local_dec_vars_X(z_context); + z3::expr_vector local_dec_vars_Y(z_context); + z3::expr_vector local_dec_vars_T(z_context); + + vector local_values_X; + vector local_values_Y; + vector local_values_T; + + local_values_X.resize(polygons.size()); + local_values_Y.resize(polygons.size()); + local_values_T.resize(polygons.size()); + + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + #ifdef DEBUG + { + printf("Decided: %d %.3f, %.3f, %.3f\n", + decided_polygons[i], + dec_values_X[decided_polygons[i]].as_double(), + dec_values_Y[decided_polygons[i]].as_double(), + dec_values_T[decided_polygons[i]].as_double()); + } + #endif + + local_values_X[decided_polygons[i]] = dec_values_X[decided_polygons[i]]; + local_values_Y[decided_polygons[i]] = dec_values_Y[decided_polygons[i]]; + local_values_T[decided_polygons[i]] = dec_values_T[decided_polygons[i]]; + } + + string_map dec_var_names_map; + + undecided.clear(); + + for (int i = object_group_size - 1; i >= 0; --i) + { + undecided.push_back(curr_polygon + i + remaining_polygon); + } + + #ifdef DEBUG + { + printf("Undecided\n"); + for (unsigned int j = 0; j < undecided.size(); ++j) + { + printf(" %d\n", undecided[j]); + } + printf("Decided\n"); + for (unsigned int j = 0; j < decided_polygons.size(); ++j) + { + printf(" %d\n", decided_polygons[j]); + } + printf("Locals\n"); + for (unsigned int j = 0; j < polygons.size(); ++j) + { + printf("X: %ld,%ld Y: %ld,%ld T: %ld,%ld\n", + local_values_X[j].numerator, + local_values_X[j].denominator, + local_values_Y[j].numerator, + local_values_Y[j].denominator, + local_values_T[j].numerator, + local_values_T[j].denominator); + + } + } + #endif + + build_SequentialWeakPolygonNonoverlapping(z_solver, + z_context, + polygons, + unreachable_polygons, + local_dec_vars_X, + local_dec_vars_Y, + local_dec_vars_T, + local_values_X, + local_values_Y, + local_values_T, + decided_polygons, + undecided, + dec_var_names_map); + + + introduce_SequentialTemporalOrderingAgainstFixed(z_solver, + z_context, + local_dec_vars_T, + local_values_T, + decided_polygons, + undecided, + solver_configuration.temporal_spread, + polygons); + + #ifdef DEBUG + { + printf("%ld,%ld\n", local_values_X.size(), local_values_Y.size()); + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + printf("poly: %ld\n", polygons[i].points.size()); + for (unsigned int j = 0; j < polygons[i].points.size(); ++j) + { + printf(" %d,%d\n", polygons[i].points[j].x(), polygons[i].points[j].y()); + } + } + } + #endif + + optimized = optimize_SequentialWeakPolygonNonoverlapping(z_solver, + z_context, + solver_configuration, + local_dec_vars_X, + local_dec_vars_Y, + local_dec_vars_T, + local_values_X, + local_values_Y, + local_values_T, + decided_polygons, + undecided, + dec_var_names_map, + polygons, + unreachable_polygons); + + + if (optimized) + { + for (unsigned int i = 0; i < undecided.size(); ++i) + { + dec_values_X[undecided[i]] = local_values_X[undecided[i]]; + dec_values_Y[undecided[i]] = local_values_Y[undecided[i]]; + dec_values_T[undecided[i]] = local_values_T[undecided[i]]; + decided_polygons.push_back(undecided[i]); + } + augment_TemporalSpread(solver_configuration, dec_values_T, decided_polygons); + + if (curr_polygon + solver_configuration.object_group_size < polygons.size()) + { + curr_polygon += solver_configuration.object_group_size; + } + else + { + return true; + } + break; + } + else + { + #ifdef DEBUG + { + printf("Remaining polygon: %d\n", curr_polygon + remaining_polygon); + } + #endif + remaining_polygons.push_back(undecided_polygons[curr_polygon + remaining_polygon++]); + } + } + if (!optimized) + { + if (curr_polygon <= 0) + { + return false; + } + else + { + if (curr_polygon + solver_configuration.object_group_size < polygons.size()) + { + curr_polygon += solver_configuration.object_group_size; + } + else + { + return true; + } + } + } + } + return true; +} + + +bool optimize_SubglobalSequentialPolygonNonoverlappingCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + return optimize_SubglobalSequentialPolygonNonoverlappingCentered(solver_configuration, + dec_values_X, + dec_values_Y, + dec_values_T, + polygons, + _unreachable_polygons, + undecided_polygons, + decided_polygons, + remaining_polygons); +} + + +bool optimize_SubglobalSequentialPolygonNonoverlappingCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons) +{ + vector undecided; + + decided_polygons.clear(); + remaining_polygons.clear(); + + dec_values_X.resize(polygons.size()); + dec_values_Y.resize(polygons.size()); + dec_values_T.resize(polygons.size()); + + for (unsigned int curr_polygon = 0; curr_polygon < polygons.size(); /* nothing */) + { + bool optimized = false; + + int remaining_polygon = 0; + for(int object_group_size = MIN((unsigned int)solver_configuration.object_group_size, polygons.size() - curr_polygon); object_group_size > 0; --object_group_size) + { + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + + z3::context z_context; + z3::solver z_solver(z_context); + + z3::expr_vector local_dec_vars_X(z_context); + z3::expr_vector local_dec_vars_Y(z_context); + z3::expr_vector local_dec_vars_T(z_context); + + vector local_values_X; + vector local_values_Y; + vector local_values_T; + + local_values_X.resize(polygons.size()); + local_values_Y.resize(polygons.size()); + local_values_T.resize(polygons.size()); + + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + #ifdef DEBUG + { + printf("Decided: %d %.3f, %.3f, %.3f\n", + decided_polygons[i], + dec_values_X[decided_polygons[i]].as_double(), + dec_values_Y[decided_polygons[i]].as_double(), + dec_values_T[decided_polygons[i]].as_double()); + } + #endif + + local_values_X[decided_polygons[i]] = dec_values_X[decided_polygons[i]]; + local_values_Y[decided_polygons[i]] = dec_values_Y[decided_polygons[i]]; + local_values_T[decided_polygons[i]] = dec_values_T[decided_polygons[i]]; + } + + string_map dec_var_names_map; + + undecided.clear(); + + /* + for (unsigned int i = 0; i < object_group_size; ++i) + { + undecided.push_back(curr_polygon + i); + } + */ + + for (int i = object_group_size - 1; i >= 0; --i) + { + undecided.push_back(curr_polygon + i + remaining_polygon); + } + + #ifdef DEBUG + { + printf("Undecided\n"); + for (unsigned int j = 0; j < undecided.size(); ++j) + { + printf(" %d\n", undecided[j]); + } + printf("Decided\n"); + for (unsigned int j = 0; j < decided_polygons.size(); ++j) + { + printf(" %d\n", decided_polygons[j]); + } + printf("Locals\n"); + for (unsigned int j = 0; j < polygons.size(); ++j) + { + printf("X: %ld,%ld Y: %ld,%ld T: %ld,%ld\n", + local_values_X[j].numerator, + local_values_X[j].denominator, + local_values_Y[j].numerator, + local_values_Y[j].denominator, + local_values_T[j].numerator, + local_values_T[j].denominator); + + } + } + #endif + + build_SequentialWeakPolygonNonoverlapping(z_solver, + z_context, + polygons, + unreachable_polygons, + local_dec_vars_X, + local_dec_vars_Y, + local_dec_vars_T, + local_values_X, + local_values_Y, + local_values_T, + decided_polygons, + undecided, + dec_var_names_map); + + + introduce_SequentialTemporalOrderingAgainstFixed(z_solver, + z_context, + local_dec_vars_T, + local_values_T, + decided_polygons, + undecided, + solver_configuration.temporal_spread, + polygons); + + #ifdef DEBUG + { + printf("%ld,%ld\n", local_values_X.size(), local_values_Y.size()); + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + printf("poly: %ld\n", polygons[i].points.size()); + for (unsigned int j = 0; j < polygons[i].points.size(); ++j) + { + printf(" %d,%d\n", polygons[i].points[j].x(), polygons[i].points[j].y()); + } + } + } + #endif + + optimized = optimize_SequentialWeakPolygonNonoverlappingCentered(z_solver, + z_context, + solver_configuration, + local_dec_vars_X, + local_dec_vars_Y, + local_dec_vars_T, + local_values_X, + local_values_Y, + local_values_T, + decided_polygons, + undecided, + dec_var_names_map, + polygons, + unreachable_polygons); + + + if (optimized) + { + for (unsigned int i = 0; i < undecided.size(); ++i) + { + dec_values_X[undecided[i]] = local_values_X[undecided[i]]; + dec_values_Y[undecided[i]] = local_values_Y[undecided[i]]; + dec_values_T[undecided[i]] = local_values_T[undecided[i]]; + decided_polygons.push_back(undecided[i]); + } + augment_TemporalSpread(solver_configuration, dec_values_T, decided_polygons); + + if (curr_polygon + solver_configuration.object_group_size < polygons.size()) + { + curr_polygon += solver_configuration.object_group_size; + } + else + { + return true; + } + break; + } + else + { + #ifdef DEBUG + { + printf("Remaining polygon: %d\n", curr_polygon + remaining_polygon); + } + #endif + remaining_polygons.push_back(undecided_polygons[curr_polygon + remaining_polygon++]); + } + } + if (!optimized) + { + if (curr_polygon <= 0) + { + return false; + } + else + { + if (curr_polygon + solver_configuration.object_group_size < polygons.size()) + { + curr_polygon += solver_configuration.object_group_size; + } + else + { + return true; + } + } + } + } + return true; +} + + +bool optimize_SubglobalSequentialPolygonNonoverlappingBinaryCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + return optimize_SubglobalSequentialPolygonNonoverlappingBinaryCentered(solver_configuration, + dec_values_X, + dec_values_Y, + dec_values_T, + polygons, + _unreachable_polygons, + undecided_polygons, + decided_polygons, + remaining_polygons); +} + + +bool optimize_SubglobalSequentialPolygonNonoverlappingBinaryCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons) +{ + vector undecided; + + decided_polygons.clear(); + remaining_polygons.clear(); + + dec_values_X.resize(polygons.size()); + dec_values_Y.resize(polygons.size()); + dec_values_T.resize(polygons.size()); + + coord_t box_x_size = solver_configuration.plate_bounding_box.max.x() - solver_configuration.plate_bounding_box.min.x(); + coord_t box_y_size = solver_configuration.plate_bounding_box.max.y() - solver_configuration.plate_bounding_box.min.y(); + + coord_t box_half_x_min = solver_configuration.plate_bounding_box.min.x() + box_x_size / 4; + coord_t box_half_x_max = solver_configuration.plate_bounding_box.max.x() - box_x_size / 4; + + coord_t box_half_y_min = solver_configuration.plate_bounding_box.min.y() + box_y_size / 4; + coord_t box_half_y_max = solver_configuration.plate_bounding_box.max.y() - box_y_size / 4; + + for (unsigned int curr_polygon = 0; curr_polygon < polygons.size(); /* nothing */) + { + bool optimized = false; + + for(int object_group_size = MIN((unsigned int)solver_configuration.object_group_size, polygons.size() - curr_polygon); object_group_size > 0; --object_group_size) + { + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + + z3::context z_context; + z3::solver z_solver(z_context); + + z3::expr_vector local_dec_vars_X(z_context); + z3::expr_vector local_dec_vars_Y(z_context); + z3::expr_vector local_dec_vars_T(z_context); + + vector local_values_X; + vector local_values_Y; + vector local_values_T; + + local_values_X.resize(polygons.size()); + local_values_Y.resize(polygons.size()); + local_values_T.resize(polygons.size()); + + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + #ifdef DEBUG + { + printf("Decided: %d %.3f, %.3f, %.3f\n", + decided_polygons[i], + dec_values_X[decided_polygons[i]].as_double(), + dec_values_Y[decided_polygons[i]].as_double(), + dec_values_T[decided_polygons[i]].as_double()); + } + #endif + + local_values_X[decided_polygons[i]] = dec_values_X[decided_polygons[i]]; + local_values_Y[decided_polygons[i]] = dec_values_Y[decided_polygons[i]]; + local_values_T[decided_polygons[i]] = dec_values_T[decided_polygons[i]]; + } + + string_map dec_var_names_map; + + undecided.clear(); + + for (int i = 0; i < object_group_size; ++i) + { + undecided.push_back(curr_polygon + i); + } + + #ifdef DEBUG + { + printf("Undecided\n"); + for (unsigned int j = 0; j < undecided.size(); ++j) + { + printf(" %d\n", undecided[j]); + } + printf("Decided\n"); + for (unsigned int j = 0; j < decided_polygons.size(); ++j) + { + printf(" %d\n", decided_polygons[j]); + } + printf("Locals\n"); + for (unsigned int j = 0; j < polygons.size(); ++j) + { + printf("X: %ld,%ld Y: %ld,%ld T: %ld,%ld\n", + local_values_X[j].numerator, + local_values_X[j].denominator, + local_values_Y[j].numerator, + local_values_Y[j].denominator, + local_values_T[j].numerator, + local_values_T[j].denominator); + + } + } + #endif + + build_SequentialWeakPolygonNonoverlapping(z_solver, + z_context, + polygons, + unreachable_polygons, + local_dec_vars_X, + local_dec_vars_Y, + local_dec_vars_T, + local_values_X, + local_values_Y, + local_values_T, + decided_polygons, + undecided, + dec_var_names_map); + + introduce_SequentialTemporalOrderingAgainstFixed(z_solver, + z_context, + local_dec_vars_T, + local_values_T, + decided_polygons, + undecided, + solver_configuration.temporal_spread, + polygons); + + #ifdef DEBUG + { + printf("%ld,%ld\n", local_values_X.size(), local_values_Y.size()); + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + printf("poly: %ld\n", polygons[i].points.size()); + for (unsigned int j = 0; j < polygons[i].points.size(); ++j) + { + printf(" %d,%d\n", polygons[i].points[j].x(), polygons[i].points[j].y()); + } + } + } + #endif + + optimized = optimize_SequentialWeakPolygonNonoverlappingBinaryCentered(z_solver, + z_context, + solver_configuration, + box_half_x_min, + box_half_y_min, + box_half_x_max, + box_half_y_max, + local_dec_vars_X, + local_dec_vars_Y, + local_dec_vars_T, + local_values_X, + local_values_Y, + local_values_T, + decided_polygons, + undecided, + dec_var_names_map, + polygons, + unreachable_polygons); + + + if (optimized) + { + for (unsigned int i = 0; i < undecided.size(); ++i) + { + dec_values_X[undecided[i]] = local_values_X[undecided[i]]; + dec_values_Y[undecided[i]] = local_values_Y[undecided[i]]; + dec_values_T[undecided[i]] = local_values_T[undecided[i]]; + decided_polygons.push_back(undecided[i]); + } + augment_TemporalSpread(solver_configuration, dec_values_T, decided_polygons); + + if (curr_polygon + solver_configuration.object_group_size < polygons.size()) + { + curr_polygon += solver_configuration.object_group_size; + } + else + { + return true; + } + break; + } + else + { + #ifdef DEBUG + { + printf("Remaining polygon: %d\n", curr_polygon + object_group_size - 1); + } + #endif + remaining_polygons.push_back(undecided_polygons[curr_polygon + object_group_size - 1]); + } + } + if (!optimized) + { + if (curr_polygon <= 0) + { + return false; + } + else + { + if (curr_polygon + solver_configuration.object_group_size < polygons.size()) + { + curr_polygon += solver_configuration.object_group_size; + + for (; curr_polygon < polygons.size(); ++curr_polygon) + { + remaining_polygons.push_back(undecided_polygons[curr_polygon]); + } + return true; + } + else + { + return true; + } + } + } + } + return true; +} + + +bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons, + const std::vector &lepox_to_next, + bool trans_bed_lepox, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons, + int progress_object_phases_done, + int progress_total_object_phases, + std::function progress_callback) +{ + std::vector > _unreachable_polygons; + _unreachable_polygons.resize(unreachable_polygons.size()); + + for (unsigned int poly = 0; poly < unreachable_polygons.size(); ++poly) + { + _unreachable_polygons[poly].push_back(unreachable_polygons[poly]); + } + + return optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(solver_configuration, + dec_values_X, + dec_values_Y, + dec_values_T, + polygons, + _unreachable_polygons, + lepox_to_next, + trans_bed_lepox, + undecided_polygons, + decided_polygons, + remaining_polygons, + progress_object_phases_done, + progress_total_object_phases, + progress_callback); +} + + +bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const std::vector &lepox_to_next, + bool trans_bed_lepox, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons, + int &progress_object_phases_done, + int progress_total_object_phases, + std::function progress_callback) +{ + std::vector undecided; + + decided_polygons.clear(); + remaining_polygons.clear(); + + dec_values_X.resize(polygons.size()); + dec_values_Y.resize(polygons.size()); + dec_values_T.resize(polygons.size()); + + coord_t box_center_x = (solver_configuration.plate_bounding_box.min.x() + solver_configuration.plate_bounding_box.max.x()) / 2; + coord_t box_center_y = (solver_configuration.plate_bounding_box.min.y() + solver_configuration.plate_bounding_box.max.y()) / 2; + + BoundingBox inner_half_box({box_center_x, box_center_y}, {box_center_x, box_center_y}); + + for (unsigned int curr_polygon = 0; curr_polygon < polygons.size(); /* nothing */) + { + bool optimized = false; + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + + z3::context z_context; + z3::solver z_solver(z_context); + + z3::expr_vector local_dec_vars_X(z_context); + z3::expr_vector local_dec_vars_Y(z_context); + z3::expr_vector local_dec_vars_T(z_context); + + vector local_values_X; + vector local_values_Y; + vector local_values_T; + + local_values_X.resize(polygons.size()); + local_values_Y.resize(polygons.size()); + local_values_T.resize(polygons.size()); + + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + #ifdef DEBUG + { + printf("Decided: %d %.3f, %.3f, %.3f\n", + decided_polygons[i], + dec_values_X[decided_polygons[i]].as_double(), + dec_values_Y[decided_polygons[i]].as_double(), + dec_values_T[decided_polygons[i]].as_double()); + } + #endif + + local_values_X[decided_polygons[i]] = dec_values_X[decided_polygons[i]]; + local_values_Y[decided_polygons[i]] = dec_values_Y[decided_polygons[i]]; + local_values_T[decided_polygons[i]] = dec_values_T[decided_polygons[i]]; + } + + string_map dec_var_names_map; + int object_group_size = MIN((unsigned int)solver_configuration.object_group_size, polygons.size() - curr_polygon); + + undecided.clear(); + for (int i = 0; i < object_group_size; ++i) + { + undecided.push_back(curr_polygon + i); + } + + build_ConsequentialWeakPolygonNonoverlapping(solver_configuration, + z_solver, + z_context, + polygons, + unreachable_polygons, + local_dec_vars_X, + local_dec_vars_Y, + local_dec_vars_T, + local_values_X, + local_values_Y, + local_values_T, + decided_polygons, + undecided, + dec_var_names_map); + + introduce_ConsequentialTemporalOrderingAgainstFixed(z_solver, + z_context, + local_dec_vars_T, + local_values_T, + decided_polygons, + undecided, + solver_configuration.temporal_spread, + polygons); + + introduce_ConsequentialTemporalLepoxAgainstFixed(z_solver, + z_context, + local_dec_vars_T, + local_values_T, + decided_polygons, + undecided, + solver_configuration.temporal_spread, + polygons, + lepox_to_next, + trans_bed_lepox); + + std::vector missing; + std::vector remaining_local; + + while(object_group_size > 0) + { + z3::expr_vector presence_assumptions(z_context); + assume_ConsequentialObjectPresence(z_context, local_dec_vars_T, undecided, missing, presence_assumptions); + + #ifdef DEBUG + { + printf("Undecided\n"); + for (unsigned int j = 0; j < undecided.size(); ++j) + { + printf(" %d\n", undecided[j]); + } + printf("Decided\n"); + for (unsigned int j = 0; j < decided_polygons.size(); ++j) + { + printf(" %d\n", decided_polygons[j]); + } + printf("Locals\n"); + for (unsigned int j = 0; j < polygons.size(); ++j) + { + printf("X: %ld,%ld Y: %ld,%ld T: %ld,%ld\n", + local_values_X[j].numerator, + local_values_X[j].denominator, + local_values_Y[j].numerator, + local_values_Y[j].denominator, + local_values_T[j].numerator, + local_values_T[j].denominator); + } + } + #endif + + #ifdef DEBUG + { + printf("%ld,%ld\n", local_values_X.size(), local_values_Y.size()); + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + printf("poly: %ld\n", polygons[i].points.size()); + for (unsigned int j = 0; j < polygons[i].points.size(); ++j) + { + printf(" %d,%d\n", polygons[i].points[j].x(), polygons[i].points[j].y()); + } + } + } + #endif + + progress_callback((SEQ_PROGRESS_RANGE * progress_object_phases_done) / progress_total_object_phases); + + optimized = optimize_ConsequentialWeakPolygonNonoverlappingBinaryCentered(z_solver, + z_context, + solver_configuration, + inner_half_box, + local_dec_vars_X, + local_dec_vars_Y, + local_dec_vars_T, + local_values_X, + local_values_Y, + local_values_T, + decided_polygons, + undecided, + dec_var_names_map, + polygons, + unreachable_polygons, + presence_assumptions, + (progress_object_phases_done < progress_total_object_phases ? + ProgressRange((SEQ_PROGRESS_RANGE * progress_object_phases_done) / progress_total_object_phases, + (SEQ_PROGRESS_RANGE * (progress_object_phases_done + 1)) / progress_total_object_phases) : + ProgressRange(SEQ_PROGRESS_RANGE, SEQ_PROGRESS_RANGE)), + progress_callback); + + if (optimized) + { + for (unsigned int i = 0; i < undecided.size(); ++i) + { + dec_values_X[undecided[i]] = local_values_X[undecided[i]]; + dec_values_Y[undecided[i]] = local_values_Y[undecided[i]]; + dec_values_T[undecided[i]] = local_values_T[undecided[i]]; + decided_polygons.push_back(undecided[i]); + + if (progress_object_phases_done < progress_total_object_phases) + { + int progress_phase_starter = progress_object_phases_done % SEQ_PROGRESS_PHASES_PER_OBJECT; + progress_object_phases_done += progress_phase_starter > 0 ? SEQ_PROGRESS_PHASES_PER_OBJECT - progress_phase_starter : SEQ_PROGRESS_PHASES_PER_OBJECT; + } + } + augment_TemporalSpread(solver_configuration, dec_values_T, decided_polygons); + + if (curr_polygon + solver_configuration.object_group_size >= polygons.size()) + { + std::reverse(remaining_local.begin(), remaining_local.end()); + remaining_polygons.insert(remaining_polygons.end(), remaining_local.begin(), remaining_local.end()); + + progress_callback((SEQ_PROGRESS_RANGE * progress_object_phases_done) / progress_total_object_phases); + return true; + } + curr_polygon += solver_configuration.object_group_size; + + progress_callback((SEQ_PROGRESS_RANGE * progress_object_phases_done) / progress_total_object_phases); + break; + } + else + { + #ifdef DEBUG + { + printf("Remaining polygon: %d\n", curr_polygon + object_group_size - 1); + } + #endif + if (progress_object_phases_done < progress_total_object_phases) + { + ++progress_object_phases_done; + } + remaining_local.push_back(undecided_polygons[curr_polygon + object_group_size - 1]); + } + missing.push_back(undecided.back()); + undecided.pop_back(); + + --object_group_size; + progress_callback((SEQ_PROGRESS_RANGE * progress_object_phases_done) / progress_total_object_phases); + } + + std::reverse(remaining_local.begin(), remaining_local.end()); + remaining_polygons.insert(remaining_polygons.end(), remaining_local.begin(), remaining_local.end()); + + if (!optimized) + { + if (curr_polygon <= 0) + { + return false; + } + else + { + if (curr_polygon + solver_configuration.object_group_size < polygons.size()) + { + curr_polygon += solver_configuration.object_group_size; + + for (; curr_polygon < polygons.size(); ++curr_polygon) + { + remaining_polygons.push_back(undecided_polygons[curr_polygon]); + } + } + return true; + } + } + } + assert(remaining_polygons.empty()); + + return true; +} + + +bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &solvable_objects, + bool trans_bed_lepox, + std::vector &decided_polygons, + std::vector &remaining_polygons, + int &progress_object_phases_done, + int progress_total_object_phases, + std::function progress_callback) +{ + std::vector undecided; + + decided_polygons.clear(); + remaining_polygons.clear(); + + dec_values_X.resize(solvable_objects.size()); + dec_values_Y.resize(solvable_objects.size()); + dec_values_T.resize(solvable_objects.size()); + + BoundingBox inner_half_box; + Polygon inner_half_polygon; + + if (solver_configuration.plate_bounding_polygon.points.size() > 0) + { + coord_t sum_x = 0; + coord_t sum_y = 0; + + for (unsigned int i = 0; i < solver_configuration.plate_bounding_polygon.points.size(); ++i) + { + sum_x += solver_configuration.plate_bounding_polygon.points[i].x(); + sum_y += solver_configuration.plate_bounding_polygon.points[i].y(); + } + coord_t polygon_center_x = sum_x / solver_configuration.plate_bounding_polygon.points.size(); + coord_t polygon_center_y = sum_y / solver_configuration.plate_bounding_polygon.points.size(); + + for (unsigned int i = 0; i < solver_configuration.plate_bounding_polygon.points.size(); ++i) + { + inner_half_polygon.points.insert(inner_half_polygon.points.begin() + i, Point(polygon_center_x, polygon_center_y)); + } + } + else + { + coord_t box_center_x = (solver_configuration.plate_bounding_box.min.x() + solver_configuration.plate_bounding_box.max.x()) / 2; + coord_t box_center_y = (solver_configuration.plate_bounding_box.min.y() + solver_configuration.plate_bounding_box.max.y()) / 2; + + inner_half_box = BoundingBox({box_center_x, box_center_y}, {box_center_x, box_center_y}); + } + + std::vector polygons; + std::vector > unreachable_polygons; + std::vector lepox_to_next; + + for (const auto& solvable_object: solvable_objects) + { + polygons.push_back(solvable_object.polygon); + unreachable_polygons.push_back(solvable_object.unreachable_polygons); + lepox_to_next.push_back(solvable_object.lepox_to_next); + } + + for (unsigned int curr_polygon = 0; curr_polygon < solvable_objects.size(); /* nothing */) + { + bool optimized = false; + z3::set_param("timeout", solver_configuration.optimization_timeout.c_str()); + + z3::context z_context; + z3::solver z_solver(z_context); + + z3::expr_vector local_dec_vars_X(z_context); + z3::expr_vector local_dec_vars_Y(z_context); + z3::expr_vector local_dec_vars_T(z_context); + + vector local_values_X; + vector local_values_Y; + vector local_values_T; + + local_values_X.resize(solvable_objects.size()); + local_values_Y.resize(solvable_objects.size()); + local_values_T.resize(solvable_objects.size()); + + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + #ifdef DEBUG + { + printf("Decided: %d %.3f, %.3f, %.3f\n", + decided_polygons[i], + dec_values_X[decided_polygons[i]].as_double(), + dec_values_Y[decided_polygons[i]].as_double(), + dec_values_T[decided_polygons[i]].as_double()); + } + #endif + + local_values_X[decided_polygons[i]] = dec_values_X[decided_polygons[i]]; + local_values_Y[decided_polygons[i]] = dec_values_Y[decided_polygons[i]]; + local_values_T[decided_polygons[i]] = dec_values_T[decided_polygons[i]]; + } + + string_map dec_var_names_map; + int object_group_size = MIN((unsigned int)solver_configuration.object_group_size, solvable_objects.size() - curr_polygon); + + undecided.clear(); + for (int i = 0; i < object_group_size; ++i) + { + undecided.push_back(curr_polygon + i); + } + + build_ConsequentialWeakPolygonNonoverlapping(solver_configuration, + z_solver, + z_context, + polygons, + unreachable_polygons, + local_dec_vars_X, + local_dec_vars_Y, + local_dec_vars_T, + local_values_X, + local_values_Y, + local_values_T, + decided_polygons, + undecided, + dec_var_names_map); + + introduce_ConsequentialTemporalOrderingAgainstFixed(z_solver, + z_context, + local_dec_vars_T, + local_values_T, + decided_polygons, + undecided, + solver_configuration.temporal_spread, + polygons); + + introduce_ConsequentialTemporalLepoxAgainstFixed(z_solver, + z_context, + local_dec_vars_T, + local_values_T, + decided_polygons, + undecided, + solver_configuration.temporal_spread, + polygons, + lepox_to_next, + trans_bed_lepox); + std::vector missing; + std::vector remaining_local; + + while(object_group_size > 0) + { + z3::expr_vector presence_assumptions(z_context); + assume_ConsequentialObjectPresence(z_context, local_dec_vars_T, undecided, missing, presence_assumptions); + + #ifdef DEBUG + { + printf("Undecided\n"); + for (unsigned int j = 0; j < undecided.size(); ++j) + { + printf(" %d\n", undecided[j]); + } + printf("Missing\n"); + for (unsigned int j = 0; j < missing.size(); ++j) + { + printf(" %d\n", missing[j]); + } + printf("Decided\n"); + for (unsigned int j = 0; j < decided_polygons.size(); ++j) + { + printf(" %d\n", decided_polygons[j]); + } + printf("Locals\n"); + for (unsigned int j = 0; j < decided_polygons.size(); ++j) + { + printf("X: %ld,%ld Y: %ld,%ld T: %ld,%ld\n", + local_values_X[j].numerator, + local_values_X[j].denominator, + local_values_Y[j].numerator, + local_values_Y[j].denominator, + local_values_T[j].numerator, + local_values_T[j].denominator); + } + } + #endif + + #ifdef DEBUG + { + printf("%ld,%ld\n", local_values_X.size(), local_values_Y.size()); + + for (unsigned int i = 0; i < solvable_objects.size(); ++i) + { + printf("poly: %ld\n", polygons[i].points.size()); + for (unsigned int j = 0; j < polygons[i].points.size(); ++j) + { + printf(" %d,%d\n", polygons[i].points[j].x(), polygons[i].points[j].y()); + } + } + } + #endif + + progress_callback((SEQ_PROGRESS_RANGE * progress_object_phases_done) / progress_total_object_phases); + + if (solver_configuration.plate_bounding_polygon.points.size() > 0) + { + optimized = optimize_ConsequentialWeakPolygonNonoverlappingBinaryCentered(z_solver, + z_context, + solver_configuration, + inner_half_polygon, + local_dec_vars_X, + local_dec_vars_Y, + local_dec_vars_T, + local_values_X, + local_values_Y, + local_values_T, + decided_polygons, + undecided, + dec_var_names_map, + polygons, + unreachable_polygons, + presence_assumptions, + (progress_object_phases_done < progress_total_object_phases ? + ProgressRange((SEQ_PROGRESS_RANGE * progress_object_phases_done) / progress_total_object_phases, + (SEQ_PROGRESS_RANGE * (progress_object_phases_done + 1)) / progress_total_object_phases) : + ProgressRange(SEQ_PROGRESS_RANGE, SEQ_PROGRESS_RANGE)), + progress_callback); + } + else + { + optimized = optimize_ConsequentialWeakPolygonNonoverlappingBinaryCentered(z_solver, + z_context, + solver_configuration, + inner_half_box, + local_dec_vars_X, + local_dec_vars_Y, + local_dec_vars_T, + local_values_X, + local_values_Y, + local_values_T, + decided_polygons, + undecided, + dec_var_names_map, + polygons, + unreachable_polygons, + presence_assumptions, + (progress_object_phases_done < progress_total_object_phases ? + ProgressRange((SEQ_PROGRESS_RANGE * progress_object_phases_done) / progress_total_object_phases, + (SEQ_PROGRESS_RANGE * (progress_object_phases_done + 1)) / progress_total_object_phases) : + ProgressRange(SEQ_PROGRESS_RANGE, SEQ_PROGRESS_RANGE)), + progress_callback); + } + + if (optimized) + { + for (unsigned int i = 0; i < undecided.size(); ++i) + { + dec_values_X[undecided[i]] = local_values_X[undecided[i]]; + dec_values_Y[undecided[i]] = local_values_Y[undecided[i]]; + dec_values_T[undecided[i]] = local_values_T[undecided[i]]; + decided_polygons.push_back(undecided[i]); + + if (progress_object_phases_done < progress_total_object_phases) + { + int progress_phase_starter = progress_object_phases_done % SEQ_PROGRESS_PHASES_PER_OBJECT; + progress_object_phases_done += progress_phase_starter > 0 ? SEQ_PROGRESS_PHASES_PER_OBJECT - progress_phase_starter : SEQ_PROGRESS_PHASES_PER_OBJECT; + } + } + augment_TemporalSpread(solver_configuration, dec_values_T, decided_polygons); + + if (curr_polygon + solver_configuration.object_group_size >= solvable_objects.size()) + { + std::reverse(remaining_local.begin(), remaining_local.end()); + remaining_polygons.insert(remaining_polygons.end(), remaining_local.begin(), remaining_local.end()); + + progress_callback((SEQ_PROGRESS_RANGE * progress_object_phases_done) / progress_total_object_phases); + return true; + } + curr_polygon += solver_configuration.object_group_size; + progress_callback((SEQ_PROGRESS_RANGE * progress_object_phases_done) / progress_total_object_phases); + break; + } + else + { + #ifdef DEBUG + { + printf("Remaining polygon: %d\n", curr_polygon + object_group_size - 1); + } + #endif + if (progress_object_phases_done < progress_total_object_phases) + { + ++progress_object_phases_done; + } + remaining_local.push_back(undecided.back()); + } + missing.push_back(undecided.back()); + undecided.pop_back(); + + --object_group_size; + progress_callback((SEQ_PROGRESS_RANGE * progress_object_phases_done) / progress_total_object_phases); + } + + std::reverse(remaining_local.begin(), remaining_local.end()); + remaining_polygons.insert(remaining_polygons.end(), remaining_local.begin(), remaining_local.end()); + + if (!optimized) + { + if (curr_polygon <= 0) + { + return false; + } + else + { + if (curr_polygon + solver_configuration.object_group_size < solvable_objects.size()) + { + curr_polygon += solver_configuration.object_group_size; + + for (; curr_polygon < solvable_objects.size(); ++curr_polygon) + { + remaining_polygons.push_back(curr_polygon); + } + } + return true; + } + } + } + assert(remaining_polygons.empty()); + + return true; +} + + +/*----------------------------------------------------------------*/ + +} // namespace Sequential diff --git a/src/libseqarrange/src/seq_sequential.hpp b/src/libseqarrange/src/seq_sequential.hpp new file mode 100644 index 0000000..fa26597 --- /dev/null +++ b/src/libseqarrange/src/seq_sequential.hpp @@ -0,0 +1,1677 @@ +#ifndef __SEQ_SEQUENTIAL_HPP__ +#define __SEQ_SEQUENTIAL_HPP__ + + +/*----------------------------------------------------------------*/ + +#include +#include +#include + +#include + +#include + +#include "libslic3r/Geometry.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Geometry/ConvexHull.hpp" + +#include + +#include "seq_defs.hpp" + +#include "libseqarrange/seq_interface.hpp" + + +/*----------------------------------------------------------------*/ + +using namespace Slic3r; + + +/*----------------------------------------------------------------*/ + +namespace Sequential +{ + + + +/*----------------------------------------------------------------*/ + +#define SEQ_INTERSECTION_REPULSION_MIN "-0.01" +#define SEQ_INTERSECTION_REPULSION_MAX "1.01" +#define SEQ_TEMPORAL_ABSENCE_THRESHOLD "-16" +#define SEQ_TEMPORAL_PRESENCE_THRESHOLD "16" + +#define SEQ_Z3_SOLVER_TIMEOUT "8000" + +const coord_t SEQ_SVG_SCALE_FACTOR = 50000; +const int SEQ_GROUND_PRESENCE_TIME = 32; +const int SEQ_PROGRESS_RANGE = 100; +const int SEQ_PROGRESS_PHASES_PER_OBJECT = 4; +const int SEQ_PROGRESS_EXTRA_PHASES = 4 * SEQ_PROGRESS_PHASES_PER_OBJECT; +const double SEQ_PROGRESS_EXTRA_FACTOR = 1.15; + +#define SEQ_MAKE_EXTRA_PROGRESS(x) (((int)((x) * SEQ_PROGRESS_EXTRA_FACTOR / SEQ_PROGRESS_PHASES_PER_OBJECT)) * SEQ_PROGRESS_PHASES_PER_OBJECT) + +const int64_t SEQ_RATIONAL_PRECISION = 1000000; +const double SEQ_DECIMATION_TOLERANCE = 400000.0; + +const double SEQ_DECIMATION_TOLERANCE_VALUE_UNDEFINED = 0.0; +const double SEQ_DECIMATION_TOLERANCE_VALUE_LOW = 150000.0; +const double SEQ_DECIMATION_TOLERANCE_VALUE_HIGH = 650000.0; + + +/*----------------------------------------------------------------*/ + +typedef std::basic_string string; +typedef std::unordered_map string_map; + + +/*----------------------------------------------------------------*/ + +struct SolvableObject +{ + int id = 0; + + Slic3r::Polygon polygon; + std::vector unreachable_polygons; + bool lepox_to_next; +}; + + +/*----------------------------------------------------------------*/ + +struct Rational +{ + Rational() + : numerator(0) + , denominator(1) + { + /* nothing */ + } + + Rational(int64_t n) + : numerator(n) + , denominator(1) + { + /* nothing */ + } + + Rational(int64_t n, int64_t d) + : numerator(n) + , denominator(d) + { + /* nothing */ + } + + Rational(const z3::expr &expr) + { + if (expr.denominator().as_int64() != 0) + { + if (expr.numerator().as_int64() != 0) + { + numerator = expr.numerator().as_int64(); + denominator = expr.denominator().as_int64(); + } + else + { + double expr_val = expr.as_double(); + if (fabs(expr_val) > EPSILON) + { + numerator = expr_val * SEQ_RATIONAL_PRECISION; + denominator = SEQ_RATIONAL_PRECISION; + } + else + { + numerator = 0; + denominator = 1; + } + } + } + else + { + numerator = expr.as_double() * SEQ_RATIONAL_PRECISION; + denominator = SEQ_RATIONAL_PRECISION; + } + } + + bool is_Positive(void) const + { + return ((numerator > 0 && denominator > 0) || (numerator < 0 && denominator < 0)); + } + + bool is_Negative(void) const + { + return ((numerator > 0 && denominator < 0) || (numerator < 0 && denominator > 0)); + } + + double as_double() const + { + return (double)numerator / denominator; + } + + int64_t as_int64() const + { + return numerator / denominator; + } + + Rational operator+(int64_t val) const + { + return Rational(numerator + val * denominator, denominator); + } + + Rational operator*(int64_t val) const + { + return Rational(numerator * val, denominator); + } + + Rational normalize(void) const + { + return Rational(as_double() * SEQ_RATIONAL_PRECISION, SEQ_RATIONAL_PRECISION); + } + + bool operator<(const Rational &rational) const + { + return (as_double() < rational.as_double()); + } + + bool operator>(const Rational &rational) const + { + return (as_double() > rational.as_double()); + } + + int64_t numerator; + int64_t denominator; +}; + + +/*----------------------------------------------------------------*/ + +struct ProgressRange +{ + ProgressRange(int min, int max) + : progress_min(min) + , progress_max(max) + { /* nothing */ } + + int progress_min; + int progress_max; +}; + + +/*----------------------------------------------------------------*/ + +bool lines_intersect_(coord_t ax, coord_t ay, coord_t ux, coord_t uy, coord_t bx, coord_t by, coord_t vx, coord_t vy); +bool lines_intersect(double ax, double ay, double ux, double uy, double bx, double by, double vx, double vy); +bool lines_intersect_closed(double ax, double ay, double ux, double uy, double bx, double by, double vx, double vy); +bool lines_intersect_open(double ax, double ay, double ux, double uy, double bx, double by, double vx, double vy); + + +/*----------------------------------------------------------------*/ + +void introduce_DecisionBox(z3::solver &Solver, + const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + int box_size_x, + int box_size_y); + +void assume_DecisionBox(const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + int box_size_x, + int box_size_y, + z3::expr_vector &box_constraints); + +void introduce_BedBoundingBox(z3::solver &Solver, + const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + const Slic3r::Polygon &polygon, + int box_size_x, + int box_size_y); + +void assume_BedBoundingBox(const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + const Slic3r::Polygon &polygon, + int box_size_x, + int box_size_y, + z3::expr_vector &bounding_constraints); + +void introduce_BedBoundingBox(z3::solver &Solver, + const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + const Slic3r::Polygon &polygon, + int box_min_x, + int box_min_y, + int box_max_x, + int box_max_y); + +void assume_BedBoundingBox(const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + const Slic3r::Polygon &polygon, + int box_min_x, + int box_min_y, + int box_max_x, + int box_max_y, + z3::expr_vector &bounding_constraints); + +void assume_BedBoundingPolygon(z3::context &Context, + const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + const Slic3r::Polygon &polygon, + const Slic3r::Polygon &bed_bounding_polygon, + z3::expr_vector &bounding_constraints); + +void introduce_BedBoundingBox(z3::solver &Solver, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &polygons, + int box_size_x, + int box_size_y); + +void assume_BedBoundingBox(const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &polygons, + int box_size_x, + int box_size_y, + z3::expr_vector &bounding_constraints); + +void introduce_BedBoundingBox(z3::solver &Solver, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &polygons, + int box_min_x, + int box_min_y, + int box_max_x, + int box_max_y); + +void assume_BedBoundingBox(const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &polygons, + int box_min_x, + int box_min_y, + int box_max_x, + int box_max_y, + z3::expr_vector &bounding_constraints); + +void assume_ConsequentialObjectPresence(z3::context &Context, + const z3::expr_vector &dec_vars_T, + const std::vector &present, + const std::vector &missing, + z3::expr_vector &presence_constraints); + + +/*----------------------------------------------------------------*/ + +void introduce_TemporalOrdering(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_T, + int temporal_spread, + const std::vector &polygons); + +void introduce_SequentialTemporalOrderingAgainstFixed(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + int temporal_spread, + const std::vector &polygons); + +void introduce_ConsequentialTemporalOrderingAgainstFixed(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + int temporal_spread, + const std::vector &polygons); + +void introduce_ConsequentialTemporalLepoxAgainstFixed(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + int temporal_spread, + const std::vector &SEQ_UNUSED(polygons), + const std::vector &lepox_to_next, + bool trans_bed_lepox); + +/*----------------------------------------------------------------*/ + +void introduce_LineNonIntersection(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Line &line2); + +void introduce_SequentialLineNonIntersection(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2); + +void introduce_ConsequentialLineNonIntersection(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2); + +void introduce_LineNonIntersection_implicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Line &line2); + +void introduce_SequentialLineNonIntersection_implicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2); + +void introduce_ConsequentialLineNonIntersection_implicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2); + +void introduce_LineNonIntersection_explicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Line &line2); + +void introduce_LineNonIntersectionAgainstFixedLine(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Line &line2); + +void introduce_SequentialLineNonIntersectionAgainstFixedLine(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2); + +void introduce_SequentialFixedLineNonIntersectionAgainstLine(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const Rational &dec_value_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2); + +void introduce_ConsequentialLineNonIntersectionAgainstFixedLine(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2); + +void introduce_ConsequentialFixedLineNonIntersectionAgainstLine(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const Rational &dec_value_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2); + +void introduce_LineNonIntersectionAgainstFixedLine_implicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Line &line2); + +void introduce_LineNonIntersectionAgainstFixedLine_explicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Line &line2); + +void introduce_SequentialLineNonIntersectionAgainstFixedLine_implicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2); + +void introduce_SequentialFixedLineNonIntersectionAgainstLine_implicit(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const Rational &dec_value_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2); + +void introduce_ConsequentialLineNonIntersectionAgainstFixedLine_implicit(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2); + +void introduce_ConsequentialFixedLineNonIntersectionAgainstLine_implicit(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const Rational &dec_value_T1, + const z3::expr &dec_var_t1, + const Slic3r::Line &line1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const z3::expr &dec_var_t2, + const Slic3r::Line &line2); + + +/*----------------------------------------------------------------*/ + +void introduce_PointInsideHalfPlane(z3::solver &Solver, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Line &halving_line); + +void introduce_PointOutsideHalfPlane(z3::solver &Solver, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Line &halving_line); + +void introduce_PointInsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Polygon &polygon); + +void assume_PointInsidePolygon(z3::context &Context, + const z3::expr &dec_var_X, + const z3::expr &dec_var_Y, + const Slic3r::Polygon &polygon, + z3::expr_vector &constraints); + +void introduce_PointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Polygon &polygon); + +void introduce_SequentialPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon); + +void introduce_ConsequentialPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon); + +void introduce_FixedPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + double dec_value_X1, + double dec_value_Y1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Polygon &polygon); + +void introduce_FixedPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Polygon &polygon); + +void introduce_SequentialFixedPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const Rational &dec_value_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon); + +void introduce_SequentialFixedPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const z3::expr &dec_var_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon); + +void introduce_ConsequentialFixedPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const Rational &dec_value_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon); + +void introduce_ConsequentialFixedPointOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const Rational &dec_value_X1, + const Rational &dec_value_Y1, + const Rational &dec_value_T1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon); + +void introduce_PointOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + double dec_value_X2, + double dec_value_Y2, + const Slic3r::Polygon &polygon); + +void introduce_PointOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Slic3r::Polygon &polygon); + +void introduce_SequentialPointOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon); + +void introduce_SequentialPointOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const Rational &dec_value_T1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon); + +void introduce_ConsequentialPointOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon); + +void introduce_ConsequentialPointOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const Rational &dec_value_T1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon); + +void introduce_PolygonOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const Slic3r::Polygon &polygon1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Polygon &polygon2); + +void introduce_PolygonOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const Slic3r::Polygon &polygon1, + double dec_value_X2, + double dec_value_Y2, + const Slic3r::Polygon &polygon2); + +void introduce_PolygonOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const Slic3r::Polygon &polygon1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Slic3r::Polygon &polygon2); + +void introduce_SequentialPolygonOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const Slic3r::Polygon &unreachable_polygon1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2, + const Slic3r::Polygon &unreachable_polygon2); + +void introduce_SequentialPolygonOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const std::vector &unreachable_polygons1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2, + const std::vector &unreachable_polygons2); + +void introduce_SequentialPolygonOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const Slic3r::Polygon &unreachable_polygon1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon2, + const Slic3r::Polygon &unreachable_polygon2); + +void introduce_SequentialPolygonOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const std::vector &unreachable_polygons1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon2, + const std::vector &unreachable_polygons2); + +void introduce_ConsequentialPolygonOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const Slic3r::Polygon &unreachable_polygon1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2, + const Slic3r::Polygon &unreachable_polygon2); + +void introduce_ConsequentialPolygonOutsidePolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const std::vector &unreachable_polygons1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2, + const std::vector &unreachable_polygons2); + +void introduce_ConsequentialPolygonExternalPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const Slic3r::Polygon &unreachable_polygon1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2, + const Slic3r::Polygon &unreachable_polygon2); + +void introduce_ConsequentialPolygonExternalPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const std::vector &unreachable_polygons1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const z3::expr &dec_var_T2, + const Slic3r::Polygon &polygon2, + const std::vector &unreachable_polygons2); + +void introduce_ConsequentialPolygonOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const Slic3r::Polygon &unreachable_polygon1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon2, + const Slic3r::Polygon &unreachable_polygon2); + +void introduce_ConsequentialPolygonOutsideFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const std::vector &unreachable_polygons1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon2, + const std::vector &unreachable_polygons2); + +void introduce_ConsequentialPolygonExternalFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const Slic3r::Polygon &unreachable_polygon1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon2, + const Slic3r::Polygon &unreachable_polygon2); + +void introduce_ConsequentialPolygonExternalFixedPolygon(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const z3::expr &dec_var_T1, + const Slic3r::Polygon &polygon1, + const std::vector &unreachable_polygons1, + const Rational &dec_value_X2, + const Rational &dec_value_Y2, + const Rational &dec_value_T2, + const Slic3r::Polygon &polygon2, + const std::vector &unreachable_polygons2); + +void introduce_PolygonLineNonIntersection(z3::solver &Solver, + z3::context &Context, + const z3::expr &dec_var_X1, + const z3::expr &dec_var_Y1, + const Slic3r::Polygon &polygon1, + const z3::expr &dec_var_X2, + const z3::expr &dec_var_Y2, + const Slic3r::Polygon &polygon2); + + +/*----------------------------------------------------------------*/ + +void introduce_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &polygons); + +void introduce_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &polygons, + const std::vector &unreachable_polygons); + +void introduce_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + +void introduce_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &polygons, + const std::vector &unreachable_polygons); + +void introduce_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + +void introduce_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons); + +void introduce_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector &unreachable_polygons); + +void introduce_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + +void introduce_ConsequentialPolygonWeakNonoverlapping(const SolverConfiguration &solver_configuration, + z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector &unreachable_polygons); + +void introduce_ConsequentialPolygonWeakNonoverlapping(const SolverConfiguration &solver_configuration, + z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + +void introduce_PolygonStrongNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &polygons); + +bool refine_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &polygons); + +bool refine_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_values_X, + const z3::expr_vector &dec_values_Y, + const std::vector &polygons); + +bool refine_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &polygons); + +bool refine_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons); + +bool refine_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons); + +bool refine_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + +bool refine_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons); + +bool refine_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons); + +bool refine_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + + +/*----------------------------------------------------------------*/ + +void introduce_PolygonWeakNonoverlappingAgainstFixed(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_values_X, + const z3::expr_vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons); + +bool refine_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_values_X, + const z3::expr_vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons); + +bool refine_PolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons); + +bool refine_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector &unreachable_polygons); + +bool refine_SequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + +bool refine_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector &unreachable_polygons); + +bool refine_ConsequentialPolygonWeakNonoverlapping(z3::solver &Solver, + z3::context &Context, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + + +/*----------------------------------------------------------------*/ + +std::optional > check_PointsOutsidePolygons(const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + +std::optional > check_PolygonLineIntersections(const std::vector &dec_values_X, + const std::vector &dec_values_Y, + const std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + + +/*----------------------------------------------------------------*/ + +void extract_DecisionValuesFromModel(const z3::model &Model, + const string_map &dec_var_names_map, + std::vector &dec_values_X, + std::vector &dec_values_Y); + +void extract_DecisionValuesFromModel(const z3::model &Model, + z3::context &Context, + const string_map &dec_var_names_map, + z3::expr_vector &dec_values_X, + z3::expr_vector &dec_values_Y); + +void extract_DecisionValuesFromModel(const z3::model &Model, + const string_map &dec_var_names_map, + std::vector &dec_values_X, + std::vector &dec_values_Y); + +void extract_DecisionValuesFromModel(const z3::model &Model, + const string_map &dec_var_names_map, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T); + +void build_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + string_map &dec_var_names_map); + +void build_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_values_X, + z3::expr_vector &dec_values_Y, + string_map &dec_var_names_map); + +void build_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + string_map &dec_var_names_map); + +bool optimize_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const string_map &dec_var_names_map, + const std::vector &polygons); + +bool optimize_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_values_X, + z3::expr_vector &dec_values_Y, + const string_map &dec_var_names_map, + const std::vector &polygons); + +bool optimize_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const string_map &dec_var_names_map, + const std::vector &polygons); + +/*----------------------------------------------------------------*/ + +void build_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + string_map &dec_var_names_map); + +void build_SequentialWeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + const std::vector &unreachable_polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + string_map &dec_var_names_map); + +void build_SequentialWeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + string_map &dec_var_names_map); + +void build_ConsequentialWeakPolygonNonoverlapping(const SolverConfiguration &solver_configuration, + z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + const std::vector &unreachable_polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + string_map &dec_var_names_map); + +void build_ConsequentialWeakPolygonNonoverlapping(const SolverConfiguration &solver_configuration, + z3::solver &Solver, + z3::context &Context, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + z3::expr_vector &dec_vars_X, + z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + string_map &dec_var_names_map); + +bool optimize_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + z3::expr_vector &dec_values_X, + z3::expr_vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons); + +bool optimize_WeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons); + +bool optimize_SequentialWeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector &unreachable_polygons); + +bool optimize_SequentialWeakPolygonNonoverlapping(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + +bool optimize_SequentialWeakPolygonNonoverlappingCentered(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + +bool checkArea_SequentialWeakPolygonNonoverlapping(coord_t box_min_x, + coord_t box_min_y, + coord_t box_max_x, + coord_t box_max_y, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + +bool checkArea_SequentialWeakPolygonNonoverlapping(const Slic3r::Polygon &bounding_polygon, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + +bool checkExtens_SequentialWeakPolygonNonoverlapping(coord_t box_min_x, + coord_t box_min_y, + coord_t box_max_x, + coord_t box_max_y, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const std::vector &fixed, + const std::vector &undecided, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + +bool optimize_SequentialWeakPolygonNonoverlappingBinaryCentered(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + coord_t &box_half_x_min, + coord_t &box_half_y_min, + coord_t &box_half_x_max, + coord_t &box_half_y_max, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector > &unreachable_polygons); + +bool optimize_ConsequentialWeakPolygonNonoverlappingBinaryCentered(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + coord_t &box_half_x_min, + coord_t &box_half_y_min, + coord_t &box_half_x_max, + coord_t &box_half_y_max, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const ProgressRange &progress_range, + std::function progress_callback); + +bool optimize_ConsequentialWeakPolygonNonoverlappingBinaryCentered(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + BoundingBox &inner_half_box, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const ProgressRange &progress_range, + std::function progress_callback); + +bool optimize_ConsequentialWeakPolygonNonoverlappingBinaryCentered(z3::solver &Solver, + z3::context &Context, + const SolverConfiguration &solver_configuration, + Polygon &inner_half_polygon, + const z3::expr_vector &dec_vars_X, + const z3::expr_vector &dec_vars_Y, + const z3::expr_vector &dec_vars_T, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &fixed, + const std::vector &undecided, + const string_map &dec_var_names_map, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const ProgressRange &progress_range, + std::function progress_callback); + + +/*----------------------------------------------------------------*/ + +void augment_TemporalSpread(const SolverConfiguration &solver_configuration, + std::vector &dec_values_T, + const std::vector &decided_polygons); + + +bool optimize_SubglobalPolygonNonoverlapping(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + const std::vector &polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons); + +bool optimize_SubglobalSequentialPolygonNonoverlapping(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons); + +bool optimize_SubglobalSequentialPolygonNonoverlapping(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons); + +bool optimize_SubglobalSequentialPolygonNonoverlappingCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons); + +bool optimize_SubglobalSequentialPolygonNonoverlappingCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons); + +bool optimize_SubglobalSequentialPolygonNonoverlappingBinaryCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons); + +bool optimize_SubglobalSequentialPolygonNonoverlappingBinaryCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons); + + +bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector &unreachable_polygons, + const std::vector &lepox_to_next, + bool trans_bed_lepox, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons, + int objects_done, + int total_objects, + std::function progress_callback = [](int progress){}); + +bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &polygons, + const std::vector > &unreachable_polygons, + const std::vector &lepox_to_next, + bool trans_bed_lepox, + const std::vector &undecided_polygons, + std::vector &decided_polygons, + std::vector &remaining_polygons, + int &progress_object_phases_done, + int progress_total_object_phases, + std::function progress_callback = [](int progress){}); + +bool optimize_SubglobalConsequentialPolygonNonoverlappingBinaryCentered(const SolverConfiguration &solver_configuration, + std::vector &dec_values_X, + std::vector &dec_values_Y, + std::vector &dec_values_T, + const std::vector &solvable_objects, + bool trans_bed_lepox, + std::vector &decided_polygons, + std::vector &remaining_polygons, + int &progress_object_phases_done, + int progress_total_object_phases, + std::function progress_callback = [](int progress){}); + +/*----------------------------------------------------------------*/ + +} // namespace Sequential + + +/*----------------------------------------------------------------*/ + +#endif /* __SEQ_SEQUENTIAL_HPP__ */ diff --git a/src/libseqarrange/src/seq_utilities.cpp b/src/libseqarrange/src/seq_utilities.cpp new file mode 100644 index 0000000..d27b977 --- /dev/null +++ b/src/libseqarrange/src/seq_utilities.cpp @@ -0,0 +1,235 @@ +#include +#include +#include + +#include "seq_defs.hpp" + +#include "libslic3r/Geometry.hpp" +#include "libslic3r/ClipperUtils.hpp" + +#include "seq_utilities.hpp" +#include "seq_preprocess.hpp" + + +/*----------------------------------------------------------------*/ + +using namespace std; +using namespace Slic3r; + + +/*----------------------------------------------------------------*/ + +namespace Sequential +{ + + +/*----------------------------------------------------------------*/ + + +bool find_and_remove(std::string &src, const std::string &key) +{ + size_t pos = src.find(key); + + if (pos != std::string::npos) + { + src.erase(pos, key.length()); + return true; + } + return false; +} + + +std::vector load_exported_data_from_file(const std::string &filename) +{ + std::ifstream in(filename); + + if (!in) + { + throw std::runtime_error("NO EXPORTED FILE WAS FOUND"); + } + + return load_exported_data_from_stream(in); +} + + +std::vector load_exported_data_from_text(const std::string &data_text) +{ + std::istringstream iss(data_text); + + return load_exported_data_from_stream(iss); +} + + +std::vector load_exported_data_from_stream(std::istream &data_stream) +{ + std::vector objects_to_print; + + std::string line; + + while (data_stream) + { + std::getline(data_stream, line); + + if (find_and_remove(line, "OBJECT_ID")) { + objects_to_print.push_back(ObjectToPrint()); + objects_to_print.back().id = std::stoi(line); + } + if (find_and_remove(line, "TOTAL_HEIGHT")) + { + objects_to_print.back().total_height = std::stoi(line); + } + if (find_and_remove(line, "POLYGON_AT_HEIGHT")) + { + objects_to_print.back().pgns_at_height.emplace_back(std::make_pair(std::stoi(line), Polygon())); + } + if (find_and_remove(line, "POINT")) + { + std::stringstream ss(line); + std::string val; + ss >> val; + Point pt(std::stoi(val), 0); + ss >> val; + pt.y() = std::stoi(val); + objects_to_print.back().pgns_at_height.back().second.append(pt); + } + } + return objects_to_print; +} + + +int load_printer_geometry_from_file(const std::string &filename, PrinterGeometry &printer_geometry) +{ + std::ifstream in(filename); + + if (!in) + { + throw std::runtime_error("NO PRINTER GEOMETRY FILE WAS FOUND"); + } + + return load_printer_geometry_from_stream(in, printer_geometry); +} + + +int load_printer_geometry_from_text(const std::string &geometry_text, PrinterGeometry &printer_geometry) +{ + std::istringstream iss(geometry_text); + + return load_printer_geometry_from_stream(iss, printer_geometry); +} + + +int load_printer_geometry_from_stream(std::istream &geometry_stream, PrinterGeometry &printer_geometry) +{ + Polygon *current_polygon = NULL; + std::string line; + + coord_t x_size = -1; + coord_t y_size = -1; + + while (geometry_stream) + { + std::getline(geometry_stream, line); + + if (find_and_remove(line, "POLYGON_AT_HEIGHT")) + { + coord_t height = std::stoi(line); + + std::map >::iterator extruder_slice = printer_geometry.extruder_slices.find(height); + + if (extruder_slice != printer_geometry.extruder_slices.end()) + { + extruder_slice->second.push_back(Polygon()); + current_polygon = &extruder_slice->second.back(); + } + else + { + vector polygons; + polygons.push_back(Polygon()); + + current_polygon = &printer_geometry.extruder_slices.insert(std::pair(height, polygons)).first->second.back(); + } + } + else if (find_and_remove(line, "POINT")) + { + std::stringstream ss(line); + std::string val; + ss >> val; + Point pt(std::stoi(val), 0); + ss >> val; + pt.y() = std::stoi(val); + + assert(current_polygon != NULL); + current_polygon->append(pt); + } + else if (find_and_remove(line, "CONVEX_HEIGHT")) + { + std::stringstream ss(line); + std::string val; + ss >> val; + coord_t height = std::stoi(val); + + printer_geometry.convex_heights.insert(height); + } + else if (find_and_remove(line, "BOX_HEIGHT")) + { + std::stringstream ss(line); + std::string val; + ss >> val; + coord_t height = std::stoi(val); + + printer_geometry.box_heights.insert(height); + } + + else if (find_and_remove(line, "X_SIZE")) + { + std::stringstream ss(line); + std::string val; + ss >> val; + x_size = std::stoi(val); + } + else if (find_and_remove(line, "Y_SIZE")) + { + std::stringstream ss(line); + std::string val; + ss >> val; + y_size = std::stoi(val); + } + } + assert(x_size > 0 && y_size > 0); + + printer_geometry.plate = { {0, 0}, {x_size, 0}, {x_size, y_size}, {0, y_size} }; + + return 0; +} + + +void save_import_data_to_file(const std::string &filename, + const std::map &scheduled_polygons, + const map &original_index_map, + const vector &poly_positions_X, + const vector &poly_positions_Y) +{ + std::ofstream out(filename); + if (!out) + { + throw std::runtime_error("CANNOT CREATE IMPORT FILE"); + } + + for (const auto& scheduled_polygon: scheduled_polygons) + { + coord_t X, Y; + + scaleUp_PositionForSlicer(poly_positions_X[scheduled_polygon.second], + poly_positions_Y[scheduled_polygon.second], + X, + Y); + const auto& original_index = original_index_map.find(scheduled_polygon.second); + + out << original_index->second << " " << X << " " << Y << endl; + } +} + + +/*----------------------------------------------------------------*/ + +} // namespace Sequential diff --git a/src/libseqarrange/src/seq_utilities.hpp b/src/libseqarrange/src/seq_utilities.hpp new file mode 100644 index 0000000..19ca46e --- /dev/null +++ b/src/libseqarrange/src/seq_utilities.hpp @@ -0,0 +1,41 @@ +#ifndef __SEQ_UTILITIES_HPP__ +#define __SEQ_UTILITIES_HPP__ + + +/*----------------------------------------------------------------*/ + +#include "seq_sequential.hpp" +#include "libseqarrange/seq_interface.hpp" + + +/*----------------------------------------------------------------*/ + +namespace Sequential +{ + + +bool find_and_remove(std::string &src, const std::string &key); + +std::vector load_exported_data_from_file(const std::string &filename); +std::vector load_exported_data_from_text(const std::string &data_text); +std::vector load_exported_data_from_stream(std::istream &data_stream); + +int load_printer_geometry_from_file(const std::string& filename, PrinterGeometry &printer_geometry); +int load_printer_geometry_from_text(const std::string& geometry_text, PrinterGeometry &printer_geometry); +int load_printer_geometry_from_stream(std::istream& geometry_stream, PrinterGeometry &printer_geometry); + +void save_import_data_to_file(const std::string &filename, + const std::map &scheduled_polygons, + const map &original_index_map, + const vector &poly_positions_X, + const vector &poly_positions_Y); + + +/*----------------------------------------------------------------*/ + +} // namespace Sequential + + +/*----------------------------------------------------------------*/ + +#endif /* __SEQ_UTILITIES_HPP__ */ diff --git a/src/libseqarrange/src/sequential_decimator.cpp b/src/libseqarrange/src/sequential_decimator.cpp new file mode 100644 index 0000000..5a24c39 --- /dev/null +++ b/src/libseqarrange/src/sequential_decimator.cpp @@ -0,0 +1,415 @@ +#include +#include +#include + +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Geometry/ConvexHull.hpp" +#include "libslic3r/SVG.hpp" + +#include "seq_utilities.hpp" + +#include "sequential_decimator.hpp" + +/*----------------------------------------------------------------*/ + +using namespace Slic3r; +using namespace Sequential; + + +/*----------------------------------------------------------------*/ + +#define SCALE_FACTOR 50000.0 + + +/*----------------------------------------------------------------*/ + +//const Point polygon_offset_0(28000000, -16000000); // body +//const Point polygon_offset_1(-3000000, -60000000); // hose +//const Point polygon_offset_2(28000000, -16000000); // fan +//const Point polygon_offset_3(0,-24000000); // gantry +//const Point polygon_offset_4(0,0); // nozzle + +const int SEQ_QIDI_MK3S_X_SIZE = 2500; +const int SEQ_QIDI_MK3S_Y_SIZE = 2100; + + +/*----------------------------------------------------------------*/ + + +void print_IntroductoryMessage(void) +{ + printf("----------------------------------------------------------------\n"); + printf("Polygon decimation utility\n"); + printf("(C) 2024 QIDI Tech \n"); + printf("================================================================\n"); +} + + +void print_ConcludingMessage(void) +{ + printf("----------------------------------------------------------------\n"); +} + + +void print_Help(void) +{ + printf("Usage:\n"); + printf("sequential_decimator [--input-file=]\n"); + printf(" [--output-file=]\n"); + printf(" [--tolerance=]\n"); + printf(" [--x-pos= (in mm)]\n"); + printf(" [--y-pos= (in mm)]\n"); + printf(" [--x-nozzle= (in coord_t)]\n"); + printf(" [--y-nozzle= (in coord_t)]\n"); + printf(" [--help]\n"); + printf("\n"); + printf("\n"); + printf("Defaults: --input-file=arrange_data_export.txt\n"); + printf(" --output-file=arrange_data_import.txt\n"); + printf(" --x-pos='random'\n"); + printf(" --y-pos='random'\n"); + printf(" --x-nozzle=0\n"); + printf(" --y-nozzle=0\n"); + printf(" --tolerance=400000 \n"); + printf("\n"); +} + + +int parse_CommandLineParameter(const string ¶meter, CommandParameters &command_parameters) +{ + if (parameter.find("--input-file=") == 0) + { + command_parameters.input_filename = parameter.substr(13, parameter.size()); + } + else if (parameter.find("--output-file=") == 0) + { + command_parameters.output_filename = parameter.substr(14, parameter.size()); + } + else if (parameter.find("--tolerance=") == 0) + { + command_parameters.tolerance = std::atof(parameter.substr(12, parameter.size()).c_str()); + } + else if (parameter.find("--x-pos=") == 0) + { + command_parameters.x_position = std::atof(parameter.substr(8, parameter.size()).c_str()); + command_parameters.random_position = false; + + } + else if (parameter.find("--y-pos=") == 0) + { + command_parameters.y_position = std::atof(parameter.substr(8, parameter.size()).c_str()); + command_parameters.random_position = false; + } + else if (parameter.find("--x-nozzle=") == 0) + { + command_parameters.x_nozzle = std::atoi(parameter.substr(11, parameter.size()).c_str()); + + } + else if (parameter.find("--y-nozzle=") == 0) + { + command_parameters.y_nozzle = std::atoi(parameter.substr(11, parameter.size()).c_str()); + } + else if (parameter.find("--help") == 0) + { + command_parameters.help = true; + } + else + { + return -1; + } + return 0; +} + + +void save_DecimatedPolygons(const CommandParameters &command_parameters, + const std::vector &decimated_polygons) +{ + std::ofstream out(command_parameters.output_filename); + if (!out) + throw std::runtime_error("CANNOT CREATE OUTPUT FILE"); + + Point nozzle_offset(-command_parameters.x_nozzle, -command_parameters.y_nozzle); + + for (unsigned int i = 0; i < decimated_polygons.size(); ++i) + { + out << "[" << i << "]" << endl; + out << "{" << endl; + + Slic3r::Polygon shift_polygon = scaleUp_PolygonForSlicer(1, + decimated_polygons[i], + (command_parameters.x_position * SEQ_SLICER_SCALE_FACTOR) * 10, + (command_parameters.y_position * SEQ_SLICER_SCALE_FACTOR) * 10); + shift_Polygon(shift_polygon, nozzle_offset); + + for (const auto& point: shift_polygon.points) + { + out << " { " << point.x() << ", " << point.y() << "}," << endl; + } + out << "}" << endl; + } +} + + +int decimate_Polygons(const CommandParameters &command_parameters) +{ + clock_t start, finish; + + printf("Decimation ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + std::vector objects_to_print = load_exported_data_from_file(command_parameters.input_filename); + + std::vector decimated_polygons; + std::vector > unreachable_polygons; + + printf(" Decimating objects (polygons) ...\n"); + + for (unsigned int i = 0; i < objects_to_print.size(); ++i) + { + for (unsigned int j = 0; j < objects_to_print[i].pgns_at_height.size(); ++j) + { + //coord_t height = objects_to_print[i].pgns_at_height[j].first; + + if (!objects_to_print[i].pgns_at_height[j].second.points.empty()) + { + Polygon decimated_polygon; + //ground_PolygonByFirstPoint(objects_to_print[i].pgns_at_height[j].second); + + decimate_PolygonForSequentialSolver(command_parameters.tolerance, + objects_to_print[i].pgns_at_height[j].second, + decimated_polygon, + false); + + decimated_polygons.push_back(decimated_polygon); + } + } + } + printf(" Decimating objects (polygons) ... finished\n"); + + Point nozzle_offset(-command_parameters.x_nozzle, -command_parameters.y_nozzle); + + for (unsigned int i = 0; i < decimated_polygons.size(); ++i) + { + printf(" [%d]\n", i); + Slic3r::Polygon shift_polygon = decimated_polygons[i]; + shift_Polygon(shift_polygon, nozzle_offset); + + shift_polygon = scaleUp_PolygonForSlicer(1, + shift_polygon, + (command_parameters.x_position * SEQ_SLICER_SCALE_FACTOR) * 10, + (command_parameters.y_position * SEQ_SLICER_SCALE_FACTOR) * 10); + + for (const auto &point: shift_polygon.points) + { + cout << " " << point.x() << " " << point.y() << endl; + } + + BoundingBox bounding_box = get_extents(shift_polygon); + + cout << " BB" << endl; + cout << " " << bounding_box.min.x() << " " << bounding_box.min.y() << endl; + cout << " " << bounding_box.max.x() << " " << bounding_box.max.y() << endl; + cout << endl; + } + + if (command_parameters.output_filename != "") + { + save_DecimatedPolygons(command_parameters, decimated_polygons); + } + + string svg_filename = "sequential_decimator.svg"; + SVG preview_svg(svg_filename); + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE, SEQ_QIDI_MK3S_Y_SIZE}); + + printf(" Generating output SVG ...\n"); + for (unsigned int i = 0; i < decimated_polygons.size(); ++i) + { + Polygon transformed_polygon; + Polygon shift_polygon = decimated_polygons[i]; + + shift_Polygon(shift_polygon, nozzle_offset); + + if (command_parameters.random_position) + { + transformed_polygon = transform_UpsideDown(solver_configuration, + scaleUp_PolygonForSlicer(1, + shift_polygon, + (solver_configuration.plate_bounding_box.min.x() + rand() % (solver_configuration.plate_bounding_box.max.x() - solver_configuration.plate_bounding_box.min.x())) * SEQ_SLICER_SCALE_FACTOR, + (solver_configuration.plate_bounding_box.min.y() + rand() % (solver_configuration.plate_bounding_box.max.y() - solver_configuration.plate_bounding_box.min.y()) * SEQ_SLICER_SCALE_FACTOR))); + } + else + { + transformed_polygon = transform_UpsideDown(solver_configuration, + scaleUp_PolygonForSlicer(1, + shift_polygon, + (command_parameters.x_position * SEQ_SLICER_SCALE_FACTOR) * 10, + (command_parameters.y_position * SEQ_SLICER_SCALE_FACTOR) * 10)); + } + Polygon display_polygon = scaleDown_PolygonForSequentialSolver(2, transformed_polygon); + + string color; + + switch(i % 16) + { + case 0: + { + color = "green"; + break; + } + case 1: + { + color = "blue"; + break; + } + case 2: + { + color = "red"; + break; + } + case 3: + { + color = "grey"; + break; + } + case 4: + { + color = "cyan"; + break; + } + case 5: + { + color = "magenta"; + break; + } + case 6: + { + color = "yellow"; + break; + } + case 7: + { + color = "black"; + break; + } + case 8: + { + color = "indigo"; + break; + } + case 9: + { + color = "olive"; + break; + } + case 10: + { + color = "firebrick"; + break; + } + case 11: + { + color = "violet"; + break; + } + case 12: + { + color = "midnightblue"; + break; + } + case 13: + { + color = "khaki"; + break; + } + case 14: + { + color = "darkslategrey"; + break; + } + case 15: + { + color = "hotpink"; + break; + } + + default: + { + break; + } + } + + preview_svg.draw(display_polygon, color); + } + + // general plate polygons are currently not supported + assert(solver_configuration.plate_bounding_polygon.points.size() == 0); + + Polygon bed_polygon({ { solver_configuration.plate_bounding_box.min.x(), solver_configuration.plate_bounding_box.min.y() }, + { solver_configuration.plate_bounding_box.max.x(), solver_configuration.plate_bounding_box.min.y() }, + { solver_configuration.plate_bounding_box.max.x(), solver_configuration.plate_bounding_box.max.y() }, + { solver_configuration.plate_bounding_box.min.x(), solver_configuration.plate_bounding_box.max.y() } }); + + Polygon display_bed_polygon = scaleUp_PolygonForSlicer(SEQ_SVG_SCALE_FACTOR, + bed_polygon, + 0, + 0); + preview_svg.draw_outline(display_bed_polygon, "black"); + + preview_svg.Close(); + printf(" Generating output SVG ... finised\n"); + + finish = clock(); + + printf("Decimation ... finished\n"); + printf("Total CPU time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + + return 0; +} + + +/*----------------------------------------------------------------------------*/ +// main program + +int main(int argc, char **argv) +{ + int result; + CommandParameters command_parameters; + + print_IntroductoryMessage(); + + if (argc >= 1 && argc <= 10) + { + for (int i = 1; i < argc; ++i) + { + result = parse_CommandLineParameter(argv[i], command_parameters); + if (result < 0) + { + printf("Error: Cannot parse command line parameters (code = %d).\n", result); + print_Help(); + + return result; + } + } + if (command_parameters.help) + { + print_Help(); + } + else + { + result = decimate_Polygons(command_parameters); + if (result < 0) + { + return result; + } + } + } + else + { + print_Help(); + } + print_ConcludingMessage(); + + return 0; +} diff --git a/src/libseqarrange/src/sequential_decimator.hpp b/src/libseqarrange/src/sequential_decimator.hpp new file mode 100644 index 0000000..3cd275c --- /dev/null +++ b/src/libseqarrange/src/sequential_decimator.hpp @@ -0,0 +1,62 @@ +#ifndef __SEQUENTIAL_DECIMATOR_HPP__ +#define __SEQUENTIAL_DECIMATOR_HPP__ + +/*----------------------------------------------------------------*/ + +#include "seq_sequential.hpp" +#include "seq_preprocess.hpp" +#include "libseqarrange/seq_interface.hpp" + + +/*----------------------------------------------------------------*/ + +const double SEQ_DECIMATION_TOLERANCE = 400000.0; + + +/*----------------------------------------------------------------*/ + +struct CommandParameters +{ + CommandParameters() + : tolerance(SEQ_DECIMATION_TOLERANCE) + , input_filename("arrange_data_export.txt") + , output_filename("arrange_data_import.txt") + , x_position(0) + , y_position(0) + , random_position(true) + , help(false) + , x_nozzle(0) + , y_nozzle(0) + { + /* nothing */ + } + + double tolerance; + + string input_filename; + string output_filename; + + double x_position; + double y_position; + bool random_position; + + coord_t x_nozzle; + coord_t y_nozzle; + + bool help; +}; + + +/*----------------------------------------------------------------------------*/ + +void print_IntroductoryMessage(void); +void print_ConcludingMessage(void); +void print_Help(void); + +int parse_CommandLineParameter(const string ¶meter, CommandParameters ¶meters); +int decimate_Polygons(const CommandParameters &command_parameters); + + +/*----------------------------------------------------------------*/ + +#endif /* __SEQUENTIAL_DECIMATOR_HPP__ */ diff --git a/src/libseqarrange/test/qidiparts.cpp b/src/libseqarrange/test/qidiparts.cpp new file mode 100644 index 0000000..e21ee0d --- /dev/null +++ b/src/libseqarrange/test/qidiparts.cpp @@ -0,0 +1,5981 @@ +#include "qidiparts.hpp" + +const TestData QIDI_PART_POLYGONS = +{ + { + {-5000000, 8954050}, + {5000000, 8954050}, + {5000000, -45949}, + {4972609, -568550}, + {3500000, -8954050}, + {-3500000, -8954050}, + {-4972609, -568550}, + {-5000000, -45949}, + {-5000000, 8954050}, + }, + { + {-63750000, -8000000}, + {-54750000, 46000000}, + {50750000, 46000000}, + {63750000, 33000000}, + {63750000, -46000000}, + {-54750000, -46000000}, + {-63750000, -28000000}, + {-63750000, -8000000}, + }, + { + {-52750000, 41512348}, + {-31250000, 45987651}, + {52750000, 45987651}, + {52750000, -45987651}, + {-52750000, -45987651}, + {-52750000, 41512348}, + }, + { + {-3900000, 14000000}, + {-2167950, 14000000}, + {1721454, 7263400}, + {3828529, 3613790}, + {3838809, 3582149}, + {3871560, 3270569}, + {3900000, 3000000}, + {3500000, -3000000}, + {3471560, -3270565}, + {3447549, -3498986}, + {3292510, -3976167}, + {3099999, -4512949}, + {2530129, -5500000}, + {807565, -8483570}, + {-2377349, -14000000}, + {-3900000, -14000000}, + {-3900000, 14000000}, + }, + { + {-31750000, -1000000}, + {-25250000, 40500000}, + {-18250000, 47500000}, + {10750000, 47500000}, + {16750000, 41500000}, + {31750000, -37000000}, + {31750000, -43857898}, + {28107900, -47500000}, + {18392099, -47500000}, + {-20750000, -46500000}, + {-31750000, -4000000}, + {-31750000, -1000000}, + }, + { + {-34625000, -14265399}, + {-10924999, 24875000}, + {33325000, 24875000}, + {37575000, 20625000}, + {37575000, 17625000}, + {26575000, -24875000}, + {-8924999, -24875000}, + {-34625000, -24484600}, + {-37575000, -19375000}, + {-34625000, -14265399}, + }, + { + {-14000000, 9000000}, + {-11000000, 17000000}, + {14000000, 17000000}, + {14000000, -17000000}, + {-11000000, -17000000}, + {-14000000, -8000000}, + {-14000000, 9000000}, + }, + { + {-5300000, 2227401}, + {-237800, 5150001}, + {5299999, 5150001}, + {5299999, 650001}, + {4699999, -5149997}, + {-5300000, -5149997}, + {-5300000, 2227401}, + }, + { + {-12000000, 18000000}, + {12000000, 18000000}, + {12000000, -18000000}, + {-12000000, -18000000}, + {-12000000, 18000000}, + }, + { + {-18000000, -1000000}, + {-15000000, 22000000}, + {-11000000, 26000000}, + {11000000, 26000000}, + {15000000, 22000000}, + {18000000, -1000000}, + {18000000, -26000000}, + {-18000000, -26000000}, + {-18000000, -1000000}, + }, + { + {-77500000, 30000000}, + {-72500000, 35000000}, + {72500000, 35000000}, + {77500000, 30000000}, + {77500000, -32928901}, + {75428901, -35000000}, + {-75428901, -35000000}, + {-77500000, -32928901}, + {-77500000, 30000000}, + }, + { + {-9945219, -3065619}, + {-9781479, -2031780}, + {-9510560, -1020730}, + {-9135450, -43529}, + {-2099999, 14110899}, + {2099999, 14110899}, + {9135450, -43529}, + {9510560, -1020730}, + {9781479, -2031780}, + {9945219, -3065619}, + {10000000, -4110899}, + {9945219, -5156179}, + {9781479, -6190019}, + {9510560, -7201069}, + {9135450, -8178270}, + {8660249, -9110899}, + {8090169, -9988750}, + {7431449, -10802209}, + {6691309, -11542349}, + {5877850, -12201069}, + {5000000, -12771149}, + {4067369, -13246350}, + {3090169, -13621459}, + {2079119, -13892379}, + {1045279, -14056119}, + {0, -14110899}, + {-1045279, -14056119}, + {-2079119, -13892379}, + {-3090169, -13621459}, + {-4067369, -13246350}, + {-5000000, -12771149}, + {-5877850, -12201069}, + {-6691309, -11542349}, + {-7431449, -10802209}, + {-8090169, -9988750}, + {-8660249, -9110899}, + {-9135450, -8178270}, + {-9510560, -7201069}, + {-9781479, -6190019}, + {-9945219, -5156179}, + {-10000000, -4110899}, + {-9945219, -3065619}, + }, + { + {-34192394, -5192389}, + {-31499996, 39000000}, + {-8183795, 47668998}, + {-6769596, 47668998}, + {-4648197, 45547698}, + {34192394, 6707109}, + {34192394, 5192389}, + {31500003, -39000000}, + {8183803, -47668998}, + {6769603, -47668998}, + {4648202, -45547698}, + {-32474895, -8424619}, + {-34192394, -6707109}, + {-34192394, -5192389}, + }, + { + {-23475500, -11910099}, + {-18000000, 8217699}, + {-11139699, 20100000}, + {-10271400, 20899999}, + {9532010, 20899999}, + {11199999, 20100000}, + {18500000, 8600000}, + {23475500, -11910099}, + {23799999, -14899999}, + {23706600, -15788900}, + {23668899, -16147499}, + {23281299, -17340400}, + {22654100, -18426700}, + {21814800, -19358900}, + {20799999, -20096199}, + {19654100, -20606300}, + {18427200, -20867099}, + {17799999, -20899999}, + {-17799999, -20899999}, + {-18427200, -20867099}, + {-19654100, -20606300}, + {-20799999, -20096199}, + {-21814800, -19358900}, + {-22654100, -18426700}, + {-23281299, -17340400}, + {-23668899, -16147499}, + {-23799999, -14899999}, + {-23475500, -11910099}, + }, + { + {-32000000, 10000000}, + {-31934440, 10623733}, + {-31740640, 11220210}, + {-31427049, 11763360}, + {-31007389, 12229430}, + {-30500000, 12598079}, + {-29927051, 12853170}, + {-29313585, 12983570}, + {16000000, 16000000}, + {26000000, 16000000}, + {31007400, 12229430}, + {31427101, 11763360}, + {31740600, 11220210}, + {31934398, 10623733}, + {32000000, 10000000}, + {32000000, -13000000}, + {31934398, -13623699}, + {31740600, -14220199}, + {31427101, -14763399}, + {31007400, -15229400}, + {30500000, -15598100}, + {29927101, -15853200}, + {29313598, -15983600}, + {29000000, -16000000}, + {-28000000, -16000000}, + {-29313585, -15983600}, + {-29927051, -15853200}, + {-30500000, -15598100}, + {-31007389, -15229400}, + {-31427049, -14763399}, + {-31740640, -14220199}, + {-31934440, -13623699}, + {-32000000, -13000000}, + {-32000000, 10000000}, + }, + { + {-36133789, -46431022}, + {-36040100, -46171817}, + {-35852722, -45653411}, + {2200073, 59616485}, + {12112792, 87039184}, + {14274505, 93019332}, + {14382049, 93291641}, + {14508483, 93563430}, + {14573425, 93688369}, + {14654052, 93832443}, + {14818634, 94096328}, + {14982757, 94327621}, + {15001708, 94352630}, + {15202392, 94598999}, + {15419342, 94833160}, + {15497497, 94910552}, + {15650848, 95053039}, + {15894866, 95256866}, + {16104309, 95412185}, + {16149047, 95443206}, + {16410888, 95611038}, + {16677795, 95759750}, + {16782348, 95812332}, + {16947143, 95889144}, + {17216400, 95999465}, + {17483123, 96091293}, + {17505554, 96098251}, + {17745178, 96165542}, + {18000671, 96223373}, + {18245880, 96265884}, + {18484039, 96295257}, + {18976715, 96319580}, + {31135131, 96319580}, + {31697082, 96287902}, + {31746368, 96282104}, + {32263000, 96190719}, + {32338623, 96172576}, + {32821411, 96026641}, + {32906188, 95995391}, + {33360565, 95797012}, + {33443420, 95754882}, + {33869171, 95505874}, + {33900756, 95485122}, + {34136413, 95318618}, + {34337127, 95159790}, + {34377288, 95125930}, + {34619628, 94905410}, + {34756286, 94767364}, + {34859008, 94656143}, + {35090606, 94378067}, + {35120849, 94338546}, + {35309295, 94072113}, + {35434875, 93871475}, + {35510070, 93740310}, + {35688232, 93385772}, + {35699096, 93361679}, + {35839782, 93012557}, + {35905487, 92817459}, + {35961578, 92625488}, + {36048004, 92249023}, + {36051574, 92229934}, + {36108856, 91831405}, + {36122985, 91667816}, + {36133789, 91435317}, + {36129669, 91085830}, + {36127685, 91046661}, + {36092742, 90669830}, + {36069946, 90514739}, + {36031829, 90308425}, + {35948211, 89965225}, + {34482635, 84756820}, + {27911407, 61403976}, + {-5872558, -58657440}, + {-14243621, -88406509}, + {-14576812, -89590599}, + {-15421997, -92594200}, + {-15657684, -93431732}, + {-16038940, -93720520}, + {-16420196, -94009307}, + {-17182708, -94586875}, + {-18834838, -95838272}, + {-19470275, -96319580}, + {-21368133, -96319580}, + {-22763854, -96319534}, + {-29742462, -96319274}, + {-32533935, -96319168}, + {-36133789, -54619018}, + {-36133789, -46431022}, + }, + { + {-26000000, 25500000}, + {-6500000, 45000000}, + {17499998, 45000000}, + {23966310, 38533699}, + {26000000, 36500000}, + {26000000, -19000000}, + {25950000, -24500000}, + {17000000, -42214698}, + {14300000, -45000000}, + {-14299999, -45000000}, + {-17500000, -41714698}, + {-23400001, -24500000}, + {-26000000, -10464000}, + {-26000000, 25500000}, + }, + { + {-26000000, 16636100}, + {-25072200, 18777799}, + {-16500000, 35299999}, + {-15050000, 36750000}, + {13550000, 36750000}, + {15000000, 35299999}, + {26000000, 16045200}, + {26000000, -2750000}, + {16500000, -34507900}, + {14840600, -36167301}, + {14257900, -36750000}, + {-14257900, -36750000}, + {-16500000, -34507900}, + {-26000000, -2750000}, + {-26000000, 16636100}, + }, + { + {-18062349, 18950099}, + {4644938, 20049900}, + {6230361, 20049900}, + {7803279, 19851200}, + {9338899, 19456899}, + {10812990, 18873300}, + {12202310, 18109500}, + {13484951, 17177600}, + {14640670, 16092300}, + {15651250, 14870700}, + {16500749, 13532100}, + {17175849, 12097599}, + {17665750, 10589700}, + {17962850, 9032400}, + {18062349, 7450099}, + {17962850, 5867799}, + {15810750, -11007740}, + {15683750, -11727769}, + {15506849, -12437200}, + {15280929, -13132559}, + {15007040, -13810470}, + {14686531, -14467609}, + {14320949, -15100799}, + {13912099, -15706950}, + {13461959, -16283100}, + {12972730, -16826450}, + {12446790, -17334339}, + {11886699, -17804309}, + {11295190, -18234069}, + {10675149, -18621520}, + {10029590, -18964771}, + {9361650, -19262149}, + {8674600, -19512220}, + {7971780, -19713699}, + {7256609, -19865798}, + {6532589, -19967498}, + {5803222, -20018501}, + {5437650, -20024900}, + {-1062349, -20049900}, + {-16562349, -20049900}, + {-18062349, -18549900}, + {-18062349, 18950099}, + }, + { + {-18062349, 41299900}, + {-1062349, 41299900}, + {15280929, -8117440}, + {15506849, -8812799}, + {15683750, -9522230}, + {15810750, -10242259}, + {17962850, -27117799}, + {18062349, -28700099}, + {17962850, -30282400}, + {17665750, -31839700}, + {17175849, -33347599}, + {16500749, -34782100}, + {15651250, -36120700}, + {14640670, -37342300}, + {13484951, -38427600}, + {12202310, -39359500}, + {10812990, -40123298}, + {9338899, -40706901}, + {7803279, -41101200}, + {6230361, -41299900}, + {4644938, -41299900}, + {-18062349, -40200099}, + {-18062349, 41299900}, + }, + { + {-11750000, 13057900}, + {-9807860, 15000000}, + {4392139, 24000000}, + {11750000, 24000000}, + {11750000, -24000000}, + {4392139, -24000000}, + {-9807860, -15000000}, + {-11750000, -13057900}, + {-11750000, 13057900}, + }, + { + {-12500000, 17500000}, + {12500000, 17500000}, + {12500000, -17500000}, + {-12500000, -17500000}, + {-12500000, 17500000}, + }, + { + {-23500000, 11500000}, + {-13857859, 21000000}, + {-11000000, 21000000}, + {18500000, 500000}, + {23500000, -4500000}, + {23500000, -19500000}, + {22000000, -21000000}, + {-23500000, -21000000}, + {-23500000, 11500000}, + }, + { + {-13000000, 5250000}, + {-4000000, 6750000}, + {4000000, 6750000}, + {13000000, 5250000}, + {13000000, 838459}, + {11376299, -1973939}, + {10350899, -3750000}, + {8618800, -6750000}, + {-8498290, -6750000}, + {-13000000, 1047180}, + {-13000000, 5250000}, + }, + { + {-25000000, 50500000}, + {-21500000, 54000000}, + {18286800, 54000000}, + {25000000, 47286800}, + {25000000, -47286800}, + {18286800, -54000000}, + {-21500000, -54000000}, + {-25000000, -50500000}, + {-25000000, 50500000}, + }, + { + {-19000000, 46000000}, + {-16799999, 46000000}, + {14000000, 34000000}, + {19000000, 29000000}, + {19000000, -29000000}, + {14000000, -34000000}, + {-16799999, -46000000}, + {-19000000, -46000000}, + {-19000000, 46000000}, + }, + { + {-7956170, 836226}, + {-7825180, 1663290}, + {-7767529, 1914530}, + {-7608449, 2472140}, + {-7308360, 3253890}, + {-7083650, 3717780}, + {-6928199, 4000000}, + {-6472139, 4702280}, + {-5988090, 5304979}, + {-5945159, 5353040}, + {-5353040, 5945159}, + {-4702280, 6472139}, + {-4544519, 6583869}, + {-4000000, 6928199}, + {-3253890, 7308360}, + {-2836839, 7480130}, + {-2472140, 7608449}, + {-1663290, 7825180}, + {-964293, 7941669}, + {-836226, 7956170}, + {0, 8000000}, + {836226, 7956170}, + {964293, 7941669}, + {1663290, 7825180}, + {2472140, 7608449}, + {2836839, 7480130}, + {3253890, 7308360}, + {4000000, 6928199}, + {4544519, 6583869}, + {4702280, 6472139}, + {5353040, 5945159}, + {5945159, 5353040}, + {5988090, 5304979}, + {6472139, 4702280}, + {6928199, 4000000}, + {7083650, 3717780}, + {7308360, 3253890}, + {7608449, 2472140}, + {7767529, 1914530}, + {7825180, 1663290}, + {7956170, 836226}, + {8000000, 0}, + {7956170, -836226}, + {7825180, -1663290}, + {7767529, -1914530}, + {7608449, -2472140}, + {7308360, -3253890}, + {7083650, -3717780}, + {6928199, -4000000}, + {6472139, -4702280}, + {5988090, -5304979}, + {5945159, -5353040}, + {5353040, -5945159}, + {4702280, -6472139}, + {4544519, -6583869}, + {4000000, -6928199}, + {3253890, -7308360}, + {2836839, -7480130}, + {2472140, -7608449}, + {1663290, -7825180}, + {964293, -7941669}, + {836226, -7956170}, + {0, -8000000}, + {-836226, -7956170}, + {-964293, -7941669}, + {-1663290, -7825180}, + {-2472140, -7608449}, + {-2836839, -7480130}, + {-3253890, -7308360}, + {-4000000, -6928199}, + {-4544519, -6583869}, + {-4702280, -6472139}, + {-5353040, -5945159}, + {-5945159, -5353040}, + {-5988090, -5304979}, + {-6472139, -4702280}, + {-6928199, -4000000}, + {-7083650, -3717780}, + {-7308360, -3253890}, + {-7608449, -2472140}, + {-7767529, -1914530}, + {-7825180, -1663290}, + {-7956170, -836226}, + {-8000000, 0}, + {-7956170, 836226}, + }, +}; + +const TestData QIDI_STEGOSAUR_POLYGONS = +{ + { + {113210205, 107034095}, + {113561798, 109153793}, + {113750099, 109914001}, + {114396499, 111040199}, + {114599197, 111321998}, + {115570404, 112657096}, + {116920097, 114166595}, + {117630599, 114609390}, + {119703704, 115583900}, + {120559494, 115811996}, + {121045410, 115754493}, + {122698097, 115526496}, + {123373001, 115370193}, + {123482406, 115315689}, + {125664199, 114129798}, + {125920303, 113968193}, + {128551208, 111866195}, + {129075592, 111443199}, + {135044692, 106572608}, + {135254898, 106347694}, + {135415100, 106102897}, + {136121704, 103779891}, + {136325103, 103086303}, + {136690093, 101284896}, + {136798309, 97568496}, + {136798309, 97470397}, + {136787399, 97375297}, + {136753295, 97272102}, + {136687988, 97158699}, + {136539794, 96946899}, + {135526702, 95550994}, + {135388488, 95382293}, + {135272491, 95279098}, + {135214904, 95250595}, + {135122894, 95218002}, + {134966705, 95165191}, + {131753997, 94380798}, + {131226806, 94331001}, + {129603393, 94193893}, + {129224197, 94188003}, + {127874107, 94215103}, + {126812797, 94690200}, + {126558197, 94813896}, + {118361801, 99824195}, + {116550796, 101078796}, + {116189704, 101380493}, + {114634002, 103027999}, + {114118103, 103820297}, + {113399200, 105568000}, + {113201705, 106093597}, + {113210205, 107034095}, + }, + { + {77917999, 130563003}, + {77926300, 131300903}, + {77990196, 132392700}, + {78144195, 133328002}, + {78170593, 133427093}, + {78235900, 133657592}, + {78799598, 135466705}, + {78933296, 135832397}, + {79112899, 136247604}, + {79336303, 136670898}, + {79585197, 137080596}, + {79726303, 137309005}, + {79820297, 137431900}, + {79942199, 137549407}, + {90329193, 145990203}, + {90460197, 146094390}, + {90606399, 146184509}, + {90715194, 146230010}, + {90919601, 146267211}, + {142335296, 153077697}, + {143460296, 153153594}, + {143976593, 153182189}, + {145403991, 153148605}, + {145562301, 153131195}, + {145705993, 153102905}, + {145938796, 153053192}, + {146134094, 153010101}, + {146483184, 152920196}, + {146904693, 152806396}, + {147180099, 152670196}, + {147357788, 152581695}, + {147615295, 152423095}, + {147782287, 152294708}, + {149281799, 150908386}, + {149405303, 150784912}, + {166569305, 126952499}, + {166784301, 126638099}, + {166938491, 126393699}, + {167030899, 126245101}, + {167173004, 126015899}, + {167415298, 125607200}, + {167468292, 125504699}, + {167553100, 125320899}, + {167584594, 125250694}, + {167684997, 125004394}, + {167807098, 124672401}, + {167938995, 124255203}, + {168052307, 123694000}, + {170094100, 112846900}, + {170118408, 112684204}, + {172079101, 88437797}, + {172082000, 88294403}, + {171916290, 82827606}, + {171911590, 82705703}, + {171874893, 82641906}, + {169867004, 79529907}, + {155996795, 58147998}, + {155904998, 58066299}, + {155864791, 58054199}, + {134315704, 56830902}, + {134086486, 56817901}, + {98200096, 56817798}, + {97838195, 56818599}, + {79401695, 56865097}, + {79291297, 56865501}, + {79180694, 56869499}, + {79058799, 56885097}, + {78937301, 56965301}, + {78324691, 57374599}, + {77932998, 57638401}, + {77917999, 57764297}, + {77917999, 130563003}, + }, + { + {75566848, 109289947}, + {75592651, 109421951}, + {75644248, 109534446}, + {95210548, 141223846}, + {95262649, 141307449}, + {95487854, 141401443}, + {95910850, 141511642}, + {96105651, 141550338}, + {106015045, 142803451}, + {106142852, 142815155}, + {166897460, 139500244}, + {167019348, 139484741}, + {168008239, 138823043}, + {168137542, 138735153}, + {168156250, 138616851}, + {173160751, 98882049}, + {174381546, 87916046}, + {174412246, 87579048}, + {174429443, 86988746}, + {174436141, 86297348}, + {174438949, 84912048}, + {174262939, 80999145}, + {174172546, 80477546}, + {173847549, 79140846}, + {173623840, 78294349}, + {173120239, 76485046}, + {173067138, 76300544}, + {173017852, 76137542}, + {172941543, 75903045}, + {172892547, 75753143}, + {172813537, 75533348}, + {172758453, 75387046}, + {172307556, 74196746}, + {171926544, 73192848}, + {171891448, 73100448}, + {171672546, 72524147}, + {171502441, 72085144}, + {171414459, 71859146}, + {171294250, 71552352}, + {171080139, 71019744}, + {171039245, 70928146}, + {170970550, 70813346}, + {170904235, 70704040}, + {170786254, 70524353}, + {168063247, 67259048}, + {167989547, 67184844}, + {83427947, 67184844}, + {78360847, 67201248}, + {78238845, 67220550}, + {78151550, 67350547}, + {77574554, 68220550}, + {77494949, 68342651}, + {77479949, 68464546}, + {75648345, 106513351}, + {75561050, 109165740}, + {75566848, 109289947}, + }, + { + {75619415, 108041595}, + {83609863, 134885772}, + {83806945, 135450820}, + {83943908, 135727371}, + {84799934, 137289794}, + {86547897, 140033782}, + {86674118, 140192962}, + {86810661, 140364715}, + {87045211, 140619918}, + {88187042, 141853240}, + {93924575, 147393783}, + {94058013, 147454803}, + {111640083, 153754562}, + {111762550, 153787933}, + {111975250, 153835311}, + {112127426, 153842803}, + {116797996, 154005157}, + {116969688, 154010681}, + {117141731, 154005935}, + {117333145, 153988037}, + {118007507, 153919952}, + {118159675, 153902130}, + {118931480, 153771942}, + {120878150, 153379089}, + {121172164, 153319259}, + {122074508, 153034362}, + {122260681, 152970367}, + {122313438, 152949584}, + {130755096, 149423736}, + {130996063, 149316818}, + {138893524, 144469665}, + {138896423, 144466918}, + {169883666, 97686134}, + {170115036, 96518981}, + {170144317, 96365257}, + {174395645, 67672065}, + {174396560, 67664222}, + {174288452, 66839241}, + {174170364, 66096923}, + {174112731, 65952033}, + {174021377, 65823486}, + {173948608, 65743225}, + {173863830, 65654769}, + {170408340, 63627494}, + {170004867, 63394714}, + {169585632, 63194389}, + {169441162, 63137046}, + {168944274, 62952133}, + {160605072, 60214218}, + {160331573, 60126396}, + {159674743, 59916877}, + {150337249, 56943778}, + {150267730, 56922073}, + {150080139, 56864868}, + {149435333, 56676422}, + {149310241, 56640579}, + {148055419, 56285041}, + {147828796, 56230949}, + {147598205, 56181800}, + {147149963, 56093917}, + {146834457, 56044700}, + {146727966, 56028717}, + {146519729, 56004882}, + {146328521, 55989326}, + {146170684, 55990036}, + {146151321, 55990745}, + {145800170, 56003616}, + {145639526, 56017753}, + {145599426, 56022491}, + {145481338, 56039184}, + {145389556, 56052757}, + {145325134, 56062591}, + {145176574, 56086135}, + {145017272, 56113922}, + {107163085, 63504539}, + {101013870, 65454101}, + {100921798, 65535285}, + {95362182, 74174079}, + {75652366, 107803443}, + {75635391, 107834983}, + {75628814, 107853294}, + {75603431, 107933692}, + {75619415, 108041595}, + }, + { + {83617141, 120264900}, + {84617370, 126416427}, + {84648635, 126601341}, + {84693695, 126816085}, + {84762496, 127082641}, + {84772140, 127117034}, + {84860748, 127391693}, + {84927398, 127550239}, + {85072967, 127789642}, + {85155151, 127908851}, + {86745422, 130042907}, + {86982666, 130317489}, + {89975143, 133230743}, + {90091384, 133338500}, + {96260833, 138719818}, + {96713928, 139103668}, + {98139297, 140307388}, + {102104766, 143511505}, + {102142089, 143536468}, + {102457626, 143735107}, + {103386764, 144312988}, + {103845001, 144579177}, + {104139175, 144737136}, + {104551254, 144932250}, + {104690155, 144985778}, + {104844238, 145010009}, + {105020034, 145010375}, + {128999633, 144082305}, + {129096542, 144076141}, + {133932327, 143370178}, + {134130615, 143326751}, + {134281250, 143289520}, + {135247116, 142993438}, + {150774948, 137828704}, + {150893478, 137786178}, + {151350921, 137608901}, + {159797760, 134318115}, + {159979827, 134244384}, + {159988128, 134240997}, + {160035186, 134221633}, + {160054962, 134211486}, + {160168762, 134132736}, + {160181228, 134121047}, + {160336425, 133961502}, + {160689147, 133564331}, + {161446258, 132710739}, + {163306427, 130611648}, + {164845474, 128873855}, + {165270233, 128393600}, + {165281478, 128380706}, + {165300598, 128358673}, + {165303497, 128355194}, + {166411590, 122772674}, + {166423767, 122708648}, + {164745605, 66237312}, + {164740341, 66193061}, + {164721755, 66082092}, + {164721160, 66078750}, + {164688476, 65914146}, + {164668426, 65859436}, + {164563110, 65765937}, + {164431152, 65715034}, + {163997619, 65550788}, + {163946426, 65531440}, + {162998107, 65173629}, + {162664978, 65049140}, + {162482696, 64991668}, + {162464660, 64989639}, + {148029083, 66896141}, + {147862396, 66932853}, + {130087829, 73341102}, + {129791564, 73469726}, + {100590927, 90307685}, + {100483535, 90373847}, + {100364990, 90458930}, + {96447448, 93276664}, + {95179656, 94189010}, + {93692718, 95260208}, + {87904327, 99430885}, + {87663711, 99606147}, + {87576202, 99683990}, + {87498199, 99801719}, + {85740264, 104173728}, + {85538925, 104710494}, + {84786132, 107265830}, + {84635955, 107801383}, + {84619506, 107868064}, + {84518463, 108287200}, + {84456848, 108613471}, + {84419158, 108826194}, + {84375244, 109093818}, + {84329818, 109435180}, + {84249862, 110179664}, + {84218429, 110572166}, + {83630020, 117995208}, + {83595535, 118787673}, + {83576217, 119290679}, + {83617141, 120264900}, + }, + { + {91735549, 117640846}, + {91748252, 117958145}, + {91823547, 118515449}, + {92088752, 119477249}, + {97995346, 140538452}, + {98031051, 140660446}, + {98154449, 141060241}, + {98179855, 141133758}, + {98217056, 141232849}, + {98217147, 141233047}, + {98269256, 141337051}, + {98298950, 141387954}, + {98337753, 141445755}, + {99455047, 142984451}, + {99656250, 143247344}, + {102567855, 146783752}, + {102685150, 146906845}, + {102828948, 147031250}, + {102972457, 147120452}, + {103676147, 147539642}, + {103758956, 147586151}, + {103956756, 147682144}, + {104479949, 147931457}, + {104744453, 148044143}, + {104994750, 148123443}, + {105375648, 148158645}, + {109266250, 148178253}, + {109447753, 148169052}, + {109693649, 148129150}, + {113729949, 147337448}, + {113884552, 147303054}, + {115155349, 146956146}, + {117637145, 146174346}, + {154694046, 134048049}, + {156979949, 133128555}, + {157076843, 133059356}, + {157125045, 133001449}, + {157561340, 132300750}, + {157865753, 131795959}, + {157923156, 131667358}, + {158007049, 131297653}, + {158112747, 130777053}, + {158116653, 130640853}, + {158268951, 119981643}, + {158260040, 119824752}, + {158229949, 119563751}, + {149914047, 73458648}, + {149877548, 73331748}, + {144460754, 66413558}, + {144230545, 66153152}, + {144128051, 66075057}, + {143974853, 65973152}, + {142812744, 65353149}, + {141810943, 64837249}, + {141683349, 64805152}, + {141505157, 64784652}, + {108214355, 61896251}, + {107826354, 61866352}, + {107072151, 61821750}, + {106938850, 61873550}, + {106584251, 62055152}, + {106419952, 62147548}, + {100459152, 65546951}, + {100343849, 65615150}, + {100198852, 65716949}, + {99825149, 65979751}, + {94619247, 70330352}, + {94492355, 70480850}, + {94445846, 70547355}, + {94425354, 70588752}, + {94379753, 70687652}, + {94110252, 71443450}, + {94095252, 71569053}, + {91737251, 117308746}, + {91731048, 117430946}, + {91735549, 117640846}, + }, + { + {108231399, 111763748}, + {108335403, 111927955}, + {108865203, 112754745}, + {109206703, 113283851}, + {127117500, 125545951}, + {127212097, 125560951}, + {127358497, 125563652}, + {131348007, 125551147}, + {131412002, 125550849}, + {131509506, 125535446}, + {131579391, 125431343}, + {132041000, 124735656}, + {132104690, 124637847}, + {144108505, 100950546}, + {144120605, 100853042}, + {144123291, 100764648}, + {144122695, 100475143}, + {144086898, 85637748}, + {144083602, 85549346}, + {144071105, 85451843}, + {144007003, 85354545}, + {143679595, 84864547}, + {143468597, 84551048}, + {143367889, 84539146}, + {109847702, 84436347}, + {109684700, 84458953}, + {105946502, 89406143}, + {105915901, 91160446}, + {105880905, 93187744}, + {105876701, 93441345}, + {108231399, 111763748}, + }, + { + {102614700, 117684249}, + {102675102, 118074157}, + {102888999, 118743148}, + {103199707, 119517555}, + {103446800, 120099655}, + {103488204, 120193450}, + {104063903, 121373947}, + {104535499, 122192245}, + {104595802, 122295249}, + {104663002, 122402854}, + {104945701, 122854858}, + {105740501, 124038848}, + {106809700, 125479354}, + {107564399, 126380050}, + {108116203, 126975646}, + {123724700, 142516540}, + {124938400, 143705444}, + {127919601, 146599243}, + {128150894, 146821456}, + {128251602, 146917251}, + {128383605, 147041839}, + {128527709, 147176147}, + {128685699, 147321456}, + {128861007, 147481246}, + {132825103, 151046661}, + {133005493, 151205657}, + {133389007, 151488143}, + {133896499, 151858062}, + {134172302, 151991546}, + {134375000, 152063140}, + {135316101, 152300949}, + {136056304, 152220947}, + {136242706, 152186843}, + {136622207, 152016448}, + {136805404, 151908355}, + {147099594, 145766845}, + {147246704, 144900756}, + {147387603, 144048461}, + {144353698, 99345855}, + {144333801, 99232254}, + {144244598, 98812850}, + {144228698, 98757858}, + {144174606, 98616455}, + {133010101, 72396743}, + {132018905, 70280853}, + {130667404, 67536949}, + {129167297, 64854446}, + {128569198, 64098350}, + {124458503, 59135948}, + {124260597, 58946949}, + {123908706, 58658851}, + {123460098, 58327850}, + {122674499, 57840648}, + {122041801, 57712150}, + {121613403, 57699047}, + {121359901, 57749351}, + {121123199, 57826450}, + {120953498, 57882247}, + {120431701, 58198547}, + {120099205, 58599349}, + {119892303, 58903049}, + {102835296, 115179351}, + {102686599, 115817245}, + {102612396, 116540557}, + {102614700, 117684249}, + }, + { + {98163757, 71203430}, + {98212463, 73314544}, + {98326538, 74432693}, + {98402908, 75169799}, + {98524154, 76328353}, + {99088806, 79911361}, + {99304885, 80947769}, + {100106689, 84244186}, + {100358123, 85080337}, + {101715545, 89252807}, + {101969528, 89987213}, + {107989440, 106391418}, + {126299575, 140277343}, + {127061813, 141486663}, + {127405746, 141872253}, + {127846908, 142318450}, + {130818496, 145301574}, + {134366424, 148100921}, + {135308380, 148798828}, + {135745666, 149117523}, + {136033020, 149251800}, + {136500579, 149387725}, + {136662719, 149418395}, + {136973922, 149474822}, + {137184890, 149484375}, + {137623748, 149434356}, + {137830810, 149355072}, + {138681732, 148971343}, + {139374465, 148463409}, + {139589187, 148264312}, + {139809707, 148010711}, + {139985610, 147685028}, + {140196029, 147284973}, + {140355834, 146978668}, + {142079666, 142575622}, + {146702194, 129469726}, + {151285888, 113275238}, + {151543731, 112046264}, + {151701629, 110884704}, + {151837020, 108986206}, + {151837097, 107724029}, + {151760101, 106529205}, + {151581970, 105441925}, + {151577301, 105413757}, + {151495269, 105014709}, + {151393142, 104551513}, + {151058502, 103296112}, + {150705520, 102477264}, + {150137725, 101686370}, + {149427032, 100938537}, + {102979965, 60772064}, + {101930953, 60515609}, + {101276748, 60634414}, + {100717803, 60918136}, + {100125732, 61584625}, + {99618148, 62413436}, + {99457214, 62709442}, + {99368347, 62914794}, + {99166992, 63728332}, + {98313827, 69634780}, + {98176910, 70615707}, + {98162902, 70798233}, + {98163757, 71203430}, + }, + { + {79090698, 116426399}, + {80959800, 137087692}, + {81030303, 137762298}, + {81190704, 138903503}, + {81253700, 139084197}, + {81479301, 139544998}, + {81952003, 140118896}, + {82319900, 140523895}, + {82967803, 140993896}, + {83022903, 141032104}, + {83777900, 141493606}, + {84722099, 141849899}, + {84944396, 141887207}, + {86144699, 141915893}, + {87643997, 141938095}, + {88277503, 141887695}, + {88582099, 141840606}, + {89395401, 141712203}, + {90531204, 141528396}, + {91014801, 141438400}, + {92097595, 141190093}, + {123348297, 132876998}, + {123399505, 132860000}, + {123452804, 132841506}, + {123515502, 132818908}, + {123543800, 132806198}, + {124299598, 132437393}, + {124975502, 132042098}, + {125047500, 131992202}, + {125119506, 131930603}, + {166848800, 86317703}, + {168976409, 83524902}, + {169359603, 82932701}, + {169852600, 81917800}, + {170686904, 79771202}, + {170829406, 79245597}, + {170885498, 78796295}, + {170909301, 78531898}, + {170899703, 78238700}, + {170842803, 77553199}, + {170701293, 76723495}, + {170302307, 75753898}, + {169924301, 75067398}, + {169359802, 74578796}, + {168148605, 73757499}, + {163261596, 71124702}, + {162986007, 70977798}, + {162248703, 70599098}, + {158193405, 68923995}, + {157514297, 68667495}, + {156892700, 68495201}, + {156607299, 68432998}, + {154301895, 68061904}, + {93440299, 68061904}, + {88732002, 68255996}, + {88627304, 68298500}, + {88111396, 68541900}, + {86393898, 69555404}, + {86138298, 69706695}, + {85871704, 69913200}, + {85387199, 70393402}, + {79854499, 76783203}, + {79209701, 77649398}, + {79108505, 78072502}, + {79090698, 78472198}, + {79090698, 116426399}, + }, + { + {90956314, 84639938}, + {91073814, 85141891}, + {91185752, 85505371}, + {109815368, 137196487}, + {110342590, 138349899}, + {110388549, 138447540}, + {110652862, 138971343}, + {110918045, 139341140}, + {114380859, 143159042}, + {114446723, 143220352}, + {114652198, 143392166}, + {114712196, 143437301}, + {114782165, 143476028}, + {114873054, 143514923}, + {115217086, 143660934}, + {115306060, 143695526}, + {115344009, 143707580}, + {115444541, 143737747}, + {115589378, 143779937}, + {115751358, 143823989}, + {115802780, 143825820}, + {116872810, 143753616}, + {116927055, 143744644}, + {154690734, 133504180}, + {155009704, 133371856}, + {155029907, 133360061}, + {155089141, 133323181}, + {155342315, 133163360}, + {155602294, 132941406}, + {155669158, 132880294}, + {155821624, 132737884}, + {155898986, 132656890}, + {155934936, 132608932}, + {155968627, 132562713}, + {156062896, 132431808}, + {156111694, 132363174}, + {156148147, 132297180}, + {158738342, 127281066}, + {159026672, 126378631}, + {159073699, 125806335}, + {159048522, 125299743}, + {159040313, 125192901}, + {158898300, 123934677}, + {149829376, 70241508}, + {149763031, 69910629}, + {149684692, 69628723}, + {149557800, 69206214}, + {149366485, 68864326}, + {149137390, 68578514}, + {148637466, 68048767}, + {147027725, 66632934}, + {146228607, 66257507}, + {146061309, 66184646}, + {146017929, 66174186}, + {145236465, 66269500}, + {144802490, 66345039}, + {144673995, 66376220}, + {93732284, 79649864}, + {93345336, 79785865}, + {93208084, 79840286}, + {92814521, 79997779}, + {92591087, 80098968}, + {92567016, 80110511}, + {92032684, 80860725}, + {91988853, 80930152}, + {91471725, 82210029}, + {91142349, 83076683}, + {90969284, 83653182}, + {90929664, 84043212}, + {90926315, 84325256}, + {90956314, 84639938}, + }, + { + {114758499, 88719909}, + {114771591, 88860549}, + {115515533, 94195907}, + {115559539, 94383651}, + {119882980, 109502059}, + {120660522, 111909683}, + {126147735, 124949630}, + {127127212, 127107215}, + {129976379, 132117279}, + {130754470, 133257080}, + {130820968, 133340835}, + {130889312, 133423858}, + {131094787, 133652832}, + {131257629, 133828247}, + {131678619, 134164276}, + {131791107, 134248901}, + {131969482, 134335189}, + {132054107, 134373718}, + {132927368, 134701141}, + {133077072, 134749313}, + {133196075, 134785705}, + {133345230, 134804351}, + {133498809, 134809051}, + {133611541, 134797607}, + {134621170, 134565322}, + {134741165, 134527511}, + {134892089, 134465240}, + {135071212, 134353820}, + {135252029, 134185821}, + {135384979, 134003631}, + {135615585, 133576675}, + {135793029, 132859008}, + {135890228, 131382904}, + {135880828, 131261657}, + {135837570, 130787963}, + {135380661, 127428909}, + {132830596, 109495368}, + {132815826, 109411666}, + {132765869, 109199302}, + {132724380, 109068161}, + {127490066, 93353515}, + {125330810, 87852828}, + {125248336, 87647026}, + {125002182, 87088424}, + {124894592, 86872482}, + {121007278, 80019584}, + {120962829, 79941261}, + {120886489, 79833923}, + {120154983, 78949615}, + {119366561, 78111709}, + {119014755, 77776794}, + {116728790, 75636238}, + {116660522, 75593933}, + {116428192, 75458541}, + {116355255, 75416870}, + {116264663, 75372528}, + {115952728, 75233367}, + {115865554, 75205482}, + {115756835, 75190956}, + {115564163, 75197830}, + {115481170, 75202087}, + {115417144, 75230400}, + {115226959, 75337806}, + {115203842, 75351448}, + {114722015, 75746932}, + {114672103, 75795661}, + {114594619, 75891891}, + {114565811, 75973831}, + {114478256, 76240814}, + {114178039, 77252197}, + {114137664, 77769668}, + {114109771, 78154464}, + {114758499, 88719909}, + }, + { + {108135070, 109828002}, + {108200347, 110091529}, + {108319419, 110298500}, + {108439025, 110488388}, + {108663574, 110766731}, + {108812957, 110935768}, + {109321914, 111398925}, + {109368087, 111430320}, + {109421295, 111466331}, + {110058998, 111849746}, + {127160308, 120588981}, + {127350692, 120683456}, + {128052749, 120997207}, + {128326919, 121113449}, + {131669586, 122213058}, + {131754745, 122240592}, + {131854583, 122264770}, + {132662048, 122449813}, + {132782669, 122449897}, + {132909118, 122443687}, + {133013442, 122436058}, + {140561035, 121609939}, + {140786346, 121583320}, + {140876144, 121570228}, + {140962356, 121547996}, + {141052612, 121517837}, + {141231292, 121442184}, + {141309371, 121390007}, + {141370132, 121327003}, + {141456008, 121219932}, + {141591598, 121045005}, + {141905761, 120634796}, + {141894607, 120305725}, + {141881881, 120110855}, + {141840881, 119885009}, + {141685043, 119238922}, + {141617416, 118962882}, + {141570434, 118858856}, + {131617462, 100598548}, + {131542846, 100487213}, + {131229385, 100089019}, + {131091476, 99928108}, + {119824127, 90297180}, + {119636337, 90142387}, + {119507492, 90037765}, + {119436744, 89983657}, + {119423942, 89974159}, + {119207366, 89822471}, + {119117149, 89767097}, + {119039489, 89726867}, + {116322929, 88522857}, + {114817031, 87882110}, + {114683975, 87826751}, + {114306411, 87728507}, + {113876434, 87646003}, + {113792106, 87629974}, + {113658988, 87615974}, + {113574333, 87609275}, + {112813575, 87550102}, + {112578567, 87560157}, + {112439880, 87571647}, + {112306922, 87599395}, + {112225082, 87622535}, + {112132568, 87667175}, + {112103477, 87682830}, + {110795242, 88511634}, + {110373565, 88847793}, + {110286537, 88934989}, + {109730873, 89531501}, + {109648735, 89628883}, + {109552581, 89768859}, + {109514228, 89838470}, + {109501640, 89877586}, + {109480964, 89941864}, + {109461761, 90032417}, + {109457778, 90055458}, + {108105194, 109452575}, + {108094238, 109620979}, + {108135070, 109828002}, + }, + { + {108764694, 108910400}, + {108965499, 112306495}, + {109598602, 120388298}, + {110573898, 128289596}, + {110597801, 128427795}, + {113786201, 137983795}, + {113840301, 138134704}, + {113937202, 138326904}, + {114046005, 138520401}, + {114150802, 138696792}, + {114164703, 138717895}, + {114381896, 139021194}, + {114701004, 139425292}, + {114997398, 139747497}, + {115065597, 139805191}, + {115134498, 139850891}, + {115167098, 139871704}, + {115473396, 139992797}, + {115537498, 139995101}, + {116762596, 139832000}, + {116897499, 139808593}, + {118401802, 139225585}, + {118437500, 139209594}, + {118488204, 139182189}, + {118740097, 139033996}, + {118815795, 138967285}, + {134401000, 116395492}, + {134451507, 116309997}, + {135488098, 113593597}, + {137738006, 106775695}, + {140936492, 97033889}, + {140960006, 96948997}, + {141026504, 96660995}, + {141067291, 96467094}, + {141124893, 95771896}, + {141511795, 90171600}, + {141499801, 90026000}, + {141479598, 89907798}, + {141276794, 88844596}, + {141243804, 88707397}, + {140778305, 87031593}, + {140733306, 86871696}, + {140697204, 86789993}, + {140619796, 86708190}, + {140398391, 86487396}, + {125798797, 72806198}, + {125415802, 72454498}, + {123150398, 70566093}, + {123038803, 70503997}, + {122681198, 70305397}, + {121919204, 70104797}, + {121533699, 70008094}, + {121273696, 70004898}, + {121130599, 70020797}, + {121045097, 70033294}, + {120847099, 70082298}, + {120481895, 70278999}, + {120367004, 70379692}, + {120272796, 70475097}, + {119862098, 71004791}, + {119745101, 71167297}, + {119447799, 71726997}, + {119396499, 71825798}, + {119348701, 71944496}, + {109508796, 98298797}, + {109368598, 98700897}, + {109298400, 98926391}, + {108506301, 102750991}, + {108488197, 102879898}, + {108764694, 108910400}, + }, + { + {106666252, 87231246}, + {106673248, 87358055}, + {107734146, 101975646}, + {107762649, 102357955}, + {108702445, 111208351}, + {108749450, 111345153}, + {108848350, 111542648}, + {110270645, 114264358}, + {110389648, 114445144}, + {138794845, 143461151}, + {139048355, 143648956}, + {139376144, 143885345}, + {139594451, 144022644}, + {139754043, 144110046}, + {139923950, 144185852}, + {140058242, 144234451}, + {140185653, 144259552}, + {140427551, 144292648}, + {141130950, 144281448}, + {141157653, 144278152}, + {141214355, 144266555}, + {141347457, 144223449}, + {141625350, 144098953}, + {141755142, 144040145}, + {141878143, 143971557}, + {142011444, 143858154}, + {142076843, 143796356}, + {142160644, 143691055}, + {142224456, 143560852}, + {142925842, 142090850}, + {142935653, 142065353}, + {142995956, 141899154}, + {143042556, 141719757}, + {143102951, 141436157}, + {143129257, 141230453}, + {143316055, 139447250}, + {143342544, 133704650}, + {143307556, 130890960}, + {142461257, 124025558}, + {141916046, 120671051}, + {141890457, 120526153}, + {140002349, 113455749}, + {139909149, 113144149}, + {139853454, 112974456}, + {137303756, 105228057}, + {134700546, 98161254}, + {134617950, 97961547}, + {133823547, 96118057}, + {133688751, 95837356}, + {133481353, 95448059}, + {133205444, 94948150}, + {131178955, 91529853}, + {131144744, 91482055}, + {113942047, 67481246}, + {113837051, 67360549}, + {113048950, 66601745}, + {112305549, 66002746}, + {112030853, 65790351}, + {111970649, 65767547}, + {111912445, 65755249}, + {111854248, 65743453}, + {111657447, 65716354}, + {111576950, 65707351}, + {111509750, 65708549}, + {111443550, 65718551}, + {111397247, 65737449}, + {111338546, 65764648}, + {111129547, 65863349}, + {111112449, 65871551}, + {110995254, 65927856}, + {110968849, 65946151}, + {110941444, 65966751}, + {110836448, 66057853}, + {110490447, 66445449}, + {110404144, 66576751}, + {106802055, 73202148}, + {106741950, 73384948}, + {106715454, 73469650}, + {106678054, 73627151}, + {106657455, 75433448}, + {106666252, 87231246}, + }, + { + {101852752, 106261352}, + {101868949, 106406051}, + {102347549, 108974250}, + {112286750, 152027954}, + {112305648, 152106536}, + {112325752, 152175857}, + {112391448, 152290863}, + {113558250, 154187454}, + {113592048, 154226745}, + {113694351, 154313156}, + {113736549, 154335647}, + {113818145, 154367462}, + {114284454, 154490951}, + {114415847, 154504547}, + {114520751, 154489151}, + {114571350, 154478057}, + {114594551, 154472854}, + {114630546, 154463958}, + {114715148, 154429443}, + {146873657, 136143051}, + {146941741, 136074249}, + {147190155, 135763549}, + {147262649, 135654937}, + {147309951, 135557159}, + {147702255, 133903945}, + {147934143, 131616348}, + {147967041, 131273864}, + {148185852, 127892250}, + {148195648, 127669754}, + {148179656, 126409851}, + {148119552, 126182151}, + {147874053, 125334152}, + {147818954, 125150352}, + {146958557, 122656646}, + {139070251, 101025955}, + {139002655, 100879051}, + {119028450, 63067649}, + {118846649, 62740753}, + {115676048, 57814651}, + {115550453, 57629852}, + {115330352, 57319751}, + {115094749, 56998352}, + {114978347, 56847454}, + {114853050, 56740550}, + {114695053, 56609550}, + {114582252, 56528148}, + {114210449, 56375953}, + {113636245, 56214950}, + {113470352, 56171649}, + {109580749, 55503551}, + {109491645, 55495452}, + {109238754, 55511550}, + {109080352, 55534049}, + {108027748, 55687351}, + {107839950, 55732349}, + {107614456, 55834953}, + {107488143, 55925952}, + {107302551, 56062553}, + {107218353, 56145751}, + {107199447, 56167251}, + {107052749, 56354850}, + {106978652, 56476348}, + {106869644, 56710754}, + {104541351, 62448753}, + {104454551, 62672554}, + {104441253, 62707351}, + {104231750, 63366348}, + {104222648, 63419952}, + {104155746, 63922649}, + {104127349, 64147552}, + {104110847, 64299957}, + {102235450, 92366752}, + {101804351, 102877655}, + {101852752, 106261352}, + }, + { + {106808700, 120885696}, + {106818695, 120923103}, + {106873901, 121057098}, + {115123603, 133614700}, + {115128799, 133619598}, + {115182197, 133661804}, + {115330101, 133740707}, + {115455398, 133799407}, + {115595001, 133836807}, + {115651000, 133851806}, + {116413604, 134055206}, + {116654495, 134097900}, + {116887603, 134075210}, + {117071098, 134040405}, + {117458801, 133904891}, + {118057998, 133572601}, + {118546997, 133261001}, + {118578498, 133239395}, + {118818603, 133011596}, + {121109695, 130501495}, + {122661598, 128760101}, + {142458190, 102765197}, + {142789001, 102099601}, + {143105010, 101386505}, + {143154800, 101239700}, + {143193908, 100825500}, + {143160507, 100282501}, + {143133499, 100083602}, + {143092697, 99880500}, + {143050689, 99766700}, + {142657501, 98974502}, + {142580307, 98855201}, + {122267196, 76269897}, + {122036399, 76105003}, + {121832000, 76028305}, + {121688796, 75983108}, + {121591598, 75955001}, + {121119697, 75902099}, + {120789596, 75953498}, + {120487495, 76041900}, + {120042701, 76365798}, + {119886695, 76507301}, + {119774200, 76635299}, + {119739097, 76686904}, + {119685195, 76798202}, + {119456199, 77320098}, + {106877601, 119561401}, + {106854797, 119645103}, + {106849098, 119668807}, + {106847099, 119699005}, + {106840400, 119801406}, + {106807800, 120719299}, + {106806098, 120862808}, + {106808700, 120885696}, + }, + { + {99663352, 105328948}, + {99690048, 105797050}, + {99714050, 105921447}, + {99867248, 106439949}, + {100111557, 107256546}, + {104924850, 120873649}, + {105106155, 121284049}, + {105519149, 122184753}, + {105586051, 122292655}, + {105665054, 122400154}, + {106064147, 122838455}, + {106755355, 123453453}, + {106929054, 123577651}, + {107230346, 123771949}, + {107760650, 123930648}, + {108875854, 124205154}, + {108978752, 124228050}, + {131962051, 123738754}, + {135636047, 123513954}, + {135837249, 123500747}, + {136357345, 123442749}, + {136577346, 123394454}, + {136686645, 123367752}, + {137399353, 123185050}, + {137733947, 123063156}, + {137895355, 122997154}, + {138275650, 122829154}, + {138394256, 122767753}, + {138516845, 122670150}, + {139987045, 121111251}, + {149171646, 108517349}, + {149274353, 108372848}, + {149314758, 108314247}, + {149428848, 108140846}, + {149648651, 107650550}, + {149779541, 107290252}, + {149833343, 107115249}, + {149891357, 106920051}, + {150246353, 105630249}, + {150285842, 105423454}, + {150320953, 105233749}, + {150336639, 104981552}, + {150298049, 104374053}, + {150287948, 104271850}, + {150026153, 103481147}, + {149945449, 103301651}, + {149888946, 103213455}, + {149800949, 103103851}, + {149781143, 103079650}, + {149714141, 103005447}, + {149589950, 102914146}, + {149206054, 102698951}, + {128843856, 91378150}, + {128641754, 91283050}, + {119699851, 87248046}, + {117503555, 86311950}, + {117145851, 86178054}, + {116323654, 85925048}, + {115982551, 85834045}, + {115853050, 85819252}, + {115222549, 85771949}, + {107169357, 85771949}, + {107122650, 85776451}, + {106637145, 85831550}, + {105095046, 86423950}, + {104507850, 86703750}, + {104384155, 86763153}, + {104332351, 86790145}, + {104198257, 86882644}, + {103913757, 87109451}, + {103592346, 87388450}, + {103272651, 87666748}, + {103198051, 87779052}, + {101698654, 90600952}, + {101523551, 90958450}, + {101360054, 91347450}, + {101295349, 91542144}, + {99774551, 98278152}, + {99746749, 98417755}, + {99704055, 98675453}, + {99663352, 99022949}, + {99663352, 105328948}, + }, + { + {95036499, 101778106}, + {95479103, 102521301}, + {95587295, 102700103}, + {98306503, 106984901}, + {98573303, 107377700}, + {100622406, 110221702}, + {101252304, 111089599}, + {104669502, 115750198}, + {121838500, 131804107}, + {122000503, 131943695}, + {122176803, 132023406}, + {122474105, 132025390}, + {122703804, 132023101}, + {123278808, 131878112}, + {124072998, 131509109}, + {124466506, 131102508}, + {152779296, 101350906}, + {153016510, 101090606}, + {153269699, 100809097}, + {153731994, 100214096}, + {153927902, 99939796}, + {154641098, 98858100}, + {154864303, 98517601}, + {155056594, 97816604}, + {155083511, 97645599}, + {155084899, 97462097}, + {154682601, 94386100}, + {154376007, 92992599}, + {154198593, 92432403}, + {153830505, 91861701}, + {153686904, 91678695}, + {151907104, 90314605}, + {151368896, 89957603}, + {146983306, 87632202}, + {139082397, 84273605}, + {128947692, 80411399}, + {121179000, 78631301}, + {120264701, 78458198}, + {119279510, 78304603}, + {116913101, 77994102}, + {116151504, 77974601}, + {115435104, 78171401}, + {113544105, 78709106}, + {113231002, 78879898}, + {112726303, 79163604}, + {112310501, 79411102}, + {96169998, 97040802}, + {95196304, 98364402}, + {95167800, 98409599}, + {95083503, 98570701}, + {94986999, 99022201}, + {94915100, 100413299}, + {95036499, 101778106}, + }, + { + {82601348, 96004745}, + {83443847, 128861953}, + {84173248, 136147354}, + {104268249, 141388839}, + {104373649, 141395355}, + {105686950, 141389541}, + {149002243, 140435653}, + {159095748, 133388244}, + {159488143, 133112655}, + {159661849, 132894653}, + {163034149, 128290847}, + {164801849, 124684249}, + {167405746, 72553245}, + {167330444, 71960746}, + {167255050, 71791847}, + {167147155, 71572044}, + {166999557, 71341545}, + {166723937, 70961448}, + {166238250, 70611541}, + {165782348, 70359649}, + {165649444, 70286849}, + {165332946, 70122344}, + {165164154, 70062248}, + {164879150, 69967544}, + {164744949, 69928947}, + {164691452, 69915245}, + {164669448, 69910247}, + {159249938, 68738952}, + {158528259, 68704742}, + {147564254, 68604644}, + {116196655, 68982742}, + {115364944, 69005050}, + {115193145, 69013549}, + {101701248, 70984146}, + {93918449, 72233047}, + {93789749, 72285247}, + {93777046, 72292648}, + {93586044, 72444046}, + {93366348, 72662345}, + {93301147, 72745452}, + {93260345, 72816345}, + {83523948, 92593849}, + {83430145, 92810241}, + {82815048, 94665542}, + {82755554, 94858551}, + {82722953, 95014350}, + {82594253, 95682350}, + {82601348, 96004745}, + }, + { + {110371345, 125796493}, + {110411544, 126159599}, + {110445251, 126362899}, + {111201950, 127863800}, + {112030052, 129270492}, + {112367050, 129799301}, + {113088348, 130525604}, + {113418144, 130853698}, + {117363449, 134705505}, + {118131149, 135444793}, + {118307449, 135607299}, + {119102546, 136297195}, + {119385047, 136531906}, + {120080848, 137094390}, + {120794845, 137645401}, + {121150344, 137896392}, + {121528945, 138162506}, + {121644546, 138242095}, + {122142349, 138506408}, + {127540847, 141363006}, + {127933448, 141516204}, + {128728256, 141766799}, + {129877151, 141989898}, + {130626052, 142113891}, + {130912246, 142135192}, + {131246841, 142109100}, + {131496047, 142027404}, + {131596252, 141957794}, + {131696350, 141873504}, + {131741043, 141803405}, + {138788452, 128037704}, + {139628646, 125946197}, + {138319351, 112395401}, + {130035354, 78066703}, + {124174049, 69908798}, + {123970649, 69676895}, + {123874252, 69571899}, + {123246643, 68961303}, + {123193954, 68924400}, + {121952049, 68110000}, + {121787345, 68021896}, + {121661544, 67970306}, + {121313446, 67877502}, + {121010650, 67864799}, + {120995346, 67869705}, + {120583747, 68122207}, + {120509750, 68170600}, + {120485847, 68189102}, + {112160148, 77252403}, + {111128646, 78690704}, + {110969650, 78939407}, + {110512550, 79663406}, + {110397247, 79958206}, + {110371345, 80038299}, + {110371345, 125796493}, + }, + { + {112163948, 137752700}, + {112171150, 137837997}, + {112203048, 137955993}, + {112240150, 138008209}, + {112343246, 138111099}, + {112556243, 138223205}, + {112937149, 138307998}, + {113318748, 138331909}, + {126076446, 138428298}, + {126165245, 138428695}, + {126312446, 138417907}, + {134075546, 136054504}, + {134322753, 135949401}, + {134649948, 135791198}, + {135234954, 135493408}, + {135290145, 135464691}, + {135326248, 135443695}, + {135920043, 135032592}, + {135993850, 134975799}, + {136244247, 134761199}, + {136649444, 134378692}, + {137067153, 133964294}, + {137188156, 133839096}, + {137298049, 133704498}, + {137318954, 133677795}, + {137413543, 133522201}, + {137687347, 133043792}, + {137816055, 132660705}, + {137836044, 131747695}, + {137807144, 131318603}, + {136279342, 119078704}, + {136249053, 118945800}, + {127306152, 81348602}, + {127114852, 81065505}, + {127034248, 80951400}, + {126971649, 80893707}, + {125093551, 79178001}, + {124935745, 79036003}, + {115573745, 71767601}, + {115411148, 71701805}, + {115191947, 71621002}, + {115017051, 71571304}, + {114870147, 71572898}, + {113869552, 71653900}, + {112863349, 72976104}, + {112756347, 73223899}, + {112498947, 73832206}, + {112429351, 73998504}, + {112366050, 74168098}, + {112273246, 74487098}, + {112239250, 74605400}, + {112195549, 74899902}, + {112163948, 75280700}, + {112163948, 137752700}, + }, + { + {78562347, 141451843}, + {79335624, 142828186}, + {79610343, 143188140}, + {79845077, 143445724}, + {81379173, 145126678}, + {81826751, 145577178}, + {82519126, 146209472}, + {83964973, 147280502}, + {85471343, 148377868}, + {86115539, 148760803}, + {88839988, 150281188}, + {89021247, 150382217}, + {90775917, 151320526}, + {91711380, 151767288}, + {92757591, 152134277}, + {93241058, 152201766}, + {113402145, 153091995}, + {122065994, 146802825}, + {164111053, 91685104}, + {164812759, 90470565}, + {165640182, 89037384}, + {171027435, 66211853}, + {171450805, 64406951}, + {171463150, 64349624}, + {171469787, 64317184}, + {171475585, 64282028}, + {171479812, 64253036}, + {171483596, 64210433}, + {171484405, 64153488}, + {171483001, 64140785}, + {171481719, 64132751}, + {171478668, 64115478}, + {171472702, 64092437}, + {171462768, 64075408}, + {171448089, 64061347}, + {171060333, 63854789}, + {169640502, 63197738}, + {169342147, 63086711}, + {166413101, 62215766}, + {151881774, 58826736}, + {146010574, 57613151}, + {141776962, 56908004}, + {140982940, 57030628}, + {139246154, 57540817}, + {139209609, 57566974}, + {127545310, 66015594}, + {127476654, 66104812}, + {105799087, 98784980}, + {85531921, 129338897}, + {79319717, 138704513}, + {78548156, 140188079}, + {78530448, 140530456}, + {78515594, 141299987}, + {78562347, 141451843}, + }, + { + {77755004, 128712387}, + {78073547, 130552612}, + {78433593, 132017822}, + {79752693, 136839645}, + {80479461, 138929260}, + {80903221, 140119674}, + {81789848, 141978454}, + {82447387, 143105575}, + {83288436, 144264328}, + {84593582, 145846542}, + {84971939, 146242813}, + {86905578, 147321304}, + {87874191, 147594131}, + {89249092, 147245132}, + {89541542, 147169052}, + {98759140, 144071609}, + {98894233, 144024261}, + {113607818, 137992843}, + {128324356, 131649307}, + {139610076, 126210189}, + {146999572, 122112884}, + {147119415, 122036041}, + {148717330, 120934616}, + {149114776, 120652725}, + {171640289, 92086624}, + {171677917, 92036224}, + {171721191, 91973869}, + {171851608, 91721557}, + {171927795, 91507644}, + {172398696, 89846351}, + {172436752, 89559959}, + {169361663, 64753852}, + {169349029, 64687164}, + {169115127, 63616458}, + {168965728, 63218254}, + {168911788, 63121219}, + {168901611, 63106807}, + {168896896, 63100486}, + {168890686, 63092460}, + {168876586, 63081058}, + {168855529, 63067909}, + {168808746, 63046024}, + {167251068, 62405864}, + {164291717, 63716899}, + {152661651, 69910156}, + {142312393, 75421356}, + {78778053, 111143295}, + {77887222, 113905914}, + {77591979, 124378433}, + {77563247, 126586669}, + {77755004, 128712387}, + }, + { + {105954101, 131182754}, + {105959197, 131275848}, + {105972801, 131473556}, + {105981498, 131571044}, + {106077903, 132298553}, + {106134094, 132715255}, + {106155700, 132832351}, + {106180099, 132942657}, + {106326797, 133590347}, + {106375099, 133719345}, + {106417602, 133829345}, + {106471000, 133930343}, + {106707901, 134308654}, + {106728401, 134340545}, + {106778198, 134417556}, + {106832397, 134491851}, + {106891296, 134562957}, + {106981300, 134667358}, + {107044204, 134736557}, + {107111000, 134802658}, + {107180999, 134865661}, + {107291099, 134961349}, + {107362998, 135020355}, + {107485397, 135112854}, + {107558998, 135166946}, + {107690399, 135256256}, + {107765098, 135305252}, + {107903594, 135390548}, + {108183898, 135561843}, + {108459503, 135727951}, + {108532501, 135771850}, + {108796096, 135920059}, + {108944099, 135972549}, + {109102401, 136010757}, + {109660598, 136071044}, + {109971595, 136100250}, + {110209594, 136116851}, + {110752799, 136122344}, + {111059906, 136105758}, + {111152900, 136100357}, + {111237197, 136091354}, + {111316101, 136075057}, + {111402000, 136050949}, + {111475296, 136026657}, + {143546600, 123535949}, + {143899002, 122454353}, + {143917404, 122394348}, + {143929199, 122354652}, + {143944793, 122295753}, + {143956207, 122250953}, + {143969497, 122192253}, + {143980102, 122143249}, + {143991302, 122083053}, + {144000396, 122031753}, + {144009796, 121970954}, + {144017303, 121917655}, + {144025405, 121850250}, + {144030609, 121801452}, + {144036804, 121727455}, + {144040008, 121683456}, + {144043502, 121600952}, + {144044708, 121565048}, + {144045700, 121470352}, + {144045898, 121446952}, + {144041503, 121108657}, + {144037506, 121023452}, + {143733795, 118731750}, + {140461395, 95238647}, + {140461105, 95236755}, + {140433807, 95115249}, + {140392608, 95011650}, + {134840805, 84668952}, + {134824996, 84642456}, + {134781494, 84572952}, + {134716796, 84480850}, + {127473899, 74425453}, + {127467002, 74417152}, + {127431701, 74381652}, + {127402603, 74357147}, + {127375503, 74334457}, + {127294906, 74276649}, + {127181900, 74207649}, + {127177597, 74205451}, + {127123901, 74178451}, + {127078903, 74155853}, + {127028999, 74133148}, + {126870803, 74070953}, + {126442901, 73917648}, + {126432403, 73914955}, + {126326004, 73889846}, + {126262405, 73880645}, + {126128097, 73878456}, + {125998199, 73877655}, + {108701095, 74516647}, + {108644599, 74519348}, + {108495201, 74528953}, + {108311302, 74556457}, + {108252799, 74569458}, + {108079002, 74612152}, + {107981399, 74638954}, + {107921295, 74657951}, + {107862197, 74685951}, + {107601303, 74828948}, + {107546997, 74863449}, + {107192794, 75098846}, + {107131202, 75151153}, + {106260002, 76066146}, + {106195098, 76221145}, + {106168502, 76328453}, + {106144699, 76437454}, + {106124496, 76538452}, + {106103698, 76649650}, + {106084197, 76761650}, + {106066299, 76874450}, + {106049903, 76987457}, + {106034797, 77101150}, + {106020904, 77214950}, + {106008201, 77328948}, + {105996902, 77443145}, + {105986099, 77565849}, + {105977005, 77679649}, + {105969299, 77793151}, + {105963096, 77906349}, + {105958297, 78019149}, + {105955299, 78131454}, + {105954101, 78242950}, + {105954101, 131182754}, + }, + { + {91355499, 77889205}, + {114834197, 120804504}, + {114840301, 120815200}, + {124701507, 132324798}, + {124798805, 132436706}, + {124901504, 132548309}, + {125126602, 132788909}, + {125235000, 132901901}, + {125337707, 133005401}, + {125546302, 133184707}, + {125751602, 133358703}, + {126133300, 133673004}, + {126263900, 133775604}, + {126367401, 133855499}, + {126471908, 133935104}, + {126596008, 134027496}, + {127119308, 134397094}, + {127135101, 134408203}, + {127433609, 134614303}, + {127554107, 134695709}, + {128155395, 135070907}, + {128274505, 135141799}, + {129132003, 135573211}, + {129438003, 135713195}, + {129556106, 135767196}, + {131512695, 136648498}, + {132294509, 136966598}, + {132798400, 137158798}, + {133203796, 137294494}, + {133377410, 137350799}, + {133522399, 137396606}, + {133804397, 137480697}, + {134017807, 137542205}, + {134288696, 137618408}, + {134564208, 137680099}, + {134844696, 137740097}, + {135202606, 137807098}, + {135489105, 137849807}, + {135626800, 137864898}, + {135766906, 137878692}, + {135972808, 137895797}, + {136110107, 137905502}, + {136235000, 137913101}, + {136485809, 137907196}, + {139194305, 136979202}, + {140318298, 136536209}, + {140380004, 136505004}, + {140668197, 136340499}, + {140724304, 136298904}, + {140808197, 136228210}, + {140861801, 136180603}, + {140917404, 136129104}, + {140979202, 136045104}, + {141022903, 135984207}, + {147591094, 126486999}, + {147661315, 126356101}, + {147706100, 126261901}, + {147749099, 126166000}, + {147817108, 126007507}, + {147859100, 125908599}, + {153693206, 111901100}, + {153731109, 111807800}, + {153760894, 111698806}, + {158641998, 92419303}, + {158644500, 92263702}, + {158539703, 92013504}, + {158499603, 91918899}, + {158335510, 91626800}, + {158264007, 91516304}, + {158216308, 91449203}, + {158178314, 91397506}, + {158094299, 91283203}, + {157396408, 90368202}, + {157285491, 90224700}, + {157169906, 90079200}, + {157050003, 89931304}, + {156290603, 89006805}, + {156221099, 88922897}, + {156087707, 88771003}, + {155947906, 88620498}, + {155348602, 88004203}, + {155113204, 87772796}, + {154947296, 87609703}, + {154776306, 87448204}, + {154588806, 87284301}, + {153886306, 86716400}, + {153682403, 86560501}, + {152966705, 86032402}, + {152687805, 85828704}, + {152484313, 85683204}, + {152278808, 85539001}, + {150878204, 84561401}, + {150683013, 84426498}, + {150599395, 84372703}, + {150395599, 84243202}, + {149988906, 83989395}, + {149782897, 83864501}, + {149568908, 83739799}, + {148872100, 83365303}, + {148625396, 83242202}, + {128079010, 73079605}, + {127980506, 73031005}, + {126701103, 72407104}, + {126501701, 72312202}, + {126431503, 72280601}, + {126311706, 72230606}, + {126260101, 72210899}, + {126191902, 72187599}, + {126140106, 72170303}, + {126088203, 72155303}, + {126036102, 72142700}, + {125965904, 72126899}, + {125913009, 72116600}, + {125859603, 72108505}, + {125788101, 72100296}, + {125733505, 72094398}, + {125678100, 72090400}, + {125621398, 72088302}, + {125548805, 72087303}, + {125490707, 72086898}, + {125430908, 72088203}, + {125369804, 72091094}, + {125306900, 72095306}, + {125233505, 72100997}, + {125168609, 72106506}, + {125102203, 72113601}, + {125034103, 72122207}, + {124964309, 72132095}, + {124890701, 72143707}, + {124819305, 72155105}, + {91355499, 77889099}, + {91355499, 77889205}, + }, + { + {84531845, 127391708}, + {84916946, 130417510}, + {86133247, 131166900}, + {86338447, 131292892}, + {86748847, 131544799}, + {102193946, 136599502}, + {103090942, 136796798}, + {103247146, 136822509}, + {104083549, 136911499}, + {106119346, 137109802}, + {106265853, 137122207}, + {106480247, 137139205}, + {110257850, 137133605}, + {116917747, 136131408}, + {117054946, 136106704}, + {119043945, 135244293}, + {119249046, 135154708}, + {136220947, 126833007}, + {165896347, 91517105}, + {166032546, 91314697}, + {166055435, 91204902}, + {166056152, 91176803}, + {166047256, 91100006}, + {166039733, 91063705}, + {165814849, 90080802}, + {165736450, 89837707}, + {165677246, 89732101}, + {165676956, 89731803}, + {165560241, 89629302}, + {154419952, 82608505}, + {153822143, 82239700}, + {137942749, 74046104}, + {137095245, 73845504}, + {135751342, 73537704}, + {134225952, 73208602}, + {132484344, 72860801}, + {124730346, 73902000}, + {120736549, 74464401}, + {100401245, 78685401}, + {90574645, 90625701}, + {90475944, 90748809}, + {90430747, 90808700}, + {90321548, 90958305}, + {90254852, 91077903}, + {90165641, 91244003}, + {90134941, 91302398}, + {84474647, 103745697}, + {84328048, 104137901}, + {84288543, 104327606}, + {84038047, 106164604}, + {84013351, 106368698}, + {83943847, 110643203}, + {84531845, 127391708}, + }, +}; + +using Slic3r::ExPolygon; +using Slic3r::Polygon; +using Slic3r::Polygons; +using Slic3r::ExPolygons; + +struct MyPoly { + ExPolygon poly; + MyPoly(Polygon contour, Polygons holes) + : poly(std::move(contour)) + { + poly.holes = std::move(holes); + } + + operator ExPolygon () { return poly; } +}; + +const TestDataEx QIDI_PART_POLYGONS_EX = { + ExPolygons{ + // "x-carriage.stl": + MyPoly{{ + {-22097700, -14878600}, {-21981300, -14566100}, + {-21807600, -14303900}, {-21354100, -13619200}, + {-20514800, -12806600}, {-19500000, -12163900}, + {-18553700, -11796600}, {-18354100, -11719200}, + {-18146200, -11680600}, {-17127200, -11491800}, + {-15872800, -11491800}, {-14853800, -11680600}, + {-14645900, -11719200}, {-14446300, -11796600}, + {-13500000, -12163900}, {-12485200, -12806600}, + {-11645900, -13619200}, {-11192400, -14303900}, + {-11018700, -14566100}, {-10902300, -14878600}, + {-10857000, -15000000}, {-2200000, -15000000}, + {-2242640, -14957400}, {500000, -12214700}, + {500000, 5500000}, {9450000, 5500000}, + {9450000, 7500000}, {273885, 7500000}, + {273885, 11050000}, {2706110, 11050000}, + {2706110, 11000000}, {9500000, 11000000}, + {9500000, 66500000}, {7466310, 68533696}, + {999999, 75000000}, {-8500000, 75000000}, + {-8500000, 74250000}, {-7500000, 74250000}, + {-7500000, 71750000}, {-8500000, 71750000}, + {-8500000, 68250000}, {-7500000, 68250000}, + {-7500000, 65750000}, {-8500000, 65750000}, + {-8500000, 64000000}, {-12500000, 64000000}, + {-12500000, 67000000}, {-14500000, 67000000}, + {-14500000, 73000000}, {-12500000, 73000000}, + {-12500000, 75000000}, {-23000000, 75000000}, + {-23000000, 59500000}, {-38500000, 59500000}, + {-42500000, 55500000}, {-42500000, 19536000}, + {-36767700, 18000000}, {-34000000, 18000000}, + {-34000000, 13000000}, {-39900000, 13000000}, + {-39900000, 11000000}, {-34000000, 11000000}, + {-34000000, 7500000}, {-39900000, 7500000}, + {-39900000, 5500000}, {-34000000, 5500000}, + {-34000000, -11714700}, {-30757400, -14957400}, + {-30800000, -15000000}, {-22143000, -15000000}, + }, + { + { + {2311850, 65709900}, {2076590, 65759904}, + {1943770, 65788100}, {1600000, 65941200}, + {1362567, 66113636}, {1329590, 66137604}, + {1295560, 66162300}, {1043769, 66442000}, + {855618, 66767900}, {739334, 67125800}, + {714193, 67365000}, {700000, 67500000}, + {714193, 67635000}, {739334, 67874200}, + {855618, 68232104}, {1043769, 68558000}, + {1295560, 68837696}, {1329590, 68862400}, + {1352596, 68879119}, {1600000, 69058800}, + {1943770, 69211896}, {2076590, 69240096}, + {2311850, 69290104}, {2688150, 69290104}, + {3056230, 69211896}, {3400000, 69058800}, + {3541910, 68955704}, {3704430, 68837696}, + {3762210, 68773496}, {3865370, 68658896}, + {3956230, 68558000}, {4024119, 68440400}, + {4065821, 68368176}, {4144380, 68232104}, + {4260660, 67874200}, {4300000, 67500000}, + {4260660, 67125800}, {4144380, 66767900}, + {4024119, 66559600}, {3956230, 66442000}, + {3865370, 66341104}, {3762210, 66226500}, + {3704430, 66162300}, {3541910, 66044296}, + {3400000, 65941200}, {3056230, 65788100}, + {2688150, 65709900}, + }, + { + {-27606700, 54303400}, {-27818500, 54330100}, + {-27896000, 54350000}, {-28025300, 54383200}, + {-28223800, 54461800}, {-28410900, 54564600}, + {-28583600, 54690100}, {-28739200, 54836300}, + {-28875300, 55000800}, {-28989700, 55181000}, + {-29080600, 55374200}, {-29146600, 55577200}, + {-29150000, 55595100}, {-29186600, 55786900}, + {-29200000, 56000000}, {-29186600, 56213100}, + {-29150000, 56404900}, {-29146600, 56422800}, + {-29080600, 56625800}, {-28989700, 56819000}, + {-28875300, 56999200}, {-28739200, 57163700}, + {-28583600, 57309900}, {-28410900, 57435400}, + {-28223800, 57538200}, {-28025300, 57616800}, + {-27896000, 57650000}, {-27818500, 57669900}, + {-27606700, 57696600}, {-27393300, 57696600}, + {-27181400, 57669900}, {-27104000, 57650000}, + {-26974700, 57616800}, {-26776200, 57538200}, + {-26589100, 57435400}, {-26416400, 57309900}, + {-26260800, 57163700}, {-26124700, 56999200}, + {-26010300, 56819000}, {-25919400, 56625800}, + {-25853400, 56422800}, {-25850000, 56404900}, + {-25813400, 56213100}, {-25800000, 56000000}, + {-25813400, 55786900}, {-25850000, 55595100}, + {-25853400, 55577200}, {-25919400, 55374200}, + {-26010300, 55181000}, {-26124700, 55000800}, + {-26260800, 54836300}, {-26416400, 54690100}, + {-26589100, 54564600}, {-26776200, 54461800}, + {-26974700, 54383200}, {-27104000, 54350000}, + {-27181400, 54330100}, {-27393300, 54303400}, + }, + { + {-4106740, 54303400}, {-4318550, 54330100}, + {-4396010, 54350000}, {-4525330, 54383200}, + {-4723820, 54461800}, {-4910900, 54564600}, + {-5083620, 54690100}, {-5239250, 54836300}, + {-5375330, 55000800}, {-5489720, 55181000}, + {-5580620, 55374200}, {-5646590, 55577200}, + {-5650000, 55595100}, {-5686590, 55786900}, + {-5700000, 56000000}, {-5686590, 56213100}, + {-5650000, 56404900}, {-5646590, 56422800}, + {-5580620, 56625800}, {-5489720, 56819000}, + {-5375330, 56999200}, {-5239250, 57163700}, + {-5083620, 57309900}, {-4910900, 57435400}, + {-4723820, 57538200}, {-4525330, 57616800}, + {-4396010, 57650000}, {-4318550, 57669900}, + {-4106740, 57696600}, {-3893260, 57696600}, + {-3681450, 57669900}, {-3603990, 57650000}, + {-3474670, 57616800}, {-3276170, 57538200}, + {-3089090, 57435400}, {-2916380, 57309900}, + {-2760750, 57163700}, {-2624670, 56999200}, + {-2510280, 56819000}, {-2419380, 56625800}, + {-2353410, 56422800}, {-2350000, 56404900}, + {-2313400, 56213100}, {-2300000, 56000000}, + {-2313400, 55786900}, {-2350000, 55595100}, + {-2353410, 55577200}, {-2419380, 55374200}, + {-2510280, 55181000}, {-2624670, 55000800}, + {-2760750, 54836300}, {-2916380, 54690100}, + {-3089090, 54564600}, {-3276170, 54461800}, + {-3474670, 54383200}, {-3603990, 54350000}, + {-3681450, 54330100}, {-3893260, 54303400}, + }, + { + {-16103600, 27353300}, {-16309200, 27379200}, + {-16509899, 27430800}, {-16702499, 27507000}, + {-16884100, 27606900}, {-17051800, 27728700}, + {-17202800, 27870500}, {-17334900, 28030200}, + {-17445900, 28205100}, {-17534100, 28392600}, + {-17598200, 28589700}, {-17637000, 28793200}, + {-17650000, 29000000}, {-17637000, 29206800}, + {-17598200, 29410300}, {-17534100, 29607400}, + {-17445900, 29794900}, {-17334900, 29969800}, + {-17202800, 30129500}, {-17051800, 30271300}, + {-16884100, 30393100}, {-16702499, 30493000}, + {-16509899, 30569200}, {-16309200, 30620800}, + {-16103600, 30646700}, {-15896400, 30646700}, + {-15690800, 30620800}, {-15490100, 30569200}, + {-15297500, 30493000}, {-15115900, 30393100}, + {-14948200, 30271300}, {-14797200, 30129500}, + {-14665100, 29969800}, {-14554100, 29794900}, + {-14465900, 29607400}, {-14401800, 29410300}, + {-14363000, 29206800}, {-14350000, 29000000}, + {-14363000, 28793200}, {-14401800, 28589700}, + {-14465900, 28392600}, {-14554100, 28205100}, + {-14665100, 28030200}, {-14797200, 27870500}, + {-14948200, 27728700}, {-15115900, 27606900}, + {-15297500, 27507000}, {-15490100, 27430800}, + {-15690800, 27379200}, {-15896400, 27353300}, + }, + { + {-5809180, 22879200}, {-6202540, 23007000}, + {-6551750, 23228700}, {-6834880, 23530200}, + {-7034130, 23892600}, {-7136990, 24293200}, + {-7136990, 24706800}, {-7034130, 25107400}, + {-6834880, 25469800}, {-6551750, 25771300}, + {-6202540, 25993000}, {-5809180, 26120800}, + {-5396390, 26146700}, {-4990120, 26069200}, + {-4615890, 25893100}, {-4297200, 25629500}, + {-4054090, 25294900}, {-3901840, 24910300}, + {-3850000, 24500000}, {-3901840, 24089700}, + {-4054090, 23705100}, {-4297200, 23370500}, + {-4615890, 23106900}, {-4990120, 22930800}, + {-5396390, 22853300}, + }, + { + {-28809200, 22879200}, {-29202500, 23007000}, + {-29551800, 23228700}, {-29834900, 23530200}, + {-30034100, 23892600}, {-30137000, 24293200}, + {-30137000, 24706800}, {-30034100, 25107400}, + {-29834900, 25469800}, {-29551800, 25771300}, + {-29202500, 25993000}, {-28809200, 26120800}, + {-28396400, 26146700}, {-27990100, 26069200}, + {-27615900, 25893100}, {-27297200, 25629500}, + {-27054100, 25294900}, {-26901800, 24910300}, + {-26850000, 24500000}, {-26901800, 24089700}, + {-27054100, 23705100}, {-27297200, 23370500}, + {-27615900, 23106900}, {-27990100, 22930800}, + {-28396400, 22853300}, + }, + { + {-15718329, 8800000}, + {-15729700, 8808230}, + {-15736300, 8814060}, + {-15742800, 8833890}, + {-15876410, 9243607}, + {-15729700, 9696850}, + {-14969700, 10251100}, + {-14030300, 10251100}, + {-13270300, 9696850}, + {-13123590, 9243607}, + {-13257200, 8833890}, + {-13263700, 8814060}, + {-13270300, 8808230}, + {-13281671, 8800000}, + }, + }}, + }, + ExPolygons{ + // "Spool-holder.stl": + MyPoly{{ + {338485792, -31307222}, {338867040, -31018436}, + {339248320, -30729652}, {339769915, -30334566}, + {340010848, -30152082}, {340392096, -29863298}, + {340773344, -29574512}, {341244704, -27899436}, + {341480384, -27061900}, {342060734, -24999444}, + {342187424, -24549286}, {343068058, -21419626}, + {343130112, -21199134}, {343521972, -19806477}, + {344953440, -14719350}, {345583712, -12479458}, + {345898880, -11359512}, {346213984, -10239566}, + {346529152, -9119620}, {346684120, -8568830}, + {347258496, -6527694}, {348879776, -765989}, + {351121248, 7199785}, {351160318, 7338666}, + {351581888, 8836852}, {358349952, 32889144}, + {361733984, 44915292}, {362502080, 47644968}, + {365226370, 57326618}, {367181933, 64276284}, + {369782208, 73517048}, {372004549, 81414857}, + {375270080, 93019880}, {377062304, 99389120}, + {380702368, 112325160}, {387982496, 138197232}, + {390913664, 148614048}, {392379232, 153822448}, + {392462848, 154165648}, {392500992, 154371968}, + {392523776, 154527056}, {392558720, 154903888}, + {392560704, 154943056}, {392564832, 155292544}, + {392554016, 155525040}, {392539872, 155688624}, + {392482592, 156087152}, {392479040, 156106240}, + {392392608, 156482704}, {392336512, 156674688}, + {392270816, 156869776}, {392130112, 157218896}, + {392119264, 157242992}, {391941088, 157597536}, + {391865920, 157728704}, {391740320, 157929344}, + {391551872, 158195776}, {391521632, 158235296}, + {391290048, 158513360}, {391187328, 158624592}, + {391050656, 158762640}, {390808320, 158983152}, + {390768160, 159017008}, {390567456, 159175840}, + {390331776, 159342352}, {390300192, 159363104}, + {389874464, 159612112}, {389791584, 159654240}, + {389337216, 159852608}, {389252448, 159883872}, + {388769664, 160029808}, {388694016, 160047936}, + {388177408, 160139328}, {388128128, 160145120}, + {387566176, 160176800}, {375407744, 160176800}, + {374915072, 160152480}, {374676896, 160123104}, + {374431712, 160080592}, {374176224, 160022768}, + {373936576, 159955472}, {373914144, 159948512}, + {373647424, 159856688}, {373378176, 159746368}, + {373213376, 159669552}, {373108832, 159616976}, + {372841920, 159468256}, {372580064, 159300432}, + {372535328, 159269408}, {372325888, 159114096}, + {372081888, 158910256}, {371928512, 158767776}, + {371850368, 158690384}, {371633408, 158456224}, + {371432736, 158209856}, {371413792, 158184848}, + {371249664, 157953552}, {371085088, 157689664}, + {371004448, 157545600}, {370939520, 157420656}, + {370813088, 157148864}, {370705536, 156876560}, + {368543808, 150896416}, {363439712, 136776352}, + {358631104, 123473712}, {358408023, 122856568}, + {356409504, 117327816}, {355922364, 115980139}, + {355915437, 115960977}, {352669088, 106980280}, + {351986938, 105093166}, {351083520, 102593952}, + {349781616, 98992320}, {348098080, 94334952}, + {340262048, 72657256}, {338954668, 69040480}, + {336962208, 63528480}, {332255104, 50506656}, + {327202016, 36527760}, {322789144, 24319856}, + {322760544, 24240790}, {322533686, 23613197}, + {322519552, 23574124}, {320672032, 18463012}, + {320578304, 18203810}, {320531456, 18074210}, + {320484608, 17944606}, {320437760, 17815006}, + {320297248, 17426202}, {320297248, 9238203}, + {321164066, 9238176}, {321689312, 9238155}, + {323777376, 9238073}, {324473408, 9238046}, + {325169440, 9238018}, {325496384, 10782991}, + {325496360, 12868520}, {327892320, 12868504}, + {329090336, 12868496}, {330288320, 12868487}, + {331486336, 12868480}, {332684279, 12868472}, + {332096736, 10092249}, {332096736, -26761938}, + {325697024, -26761692}, {325697024, -26311692}, + {324897056, -26311692}, {323897056, -27061692}, + {323897056, -29536704}, {323897088, -30511784}, + {323897088, -32461944}, {323897091, -32461944}, + {328084288, -32462100}, {329480000, -32462150}, + {332271456, -32462258}, {335062912, -32462360}, + {336960768, -32462360}, + }, + { + { + {376588032, 136952960}, {375810912, 137178704}, + {375411104, 137361136}, {375032960, 137582800}, + {374679360, 137841776}, {374353152, 138136224}, + {374058688, 138462448}, {373799680, 138816048}, + {373578048, 139194192}, {373395584, 139594016}, + {373169856, 140371136}, {373093728, 141176800}, + {373169856, 141982464}, {373395584, 142759600}, + {373578048, 143159392}, {373799680, 143537536}, + {374058688, 143891136}, {374353152, 144217360}, + {374679360, 144511824}, {375032960, 144770816}, + {375411104, 144992464}, {375810912, 145174896}, + {376588032, 145400656}, {377393696, 145476800}, + {378199360, 145400656}, {378976512, 145174896}, + {379376320, 144992480}, {379754464, 144770816}, + {380108064, 144511808}, {380434272, 144217360}, + {380728736, 143891136}, {380987744, 143537536}, + {381209376, 143159392}, {381391776, 142759600}, + {381617568, 141982464}, {381693696, 141176800}, + {381617568, 140371136}, {381391776, 139594000}, + {381209376, 139194192}, {380987744, 138816064}, + {380728736, 138462464}, {380434272, 138136240}, + {380108064, 137841792}, {379754464, 137582800}, + {379376320, 137361136}, {378976512, 137178704}, + {378199360, 136952960}, {377393696, 136876800}, + }, + { + {354604704, 97626944}, {355293600, 99532704}, + {355982496, 101438472}, {356671392, 103344232}, + {357360288, 105250000}, {358424054, 108192839}, + {358738080, 109061520}, {359426976, 110967296}, + {360115840, 112873056}, {362111392, 113825960}, + {368097952, 116684672}, {370093472, 117637584}, + {372089024, 118590488}, {374084544, 119543392}, + {378075584, 121449192}, {377003072, 117637704}, + {375930560, 113826200}, {375394304, 111920456}, + {374321792, 108108952}, {373249280, 104297464}, + {368952928, 102391616}, {362508448, 99532856}, + {360360288, 98579944}, {358212128, 97627024}, + {356063968, 96674096}, {353915808, 95721176}, + }, + { + {342204640, 63323192}, {342893536, 65228960}, + {344271328, 69040480}, {344960192, 70946248}, + {345649120, 72852016}, {346338016, 74757776}, + {347026880, 76663536}, {347715776, 78569304}, + {354618176, 81428112}, {356918976, 82381040}, + {359219776, 83333976}, {361520576, 84286920}, + {363821376, 85239856}, {366122176, 86192784}, + {368422976, 87145720}, {367886720, 85239976}, + {366814208, 81428472}, {366277952, 79522728}, + {365741664, 77616984}, {365205408, 75711224}, + {364132896, 71899736}, {363596640, 69993984}, + {361143232, 69041032}, {356236352, 67135128}, + {353782944, 66182184}, {351329504, 65229232}, + {348876064, 64276284}, {346422592, 63323328}, + {343969184, 62370380}, {341515744, 61417428}, + }, + { + {329804576, 29019442}, {330493472, 30925208}, + {331182368, 32830970}, {331871232, 34736732}, + {332560160, 36642500}, {333249056, 38548264}, + {333937920, 40454024}, {334626816, 42359792}, + {335315744, 44265552}, {337921792, 45218520}, + {340527872, 46171484}, {343133952, 47124452}, + {345740000, 48077416}, {348346080, 49030384}, + {350952160, 49983348}, {353558208, 50936312}, + {356164288, 51889284}, {358770368, 52842248}, + {358234112, 50936496}, {357697856, 49030752}, + {357161568, 47125000}, {356089056, 43313504}, + {355552800, 41407752}, {355016544, 39502008}, + {354480288, 37596256}, {353944032, 35690508}, + {351185344, 34737524}, {348426624, 33784544}, + {345667904, 32831566}, {342909216, 31878584}, + {340150528, 30925604}, {334633088, 29019640}, + {331874400, 28066660}, {329115680, 27113678}, + }, + }}, + }, + ExPolygons{ + // "x-end-idler.stl": + MyPoly{{ + {-6500000, -10475000}, {0, -10475000}, + {0, -10468600}, {365572, -10468600}, + {1094940, -10417600}, {1818960, -10315900}, + {2534130, -10163800}, {3236950, -9962320}, + {3924000, -9712250}, {4591940, -9414870}, + {5237500, -9071620}, {5857540, -8684170}, + {6449050, -8254410}, {7009140, -7784440}, + {7535080, -7276550}, {8024310, -6733200}, + {8474450, -6157050}, {8883300, -5550900}, + {9248880, -4917710}, {9569390, -4260570}, + {9843280, -3582660}, {10069200, -2887300}, + {10246100, -2177870}, {10373100, -1457840}, + {10449500, -730699}, {10475000, 0}, + {10449500, 730699}, {10373100, 1457840}, + {10246100, 2177870}, {10069200, 2887300}, + {9843280, 3582660}, {9569390, 4260570}, + {9248880, 4917710}, {8883300, 5550900}, + {8474450, 6157050}, {8024310, 6733200}, + {7739860, 7049120}, {8047300, 7272490}, + {9203020, 8357790}, {10213600, 9579380}, + {11063100, 10918000}, {11738200, 12352500}, + {12228100, 13860400}, {12525200, 15417700}, + {12624700, 17000000}, {12525200, 18582300}, + {12228100, 20139600}, {11738200, 21647500}, + {11063100, 23082000}, {10213600, 24420600}, + {9203020, 25642200}, {8047300, 26727500}, + {6764660, 27659400}, {5375340, 28423200}, + {3901250, 29006800}, {2365630, 29401100}, + {792712, 29599800}, {-792712, 29599800}, + {-2365630, 29401100}, {-3901250, 29006800}, + {-5181320, 28500000}, {-23500000, 28500000}, + {-23500000, -9000000}, {-22000000, -10500000}, + {-6500000, -10500000}, + }, + { + { + {6562230, 22074800}, {6357580, 22107300}, + {6158600, 22165100}, {5968430, 22247400}, + {5790080, 22352800}, {5626350, 22479800}, + {5479830, 22626400}, {5352830, 22790100}, + {5247350, 22968400}, {5165060, 23158600}, + {5107250, 23357600}, {5074840, 23562200}, + {5068330, 23769300}, {5087830, 23975600}, + {5133030, 24177800}, {5203220, 24372800}, + {5297290, 24557400}, {5413760, 24728800}, + {5550790, 24884200}, {5706220, 25021300}, + {5877600, 25137700}, {6062220, 25231800}, + {6257180, 25302000}, {6459400, 25347200}, + {6665690, 25366700}, {6872790, 25360200}, + {7077450, 25327800}, {7276430, 25270000}, + {7466600, 25187700}, {7644950, 25082200}, + {7808680, 24955200}, {7955200, 24808700}, + {8082200, 24645000}, {8187670, 24466600}, + {8269970, 24276400}, {8327780, 24077400}, + {8360190, 23872800}, {8366700, 23665700}, + {8347200, 23459400}, {8302000, 23257200}, + {8231809, 23062200}, {8137740, 22877600}, + {8021270, 22706200}, {7884240, 22550800}, + {7728810, 22413800}, {7557430, 22297300}, + {7372810, 22203200}, {7177850, 22133000}, + {6975630, 22087800}, {6769340, 22068300}, + }, + { + {1094940, 10417600}, {365572, 10468600}, + {0, 10468600}, {0, 10475000}, + {-1431080, 10475000}, {-6000000, 15108169}, + {-6000000, 19962102}, {-5802370, 20350000}, + {-5420410, 20938200}, {-4979070, 21483200}, + {-4483170, 21979100}, {-3938160, 22420400}, + {-3350000, 22802400}, {-2725130, 23120800}, + {-2070410, 23372100}, {-1393010, 23553600}, + {-700340, 23663300}, {0, 23700000}, + {700340, 23663300}, {1393010, 23553600}, + {2070410, 23372100}, {2725130, 23120800}, + {3350000, 22802400}, {3938160, 22420400}, + {4483170, 21979100}, {4979070, 21483200}, + {5420410, 20938200}, {5802370, 20350000}, + {6120750, 19725100}, {6372080, 19070400}, + {6553590, 18393000}, {6663300, 17700300}, + {6700000, 17000000}, {6663300, 16299700}, + {6553590, 15607000}, {6372080, 14929600}, + {6120750, 14274900}, {5802370, 13650000}, + {5420410, 13061800}, {4979070, 12516800}, + {4483170, 12020900}, {3938160, 11579600}, + {3350000, 11197600}, {2725130, 10879200}, + {2070410, 10627900}, {1393010, 10446400}, + {1156540, 10409000}, + }, + { + {-1455380, -6847030}, {-2847160, -6394820}, + {-4114500, -5663120}, {-5202010, -4683910}, + {-6062180, -3500000}, {-6657400, -2163120}, + {-6961650, -731699}, {-6961650, 731699}, + {-6657400, 2163120}, {-6062180, 3500000}, + {-5202010, 4683910}, {-4114500, 5663120}, + {-2847160, 6394820}, {-1455380, 6847030}, + {0, 7000000}, {1455380, 6847030}, + {2847160, 6394820}, {4114500, 5663120}, + {5018810, 4848870}, {5421400, 5186681}, + {5472037, 5130444}, {6083180, 4451690}, + {6090937, 4443078}, {6007070, 4372710}, + {5647390, 4070900}, {6062180, 3500000}, + {6657400, 2163120}, {6961650, 731699}, + {6961650, -731699}, {6657400, -2163120}, + {6062180, -3500000}, {5202010, -4683910}, + {4114500, -5663120}, {2847160, -6394820}, + {1455380, -6847030}, {0, -7000000}, + }, + }}, + }, + ExPolygons{ + // "Einsy-hinges.stl": + MyPoly{ + { + {865247, 3337040}, {1400000, 3575130}, {1873570, 3919190}, + {2265250, 4354200}, {2557930, 4861140}, {2738810, 5417850}, + {2762880, 5646830}, {2785290, 5860020}, {2786450, 5871067}, + {2796080, 5962680}, {2800000, 6000000}, {2738810, 6582150}, + {2728530, 6613790}, {2344020, 7279790}, {2195738, 7536616}, + {1639530, 8500000}, {1552105, 8651421}, {935040, 9720210}, + {621454, 10263400}, {-3267950, 17000000}, {-5000000, 17000000}, + {-5000000, 6000000}, {-2800000, 6000000}, {-2738810, 5417850}, + {-2557930, 4861140}, {-2265250, 4354200}, {-1873570, 3919190}, + {-1400000, 3575130}, {-865247, 3337040}, {-292679, 3215340}, + {292679, 3215340}, + }, + {}}, + MyPoly{{ + {412054, -4263360}, {725639, -3720210}, + {1315606, -2698356}, {1430130, -2500000}, + {2000000, -1512950}, {2000000, -1309600}, + {2192510, -976168}, {2347550, -498987}, + {2400000, 0}, {2382076, 170521}, + {2362880, 353169}, {2349180, 483565}, + {2347550, 498987}, {2192510, 976168}, + {1941640, 1410680}, {1605910, 1783550}, + {1200000, 2078460}, {741640, 2282540}, + {250868, 2386850}, {-250868, 2386850}, + {-741640, 2282540}, {-1200000, 2078460}, + {-1605910, 1783550}, {-1941640, 1410680}, + {-2192510, 976168}, {-2347550, 498987}, + {-2400000, 0}, {-5000000, 0}, + {-5000000, -11000000}, {-3477350, -11000000}, + }, + {}}, + }, + ExPolygons{ + // "LCD-cover-ORIGINAL-MK3.stl": + MyPoly{{ + {78000000, -11928900}, + {78000000, 51000000}, + {73000000, 56000000}, + {-72000000, 56000000}, + {-77000000, 51000000}, + {-77000000, -11928900}, + {-74928904, -14000000}, + {75928904, -14000000}, + }, + { + { + {44000000, 26000000}, {44000000, 31980000}, + {43992900, 31987100}, {44000000, 31994200}, + {44000000, 32000000}, {44005800, 32000000}, + {56000000, 43994200}, {56000000, 44000000}, + {56005800, 44000000}, {56013700, 44007900}, + {56021600, 44000000}, {69500000, 44000000}, + {69500000, 36020800}, {69510400, 36010400}, + {63500000, 30000000}, {50900000, 30000000}, + {49000000, 28100000}, {49000000, 26000000}, + {48000000, 26000000}, {48000000, 28500000}, + {47992900, 28507100}, {50503100, 31017300}, + {50520500, 31000000}, {63085800, 31000000}, + {68500000, 36414200}, {68500000, 43000000}, + {56420000, 43000000}, {45000000, 31580000}, + {45000000, 26000000}, + }, + { + {-54500000, 8000000}, + {-54500000, 38500000}, + {30500000, 38500000}, + {30500000, 8000000}, + }, + { + {61872800, 15032900}, {60645900, 15293700}, + {59500000, 15803800}, {58485200, 16541100}, + {57645900, 17473300}, {57018700, 18559600}, + {56631100, 19752500}, {56500000, 21000000}, + {56631100, 22247500}, {57018700, 23440400}, + {57645900, 24526700}, {58485200, 25458900}, + {59500000, 26196200}, {60645900, 26706300}, + {61872800, 26967100}, {63127200, 26967100}, + {64354104, 26706300}, {65500000, 26196200}, + {66514800, 25458900}, {67354104, 24526700}, + {67981304, 23440400}, {68368896, 22247500}, + {68500000, 21000000}, {68368896, 19752500}, + {67981304, 18559600}, {67354104, 17473300}, + {66514800, 16541100}, {65500000, 15803800}, + {64354104, 15293700}, {63127200, 15032900}, + }, + { + {57000000, 1500000}, + {57000000, 5500000}, + {58300000, 5500000}, + {58300000, 1500000}, + }, + { + {55000000, 1500000}, + {55000000, 5500000}, + {56300000, 5500000}, + {56300000, 1500000}, + }, + { + {59000000, 1500000}, + {59000000, 5500000}, + {60300000, 5500000}, + {60300000, 1500000}, + }, + { + {61000000, 1500000}, + {61000000, 5500000}, + {62300000, 5500000}, + {62300000, 1500000}, + }, + { + {63000000, 1500000}, + {63000000, 5500000}, + {64300004, 5500000}, + {64300004, 1500000}, + }, + { + {65000000, 1500000}, + {65000000, 5500000}, + {66300004, 5500000}, + {66300004, 1500000}, + }, + { + {67000000, 1500000}, + {67000000, 5500000}, + {68300000, 5500000}, + {68300000, 1500000}, + }, + }}, + }, + ExPolygons{ + // "x-end-motor.stl": + MyPoly{{ + {2365630, -29401100}, {3901250, -29006800}, + {5375340, -28423200}, {6764660, -27659400}, + {8047300, -26727500}, {9203020, -25642200}, + {10213600, -24420600}, {11063100, -23082000}, + {11738200, -21647500}, {12228100, -20139600}, + {12525200, -18582300}, {12624700, -17000000}, + {12525200, -15417700}, {12228100, -13860400}, + {11738200, -12352500}, {11063100, -10918000}, + {10213600, -9579380}, {9203020, -8357790}, + {8047300, -7272490}, {7739860, -7049120}, + {8024310, -6733200}, {8474450, -6157050}, + {8883300, -5550900}, {9248880, -4917710}, + {9569390, -4260570}, {9843280, -3582660}, + {10069200, -2887300}, {10246100, -2177870}, + {10373100, -1457840}, {10449500, -730699}, + {10475000, 0}, {10449500, 730699}, + {10373100, 1457840}, {10246100, 2177870}, + {10069200, 2887300}, {9843280, 3582660}, + {9569390, 4260570}, {9248880, 4917710}, + {8883300, 5550900}, {8474450, 6157050}, + {8024310, 6733200}, {7535080, 7276550}, + {7009140, 7784440}, {6449050, 8254410}, + {5857540, 8684170}, {5237500, 9071620}, + {4591940, 9414870}, {3924000, 9712250}, + {3236950, 9962320}, {2534130, 10163800}, + {1818960, 10315900}, {1094940, 10417600}, + {365572, 10468600}, {0, 10468600}, + {0, 10475000}, {-6500000, 10475000}, + {-6500000, 53000000}, {-23500000, 53000000}, + {-23500000, -28500000}, {-5181320, -28500000}, + {-3901250, -29006800}, {-2365630, -29401100}, + {-792712, -29599800}, {792712, -29599800}, + }, + { + { + {-1455380, -6847030}, {-2847160, -6394820}, + {-4114500, -5663120}, {-5202010, -4683910}, + {-6062180, -3500000}, {-6657400, -2163120}, + {-6961650, -731699}, {-6961650, 731699}, + {-6657400, 2163120}, {-6062180, 3500000}, + {-5202010, 4683910}, {-4114500, 5663120}, + {-2847160, 6394820}, {-1455380, 6847030}, + {0, 7000000}, {1455380, 6847030}, + {2847160, 6394820}, {4114500, 5663120}, + {5202010, 4683910}, {6062180, 3500000}, + {6657400, 2163120}, {6961650, 731699}, + {6961650, -731699}, {6657400, -2163120}, + {6062180, -3500000}, {5641320, -4079259}, + {6084032, -4450744}, {6083180, -4451690}, + {5472037, -5130444}, {5414502, -5194343}, + {5328022, -5121778}, {5011080, -4855830}, + {4114500, -5663120}, {2847160, -6394820}, + {1455380, -6847030}, {0, -7000000}, + }, + { + {-700340, -23663300}, {-1393010, -23553600}, + {-2070410, -23372100}, {-2725130, -23120800}, + {-3350000, -22802400}, {-3938160, -22420400}, + {-4483170, -21979100}, {-4979070, -21483200}, + {-5420410, -20938200}, {-5802370, -20350000}, + {-6120750, -19725100}, {-6372080, -19070400}, + {-6500000, -18593000}, {-6500000, -15515603}, + {-1406282, -10475000}, {0, -10475000}, + {0, -10468600}, {365572, -10468600}, + {1094940, -10417600}, {1156540, -10409000}, + {1393010, -10446400}, {2070410, -10627900}, + {2725130, -10879200}, {3350000, -11197600}, + {3938160, -11579600}, {4483170, -12020900}, + {4979070, -12516800}, {5420410, -13061800}, + {5802370, -13650000}, {6120750, -14274900}, + {6372080, -14929600}, {6553590, -15607000}, + {6663300, -16299700}, {6700000, -17000000}, + {6663300, -17700300}, {6553590, -18393000}, + {6372080, -19070400}, {6120750, -19725100}, + {5802370, -20350000}, {5420410, -20938200}, + {4979070, -21483200}, {4483170, -21979100}, + {3938160, -22420400}, {3350000, -22802400}, + {2725130, -23120800}, {2070410, -23372100}, + {1393010, -23553600}, {700340, -23663300}, + {0, -23700000}, + }, + { + {6459400, -25347200}, {6257180, -25302000}, + {6062220, -25231800}, {5877600, -25137700}, + {5706220, -25021300}, {5550790, -24884200}, + {5413760, -24728800}, {5297290, -24557400}, + {5203220, -24372800}, {5133030, -24177800}, + {5087830, -23975600}, {5068330, -23769300}, + {5074840, -23562200}, {5107250, -23357600}, + {5165060, -23158600}, {5247350, -22968400}, + {5352830, -22790100}, {5479830, -22626400}, + {5626350, -22479800}, {5790080, -22352800}, + {5968430, -22247400}, {6158600, -22165100}, + {6357580, -22107300}, {6562230, -22074800}, + {6769340, -22068300}, {6975630, -22087800}, + {7177850, -22133000}, {7372810, -22203200}, + {7557430, -22297300}, {7728810, -22413800}, + {7884240, -22550800}, {8021270, -22706200}, + {8137740, -22877600}, {8231809, -23062200}, + {8302000, -23257200}, {8347200, -23459400}, + {8366700, -23665700}, {8360190, -23872800}, + {8327780, -24077400}, {8269970, -24276400}, + {8187670, -24466600}, {8082200, -24645000}, + {7955200, -24808700}, {7808680, -24955200}, + {7644950, -25082200}, {7466600, -25187700}, + {7276430, -25270000}, {7077450, -25327800}, + {6872790, -25360200}, {6665690, -25366700}, + }, + }}, + }, + ExPolygons{ + // "y-belt-idler.stl": + MyPoly{{ + {12500000, 40000000}, + {-12500000, 40000000}, + {-12500000, 5000000}, + {12500000, 5000000}, + }, + { + { + {-103604, 34353300}, {-309178, 34379200}, + {-509877, 34430800}, {-702536, 34507000}, + {-884113, 34606900}, {-1051750, 34728700}, + {-1202800, 34870500}, {-1334880, 35030200}, + {-1445910, 35205100}, {-1534130, 35392600}, + {-1598160, 35589700}, {-1636990, 35793200}, + {-1650000, 36000000}, {-1636990, 36206800}, + {-1598160, 36410300}, {-1534130, 36607400}, + {-1445910, 36794900}, {-1334880, 36969800}, + {-1202800, 37129500}, {-1051750, 37271300}, + {-884113, 37393100}, {-702536, 37493000}, + {-509877, 37569200}, {-309178, 37620800}, + {-103604, 37646700}, {103604, 37646700}, + {309178, 37620800}, {509877, 37569200}, + {702536, 37493000}, {884113, 37393100}, + {1051750, 37271300}, {1202800, 37129500}, + {1334880, 36969800}, {1445910, 36794900}, + {1534130, 36607400}, {1598160, 36410300}, + {1636990, 36206800}, {1650000, 36000000}, + {1636990, 35793200}, {1598160, 35589700}, + {1534130, 35392600}, {1445910, 35205100}, + {1334880, 35030200}, {1202800, 34870500}, + {1051750, 34728700}, {884113, 34606900}, + {702536, 34507000}, {509877, 34430800}, + {309178, 34379200}, {103604, 34353300}, + }, + { + {-103604, 8353260}, {-309178, 8379229}, + {-509877, 8430760}, {-702536, 8507040}, + {-884113, 8606860}, {-1051750, 8728650}, + {-1202800, 8870500}, {-1334880, 9030150}, + {-1445910, 9205110}, {-1534130, 9392590}, + {-1598160, 9589660}, {-1636990, 9793200}, + {-1650000, 10000000}, {-1636990, 10206800}, + {-1598160, 10410300}, {-1534130, 10607400}, + {-1445910, 10794900}, {-1334880, 10969800}, + {-1202800, 11129500}, {-1051750, 11271300}, + {-884113, 11393100}, {-702536, 11493000}, + {-509877, 11569200}, {-309178, 11620800}, + {-103604, 11646700}, {103604, 11646700}, + {309178, 11620800}, {509877, 11569200}, + {702536, 11493000}, {884113, 11393100}, + {1051750, 11271300}, {1202800, 11129500}, + {1334880, 10969800}, {1445910, 10794900}, + {1534130, 10607400}, {1598160, 10410300}, + {1636990, 10206800}, {1650000, 10000000}, + {1636990, 9793200}, {1598160, 9589660}, + {1534130, 9392590}, {1445910, 9205110}, + {1334880, 9030150}, {1202800, 8870500}, + {1051750, 8728650}, {884113, 8606860}, + {702536, 8507040}, {509877, 8430760}, + {309178, 8379229}, {103604, 8353260}, + }, + }}, + }, + ExPolygons{ + // "z-screw-cover.stl": + MyPoly{{ + {836227, -7956170}, {927804, -7941670}, + {964293, -7941670}, {1029899, -7925500}, + {1663290, -7825180}, {2472140, -7608450}, + {2751896, -7501064}, {2836840, -7480130}, + {2919650, -7436670}, {3253890, -7308360}, + {4000000, -6928200}, {4470019, -6622970}, + {4544520, -6583870}, {4583731, -6549125}, + {4702280, -6472140}, {5353040, -5945160}, + {5945160, -5353040}, {5973910, -5317540}, + {5988090, -5304980}, {6011204, -5271483}, + {6472140, -4702280}, {6928200, -4000000}, + {7039150, -3782250}, {7083650, -3717780}, + {7117560, -3628360}, {7308360, -3253890}, + {7608450, -2472140}, {7734580, -2001420}, + {7767530, -1914530}, {7775550, -1848520}, + {7825180, -1663290}, {7956170, -836227}, + {8000000, 0}, {7956170, 836227}, + {7825180, 1663290}, {7775550, 1848520}, + {7767530, 1914530}, {7734580, 2001420}, + {7608450, 2472140}, {7308360, 3253890}, + {7117560, 3628360}, {7083650, 3717780}, + {7039150, 3782250}, {6928200, 4000000}, + {6472140, 4702280}, {6011204, 5271483}, + {5988090, 5304980}, {5973910, 5317540}, + {5945160, 5353040}, {5353040, 5945160}, + {4702280, 6472140}, {4583731, 6549125}, + {4544520, 6583870}, {4470019, 6622970}, + {4000000, 6928200}, {3253890, 7308360}, + {2919650, 7436670}, {2836840, 7480130}, + {2751896, 7501064}, {2472140, 7608450}, + {1663290, 7825180}, {1029899, 7925500}, + {964293, 7941670}, {927804, 7941670}, + {836227, 7956170}, {0, 8000000}, + {-836227, 7956170}, {-927804, 7941670}, + {-964293, 7941670}, {-1029899, 7925500}, + {-1663290, 7825180}, {-2472140, 7608450}, + {-2751896, 7501064}, {-2836840, 7480130}, + {-2919650, 7436670}, {-3253890, 7308360}, + {-4000000, 6928200}, {-4470019, 6622970}, + {-4544520, 6583870}, {-4583731, 6549125}, + {-4702280, 6472140}, {-5353040, 5945160}, + {-5945160, 5353040}, {-5973910, 5317540}, + {-5988090, 5304980}, {-6011204, 5271483}, + {-6472140, 4702280}, {-6928200, 4000000}, + {-7039150, 3782250}, {-7083650, 3717780}, + {-7117560, 3628360}, {-7308360, 3253890}, + {-7608450, 2472140}, {-7734580, 2001420}, + {-7767530, 1914530}, {-7775550, 1848520}, + {-7825180, 1663290}, {-7956170, 836227}, + {-8000000, 0}, {-7956170, -836227}, + {-7825180, -1663290}, {-7775550, -1848520}, + {-7767530, -1914530}, {-7734580, -2001420}, + {-7608450, -2472140}, {-7308360, -3253890}, + {-7117560, -3628360}, {-7083650, -3717780}, + {-7039150, -3782250}, {-6928200, -4000000}, + {-6472140, -4702280}, {-6011204, -5271483}, + {-5988090, -5304980}, {-5973910, -5317540}, + {-5945160, -5353040}, {-5353040, -5945160}, + {-4702280, -6472140}, {-4583731, -6549125}, + {-4544520, -6583870}, {-4470019, -6622970}, + {-4000000, -6928200}, {-3253890, -7308360}, + {-2919650, -7436670}, {-2836840, -7480130}, + {-2751896, -7501064}, {-2472140, -7608450}, + {-1663290, -7825180}, {-1029899, -7925500}, + {-964293, -7941670}, {-927804, -7941670}, + {-836227, -7956170}, {0, -8000000}, + }, + { + { + {400000, -3200000}, {-400000, -3200000}, + {-440000, -3400000}, {-799999, -3400000}, + {-875001, -3600000}, {-1300000, -3600000}, + {-1416318, -3948965}, {-1708290, -3836890}, + {-2100000, -3637310}, {-2468700, -3397870}, + {-2810350, -3121210}, {-3121210, -2810350}, + {-3397870, -2468700}, {-3637310, -2100000}, + {-3836890, -1708290}, {-3994440, -1297870}, + {-4108220, -873229}, {-4152979, -590596}, + {-3200000, -400000}, {-3200000, 400000}, + {-3400000, 440000}, {-3400000, 799999}, + {-3600000, 874998}, {-3600000, 1300000}, + {-3948965, 1416318}, {-3836890, 1708290}, + {-3637310, 2100000}, {-3397870, 2468700}, + {-3121210, 2810350}, {-2810350, 3121210}, + {-2468700, 3397870}, {-2100000, 3637310}, + {-1708290, 3836890}, {-1297870, 3994440}, + {-873229, 4108220}, {-590596, 4152979}, + {-400000, 3200000}, {400000, 3200000}, + {440000, 3400000}, {799999, 3400000}, + {874998, 3600000}, {1300000, 3600000}, + {1416318, 3948965}, {1708290, 3836890}, + {2100000, 3637310}, {2468700, 3397870}, + {2810350, 3121210}, {3121210, 2810350}, + {3397870, 2468700}, {3637310, 2100000}, + {3836890, 1708290}, {3994440, 1297870}, + {4108220, 873229}, {4152979, 590596}, + {3200000, 400000}, {3200000, -400000}, + {3400000, -440000}, {3400000, -799999}, + {3600000, -874998}, {3600000, -1300000}, + {3948965, -1416318}, {3836890, -1708290}, + {3637310, -2100000}, {3397870, -2468700}, + {3121210, -2810350}, {2810350, -3121210}, + {2468700, -3397870}, {2100000, -3637310}, + {1708290, -3836890}, {1297870, -3994440}, + {873229, -4108220}, {590596, -4152979}, + }, + }}, + }, + ExPolygons{ + // "cable-holder.stl": + MyPoly{{ + {-2043150, -34799100}, {-1990180, -34549300}, + {-1988820, -34542900}, {-1986150, -34536800}, + {-1882530, -34303500}, {-1732900, -34097100}, + {-1728930, -34091600}, {-1723900, -34087100}, + {-1534730, -33916300}, {-1308420, -33785400}, + {-1059890, -33704400}, {-806907, -33677700}, + {-799999, -33677000}, {-793091, -33677700}, + {-540110, -33704400}, {-291578, -33785400}, + {-65267, -33916300}, {123903, -34087100}, + {128930, -34091600}, {132903, -34097100}, + {282532, -34303500}, {386150, -34536800}, + {388820, -34542900}, {390183, -34549300}, + {443151, -34799100}, {443151, -34908100}, + {556848, -34908100}, {556848, -34799100}, + {609816, -34549300}, {611179, -34542900}, + {613849, -34536800}, {717467, -34303500}, + {867096, -34097100}, {871069, -34091600}, + {876096, -34087100}, {1065270, -33916300}, + {1291580, -33785400}, {1540110, -33704400}, + {1793090, -33677700}, {1800000, -33677000}, + {1806910, -33677700}, {2059890, -33704400}, + {2308420, -33785400}, {2534730, -33916300}, + {2723900, -34087100}, {2728930, -34091600}, + {2732900, -34097100}, {2882530, -34303500}, + {2986150, -34536800}, {2988820, -34542900}, + {2990180, -34549300}, {3043150, -34799100}, + {3043150, -34908100}, {4000000, -34908100}, + {4000000, -29539900}, {4215720, -29345700}, + {4830130, -28500000}, {5255280, -27545100}, + {5472610, -26522600}, {5472610, -26000000}, + {5500000, -26000000}, {5500000, -17000000}, + {4805710, -17000000}, {4215720, -17815100}, + {3438930, -18517200}, {2533680, -19041900}, + {1539560, -19366100}, {499999, -19475800}, + {-539558, -19366100}, {-1533680, -19041900}, + {-2438930, -18517200}, {-3215720, -17815100}, + {-3805710, -17000000}, {-4500000, -17000000}, + {-4500000, -26000000}, {-4472610, -26000000}, + {-4472610, -26522600}, {-4255280, -27545100}, + {-3830130, -28500000}, {-3215720, -29345700}, + {-3000000, -29539900}, {-3000000, -34908100}, + {-2043150, -34908100}, + }, + { + { + {136154, -28711800}, {-211788, -28598700}, + {-382749, -28500000}, {-528624, -28415800}, + {-800503, -28171000}, {-1015540, -27875000}, + {-1164350, -27540800}, {-1240410, -27182900}, + {-1240410, -26817100}, {-1164350, -26459200}, + {-1015540, -26125000}, {-800503, -25829000}, + {-528624, -25584200}, {-382751, -25500000}, + {-211788, -25401300}, {136154, -25288200}, + {500000, -25250000}, {863845, -25288200}, + {1211790, -25401300}, {1382750, -25500000}, + {1528620, -25584200}, {1800500, -25829000}, + {2015539, -26125000}, {2164350, -26459200}, + {2240410, -26817100}, {2240410, -27182900}, + {2164350, -27540800}, {2015539, -27875000}, + {1800500, -28171000}, {1528620, -28415800}, + {1382750, -28500000}, {1211790, -28598700}, + {863845, -28711800}, {499999, -28750000}, + }, + }}, + }, + ExPolygons{ + // "Einsy-doors.stl": + MyPoly{{ + {105500000, 91975304}, + {21500000, 91975304}, + {21500000, 87500000}, + {0, 87500000}, + {0, 0}, + {105500000, 0}, + }, + { + { + {46000000, 60500000}, + {46000000, 79500000}, + {49650000, 79500000}, + {49650000, 60500000}, + }, + { + {58000000, 60500000}, + {58000000, 79500000}, + {61650000, 79500000}, + {61650000, 60500000}, + }, + { + {70000000, 60500000}, + {70000000, 79500000}, + {73650000, 79500000}, + {73650000, 60500000}, + }, + { + {64000000, 60500000}, + {64000000, 79500000}, + {67650000, 79500000}, + {67650000, 60500000}, + }, + { + {94000000, 60500000}, + {94000000, 79500000}, + {97650000, 79500000}, + {97650000, 60500000}, + }, + { + {52000000, 60500000}, + {52000000, 79500000}, + {55650000, 79500000}, + {55650000, 60500000}, + }, + { + {88000000, 60500000}, + {88000000, 79500000}, + {91650000, 79500000}, + {91650000, 60500000}, + }, + { + {82000000, 60500000}, + {82000000, 79500000}, + {85650000, 79500000}, + {85650000, 60500000}, + }, + { + {40000000, 60500000}, + {40000000, 79500000}, + {43650000, 79500000}, + {43650000, 60500000}, + }, + { + {76000000, 60500000}, + {76000000, 79500000}, + {79650000, 79500000}, + {79650000, 60500000}, + }, + { + {52000000, 35500000}, + {52000000, 54500000}, + {55650000, 54500000}, + {55650000, 35500000}, + }, + { + {40000000, 35500000}, + {40000000, 54500000}, + {43650000, 54500000}, + {43650000, 35500000}, + }, + { + {58000000, 35500000}, + {58000000, 54500000}, + {61650000, 54500000}, + {61650000, 35500000}, + }, + { + {76000000, 35500000}, + {76000000, 54500000}, + {79650000, 54500000}, + {79650000, 35500000}, + }, + { + {94000000, 35500000}, + {94000000, 54500000}, + {97650000, 54500000}, + {97650000, 35500000}, + }, + { + {82000000, 35500000}, + {82000000, 54500000}, + {85650000, 54500000}, + {85650000, 35500000}, + }, + { + {64000000, 35500000}, + {64000000, 54500000}, + {67650000, 54500000}, + {67650000, 35500000}, + }, + { + {70000000, 35500000}, + {70000000, 54500000}, + {73650000, 54500000}, + {73650000, 35500000}, + }, + { + {46000000, 35500000}, + {46000000, 54500000}, + {49650000, 54500000}, + {49650000, 35500000}, + }, + { + {88000000, 35500000}, + {88000000, 54500000}, + {91650000, 54500000}, + {91650000, 35500000}, + }, + { + {40000000, 10500000}, + {40000000, 29500000}, + {43650000, 29500000}, + {43650000, 10500000}, + }, + { + {82000000, 10500000}, + {82000000, 29500000}, + {85650000, 29500000}, + {85650000, 10500000}, + }, + { + {94000000, 10500000}, + {94000000, 29500000}, + {97650000, 29500000}, + {97650000, 10500000}, + }, + { + {88000000, 10500000}, + {88000000, 29500000}, + {91650000, 29500000}, + {91650000, 10500000}, + }, + { + {76000000, 10500000}, + {76000000, 29500000}, + {79650000, 29500000}, + {79650000, 10500000}, + }, + { + {64000000, 10500000}, + {64000000, 29500000}, + {67650000, 29500000}, + {67650000, 10500000}, + }, + { + {52000000, 10500000}, + {52000000, 29500000}, + {55650000, 29500000}, + {55650000, 10500000}, + }, + { + {70000000, 10500000}, + {70000000, 29500000}, + {73650000, 29500000}, + {73650000, 10500000}, + }, + { + {46000000, 10500000}, + {46000000, 29500000}, + {49650000, 29500000}, + {49650000, 10500000}, + }, + { + {58000000, 10500000}, + {58000000, 29500000}, + {61650000, 29500000}, + {61650000, 10500000}, + }, + }}, + }, + ExPolygons{ + // "y-motor-holder.stl": + MyPoly{{ + {47000000, 0}, {47000000, 15000000}, + {42000000, 20000000}, {37468500, 20000000}, + {37500000, 19500000}, {37409300, 18058700}, + {37138700, 16640100}, {36692400, 15266600}, + {36077500, 13959800}, {35303700, 12740500}, + {34383100, 11627700}, {33330398, 10639100}, + {32161998, 9790230}, {30896500, 9094490}, + {29553700, 8562850}, {28154900, 8203700}, + {26722100, 8022690}, {25277900, 8022690}, + {23845100, 8203700}, {22446300, 8562850}, + {21103500, 9094490}, {19838000, 9790230}, + {18669600, 10639100}, {17616900, 11627700}, + {16696301, 12740500}, {15922500, 13959800}, + {15307600, 15266600}, {14861300, 16640100}, + {14590700, 18058700}, {14500000, 19500000}, + {14590700, 20941300}, {14861300, 22359900}, + {15000000, 22786800}, {15000000, 38000000}, + {12500000, 40500000}, {9642140, 40500000}, + {71067, 30928900}, {0, 31000000}, + {0, -1500000}, {45500000, -1500000}, + }, + { + { + {10396400, 33353298}, {10190800, 33379200}, + {9990120, 33430802}, {9797460, 33507000}, + {9615890, 33606900}, {9448250, 33728700}, + {9297200, 33870500}, {9165120, 34030200}, + {9054090, 34205100}, {8965870, 34392600}, + {8901840, 34589700}, {8863010, 34793200}, + {8850000, 35000000}, {8863010, 35206800}, + {8901840, 35410300}, {8965870, 35607400}, + {9054090, 35794900}, {9165120, 35969800}, + {9297200, 36129500}, {9448250, 36271300}, + {9615890, 36393100}, {9797460, 36493000}, + {9990120, 36569200}, {10190800, 36620800}, + {10396400, 36646700}, {10603600, 36646700}, + {10809200, 36620800}, {11009900, 36569200}, + {11202500, 36493000}, {11384100, 36393100}, + {11551700, 36271300}, {11702800, 36129500}, + {11834900, 35969800}, {11945900, 35794900}, + {12034100, 35607400}, {12098200, 35410300}, + {12137000, 35206800}, {12150000, 35000000}, + {12137000, 34793200}, {12098200, 34589700}, + {12034100, 34392600}, {11945900, 34205100}, + {11834900, 34030200}, {11702800, 33870500}, + {11551700, 33728700}, {11384100, 33606900}, + {11202500, 33507000}, {11009900, 33430802}, + {10809200, 33379200}, {10603600, 33353298}, + }, + { + {41396400, 2353260}, {41190800, 2379230}, + {40990100, 2430760}, {40797500, 2507040}, + {40615900, 2606860}, {40448200, 2728650}, + {40297200, 2870500}, {40165100, 3030150}, + {40054100, 3205110}, {39965900, 3392590}, + {39901800, 3589660}, {39863000, 3793200}, + {39850000, 4000000}, {39863000, 4206800}, + {39901800, 4410340}, {39965900, 4607400}, + {40054100, 4794890}, {40165100, 4969840}, + {40297200, 5129500}, {40448200, 5271350}, + {40615900, 5393140}, {40797500, 5492960}, + {40990100, 5569240}, {41190800, 5620770}, + {41396400, 5646740}, {41603600, 5646740}, + {41809200, 5620770}, {42009900, 5569240}, + {42202500, 5492960}, {42384100, 5393140}, + {42551800, 5271350}, {42702800, 5129500}, + {42834900, 4969840}, {42945900, 4794890}, + {43034100, 4607400}, {43098200, 4410340}, + {43137000, 4206800}, {43150000, 4000000}, + {43137000, 3793200}, {43098200, 3589660}, + {43034100, 3392590}, {42945900, 3205110}, + {42834900, 3030150}, {42702800, 2870500}, + {42551800, 2728650}, {42384100, 2606860}, + {42202500, 2507040}, {42009900, 2430760}, + {41809200, 2379230}, {41603600, 2353260}, + }, + }}, + }, + ExPolygons{ + // "heatbed-cable-cover.stl": + MyPoly{{ + {15000000, 48000000}, + {11000000, 52000000}, + {-11000000, 52000000}, + {-15000000, 48000000}, + {-15000000, 35500000}, + {15000000, 35500000}, + }, + { + { + {-10100500, 43403200}, {-10299800, 43428300}, + {-10494400, 43478300}, {-10681200, 43552300}, + {-10857300, 43649100}, {-11019900, 43767200}, + {-11166300, 43904700}, {-11294400, 44059500}, + {-11402100, 44229200}, {-11487600, 44411000}, + {-11549700, 44602100}, {-11587400, 44799500}, + {-11600000, 45000000}, {-11587400, 45200500}, + {-11549700, 45397900}, {-11487600, 45589000}, + {-11402100, 45770800}, {-11294400, 45940500}, + {-11166300, 46095300}, {-11019900, 46232800}, + {-10857300, 46350900}, {-10681200, 46447700}, + {-10494400, 46521700}, {-10299800, 46571700}, + {-10100500, 46596800}, {-9899530, 46596800}, + {-9700190, 46571700}, {-9505570, 46521700}, + {-9318750, 46447700}, {-9142680, 46350900}, + {-8980120, 46232800}, {-8833650, 46095300}, + {-8705570, 45940500}, {-8597910, 45770800}, + {-8512360, 45589000}, {-8450270, 45397900}, + {-8412620, 45200500}, {-8400000, 45000000}, + {-8412620, 44799500}, {-8450270, 44602100}, + {-8512360, 44411000}, {-8597910, 44229200}, + {-8705570, 44059500}, {-8833650, 43904700}, + {-8980120, 43767200}, {-9142680, 43649100}, + {-9318750, 43552300}, {-9505570, 43478300}, + {-9700190, 43428300}, {-9899530, 43403200}, + }, + { + {9899530, 43403200}, {9700190, 43428300}, + {9505570, 43478300}, {9318750, 43552300}, + {9142680, 43649100}, {8980120, 43767200}, + {8833650, 43904700}, {8705570, 44059500}, + {8597910, 44229200}, {8512360, 44411000}, + {8450270, 44602100}, {8412620, 44799500}, + {8400000, 45000000}, {8412620, 45200500}, + {8450270, 45397900}, {8512360, 45589000}, + {8597910, 45770800}, {8705570, 45940500}, + {8833650, 46095300}, {8980120, 46232800}, + {9142680, 46350900}, {9318750, 46447700}, + {9505570, 46521700}, {9700190, 46571700}, + {9899530, 46596800}, {10100500, 46596800}, + {10299800, 46571700}, {10494400, 46521700}, + {10681200, 46447700}, {10857300, 46350900}, + {11019900, 46232800}, {11166300, 46095300}, + {11294400, 45940500}, {11402100, 45770800}, + {11487600, 45589000}, {11549700, 45397900}, + {11587400, 45200500}, {11600000, 45000000}, + {11587400, 44799500}, {11549700, 44602100}, + {11487600, 44411000}, {11402100, 44229200}, + {11294400, 44059500}, {11166300, 43904700}, + {11019900, 43767200}, {10857300, 43649100}, + {10681200, 43552300}, {10494400, 43478300}, + {10299800, 43428300}, {10100500, 43403200}, + }, + }}, + MyPoly{{ + {18000000, 25000000}, + {16426001, 26574000}, + {11000000, 32000000}, + {-11000000, 32000000}, + {-18000000, 25000000}, + {-18000000, 0}, + {18000000, 0}, + }, + { + { + {-10100500, 23403200}, {-10299800, 23428300}, + {-10494400, 23478300}, {-10681200, 23552300}, + {-10857300, 23649100}, {-11019900, 23767200}, + {-11166300, 23904700}, {-11294400, 24059500}, + {-11402100, 24229200}, {-11487600, 24411000}, + {-11549700, 24602100}, {-11587400, 24799500}, + {-11600000, 25000000}, {-11587400, 25200500}, + {-11549700, 25397900}, {-11487600, 25589000}, + {-11402100, 25770800}, {-11294400, 25940500}, + {-11166300, 26095300}, {-11019900, 26232800}, + {-10857300, 26350900}, {-10681200, 26447700}, + {-10494400, 26521700}, {-10299800, 26571700}, + {-10100500, 26596800}, {-9899530, 26596800}, + {-9700190, 26571700}, {-9505570, 26521700}, + {-9318750, 26447700}, {-9142680, 26350900}, + {-8980120, 26232800}, {-8833650, 26095300}, + {-8705570, 25940500}, {-8597910, 25770800}, + {-8512360, 25589000}, {-8450270, 25397900}, + {-8412620, 25200500}, {-8400000, 25000000}, + {-8412620, 24799500}, {-8450270, 24602100}, + {-8512360, 24411000}, {-8597910, 24229200}, + {-8705570, 24059500}, {-8833650, 23904700}, + {-8980120, 23767200}, {-9142680, 23649100}, + {-9318750, 23552300}, {-9505570, 23478300}, + {-9700190, 23428300}, {-9899530, 23403200}, + }, + { + {9899530, 23403200}, {9700190, 23428300}, + {9505570, 23478300}, {9318750, 23552300}, + {9142680, 23649100}, {8980120, 23767200}, + {8833650, 23904700}, {8705570, 24059500}, + {8597910, 24229200}, {8512360, 24411000}, + {8450270, 24602100}, {8412620, 24799500}, + {8400000, 25000000}, {8412620, 25200500}, + {8450270, 25397900}, {8512360, 25589000}, + {8597910, 25770800}, {8705570, 25940500}, + {8833650, 26095300}, {8980120, 26232800}, + {9142680, 26350900}, {9318750, 26447700}, + {9505570, 26521700}, {9700190, 26571700}, + {9899530, 26596800}, {10100500, 26596800}, + {10299800, 26571700}, {10494400, 26521700}, + {10681200, 26447700}, {10857300, 26350900}, + {11019900, 26232800}, {11166300, 26095300}, + {11294400, 25940500}, {11402100, 25770800}, + {11487600, 25589000}, {11549700, 25397900}, + {11587400, 25200500}, {11600000, 25000000}, + {11587400, 24799500}, {11549700, 24602100}, + {11487600, 24411000}, {11402100, 24229200}, + {11294400, 24059500}, {11166300, 23904700}, + {11019900, 23767200}, {10857300, 23649100}, + {10681200, 23552300}, {10494400, 23478300}, + {10299800, 23428300}, {10100500, 23403200}, + }, + { + {-100465, 5903160}, {-299809, 5928340}, + {-494427, 5978310}, {-681247, 6052280}, + {-857323, 6149070}, {-1019880, 6267180}, + {-1166350, 6404720}, {-1294430, 6559540}, + {-1402090, 6729190}, {-1487640, 6911000}, + {-1549730, 7102100}, {-1587380, 7299470}, + {-1600000, 7500000}, {-1587380, 7700530}, + {-1549730, 7897900}, {-1487640, 8088999}, + {-1402090, 8270810}, {-1294430, 8440460}, + {-1166350, 8595270}, {-1019880, 8732820}, + {-857323, 8850920}, {-681247, 8947720}, + {-494427, 9021690}, {-299809, 9071660}, + {-100465, 9096840}, {100465, 9096840}, + {299809, 9071660}, {494427, 9021690}, + {681247, 8947720}, {857323, 8850920}, + {1019880, 8732820}, {1166350, 8595270}, + {1294430, 8440460}, {1402090, 8270810}, + {1487640, 8088999}, {1549730, 7897900}, + {1587380, 7700530}, {1600000, 7500000}, + {1587380, 7299470}, {1549730, 7102100}, + {1487640, 6911000}, {1402090, 6729190}, + {1294430, 6559540}, {1166350, 6404720}, + {1019880, 6267180}, {857323, 6149070}, + {681247, 6052280}, {494427, 5978310}, + {299809, 5928340}, {100465, 5903160}, + }, + }}, + }, + ExPolygons{ + // "y-rod-holder.stl": + MyPoly{{ + {-4130159, -11630200}, {-4125905, -11625938}, + {-4036359, -11536400}, {-3977214, -11477197}, + {-3893620, -11393600}, {-3968460, -11001300}, + {-4000000, -10500000}, {-3968460, -9998670}, + {-3874330, -9505240}, {-3719110, -9027500}, + {-3505230, -8572980}, {-3236070, -8148860}, + {-2915870, -7761810}, {-2549700, -7417950}, + {-2143310, -7122690}, {-1920140, -7000000}, + {-1703120, -6880690}, {-1236070, -6695770}, + {-749525, -6570850}, {-251162, -6507890}, + {251162, -6507890}, {749525, -6570850}, + {1236070, -6695770}, {1703120, -6880690}, + {1920140, -7000000}, {2143310, -7122690}, + {2549700, -7417950}, {2915870, -7761810}, + {3236070, -8148860}, {3505230, -8572980}, + {3719110, -9027500}, {3874330, -9505240}, + {3968460, -9998670}, {4000000, -10500000}, + {3968460, -11001300}, {3916390, -11274300}, + {4089891, -11447789}, {4113299, -11471200}, + {4642140, -12000000}, {8618800, -12000000}, + {10350900, -9000000}, {11376300, -7223940}, + {13000000, -4411540}, {13000000, 0}, + {4000000, 0}, {4000000, 1500000}, + {-4000000, 1500000}, {-4000000, 0}, + {-13000000, 0}, {-13000000, -4202820}, + {-8498290, -12000000}, {-4500000, -12000000}, + }, + {}}, + }, + ExPolygons{ + // "extruder-body.stl": + MyPoly{{ + {32000000, -41357900}, {32000000, -34500000}, + {27500000, -30000000}, {22600000, -30000000}, + {22600000, -29900000}, {22500000, -30000000}, + {17000000, -24500000}, {17000000, -12000000}, + {23000000, -12000000}, {23000000, -18000000}, + {23928900, -18000000}, {26000000, -15928900}, + {26000000, -10000000}, {23000000, -7000000}, + {17000000, -7000000}, {17000000, 44000000}, + {11000000, 50000000}, {-18000000, 50000000}, + {-25000000, 43000000}, {-25000000, 5750000}, + {-27250000, 5750000}, {-31500000, 1500000}, + {-31500000, -1500000}, {-24500000, -1500000}, + {-24500000, 2500000}, {-21309400, 2500000}, + {-20500000, 1098080}, {-20500000, -44000000}, + {-15500000, -44000000}, {-15500000, -38000000}, + {-14000000, -36500000}, {14000000, -36500000}, + {14000000, -38916000}, {14423151, -39823468}, + {14452100, -39885600}, {15259800, -41617700}, + {18642100, -45000000}, {28357900, -45000000}, + }, + { + { + {-19603600, 40853300}, {-19790500, 40876900}, + {-19809200, 40879200}, {-19991600, 40926100}, + {-20009900, 40930800}, {-20202500, 41007000}, + {-20384100, 41106900}, {-20491899, 41185194}, + {-20551700, 41228700}, {-20551800, 41228700}, + {-20702800, 41370500}, {-20834900, 41530200}, + {-20945900, 41705100}, {-21034100, 41892600}, + {-21098200, 42089700}, {-21137000, 42293200}, + {-21150000, 42500000}, {-21137000, 42706800}, + {-21098200, 42910300}, {-21034100, 43107400}, + {-20945900, 43294900}, {-20834900, 43469800}, + {-20702800, 43629500}, {-20551800, 43771300}, + {-20551700, 43771300}, {-20491899, 43814806}, + {-20384100, 43893100}, {-20202500, 43993000}, + {-20009900, 44069200}, {-19991600, 44073900}, + {-19809200, 44120800}, {-19790500, 44123100}, + {-19603600, 44146700}, {-19396400, 44146700}, + {-19209500, 44123100}, {-19190800, 44120800}, + {-19008400, 44073900}, {-18990100, 44069200}, + {-18797500, 43993000}, {-18615900, 43893100}, + {-18448200, 43771300}, {-18297200, 43629500}, + {-18165100, 43469800}, {-18054100, 43294900}, + {-17965900, 43107400}, {-17901800, 42910300}, + {-17863000, 42706800}, {-17850000, 42500000}, + {-17863000, 42293200}, {-17901800, 42089700}, + {-17965900, 41892600}, {-18054100, 41705100}, + {-18165100, 41530200}, {-18297200, 41370500}, + {-18448200, 41228700}, {-18615900, 41106900}, + {-18797500, 41007000}, {-18990100, 40930800}, + {-19008400, 40926100}, {-19190800, 40879200}, + {-19209500, 40876900}, {-19396400, 40853300}, + }, + { + {11396400, 40853300}, {11190800, 40879200}, + {10990100, 40930800}, {10797500, 41007000}, + {10615900, 41106900}, {10448200, 41228700}, + {10297200, 41370500}, {10165100, 41530200}, + {10054100, 41705100}, {9965870, 41892600}, + {9901840, 42089700}, {9863010, 42293200}, + {9850000, 42500000}, {9863010, 42706800}, + {9901840, 42910300}, {9965870, 43107400}, + {10054100, 43294900}, {10165100, 43469800}, + {10297200, 43629500}, {10448200, 43771300}, + {10615900, 43893100}, {10797500, 43993000}, + {10990100, 44069200}, {11190800, 44120800}, + {11396400, 44146700}, {11603600, 44146700}, + {11809200, 44120800}, {12009900, 44069200}, + {12202500, 43993000}, {12384100, 43893100}, + {12551700, 43771300}, {12702800, 43629500}, + {12834900, 43469800}, {12945900, 43294900}, + {13034100, 43107400}, {13098200, 42910300}, + {13137000, 42706800}, {13150000, 42500000}, + {13137000, 42293200}, {13098200, 42089700}, + {13034100, 41892600}, {12945900, 41705100}, + {12834900, 41530200}, {12702800, 41370500}, + {12551700, 41228700}, {12384100, 41106900}, + {12202500, 41007000}, {12009900, 40930800}, + {11809200, 40879200}, {11603600, 40853300}, + }, + { + {-3181780, 21500000}, {-15111782, 22578598}, + {-15737800, 24505100}, {-15797300, 25071800}, + {-15997500, 26976600}, {-16000000, 27000000}, + {-15737800, 29494900}, {-14962500, 31880800}, + {-13708200, 34053400}, {-12029600, 35917700}, + {-10000000, 37392300}, {-8500000, 38060100}, + {-7708200, 38412700}, {-5282850, 38928200}, + {-5254340, 38934300}, {-3000000, 38934300}, + {-3000000, 33500000}, {-1092350, 31592300}, + {-1091812, 31591773}, {-1065440, 31565400}, + {-1063162, 31563127}, {-963937, 31463900}, + {-889918, 31389900}, {-860013, 31360013}, + {-612800, 31112800}, {-589409, 31089400}, + {-366049, 30866044}, {-339918, 30839900}, + {-206119, 30706100}, {0, 30500000}, + {206119, 30706100}, {339918, 30839900}, + {362385, 30862377}, {889918, 31389900}, + {963937, 31463900}, {1063442, 31563406}, + {1065440, 31565400}, {1091822, 31591782}, + {1092350, 31592300}, {4000000, 34500000}, + {4000000, 35939184}, {4029570, 35917700}, + {5708200, 34053400}, {6962550, 31880800}, + {7737770, 29494900}, {8000000, 27000000}, + {7737770, 24505100}, {6962550, 22119200}, + {6605070, 21500000}, {1727920, 21500000}, + {1698940, 21529000}, {1530830, 21697100}, + {1516490, 21711437}, {1125240, 22102700}, + {894136, 22333800}, {648935, 22579000}, + {318574, 22909343}, {131860, 23096100}, + {0, 23227900}, {-131860, 23096100}, + {-318574, 22909343}, {-648935, 22579000}, + {-894136, 22333800}, {-1125240, 22102700}, + {-1516490, 21711437}, {-1530830, 21697100}, + {-1698940, 21529000}, {-1727920, 21500000}, + }, + { + {-19603600, 9853260}, {-19809200, 9879230}, + {-20009900, 9930760}, {-20202500, 10007000}, + {-20384100, 10106900}, {-20551800, 10228700}, + {-20702800, 10370500}, {-20834900, 10530200}, + {-20945900, 10705100}, {-21034100, 10892600}, + {-21098200, 11089700}, {-21137000, 11293200}, + {-21150000, 11500000}, {-21137000, 11706800}, + {-21098200, 11910300}, {-21034100, 12107400}, + {-20945900, 12294900}, {-20834900, 12469800}, + {-20702800, 12629500}, {-20551800, 12771300}, + {-20384100, 12893100}, {-20202500, 12993000}, + {-20009900, 13069200}, {-19809200, 13120800}, + {-19603600, 13146700}, {-19396400, 13146700}, + {-19190800, 13120800}, {-18990100, 13069200}, + {-18797500, 12993000}, {-18615900, 12893100}, + {-18448200, 12771300}, {-18297200, 12629500}, + {-18165100, 12469800}, {-18054100, 12294900}, + {-17965900, 12107400}, {-17901800, 11910300}, + {-17863000, 11706800}, {-17850000, 11500000}, + {-17863000, 11293200}, {-17901800, 11089700}, + {-17965900, 10892600}, {-18054100, 10705100}, + {-18165100, 10530200}, {-18297200, 10370500}, + {-18448200, 10228700}, {-18615900, 10106900}, + {-18797500, 10007000}, {-18990100, 9930760}, + {-19190800, 9879230}, {-19396400, 9853260}, + }, + { + {11396400, 9853260}, {11190800, 9879230}, + {10990100, 9930760}, {10797500, 10007000}, + {10615900, 10106900}, {10448200, 10228700}, + {10297200, 10370500}, {10165100, 10530200}, + {10054100, 10705100}, {9965870, 10892600}, + {9901840, 11089700}, {9863010, 11293200}, + {9850000, 11500000}, {9863010, 11706800}, + {9901840, 11910300}, {9965870, 12107400}, + {10054100, 12294900}, {10165100, 12469800}, + {10297200, 12629500}, {10448200, 12771300}, + {10615900, 12893100}, {10797500, 12993000}, + {10990100, 13069200}, {11190800, 13120800}, + {11396400, 13146700}, {11603600, 13146700}, + {11809200, 13120800}, {12009900, 13069200}, + {12202500, 12993000}, {12384100, 12893100}, + {12551700, 12771300}, {12702800, 12629500}, + {12834900, 12469800}, {12945900, 12294900}, + {13034100, 12107400}, {13098200, 11910300}, + {13137000, 11706800}, {13150000, 11500000}, + {13137000, 11293200}, {13098200, 11089700}, + {13034100, 10892600}, {12945900, 10705100}, + {12834900, 10530200}, {12702800, 10370500}, + {12551700, 10228700}, {12384100, 10106900}, + {12202500, 10007000}, {12009900, 9930760}, + {11809200, 9879230}, {11603600, 9853260}, + }, + { + {-17177700, 1309310}, {-17525300, 1383200}, + {-17850000, 1527760}, {-18137500, 1736650}, + {-18375300, 2000760}, {-18553000, 2308550}, + {-18662800, 2646550}, {-18700000, 3000000}, + {-18662800, 3353450}, {-18553000, 3691450}, + {-18375300, 3999230}, {-18137500, 4263350}, + {-17850000, 4472240}, {-17525300, 4616800}, + {-17177700, 4690690}, {-16822300, 4690690}, + {-16474701, 4616800}, {-16150000, 4472240}, + {-15862500, 4263350}, {-15624700, 3999230}, + {-15447000, 3691450}, {-15337100, 3353450}, + {-15300000, 3000000}, {-15337100, 2646550}, + {-15447000, 2308550}, {-15624700, 2000760}, + {-15862500, 1736650}, {-16150000, 1527760}, + {-16474701, 1383200}, {-16822300, 1309310}, + }, + { + {-11603600, -2146740}, {-11809200, -2120770}, + {-12009900, -2069240}, {-12202500, -1992960}, + {-12384100, -1893140}, {-12551700, -1771350}, + {-12702800, -1629500}, {-12834900, -1469840}, + {-12945900, -1294890}, {-13034100, -1107400}, + {-13098200, -910337}, {-13137000, -706800}, + {-13150000, -500000}, {-13137000, -293200}, + {-13098200, -89661}, {-13034100, 107405}, + {-12945900, 294893}, {-12834900, 469845}, + {-12702800, 629502}, {-12551700, 771346}, + {-12384100, 893141}, {-12202500, 992964}, + {-12009900, 1069240}, {-11809200, 1120770}, + {-11603600, 1146740}, {-11396400, 1146740}, + {-11190800, 1120770}, {-10990100, 1069240}, + {-10797500, 992964}, {-10615900, 893141}, + {-10448200, 771346}, {-10297200, 629502}, + {-10165100, 469845}, {-10054100, 294893}, + {-9965870, 107405}, {-9901840, -89661}, + {-9863010, -293200}, {-9850000, -499999}, + {-9863010, -706800}, {-9901840, -910337}, + {-9965870, -1107400}, {-10054100, -1294890}, + {-10165100, -1469840}, {-10297200, -1629500}, + {-10448200, -1771350}, {-10615900, -1893140}, + {-10797500, -1992960}, {-10990100, -2069240}, + {-11190800, -2120770}, {-11396400, -2146740}, + }, + { + {11396400, -2146740}, {11190800, -2120770}, + {10990100, -2069240}, {10797500, -1992960}, + {10615900, -1893140}, {10448200, -1771350}, + {10297200, -1629500}, {10165100, -1469840}, + {10054100, -1294890}, {9965870, -1107400}, + {9901840, -910337}, {9863010, -706800}, + {9850000, -500000}, {9863010, -293200}, + {9901840, -89661}, {9965870, 107405}, + {10054100, 294893}, {10165100, 469845}, + {10297200, 629502}, {10448200, 771346}, + {10615900, 893141}, {10797500, 992964}, + {10990100, 1069240}, {11190800, 1120770}, + {11396400, 1146740}, {11603600, 1146740}, + {11809200, 1120770}, {12009900, 1069240}, + {12202500, 992964}, {12384100, 893141}, + {12551700, 771346}, {12702800, 629502}, + {12834900, 469845}, {12945900, 294893}, + {13034100, 107405}, {13098200, -89661}, + {13137000, -293200}, {13150000, -499999}, + {13137000, -706800}, {13098200, -910337}, + {13034100, -1107400}, {12945900, -1294890}, + {12834900, -1469840}, {12702800, -1629500}, + {12551700, -1771350}, {12384100, -1893140}, + {12202500, -1992960}, {12009900, -2069240}, + {11809200, -2120770}, {11603600, -2146740}, + }, + }}, + }, + ExPolygons{ + // "z-axis-top.stl": + MyPoly{{ + {34521100, -3478930}, + {38000000, 0}, + {38000000, 23000000}, + {33000000, 28000000}, + {24000000, 28000000}, + {20000000, 21071800}, + {12000000, 21071800}, + {8000000, 28000000}, + {8000000, 34200000}, + {2200000, 40000000}, + {0, 40000000}, + {0, 1000000}, + {6000000, -5000000}, + {33000000, -5000000}, + }, + { + { + {12000000, 3071800}, + {8000000, 10000000}, + {12000000, 16928200}, + {20000000, 16928200}, + {24000000, 10000000}, + {20000000, 3071800}, + }, + }}, + MyPoly{{ + {8000000, -46200000}, + {8000000, -40000000}, + {12000000, -33071800}, + {20000000, -33071800}, + {24000000, -40000000}, + {33000000, -40000000}, + {38000000, -35000000}, + {38000000, -12000000}, + {34521100, -8521070}, + {33000000, -7000000}, + {6000000, -7000000}, + {0, -13000000}, + {0, -52000000}, + {2200000, -52000000}, + }, + { + { + {12000000, -28928200}, + {8000000, -22000000}, + {12000000, -15071800}, + {20000000, -15071800}, + {24000000, -22000000}, + {20000000, -28928200}, + }, + }}, + }, + ExPolygons{ + // "y-belt-holder.stl": + MyPoly{{ + {12500000, 24000000}, + {5142140, 24000000}, + {4500000, 23357900}, + {4500000, 15000000}, + {-9057860, 15000000}, + {-11000000, 13057900}, + {-11000000, -13057900}, + {-9057860, -15000000}, + {4500000, -15000000}, + {4500000, -23357900}, + {5142140, -24000000}, + {12500000, -24000000}, + }, + {}}, + }, + ExPolygons{ + // "LCD-knob.stl": + MyPoly{{ + {1045280, -9945220}, {2079119, -9781480}, + {3090170, -9510560}, {4067370, -9135450}, + {5000000, -8660250}, {5877850, -8090170}, + {6691310, -7431450}, {7431450, -6691310}, + {8090170, -5877850}, {8660250, -5000000}, + {9135450, -4067370}, {9510560, -3090170}, + {9781480, -2079119}, {9945220, -1045280}, + {10000000, 0}, {9945220, 1045280}, + {9781480, 2079119}, {9510560, 3090170}, + {9135450, 4067370}, {8660250, 5000000}, + {8090170, 5877850}, {7431450, 6691310}, + {6691310, 7431450}, {5877850, 8090170}, + {5000000, 8660250}, {4067370, 9135450}, + {3090170, 9510560}, {2100000, 9775880}, + {2100000, 18221800}, {-2100000, 18221800}, + {-2100000, 9775880}, {-3090170, 9510560}, + {-4067370, 9135450}, {-5000000, 8660250}, + {-5877850, 8090170}, {-6691310, 7431450}, + {-7431450, 6691310}, {-8090170, 5877850}, + {-8660250, 5000000}, {-9135450, 4067370}, + {-9510560, 3090170}, {-9781480, 2079119}, + {-9945220, 1045280}, {-10000000, 0}, + {-9945220, -1045280}, {-9781480, -2079119}, + {-9510560, -3090170}, {-9135450, -4067370}, + {-8660250, -5000000}, {-8090170, -5877850}, + {-7431450, -6691310}, {-6691310, -7431450}, + {-5877850, -8090170}, {-5000000, -8660250}, + {-4067370, -9135450}, {-3090170, -9510560}, + {-2079119, -9781480}, {-1045280, -9945220}, + {0, -10000000}, + }, + {}}, + }, + ExPolygons{ + // "rpi-zero-frame.stl": + MyPoly{{ + {58000000, -25983600}, {58313600, -25983600}, + {58927100, -25853200}, {59500000, -25598100}, + {60007400, -25229400}, {60427100, -24763400}, + {60740600, -24220200}, {60934400, -23623700}, + {61000000, -23000000}, {61000000, 0}, + {60934400, 623734}, {60740600, 1220210}, + {60427100, 1763360}, {60007400, 2229430}, + {59500000, 2598080}, {58927100, 2853170}, + {58313600, 2983570}, {58000000, 2983570}, + {58000000, 3000000}, {55000000, 3000000}, + {55000000, 6000000}, {45000000, 6000000}, + {45000000, 3000000}, {0, 3000000}, + {0, 2983570}, {-313585, 2983570}, + {-927051, 2853170}, {-1500000, 2598080}, + {-2007390, 2229430}, {-2427050, 1763360}, + {-2740640, 1220210}, {-2934440, 623734}, + {-3000000, 0}, {-3000000, -23000000}, + {-2934440, -23623700}, {-2740640, -24220200}, + {-2427050, -24763400}, {-2007390, -25229400}, + {-1500000, -25598100}, {-927051, -25853200}, + {-313585, -25983600}, {313585, -25983600}, + {927051, -25853200}, {1000000, -25820720}, + {1000000, -26000000}, {58000000, -26000000}, + }, + { + { + {44883600, -2063829}, + {44638500, -2012070}, + {44409000, -1909530}, + {44205900, -1762070}, + {44037900, -1575550}, + {43912900, -1358750}, + {43834800, -1120470}, + {43822600, -1000000}, + {46195173, -1000000}, + {46182500, -1120470}, + {46105300, -1358750}, + {45979300, -1575550}, + {45812300, -1762070}, + {45609200, -1909530}, + {45379700, -2012070}, + {45134600, -2063829}, + }, + { + {51045700, -1970080}, + {50800600, -1918320}, + {50571100, -1815780}, + {50368000, -1668320}, + {50200000, -1481800}, + {50075000, -1265000}, + {49996900, -1025740}, + {49994200, -1000000}, + {52347300, -1000000}, + {52344600, -1025740}, + {52267400, -1265000}, + {52141400, -1481800}, + {51973500, -1668320}, + {51771300, -1815780}, + {51541800, -1918320}, + {51296700, -1970080}, + }, + { + {3000000, -20000000}, + {3000000, -3000000}, + {43887500, -3000000}, + {43912900, -2922230}, + {44037900, -2705430}, + {44205900, -2518910}, + {44409000, -2371440}, + {44638500, -2268910}, + {44883600, -2217150}, + {45134600, -2217150}, + {45379700, -2268910}, + {45609200, -2371440}, + {45812300, -2518910}, + {45979300, -2705430}, + {46105300, -2922230}, + {46130400, -3000000}, + {55000000, -3000000}, + {55000000, -20000000}, + }, + { + {22525500, -22729500}, {22321000, -22686100}, + {22130000, -22601000}, {21960900, -22478100}, + {21821000, -22322800}, {21716500, -22141700}, + {21651900, -21942900}, {21630000, -21735000}, + {21651900, -21527100}, {21716500, -21328300}, + {21821000, -21147200}, {21960900, -20991900}, + {22130000, -20869000}, {22321000, -20783900}, + {22525500, -20740500}, {22734500, -20740500}, + {22939000, -20783900}, {23130000, -20869000}, + {23299100, -20991900}, {23439000, -21147200}, + {23543500, -21328300}, {23608100, -21527100}, + {23630000, -21735000}, {23608100, -21942900}, + {23543500, -22141700}, {23439000, -22322800}, + {23299100, -22478100}, {23130000, -22601000}, + {22939000, -22686100}, {22734500, -22729500}, + }, + { + {7285470, -25269500}, {7080980, -25226100}, + {6890000, -25141000}, {6720870, -25018100}, + {6580980, -24862800}, {6476450, -24681700}, + {6411850, -24482900}, {6390000, -24275000}, + {6411850, -24067100}, {6476450, -23868300}, + {6580980, -23687200}, {6720870, -23531900}, + {6890000, -23409000}, {7080980, -23323900}, + {7285470, -23280500}, {7494530, -23280500}, + {7699020, -23323900}, {7890000, -23409000}, + {8059129, -23531900}, {8199020, -23687200}, + {8303540, -23868300}, {8368150, -24067100}, + {8390000, -24275000}, {8368150, -24482900}, + {8303540, -24681700}, {8199020, -24862800}, + {8059129, -25018100}, {7890000, -25141000}, + {7699020, -25226100}, {7494530, -25269500}, + }, + { + {22525500, -25269500}, {22321000, -25226100}, + {22130000, -25141000}, {21960900, -25018100}, + {21821000, -24862800}, {21716500, -24681700}, + {21651900, -24482900}, {21630000, -24275000}, + {21651900, -24067100}, {21716500, -23868300}, + {21821000, -23687200}, {21960900, -23531900}, + {22130000, -23409000}, {22321000, -23323900}, + {22525500, -23280500}, {22734500, -23280500}, + {22939000, -23323900}, {23130000, -23409000}, + {23299100, -23531900}, {23439000, -23687200}, + {23543500, -23868300}, {23608100, -24067100}, + {23630000, -24275000}, {23608100, -24482900}, + {23543500, -24681700}, {23439000, -24862800}, + {23299100, -25018100}, {23130000, -25141000}, + {22939000, -25226100}, {22734500, -25269500}, + }, + { + {14905500, -25269500}, {14701000, -25226100}, + {14510000, -25141000}, {14340900, -25018100}, + {14201000, -24862800}, {14096500, -24681700}, + {14031900, -24482900}, {14010000, -24275000}, + {14031900, -24067100}, {14096500, -23868300}, + {14201000, -23687200}, {14340900, -23531900}, + {14510000, -23409000}, {14701000, -23323900}, + {14905500, -23280500}, {15114500, -23280500}, + {15319000, -23323900}, {15510000, -23409000}, + {15679100, -23531900}, {15819000, -23687200}, + {15923500, -23868300}, {15988100, -24067100}, + {16010000, -24275000}, {15988100, -24482900}, + {15923500, -24681700}, {15819000, -24862800}, + {15679100, -25018100}, {15510000, -25141000}, + {15319000, -25226100}, {15114500, -25269500}, + }, + { + {12365500, -25269500}, {12161000, -25226100}, + {11970000, -25141000}, {11800900, -25018100}, + {11661000, -24862800}, {11556500, -24681700}, + {11491900, -24482900}, {11470000, -24275000}, + {11491900, -24067100}, {11556500, -23868300}, + {11661000, -23687200}, {11800900, -23531900}, + {11970000, -23409000}, {12161000, -23323900}, + {12365500, -23280500}, {12574500, -23280500}, + {12779000, -23323900}, {12970000, -23409000}, + {13139100, -23531900}, {13279000, -23687200}, + {13383500, -23868300}, {13448100, -24067100}, + {13470000, -24275000}, {13448100, -24482900}, + {13383500, -24681700}, {13279000, -24862800}, + {13139100, -25018100}, {12970000, -25141000}, + {12779000, -25226100}, {12574500, -25269500}, + }, + { + {9825470, -25269500}, {9620980, -25226100}, + {9430000, -25141000}, {9260870, -25018100}, + {9120980, -24862800}, {9016450, -24681700}, + {8951850, -24482900}, {8930000, -24275000}, + {8951850, -24067100}, {9016450, -23868300}, + {9120980, -23687200}, {9260870, -23531900}, + {9430000, -23409000}, {9620980, -23323900}, + {9825470, -23280500}, {10034500, -23280500}, + {10239000, -23323900}, {10430000, -23409000}, + {10599100, -23531900}, {10739000, -23687200}, + {10843500, -23868300}, {10908100, -24067100}, + {10930000, -24275000}, {10908100, -24482900}, + {10843500, -24681700}, {10739000, -24862800}, + {10599100, -25018100}, {10430000, -25141000}, + {10239000, -25226100}, {10034500, -25269500}, + }, + }}, + }, + ExPolygons{ + // "extruder-idler.stl": + MyPoly{{ + {31500000, 47000000}, {21500000, 47000000}, + {21500000, 43000000}, {21483600, 43000000}, + {21483600, 42686400}, {21443900, 42500000}, + {21391492, 42253213}, {21356700, 42089700}, + {21353200, 42072900}, {21302200, 41958400}, + {21234000, 41805300}, {21184936, 41695077}, + {21111500, 41530200}, {21098100, 41500000}, + {21058200, 41445200}, {20966500, 41319000}, + {20900900, 41228700}, {20812400, 41106900}, + {20729400, 40992600}, {20660700, 40930800}, + {20566175, 40845649}, {20359300, 40659400}, + {20263400, 40572900}, {19720200, 40259400}, + {19123700, 40065600}, {18688436, 40019806}, + {18500000, 40000000}, {18409800, 40009500}, + {17876300, 40065600}, {17279800, 40259400}, + {16736601, 40572900}, {16640699, 40659400}, + {16435924, 40843758}, {16339300, 40930800}, + {16270599, 40992600}, {16187599, 41106900}, + {16099100, 41228700}, {15996000, 41370500}, + {16270599, 40992600}, {15901900, 41500000}, + {15888500, 41530200}, {15810600, 41705100}, + {15755314, 41829246}, {15735700, 41873300}, + {15646800, 42072900}, {15643300, 42089700}, + {15608508, 42253213}, {15556100, 42500000}, + {15516400, 42686400}, {15516400, 43000000}, + {15500000, 43000000}, {15500000, 47000000}, + {6500000, 47000000}, {6500000, 39000000}, + {3500000, 39000000}, {3500000, 22000000}, + {6500000, 22000000}, {6500000, 13000000}, + {31500000, 13000000}, + }, + { + { + {12923500, 25400000}, + {12144000, 25850000}, + {12144000, 32150002}, + {12923500, 32599998}, + {17600000, 35300000}, + {18379400, 34850000}, + {23056000, 32150002}, + {23056000, 32000000}, + {22750000, 32000000}, + {22750000, 30992100}, + {21750000, 29994100}, + {21750000, 25096023}, + {17600000, 22700000}, + }, + { + {26393300, 16803400}, {26181400, 16830100}, + {25974700, 16883200}, {25776200, 16961800}, + {25589100, 17064600}, {25416400, 17190100}, + {25260800, 17336300}, {25124700, 17500800}, + {25010300, 17681000}, {24919400, 17874200}, + {24853400, 18077200}, {24813400, 18286900}, + {24800000, 18500000}, {24813400, 18713100}, + {24853400, 18922800}, {24919400, 19125800}, + {25010300, 19319000}, {25124700, 19499200}, + {25260800, 19663700}, {25416400, 19809900}, + {25589100, 19935400}, {25776200, 20038200}, + {25974700, 20116800}, {26181400, 20169900}, + {26393300, 20196600}, {26606700, 20196600}, + {26818500, 20169900}, {27025300, 20116800}, + {27223800, 20038200}, {27410900, 19935400}, + {27583600, 19809900}, {27739200, 19663700}, + {27875300, 19499200}, {27989700, 19319000}, + {28080600, 19125800}, {28146600, 18922800}, + {28186600, 18713100}, {28200000, 18500000}, + {28186600, 18286900}, {28146600, 18077200}, + {28080600, 17874200}, {27989700, 17681000}, + {27875300, 17500800}, {27739200, 17336300}, + {27583600, 17190100}, {27410900, 17064600}, + {27223800, 16961800}, {27025300, 16883200}, + {26818500, 16830100}, {26606700, 16803400}, + }, + { + {11393300, 16803400}, {11181500, 16830100}, + {10974700, 16883200}, {10776200, 16961800}, + {10589100, 17064600}, {10416400, 17190100}, + {10260800, 17336300}, {10124700, 17500800}, + {10010300, 17681000}, {9919380, 17874200}, + {9853410, 18077200}, {9813400, 18286900}, + {9800000, 18500000}, {9813400, 18713100}, + {9853410, 18922800}, {9919380, 19125800}, + {10010300, 19319000}, {10124700, 19499200}, + {10260800, 19663700}, {10416400, 19809900}, + {10589100, 19935400}, {10776200, 20038200}, + {10974700, 20116800}, {11181500, 20169900}, + {11393300, 20196600}, {11606700, 20196600}, + {11818500, 20169900}, {12025300, 20116800}, + {12223800, 20038200}, {12410900, 19935400}, + {12583600, 19809900}, {12739200, 19663700}, + {12875300, 19499200}, {12989700, 19319000}, + {13080600, 19125800}, {13146600, 18922800}, + {13186600, 18713100}, {13200000, 18500000}, + {13186600, 18286900}, {13146600, 18077200}, + {13080600, 17874200}, {12989700, 17681000}, + {12875300, 17500800}, {12739200, 17336300}, + {12583600, 17190100}, {12410900, 17064600}, + {12223800, 16961800}, {12025300, 16883200}, + {11818500, 16830100}, {11606700, 16803400}, + }, + }}, + }, + ExPolygons{ + // "filament-sensor-cover.stl": + MyPoly{{ + {18000000, 30500000}, + {-6000000, 30500000}, + {-6000000, -5500000}, + {18000000, -5500000}, + }, + { + { + {-1167240, 22908800}, {-1494430, 22978300}, + {-1800000, 23114400}, {-2070610, 23311000}, + {-2294430, 23559500}, {-2461670, 23849200}, + {-2565040, 24167300}, {-2582520, 24333700}, + {-2600000, 24500000}, {-2582520, 24666300}, + {-2565040, 24832700}, {-2461670, 25150800}, + {-2294430, 25440500}, {-2070610, 25689000}, + {-1800000, 25885600}, {-1494430, 26021700}, + {-1167240, 26091200}, {-832754, 26091200}, + {-505572, 26021700}, {-200000, 25885600}, + {70608, 25689000}, {294427, 25440500}, + {461672, 25150800}, {565036, 24832700}, + {582518, 24666300}, {599999, 24500000}, + {582518, 24333700}, {565036, 24167300}, + {461672, 23849200}, {294427, 23559500}, + {70608, 23311000}, {-200000, 23114400}, + {-505572, 22978300}, {-832754, 22908800}, + }, + { + {-144249, 15627600}, {-426443, 15687500}, + {-689999, 15804900}, {-740738, 15841700}, + {-923400, 15974500}, {-965366, 16021099}, + {-1116440, 16188900}, {-1229330, 16384399}, + {-1260690, 16438700}, {-1280070, 16498400}, + {-1349840, 16713100}, {-1373440, 16937600}, + {-1380000, 17000000}, {-1373440, 17062400}, + {-1349840, 17286900}, {-1280070, 17501600}, + {-1260690, 17561300}, {-1229330, 17615600}, + {-1116440, 17811100}, {-965366, 17978900}, + {-923400, 18025500}, {-872661, 18062400}, + {-689999, 18195100}, {-483738, 18286900}, + {-426443, 18312500}, {-144249, 18372400}, + {144249, 18372400}, {426443, 18312500}, + {483738, 18286900}, {689999, 18195100}, + {872661, 18062400}, {923400, 18025500}, + {965366, 17978900}, {1116440, 17811100}, + {1229330, 17615600}, {1260690, 17561300}, + {1280070, 17501600}, {1349840, 17286900}, + {1373440, 17062400}, {1380000, 17000000}, + {1373440, 16937600}, {1349840, 16713100}, + {1280070, 16498400}, {1260690, 16438700}, + {1229330, 16384399}, {1116440, 16188900}, + {965366, 16021099}, {923400, 15974500}, + {872661, 15937600}, {689999, 15804900}, + {483738, 15713100}, {426443, 15687500}, + {144249, 15627600}, + }, + { + {11832800, 10408800}, {11505600, 10478300}, + {11200000, 10614400}, {10929400, 10811000}, + {10705600, 11059500}, {10538300, 11349200}, + {10435000, 11667300}, {10400000, 12000000}, + {10435000, 12332700}, {10538300, 12650800}, + {10705600, 12940500}, {10929400, 13189000}, + {11200000, 13385600}, {11505600, 13521700}, + {11832800, 13591200}, {12167200, 13591200}, + {12494400, 13521700}, {12800000, 13385600}, + {13070600, 13189000}, {13294400, 12940500}, + {13461700, 12650800}, {13565000, 12332700}, + {13585100, 12141400}, {13600000, 12000000}, + {13582500, 11833700}, {13565000, 11667300}, + {13461700, 11349200}, {13294400, 11059500}, + {13070600, 10811000}, {12800000, 10614400}, + {12494400, 10478300}, {12167200, 10408800}, + }, + }}, + }, + ExPolygons{ + // "nozzle-fan.stl": + MyPoly{{ + {-14922022, 12367866}, {-14205200, 14337200}, + {-13800000, 15450500}, {-13800000, 17000000}, + {-13789800, 17000000}, {-13704300, 17813300}, + {-13694100, 17910800}, {-12789600, 20694300}, + {-11326200, 23229000}, {-9367830, 25404000}, + {-7000000, 27124400}, {-5253290, 27902000}, + {-4326240, 28314800}, {-1463400, 28923300}, + {1463400, 28923300}, {4326240, 28314800}, + {5253290, 27902000}, {7000000, 27124400}, + {9367830, 25404000}, {11326200, 23229000}, + {12789600, 20694300}, {13694100, 17910800}, + {13704300, 17813300}, {13789800, 17000000}, + {13800000, 17000000}, {13800000, 15606900}, + {14240100, 14397700}, {15015200, 12268200}, + {15476800, 11000000}, {17800000, 11000000}, + {17800000, 11032900}, {18427200, 11032900}, + {19654100, 11293700}, {20800000, 11803800}, + {21814800, 12541100}, {22654100, 13473300}, + {23281300, 14559600}, {23668900, 15752500}, + {23706600, 16111099}, {23800000, 17000000}, + {23789800, 17000000}, {23475500, 19989900}, + {21925100, 24761700}, {19416400, 29106800}, + {18612200, 30000000}, {18000000, 30679900}, + {18000000, 35500000}, {18500000, 35500000}, + {18500000, 40500000}, {17839500, 40500000}, + {11200000, 52000000}, {9532010, 52000000}, + {9532010, 52800000}, {5416000, 52800000}, + {5416000, 52000000}, {4793090, 52000000}, + {4793090, 52800000}, {-65918, 52800000}, + {-65918, 52000000}, {-296738, 52000000}, + {-296738, 52800000}, {-4368740, 52800000}, + {-4368740, 52000000}, {-4995880, 52000000}, + {-4995880, 52800000}, {-5997880, 52800000}, + {-5997880, 52000000}, {-6891430, 52000000}, + {-6891430, 52800000}, {-10271400, 52800000}, + {-10271400, 52000000}, {-11139700, 52000000}, + {-18000000, 40117700}, {-18000000, 30679900}, + {-18612200, 30000000}, {-19416400, 29106800}, + {-21925100, 24761700}, {-23475500, 19989900}, + {-23789800, 17000000}, {-23800000, 17000000}, + {-23668900, 15752500}, {-23281300, 14559600}, + {-22654100, 13473300}, {-21814800, 12541100}, + {-20800000, 11803800}, {-19654100, 11293700}, + {-18427200, 11032900}, {-17800000, 11032900}, + {-17800000, 11000000}, {-15419900, 11000000}, + }, + {}}, + }, + ExPolygons{ + // "x-carriage-back.stl": + MyPoly{{ + {-5981270, -38729200}, {-5354100, -37638700}, + {-4514780, -36703000}, {-3500000, -35962900}, + {-2354100, -35450800}, {-1969730, -35368800}, + {-1127170, -35189000}, {127170, -35189000}, + {969727, -35368800}, {1354100, -35450800}, + {2500000, -35962900}, {3514780, -36703000}, + {4354100, -37638700}, {4981270, -38729200}, + {5068930, -39000000}, {13757900, -39000000}, + {16000000, -36757900}, {16000000, -5000000}, + {25500000, -5000000}, {25500000, 13795200}, + {25057400, 14352100}, {24542500, 15342500}, + {24400000, 15200000}, {14600000, 25000000}, + {14500000, 25000000}, {14500000, 33050000}, + {13050000, 34500000}, {-500000, 34500000}, + {-500000, 28500000}, {-8000000, 28500000}, + {-8000000, 32500000}, {-5000000, 32500000}, + {-5000000, 34500000}, {-15550000, 34500000}, + {-17000000, 33050000}, {-17000000, 25000000}, + {-17100000, 25000000}, {-25572200, 16527800}, + {-25903900, 15532800}, {-26500000, 14386100}, + {-26500000, -5000000}, {-17000000, -5000000}, + {-17000000, -36757900}, {-14757900, -39000000}, + {-6068930, -39000000}, + }, + { + { + {-13103600, 29353300}, {-13309200, 29379200}, + {-13509900, 29430800}, {-13702500, 29507000}, + {-13884100, 29606900}, {-14051700, 29728700}, + {-14202800, 29870500}, {-14334900, 30030200}, + {-14445900, 30205100}, {-14534100, 30392600}, + {-14598200, 30589700}, {-14637000, 30793200}, + {-14650000, 31000000}, {-14637000, 31206800}, + {-14598200, 31410300}, {-14534100, 31607400}, + {-14445900, 31794900}, {-14334900, 31969800}, + {-14202800, 32129502}, {-14051700, 32271302}, + {-13884100, 32393100}, {-13702500, 32493000}, + {-13509900, 32569198}, {-13309200, 32620800}, + {-13103600, 32646702}, {-12896400, 32646702}, + {-12690800, 32620800}, {-12490100, 32569198}, + {-12297500, 32493000}, {-12115900, 32393100}, + {-11948200, 32271302}, {-11797200, 32129502}, + {-11665100, 31969800}, {-11554100, 31794900}, + {-11465900, 31607400}, {-11401800, 31410300}, + {-11363000, 31206800}, {-11350000, 31000000}, + {-11363000, 30793200}, {-11401800, 30589700}, + {-11465900, 30392600}, {-11554100, 30205100}, + {-11665100, 30030200}, {-11797200, 29870500}, + {-11948200, 29728700}, {-12115900, 29606900}, + {-12297500, 29507000}, {-12490100, 29430800}, + {-12690800, 29379200}, {-12896400, 29353300}, + }, + { + {10396400, 29353300}, {10190800, 29379200}, + {9990120, 29430800}, {9797460, 29507000}, + {9615890, 29606900}, {9448250, 29728700}, + {9297200, 29870500}, {9165120, 30030200}, + {9054090, 30205100}, {8965870, 30392600}, + {8901840, 30589700}, {8863010, 30793200}, + {8850000, 31000000}, {8863010, 31206800}, + {8901840, 31410300}, {8965870, 31607400}, + {9054090, 31794900}, {9165120, 31969800}, + {9297200, 32129502}, {9448250, 32271302}, + {9615890, 32393100}, {9797460, 32493000}, + {9990120, 32569198}, {10190800, 32620800}, + {10396400, 32646702}, {10603600, 32646702}, + {10809200, 32620800}, {11009900, 32569198}, + {11202500, 32493000}, {11384100, 32393100}, + {11551700, 32271302}, {11702800, 32129502}, + {11834900, 31969800}, {11945900, 31794900}, + {12034100, 31607400}, {12098200, 31410300}, + {12137000, 31206800}, {12150000, 31000000}, + {12137000, 30793200}, {12098200, 30589700}, + {12034100, 30392600}, {11945900, 30205100}, + {11834900, 30030200}, {11702800, 29870500}, + {11551700, 29728700}, {11384100, 29606900}, + {11202500, 29507000}, {11009900, 29430800}, + {10809200, 29379200}, {10603600, 29353300}, + }, + { + {-8000000, 17500000}, + {-8000000, 22500000}, + {-4500000, 22500000}, + {-4500000, 17500000}, + }, + { + {-1103600, 2353260}, {-1309180, 2379230}, + {-1509880, 2430760}, {-1702540, 2507040}, + {-1884110, 2606860}, {-2051750, 2728650}, + {-2202800, 2870500}, {-2334880, 3030150}, + {-2445910, 3205110}, {-2534130, 3392590}, + {-2598160, 3589660}, {-2636990, 3793200}, + {-2650000, 4000000}, {-2636990, 4206800}, + {-2598160, 4410340}, {-2534130, 4607400}, + {-2445910, 4794890}, {-2334880, 4969840}, + {-2202800, 5129500}, {-2051750, 5271350}, + {-1884110, 5393140}, {-1702540, 5492960}, + {-1509880, 5569240}, {-1309180, 5620770}, + {-1103600, 5646740}, {-896395, 5646740}, + {-690821, 5620770}, {-490122, 5569240}, + {-297463, 5492960}, {-115886, 5393140}, + {51749, 5271350}, {202798, 5129500}, + {334878, 4969840}, {445906, 4794890}, + {534131, 4607400}, {598162, 4410340}, + {636989, 4206800}, {650000, 4000000}, + {636989, 3793200}, {598162, 3589660}, + {534131, 3392590}, {445906, 3205110}, + {334878, 3030150}, {202798, 2870500}, + {51749, 2728650}, {-115886, 2606860}, + {-297463, 2507040}, {-490122, 2430760}, + {-690821, 2379230}, {-896395, 2353260}, + }, + { + {10876300, -3434440}, {10279800, -3240640}, + {9736640, -2927050}, {9270570, -2507390}, + {8901920, -2000000}, {8646830, -1427050}, + {8516430, -813585}, {8516430, -186414}, + {8646830, 427051}, {8901920, 999999}, + {9270570, 1507390}, {9736640, 1927050}, + {10279800, 2240640}, {10876300, 2434440}, + {11500000, 2500000}, {12123700, 2434440}, + {12720200, 2240640}, {13263400, 1927050}, + {13729400, 1507390}, {14098100, 1000000}, + {14353200, 427051}, {14483600, -186414}, + {14483600, -813585}, {14353200, -1427050}, + {14098100, -2000000}, {13729400, -2507390}, + {13263400, -2927050}, {12720200, -3240640}, + {12123700, -3434440}, {11500000, -3500000}, + }, + { + {-12123700, -3434440}, {-12720200, -3240640}, + {-13263400, -2927050}, {-13729400, -2507390}, + {-14098100, -2000000}, {-14353200, -1427050}, + {-14483600, -813585}, {-14483600, -186414}, + {-14353200, 427051}, {-14098100, 999999}, + {-13729400, 1507390}, {-13263400, 1927050}, + {-12720200, 2240640}, {-12123700, 2434440}, + {-11500000, 2500000}, {-10876300, 2434440}, + {-10279800, 2240640}, {-9736640, 1927050}, + {-9270570, 1507390}, {-8901920, 1000000}, + {-8646830, 427051}, {-8516430, -186414}, + {-8516430, -813585}, {-8646830, -1427050}, + {-8901920, -2000000}, {-9270570, -2507390}, + {-9736640, -2927050}, {-10279800, -3240640}, + {-10876300, -3434440}, {-11500000, -3500000}, + }, + { + {-1539560, -22890700}, {-2533680, -22567700}, + {-3438930, -22045100}, {-3590280, -21908800}, + {-4215720, -21345700}, {-4806270, -20532800}, + {-4830130, -20500000}, {-5012570, -20090200}, + {-5255280, -19545100}, {-5472610, -18522600}, + {-5472610, -18000000}, {-5500000, -18000000}, + {-5500000, -14000000}, {-5472610, -14000000}, + {-5472610, -13477400}, {-5255280, -12454900}, + {-5052740, -12000000}, {-4830130, -11500000}, + {-4215720, -10654300}, {-3438930, -9954910}, + {-3189080, -9810670}, {-2533680, -9432270}, + {-1539560, -9109260}, {-500000, -9000000}, + {539558, -9109260}, {1309400, -9359400}, + {1533680, -9432270}, {2438930, -9954910}, + {3215720, -10654300}, {3830130, -11500000}, + {4052740, -12000000}, {4255280, -12454900}, + {4472610, -13477400}, {4472610, -14000000}, + {4500000, -14000000}, {4500000, -18000000}, + {4472610, -18000000}, {4472610, -18522600}, + {4255280, -19545100}, {4012570, -20090200}, + {3830130, -20500000}, {3806270, -20532800}, + {3215720, -21345700}, {2590280, -21908800}, + {2438930, -22045100}, {1533680, -22567700}, + {539558, -22890700}, {-499999, -23000000}, + }, + { + {-832658, -28565000}, {-1150780, -28461700}, + {-1440460, -28294400}, {-1689030, -28070600}, + {-1885640, -27800000}, {-2021689, -27494400}, + {-2091229, -27167200}, {-2091229, -26832800}, + {-2021689, -26505600}, {-1885640, -26200000}, + {-1689030, -25929400}, {-1440460, -25705600}, + {-1150780, -25538300}, {-832658, -25435000}, + {-500000, -25400000}, {-167341, -25435000}, + {150778, -25538300}, {440456, -25705600}, + {689032, -25929400}, {885640, -26200000}, + {1021690, -26505600}, {1091230, -26832800}, + {1091230, -27167200}, {1021690, -27494400}, + {885640, -27800000}, {689032, -28070600}, + {440456, -28294400}, {150778, -28461700}, + {-167341, -28565000}, {-499999, -28600000}, + }, + { + {9396390, -37646700}, {9190820, -37620800}, + {8990120, -37569200}, {8797460, -37493000}, + {8615890, -37393100}, {8448250, -37271300}, + {8297200, -37129500}, {8165120, -36969800}, + {8054089, -36794900}, {7965870, -36607400}, + {7901840, -36410300}, {7863010, -36206800}, + {7850000, -36000000}, {7863010, -35793200}, + {7901840, -35589700}, {7965870, -35392600}, + {8054089, -35205100}, {8165120, -35030200}, + {8297200, -34870500}, {8448250, -34728700}, + {8615890, -34606900}, {8797460, -34507000}, + {8990120, -34430800}, {9190820, -34379200}, + {9396390, -34353300}, {9603600, -34353300}, + {9809180, -34379200}, {10009900, -34430800}, + {10202500, -34507000}, {10384100, -34606900}, + {10551700, -34728700}, {10702800, -34870500}, + {10834900, -35030200}, {10945900, -35205100}, + {11034100, -35392600}, {11098200, -35589700}, + {11137000, -35793200}, {11150000, -36000000}, + {11137000, -36206800}, {11098200, -36410300}, + {11034100, -36607400}, {10945900, -36794900}, + {10834900, -36969800}, {10702800, -37129500}, + {10551700, -37271300}, {10384100, -37393100}, + {10202500, -37493000}, {10009900, -37569200}, + {9809180, -37620800}, {9603600, -37646700}, + }, + { + {-10603600, -37646700}, {-10809200, -37620800}, + {-11009900, -37569200}, {-11202500, -37493000}, + {-11384100, -37393100}, {-11551700, -37271300}, + {-11702800, -37129500}, {-11834900, -36969800}, + {-11945900, -36794900}, {-12034100, -36607400}, + {-12098200, -36410300}, {-12137000, -36206800}, + {-12150000, -36000000}, {-12137000, -35793200}, + {-12098200, -35589700}, {-12034100, -35392600}, + {-11945900, -35205100}, {-11834900, -35030200}, + {-11702800, -34870500}, {-11551700, -34728700}, + {-11384100, -34606900}, {-11202500, -34507000}, + {-11009900, -34430800}, {-10809200, -34379200}, + {-10603600, -34353300}, {-10396400, -34353300}, + {-10190800, -34379200}, {-9990120, -34430800}, + {-9797460, -34507000}, {-9615890, -34606900}, + {-9448250, -34728700}, {-9297200, -34870500}, + {-9165120, -35030200}, {-9054090, -35205100}, + {-8965870, -35392600}, {-8901840, -35589700}, + {-8863010, -35793200}, {-8850000, -36000000}, + {-8863010, -36206800}, {-8901840, -36410300}, + {-8965870, -36607400}, {-9054090, -36794900}, + {-9165120, -36969800}, {-9297200, -37129500}, + {-9448250, -37271300}, {-9615890, -37393100}, + {-9797460, -37493000}, {-9990120, -37569200}, + {-10190800, -37620800}, {-10396400, -37646700}, + }, + }}, + }, + ExPolygons{ + // "extruder-idler-plug.stl": + MyPoly{{ + {-13000000, 42500000}, {-12967200, 42811900}, + {-12906100, 43000000}, {-12870300, 43110100}, + {-12713500, 43381700}, {-12503700, 43614700}, + {-12250000, 43799000}, {-11963500, 43926600}, + {-11656800, 43991800}, {-11343200, 43991800}, + {-11036500, 43926600}, {-10750000, 43799000}, + {-10496300, 43614700}, {-10286500, 43381700}, + {-10129700, 43110100}, {-10093900, 43000000}, + {-10032800, 42811900}, {-10000000, 42500000}, + {-10000000, 40200000}, {-7000000, 40200000}, + {-7000000, 46000000}, {-6400000, 46000000}, + {-6400000, 50500000}, {-11937800, 50500000}, + {-17000000, 47577400}, {-17000000, 40200000}, + {-13000000, 40200000}, + }, + {}}, + }, + ExPolygons{ + // "z-axis-bottom.stl": + MyPoly{{ + {45101600, -4898420}, + {50000000, 0}, + {50000000, 40786800}, + {43286800, 47500000}, + {3500000, 47500000}, + {0, 44000000}, + {0, -2000000}, + {3000000, -5000000}, + {45000000, -5000000}, + }, + { + { + {13696400, 33853300}, {13509500, 33876900}, + {13490800, 33879200}, {13308400, 33926100}, + {13290100, 33930800}, {13097500, 34007000}, + {12915900, 34106900}, {12748300, 34228700}, + {12597200, 34370500}, {12465100, 34530200}, + {12354100, 34705100}, {12265900, 34892600}, + {12201800, 35089700}, {12163000, 35293200}, + {12150000, 35500000}, {12163000, 35706800}, + {12201800, 35910300}, {12265900, 36107400}, + {12354100, 36294900}, {12465100, 36469800}, + {12597200, 36629500}, {12748300, 36771300}, + {12915900, 36893100}, {13097500, 36993000}, + {13290100, 37069200}, {13308400, 37073900}, + {13490800, 37120800}, {13509500, 37123100}, + {13696400, 37146700}, {13903600, 37146700}, + {14090500, 37123100}, {14109200, 37120800}, + {14291600, 37073900}, {14309900, 37069200}, + {14502500, 36993000}, {14684100, 36893100}, + {14791899, 36814806}, {14851700, 36771300}, + {14851800, 36771300}, {15002800, 36629500}, + {15134900, 36469800}, {15245900, 36294900}, + {15334100, 36107400}, {15398200, 35910300}, + {15437000, 35706800}, {15450000, 35500000}, + {15437000, 35293200}, {15398200, 35089700}, + {15334100, 34892600}, {15245900, 34705100}, + {15134900, 34530200}, {15002800, 34370500}, + {14851800, 34228700}, {14851700, 34228700}, + {14791899, 34185194}, {14684100, 34106900}, + {14502500, 34007000}, {14309900, 33930800}, + {14291600, 33926100}, {14109200, 33879200}, + {14090500, 33876900}, {13903600, 33853300}, + }, + { + {44696400, 33853300}, {44509500, 33876900}, + {44490800, 33879200}, {44308400, 33926100}, + {44290100, 33930800}, {44097500, 34007000}, + {43915900, 34106900}, {43748200, 34228700}, + {43597200, 34370500}, {43465100, 34530200}, + {43354100, 34705100}, {43265900, 34892600}, + {43201800, 35089700}, {43163000, 35293200}, + {43150000, 35500000}, {43163000, 35706800}, + {43201800, 35910300}, {43265900, 36107400}, + {43354100, 36294900}, {43465100, 36469800}, + {43597200, 36629500}, {43748200, 36771300}, + {43915900, 36893100}, {44097500, 36993000}, + {44290100, 37069200}, {44308400, 37073900}, + {44490800, 37120800}, {44509500, 37123100}, + {44696400, 37146700}, {44903600, 37146700}, + {45090500, 37123100}, {45109200, 37120800}, + {45291600, 37073900}, {45309900, 37069200}, + {45502500, 36993000}, {45684100, 36893100}, + {45851700, 36771300}, {46002800, 36629500}, + {46134900, 36469800}, {46245900, 36294900}, + {46334100, 36107400}, {46398200, 35910300}, + {46437000, 35706800}, {46450000, 35500000}, + {46437000, 35293200}, {46398200, 35089700}, + {46334100, 34892600}, {46245900, 34705100}, + {46134900, 34530200}, {46002800, 34370500}, + {45851700, 34228700}, {45684100, 34106900}, + {45502500, 34007000}, {45309900, 33930800}, + {45291600, 33926100}, {45109200, 33879200}, + {45090500, 33876900}, {44903600, 33853300}, + }, + { + {28300000, 8702230}, {28300000, 8861350}, + {28129300, 8861350}, {25839000, 9348170}, + {23700000, 10300500}, {21805700, 11676800}, + {20239000, 13416800}, {19068300, 15444600}, + {18344700, 17671400}, {18100000, 20000000}, + {18344700, 22328600}, {19068300, 24555500}, + {20239000, 26583200}, {21805700, 28323200}, + {23700000, 29699500}, {25839000, 30651800}, + {28129300, 31138600}, {30470700, 31138600}, + {32761002, 30651800}, {34900000, 29699500}, + {36794300, 28323200}, {38361000, 26583200}, + {39531700, 24555500}, {40255300, 22328600}, + {40500000, 20000000}, {40255300, 17671400}, + {39531700, 15444600}, {38361000, 13416800}, + {36794300, 11676800}, {34900000, 10300500}, + {32761002, 9348170}, {30470700, 8861350}, + {30300000, 8861350}, {30300000, 8702230}, + }, + { + {29045700, -1042009}, {28541100, -978263}, + {28048500, -851778}, {27575600, -664549}, + {27129900, -419528}, {26718400, -120578}, + {26347700, 227584}, {26023500, 619470}, + {25751000, 1048900}, {25534400, 1509100}, + {25377200, 1992810}, {25281900, 2492400}, + {25250000, 3000000}, {25281900, 3507600}, + {25377200, 4007190}, {25534400, 4490900}, + {25751000, 4951100}, {26023500, 5380530}, + {26347700, 5772420}, {26718400, 6120580}, + {27129900, 6419530}, {27575600, 6664550}, + {28048500, 6851780}, {28300000, 6916360}, + {28300000, 7213590}, {28487100, 7261610}, + {28717100, 7290670}, {29027600, 7329900}, + {29572400, 7329900}, {29882900, 7290670}, + {30112900, 7261610}, {30300000, 7213590}, + {30300000, 6916360}, {30551500, 6851780}, + {31024400, 6664550}, {31470100, 6419530}, + {31881600, 6120580}, {32252300, 5772420}, + {32576500, 5380530}, {32849000, 4951100}, + {33065602, 4490900}, {33222802, 4007190}, + {33318100, 3507600}, {33349998, 3000000}, + {33318100, 2492400}, {33222802, 1992810}, + {33065602, 1509100}, {32849000, 1048900}, + {32576500, 619470}, {32252300, 227584}, + {31881600, -120578}, {31470100, -419528}, + {31024400, -664549}, {30551500, -851778}, + {30058900, -978263}, {29554300, -1042009}, + }, + { + {44696400, 2853260}, {44509500, 2876870}, + {44490800, 2879230}, {44308400, 2926070}, + {44290100, 2930760}, {44097500, 3007040}, + {43915900, 3106860}, {43748200, 3228650}, + {43597200, 3370500}, {43465100, 3530160}, + {43354100, 3705110}, {43265900, 3892600}, + {43201800, 4089660}, {43163000, 4293200}, + {43150000, 4500000}, {43163000, 4706800}, + {43201800, 4910340}, {43265900, 5107410}, + {43354100, 5294890}, {43465100, 5469850}, + {43597200, 5629500}, {43748200, 5771350}, + {43915900, 5893140}, {44097500, 5992960}, + {44290100, 6069240}, {44308400, 6073930}, + {44490800, 6120770}, {44696400, 6146740}, + {44903600, 6146740}, {45109200, 6120770}, + {45291600, 6073930}, {45309900, 6069240}, + {45502500, 5992960}, {45684100, 5893140}, + {45851700, 5771350}, {46002800, 5629500}, + {46134900, 5469850}, {46245900, 5294890}, + {46334100, 5107410}, {46398200, 4910340}, + {46437000, 4706800}, {46450000, 4500000}, + {46437000, 4293200}, {46398200, 4089660}, + {46334100, 3892600}, {46245900, 3705110}, + {46134900, 3530160}, {46002800, 3370500}, + {45851700, 3228650}, {45684100, 3106860}, + {45502500, 3007040}, {45309900, 2930760}, + {45291600, 2926070}, {45109200, 2879230}, + {45090500, 2876870}, {44903600, 2853260}, + }, + { + {13696400, 2853260}, {13509500, 2876870}, + {13490800, 2879230}, {13308400, 2926070}, + {13290100, 2930760}, {13097500, 3007040}, + {12915900, 3106860}, {12748300, 3228650}, + {12597200, 3370500}, {12465100, 3530160}, + {12354100, 3705110}, {12265900, 3892600}, + {12201800, 4089660}, {12163000, 4293200}, + {12150000, 4500000}, {12163000, 4706800}, + {12201800, 4910340}, {12265900, 5107410}, + {12354100, 5294890}, {12465100, 5469850}, + {12597200, 5629500}, {12748300, 5771350}, + {12915900, 5893140}, {13097500, 5992960}, + {13290100, 6069240}, {13308400, 6073930}, + {13490800, 6120770}, {13696400, 6146740}, + {13903600, 6146740}, {14109200, 6120770}, + {14291600, 6073930}, {14309900, 6069240}, + {14502500, 5992960}, {14684100, 5893140}, + {14754724, 5841850}, {14851700, 5771350}, + {14851800, 5771350}, {15002800, 5629500}, + {15134900, 5469850}, {15245900, 5294890}, + {15334100, 5107410}, {15398200, 4910340}, + {15437000, 4706800}, {15450000, 4500000}, + {15437000, 4293200}, {15398200, 4089660}, + {15334100, 3892600}, {15245900, 3705110}, + {15134900, 3530160}, {15002800, 3370500}, + {14851800, 3228650}, {14851700, 3228650}, + {14754724, 3158150}, {14684100, 3106860}, + {14502500, 3007040}, {14309900, 2930760}, + {14291600, 2926070}, {14109200, 2879230}, + {14090500, 2876870}, {13903600, 2853260}, + }, + }}, + MyPoly{{ + {50000000, -53786800}, + {50000000, -13000000}, + {45101600, -8101579}, + {45000000, -8000000}, + {3000000, -8000000}, + {0, -11000000}, + {0, -57000000}, + {3500000, -60500000}, + {43286800, -60500000}, + }, + { + { + {29027600, -20329900}, {28717100, -20290700}, + {28487100, -20261600}, {28300000, -20213600}, + {28300000, -19916400}, {28048500, -19851800}, + {27575600, -19664500}, {27129900, -19419500}, + {26718400, -19120600}, {26347700, -18772400}, + {26023500, -18380500}, {25751000, -17951100}, + {25534400, -17490900}, {25377200, -17007200}, + {25281900, -16507601}, {25250000, -16000000}, + {25281900, -15492400}, {25377200, -14992800}, + {25534400, -14509100}, {25751000, -14048900}, + {26023500, -13619500}, {26347700, -13227600}, + {26718400, -12879400}, {27129900, -12580500}, + {27575600, -12335500}, {28048500, -12148200}, + {28541100, -12021700}, {29045700, -11958000}, + {29554300, -11958000}, {30058900, -12021700}, + {30551500, -12148200}, {31024400, -12335500}, + {31470100, -12580500}, {31881600, -12879400}, + {32252300, -13227600}, {32576500, -13619500}, + {32849000, -14048900}, {33065602, -14509100}, + {33222802, -14992800}, {33318100, -15492400}, + {33349998, -16000000}, {33318100, -16507601}, + {33222802, -17007200}, {33065602, -17490900}, + {32849000, -17951100}, {32576500, -18380500}, + {32252300, -18772400}, {31881600, -19120600}, + {31470100, -19419500}, {31024400, -19664500}, + {30551500, -19851800}, {30300000, -19916400}, + {30300000, -20213600}, {30112900, -20261600}, + {29882900, -20290700}, {29572400, -20329900}, + }, + { + {13696400, -19146700}, {13509500, -19123100}, + {13490800, -19120800}, {13308400, -19073900}, + {13290100, -19069200}, {13097500, -18993000}, + {12915900, -18893100}, {12748300, -18771300}, + {12597200, -18629500}, {12465100, -18469800}, + {12354100, -18294900}, {12265900, -18107400}, + {12201800, -17910300}, {12163000, -17706800}, + {12150000, -17500000}, {12163000, -17293200}, + {12201800, -17089700}, {12265900, -16892600}, + {12354100, -16705099}, {12465100, -16530199}, + {12597200, -16370501}, {12748300, -16228701}, + {12915900, -16106899}, {13097500, -16007000}, + {13290100, -15930800}, {13308400, -15926100}, + {13490800, -15879200}, {13509500, -15876900}, + {13696400, -15853300}, {13903600, -15853300}, + {14090500, -15876900}, {14109200, -15879200}, + {14291600, -15926100}, {14309900, -15930800}, + {14502500, -16007000}, {14684100, -16106899}, + {14791305, -16184763}, {14851700, -16228701}, + {14851800, -16228701}, {15002800, -16370501}, + {15134900, -16530199}, {15245900, -16705099}, + {15334100, -16892600}, {15398200, -17089700}, + {15437000, -17293200}, {15450000, -17500000}, + {15437000, -17706800}, {15398200, -17910300}, + {15334100, -18107400}, {15245900, -18294900}, + {15134900, -18469800}, {15002800, -18629500}, + {14851800, -18771300}, {14851700, -18771300}, + {14791899, -18814806}, {14684100, -18893100}, + {14502500, -18993000}, {14309900, -19069200}, + {14291600, -19073900}, {14109200, -19120800}, + {14090500, -19123100}, {13903600, -19146700}, + }, + { + {44696400, -19146700}, {44509500, -19123100}, + {44490800, -19120800}, {44308400, -19073900}, + {44290100, -19069200}, {44097500, -18993000}, + {43915900, -18893100}, {43748200, -18771300}, + {43597200, -18629500}, {43465100, -18469800}, + {43354100, -18294900}, {43265900, -18107400}, + {43201800, -17910300}, {43163000, -17706800}, + {43150000, -17500000}, {43163000, -17293200}, + {43201800, -17089700}, {43265900, -16892600}, + {43354100, -16705099}, {43465100, -16530199}, + {43597200, -16370501}, {43748200, -16228701}, + {43915900, -16106899}, {44097500, -16007000}, + {44290100, -15930800}, {44308400, -15926100}, + {44490800, -15879200}, {44509500, -15876900}, + {44696400, -15853300}, {44903600, -15853300}, + {45090500, -15876900}, {45109200, -15879200}, + {45291600, -15926100}, {45309900, -15930800}, + {45502500, -16007000}, {45684100, -16106899}, + {45851700, -16228701}, {46002800, -16370501}, + {46134900, -16530199}, {46245900, -16705099}, + {46334100, -16892600}, {46398200, -17089700}, + {46437000, -17293200}, {46450000, -17500000}, + {46437000, -17706800}, {46398200, -17910300}, + {46334100, -18107400}, {46245900, -18294900}, + {46134900, -18469800}, {46002800, -18629500}, + {45851700, -18771300}, {45684100, -18893100}, + {45502500, -18993000}, {45309900, -19069200}, + {45291600, -19073900}, {45109200, -19120800}, + {45090500, -19123100}, {44903600, -19146700}, + }, + { + {28129300, -44138600}, {25839000, -43651800}, + {23700000, -42699500}, {21805700, -41323200}, + {20239000, -39583200}, {19068300, -37555500}, + {18344700, -35328600}, {18100000, -33000000}, + {18344700, -30671400}, {19068300, -28444500}, + {20239000, -26416800}, {21805700, -24676800}, + {23700000, -23300500}, {25839000, -22348200}, + {28129300, -21861400}, {28300000, -21861400}, + {28300000, -21702200}, {30300000, -21702200}, + {30300000, -21861400}, {30470700, -21861400}, + {32761002, -22348200}, {34900000, -23300500}, + {36794300, -24676800}, {38361000, -26416800}, + {39531700, -28444500}, {40255300, -30671400}, + {40500000, -33000000}, {40255300, -35328600}, + {39531700, -37555500}, {38361000, -39583200}, + {36794300, -41323200}, {34900000, -42699500}, + {32761002, -43651800}, {30470700, -44138600}, + }, + { + {44696400, -50146700}, {44509500, -50123100}, + {44490800, -50120800}, {44308400, -50073900}, + {44290100, -50069200}, {44097500, -49993000}, + {43915900, -49893100}, {43748200, -49771300}, + {43597200, -49629500}, {43465100, -49469800}, + {43354100, -49294900}, {43265900, -49107400}, + {43201800, -48910300}, {43163000, -48706800}, + {43150000, -48500000}, {43163000, -48293200}, + {43201800, -48089700}, {43265900, -47892600}, + {43354100, -47705100}, {43465100, -47530200}, + {43597200, -47370500}, {43748200, -47228700}, + {43915900, -47106900}, {44097500, -47007000}, + {44290100, -46930800}, {44308400, -46926100}, + {44490800, -46879200}, {44509500, -46876900}, + {44696400, -46853300}, {44903600, -46853300}, + {45090500, -46876900}, {45109200, -46879200}, + {45291600, -46926100}, {45309900, -46930800}, + {45502500, -47007000}, {45684100, -47106900}, + {45851700, -47228700}, {46002800, -47370500}, + {46134900, -47530200}, {46245900, -47705100}, + {46334100, -47892600}, {46398200, -48089700}, + {46437000, -48293200}, {46450000, -48500000}, + {46437000, -48706800}, {46398200, -48910300}, + {46334100, -49107400}, {46245900, -49294900}, + {46134900, -49469800}, {46002800, -49629500}, + {45851700, -49771300}, {45684100, -49893100}, + {45502500, -49993000}, {45309900, -50069200}, + {45291600, -50073900}, {45109200, -50120800}, + {45090500, -50123100}, {44903600, -50146700}, + }, + { + {13696400, -50146700}, {13509500, -50123100}, + {13490800, -50120800}, {13308400, -50073900}, + {13290100, -50069200}, {13097500, -49993000}, + {12915900, -49893100}, {12748300, -49771300}, + {12597200, -49629500}, {12465100, -49469800}, + {12354100, -49294900}, {12265900, -49107400}, + {12201800, -48910300}, {12163000, -48706800}, + {12150000, -48500000}, {12163000, -48293200}, + {12201800, -48089700}, {12265900, -47892600}, + {12354100, -47705100}, {12465100, -47530200}, + {12597200, -47370500}, {12748300, -47228700}, + {12915900, -47106900}, {13097500, -47007000}, + {13290100, -46930800}, {13308400, -46926100}, + {13490800, -46879200}, {13509500, -46876900}, + {13696400, -46853300}, {13903600, -46853300}, + {14090500, -46876900}, {14109200, -46879200}, + {14291600, -46926100}, {14309900, -46930800}, + {14502500, -47007000}, {14684100, -47106900}, + {14791899, -47185194}, {14851700, -47228700}, + {14851800, -47228700}, {15002800, -47370500}, + {15134900, -47530200}, {15245900, -47705100}, + {15334100, -47892600}, {15398200, -48089700}, + {15437000, -48293200}, {15450000, -48500000}, + {15437000, -48706800}, {15398200, -48910300}, + {15334100, -49107400}, {15245900, -49294900}, + {15134900, -49469800}, {15002800, -49629500}, + {14851800, -49771300}, {14851700, -49771300}, + {14791899, -49814806}, {14684100, -49893100}, + {14502500, -49993000}, {14309900, -50069200}, + {14291600, -50073900}, {14109200, -50120800}, + {14090500, -50123100}, {13903600, -50146700}, + }, + }}, + }, + ExPolygons{ + // "extruder-cover.stl": + MyPoly{{ + {20500000, 366025}, {21732100, 2500000}, + {24500000, 2500000}, {24500000, -1500000}, + {31500000, -1500000}, {31500000, 1500000}, + {27250000, 5750000}, {-17000000, 5750000}, + {-17000000, -26799100}, {-35109600, -33390400}, + {-40700000, -33390400}, {-43650000, -38500000}, + {-40700000, -43609600}, {-34800000, -43609600}, + {-33470820, -41307370}, {-17000000, -35312500}, + {-17000000, -36500000}, {-15000000, -36500000}, + {-15000000, -44000000}, {20500000, -44000000}, + }, + { + { + {16832800, 1408760}, {16667299, 1434960}, + {16505600, 1478310}, {16349199, 1538330}, + {16200001, 1614360}, {16059500, 1705570}, + {15929400, 1810970}, {15811000, 1929390}, + {15705600, 2059540}, {15614400, 2200000}, + {15538300, 2349220}, {15478300, 2505570}, + {15435000, 2667340}, {15408800, 2832750}, + {15400000, 3000000}, {15408800, 3167240}, + {15435000, 3332660}, {15478300, 3494430}, + {15538300, 3650780}, {15614400, 3800000}, + {15705600, 3940460}, {15811000, 4070610}, + {15929400, 4189030}, {16059500, 4294430}, + {16200001, 4385640}, {16349199, 4461670}, + {16505600, 4521690}, {16667299, 4565040}, + {16832800, 4591230}, {17000000, 4600000}, + {17167200, 4591230}, {17332700, 4565040}, + {17494400, 4521690}, {17650800, 4461670}, + {17800000, 4385640}, {17940500, 4294430}, + {18070600, 4189030}, {18189000, 4070610}, + {18294400, 3940460}, {18385600, 3800000}, + {18461700, 3650780}, {18521700, 3494430}, + {18565000, 3332660}, {18591200, 3167240}, + {18600000, 3000000}, {18591200, 2832750}, + {18565000, 2667340}, {18521700, 2505570}, + {18461700, 2349220}, {18385600, 2200000}, + {18294400, 2059540}, {18189000, 1929390}, + {18070600, 1810970}, {17940500, 1705570}, + {17800000, 1614360}, {17650800, 1538330}, + {17494400, 1478310}, {17332700, 1434960}, + {17167200, 1408760}, {17000000, 1400000}, + }, + { + {-11603600, -2146740}, {-11809200, -2120770}, + {-12009900, -2069240}, {-12202500, -1992960}, + {-12384100, -1893140}, {-12551700, -1771350}, + {-12702800, -1629500}, {-12834900, -1469840}, + {-12945900, -1294890}, {-13034100, -1107400}, + {-13098200, -910337}, {-13137000, -706800}, + {-13150000, -499999}, {-13137000, -293200}, + {-13098200, -89661}, {-13034100, 107405}, + {-12945900, 294893}, {-12834900, 469845}, + {-12702800, 629502}, {-12551700, 771346}, + {-12384100, 893141}, {-12202500, 992964}, + {-12009900, 1069240}, {-11809200, 1120770}, + {-11603600, 1146740}, {-11396400, 1146740}, + {-11190800, 1120770}, {-10990100, 1069240}, + {-10797500, 992964}, {-10615900, 893141}, + {-10448200, 771346}, {-10297200, 629502}, + {-10165100, 469845}, {-10054100, 294893}, + {-9965870, 107405}, {-9901840, -89661}, + {-9863010, -293200}, {-9850000, -500000}, + {-9863010, -706800}, {-9901840, -910337}, + {-9965870, -1107400}, {-10054100, -1294890}, + {-10165100, -1469840}, {-10297200, -1629500}, + {-10448200, -1771350}, {-10615900, -1893140}, + {-10797500, -1992960}, {-10990100, -2069240}, + {-11190800, -2120770}, {-11396400, -2146740}, + }, + { + {-37917200, -40091200}, {-38244400, -40021700}, + {-38550000, -39885600}, {-38820600, -39689000}, + {-39044400, -39440500}, {-39211700, -39150800}, + {-39315000, -38832700}, {-39350000, -38500000}, + {-39315000, -38167300}, {-39211700, -37849200}, + {-39044400, -37559500}, {-38820600, -37311000}, + {-38550000, -37114400}, {-38244400, -36978300}, + {-37917200, -36908800}, {-37582800, -36908800}, + {-37255600, -36978300}, {-36950000, -37114400}, + {-36679400, -37311000}, {-36455600, -37559500}, + {-36288300, -37849200}, {-36185000, -38167300}, + {-36150000, -38500000}, {-36185000, -38832700}, + {-36288300, -39150800}, {-36455600, -39440500}, + {-36679400, -39689000}, {-36950000, -39885600}, + {-37255600, -40021700}, {-37582800, -40091200}, + }, + { + {14353700, -41892300}, {14067400, -41831500}, + {13800000, -41712400}, {13563200, -41540400}, + {13367400, -41322900}, {13221000, -41069400}, + {13130600, -40791100}, {13100000, -40500000}, + {13130600, -40208900}, {13221000, -39930600}, + {13367400, -39677100}, {13563200, -39459600}, + {13800000, -39287600}, {14067400, -39168500}, + {14353700, -39107700}, {14646300, -39107700}, + {14932600, -39168500}, {15200000, -39287600}, + {15436800, -39459600}, {15632600, -39677100}, + {15779000, -39930600}, {15869400, -40208900}, + {15900000, -40500000}, {15869400, -40791100}, + {15779000, -41069400}, {15632600, -41322900}, + {15436800, -41540400}, {15200000, -41712400}, + {14932600, -41831500}, {14646300, -41892300}, + }, + }}, + }, + ExPolygons{ + // "Einsy-base.stl": + MyPoly{{ + {85000000, 2000000}, + {87000000, 5464100}, + {91000000, 5464100}, + {93000000, 2000000}, + {91845296, 0}, + {118500000, 0}, + {118500000, 79000000}, + {105500000, 92000000}, + {0, 92000000}, + {0, 41000000}, + {-5000000, 41000000}, + {-9000000, 38000000}, + {-9000000, 18000000}, + {-5000000, 15000000}, + {0, 15000000}, + {0, 0}, + {86154704, 0}, + }, + { + { + {58301400, 86110400}, {57912900, 86193000}, + {57550000, 86354600}, {57228700, 86588000}, + {56962900, 86883200}, {56764300, 87227200}, + {56641500, 87605000}, {56600000, 88000000}, + {56641500, 88395000}, {56764300, 88772800}, + {56962900, 89116800}, {57228700, 89412000}, + {57550000, 89645400}, {57912900, 89807000}, + {58301400, 89889600}, {58698600, 89889600}, + {59087100, 89807000}, {59450000, 89645400}, + {59771300, 89412000}, {60037100, 89116800}, + {60235700, 88772800}, {60358500, 88395000}, + {60400000, 88000000}, {60358500, 87605000}, + {60235700, 87227200}, {60037100, 86883200}, + {59771300, 86588000}, {59450000, 86354600}, + {59087100, 86193000}, {58698600, 86110400}, + }, + { + {78916400, 80204400}, {78752800, 80239200}, + {78600000, 80307200}, {78464696, 80405504}, + {78352800, 80529800}, {78269200, 80674600}, + {78217496, 80833704}, {78200000, 81000000}, + {78217496, 81166296}, {78269200, 81325400}, + {78352800, 81470200}, {78464696, 81594496}, + {78600000, 81692800}, {78752800, 81760800}, + {78916400, 81795600}, {79083600, 81795600}, + {79247200, 81760800}, {79400000, 81692800}, + {79535304, 81594496}, {79647200, 81470200}, + {79730800, 81325400}, {79782504, 81166296}, + {79800000, 81000000}, {79782504, 80833704}, + {79730800, 80674600}, {79647200, 80529800}, + {79535304, 80405504}, {79400000, 80307200}, + {79247200, 80239200}, {79083600, 80204400}, + }, + { + {20916400, 80204400}, {20752800, 80239200}, + {20600000, 80307200}, {20464700, 80405504}, + {20352800, 80529800}, {20269200, 80674600}, + {20217500, 80833704}, {20200000, 81000000}, + {20217500, 81166296}, {20269200, 81325400}, + {20352800, 81470200}, {20464700, 81594496}, + {20600000, 81692800}, {20752800, 81760800}, + {20916400, 81795600}, {21083600, 81795600}, + {21247200, 81760800}, {21400000, 81692800}, + {21535300, 81594496}, {21647200, 81470200}, + {21730800, 81325400}, {21782500, 81166296}, + {21800000, 81000000}, {21782500, 80833704}, + {21730800, 80674600}, {21647200, 80529800}, + {21535300, 80405504}, {21400000, 80307200}, + {21247200, 80239200}, {21083600, 80204400}, + }, + { + {81000000, 60500000}, + {81000000, 78500000}, + {84650000, 78500000}, + {84650000, 60500000}, + }, + { + {70000000, 60500000}, + {70000000, 78500000}, + {73650000, 78500000}, + {73650000, 60500000}, + }, + { + {75500000, 60500000}, + {75500000, 78500000}, + {79150000, 78500000}, + {79150000, 60500000}, + }, + { + {26000000, 60500000}, + {26000000, 78500000}, + {29650000, 78500000}, + {29650000, 60500000}, + }, + { + {86500000, 60500000}, + {86500000, 78500000}, + {90150000, 78500000}, + {90150000, 60500000}, + }, + { + {48000000, 60500000}, + {48000000, 78500000}, + {51650000, 78500000}, + {51650000, 60500000}, + }, + { + {64500000, 60500000}, + {64500000, 78500000}, + {68150000, 78500000}, + {68150000, 60500000}, + }, + { + {59000000, 60500000}, + {59000000, 78500000}, + {62650000, 78500000}, + {62650000, 60500000}, + }, + { + {20500000, 60500000}, + {20500000, 78500000}, + {24150000, 78500000}, + {24150000, 60500000}, + }, + { + {92000000, 60500000}, + {92000000, 78500000}, + {95650000, 78500000}, + {95650000, 60500000}, + }, + { + {42500000, 60500000}, + {42500000, 78500000}, + {46150000, 78500000}, + {46150000, 60500000}, + }, + { + {31500000, 60500000}, + {31500000, 78500000}, + {35150000, 78500000}, + {35150000, 60500000}, + }, + { + {37000000, 60500000}, + {37000000, 78500000}, + {40650000, 78500000}, + {40650000, 60500000}, + }, + { + {53500000, 60500000}, + {53500000, 78500000}, + {57150000, 78500000}, + {57150000, 60500000}, + }, + { + {7301400, 73110400}, {6912870, 73193000}, + {6550000, 73354600}, {6228650, 73588000}, + {5962870, 73883200}, {5900000, 73992104}, + {5764260, 74227200}, {5641520, 74605000}, + {5600000, 75000000}, {5641520, 75395000}, + {5764260, 75772800}, {5900000, 76007896}, + {5962870, 76116800}, {6228650, 76412000}, + {6550000, 76645400}, {6912870, 76807000}, + {7301400, 76889600}, {7698600, 76889600}, + {8087129, 76807000}, {8450000, 76645400}, + {8771350, 76412000}, {9037130, 76116800}, + {9100000, 76007896}, {9235740, 75772800}, + {9358480, 75395000}, {9400000, 75000000}, + {9358480, 74605000}, {9235740, 74227200}, + {9100000, 73992104}, {9037130, 73883200}, + {8771350, 73588000}, {8450000, 73354600}, + {8087129, 73193000}, {7698600, 73110400}, + }, + { + {102301000, 73110400}, {101913000, 73193000}, + {101550000, 73354600}, {101229000, 73588000}, + {100963000, 73883200}, {100764000, 74227200}, + {100642000, 74605000}, {100600000, 75000000}, + {100642000, 75395000}, {100764000, 75772800}, + {100963000, 76116800}, {101229000, 76412000}, + {101550000, 76645400}, {101913000, 76807000}, + {102301000, 76889600}, {102699000, 76889600}, + {103087000, 76807000}, {103450000, 76645400}, + {103771000, 76412000}, {104037000, 76116800}, + {104236000, 75772800}, {104358000, 75395000}, + {104400000, 75000000}, {104358000, 74605000}, + {104236000, 74227200}, {104037000, 73883200}, + {103771000, 73588000}, {103450000, 73354600}, + {103087000, 73193000}, {102699000, 73110400}, + }, + { + {37000000, 35500000}, + {37000000, 53500000}, + {40650000, 53500000}, + {40650000, 35500000}, + }, + { + {53500000, 35500000}, + {53500000, 53500000}, + {57150000, 53500000}, + {57150000, 35500000}, + }, + { + {75500000, 35500000}, + {75500000, 53500000}, + {79150000, 53500000}, + {79150000, 35500000}, + }, + { + {31500000, 35500000}, + {31500000, 53500000}, + {35150000, 53500000}, + {35150000, 35500000}, + }, + { + {92000000, 35500000}, + {92000000, 53500000}, + {95650000, 53500000}, + {95650000, 35500000}, + }, + { + {81000000, 35500000}, + {81000000, 53500000}, + {84650000, 53500000}, + {84650000, 35500000}, + }, + { + {86500000, 35500000}, + {86500000, 53500000}, + {90150000, 53500000}, + {90150000, 35500000}, + }, + { + {48000000, 35500000}, + {48000000, 53500000}, + {51650000, 53500000}, + {51650000, 35500000}, + }, + { + {42500000, 35500000}, + {42500000, 53500000}, + {46150000, 53500000}, + {46150000, 35500000}, + }, + { + {70000000, 35500000}, + {70000000, 53500000}, + {73650000, 53500000}, + {73650000, 35500000}, + }, + { + {20500000, 35500000}, + {20500000, 53500000}, + {24150000, 53500000}, + {24150000, 35500000}, + }, + { + {59000000, 35500000}, + {59000000, 53500000}, + {62650000, 53500000}, + {62650000, 35500000}, + }, + { + {64500000, 35500000}, + {64500000, 53500000}, + {68150000, 53500000}, + {68150000, 35500000}, + }, + { + {26000000, 35500000}, + {26000000, 53500000}, + {29650000, 53500000}, + {29650000, 35500000}, + }, + { + {16290899, 8010959}, {15882000, 8097890}, + {15500000, 8267950}, {15161700, 8513710}, + {14882000, 8824430}, {14672900, 9186530}, + {14543700, 9584180}, {14500000, 10000000}, + {14500000, 34000000}, {14543700, 34415800}, + {14672900, 34813500}, {14882000, 35175600}, + {15161700, 35486300}, {15500000, 35732000}, + {15882000, 35902100}, {16290899, 35989000}, + {16709101, 35989000}, {17118000, 35902100}, + {17500000, 35732000}, {17838300, 35486300}, + {18118000, 35175600}, {18327100, 34813500}, + {18456300, 34415800}, {18500000, 34000000}, + {18500000, 10000000}, {18456300, 9584180}, + {18327100, 9186530}, {18118000, 8824430}, + {17838300, 8513710}, {17500000, 8267950}, + {17118000, 8097890}, {16709101, 8010959}, + }, + { + {59000000, 10500000}, + {59000000, 28500000}, + {62650000, 28500000}, + {62650000, 10500000}, + }, + { + {81000000, 10500000}, + {81000000, 28500000}, + {84650000, 28500000}, + {84650000, 10500000}, + }, + { + {75500000, 10500000}, + {75500000, 28500000}, + {79150000, 28500000}, + {79150000, 10500000}, + }, + { + {70000000, 10500000}, + {70000000, 28500000}, + {73650000, 28500000}, + {73650000, 10500000}, + }, + { + {20500000, 10500000}, + {20500000, 28500000}, + {24150000, 28500000}, + {24150000, 10500000}, + }, + { + {92000000, 10500000}, + {92000000, 28500000}, + {95650000, 28500000}, + {95650000, 10500000}, + }, + { + {26000000, 10500000}, + {26000000, 28500000}, + {29650000, 28500000}, + {29650000, 10500000}, + }, + { + {53500000, 10500000}, + {53500000, 28500000}, + {57150000, 28500000}, + {57150000, 10500000}, + }, + { + {48000000, 10500000}, + {48000000, 28500000}, + {51650000, 28500000}, + {51650000, 10500000}, + }, + { + {42500000, 10500000}, + {42500000, 28500000}, + {46150000, 28500000}, + {46150000, 10500000}, + }, + { + {37000000, 10500000}, + {37000000, 28500000}, + {40650000, 28500000}, + {40650000, 10500000}, + }, + { + {31500000, 10500000}, + {31500000, 28500000}, + {35150000, 28500000}, + {35150000, 10500000}, + }, + { + {64500000, 10500000}, + {64500000, 28500000}, + {68150000, 28500000}, + {68150000, 10500000}, + }, + { + {86500000, 10500000}, + {86500000, 28500000}, + {90150000, 28500000}, + {90150000, 10500000}, + }, + { + {102301000, 12110400}, {101913000, 12193000}, + {101550000, 12354600}, {101229000, 12588000}, + {100963000, 12883200}, {100764000, 13227200}, + {100642000, 13605000}, {100600000, 14000000}, + {100642000, 14395000}, {100764000, 14772800}, + {100963000, 15116800}, {101229000, 15412000}, + {101550000, 15645400}, {101913000, 15807000}, + {102301000, 15889600}, {102699000, 15889600}, + {103087000, 15807000}, {103450000, 15645400}, + {103771000, 15412000}, {104037000, 15116800}, + {104236000, 14772800}, {104358000, 14395000}, + {104400000, 14000000}, {104358000, 13605000}, + {104236000, 13227200}, {104037000, 12883200}, + {103771000, 12588000}, {103450000, 12354600}, + {103087000, 12193000}, {102699000, 12110400}, + }, + { + {7301400, 12110400}, {6912870, 12193000}, + {6550000, 12354600}, {6228650, 12588000}, + {5962870, 12883200}, {5900000, 12992100}, + {5764260, 13227200}, {5641520, 13605000}, + {5600000, 14000000}, {5641520, 14395000}, + {5764260, 14772800}, {5900000, 15007900}, + {5962870, 15116800}, {6228650, 15412000}, + {6550000, 15645400}, {6912870, 15807000}, + {7301400, 15889600}, {7698600, 15889600}, + {8087129, 15807000}, {8450000, 15645400}, + {8771350, 15412000}, {9037130, 15116800}, + {9100000, 15007900}, {9235740, 14772800}, + {9358480, 14395000}, {9400000, 14000000}, + {9358480, 13605000}, {9235740, 13227200}, + {9100000, 12992100}, {9037130, 12883200}, + {8771350, 12588000}, {8450000, 12354600}, + {8087129, 12193000}, {7698600, 12110400}, + }, + }}, + }, + ExPolygons{ + // "lcd-supports.stl": + MyPoly{{ + {4192390, 4192390}, {4192390, 5707110}, + {2474870, 7424620}, {1626350, 6576090}, + {3040560, 5161880}, {1767770, 3889090}, + {-2474870, 8131730}, {-5303300, 5303300}, + {-36769600, 36769600}, {-33941100, 39598000}, + {-38183750, 43840650}, {-36911000, 45113400}, + {-35496800, 43699200}, {-34648200, 44547700}, + {-36769600, 46669000}, {-38183800, 46669000}, + {-46852800, 38000000}, {-61500000, 38000000}, + {-61500000, 12000000}, {-50000000, 12000000}, + {-50000000, 11984300}, {-37204500, -811183}, + {-811183, -811183}, + }, + { + { + {-36000000, 8000000}, + {-51500000, 23500000}, + {-37357900, 23500000}, + {-21857900, 8000000}, + }, + }}, + MyPoly{{ + {-13147200, -40000000}, {1500000, -40000000}, + {1500000, -14000000}, {-10000000, -14000000}, + {-10000000, -13984300}, {-22795500, -1188820}, + {-59188800, -1188820}, {-64192400, -6192390}, + {-64192400, -7707110}, {-62474900, -9424620}, + {-61626300, -8576090}, {-63040571, -7161851}, + {-61767800, -5889090}, {-57525100, -10131700}, + {-54696700, -7303300}, {-23230400, -38769600}, + {-26058900, -41598000}, {-21816250, -45840650}, + {-23089000, -47113400}, {-24503200, -45699200}, + {-25351800, -46547700}, {-23230400, -48669000}, + {-21816200, -48669000}, + }, + { + { + {-22642100, -25500000}, + {-38142100, -10000000}, + {-24000000, -10000000}, + {-9357800, -24642200}, + {-9288210, -24711800}, + {-8500000, -25500000}, + }, + }}, + }, +}; diff --git a/src/libseqarrange/test/qidiparts.hpp b/src/libseqarrange/test/qidiparts.hpp new file mode 100644 index 0000000..4340e4e --- /dev/null +++ b/src/libseqarrange/test/qidiparts.hpp @@ -0,0 +1,14 @@ +#ifndef QIDIPARTS_H +#define QIDIPARTS_H + +#include +#include "libslic3r/ExPolygon.hpp" + +using TestData = std::vector; +using TestDataEx = std::vector; + +extern const TestData QIDI_PART_POLYGONS; +extern const TestData QIDI_STEGOSAUR_POLYGONS; +extern const TestDataEx QIDI_PART_POLYGONS_EX; + +#endif // QIDIPARTS_H diff --git a/src/libseqarrange/test/seq_test_interface.cpp b/src/libseqarrange/test/seq_test_interface.cpp new file mode 100644 index 0000000..a574cd6 --- /dev/null +++ b/src/libseqarrange/test/seq_test_interface.cpp @@ -0,0 +1,1241 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include "libslic3r/Polygon.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Geometry/ConvexHull.hpp" +#include "libslic3r/SVG.hpp" + +#include + +#include "libseqarrange/seq_interface.hpp" +#include "seq_utilities.hpp" +#include "seq_preprocess.hpp" + +#include "seq_test_interface.hpp" + + +/*----------------------------------------------------------------*/ + + +using namespace Sequential; + + +/*----------------------------------------------------------------*/ + +const coord_t SEQ_QIDI_MK3S_X_SIZE = 250000000; +const coord_t SEQ_QIDI_MK3S_Y_SIZE = 210000000; + + +/*----------------------------------------------------------------*/ + +const std::string arrange_data_export_text = "OBJECT_ID131\n\ +TOTAL_HEIGHT62265434\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000000 16000000\n\ +POINT-21000000 12000000\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000000 16000000\n\ +POINT-21000000 12000000\n\ +POLYGON_AT_HEIGHT18000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +OBJECT_ID66\n\ +TOTAL_HEIGHT10000000\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000000 16000000\n\ +POINT-21000000 12000000\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +POLYGON_AT_HEIGHT18000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +OBJECT_ID44\n\ +TOTAL_HEIGHT10000000\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 11999992\n\ +POINT17000000 15999992\n\ +POINT-17000000 15999992\n\ +POINT-21000000 11999992\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 3999992\n\ +POINT-21000000 3999992\n\ +POLYGON_AT_HEIGHT18000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +OBJECT_ID88\n\ +TOTAL_HEIGHT10000000\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000000 16000000\n\ +POINT-21000000 12000000\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +POLYGON_AT_HEIGHT18000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +OBJECT_ID77\n\ +TOTAL_HEIGHT10000000\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 12000008\n\ +POINT17000000 16000008\n\ +POINT-17000000 16000008\n\ +POINT-21000000 12000008\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +POLYGON_AT_HEIGHT18000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +OBJECT_ID120\n\ +TOTAL_HEIGHT62265434\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-21000000 -15999992\n\ +POINT21000000 -15999992\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000000 16000000\n\ +POINT-21000000 12000000\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-21000000 -15999992\n\ +POINT21000000 -15999992\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000000 16000000\n\ +POINT-21000000 12000000\n\ +POLYGON_AT_HEIGHT18000000\n\ +POINT-21000000 -15999992\n\ +POINT21000000 -15999992\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +POINT-21000000 -15999992\n\ +POINT21000000 -15999992\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +OBJECT_ID99\n\ +TOTAL_HEIGHT62265434\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000000 16000000\n\ +POINT-21000000 12000000\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000000 16000000\n\ +POINT-21000000 12000000\n\ +POLYGON_AT_HEIGHT18000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +OBJECT_ID151\n\ +TOTAL_HEIGHT62265434\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000000 16000000\n\ +POINT-21000000 12000000\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000000 16000000\n\ +POINT-21000000 12000000\n\ +POLYGON_AT_HEIGHT18000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +OBJECT_ID162\n\ +TOTAL_HEIGHT62265434\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-30189590 -16000000\n\ +POINT30189576 -16000000\n\ +POINT30189576 12000000\n\ +POINT24439178 16000000\n\ +POINT-24439194 16000000\n\ +POINT-30189590 12000000\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-30189590 -16000000\n\ +POINT30189576 -16000000\n\ +POINT30189576 12000000\n\ +POINT26286238 14715178\n\ +POINT24439178 16000000\n\ +POINT-24439194 16000000\n\ +POINT-28342532 13284822\n\ +POINT-30189590 12000000\n\ +POLYGON_AT_HEIGHT18000000\n\ +POINT-30189590 -16000000\n\ +POINT30189576 -16000000\n\ +POINT30189576 4000000\n\ +POINT-30189590 4000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +POINT-30189590 -16000000\n\ +POINT30189576 -16000000\n\ +POINT30189576 4000000\n\ +POINT-30189590 4000000\n\ +OBJECT_ID192\n\ +TOTAL_HEIGHT62265434\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000000 16000000\n\ +POINT-21000000 12000000\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000000 16000000\n\ +POINT-21000000 12000000\n\ +POLYGON_AT_HEIGHT18000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +POINT-21000000 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +OBJECT_ID203\n\ +TOTAL_HEIGHT62265434\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-21000000 -15999999\n\ +POINT21000000 -15999999\n\ +POINT21000000 12000002\n\ +POINT17000000 16000002\n\ +POINT-17000000 16000002\n\ +POINT-21000000 12000002\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-21000000 -15999999\n\ +POINT21000000 -15999999\n\ +POINT21000000 12000002\n\ +POINT17000000 16000002\n\ +POINT-17000000 16000002\n\ +POINT-21000000 12000002\n\ +POLYGON_AT_HEIGHT18000000\n\ +POINT-21000000 -15999999\n\ +POINT21000000 -15999999\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +POINT-21000000 -15999999\n\ +POINT21000000 -15999999\n\ +POINT21000000 4000000\n\ +POINT-21000000 4000000\n\ +OBJECT_ID223\n\ +TOTAL_HEIGHT62265434\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-20999998 -16000000\n\ +POINT21000004 -16000000\n\ +POINT21000004 12000000\n\ +POINT17000004 16000000\n\ +POINT-16999998 16000000\n\ +POINT-20999998 12000000\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-20999998 -16000000\n\ +POINT21000004 -16000000\n\ +POINT21000004 12000000\n\ +POINT17000004 16000000\n\ +POINT-16999998 16000000\n\ +POINT-20999998 12000000\n\ +POLYGON_AT_HEIGHT18000000\n\ +POINT-20999998 -16000000\n\ +POINT21000004 -16000000\n\ +POINT21000004 4000000\n\ +POINT-20999998 4000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +POINT-20999998 -16000000\n\ +POINT21000004 -16000000\n\ +POINT21000004 4000000\n\ +POINT-20999998 4000000\n\ +OBJECT_ID234\n\ +TOTAL_HEIGHT62265434\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-21000002 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000002 16000000\n\ +POINT-21000002 12000000\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-21000002 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 12000000\n\ +POINT17000000 16000000\n\ +POINT-17000002 16000000\n\ +POINT-21000002 12000000\n\ +POLYGON_AT_HEIGHT18000000\n\ +POINT-21000002 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 4000000\n\ +POINT-21000002 4000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +POINT-21000002 -16000000\n\ +POINT21000000 -16000000\n\ +POINT21000000 4000000\n\ +POINT-21000002 4000000\n\ +"; + +const std::string printer_geometry_mk4_compatibility_text = "X_SIZE250000000\n\ +Y_SIZE210000000\n\ +CONVEX_HEIGHT0\n\ +CONVEX_HEIGHT2000000\n\ +BOX_HEIGHT18000000\n\ +BOX_HEIGHT26000000\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-500000 -500000\n\ +POINT500000 -500000\n\ +POINT500000 500000\n\ +POINT-500000 500000\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-1000000 -21000000 \n\ +POINT37000000 -21000000\n\ +POINT37000000 44000000\n\ +POINT-1000000 44000000\n\ +POLYGON_AT_HEIGHT2000000\n\ +POINT-40000000 -45000000\n\ +POINT38000000 -45000000\n\ +POINT38000000 20000000\n\ +POINT-40000000 20000000\n\ +POLYGON_AT_HEIGHT18000000\n\ +POINT-350000000 -23000000\n\ +POINT350000000 -23000000\n\ +POINT350000000 -35000000\n\ +POINT-350000000 -35000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +POINT-12000000 -350000000\n\ +POINT9000000 -350000000\n\ +POINT9000000 -39000000\n\ +POINT-12000000 -39000000\n\ +POLYGON_AT_HEIGHT26000000\n\ +POINT-12000000 -350000000\n\ +POINT250000000 -350000000\n\ +POINT250000000 -82000000\n\ +POINT-12000000 -82000000\n\ +"; + + +const std::string printer_geometry_mk4_text = "X_SIZE250000000\n\ +Y_SIZE210000000\n\ +CONVEX_HEIGHT0\n\ +CONVEX_HEIGHT3000000\n\ +BOX_HEIGHT11000000\n\ +BOX_HEIGHT13000000\n\ +POLYGON_AT_HEIGHT0\n\ +POINT-500000 -500000\n\ +POINT500000 -500000\n\ +POINT500000 500000\n\ +POINT-500000 500000\n\ +POLYGON_AT_HEIGHT3000000\n\ +POINT-1000000 -21000000\n\ +POINT37000000 -21000000\n\ +POINT37000000 44000000\n\ +POINT-1000000 44000000\n\ +POLYGON_AT_HEIGHT3000000\n\ +POINT-40000000 -45000000\n\ +POINT38000000 -45000000\n\ +POINT38000000 20000000\n\ +POINT-40000000 20000000\n\ +POLYGON_AT_HEIGHT11000000\n\ +POINT-350000000 -23000000\n\ +POINT350000000 -23000000\n\ +POINT350000000 -35000000\n\ +POINT-350000000 -35000000\n\ +POLYGON_AT_HEIGHT13000000\n\ +POINT-12000000 -350000000\n\ +POINT9000000 -350000000\n\ +POINT9000000 -39000000\n\ +POINT-12000000 -39000000\n\ +POLYGON_AT_HEIGHT13000000\n\ +POINT-12000000 -350000000\n\ +POINT250000000 -350000000\n\ +POINT250000000 -82000000\n\ +POINT-12000000 -82000000\n\ +"; + + +/* +static bool find_and_remove(std::string& src, const std::string& key) +{ + size_t pos = src.find(key); + if (pos != std::string::npos) { + src.erase(pos, key.length()); + return true; + } + return false; +} +*/ + +/* +std::vector load_exported_data(const std::string& filename) +{ + std::vector objects_to_print; + + std::ifstream in(filename); + if (!in) + throw std::runtime_error("NO EXPORTED FILE WAS FOUND"); + std::string line; + + while (in) { + std::getline(in, line); + if (find_and_remove(line, "OBJECT_ID")) { + objects_to_print.push_back(ObjectToPrint()); + objects_to_print.back().id = std::stoi(line); + } + if (find_and_remove(line, "TOTAL_HEIGHT")) + objects_to_print.back().total_height = std::stoi(line); + if (find_and_remove(line, "POLYGON_AT_HEIGHT")) + objects_to_print.back().pgns_at_height.emplace_back(std::make_pair(std::stoi(line), Polygon())); + if (find_and_remove(line, "POINT")) { + std::stringstream ss(line); + std::string val; + ss >> val; + Point pt(std::stoi(val), 0); + ss >> val; + pt.y() = std::stoi(val); + objects_to_print.back().pgns_at_height.back().second.append(pt); + } + } + return objects_to_print; +} +*/ + + +void save_import_data(const std::string &filename, + const std::map &scheduled_polygons, + const map &original_index_map, + const vector &poly_positions_X, + const vector &poly_positions_Y) +{ + std::ofstream out(filename); + if (!out) + throw std::runtime_error("CANNOT CREATE IMPORT FILE"); + + for (const auto& scheduled_polygon: scheduled_polygons) + { + coord_t X, Y; + + scaleUp_PositionForSlicer(poly_positions_X[scheduled_polygon.second], + poly_positions_Y[scheduled_polygon.second], + X, + Y); + const auto& original_index = original_index_map.find(scheduled_polygon.second); + +// out << original_index_map[scheduled_polygon.second] << " " << X << " " << Y << endl; + out << original_index->second << " " << X << " " << Y << endl; + } +} + + +/*----------------------------------------------------------------*/ + +TEST_CASE("Interface test 1", "[Sequential Arrangement Interface]") +//void interface_test_1(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing interface 1 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.decimation_precision = SEQ_DECIMATION_PRECISION_HIGH; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE / SEQ_SLICER_SCALE_FACTOR, SEQ_QIDI_MK3S_Y_SIZE / SEQ_SLICER_SCALE_FACTOR}); + + #ifdef DEBUG + { + printf("Loading objects ...\n"); + } + #endif + + std::vector objects_to_print = load_exported_data_from_text(arrange_data_export_text); + REQUIRE(objects_to_print.size() > 0); + + #ifdef DEBUG + { + printf("Loading objects ... finished\n"); + } + #endif + + std::vector scheduled_plates; + #ifdef DEBUG + { + printf("Scheduling objects for sequential print ...\n"); + } + #endif + + int result = schedule_ObjectsForSequentialPrint(solver_configuration, + objects_to_print, + scheduled_plates); + + REQUIRE(result == 0); + if (result == 0) + { + #ifdef DEBUG + { + printf("Object scheduling for sequential print SUCCESSFUL !\n"); + } + #endif + + #ifdef DEBUG + { + printf("Number of plates: %ld\n", scheduled_plates.size()); + } + #endif + REQUIRE(scheduled_plates.size() > 0); + + for (unsigned int plate = 0; plate < scheduled_plates.size(); ++plate) + { + #ifdef DEBUG + { + printf(" Number of objects on plate: %ld\n", scheduled_plates[plate].scheduled_objects.size()); + } + #endif + REQUIRE(scheduled_plates[plate].scheduled_objects.size() > 0); + + for (const auto& scheduled_object: scheduled_plates[plate].scheduled_objects) + { + #ifdef DEBUG + { + cout << " ID: " << scheduled_object.id << " X: " << scheduled_object.x << " Y: " << scheduled_object.y << endl; + } + #endif + REQUIRE(scheduled_object.x >= solver_configuration.plate_bounding_box.min.x() * SEQ_SLICER_SCALE_FACTOR); + REQUIRE(scheduled_object.x <= solver_configuration.plate_bounding_box.max.x() * SEQ_SLICER_SCALE_FACTOR); + REQUIRE(scheduled_object.y >= solver_configuration.plate_bounding_box.min.y() * SEQ_SLICER_SCALE_FACTOR); + REQUIRE(scheduled_object.y <= solver_configuration.plate_bounding_box.max.y() * SEQ_SLICER_SCALE_FACTOR); + } + } + } + else + { + #ifdef DEBUG + { + printf("Something went WRONG during sequential scheduling (code: %d)\n", result); + } + #endif + } + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing interface 1 ... finished"); +} + + +TEST_CASE("Interface test 2", "[Sequential Arrangement Interface]") +//void interface_test_2(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing interface 2 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.decimation_precision = SEQ_DECIMATION_PRECISION_HIGH; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE / SEQ_SLICER_SCALE_FACTOR, SEQ_QIDI_MK3S_Y_SIZE / SEQ_SLICER_SCALE_FACTOR}); + + #ifdef DEBUG + { + printf("Loading objects ...\n"); + } + #endif + std::vector objects_to_print = load_exported_data_from_text(arrange_data_export_text); + + std::vector > convex_unreachable_zones; + std::vector > box_unreachable_zones; + + #ifdef DEBUG + { + printf("Preparing extruder unreachable zones ...\n"); + } + #endif + setup_ExtruderUnreachableZones(solver_configuration, convex_unreachable_zones, box_unreachable_zones); + + std::vector scheduled_plates; + #ifdef DEBUG + { + printf("Scheduling objects for sequential print ...\n"); + } + #endif + + int result = schedule_ObjectsForSequentialPrint(solver_configuration, + objects_to_print, + convex_unreachable_zones, + box_unreachable_zones, + scheduled_plates); + + REQUIRE(result == 0); + if (result == 0) + { + #ifdef DEBUG + { + printf("Object scheduling for sequential print SUCCESSFUL !\n"); + printf("Number of plates: %ld\n", scheduled_plates.size()); + } + #endif + REQUIRE(scheduled_plates.size() > 0); + + for (unsigned int plate = 0; plate < scheduled_plates.size(); ++plate) + { + #ifdef DEBUG + { + printf(" Number of objects on plate: %ld\n", scheduled_plates[plate].scheduled_objects.size()); + } + #endif + REQUIRE(scheduled_plates[plate].scheduled_objects.size() > 0); + + for (const auto& scheduled_object: scheduled_plates[plate].scheduled_objects) + { + #ifdef DEBUG + { + cout << " ID: " << scheduled_object.id << " X: " << scheduled_object.x << " Y: " << scheduled_object.y << endl; + } + #endif + REQUIRE(scheduled_object.x >= solver_configuration.plate_bounding_box.min.x() * SEQ_SLICER_SCALE_FACTOR); + REQUIRE(scheduled_object.x <= solver_configuration.plate_bounding_box.max.x() * SEQ_SLICER_SCALE_FACTOR); + REQUIRE(scheduled_object.y >= solver_configuration.plate_bounding_box.min.y() * SEQ_SLICER_SCALE_FACTOR); + REQUIRE(scheduled_object.y <= solver_configuration.plate_bounding_box.max.y() * SEQ_SLICER_SCALE_FACTOR); + } + } + } + else + { + #ifdef DEBUG + { + printf("Something went WRONG during sequential scheduling (code: %d)\n", result); + } + #endif + } + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing interface 2 ... finished"); +} + + +TEST_CASE("Interface test 3", "[Sequential Arrangement Interface]") +//void interface_test_3(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing interface 3 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + PrinterGeometry printer_geometry = + { + { {0, 0}, {250000000, 0}, {250000000, 210000000}, {0, 210000000} }, + { 0, 3000000, 22000000}, + { 11000000, 13000000 }, + { + {0, { { {-500000, -500000}, {500000, -500000}, {500000, 500000}, {-500000, 500000} } } }, + {3000000, { { {-9000000, -17000000}, {40000000, -17000000}, {40000000, 44000000}, {-9000000, 44000000} }, + { {-36000000, -44000000}, {40000000, -44000000}, {40000000, -13000000}, {-36000000, -13000000} } } }, + {22000000, { { {-41000000, -45000000}, {16000000, -45000000}, {16000000, 22000000}, {-41000000, 22000000} }, + { {11000000, -45000000}, {39000000, -45000000}, {39000000, 45000000}, {11000000 , 45000000} } } }, + {11000000, { { {-300000000, -4000000}, {300000000, -4000000}, {300000000, -14000000}, {-300000000, -14000000} } } }, + {13000000, { { {-13000000, -84000000}, {11000000, -84000000}, {11000000, -38000000}, {-13000000, -38000000} }, + { {11000000, -300000000}, {300000000, -300000000}, {300000000, -84000000}, {11000000, -84000000} } } } + + } + }; + + /* + int result = load_printer_geometry_from_text(printer_geometry_mk4_text, printer_geometry); + REQUIRE(result == 0); + + if (result != 0) + { + #ifdef DEBUG + { + printf("Printer geometry load error.\n"); + } + #endif + return; + } + */ + + REQUIRE(printer_geometry.plate.points.size() == 4); + + #ifdef DEBUG + { + for (const auto& convex_height: printer_geometry.convex_heights) + { + cout << "convex_height:" << convex_height << endl; + } + } + #endif + + #ifdef DEBUG + { + for (const auto& box_height: printer_geometry.box_heights) + { + cout << "box_height:" << box_height << endl; + } + } + #endif + + #ifdef DEBUG + { + printf("extruder slices:\n"); + } + #endif + REQUIRE(printer_geometry.extruder_slices.size() > 0); + + #ifdef DEBUG + { + for (std::map >::const_iterator extruder_slice = printer_geometry.extruder_slices.begin(); extruder_slice != printer_geometry.extruder_slices.end(); ++extruder_slice) + { + for (const auto &polygon: extruder_slice->second) + { + printf(" polygon height: %d\n", extruder_slice->first); + + for (const auto &point: polygon.points) + { + cout << " " << point.x() << " " << point.y() << endl; + } + } + } + + } + #endif + + #ifdef DEBUG + finish = clock(); + + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing interface 3 ... finished"); +} + + +TEST_CASE("Interface test 4", "[Sequential Arrangement Interface]") +//void interface_test_4(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing interface 4 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.decimation_precision = SEQ_DECIMATION_PRECISION_HIGH; + solver_configuration.object_group_size = 4; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE / SEQ_SLICER_SCALE_FACTOR, SEQ_QIDI_MK3S_Y_SIZE / SEQ_SLICER_SCALE_FACTOR}); + + #ifdef DEBUG + { + printf("Loading objects ...\n"); + } + #endif + std::vector objects_to_print = load_exported_data_from_text(arrange_data_export_text); + #ifdef DEBUG + { + printf("Loading objects ... finished\n"); + } + #endif + + PrinterGeometry printer_geometry; + + #ifdef DEBUG + { + printf("Loading printer geometry ...\n"); + } + #endif + int result = load_printer_geometry_from_text(printer_geometry_mk4_compatibility_text, printer_geometry); + + REQUIRE(result == 0); + if (result != 0) + { + #ifdef DEBUG + { + printf("Cannot load printer geometry (code: %d).\n", result); + } + #endif + return; + } + solver_configuration.setup(printer_geometry); + #ifdef DEBUG + { + printf("Loading printer geometry ... finished\n"); + } + #endif + + std::vector scheduled_plates; + #ifdef DEBUG + { + printf("Scheduling objects for sequential print ...\n"); + } + #endif + + scheduled_plates = schedule_ObjectsForSequentialPrint(solver_configuration, + printer_geometry, + objects_to_print); + + #ifdef DEBUG + { + printf("Object scheduling for sequential print SUCCESSFUL !\n"); + } + #endif + + #ifdef DEBUG + { + printf("Number of plates: %ld\n", scheduled_plates.size()); + } + #endif + REQUIRE(scheduled_plates.size() > 0); + + for (unsigned int plate = 0; plate < scheduled_plates.size(); ++plate) + { + #ifdef DEBUG + { + printf(" Number of objects on plate: %ld\n", scheduled_plates[plate].scheduled_objects.size()); + } + #endif + REQUIRE(scheduled_plates[plate].scheduled_objects.size() > 0); + + for (const auto& scheduled_object: scheduled_plates[plate].scheduled_objects) + { + #ifdef DEBUG + { + cout << " ID: " << scheduled_object.id << " X: " << scheduled_object.x << " Y: " << scheduled_object.y << endl; + } + #endif + + BoundingBox plate_box = get_extents(printer_geometry.plate); + + REQUIRE(scheduled_object.x >= plate_box.min.x()); + REQUIRE(scheduled_object.x <= plate_box.max.x()); + REQUIRE(scheduled_object.y >= plate_box.min.y()); + REQUIRE(scheduled_object.y <= plate_box.max.y()); + } + } + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing interface 4 ... finished"); +} + + +TEST_CASE("Interface test 5", "[Sequential Arrangement Interface]") +//void interface_test_5(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing interface 5 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.decimation_precision = SEQ_DECIMATION_PRECISION_LOW; + solver_configuration.object_group_size = 4; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE / SEQ_SLICER_SCALE_FACTOR, SEQ_QIDI_MK3S_Y_SIZE / SEQ_SLICER_SCALE_FACTOR}); + + #ifdef DEBUG + { + printf("Loading objects ...\n"); + } + #endif + std::vector objects_to_print = load_exported_data_from_text(arrange_data_export_text); + #ifdef DEBUG + { + printf("Loading objects ... finished\n"); + } + #endif + + PrinterGeometry printer_geometry; + + #ifdef DEBUG + { + printf("Loading printer geometry ...\n"); + } + #endif + int result = load_printer_geometry_from_text(printer_geometry_mk4_compatibility_text, printer_geometry); + + REQUIRE(result == 0); + if (result != 0) + { + #ifdef DEBUG + { + printf("Cannot load printer geometry (code: %d).\n", result); + } + #endif + return; + } + solver_configuration.setup(printer_geometry); + #ifdef DEBUG + { + printf("Loading printer geometry ... finished\n"); + } + #endif + + std::vector scheduled_plates; + + #ifdef DEBUG + { + printf("Scheduling objects for sequential print ...\n"); + } + #endif + scheduled_plates = schedule_ObjectsForSequentialPrint(solver_configuration, + printer_geometry, + objects_to_print, + [](int progress) { + #ifdef DEBUG + { printf("Progress: %d\n", progress); } + #endif + REQUIRE(progress >= 0); + REQUIRE(progress <= 100); }); + + #ifdef DEBUG + { + printf("Object scheduling for sequential print SUCCESSFUL !\n"); + } + #endif + + #ifdef DEBUG + { + printf("Number of plates: %ld\n", scheduled_plates.size()); + } + #endif + REQUIRE(scheduled_plates.size() > 0); + + for (unsigned int plate = 0; plate < scheduled_plates.size(); ++plate) + { + #ifdef DEBUG + { + printf("Number of objects on plate: %ld\n", scheduled_plates[plate].scheduled_objects.size()); + } + #endif + REQUIRE(scheduled_plates[plate].scheduled_objects.size() > 0); + + for (const auto& scheduled_object: scheduled_plates[plate].scheduled_objects) + { + #ifdef DEBUG + { + cout << " ID: " << scheduled_object.id << " X: " << scheduled_object.x << " Y: " << scheduled_object.y << endl; + } + #endif + + BoundingBox plate_box = get_extents(printer_geometry.plate); + + REQUIRE(scheduled_object.x >= plate_box.min.x()); + REQUIRE(scheduled_object.x <= plate_box.max.x()); + REQUIRE(scheduled_object.y >= plate_box.min.y()); + REQUIRE(scheduled_object.y <= plate_box.max.y()); + } + } + + #ifdef DEBUG + finish = clock(); + { + printf("Solving time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + start = clock(); + #endif + + + #ifdef DEBUG + { + printf("Checking sequential printability ...\n"); + } + #endif + + bool printable = check_ScheduledObjectsForSequentialPrintability(solver_configuration, + printer_geometry, + objects_to_print, + scheduled_plates); + + #ifdef DEBUG + { + printf(" Scheduled/arranged objects are sequentially printable: %s\n", (printable ? "YES" : "NO")); + } + #endif + REQUIRE(printable); + + #ifdef DEBUG + { + printf("Checking sequential printability ... finished\n"); + } + #endif + + #ifdef DEBUG + finish = clock(); + { + printf("Checking time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing interface 5 ... finished"); +} + + +TEST_CASE("Interface test 6", "[Sequential Arrangement Interface]") +//void interface_test_6(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing interface 6 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.decimation_precision = SEQ_DECIMATION_PRECISION_LOW; + solver_configuration.object_group_size = 4; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE / SEQ_SLICER_SCALE_FACTOR, SEQ_QIDI_MK3S_Y_SIZE / SEQ_SLICER_SCALE_FACTOR}); + + #ifdef DEBUG + { + printf("Loading objects ...\n"); + } + #endif + std::vector objects_to_print = load_exported_data_from_text(arrange_data_export_text); + REQUIRE(objects_to_print.size() > 0); + + #ifdef DEBUG + { + printf("Loading objects ... finished\n"); + } + #endif + + for (auto& object_to_print: objects_to_print) + { + object_to_print.glued_to_next = true; + } + + PrinterGeometry printer_geometry; + + #ifdef DEBUG + { + printf("Loading printer geometry ...\n"); + } + #endif + int result = load_printer_geometry_from_text(printer_geometry_mk4_compatibility_text, printer_geometry); + + REQUIRE(result == 0); + if (result != 0) + { + #ifdef DEBUG + { + printf("Cannot load printer geometry (code: %d).\n", result); + } + #endif + return; + } + solver_configuration.setup(printer_geometry); + #ifdef DEBUG + { + printf("Loading printer geometry ... finished\n"); + } + #endif + + std::vector scheduled_plates; + #ifdef DEBUG + { + printf("Scheduling objects for sequential print ...\n"); + } + #endif + + scheduled_plates = schedule_ObjectsForSequentialPrint(solver_configuration, + printer_geometry, + objects_to_print, + [](int progress) { + #ifdef DEBUG + { printf("Progress: %d\n", progress); } + #endif + REQUIRE(progress >= 0); + REQUIRE(progress <= 100); }); + + #ifdef DEBUG + { + printf("Object scheduling for sequential print SUCCESSFUL !\n"); + } + #endif + + #ifdef DEBUG + { + printf("Number of plates: %ld\n", scheduled_plates.size()); + } + #endif + REQUIRE(scheduled_plates.size() > 0); + + for (unsigned int plate = 0; plate < scheduled_plates.size(); ++plate) + { + #ifdef DEBUG + { + printf(" Number of objects on plate: %ld\n", scheduled_plates[plate].scheduled_objects.size()); + } + #endif + + REQUIRE(scheduled_plates[plate].scheduled_objects.size() > 0); + + for (const auto& scheduled_object: scheduled_plates[plate].scheduled_objects) + { + #ifdef DEBUG + { + cout << " ID: " << scheduled_object.id << " X: " << scheduled_object.x << " Y: " << scheduled_object.y << endl; + } + #endif + BoundingBox plate_box = get_extents(printer_geometry.plate); + + REQUIRE(scheduled_object.x >= plate_box.min.x()); + REQUIRE(scheduled_object.x <= plate_box.max.x()); + REQUIRE(scheduled_object.y >= plate_box.min.y()); + REQUIRE(scheduled_object.y <= plate_box.max.y()); + } + } + + #ifdef DEBUG + finish = clock(); + { + printf("Solving time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + start = clock(); + #endif + + #ifdef DEBUG + { + printf("Checking sequential printability ...\n"); + } + #endif + + bool printable = check_ScheduledObjectsForSequentialPrintability(solver_configuration, + printer_geometry, + objects_to_print, + scheduled_plates); + + #ifdef DEBUG + { + printf(" Scheduled/arranged objects are sequentially printable: %s\n", (printable ? "YES" : "NO")); + } + #endif + REQUIRE(printable); + + #ifdef DEBUG + { + printf("Checking sequential printability ... finished\n"); + } + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Checking time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing interface 6 ... finished"); +} + + +/*----------------------------------------------------------------*/ + + diff --git a/src/libseqarrange/test/seq_test_interface.hpp b/src/libseqarrange/test/seq_test_interface.hpp new file mode 100644 index 0000000..f71a8f7 --- /dev/null +++ b/src/libseqarrange/test/seq_test_interface.hpp @@ -0,0 +1,7 @@ +#ifndef __SEQ_TEST_INTERFACE_HPP__ +#define __SEQ_TEST_INTERFACE_HPP__ + +/*----------------------------------------------------------------*/ + + +#endif /* __SEQ_TEST_PREPROCESS_HPP__ */ diff --git a/src/libseqarrange/test/seq_test_polygon.cpp b/src/libseqarrange/test/seq_test_polygon.cpp new file mode 100644 index 0000000..eb01fa6 --- /dev/null +++ b/src/libseqarrange/test/seq_test_polygon.cpp @@ -0,0 +1,3356 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Geometry/ConvexHull.hpp" +#include "libslic3r/SVG.hpp" + +#include + +#include "qidiparts.hpp" + +#include "seq_defs.hpp" + +#include "seq_sequential.hpp" +#include "seq_preprocess.hpp" + +#include "seq_test_polygon.hpp" + + +/*----------------------------------------------------------------*/ + +using namespace Slic3r; +using namespace Slic3r::Geometry; + +using namespace z3; + +using namespace Sequential; + +#define SCALE_FACTOR 100000 + + +/*----------------------------------------------------------------*/ + +const int SEQ_QIDI_MK3S_X_SIZE = 2500; +const int SEQ_QIDI_MK3S_Y_SIZE = 2100; + + +/*----------------------------------------------------------------*/ + +TEST_CASE("Polygon test 1", "[Polygon]") +{ + INFO("Testing polygon 1 ..."); + + Polygon polygon_1 = {{-1000000, -1000000}, {1000000, -1000000}, {1000000, 1000000}, {-1000000, 1000000} }; + + #ifdef DEBUG + { + for (unsigned int i = 0; i < polygon_1.size(); ++i) + { + Point point = polygon_1[i]; + printf("%d,%d\n", point.x(), point.y()); + } + } + #endif + REQUIRE(polygon_1.size() > 0); + + INFO("Testing polygon 1 ... finished"); +} + + +TEST_CASE("Polygon test 2", "[Polygon]") +{ + INFO("Testing polygon 2 ..."); + + for (unsigned int k = 0; k < QIDI_PART_POLYGONS.size(); ++k) + { + #ifdef DEBUG + { + printf("k = %d\n", k); + } + #endif + + const Polygon &polygon_1 = QIDI_PART_POLYGONS[k]; + Polygon hull_1 = convex_hull(polygon_1); + + #ifdef DEBUG + { + for (unsigned int i = 0; i < polygon_1.size(); ++i) + { + const Point &point = polygon_1[i]; + printf("poly %d: %d,%d\n", i, point.x(), point.y()); + } + printf("\n"); + + for (unsigned int i = 0; i < hull_1.size(); ++i) + { + const Point &point = hull_1[i]; + printf("hull %d: %d,%d\n", i, point.x(), point.y()); + } + } + #endif + + REQUIRE(hull_1.size() > 0); + + if (hull_1.size() >= 2) + { + const Point &point_1 = hull_1[0]; + const Point &point_2 = hull_1[1]; + + Point v = (point_2 - point_1); //.normalized(); + #ifdef DEBUG + { + printf("v: %d,%d\n", v.x(), v.y()); + cout << v << endl; + } + #endif + + #ifdef DEBUG + { + Point u = v.normalized(); + printf("u: %d,%d\n", u.x(), u.y()); + cout << u << endl; + } + #endif + + Point n(v.y(), -v.x()); + + #ifdef DEBUG + { + printf("Ortho:\n"); + cout << n << endl; + } + #endif + + coord_t d = n.x() * point_1.x() + n.y() * point_1.y(); + + #ifdef DEBUG + { + printf("%d\n", d); + cout << d << endl; + } + #endif + + auto is_inside=[&](const Point &p) + { + coord_t d1 = n.x() * p.x() + n.y() * p.y() - d; + + #ifdef DEBUG + { + printf("d1: %d\n", d1); + } + #endif + + if (d1 >= 0) + { + return true; + } + else + { + return false; + } + }; + + bool ins1 = is_inside(point_1); + #ifdef DEBUG + { + printf("%s\n", ins1 ? "yes" : "no"); + } + #endif + REQUIRE(ins1); + + bool ins2 = is_inside(point_2); + #ifdef DEBUG + { + printf("%s\n", ins2 ? "yes" : "no"); + } + #endif + REQUIRE(ins2); + + #ifdef DEBUG + { + bool ins3 = is_inside(point_1 + point_2); + printf("%s\n", ins3 ? "yes" : "no"); + } + #endif + + #ifdef DEBUG + { + bool ins4 = is_inside(point_1 - point_2); + printf("%s\n", ins4 ? "yes" : "no"); + } + #endif + } + } + + INFO("Testing polygon 2 ... finished"); +} + + +int line_count = 4; +Line lines[] = {{Point(100,100), Point(200,200)}, {Point(200,100), Point(100,200)}, {Point(0,0), Point(100,10)}, {Point(50,0), Point(60,100)} }; + +TEST_CASE("Polygon test 3", "[Polygon]") + +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 3 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + z3::expr_vector T_parameters(z_context); + + for (int i = 0; i < line_count; ++i) + { + string name = "x_pos-" + to_string(i); + #ifdef DEBUG + { + printf("i:%d\n", i); + printf("name: %s\n", name.c_str()); + } + #endif + X_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < line_count; ++i) + { + string name = "y_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + Y_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < line_count; ++i) + { + string name = "t_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + z3::solver z_solver(z_context); + + introduce_LineNonIntersection_explicit(z_solver, + z_context, + X_positions[0], + Y_positions[0], + T_parameters[0], + lines[0], + X_positions[1], + Y_positions[1], + T_parameters[1], + lines[1]); + + introduce_LineNonIntersection_explicit(z_solver, + z_context, + X_positions[2], + Y_positions[2], + T_parameters[2], + lines[2], + X_positions[3], + Y_positions[3], + T_parameters[3], + lines[3]); + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + bool sat = false; + switch (z_solver.check()) + { + case z3::sat: + { + sat = true; + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + return; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Printing interpretation:\n"); + for (unsigned int i = 0; i < z_model.size(); ++i) + { + printf("Variable:%s ", z_model[i].name().str().c_str()); + { + cout << z_model.get_const_interp(z_model[i]).as_double() << "\n"; + double value = z_model.get_const_interp(z_model[i]).as_double(); + + printf("value: %.3f\n", value); + + cout << float(z_model[i]) << "\n"; + + switch (z_model.get_const_interp(z_model[i]).bool_value()) + { + case Z3_L_FALSE: + { + printf(" value: FALSE\n"); + break; + } + case Z3_L_TRUE: + { + printf(" value: TRUE\n"); + break; + } + case Z3_L_UNDEF: + { + printf(" value: UNDEF\n"); + break; + } + default: + { + break; + } + } + } + } + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 3 ... finished"); +} + + +TEST_CASE("Polygon test 4", "[Polygon]") +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 4 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + z3::expr_vector T_parameters(z_context); + + for (int i = 0; i < line_count; ++i) + { + string name = "x_pos-" + to_string(i); + #ifdef DEBUG + { + printf("i:%d\n", i); + printf("name: %s\n", name.c_str()); + } + #endif + X_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < line_count; ++i) + { + string name = "y_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + Y_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < line_count; ++i) + { + string name = "t_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + z3::solver z_solver(z_context); + + introduce_LineNonIntersection_implicit(z_solver, + z_context, + X_positions[0], + Y_positions[0], + T_parameters[0], + lines[0], + X_positions[1], + Y_positions[1], + T_parameters[1], + lines[1]); + + introduce_LineNonIntersection_implicit(z_solver, + z_context, + X_positions[2], + Y_positions[2], + T_parameters[2], + lines[2], + X_positions[3], + Y_positions[3], + T_parameters[3], + lines[3]); + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + bool sat = false; + + switch (z_solver.check()) + { + case z3::sat: + { + sat = true; + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + return; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + #ifdef DEBUG + { + z3::model z_model(z_solver.get_model()); + printf("Printing model:\n"); + cout << z_model << "\n"; + + finish = clock(); + + printf("Printing interpretation:\n"); + for (unsigned int i = 0; i < z_model.size(); ++i) + { + printf("Variable:%s ", z_model[i].name().str().c_str()); + + cout << z_model.get_const_interp(z_model[i]).as_double() << "\n"; + double value = z_model.get_const_interp(z_model[i]).as_double(); + + printf("value: %.3f\n", value); + + cout << float(z_model[i]) << "\n"; + + switch (z_model.get_const_interp(z_model[i]).bool_value()) + { + case Z3_L_FALSE: + { + printf(" value: FALSE\n"); + break; + } + case Z3_L_TRUE: + { + printf(" value: TRUE\n"); + break; + } + case Z3_L_UNDEF: + { + printf(" value: UNDEF\n"); + break; + } + default: + { + break; + } + } + } + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 4 ... finished"); +} + + +int poly_line_count = 4; +Line poly_lines[] = {{Point(100,100), Point(200,100)}, {Point(200,100), Point(200,200)}, {Point(200,200), Point(100,200)}, {Point(100,200), Point(100,100)} }; + + +TEST_CASE("Polygon test 5", "[Polygon]") +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 5 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + + for (int i = 0; i < poly_line_count; ++i) + { + string name = "x_pos-" + to_string(i); + #ifdef DEBUG + { + printf("i:%d\n", i); + printf("name: %s\n", name.c_str()); + } + #endif + X_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < poly_line_count; ++i) + { + string name = "y_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + Y_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + z3::solver z_solver(z_context); + + introduce_PointInsideHalfPlane(z_solver, + X_positions[0], + Y_positions[0], + X_positions[1], + Y_positions[1], + poly_lines[0]); + + introduce_PointInsideHalfPlane(z_solver, + X_positions[0], + Y_positions[0], + X_positions[1], + Y_positions[1], + poly_lines[1]); + + introduce_PointInsideHalfPlane(z_solver, + X_positions[0], + Y_positions[0], + X_positions[1], + Y_positions[1], + poly_lines[2]); + + introduce_PointInsideHalfPlane(z_solver, + X_positions[0], + Y_positions[0], + X_positions[1], + Y_positions[1], + poly_lines[3]); + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + bool sat = false; + switch (z_solver.check()) + { + case z3::sat: + { + sat = true; + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + return; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + z3::model z_model(z_solver.get_model()); + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Printing interpretation:\n"); + + for (unsigned int i = 0; i < z_model.size(); ++i) + { + printf("Variable:%s ", z_model[i].name().str().c_str()); + + cout << z_model.get_const_interp(z_model[i]).as_double() << "\n"; + double value = z_model.get_const_interp(z_model[i]).as_double(); + + printf("value: %.3f\n", value); + + cout << float(z_model[i]) << "\n"; + + switch (z_model.get_const_interp(z_model[i]).bool_value()) + { + case Z3_L_FALSE: + { + printf(" value: FALSE\n"); + break; + } + case Z3_L_TRUE: + { + printf(" value: TRUE\n"); + break; + } + case Z3_L_UNDEF: + { + printf(" value: UNDEF\n"); + break; + } + default: + { + break; + } + } + } + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 5 ... finished"); +} + +namespace { + Polygon polygon_1 = { {0, 0}, {50, 0}, {50, 50}, {0, 50} }; + //Polygon polygon_1 = {{scale_(0), scale_(0)}, {scale_(50), scale_(0)}, {scale_(50), scale_(50)}, {scale_(0), scale_(50)}}; +} + + +//TEST_CASE("Polygon test 6", "[Polygon]") +void polygon_test_6(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 6 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + + for (int i = 0; i < poly_line_count; ++i) + { + string name = "x_pos-" + to_string(i); + #ifdef DEBUG + { + printf("i:%d\n", i); + printf("name: %s\n", name.c_str()); + } + #endif + X_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < poly_line_count; ++i) + { + string name = "y_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + Y_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + z3::solver z_solver(z_context); + + introduce_PointOutsidePolygon(z_solver, + z_context, + X_positions[0], + Y_positions[0], + X_positions[1], + Y_positions[1], + polygon_1); + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + bool sat = false; + switch (z_solver.check()) + { + case z3::sat: + { + sat = true; + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + return; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Printing interpretation:\n"); + + for (unsigned int i = 0; i < z_model.size(); ++i) + { + printf("Variable:%s ", z_model[i].name().str().c_str()); + cout << z_model.get_const_interp(z_model[i]).as_double() << "\n"; + + z3::expr valo_1 = z_model.get_const_interp(z_model[i]); + z3::expr deco_1 = expr(z_context.real_const("deco_1")); + + z3::expr lino_1 = (valo_1 * deco_1 == 0); + + cout << float(z_model[i]) << "\n"; + + switch (z_model.get_const_interp(z_model[i]).bool_value()) + { + case Z3_L_FALSE: + { + printf(" value: FALSE\n"); + break; + } + case Z3_L_TRUE: + { + printf(" value: TRUE\n"); + break; + } + case Z3_L_UNDEF: + { + printf(" value: UNDEF\n"); + break; + } + default: + { + break; + } + } + } + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 6 ... finished"); +} + + +Polygon polygon_2 = {{0, 0}, {150, 0}, {150, 50}, {75, 120}, {0, 50} }; +//Polygon polygon_2 = {{scale_(0), scale_(0)}, {scale_(150), scale_(0)}, {scale_(150), scale_(50)}, {scale_(75), scale_(120)}, {scale_(0), scale_(50)} }; + + +TEST_CASE("Polygon test 7", "[Polygon]") +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 7 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + z3::expr_vector T1_parameters(z_context); + z3::expr_vector T2_parameters(z_context); + + for (int i = 0; i < 2; ++i) + { + string name = "x_pos-" + to_string(i); + #ifdef DEBUG + { + printf("i:%d\n", i); + printf("name: %s\n", name.c_str()); + } + #endif + X_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < 2; ++i) + { + string name = "y_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + Y_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_1.points.size(); ++i) + { + string name = "t1_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T1_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_2.points.size(); ++i) + { + string name = "t2_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T2_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + z3::solver z_solver(z_context); + + introduce_DecisionBox(z_solver, X_positions[0], Y_positions[0], 200, 200); + introduce_DecisionBox(z_solver, X_positions[1], Y_positions[1], 200, 200); + + introduce_PolygonOutsidePolygon(z_solver, + z_context, + X_positions[0], + Y_positions[0], + polygon_1, + X_positions[1], + Y_positions[1], + polygon_2); + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + bool sat = false; + switch (z_solver.check()) + { + case z3::sat: + { + sat = true; + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + return; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + #ifdef DEBUG + finish = clock(); + + double poly_1_pos_x, poly_1_pos_y, poly_2_pos_x, poly_2_pos_y; + poly_1_pos_x = poly_1_pos_y = poly_2_pos_x = poly_2_pos_y = 0.0; + #endif + + #ifdef DEBUG + { + printf("Printing interpretation:\n"); + } + #endif + + for (unsigned int i = 0; i < z_model.size(); ++i) + { + #ifdef DEBUG + { + double value = z_model.get_const_interp(z_model[i]).as_double(); + + printf("Variable:%s ", z_model[i].name().str().c_str()); + cout << z_model.get_const_interp(z_model[i]).as_double() << "\n"; + printf("value: %.3f\n", value); + + if (z_model[i].name().str() == "x_pos-0") + { + poly_1_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-0") + { + poly_1_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-1") + { + poly_2_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-1") + { + poly_2_pos_y = value; + } + } + #endif + + #ifdef DEBUG + { + cout << float(z_model[i]) << "\n"; + + switch (z_model.get_const_interp(z_model[i]).bool_value()) + { + case Z3_L_FALSE: + { + printf(" value: FALSE\n"); + break; + } + case Z3_L_TRUE: + { + printf(" value: TRUE\n"); + break; + } + case Z3_L_UNDEF: + { + printf(" value: UNDEF\n"); + break; + } + default: + { + break; + } + } + } + #endif + + } + + #ifdef DEBUG + { + printf("Positions: %.3f, %.3f, %.3f, %.3f\n", poly_1_pos_x, poly_1_pos_y, poly_2_pos_x, poly_2_pos_y); + } + #endif + + #ifdef DEBUG + { + for (int i = 0; i < 2; ++i) + { + double value = X_positions[i].as_double(); + printf("Orig X: %.3f\n", value); + + value = Y_positions[i].as_double(); + printf("Orig Y: %.3f\n", value); + } + } + #endif + + SVG preview_svg("polygon_test_7.svg"); + + #ifdef DEBUG + { + preview_svg.draw(polygon_1); + preview_svg.draw(polygon_2); + } + #endif + + preview_svg.Close(); + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 7 ... finished"); +} + + +Polygon scale_UP(const Polygon &polygon) +{ + Polygon poly = polygon; + + for (unsigned int i = 0; i < poly.points.size(); ++i) + { + poly.points[i] = Point(poly.points[i].x() * SCALE_FACTOR, poly.points[i].y() * SCALE_FACTOR); + } + + return poly; +} + + +Polygon scale_UP(const Polygon &polygon, double x_pos, double y_pos) +{ + Polygon poly = polygon; + + for (unsigned int i = 0; i < poly.points.size(); ++i) + { + poly.points[i] = Point(poly.points[i].x() * SCALE_FACTOR + x_pos * SCALE_FACTOR, poly.points[i].y() * SCALE_FACTOR + y_pos * SCALE_FACTOR); + } + + return poly; +} + + +Polygon polygon_3 = {{40, 0}, {80, 40}, {40, 80}, {0, 40}}; +//Polygon polygon_3 = {{20, 0}, {40, 0}, {60, 30}, {30, 50}, {0, 30}}; + +//TEST_CASE("Polygon test 8", "[Polygon]") +void polygon_test_8(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 8 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + z3::expr_vector T1_parameters(z_context); + z3::expr_vector T2_parameters(z_context); + z3::expr_vector T3_parameters(z_context); + + for (int i = 0; i < 3; ++i) + { + string name = "x_pos-" + to_string(i); + #ifdef DEBUG + { + printf("i:%d\n", i); + printf("name: %s\n", name.c_str()); + } + #endif + X_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < 3; ++i) + { + string name = "y_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + Y_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_1.points.size(); ++i) + { + string name = "t1_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T1_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_2.points.size(); ++i) + { + string name = "t2_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T2_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_3.points.size(); ++i) + { + string name = "t3_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T3_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + z3::solver z_solver(z_context); + + introduce_PolygonOutsidePolygon(z_solver, + z_context, + X_positions[0], + Y_positions[0], + polygon_1, + X_positions[1], + Y_positions[1], + polygon_2); + + introduce_PolygonLineNonIntersection(z_solver, + z_context, + X_positions[0], + Y_positions[0], + polygon_1, + X_positions[1], + Y_positions[1], + polygon_2); + + introduce_PolygonOutsidePolygon(z_solver, + z_context, + X_positions[1], + Y_positions[1], + polygon_2, + X_positions[2], + Y_positions[2], + polygon_3); + + introduce_PolygonLineNonIntersection(z_solver, + z_context, + X_positions[1], + Y_positions[1], + polygon_2, + X_positions[2], + Y_positions[2], + polygon_3); + + introduce_PolygonOutsidePolygon(z_solver, + z_context, + X_positions[0], + Y_positions[0], + polygon_1, + X_positions[2], + Y_positions[2], + polygon_3); + + introduce_PolygonLineNonIntersection(z_solver, + z_context, + X_positions[0], + Y_positions[0], + polygon_1, + X_positions[2], + Y_positions[2], + polygon_3); + + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + int last_solvable_decision_box_size = -1; + double poly_1_pos_x, poly_1_pos_y, poly_2_pos_x, poly_2_pos_y, poly_3_pos_x, poly_3_pos_y; + poly_1_pos_x = poly_1_pos_y = poly_2_pos_x = poly_2_pos_y = poly_3_pos_x = poly_3_pos_y = 0.0; + + for (int decision_box_size = 300; decision_box_size > 10; decision_box_size -= 4) + { + z3::expr_vector decision_box_assumptions(z_context); + + assume_DecisionBox(X_positions[0], Y_positions[0], decision_box_size, decision_box_size, decision_box_assumptions); + assume_DecisionBox(X_positions[1], Y_positions[1], decision_box_size, decision_box_size, decision_box_assumptions); + assume_DecisionBox(X_positions[2], Y_positions[2], decision_box_size, decision_box_size, decision_box_assumptions); + + bool sat = false; + + switch (z_solver.check(decision_box_assumptions)) + { + case z3::sat: + { + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + last_solvable_decision_box_size = decision_box_size; + sat = true; + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + sat = false; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + #ifdef DEBUG + { + printf("Printing interpretation:\n"); + } + #endif + for (unsigned int i = 0; i < z_model.size(); ++i) + { + double value = z_model.get_const_interp(z_model[i]).as_double(); + + #ifdef DEBUG + { + printf("Variable:%s ", z_model[i].name().str().c_str()); + cout << z_model.get_const_interp(z_model[i]).as_double() << "\n"; + printf("value: %.3f\n", value); + } + #endif + + if (z_model[i].name().str() == "x_pos-0") + { + poly_1_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-0") + { + poly_1_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-1") + { + poly_2_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-1") + { + poly_2_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-2") + { + poly_3_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-2") + { + poly_3_pos_y = value; + } + } + } + else + { + break; + } + } + #ifdef DEBUG + finish = clock(); + #endif + + REQUIRE(last_solvable_decision_box_size > 0); + + #ifdef DEBUG + { + printf("Solvable decision box: %d\n", last_solvable_decision_box_size); + printf("Positions: %.3f, %.3f, %.3f, %.3f, %.3f, %.3f\n", poly_1_pos_x, poly_1_pos_y, poly_2_pos_x, poly_2_pos_y, poly_3_pos_x, poly_3_pos_y); + } + #endif + + #ifdef DEBUG + { + for (int i = 0; i < 2; ++i) + { + double value = X_positions[i].as_double(); + printf("Orig X: %.3f\n", value); + + value = Y_positions[i].as_double(); + printf("Orig Y: %.3f\n", value); + } + } + #endif + + SVG preview_svg("polygon_test_8.svg"); + + Polygon display_polygon_1 = scale_UP(polygon_1, poly_1_pos_x, poly_1_pos_y); + Polygon display_polygon_2 = scale_UP(polygon_2, poly_2_pos_x, poly_2_pos_y); + Polygon display_polygon_3 = scale_UP(polygon_3, poly_3_pos_x, poly_3_pos_y); + + preview_svg.draw(display_polygon_1, "green"); + preview_svg.draw(display_polygon_2, "blue"); + preview_svg.draw(display_polygon_3, "red"); + + preview_svg.Close(); + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 8 ... finished"); +} + + +TEST_CASE("Polygon test 9", "[Polygon]") +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 9 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + z3::expr_vector T1_parameters(z_context); + z3::expr_vector T2_parameters(z_context); + z3::expr_vector T3_parameters(z_context); + + for (int i = 0; i < 3; ++i) + { + string name = "x_pos-" + to_string(i); + #ifdef DEBUG + { + printf("i:%d\n", i); + printf("name: %s\n", name.c_str()); + } + #endif + X_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < 3; ++i) + { + string name = "y_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + Y_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_1.points.size(); ++i) + { + string name = "t1_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T1_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_2.points.size(); ++i) + { + string name = "t2_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T2_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_3.points.size(); ++i) + { + string name = "t3_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T3_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + z3::solver z_solver(z_context); + + introduce_PolygonOutsidePolygon(z_solver, + z_context, + X_positions[0], + Y_positions[0], + polygon_1, + X_positions[1], + Y_positions[1], + polygon_2); + + introduce_PolygonLineNonIntersection(z_solver, + z_context, + X_positions[0], + Y_positions[0], + polygon_1, + X_positions[1], + Y_positions[1], + polygon_2); + + introduce_PolygonOutsidePolygon(z_solver, + z_context, + X_positions[1], + Y_positions[1], + polygon_2, + X_positions[2], + Y_positions[2], + polygon_3); + + introduce_PolygonLineNonIntersection(z_solver, + z_context, + X_positions[1], + Y_positions[1], + polygon_2, + X_positions[2], + Y_positions[2], + polygon_3); + + introduce_PolygonOutsidePolygon(z_solver, + z_context, + X_positions[0], + Y_positions[0], + polygon_1, + X_positions[2], + Y_positions[2], + polygon_3); + + introduce_PolygonLineNonIntersection(z_solver, + z_context, + X_positions[0], + Y_positions[0], + polygon_1, + X_positions[2], + Y_positions[2], + polygon_3); + + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + int last_solvable_bounding_box_size = -1; + double poly_1_pos_x, poly_1_pos_y, poly_2_pos_x, poly_2_pos_y, poly_3_pos_x, poly_3_pos_y; + poly_1_pos_x = poly_1_pos_y = poly_2_pos_x = poly_2_pos_y = poly_3_pos_x = poly_3_pos_y = 0.0; + + for (int bounding_box_size = 300; bounding_box_size > 10; bounding_box_size -= 4) + { + z3::expr_vector bounding_box_assumptions(z_context); + + assume_BedBoundingBox(X_positions[0], Y_positions[0], polygon_1, bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[1], Y_positions[1], polygon_2, bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[2], Y_positions[2], polygon_3, bounding_box_size, bounding_box_size, bounding_box_assumptions); + + bool sat = false; + + switch (z_solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + last_solvable_bounding_box_size = bounding_box_size; + sat = true; + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + sat = false; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + #ifdef DEBUG + { + printf("Printing interpretation:\n"); + } + #endif + for (unsigned int i = 0; i < z_model.size(); ++i) + { + double value = z_model.get_const_interp(z_model[i]).as_double(); + + #ifdef DEBUG + { + printf("Variable:%s ", z_model[i].name().str().c_str()); + cout << z_model.get_const_interp(z_model[i]).as_double() << "\n"; + printf("value: %.3f\n", value); + } + #endif + + if (z_model[i].name().str() == "x_pos-0") + { + poly_1_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-0") + { + poly_1_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-1") + { + poly_2_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-1") + { + poly_2_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-2") + { + poly_3_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-2") + { + poly_3_pos_y = value; + } + } + } + else + { + break; + } + } + #ifdef DEBUG + finish = clock(); + #endif + + REQUIRE(last_solvable_bounding_box_size > 0); + + #ifdef DEBUG + { + printf("Solvable bounding box: %d\n", last_solvable_bounding_box_size); + printf("Positions: %.3f, %.3f, %.3f, %.3f, %.3f, %.3f\n", poly_1_pos_x, poly_1_pos_y, poly_2_pos_x, poly_2_pos_y, poly_3_pos_x, poly_3_pos_y); + } + #endif + + #ifdef DEBUG + { + for (int i = 0; i < 2; ++i) + { + double value = X_positions[i].as_double(); + printf("Orig X: %.3f\n", value); + + value = Y_positions[i].as_double(); + printf("Orig Y: %.3f\n", value); + } + } + #endif + + SVG preview_svg("polygon_test_9.svg"); + + Polygon display_polygon_1 = scale_UP(polygon_1, poly_1_pos_x, poly_1_pos_y); + Polygon display_polygon_2 = scale_UP(polygon_2, poly_2_pos_x, poly_2_pos_y); + Polygon display_polygon_3 = scale_UP(polygon_3, poly_3_pos_x, poly_3_pos_y); + + preview_svg.draw(display_polygon_1, "green"); + preview_svg.draw(display_polygon_2, "blue"); + preview_svg.draw(display_polygon_3, "red"); + + preview_svg.Close(); + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 9 ... finished"); +} + + +Polygon polygon_4 = {{20, 0}, {40, 0}, {60, 30}, {30, 50}, {0, 30}}; + +//TEST_CASE("Polygon test 10", "[Polygon]") +void polygon_test_10(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 10 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + z3::expr_vector T1_parameters(z_context); + z3::expr_vector T2_parameters(z_context); + z3::expr_vector T3_parameters(z_context); + z3::expr_vector T4_parameters(z_context); + + for (int i = 0; i < 4; ++i) + { + string name = "x_pos-" + to_string(i); + #ifdef DEBUG + { + printf("i:%d\n", i); + printf("name: %s\n", name.c_str()); + } + #endif + X_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < 4; ++i) + { + string name = "y_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + Y_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_1.points.size(); ++i) + { + string name = "t1_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T1_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_2.points.size(); ++i) + { + string name = "t2_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T2_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_3.points.size(); ++i) + { + string name = "t3_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T3_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_4.points.size(); ++i) + { + string name = "t4_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T4_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + z3::solver z_solver(z_context); + + vector polygons; + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + introduce_PolygonStrongNonoverlapping(z_solver, + z_context, + X_positions, + Y_positions, + polygons); + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + int last_solvable_bounding_box_size = -1; + double poly_1_pos_x, poly_1_pos_y, poly_2_pos_x, poly_2_pos_y, poly_3_pos_x, poly_3_pos_y, poly_4_pos_x, poly_4_pos_y; + poly_1_pos_x = poly_1_pos_y = poly_2_pos_x = poly_2_pos_y = poly_3_pos_x = poly_3_pos_y = poly_4_pos_x = poly_4_pos_y = 0.0; + + for (int bounding_box_size = 300; bounding_box_size > 10; bounding_box_size -= 4) + { + z3::expr_vector bounding_box_assumptions(z_context); + + assume_BedBoundingBox(X_positions[0], Y_positions[0], polygons[0], bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[1], Y_positions[1], polygons[1], bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[2], Y_positions[2], polygons[2], bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[3], Y_positions[3], polygons[3], bounding_box_size, bounding_box_size, bounding_box_assumptions); + + bool sat = false; + + switch (z_solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + last_solvable_bounding_box_size = bounding_box_size; + sat = true; + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + sat = false; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + #ifdef DEBUG + { + printf("Printing interpretation:\n"); + } + #endif + + for (unsigned int i = 0; i < z_model.size(); ++i) + { + double value = z_model.get_const_interp(z_model[i]).as_double(); + + #ifdef DEBUG + { + printf("Variable:%s ", z_model[i].name().str().c_str()); + cout << z_model.get_const_interp(z_model[i]).as_double() << "\n"; + printf("value: %.3f\n", value); + } + #endif + + if (z_model[i].name().str() == "x_pos-0") + { + poly_1_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-0") + { + poly_1_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-1") + { + poly_2_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-1") + { + poly_2_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-2") + { + poly_3_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-2") + { + poly_3_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-3") + { + poly_4_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-3") + { + poly_4_pos_y = value; + } + } + } + else + { + break; + } + } + #ifdef DEBUG + finish = clock(); + #endif + + REQUIRE(last_solvable_bounding_box_size > 0); + + #ifdef DEBUG + { + printf("Solvable bounding box: %d\n", last_solvable_bounding_box_size); + printf("Positions: %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f\n", poly_1_pos_x, + poly_1_pos_y, + poly_2_pos_x, + poly_2_pos_y, + poly_3_pos_x, + poly_3_pos_y, + poly_4_pos_x, + poly_4_pos_y); + } + #endif + + #ifdef DEBUG + { + for (int i = 0; i < 2; ++i) + { + double value = X_positions[i].as_double(); + printf("Orig X: %.3f\n", value); + + value = Y_positions[i].as_double(); + printf("Orig Y: %.3f\n", value); + } + } + #endif + + SVG preview_svg("polygon_test_10.svg"); + + Polygon display_polygon_1 = scale_UP(polygons[0], poly_1_pos_x, poly_1_pos_y); + Polygon display_polygon_2 = scale_UP(polygons[1], poly_2_pos_x, poly_2_pos_y); + Polygon display_polygon_3 = scale_UP(polygons[2], poly_3_pos_x, poly_3_pos_y); + Polygon display_polygon_4 = scale_UP(polygons[3], poly_4_pos_x, poly_4_pos_y); + + preview_svg.draw(display_polygon_1, "green"); + preview_svg.draw(display_polygon_2, "blue"); + preview_svg.draw(display_polygon_3, "red"); + preview_svg.draw(display_polygon_4, "grey"); + + preview_svg.Close(); + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 10 ... finished"); +} + + +TEST_CASE("Polygon test 11", "[Polygon]") +//void polygon_test_11(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 11 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + z3::expr_vector T1_parameters(z_context); + z3::expr_vector T2_parameters(z_context); + z3::expr_vector T3_parameters(z_context); + z3::expr_vector T4_parameters(z_context); + + for (int i = 0; i < 4; ++i) + { + string name = "x_pos-" + to_string(i); + #ifdef DEBUG + { + printf("i:%d\n", i); + printf("name: %s\n", name.c_str()); + } + #endif + X_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < 4; ++i) + { + string name = "y_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + Y_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_1.points.size(); ++i) + { + string name = "t1_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T1_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_2.points.size(); ++i) + { + string name = "t2_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T2_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_3.points.size(); ++i) + { + string name = "t3_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T3_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_4.points.size(); ++i) + { + string name = "t4_par-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T4_parameters.push_back(expr(z_context.real_const(name.c_str()))); + } + + z3::solver z_solver(z_context); + + vector polygons; + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + introduce_PolygonWeakNonoverlapping(z_solver, + z_context, + X_positions, + Y_positions, + polygons); + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + int last_solvable_bounding_box_size = -1; + double poly_1_pos_x, poly_1_pos_y, poly_2_pos_x, poly_2_pos_y, poly_3_pos_x, poly_3_pos_y, poly_4_pos_x, poly_4_pos_y; + poly_1_pos_x = poly_1_pos_y = poly_2_pos_x = poly_2_pos_y = poly_3_pos_x = poly_3_pos_y = poly_4_pos_x = poly_4_pos_y = 0.0; + + for (int bounding_box_size = 200; bounding_box_size > 10; bounding_box_size -= 4) + { + #ifdef DEBUG + { + printf("BB: %d\n", bounding_box_size); + } + #endif + z3::expr_vector bounding_box_assumptions(z_context); + + assume_BedBoundingBox(X_positions[0], Y_positions[0], polygons[0], bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[1], Y_positions[1], polygons[1], bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[2], Y_positions[2], polygons[2], bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[3], Y_positions[3], polygons[3], bounding_box_size, bounding_box_size, bounding_box_assumptions); + + bool sat = false; + + switch (z_solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + sat = true; + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + sat = false; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + #ifdef DEBUG + { + printf("Printing interpretation:\n"); + } + #endif + for (unsigned int i = 0; i < z_model.size(); ++i) + { + double value = z_model.get_const_interp(z_model[i]).as_double(); + + #ifdef DEBUG + { + printf("Variable:%s ", z_model[i].name().str().c_str()); + cout << z_model.get_const_interp(z_model[i]).as_double() << "\n"; + printf("value: %.3f\n", value); + } + #endif + + if (z_model[i].name().str() == "x_pos-0") + { + poly_1_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-0") + { + poly_1_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-1") + { + poly_2_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-1") + { + poly_2_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-2") + { + poly_3_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-2") + { + poly_3_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-3") + { + poly_4_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-3") + { + poly_4_pos_y = value; + } + } + + #ifdef DEBUG + { + printf("preRefined positions: %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f\n", poly_1_pos_x, + poly_1_pos_y, + poly_2_pos_x, + poly_2_pos_y, + poly_3_pos_x, + poly_3_pos_y, + poly_4_pos_x, + poly_4_pos_y); + } + #endif + + while (true) + { + vector dec_values_X; + dec_values_X.push_back(poly_1_pos_x); + dec_values_X.push_back(poly_2_pos_x); + dec_values_X.push_back(poly_3_pos_x); + dec_values_X.push_back(poly_4_pos_x); + + vector dec_values_Y; + dec_values_Y.push_back(poly_1_pos_y); + dec_values_Y.push_back(poly_2_pos_y); + dec_values_Y.push_back(poly_3_pos_y); + dec_values_Y.push_back(poly_4_pos_y); + + bool refined = refine_PolygonWeakNonoverlapping(z_solver, + z_context, + X_positions, + Y_positions, + dec_values_X, + dec_values_Y, + polygons); + + bool refined_sat = false; + + if (refined) + { + switch (z_solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + #ifdef DEBUG + { + printf(" sat\n"); + } + #endif + refined_sat = true; + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" unsat\n"); + } + #endif + refined_sat = false; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" unknown\n"); + } + #endif + break; + } + default: + { + break; + } + } + + if (refined_sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + for (unsigned int i = 0; i < z_model.size(); ++i) + { + double value = z_model.get_const_interp(z_model[i]).as_double(); + + if (z_model[i].name().str() == "x_pos-0") + { + poly_1_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-0") + { + poly_1_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-1") + { + poly_2_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-1") + { + poly_2_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-2") + { + poly_3_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-2") + { + poly_3_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-3") + { + poly_4_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-3") + { + poly_4_pos_y = value; + } + } + #ifdef DEBUG + { + printf("Refined positions: %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f\n", poly_1_pos_x, + poly_1_pos_y, + poly_2_pos_x, + poly_2_pos_y, + poly_3_pos_x, + poly_3_pos_y, + poly_4_pos_x, + poly_4_pos_y); + } + #endif + } + else + { + break; + } + } + else + { + last_solvable_bounding_box_size = bounding_box_size; + break; + } + } + } + else + { + break; + } + } + #ifdef DEBUG + finish = clock(); + #endif + + REQUIRE(last_solvable_bounding_box_size > 0); + + #ifdef DEBUG + { + printf("Solvable bounding box: %d\n", last_solvable_bounding_box_size); + printf("Positions: %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f\n", poly_1_pos_x, + poly_1_pos_y, + poly_2_pos_x, + poly_2_pos_y, + poly_3_pos_x, + poly_3_pos_y, + poly_4_pos_x, + poly_4_pos_y); + } + #endif + + #ifdef DEBUG + { + for (int i = 0; i < 2; ++i) + { + double value = X_positions[i].as_double(); + printf("Orig X: %.3f\n", value); + + value = Y_positions[i].as_double(); + printf("Orig Y: %.3f\n", value); + } + } + #endif + + SVG preview_svg("polygon_test_11.svg"); + + Polygon display_polygon_1 = scale_UP(polygons[0], poly_1_pos_x, poly_1_pos_y); + Polygon display_polygon_2 = scale_UP(polygons[1], poly_2_pos_x, poly_2_pos_y); + Polygon display_polygon_3 = scale_UP(polygons[2], poly_3_pos_x, poly_3_pos_y); + Polygon display_polygon_4 = scale_UP(polygons[3], poly_4_pos_x, poly_4_pos_y); + + preview_svg.draw(display_polygon_1, "green"); + preview_svg.draw(display_polygon_2, "blue"); + preview_svg.draw(display_polygon_3, "red"); + preview_svg.draw(display_polygon_4, "grey"); + + preview_svg.Close(); + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 11 ... finished"); +} + + +TEST_CASE("Polygon test 12", "[Polygon]") +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 12 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE, SEQ_QIDI_MK3S_Y_SIZE}); + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + + std::vector X_values; + std::vector Y_values; + + string_map dec_var_names_map; + + z3::solver z_solver(z_context); + + vector polygons; + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + build_WeakPolygonNonoverlapping(z_solver, z_context, polygons, X_positions, Y_positions, X_values, Y_values, dec_var_names_map); + + bool optimized = optimize_WeakPolygonNonoverlapping(z_solver, + z_context, + solver_configuration, + X_positions, + Y_positions, + X_values, + Y_values, + dec_var_names_map, + polygons); + + #ifdef DEBUG + finish = clock(); + #endif + REQUIRE(optimized); + + if (optimized) + { + #ifdef DEBUG + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < polygons.size(); ++i) + { + printf(" %.3f, %.3f\n", X_values[i], Y_values[i]); + } + } + #endif + + SVG preview_svg("polygon_test_12.svg"); + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + Polygon display_polygon = scale_UP(polygons[i], X_values[i], Y_values[i]); + + string color; + + switch(i) + { + case 0: + { + color = "green"; + break; + } + case 1: + { + color = "blue"; + break; + } + case 2: + { + color = "red"; + break; + } + case 3: + { + color = "grey"; + break; + } + case 4: + { + color = "cyan"; + break; + } + case 5: + { + color = "magenta"; + break; + } + default: + { + break; + } + } + + preview_svg.draw(display_polygon, color); + } + + preview_svg.Close(); + } + else + { + #ifdef DEBUG + { + printf("Polygon optimization FAILED.\n"); + } + #endif + } + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 12 ... finished"); +} + + +//TEST_CASE("Polygon test 13", "[Polygon]") +void polygon_test_13(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 13 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE, SEQ_QIDI_MK3S_Y_SIZE}); + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + + std::vector X_values; + std::vector Y_values; + + string_map dec_var_names_map; + + Z3_global_param_set("timeout", "8000"); + + z3::solver z_solver(z_context); + + vector polygons; + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + build_WeakPolygonNonoverlapping(z_solver, z_context, polygons, X_positions, Y_positions, X_values, Y_values, dec_var_names_map); + + bool optimized = optimize_WeakPolygonNonoverlapping(z_solver, + z_context, + solver_configuration, + X_positions, + Y_positions, + X_values, + Y_values, + dec_var_names_map, + polygons); + + #ifdef DEBUG + finish = clock(); + #endif + + REQUIRE(optimized); + + if (optimized) + { + #ifdef DEBUG + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < polygons.size(); ++i) + { + printf(" %.3f, %.3f\n", X_values[i], Y_values[i]); + } + } + #endif + + SVG preview_svg("polygon_test_13.svg"); + + for (unsigned int i = 0; i < polygons.size(); ++i) + { + Polygon display_polygon = scale_UP(polygons[i], X_values[i], Y_values[i]); + + string color; + + switch(i) + { + case 0: + { + color = "green"; + break; + } + case 1: + { + color = "blue"; + break; + } + case 2: + { + color = "red"; + break; + } + case 3: + { + color = "grey"; + break; + } + case 4: + { + color = "cyan"; + break; + } + case 5: + { + color = "magenta"; + break; + } + case 6: + { + color = "yellow"; + break; + } + case 7: + { + color = "black"; + break; + } + case 8: + { + color = "indigo"; + break; + } + case 9: + { + color = "olive"; + break; + } + case 10: + { + color = "aqua"; + break; + } + case 11: + { + color = "violet"; + break; + } + default: + { + break; + } + } + + preview_svg.draw(display_polygon, color); + } + + preview_svg.Close(); + } + else + { + #ifdef DEBUG + { + printf("Polygon optimization FAILED.\n"); + } + #endif + } + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 13 ... finished"); +} + + +TEST_CASE("Polygon test 14", "[Polygon]") +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 14 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE, SEQ_QIDI_MK3S_Y_SIZE}); + + vector polygons; + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + vector decided; + vector undecided; + + vector poly_positions_X; + vector poly_positions_Y; + poly_positions_X.resize(polygons.size()); + poly_positions_Y.resize(polygons.size()); + + bool optimized; + { + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + + vector X_values; + vector Y_values; + + string_map dec_var_names_map; + + z3::solver z_solver(z_context); + + X_values.resize(polygons.size()); + Y_values.resize(polygons.size()); + + undecided.push_back(0); + undecided.push_back(1); + undecided.push_back(2); + undecided.push_back(3); + + build_WeakPolygonNonoverlapping(z_solver, + z_context, + polygons, + X_positions, + Y_positions, + X_values, + Y_values, + decided, + undecided, + dec_var_names_map); + + optimized = optimize_WeakPolygonNonoverlapping(z_solver, + z_context, + solver_configuration, + X_positions, + Y_positions, + X_values, + Y_values, + decided, + undecided, + dec_var_names_map, + polygons); + + for (unsigned int i = 0; i < undecided.size(); ++i) + { + poly_positions_X[undecided[i]] = X_values[undecided[i]]; + poly_positions_Y[undecided[i]] = Y_values[undecided[i]]; + } + + #ifdef DEBUG + { + printf("Optimized 1: %d\n", optimized); + } + #endif + } + + { + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + + vector X_values; + vector Y_values; + + string_map dec_var_names_map; + + z3::solver z_solver(z_context); + + X_values.resize(polygons.size()); + Y_values.resize(polygons.size()); + + decided.push_back(0); + decided.push_back(1); + decided.push_back(2); + decided.push_back(3); + + for (unsigned int i = 0; i < decided.size(); ++i) + { + X_values[decided[i]] = poly_positions_X[decided[i]]; + Y_values[decided[i]] = poly_positions_Y[decided[i]]; + } + + undecided.clear(); + undecided.push_back(4); + undecided.push_back(5); + undecided.push_back(6); + undecided.push_back(7); + + build_WeakPolygonNonoverlapping(z_solver, + z_context, + polygons, + X_positions, + Y_positions, + X_values, + Y_values, + decided, + undecided, + dec_var_names_map); + + optimized = optimize_WeakPolygonNonoverlapping(z_solver, + z_context, + solver_configuration, + X_positions, + Y_positions, + X_values, + Y_values, + decided, + undecided, + dec_var_names_map, + polygons); + + #ifdef DEBUG + { + printf("Optimized 2: %d\n", optimized); + } + #endif + + decided.push_back(4); + decided.push_back(5); + decided.push_back(6); + decided.push_back(7); + + #ifdef DEBUG + finish = clock(); + #endif + + if (optimized) + { + #ifdef DEBUG + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < decided.size(); ++i) + { + printf(" %.3f, %.3f\n", X_values[decided[i]].as_double(), Y_values[decided[i]].as_double()); + } + } + #endif + + SVG preview_svg("polygon_test_14.svg"); + + for (unsigned int i = 0; i < decided.size(); ++i) + { + Polygon display_polygon = scale_UP(polygons[decided[i]], X_values[decided[i]].as_double(), Y_values[decided[i]].as_double()); + + string color; + + switch(i) + { + case 0: + { + color = "green"; + break; + } + case 1: + { + color = "blue"; + break; + } + case 2: + { + color = "red"; + break; + } + case 3: + { + color = "grey"; + break; + } + case 4: + { + color = "cyan"; + break; + } + case 5: + { + color = "magenta"; + break; + } + case 6: + { + color = "yellow"; + break; + } + case 7: + { + color = "black"; + break; + } + case 8: + { + color = "indigo"; + break; + } + case 9: + { + color = "olive"; + break; + } + case 10: + { + color = "aqua"; + break; + } + case 11: + { + color = "violet"; + break; + } + default: + { + break; + } + } + + preview_svg.draw(display_polygon, color); + } + + preview_svg.Close(); + } + else + { + #ifdef DEBUG + { + printf("Polygon optimization FAILED.\n"); + } + #endif + } + + REQUIRE(optimized); + } + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 14 ... finished"); +} + + +TEST_CASE("Polygon test 15", "[Polygon]") +//void polygon_test_15(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 15 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE, SEQ_QIDI_MK3S_Y_SIZE}); + + vector polygons; + vector remaining_polygons; + vector polygon_index_map; + vector decided_polygons; + + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + + for (unsigned int index = 0; index < polygons.size(); ++index) + { + polygon_index_map.push_back(index); + } + + vector poly_positions_X; + vector poly_positions_Y; + + do + { + decided_polygons.clear(); + remaining_polygons.clear(); + + bool optimized = optimize_SubglobalPolygonNonoverlapping(solver_configuration, + poly_positions_X, + poly_positions_Y, + polygons, + polygon_index_map, + decided_polygons, + remaining_polygons); + + if (optimized) + { + #ifdef DEBUG + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + printf(" %.3f, %.3f\n", poly_positions_X[decided_polygons[i]].as_double(), poly_positions_Y[decided_polygons[i]].as_double()); + } + printf("Remaining polygons: %ld\n", remaining_polygons.size()); + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + printf(" %d\n", remaining_polygons[i]); + } + } + #endif + + SVG preview_svg("polygon_test_15.svg"); + + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + Polygon display_polygon = scale_UP(polygons[decided_polygons[i]], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double()); + + string color; + + switch(i) + { + case 0: + { + color = "green"; + break; + } + case 1: + { + color = "blue"; + break; + } + case 2: + { + color = "red"; + break; + } + case 3: + { + color = "grey"; + break; + } + case 4: + { + color = "cyan"; + break; + } + case 5: + { + color = "magenta"; + break; + } + case 6: + { + color = "yellow"; + break; + } + case 7: + { + color = "black"; + break; + } + case 8: + { + color = "indigo"; + break; + } + case 9: + { + color = "olive"; + break; + } + case 10: + { + color = "aqua"; + break; + } + case 11: + { + color = "violet"; + break; + } + default: + { + break; + } + } + + preview_svg.draw(display_polygon, color); + } + + preview_svg.Close(); + } + else + { + #ifdef DEBUG + { + printf("Polygon optimization FAILED.\n"); + } + #endif + } + REQUIRE(optimized); + + vector next_polygons; + + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + next_polygons.push_back(polygons[remaining_polygons[i]]); + } + + polygon_index_map = remaining_polygons; + polygons.clear(); + polygons = next_polygons; + } + while (!remaining_polygons.empty()); + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 15 ... finished"); +} + + +TEST_CASE("Polygon test 16", "[Polygon]") +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 16 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE, SEQ_QIDI_MK3S_Y_SIZE}); + + vector polygons; + + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + double area = calc_PolygonUnreachableZoneArea(polygon_1, polygons); + REQUIRE(area > 0.0); + #ifdef DEBUG + { + printf("Polygons area: %.3f\n", area); + } + #endif + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing polygon 16 ... finished"); +} + + + +/*----------------------------------------------------------------*/ diff --git a/src/libseqarrange/test/seq_test_polygon.hpp b/src/libseqarrange/test/seq_test_polygon.hpp new file mode 100644 index 0000000..372744c --- /dev/null +++ b/src/libseqarrange/test/seq_test_polygon.hpp @@ -0,0 +1,7 @@ +#ifndef __SEQ_TEST_POLYGON_HPP__ +#define __SEQ_TEST_POLYGON_HPP__ + +/*----------------------------------------------------------------*/ + + +#endif /* __SEQ_TEST_POLYGON_HPP__ */ diff --git a/src/libseqarrange/test/seq_test_preprocess.cpp b/src/libseqarrange/test/seq_test_preprocess.cpp new file mode 100644 index 0000000..62f550f --- /dev/null +++ b/src/libseqarrange/test/seq_test_preprocess.cpp @@ -0,0 +1,1243 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Geometry/ConvexHull.hpp" +#include "libslic3r/SVG.hpp" + +#include + +#include "qidiparts.hpp" + +#include "seq_defs.hpp" + +#include "seq_sequential.hpp" +#include "seq_preprocess.hpp" + +#include "seq_test_sequential.hpp" + + +/*----------------------------------------------------------------*/ + +using namespace z3; + +using namespace Slic3r; +using namespace Slic3r::Geometry; + +using namespace Sequential; + + +#define SCALE_FACTOR 50000.0 + + +/*----------------------------------------------------------------*/ + +const coord_t SEQ_QIDI_MK3S_X_SIZE = 250000000; +const coord_t SEQ_QIDI_MK3S_Y_SIZE = 210000000; + +/*----------------------------------------------------------------*/ + +/* +static Polygon scale_UP(const Polygon &polygon) +{ + Polygon poly = polygon; + + for (unsigned int i = 0; i < poly.points.size(); ++i) + { + poly.points[i] = Point(poly.points[i].x() * SCALE_FACTOR, poly.points[i].y() * SCALE_FACTOR); + } + + return poly; +} +*/ + +static Polygon scale_UP(const Polygon &polygon, double x_pos, double y_pos) +{ + Polygon poly = polygon; + + for (unsigned int i = 0; i < poly.points.size(); ++i) + { + poly.points[i] = Point(poly.points[i].x() * SCALE_FACTOR + x_pos * SCALE_FACTOR, + poly.points[i].y() * SCALE_FACTOR + y_pos * SCALE_FACTOR); + } + + return poly; +} + + +std::vector test_polygons; + +TEST_CASE("Preprocessing test 1", "[Sequential Arrangement Preprocessing]") +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing preprocessing 1 ..."); + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE / SEQ_SLICER_SCALE_FACTOR, SEQ_QIDI_MK3S_Y_SIZE / SEQ_SLICER_SCALE_FACTOR}); + #ifdef DEBUG + start = clock(); + #endif + for (unsigned int i = 0; i < QIDI_PART_POLYGONS.size(); ++i) + { + Polygon scale_down_polygon; + scaleDown_PolygonForSequentialSolver(QIDI_PART_POLYGONS[i], scale_down_polygon); + test_polygons.push_back(scale_down_polygon); + } + REQUIRE(!test_polygons.empty()); + + for (unsigned int i = 0; i < test_polygons.size(); ++i) + { + SVG preview_svg("preprocess_test_1.svg"); + Polygon display_polygon = scale_UP(test_polygons[i], 1000, 1000); + preview_svg.draw(display_polygon, "blue"); + preview_svg.Close(); + } + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing preprocessing 1 ... finished"); +} + + +//TEST_CASE("Preprocessing test 2", "[Sequential Arrangement Preprocessing]") +void preprocessing_test_2(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing preprocess 2 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE / SEQ_SLICER_SCALE_FACTOR, SEQ_QIDI_MK3S_Y_SIZE / SEQ_SLICER_SCALE_FACTOR}); + + vector polygons; + vector unreachable_polygons; + + for (unsigned int i = 0; i < 8 /*QIDI_PART_POLYGONS.size()*/; ++i) + { + Polygon scale_down_polygon; + scaleDown_PolygonForSequentialSolver(QIDI_PART_POLYGONS[i], scale_down_polygon); + scale_down_polygon.make_counter_clockwise(); + polygons.push_back(scale_down_polygon); + unreachable_polygons.push_back(scale_down_polygon); + } + + vector remaining_polygons; + vector polygon_index_map; + vector decided_polygons; + + for (unsigned int index = 0; index < polygons.size(); ++index) + { + polygon_index_map.push_back(index); + } + + vector poly_positions_X; + vector poly_positions_Y; + vector times_T; + + do + { + decided_polygons.clear(); + remaining_polygons.clear(); + + bool optimized = optimize_SubglobalSequentialPolygonNonoverlappingBinaryCentered(solver_configuration, + poly_positions_X, + poly_positions_Y, + times_T, + polygons, + unreachable_polygons, + polygon_index_map, + decided_polygons, + remaining_polygons); + + #ifdef DEBUG + { + printf("----> Optimization finished <----\n"); + } + #endif + REQUIRE(optimized); + + if (optimized) + { + #ifdef DEBUG + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + printf(" [%d] %.3f, %.3f (%.3f)\n", decided_polygons[i], poly_positions_X[decided_polygons[i]].as_double(), poly_positions_Y[decided_polygons[i]].as_double(), times_T[decided_polygons[i]].as_double()); + } + printf("Remaining polygons: %ld\n", remaining_polygons.size()); + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + printf(" %d\n", remaining_polygons[i]); + } + } + #endif + + SVG preview_svg("preprocess_test_2.svg"); + + if (!unreachable_polygons.empty()) + { + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + #ifdef DEBUG + { + printf("----> %.3f,%.3f\n", poly_positions_X[decided_polygons[i]].as_double(), poly_positions_Y[decided_polygons[i]].as_double()); + for (unsigned int k = 0; k < polygons[decided_polygons[i]].points.size(); ++k) + { + printf(" xy: %d, %d\n", polygons[decided_polygons[i]].points[k].x(), polygons[decided_polygons[i]].points[k].y()); + } + } + #endif + + #ifdef DEBUG + { + for (unsigned int k = 0; k < unreachable_polygons[decided_polygons[i]].points.size(); ++k) + { + printf(" Pxy: %d, %d\n", unreachable_polygons[decided_polygons[i]].points[k].x(), unreachable_polygons[decided_polygons[i]].points[k].y()); + } + } + #endif + + Polygon display_unreachable_polygon = scale_UP(unreachable_polygons[decided_polygons[i]], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double()); + preview_svg.draw(display_unreachable_polygon, "lightgrey"); + } + } + + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + Polygon display_polygon = scale_UP(polygons[decided_polygons[i]], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double()); + + string color; + + switch(i) + { + case 0: + { + color = "green"; + break; + } + case 1: + { + color = "blue"; + break; + } + case 2: + { + color = "red"; + break; + } + case 3: + { + color = "grey"; + break; + } + case 4: + { + color = "cyan"; + break; + } + case 5: + { + color = "magenta"; + break; + } + case 6: + { + color = "yellow"; + break; + } + case 7: + { + color = "black"; + break; + } + case 8: + { + color = "indigo"; + break; + } + case 9: + { + color = "olive"; + break; + } + case 10: + { + color = "aqua"; + break; + } + case 11: + { + color = "violet"; + break; + } + default: + { + break; + } + } + + preview_svg.draw(display_polygon, color); + } + + preview_svg.Close(); + } + else + { + #ifdef DEBUG + { + printf("Polygon optimization FAILED.\n"); + } + #endif + } + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Intermediate time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + vector next_polygons; + vector next_unreachable_polygons; + + #ifdef DEBUG + { + for (unsigned int i = 0; i < polygon_index_map.size(); ++i) + { + printf(" %d\n", polygon_index_map[i]); + } + } + #endif + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + next_polygons.push_back(polygons[remaining_polygons[i]]); + next_unreachable_polygons.push_back(unreachable_polygons[remaining_polygons[i]]); + } + + polygons.clear(); + unreachable_polygons.clear(); + polygon_index_map.clear(); + + polygons = next_polygons; + unreachable_polygons = next_unreachable_polygons; + + for (unsigned int index = 0; index < polygons.size(); ++index) + { + polygon_index_map.push_back(index); + } + } + while (!remaining_polygons.empty()); + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing preprocess 2 ... finished"); +} + + +TEST_CASE("Preprocessing test 3", "[Sequential Arrangement Preprocessing]") +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE / SEQ_SLICER_SCALE_FACTOR, SEQ_QIDI_MK3S_Y_SIZE / SEQ_SLICER_SCALE_FACTOR}); + + INFO("Testing preprocessing 3 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + std::vector nozzle_unreachable_polygons; + std::vector extruder_unreachable_polygons; + std::vector hose_unreachable_polygons; + std::vector gantry_unreachable_polygons; + + for (unsigned int p = 0; p < QIDI_PART_POLYGONS.size(); ++p) + { + { + nozzle_unreachable_polygons.clear(); + + extend_PolygonConvexUnreachableZone(solver_configuration, + QIDI_PART_POLYGONS[p], + SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK3S, + nozzle_unreachable_polygons); + REQUIRE(nozzle_unreachable_polygons.size() > 0); + + SVG preview_svg("preprocess_test_3.svg"); + + for (unsigned int j = 0; j < SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK3S.size(); ++j) + { + preview_svg.draw(SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK3S[j], "lightgrey"); + } + + if (!nozzle_unreachable_polygons.empty()) + { + for (unsigned int j = 0; j < nozzle_unreachable_polygons.size(); ++j) + { + preview_svg.draw(nozzle_unreachable_polygons[j], "lightgrey"); + } + } + preview_svg.draw(QIDI_PART_POLYGONS[p], "blue"); + + preview_svg.Close(); + } + + { + nozzle_unreachable_polygons.clear(); + + extend_PolygonBoxUnreachableZone(solver_configuration, + QIDI_PART_POLYGONS[p], + SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK3S, + nozzle_unreachable_polygons); + REQUIRE(nozzle_unreachable_polygons.size() > 0); + + SVG preview_svg("preprocess_test_3.svg"); + + for (unsigned int j = 0; j < SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK3S.size(); ++j) + { + preview_svg.draw(SEQ_UNREACHABLE_POLYGON_NOZZLE_LEVEL_MK3S[j], "lightgrey"); + } + + if (!nozzle_unreachable_polygons.empty()) + { + for (unsigned int j = 0; j < nozzle_unreachable_polygons.size(); ++j) + { + preview_svg.draw(nozzle_unreachable_polygons[j], "lightgrey"); + } + } + preview_svg.draw(QIDI_PART_POLYGONS[p], "red"); + + preview_svg.Close(); + } + + { + extruder_unreachable_polygons.clear(); + + extend_PolygonConvexUnreachableZone(solver_configuration, + QIDI_PART_POLYGONS[p], + SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK3S, + extruder_unreachable_polygons); + REQUIRE(extruder_unreachable_polygons.size() > 0); + + SVG preview_svg("preprocess_test_3.svg"); + + for (unsigned int j = 0; j < SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK3S.size(); ++j) + { + preview_svg.draw(SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK3S[j], "lightgrey"); + } + + if (!extruder_unreachable_polygons.empty()) + { + for (unsigned int j = 0; j < extruder_unreachable_polygons.size(); ++j) + { + preview_svg.draw(extruder_unreachable_polygons[j], "lightgrey"); + } + } + preview_svg.draw(QIDI_PART_POLYGONS[p], "green"); + + preview_svg.Close(); + } + + { + extruder_unreachable_polygons.clear(); + + extend_PolygonBoxUnreachableZone(solver_configuration, + QIDI_PART_POLYGONS[p], + SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK3S, + extruder_unreachable_polygons); + REQUIRE(extruder_unreachable_polygons.size() > 0); + + SVG preview_svg("preprocess_test_3.svg"); + + for (unsigned int j = 0; j < SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK3S.size(); ++j) + { + preview_svg.draw(SEQ_UNREACHABLE_POLYGON_EXTRUDER_LEVEL_MK3S[j], "lightgrey"); + } + + if (!extruder_unreachable_polygons.empty()) + { + for (unsigned int j = 0; j < extruder_unreachable_polygons.size(); ++j) + { + preview_svg.draw(extruder_unreachable_polygons[j], "lightgrey"); + } + } + preview_svg.draw(QIDI_PART_POLYGONS[p], "magenta"); + + preview_svg.Close(); + } + + { + hose_unreachable_polygons.clear(); + + extend_PolygonConvexUnreachableZone(solver_configuration, + QIDI_PART_POLYGONS[p], + SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK3S, + hose_unreachable_polygons); + REQUIRE(hose_unreachable_polygons.size() > 0); + + SVG preview_svg("preprocess_test_3.svg"); + + for (unsigned int j = 0; j < SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK3S.size(); ++j) + { + preview_svg.draw(SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK3S[j], "lightgrey"); + } + + if (!hose_unreachable_polygons.empty()) + { + for (unsigned int j = 0; j < hose_unreachable_polygons.size(); ++j) + { + preview_svg.draw(hose_unreachable_polygons[j], "lightgrey"); + } + } + preview_svg.draw(QIDI_PART_POLYGONS[p], "yellow"); + + preview_svg.Close(); + } + + { + hose_unreachable_polygons.clear(); + + extend_PolygonBoxUnreachableZone(solver_configuration, + QIDI_PART_POLYGONS[p], + SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK3S, + hose_unreachable_polygons); + REQUIRE(hose_unreachable_polygons.size() > 0); + + SVG preview_svg("preprocess_test_3.svg"); + + for (unsigned int j = 0; j < SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK3S.size(); ++j) + { + preview_svg.draw(SEQ_UNREACHABLE_POLYGON_HOSE_LEVEL_MK3S[j], "lightgrey"); + } + + if (!hose_unreachable_polygons.empty()) + { + for (unsigned int j = 0; j < hose_unreachable_polygons.size(); ++j) + { + preview_svg.draw(hose_unreachable_polygons[j], "lightgrey"); + } + } + preview_svg.draw(QIDI_PART_POLYGONS[p], "orange"); + + preview_svg.Close(); + } + + { + gantry_unreachable_polygons.clear(); + + extend_PolygonConvexUnreachableZone(solver_configuration, + QIDI_PART_POLYGONS[p], + SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK3S, + gantry_unreachable_polygons); + REQUIRE(gantry_unreachable_polygons.size() > 0); + + SVG preview_svg("preprocess_test_3.svg"); + + for (unsigned int j = 0; j < SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK3S.size(); ++j) + { + preview_svg.draw(SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK3S[j], "lightgrey"); + } + + if (!gantry_unreachable_polygons.empty()) + { + for (unsigned int j = 0; j < gantry_unreachable_polygons.size(); ++j) + { + preview_svg.draw(gantry_unreachable_polygons[j], "lightgrey"); + } + } + preview_svg.draw(QIDI_PART_POLYGONS[p], "grey"); + + preview_svg.Close(); + } + + { + gantry_unreachable_polygons.clear(); + + extend_PolygonBoxUnreachableZone(solver_configuration, + QIDI_PART_POLYGONS[p], + SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK3S, + gantry_unreachable_polygons); + REQUIRE(gantry_unreachable_polygons.size() > 0); + + SVG preview_svg("preprocess_test_3.svg"); + + for (unsigned int j = 0; j < SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK3S.size(); ++j) + { + preview_svg.draw(SEQ_UNREACHABLE_POLYGON_GANTRY_LEVEL_MK3S[j], "lightgrey"); + } + + if (!gantry_unreachable_polygons.empty()) + { + for (unsigned int j = 0; j < gantry_unreachable_polygons.size(); ++j) + { + preview_svg.draw(gantry_unreachable_polygons[j], "lightgrey"); + } + } + preview_svg.draw(QIDI_PART_POLYGONS[p], "black"); + + preview_svg.Close(); + } + } + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing preprocess 3 ... finished"); +} + + +//TEST_CASE("Preprocessing test 4", "[Sequential Arrangement Preprocessing]") +void preprocessing_test_4(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing preprocess 4 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE / SEQ_SLICER_SCALE_FACTOR, SEQ_QIDI_MK3S_Y_SIZE / SEQ_SLICER_SCALE_FACTOR}); + + std::vector polygons; + std::vector > unreachable_polygons; + + for (int i = 0; i < 12; ++i) + { + Polygon scale_down_polygon; + scaleDown_PolygonForSequentialSolver(QIDI_PART_POLYGONS[i], scale_down_polygon); + polygons.push_back(scale_down_polygon); + + std::vector convex_level_polygons; + convex_level_polygons.push_back(QIDI_PART_POLYGONS[i]); + convex_level_polygons.push_back(QIDI_PART_POLYGONS[i]); + std::vector box_level_polygons; + box_level_polygons.push_back(QIDI_PART_POLYGONS[i]); + box_level_polygons.push_back(QIDI_PART_POLYGONS[i]); + + std::vector scale_down_unreachable_polygons; + prepare_UnreachableZonePolygons(solver_configuration, + convex_level_polygons, + box_level_polygons, + SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_MK3S, + SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_MK3S, + scale_down_unreachable_polygons); + unreachable_polygons.push_back(scale_down_unreachable_polygons); + } + + vector remaining_polygons; + vector polygon_index_map; + vector decided_polygons; + + for (unsigned int index = 0; index < polygons.size(); ++index) + { + polygon_index_map.push_back(index); + } + + vector poly_positions_X; + vector poly_positions_Y; + vector times_T; + + do + { + decided_polygons.clear(); + remaining_polygons.clear(); + + bool optimized = optimize_SubglobalSequentialPolygonNonoverlappingBinaryCentered(solver_configuration, + poly_positions_X, + poly_positions_Y, + times_T, + polygons, + unreachable_polygons, + polygon_index_map, + decided_polygons, + remaining_polygons); + + #ifdef DEBUG + { + printf("----> Optimization finished <----\n"); + } + #endif + REQUIRE(optimized); + + if (optimized) + { + #ifdef DEBUG + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + printf(" [%d] %.3f, %.3f (%.3f)\n", decided_polygons[i], poly_positions_X[decided_polygons[i]].as_double(), poly_positions_Y[decided_polygons[i]].as_double(), times_T[decided_polygons[i]].as_double()); + } + printf("Remaining polygons: %ld\n", remaining_polygons.size()); + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + printf(" %d\n", remaining_polygons[i]); + } + } + #endif + + SVG preview_svg("preprocess_test_4.svg"); + + if (!unreachable_polygons.empty()) + { + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + #ifdef DEBUG + { + printf("----> %.3f,%.3f\n", poly_positions_X[decided_polygons[i]].as_double(), poly_positions_Y[decided_polygons[i]].as_double()); + for (unsigned int k = 0; k < polygons[decided_polygons[i]].points.size(); ++k) + { + printf(" xy: %d, %d\n", polygons[decided_polygons[i]].points[k].x(), polygons[decided_polygons[i]].points[k].y()); + } + } + #endif + + for (unsigned int j = 0; j < unreachable_polygons[decided_polygons[i]].size(); ++j) + { + #ifdef DEBUG + { + for (unsigned int k = 0; k < unreachable_polygons[decided_polygons[i]][j].points.size(); ++k) + { + printf(" Pxy: %d, %d\n", unreachable_polygons[decided_polygons[i]][j].points[k].x(), unreachable_polygons[decided_polygons[i]][j].points[k].y()); + } + } + #endif + + Polygon display_unreachable_polygon = scale_UP(unreachable_polygons[decided_polygons[i]][j], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double()); + preview_svg.draw(display_unreachable_polygon, "lightgrey"); + } + } + } + + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + Polygon display_polygon = scale_UP(polygons[decided_polygons[i]], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double()); + string color; + + switch(i) + { + case 0: + { + color = "green"; + break; + } + case 1: + { + color = "blue"; + break; + } + case 2: + { + color = "red"; + break; + } + case 3: + { + color = "grey"; + break; + } + case 4: + { + color = "cyan"; + break; + } + case 5: + { + color = "magenta"; + break; + } + case 6: + { + color = "yellow"; + break; + } + case 7: + { + color = "black"; + break; + } + case 8: + { + color = "indigo"; + break; + } + case 9: + { + color = "olive"; + break; + } + case 10: + { + color = "aqua"; + break; + } + case 11: + { + color = "violet"; + break; + } + default: + { + break; + } + } + + preview_svg.draw(display_polygon, color); + } + preview_svg.Close(); + } + else + { + #ifdef DEBUG + { + printf("Polygon optimization FAILED.\n"); + } + #endif + } + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Intermediate time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + vector next_polygons; + vector > next_unreachable_polygons; + + #ifdef DEBUG + { + for (unsigned int i = 0; i < polygon_index_map.size(); ++i) + { + printf(" %d\n", polygon_index_map[i]); + } + } + #endif + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + next_polygons.push_back(polygons[remaining_polygons[i]]); + next_unreachable_polygons.push_back(unreachable_polygons[remaining_polygons[i]]); + } + + polygons.clear(); + unreachable_polygons.clear(); + polygon_index_map.clear(); + + polygons = next_polygons; + unreachable_polygons = next_unreachable_polygons; + + for (unsigned int index = 0; index < polygons.size(); ++index) + { + polygon_index_map.push_back(index); + } + } + while (!remaining_polygons.empty()); + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing preprocess 4 ... finished"); +} + + +TEST_CASE("Preprocessing test 5", "[Sequential Arrangement Preprocessing]") +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing preprocess 5 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE / SEQ_SLICER_SCALE_FACTOR, SEQ_QIDI_MK3S_Y_SIZE / SEQ_SLICER_SCALE_FACTOR}); + + std::vector polygons; + std::vector > unreachable_polygons; + + for (unsigned int i = 0; i < QIDI_PART_POLYGONS.size(); ++i) + { + Polygon simplified_polygon, scale_down_polygon; + + decimate_PolygonForSequentialSolver(solver_configuration, + QIDI_PART_POLYGONS[i], + simplified_polygon, + false); + REQUIRE(simplified_polygon.size() > 0); + + std::vector convex_level_polygons; + convex_level_polygons.push_back(QIDI_PART_POLYGONS[i]); + convex_level_polygons.push_back(QIDI_PART_POLYGONS[i]); + std::vector box_level_polygons; + box_level_polygons.push_back(QIDI_PART_POLYGONS[i]); + box_level_polygons.push_back(QIDI_PART_POLYGONS[i]); + + std::vector scale_down_unreachable_polygons; + prepare_UnreachableZonePolygons(solver_configuration, + convex_level_polygons, + box_level_polygons, + SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_MK3S, + SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_MK3S, + scale_down_unreachable_polygons); + REQUIRE(scale_down_unreachable_polygons.size() > 0); + unreachable_polygons.push_back(scale_down_unreachable_polygons); + + SVG preview_svg("preprocess_test_5.svg"); + + preview_svg.draw(simplified_polygon, "lightgrey"); + preview_svg.draw(QIDI_PART_POLYGONS[i], "blue"); + + preview_svg.Close(); + } + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing preprocess 5 ... finished"); +} + + +//TEST_CASE("Preprocessing test 6", "[Sequential Arrangement Preprocessing]") +void preprocessing_test_6(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing preprocess 6 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE / SEQ_SLICER_SCALE_FACTOR, SEQ_QIDI_MK3S_Y_SIZE / SEQ_SLICER_SCALE_FACTOR}); + + std::vector polygons; + std::vector > unreachable_polygons; + for (unsigned int i = 0; i < 12 /*QIDI_PART_POLYGONS.size()*/; ++i) + { + Polygon decimated_polygon; + decimate_PolygonForSequentialSolver(solver_configuration, + QIDI_PART_POLYGONS[i], + decimated_polygon, + false); + + Polygon scale_down_polygon; + scaleDown_PolygonForSequentialSolver(decimated_polygon, scale_down_polygon); + polygons.push_back(scale_down_polygon); + + std::vector convex_level_polygons; + convex_level_polygons.push_back(QIDI_PART_POLYGONS[i]); + convex_level_polygons.push_back(QIDI_PART_POLYGONS[i]); + std::vector box_level_polygons; + box_level_polygons.push_back(QIDI_PART_POLYGONS[i]); + box_level_polygons.push_back(QIDI_PART_POLYGONS[i]); + + std::vector scale_down_unreachable_polygons; + prepare_UnreachableZonePolygons(solver_configuration, + convex_level_polygons, + box_level_polygons, + SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_MK3S, + SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_MK3S, + scale_down_unreachable_polygons); + unreachable_polygons.push_back(scale_down_unreachable_polygons); + } + + vector remaining_polygons; + vector polygon_index_map; + vector decided_polygons; + + for (unsigned int index = 0; index < polygons.size(); ++index) + { + polygon_index_map.push_back(index); + } + + vector poly_positions_X; + vector poly_positions_Y; + vector times_T; + + do + { + decided_polygons.clear(); + remaining_polygons.clear(); + + bool optimized = optimize_SubglobalSequentialPolygonNonoverlappingBinaryCentered(solver_configuration, + poly_positions_X, + poly_positions_Y, + times_T, + polygons, + unreachable_polygons, + polygon_index_map, + decided_polygons, + remaining_polygons); + + #ifdef DEBUG + { + printf("----> Optimization finished <----\n"); + } + #endif + REQUIRE(optimized); + + if (optimized) + { + #ifdef DEBUG + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + printf(" [%d] %.3f, %.3f (%.3f)\n", decided_polygons[i], poly_positions_X[decided_polygons[i]].as_double(), poly_positions_Y[decided_polygons[i]].as_double(), times_T[decided_polygons[i]].as_double()); + } + printf("Remaining polygons: %ld\n", remaining_polygons.size()); + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + printf(" %d\n", remaining_polygons[i]); + } + } + #endif + + SVG preview_svg("preprocess_test_6.svg"); + + if (!unreachable_polygons.empty()) + { + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + #ifdef DEBUG + { + printf("----> %.3f,%.3f\n", poly_positions_X[decided_polygons[i]].as_double(), poly_positions_Y[decided_polygons[i]].as_double()); + for (unsigned int k = 0; k < polygons[decided_polygons[i]].points.size(); ++k) + { + printf(" xy: %d, %d\n", polygons[decided_polygons[i]].points[k].x(), polygons[decided_polygons[i]].points[k].y()); + } + } + #endif + for (unsigned int j = 0; j < unreachable_polygons[decided_polygons[i]].size(); ++j) + { + #ifdef DEBUG + { + for (unsigned int k = 0; k < unreachable_polygons[decided_polygons[i]][j].points.size(); ++k) + { + printf(" Pxy: %d, %d\n", unreachable_polygons[decided_polygons[i]][j].points[k].x(), unreachable_polygons[decided_polygons[i]][j].points[k].y()); + } + } + #endif + Polygon display_unreachable_polygon = scale_UP(unreachable_polygons[decided_polygons[i]][j], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double()); + preview_svg.draw(display_unreachable_polygon, "lightgrey"); + } + } + } + + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + Polygon display_polygon = scale_UP(polygons[decided_polygons[i]], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double()); + + string color; + + switch(i) + { + case 0: + { + color = "green"; + break; + } + case 1: + { + color = "blue"; + break; + } + case 2: + { + color = "red"; + break; + } + case 3: + { + color = "grey"; + break; + } + case 4: + { + color = "cyan"; + break; + } + case 5: + { + color = "magenta"; + break; + } + case 6: + { + color = "yellow"; + break; + } + case 7: + { + color = "black"; + break; + } + case 8: + { + color = "indigo"; + break; + } + case 9: + { + color = "olive"; + break; + } + case 10: + { + color = "aqua"; + break; + } + case 11: + { + color = "violet"; + break; + } + default: + { + break; + } + } + + preview_svg.draw(display_polygon, color); + } + + preview_svg.Close(); + } + else + { + #ifdef DEBUG + { + printf("Polygon optimization FAILED.\n"); + } + #endif + } + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Intermediate time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + vector next_polygons; + vector > next_unreachable_polygons; + + #ifdef DEBUG + { + for (unsigned int i = 0; i < polygon_index_map.size(); ++i) + { + printf(" %d\n", polygon_index_map[i]); + } + } + #endif + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + next_polygons.push_back(polygons[remaining_polygons[i]]); + next_unreachable_polygons.push_back(unreachable_polygons[remaining_polygons[i]]); + } + + polygons.clear(); + unreachable_polygons.clear(); + polygon_index_map.clear(); + + polygons = next_polygons; + unreachable_polygons = next_unreachable_polygons; + + for (unsigned int index = 0; index < polygons.size(); ++index) + { + polygon_index_map.push_back(index); + } + } + while (!remaining_polygons.empty()); + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing preprocess 6 ... finished"); +} + + +/*----------------------------------------------------------------*/ diff --git a/src/libseqarrange/test/seq_test_preprocess.hpp b/src/libseqarrange/test/seq_test_preprocess.hpp new file mode 100644 index 0000000..cf4c1f1 --- /dev/null +++ b/src/libseqarrange/test/seq_test_preprocess.hpp @@ -0,0 +1,7 @@ +#ifndef __SEQ_TEST_PREPROCESS_HPP__ +#define __SEQ_TEST_PREPROCESS_HPP__ + +/*----------------------------------------------------------------*/ + + +#endif /* __SEQ_TEST_PREPROCESS_HPP__ */ diff --git a/src/libseqarrange/test/seq_test_sequential.cpp b/src/libseqarrange/test/seq_test_sequential.cpp new file mode 100644 index 0000000..10fd395 --- /dev/null +++ b/src/libseqarrange/test/seq_test_sequential.cpp @@ -0,0 +1,2520 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Geometry/ConvexHull.hpp" +#include "libslic3r/SVG.hpp" + +#include + +#include "seq_defs.hpp" +#include "seq_preprocess.hpp" +#include "seq_sequential.hpp" + +#include "seq_test_sequential.hpp" + + +/*----------------------------------------------------------------*/ + +using namespace z3; + +using namespace Slic3r; +using namespace Slic3r::Geometry; + +using namespace Sequential; + + +#define SCALE_FACTOR 100000.0 + +/*----------------------------------------------------------------*/ + +const int SEQ_QIDI_MK3S_X_SIZE = 250000000; +const int SEQ_QIDI_MK3S_Y_SIZE = 210000000; + + +/*----------------------------------------------------------------*/ + +/* +static Polygon scale_UP(const Polygon &polygon) +{ + Polygon poly = polygon; + + for (unsigned int i = 0; i < poly.points.size(); ++i) + { + poly.points[i] = Point(poly.points[i].x() * SCALE_FACTOR, poly.points[i].y() * SCALE_FACTOR); + } + + return poly; +} +*/ + +static Polygon scale_UP(const Polygon &polygon, double x_pos, double y_pos) +{ + Polygon poly = polygon; + + for (unsigned int i = 0; i < poly.points.size(); ++i) + { + poly.points[i] = Point(poly.points[i].x() * SCALE_FACTOR + x_pos * SCALE_FACTOR, + poly.points[i].y() * SCALE_FACTOR + y_pos * SCALE_FACTOR); + } + + return poly; +} + + +TEST_CASE("Sequential test 1", "[Sequential Arrangement Core]") +{ + INFO("Testing sequential scheduling 1 ..."); + + z3::context z_context; + + z3::expr x(z_context.bool_const("x")); + z3::expr y(z_context.bool_const("y")); + z3::expr z(z_context.bool_const("z")); + + z3::expr a(z_context.int_const("a")); + z3::expr b(z_context.int_const("b")); + + z3::expr c(z_context.real_const("cf")); + z3::expr d(z_context.real_const("df")); + + z3::expr lhs(x || y); + z3::expr rhs(implies(x, y)); + z3::expr final(lhs == rhs); + + z3::expr lhs1(a); + z3::expr rhs1(b); + z3::expr final2(lhs1 == rhs1); + + z3::expr lhs2(a > 2); + z3::expr rhs2(b < 4); + z3::expr final3(lhs2 || rhs2); + z3::expr final4(a > 5); + z3::expr final5(final3 && final4); + + z3::expr ef1((c > 3 && d < 6) && c < d); + + z3::solver z_solver(z_context); + + z_solver.add(final2); + z_solver.add(final5); + z_solver.add(ef1); + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + bool sat = false; + switch (z_solver.check()) + { + case z3::sat: + { + sat = true; + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + for (unsigned int i = 0; i < z_model.size(); ++i) + { + #ifdef DEBUG + { + printf("Variable:%s\n", z_model[i].name().str().c_str()); + printf("Printing interpretation:\n"); + + cout << z_model.get_const_interp(z_model[i]) << "\n"; + } + #endif + + #ifdef DEBUG + { + if (z_model.get_const_interp(z_model[i]).is_bool()) + { + printf(" value: TRUE\n"); + } + else + { + printf(" value: FALSE\n"); + } + } + #endif + } + + INFO("Testing sequential scheduling 1 ... finished"); +} + + +int complex_sheet_resolution_X = 200; +int complex_sheet_resolution_Y = 50; + +int complex_sheet_resolution_X_min = 10; +int complex_sheet_resolution_X_max = 200; +int complex_sheet_resolution_Y_min = 10; +int complex_sheet_resolution_Y_max = 200; + +int complex_time_resolution = 1000; +int complex_height_threshold = 25; + +const int complex_Obj_count = 26; + +int complex_Obj_widths[complex_Obj_count]; +int complex_Obj_heights[complex_Obj_count]; +int complex_Obj_durations[complex_Obj_count]; + +const int min_width = 4; +const int max_width = 20; + +const int min_height = 4; +const int max_height = 20; + +const int min_duration = 2; +const int max_duration = 50; + +const int gantry_left_height = 10; +const int gantry_left_shift = 4; + +const int gantry_right_height = 10; +const int gantry_right_shift = 4; + + +void generate_random_complex_objects(void) +{ + int width_span = max_width - min_width; + int height_span = max_height - min_height; + int duration_span = max_duration - min_duration; + + for (int i = 0; i < complex_Obj_count; ++i) + { + #ifdef DEBUG + { + printf("Generating random object %d ...\n", i); + } + #endif + + complex_Obj_widths[i] = min_width + rand() % width_span; + complex_Obj_heights[i] = min_height + rand() % height_span; + complex_Obj_durations[i] = min_duration + rand() % duration_span; + + #ifdef DEBUG + { + printf("O %d: w:%d h:%d d:%d\n", i, complex_Obj_widths[i], complex_Obj_heights[i], complex_Obj_durations[i]); + } + #endif + } +} + + +typedef std::basic_string sString; + +TEST_CASE("Sequential test 2", "[Sequential Arrangement Core]") +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing sequential scheduling 2 ..."); + generate_random_complex_objects(); + + #ifdef DEBUG + start = clock(); + #endif + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + z3::expr_vector T_schedules(z_context); + + z3::expr_vector gantry_lefts(z_context); + z3::expr_vector gantry_rights(z_context); + + for (int i = 0; i < complex_Obj_count; ++i) + { + sString name = "x_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + X_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + sString name = "y_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + Y_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + sString name = "time-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T_schedules.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + sString name_L = "gantry_L-" + to_string(i); + #ifdef DEBUG + { + printf("name_L: %s\n", name_L.c_str()); + } + #endif + sString name_R = "gantry_R-" + to_string(i); + #ifdef DEBUG + { + printf("name_R: %s\n", name_R.c_str()); + } + #endif + gantry_lefts.push_back(expr(z_context.real_const(name_L.c_str()))); + gantry_rights.push_back(expr(z_context.real_const(name_R.c_str()))); + } + + z3::solver z_solver(z_context); + + for (int i = 0; i < complex_Obj_count; ++i) + { + z_solver.add(X_positions[i] >= 0 && X_positions[i] + complex_Obj_widths[i] <= complex_sheet_resolution_X); + z_solver.add(Y_positions[i] >= 0 && Y_positions[i] + complex_Obj_heights[i] <= complex_sheet_resolution_Y); + z_solver.add(T_schedules[i] >= 0 && T_schedules[i] + complex_Obj_durations[i] <= complex_time_resolution); + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + for (int j = 0; j < complex_Obj_count; ++j) + { + if (i < j) + { + z_solver.add( X_positions[i] >= X_positions[j] + complex_Obj_widths[j] + || X_positions[j] >= X_positions[i] + complex_Obj_widths[i] + || Y_positions[i] >= Y_positions[j] + complex_Obj_heights[j] + || Y_positions[j] >= Y_positions[i] + complex_Obj_heights[i]); + } + } + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + for (int j = 0; j < complex_Obj_count; ++j) + { + if (i < j) + { + z_solver.add( T_schedules[i] >= T_schedules[j] + complex_Obj_durations[j] + || T_schedules[j] >= T_schedules[i] + complex_Obj_durations[i]); + } + } + + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + if (complex_Obj_durations[i] >= complex_height_threshold) + { + z_solver.add(gantry_lefts[i] == Y_positions[i] + gantry_left_shift && gantry_rights[i] == Y_positions[i] + gantry_right_shift); + } + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + if (complex_Obj_durations[i] >= complex_height_threshold) + { + for (int j = 0; j < complex_Obj_count; ++j) + { + if (i != j) + { + z_solver.add( T_schedules[j] < T_schedules[i] + || Y_positions[j] >= gantry_rights[i] + gantry_right_height + || gantry_rights[i] >= Y_positions[j] + complex_Obj_heights[j]); + + z_solver.add( T_schedules[j] < T_schedules[i] + || Y_positions[j] >= gantry_lefts[i] + gantry_left_height + || Y_positions[i] >= Y_positions[j] + complex_Obj_heights[j]); + } + } + } + } + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + bool sat = false; + switch (z_solver.check()) + { + case z3::sat: + { + sat = true; + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + REQUIRE(!sat); + + #ifdef DEBUG + z3::model z_model(z_solver.get_model()); + printf("Printing model:\n"); + cout << z_model << "\n"; + #endif + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + for (unsigned int i = 0; i < z_model.size(); ++i) + { + printf("Variable:%s\n", z_model[i].name().str().c_str()); + + printf("Printing interpretation:\n"); + cout << z_model.get_const_interp(z_model[i]) << "\n"; + + cout << float(z_model[i]) << "\n"; + + switch (z_model.get_const_interp(z_model[i]).bool_value()) + { + case Z3_L_FALSE: + { + printf(" value: FALSE\n"); + break; + } + case Z3_L_TRUE: + { + printf(" value: TRUE\n"); + break; + } + case Z3_L_UNDEF: + { + printf(" value: UNDEF\n"); + break; + } + default: + { + break; + } + } + } + } + #endif + + #ifdef DEBUG + { + for (int i = 0; i < complex_Obj_count; ++i) + { + printf("%s\n", z_model.get_const_interp(z_model[i]).get_string().c_str()); + } + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing sequential scheduling 2 ... finished"); +} + + +const int complex_max_rotation = 8; + +int rotated_Obj_widths[complex_Obj_count][complex_max_rotation]; +int rotated_Obj_heights[complex_Obj_count][complex_max_rotation]; + +void generate_random_rotated_complex_objects(void) +{ + int width_span = max_width - min_width; + int height_span = max_height - min_height; + int duration_span = max_duration - min_duration; + + for (int i = 0; i < complex_Obj_count; ++i) + { + #ifdef DEBUG + { + printf("Generating random object %d ...\n", i); + } + #endif + + int base_width = min_width + rand() % width_span; + int base_height = min_height + rand() % height_span; + + double angle = 0; + double angle_step = 0.5 * M_PI / complex_max_rotation; + + for (int r = 0; r < complex_max_rotation; ++r) + { + int width = cos(angle) * base_width + min_width; + int height = sin(angle) * base_height + min_height; + + #ifdef DEBUG + { + printf("w: %d, h: %d\n", width, height); + } + #endif + + rotated_Obj_widths[i][r] = width; + rotated_Obj_heights[i][r] = height; + + angle += angle_step; + + #ifdef DEBUG + { + printf("O %d: w:%d h:%d d:%d\n", i, rotated_Obj_widths[i][r], rotated_Obj_heights[i][r], complex_Obj_durations[i]); + } + #endif + } + + complex_Obj_durations[i] = min_duration + rand() % duration_span; + } +} + + +//TEST_CASE("Sequential test 3", "[Sequential Arrangement Core]") +void sequential_test_3(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing sequential scheduling 3 ..."); + generate_random_rotated_complex_objects(); + + #ifdef DEBUG + start = clock(); + #endif + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + z3::expr_vector T_schedules(z_context); + + z3::expr_vector gantry_lefts(z_context); + z3::expr_vector gantry_rights(z_context); + + z3::expr_vector rotations(z_context); + z3::expr_vector widths(z_context); + z3::expr_vector heights(z_context); + + for (int i = 0; i < complex_Obj_count; ++i) + { + sString name = "x_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + X_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + sString name = "y_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + Y_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + sString name = "time-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T_schedules.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + sString name = "width-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + widths.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + sString name = "height-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + heights.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + sString name = "rot-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + rotations.push_back(expr(z_context.int_const(name.c_str()))); + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + sString name_L = "gantry_L-" + to_string(i); + #ifdef DEBUG + { + printf("name_L: %s\n", name_L.c_str()); + } + #endif + sString name_R = "gantry_R-" + to_string(i); + #ifdef DEBUG + { + printf("name_R: %s\n", name_R.c_str()); + } + #endif + gantry_lefts.push_back(expr(z_context.real_const(name_L.c_str()))); + gantry_rights.push_back(expr(z_context.real_const(name_R.c_str()))); + } + + z3::solver z_solver(z_context); + + for (int i = 0; i < complex_Obj_count; ++i) + { + z_solver.add(X_positions[i] >= 0 && X_positions[i] + complex_Obj_widths[i] <= complex_sheet_resolution_X); + z_solver.add(Y_positions[i] >= 0 && Y_positions[i] + complex_Obj_heights[i] <= complex_sheet_resolution_Y); + z_solver.add(T_schedules[i] >= 0 && T_schedules[i] + complex_Obj_durations[i] <= complex_time_resolution); + z_solver.add(rotations[i] >= 0 && rotations[i] < complex_max_rotation); + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + for (int r = 0; r < complex_max_rotation; ++r) + { + z_solver.add(rotations[i] != r || widths[i] == rotated_Obj_widths[i][r]); + z_solver.add(rotations[i] != r || heights[i] == rotated_Obj_heights[i][r]); + } + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + for (int j = 0; j < complex_Obj_count; ++j) + { + if (i < j) + { + z_solver.add( X_positions[i] >= X_positions[j] + widths[j] + || X_positions[j] >= X_positions[i] + widths[i] + || Y_positions[i] >= Y_positions[j] + heights[j] + || Y_positions[j] >= Y_positions[i] + heights[i]); + } + } + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + for (int j = 0; j < complex_Obj_count; ++j) + { + if (i < j) + { + z_solver.add( T_schedules[i] >= T_schedules[j] + complex_Obj_durations[j] + || T_schedules[j] >= T_schedules[i] + complex_Obj_durations[i]); + } + } + + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + if (complex_Obj_durations[i] >= complex_height_threshold) + { + z_solver.add(gantry_lefts[i] == Y_positions[i] + gantry_left_shift && gantry_rights[i] == Y_positions[i] + gantry_right_shift); + } + } + + for (int i = 0; i < complex_Obj_count; ++i) + { + if (complex_Obj_durations[i] >= complex_height_threshold) + { + for (int j = 0; j < complex_Obj_count; ++j) + { + if (i != j) + { + z_solver.add( T_schedules[j] < T_schedules[i] + || Y_positions[j] >= gantry_rights[i] + gantry_right_height + || gantry_rights[i] >= Y_positions[j] + heights[j]); + + z_solver.add( T_schedules[j] < T_schedules[i] + || Y_positions[j] >= gantry_lefts[i] + gantry_left_height + || Y_positions[i] >= Y_positions[j] + heights[j]); + } + } + } + } + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + bool sat = false; + switch (z_solver.check()) + { + case z3::sat: + { + sat = true; + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + #ifdef DEBUG + z3::model z_model(z_solver.get_model()); + printf("Printing model:\n"); + cout << z_model << "\n"; + #endif + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + for (unsigned int i = 0; i < z_model.size(); ++i) + { + printf("Variable:%s\n", z_model[i].name().str().c_str()); + + printf("Printing interpretation:\n"); + cout << z_model.get_const_interp(z_model[i]) << "\n"; + + cout << float(z_model[i]) << "\n"; + + switch (z_model.get_const_interp(z_model[i]).bool_value()) + { + case Z3_L_FALSE: + { + printf(" value: FALSE\n"); + break; + } + case Z3_L_TRUE: + { + printf(" value: TRUE\n"); + break; + } + case Z3_L_UNDEF: + { + printf(" value: UNDEF\n"); + break; + } + default: + { + break; + } + } + } + } + #endif + + #ifdef DEBUG + { + for (int i = 0; i < complex_Obj_count; ++i) + { + printf("%s\n", z_model.get_const_interp(z_model[i]).get_string().c_str()); + } + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + + INFO("Testing sequential scheduling 3 ... finished"); +} + +namespace { + Polygon polygon_1 = { {0, 0}, {50, 0}, {50, 50}, {0, 50} }; + Polygon polygon_2 = { {0, 0}, {150, 10}, {150, 50}, {75, 120}, {0, 50} }; + //Polygon polygon_2 = {{0, 0}, {0, 50}, {75, 120}, {150, 50}, {150, 0} }; + Polygon polygon_3 = { {40, 0}, {80, 40}, {40, 80}, {0, 40} }; + //Polygon polygon_3 = {{40, 0}, {0, 40},{40, 80}, {80, 40}}; + Polygon polygon_4 = { {20, 0}, {40, 0}, {60, 30}, {30, 50}, {0, 30} }; + //Polygon polygon_4 = {{20, 0}, {0, 30}, {30, 50}, {60, 30}, {40, 0} }; + + Polygon unreachable_polygon_1 = { {-5, -5}, {60, -5}, {60, 60}, {-5, 60} }; + Polygon unreachable_polygon_2 = { {-20, -20}, {170, -20}, {170, 86}, {85, 140}, {-20, 60} }; + Polygon unreachable_polygon_3 = { {40, -10}, {90, 40}, {40, 90}, {-10, 40} }; + Polygon unreachable_polygon_4 = { {10, -10}, {40, -10}, {70, 40}, {30, 60}, {-10, 40} }; + //Polygon unreachable_polygon_4 = {{10, -1}, {40, -1}, {70, 40}, {30, 60}, {0, 40}}; + //Polygon unreachable_polygon_4 = {{10, -10}, {-10, 40}, {30, 60}, {70, 40}, {40, -10}}; + + + std::vector unreachable_polygons_1 = { + {{-5, -5}, {60, -5}, {60, 60}, {-5, 60}}, + // {{-20,-20}, {-25,-20}, {-25,-25}, {-20,-25}} + // {{-20,20}, {-25,20}, {-25,25}, {-20,25}} + // {{-20,20}, {-40,20}, {-40,40}, {-20,40}} + // {{-20,20}, {-80,20}, {-80,40}, {-20,40}} /* CW */ + {{-20,20}, {-20,40}, {-180,40}, {-180,20}}, /* CCW */ + {{80,20}, {240,20}, {240,40}, {80,40}} /* CCW */ + // {{-5,-5}, {-100,-5}, {-100,10}, {-5,10}} + }; + + std::vector unreachable_polygons_2 = { + {{-20, -20}, {170, -20}, {170, 86}, {85, 140}, {-20, 60} } + }; + + std::vector unreachable_polygons_3 = { + {{40, -10}, {90, 40}, {40, 90}, {-10, 40}}, + {{-20,20}, {-20,40}, {-180,40}, {-180,20}}, /* CCW */ + {{80,20}, {240,20}, {240,40}, {80,40}} /* CCW */ + }; + + std::vector unreachable_polygons_4 = { + {{10, -10}, {40, -10}, {70, 40}, {30, 60}, {-10, 40}} + }; +} + + +//TEST_CASE("Sequential test 4", "[Sequential Arrangement Core]") +void sequential_test_4(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing sequential 4 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + z3::expr_vector T_times(z_context); + + for (int i = 0; i < 4; ++i) + { + string name = "x_pos-" + to_string(i); + #ifdef DEBUG + { + printf("i:%d\n", i); + printf("name: %s\n", name.c_str()); + } + #endif + X_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < 4; ++i) + { + string name = "y_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + Y_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_1.points.size(); ++i) + { + string name = "t_time-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T_times.push_back(expr(z_context.real_const(name.c_str()))); + } + + z3::set_param("parallel.enable", "true"); + z3::solver z_solver(z_context); + + vector polygons; + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + vector unreachable_polygons; + unreachable_polygons.push_back(unreachable_polygon_1); + unreachable_polygons.push_back(unreachable_polygon_2); + unreachable_polygons.push_back(unreachable_polygon_3); + unreachable_polygons.push_back(unreachable_polygon_4); + + introduce_SequentialPolygonWeakNonoverlapping(z_solver, + z_context, + X_positions, + Y_positions, + T_times, + polygons, + unreachable_polygons); + introduce_TemporalOrdering(z_solver, z_context, T_times, 16, polygons); + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + int last_solvable_bounding_box_size = -1; + double poly_1_pos_x, poly_1_pos_y, poly_2_pos_x, poly_2_pos_y, poly_3_pos_x, poly_3_pos_y, poly_4_pos_x, poly_4_pos_y; + poly_1_pos_x = poly_1_pos_y = poly_2_pos_x = poly_2_pos_y = poly_3_pos_x = poly_3_pos_y = poly_4_pos_x = poly_4_pos_y = 0.0; + + double time_1_t, time_2_t, time_3_t, time_4_t; + time_1_t = time_2_t = time_3_t = time_4_t = -1.0; + + double _poly_1_pos_x, _poly_1_pos_y, _poly_2_pos_x, _poly_2_pos_y, _poly_3_pos_x, _poly_3_pos_y, _poly_4_pos_x, _poly_4_pos_y; + _poly_1_pos_x = _poly_1_pos_y = _poly_2_pos_x = _poly_2_pos_y = _poly_3_pos_x = _poly_3_pos_y = _poly_4_pos_x = _poly_4_pos_y = 0.0; + + #ifdef DEBUG + double _time_1_t, _time_2_t, _time_3_t, _time_4_t; + _time_1_t = _time_2_t = _time_3_t = _time_4_t = -1.0; + #endif + + for (int bounding_box_size = 200; bounding_box_size > 10; bounding_box_size -= 4) + { + #ifdef DEBUG + { + printf("BB: %d\n", bounding_box_size); + } + #endif + z3::expr_vector bounding_box_assumptions(z_context); + + assume_BedBoundingBox(X_positions[0], Y_positions[0], polygons[0], bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[1], Y_positions[1], polygons[1], bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[2], Y_positions[2], polygons[2], bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[3], Y_positions[3], polygons[3], bounding_box_size, bounding_box_size, bounding_box_assumptions); + + bool sat = false; + + switch (z_solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + sat = true; + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + sat = false; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + #ifdef DEBUG + { + printf("Printing interpretation:\n"); + } + #endif + for (unsigned int i = 0; i < z_model.size(); ++i) + { + double value = z_model.get_const_interp(z_model[i]).as_double(); + + #ifdef DEBUG + { + printf("Variable:%s ", z_model[i].name().str().c_str()); + cout << z_model.get_const_interp(z_model[i]).as_double() << "\n"; + printf("value: %.3f\n", value); + } + #endif + + if (z_model[i].name().str() == "x_pos-0") + { + poly_1_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-0") + { + poly_1_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-1") + { + poly_2_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-1") + { + poly_2_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-2") + { + poly_3_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-2") + { + poly_3_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-3") + { + poly_4_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-3") + { + poly_4_pos_y = value; + } + else if (z_model[i].name().str() == "t_time-0") + { + time_1_t = value; + } + else if (z_model[i].name().str() == "t_time-1") + { + time_2_t = value; + } + else if (z_model[i].name().str() == "t_time-2") + { + time_3_t = value; + } + else if (z_model[i].name().str() == "t_time-3") + { + time_4_t = value; + } + } + + #ifdef DEBUG + { + printf("Times: %.3f, %.3f, %.3f, %3f\n", + time_1_t, + time_2_t, + time_3_t, + time_4_t); + + printf("preRefined positions: %.3f, %.3f [%.3f], %.3f, %.3f [%.3f], %.3f, %.3f [%.3f], %.3f, %.3f [%.3f]\n", + poly_1_pos_x, + poly_1_pos_y, + time_1_t, + poly_2_pos_x, + poly_2_pos_y, + time_2_t, + poly_3_pos_x, + poly_3_pos_y, + time_3_t, + poly_4_pos_x, + poly_4_pos_y, + time_4_t); + } + #endif + + while (true) + { + vector dec_values_X; + dec_values_X.push_back(poly_1_pos_x); + dec_values_X.push_back(poly_2_pos_x); + dec_values_X.push_back(poly_3_pos_x); + dec_values_X.push_back(poly_4_pos_x); + + vector dec_values_Y; + dec_values_Y.push_back(poly_1_pos_y); + dec_values_Y.push_back(poly_2_pos_y); + dec_values_Y.push_back(poly_3_pos_y); + dec_values_Y.push_back(poly_4_pos_y); + + vector dec_values_T; + dec_values_T.push_back(time_1_t); + dec_values_T.push_back(time_2_t); + dec_values_T.push_back(time_3_t); + dec_values_T.push_back(time_4_t); + + bool refined = refine_SequentialPolygonWeakNonoverlapping(z_solver, + z_context, + X_positions, + Y_positions, + T_times, + dec_values_X, + dec_values_Y, + dec_values_T, + polygons, + unreachable_polygons); + + bool refined_sat = false; + + if (refined) + { + switch (z_solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + #ifdef DEBUG + { + printf(" sat\n"); + } + #endif + refined_sat = true; + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" unsat\n"); + } + #endif + refined_sat = false; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" unknown\n"); + } + #endif + break; + } + default: + { + break; + } + } + + if (refined_sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + for (unsigned int i = 0; i < z_model.size(); ++i) + { + #ifdef DEBUG + { + printf("Variable:%s ", z_model[i].name().str().c_str()); + } + #endif + + double value = z_model.get_const_interp(z_model[i]).as_double(); + + if (z_model[i].name().str() == "x_pos-0") + { + poly_1_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-0") + { + poly_1_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-1") + { + poly_2_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-1") + { + poly_2_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-2") + { + poly_3_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-2") + { + poly_3_pos_y = value; + } + else if (z_model[i].name().str() == "x_pos-3") + { + poly_4_pos_x = value; + } + else if (z_model[i].name().str() == "y_pos-3") + { + poly_4_pos_y = value; + } + else if (z_model[i].name().str() == "t_time-0") + { + time_1_t = value; + } + else if (z_model[i].name().str() == "t_time-1") + { + time_2_t = value; + } + else if (z_model[i].name().str() == "t_time-2") + { + time_3_t = value; + } + else if (z_model[i].name().str() == "t_time-3") + { + time_4_t = value; + } + } + #ifdef DEBUG + { + printf("Refined positions: %.3f, %.3f [%.3f], %.3f, %.3f [%.3f], %.3f, %.3f [%.3f], %.3f, %.3f [%.3f]\n", + poly_1_pos_x, + poly_1_pos_y, + time_1_t, + poly_2_pos_x, + poly_2_pos_y, + time_2_t, + poly_3_pos_x, + poly_3_pos_y, + time_3_t, + poly_4_pos_x, + poly_4_pos_y, + time_4_t); + } + #endif + } + else + { + break; + } + } + else + { + #ifdef DEBUG + { + printf("-------------------------------------------------------------------\n"); + + _poly_1_pos_x = poly_1_pos_x; + _poly_1_pos_y = poly_1_pos_y; + _time_1_t = time_1_t; + _poly_2_pos_x = poly_2_pos_x; + _poly_2_pos_y = poly_2_pos_y; + _time_2_t = time_2_t; + _poly_3_pos_x = poly_3_pos_x; + _poly_3_pos_y = poly_3_pos_y; + _time_3_t = time_3_t; + _poly_4_pos_x = poly_4_pos_x; + _poly_4_pos_y = poly_4_pos_y; + _time_4_t = time_4_t; + } + #endif + + last_solvable_bounding_box_size = bounding_box_size; + break; + } + } + } + else + { + break; + } + } + #ifdef DEBUG + finish = clock(); + #endif + + REQUIRE(last_solvable_bounding_box_size > 0); + + #ifdef DEBUG + { + printf("Solvable bounding box: %d\n", last_solvable_bounding_box_size); + + printf("Final spatio-temporal positions: %.3f, %.3f [%.3f], %.3f, %.3f [%.3f], %.3f, %.3f [%.3f], %.3f, %.3f [%.3f]\n", + _poly_1_pos_x, + _poly_1_pos_y, + _time_1_t, + _poly_2_pos_x, + _poly_2_pos_y, + _time_2_t, + _poly_3_pos_x, + _poly_3_pos_y, + _time_3_t, + _poly_4_pos_x, + _poly_4_pos_y, + _time_4_t); + } + #endif + + #ifdef DEBUG + { + for (int i = 0; i < 2; ++i) + { + double value = X_positions[i]; + printf("Orig X: %.3f\n", value); + + value = Y_positions[i]; + printf("Orig Y: %.3f\n", value); + } + } + #endif + + SVG preview_svg("sequential_test_4.svg"); + + Polygon display_pro_polygon_1 = scale_UP(unreachable_polygons[0], _poly_1_pos_x, _poly_1_pos_y); + Polygon display_pro_polygon_2 = scale_UP(unreachable_polygons[1], _poly_2_pos_x, _poly_2_pos_y); + Polygon display_pro_polygon_3 = scale_UP(unreachable_polygons[2], _poly_3_pos_x, _poly_3_pos_y); + Polygon display_pro_polygon_4 = scale_UP(unreachable_polygons[3], _poly_4_pos_x, _poly_4_pos_y); + + preview_svg.draw(display_pro_polygon_1, "lightgrey"); + preview_svg.draw(display_pro_polygon_2, "lightgrey"); + preview_svg.draw(display_pro_polygon_3, "lightgrey"); + preview_svg.draw(display_pro_polygon_4, "lightgrey"); + + Polygon display_polygon_1 = scale_UP(polygons[0], _poly_1_pos_x, _poly_1_pos_y); + Polygon display_polygon_2 = scale_UP(polygons[1], _poly_2_pos_x, _poly_2_pos_y); + Polygon display_polygon_3 = scale_UP(polygons[2], _poly_3_pos_x, _poly_3_pos_y); + Polygon display_polygon_4 = scale_UP(polygons[3], _poly_4_pos_x, _poly_4_pos_y); + + preview_svg.draw(display_polygon_1, "green"); + preview_svg.draw(display_polygon_2, "blue"); + preview_svg.draw(display_polygon_3, "red"); + preview_svg.draw(display_polygon_4, "grey"); + + preview_svg.Close(); + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing sequential 4 ... finished"); +} + + +//TEST_CASE("Sequential test 5", "[Sequential Arrangement Core]") +void sequential_test_5(void) +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing sequential 5 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + z3::context z_context; + z3::expr_vector X_positions(z_context); + z3::expr_vector Y_positions(z_context); + z3::expr_vector T_times(z_context); + + for (int i = 0; i < 4; ++i) + { + string name = "x_pos-" + to_string(i); + #ifdef DEBUG + { + printf("i:%d\n", i); + printf("name: %s\n", name.c_str()); + } + #endif + X_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (int i = 0; i < 4; ++i) + { + string name = "y_pos-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + Y_positions.push_back(expr(z_context.real_const(name.c_str()))); + } + + for (unsigned int i = 0; i < polygon_1.points.size(); ++i) + { + string name = "t_time-" + to_string(i); + #ifdef DEBUG + { + printf("name: %s\n", name.c_str()); + } + #endif + T_times.push_back(expr(z_context.real_const(name.c_str()))); + } + + z3::solver z_solver(z_context); + Z3_global_param_set("parallel.enable", "false"); + + vector polygons; + polygons.push_back(polygon_1); + polygons.push_back(polygon_2); + polygons.push_back(polygon_3); + polygons.push_back(polygon_4); + + vector > unreachable_polygons; + unreachable_polygons.push_back(unreachable_polygons_1); + unreachable_polygons.push_back(unreachable_polygons_2); + unreachable_polygons.push_back(unreachable_polygons_3); + unreachable_polygons.push_back(unreachable_polygons_4); + + #ifdef DEBUG + { + printf("pp: %ld\n", unreachable_polygons[0].size()); + printf("pp: %ld\n", unreachable_polygons[1].size()); + printf("pp: %ld\n", unreachable_polygons[2].size()); + printf("pp: %ld\n", unreachable_polygons[3].size()); + } + #endif + + introduce_SequentialPolygonWeakNonoverlapping(z_solver, + z_context, + X_positions, + Y_positions, + T_times, + polygons, + unreachable_polygons); + introduce_TemporalOrdering(z_solver, z_context, T_times, 16, polygons); + + #ifdef DEBUG + { + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + } + #endif + + int last_solvable_bounding_box_size = -1; + Rational poly_1_pos_x, poly_1_pos_y, poly_2_pos_x, poly_2_pos_y, poly_3_pos_x, poly_3_pos_y, poly_4_pos_x, poly_4_pos_y; + Rational time_1_t, time_2_t, time_3_t, time_4_t; + + Rational _poly_1_pos_x, _poly_1_pos_y, _poly_2_pos_x, _poly_2_pos_y, _poly_3_pos_x, _poly_3_pos_y, _poly_4_pos_x, _poly_4_pos_y; + Rational _time_1_t, _time_2_t, _time_3_t, _time_4_t; + + for (int bounding_box_size = 200; bounding_box_size > 10; bounding_box_size -= 4) + { + #ifdef DEBUG + { + printf("BB: %d\n", bounding_box_size); + } + #endif + z3::expr_vector bounding_box_assumptions(z_context); + + assume_BedBoundingBox(X_positions[0], Y_positions[0], polygons[0], bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[1], Y_positions[1], polygons[1], bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[2], Y_positions[2], polygons[2], bounding_box_size, bounding_box_size, bounding_box_assumptions); + assume_BedBoundingBox(X_positions[3], Y_positions[3], polygons[3], bounding_box_size, bounding_box_size, bounding_box_assumptions); + + bool sat = false; + + switch (z_solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + #ifdef DEBUG + { + printf(" SATISFIABLE\n"); + } + #endif + sat = true; + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" UNSATISFIABLE\n"); + } + #endif + sat = false; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" UNKNOWN\n"); + } + #endif + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + + printf("Printing interpretation:\n"); + } + #endif + + for (unsigned int i = 0; i < z_model.size(); ++i) + { + #ifdef DEBUG + { + double value = z_model.get_const_interp(z_model[i]).as_double(); + + printf("Variable:%s ", z_model[i].name().str().c_str()); + cout << z_model.get_const_interp(z_model[i]).as_double() << "\n"; + printf("value: %.3f\n", value); + } + #endif + + Rational rational(z_model.get_const_interp(z_model[i]).numerator().as_int64(), z_model.get_const_interp(z_model[i]).denominator().as_int64()); + + if (z_model[i].name().str() == "x_pos-0") + { + poly_1_pos_x = rational; + } + else if (z_model[i].name().str() == "y_pos-0") + { + poly_1_pos_y = rational; + } + else if (z_model[i].name().str() == "x_pos-1") + { + poly_2_pos_x = rational; + } + else if (z_model[i].name().str() == "y_pos-1") + { + poly_2_pos_y = rational; + } + else if (z_model[i].name().str() == "x_pos-2") + { + poly_3_pos_x = rational; + } + else if (z_model[i].name().str() == "y_pos-2") + { + poly_3_pos_y = rational; + } + else if (z_model[i].name().str() == "x_pos-3") + { + poly_4_pos_x = rational; + } + else if (z_model[i].name().str() == "y_pos-3") + { + poly_4_pos_y = rational; + } + else if (z_model[i].name().str() == "t_time-0") + { + time_1_t = rational; + } + else if (z_model[i].name().str() == "t_time-1") + { + time_2_t = rational; + } + else if (z_model[i].name().str() == "t_time-2") + { + time_3_t = rational; + } + else if (z_model[i].name().str() == "t_time-3") + { + time_4_t = rational; + } + } + + #ifdef DEBUG + { + printf("Times: %.3f, %.3f, %.3f, %3f\n", + time_1_t.as_double(), + time_2_t.as_double(), + time_3_t.as_double(), + time_4_t.as_double()); + + printf("preRefined positions: %.3f, %.3f [%.3f], %.3f, %.3f [%.3f], %.3f, %.3f [%.3f], %.3f, %.3f [%.3f]\n", + poly_1_pos_x.as_double(), + poly_1_pos_y.as_double(), + time_1_t.as_double(), + poly_2_pos_x.as_double(), + poly_2_pos_y.as_double(), + time_2_t.as_double(), + poly_3_pos_x.as_double(), + poly_3_pos_y.as_double(), + time_3_t.as_double(), + poly_4_pos_x.as_double(), + poly_4_pos_y.as_double(), + time_4_t.as_double()); + } + #endif + + while (true) + { + vector dec_values_X; + dec_values_X.push_back(poly_1_pos_x); + dec_values_X.push_back(poly_2_pos_x); + dec_values_X.push_back(poly_3_pos_x); + dec_values_X.push_back(poly_4_pos_x); + + vector dec_values_Y; + dec_values_Y.push_back(poly_1_pos_y); + dec_values_Y.push_back(poly_2_pos_y); + dec_values_Y.push_back(poly_3_pos_y); + dec_values_Y.push_back(poly_4_pos_y); + + vector dec_values_T; + dec_values_T.push_back(time_1_t); + dec_values_T.push_back(time_2_t); + dec_values_T.push_back(time_3_t); + dec_values_T.push_back(time_4_t); + + bool refined = refine_SequentialPolygonWeakNonoverlapping(z_solver, + z_context, + X_positions, + Y_positions, + T_times, + dec_values_X, + dec_values_Y, + dec_values_T, + polygons, + unreachable_polygons); + + bool refined_sat = false; + + if (refined) + { + switch (z_solver.check(bounding_box_assumptions)) + { + case z3::sat: + { + #ifdef DEBUG + { + printf(" sat\n"); + } + #endif + refined_sat = true; + break; + } + case z3::unsat: + { + #ifdef DEBUG + { + printf(" unsat\n"); + } + #endif + refined_sat = false; + break; + } + case z3::unknown: + { + #ifdef DEBUG + { + printf(" unknown\n"); + } + #endif + break; + } + default: + { + break; + } + } + + if (refined_sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + for (unsigned int i = 0; i < z_model.size(); ++i) + { + #ifdef DEBUG + { + double value = z_model.get_const_interp(z_model[i]).as_double(); + printf("Variable:%s ", z_model[i].name().str().c_str()); + printf("value: %.3f\n", value); + } + #endif + + Rational rational(z_model.get_const_interp(z_model[i]).numerator().as_int64(), z_model.get_const_interp(z_model[i]).denominator().as_int64()); + + if (z_model[i].name().str() == "x_pos-0") + { + poly_1_pos_x = rational; + } + else if (z_model[i].name().str() == "y_pos-0") + { + poly_1_pos_y = rational; + } + else if (z_model[i].name().str() == "x_pos-1") + { + poly_2_pos_x = rational; + } + else if (z_model[i].name().str() == "y_pos-1") + { + poly_2_pos_y = rational; + } + else if (z_model[i].name().str() == "x_pos-2") + { + poly_3_pos_x = rational; + } + else if (z_model[i].name().str() == "y_pos-2") + { + poly_3_pos_y = rational; + } + else if (z_model[i].name().str() == "x_pos-3") + { + poly_4_pos_x = rational; + } + else if (z_model[i].name().str() == "y_pos-3") + { + poly_4_pos_y = rational; + } + else if (z_model[i].name().str() == "t_time-0") + { + time_1_t = rational; + } + else if (z_model[i].name().str() == "t_time-1") + { + time_2_t = rational; + } + else if (z_model[i].name().str() == "t_time-2") + { + time_3_t = rational; + } + else if (z_model[i].name().str() == "t_time-3") + { + time_4_t = rational; + } + } + #ifdef DEBUG + { + printf("Refined positions: %.3f, %.3f [%.3f], %.3f, %.3f [%.3f], %.3f, %.3f [%.3f], %.3f, %.3f [%.3f]\n", + poly_1_pos_x.as_double(), + poly_1_pos_y.as_double(), + time_1_t.as_double(), + poly_2_pos_x.as_double(), + poly_2_pos_y.as_double(), + time_2_t.as_double(), + poly_3_pos_x.as_double(), + poly_3_pos_y.as_double(), + time_3_t.as_double(), + poly_4_pos_x.as_double(), + poly_4_pos_y.as_double(), + time_4_t.as_double()); + } + #endif + } + else + { + break; + } + } + else + { + #ifdef DEBUG + { + printf("-------------------------------------------------------------------\n"); + } + #endif + _poly_1_pos_x = poly_1_pos_x; + _poly_1_pos_y = poly_1_pos_y; + _time_1_t = time_1_t; + _poly_2_pos_x = poly_2_pos_x; + _poly_2_pos_y = poly_2_pos_y; + _time_2_t = time_2_t; + _poly_3_pos_x = poly_3_pos_x; + _poly_3_pos_y = poly_3_pos_y; + _time_3_t = time_3_t; + _poly_4_pos_x = poly_4_pos_x; + _poly_4_pos_y = poly_4_pos_y; + _time_4_t = time_4_t; + + last_solvable_bounding_box_size = bounding_box_size; + break; + } + } + } + else + { + break; + } + } + #ifdef DEBUG + finish = clock(); + #endif + REQUIRE(last_solvable_bounding_box_size > 0); + + #ifdef DEBUG + { + printf("Solvable bounding box: %d\n", last_solvable_bounding_box_size); + + printf("Final spatio-temporal positions: %.3f, %.3f [%.3f], %.3f, %.3f [%.3f], %.3f, %.3f [%.3f], %.3f, %.3f [%.3f]\n", + _poly_1_pos_x.as_double(), + _poly_1_pos_y.as_double(), + _time_1_t.as_double(), + _poly_2_pos_x.as_double(), + _poly_2_pos_y.as_double(), + _time_2_t.as_double(), + _poly_3_pos_x.as_double(), + _poly_3_pos_y.as_double(), + _time_3_t.as_double(), + _poly_4_pos_x.as_double(), + _poly_4_pos_y.as_double(), + _time_4_t.as_double()); + } + #endif + + #ifdef DEBUG + { + for (int i = 0; i < 2; ++i) + { + double value = X_positions[i].as_double(); + printf("Orig X: %.3f\n", value); + + value = Y_positions[i].as_double(); + printf("Orig Y: %.3f\n", value); + } + } + #endif + + + SVG preview_svg("sequential_test_5.svg"); + + for (unsigned int i = 0; i < unreachable_polygons[0].size(); ++i) + { + Polygon display_pro_polygon_1 = scale_UP(unreachable_polygons[0][i], _poly_1_pos_x.as_double(), _poly_1_pos_y.as_double()); + preview_svg.draw(display_pro_polygon_1, "lightgrey"); + } + + for (unsigned int i = 0; i < unreachable_polygons[1].size(); ++i) + { + Polygon display_pro_polygon_2 = scale_UP(unreachable_polygons[1][i], _poly_2_pos_x.as_double(), _poly_2_pos_y.as_double()); + preview_svg.draw(display_pro_polygon_2, "lightgrey"); + } + + for (unsigned int i = 0; i < unreachable_polygons[2].size(); ++i) + { + Polygon display_pro_polygon_3 = scale_UP(unreachable_polygons[2][i], _poly_3_pos_x.as_double(), _poly_3_pos_y.as_double()); + preview_svg.draw(display_pro_polygon_3, "lightgrey"); + } + + for (unsigned int i = 0; i < unreachable_polygons[3].size(); ++i) + { + Polygon display_pro_polygon_4 = scale_UP(unreachable_polygons[3][i], _poly_4_pos_x.as_double(), _poly_4_pos_y.as_double()); + preview_svg.draw(display_pro_polygon_4, "lightgrey"); + } + + Polygon display_polygon_1 = scale_UP(polygons[0], _poly_1_pos_x.as_double(), _poly_1_pos_y.as_double()); + Polygon display_polygon_2 = scale_UP(polygons[1], _poly_2_pos_x.as_double(), _poly_2_pos_y.as_double()); + Polygon display_polygon_3 = scale_UP(polygons[2], _poly_3_pos_x.as_double(), _poly_3_pos_y.as_double()); + Polygon display_polygon_4 = scale_UP(polygons[3], _poly_4_pos_x.as_double(), _poly_4_pos_y.as_double()); + + preview_svg.draw(display_polygon_1, "green"); + preview_svg.draw(display_polygon_2, "blue"); + preview_svg.draw(display_polygon_3, "red"); + preview_svg.draw(display_polygon_4, "grey"); + + preview_svg.Close(); + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing sequential 5 ... finished"); +} + + +TEST_CASE("Sequential test 6", "[Sequential Arrangement Core]") +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 6 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE / SEQ_SLICER_SCALE_FACTOR, SEQ_QIDI_MK3S_Y_SIZE / SEQ_SLICER_SCALE_FACTOR}); + + vector polygons; + vector unreachable_polygons; + + vector remaining_polygons; + vector polygon_index_map; + vector decided_polygons; + + polygons.push_back(polygon_1); + unreachable_polygons.push_back(unreachable_polygon_1); + polygons.push_back(polygon_2); + unreachable_polygons.push_back(unreachable_polygon_2); + polygons.push_back(polygon_3); + unreachable_polygons.push_back(unreachable_polygon_3); + polygons.push_back(polygon_4); + unreachable_polygons.push_back(unreachable_polygon_4); + + polygons.push_back(polygon_1); + unreachable_polygons.push_back(unreachable_polygon_1); + polygons.push_back(polygon_2); + unreachable_polygons.push_back(unreachable_polygon_2); + polygons.push_back(polygon_3); + unreachable_polygons.push_back(unreachable_polygon_3); + polygons.push_back(polygon_4); + unreachable_polygons.push_back(unreachable_polygon_4); + + polygons.push_back(polygon_1); + unreachable_polygons.push_back(unreachable_polygon_1); + polygons.push_back(polygon_2); + unreachable_polygons.push_back(unreachable_polygon_2); + polygons.push_back(polygon_3); + unreachable_polygons.push_back(unreachable_polygon_3); + polygons.push_back(polygon_4); + unreachable_polygons.push_back(unreachable_polygon_4); + + polygons.push_back(polygon_1); + unreachable_polygons.push_back(unreachable_polygon_1); + polygons.push_back(polygon_2); + unreachable_polygons.push_back(unreachable_polygon_2); + polygons.push_back(polygon_3); + unreachable_polygons.push_back(unreachable_polygon_3); + polygons.push_back(polygon_4); + unreachable_polygons.push_back(unreachable_polygon_4); + + polygons.push_back(polygon_1); + unreachable_polygons.push_back(unreachable_polygon_1); + polygons.push_back(polygon_2); + unreachable_polygons.push_back(unreachable_polygon_2); + polygons.push_back(polygon_3); + unreachable_polygons.push_back(unreachable_polygon_3); + polygons.push_back(polygon_4); + unreachable_polygons.push_back(unreachable_polygon_4); + + #ifdef DEBUG + { + for (unsigned int j = 0; j < unreachable_polygons_1.size(); ++j) + { + for (unsigned int k = 0; k < unreachable_polygons_1[j].points.size(); ++k) + { + printf(" Ppxy: %d, %d\n", unreachable_polygons_1[j].points[k].x(), unreachable_polygons_1[j].points[k].y()); + } + } + } + #endif + + for (unsigned int index = 0; index < polygons.size(); ++index) + { + polygon_index_map.push_back(index); + } + + vector poly_positions_X; + vector poly_positions_Y; + vector times_T; + + do + { + decided_polygons.clear(); + remaining_polygons.clear(); + + bool optimized = optimize_SubglobalSequentialPolygonNonoverlapping(solver_configuration, + poly_positions_X, + poly_positions_Y, + times_T, + polygons, + unreachable_polygons, + polygon_index_map, + decided_polygons, + remaining_polygons); + REQUIRE(optimized); + + #ifdef DEBUG + { + printf("----> Optimization finished <----\n"); + } + #endif + + if (optimized) + { + #ifdef DEBUG + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + printf(" [%d] %.3f, %.3f (%.3f)\n", decided_polygons[i], poly_positions_X[decided_polygons[i]].as_double(), poly_positions_Y[decided_polygons[i]].as_double(), times_T[decided_polygons[i]].as_double()); + } + printf("Remaining polygons: %ld\n", remaining_polygons.size()); + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + printf(" %d\n", remaining_polygons[i]); + } + } + #endif + + SVG preview_svg("sequential_test_6.svg"); + + if (!unreachable_polygons.empty()) + { + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + #ifdef DEBUG + { + printf("----> %.3f,%.3f\n", poly_positions_X[decided_polygons[i]].as_double(), poly_positions_Y[decided_polygons[i]].as_double()); + for (unsigned int k = 0; k < polygons[decided_polygons[i]].points.size(); ++k) + { + printf(" xy: %d, %d\n", polygons[decided_polygons[i]].points[k].x(), polygons[decided_polygons[i]].points[k].y()); + } + } + #endif + + Polygon display_unreachable_polygon = scale_UP(unreachable_polygons[decided_polygons[i]], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double()); + { + preview_svg.draw(display_unreachable_polygon, "lightgrey"); + } + } + } + + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + Polygon display_polygon = scale_UP(polygons[decided_polygons[i]], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double()); + + string color; + + switch(i) + { + case 0: + { + color = "green"; + break; + } + case 1: + { + color = "blue"; + break; + } + case 2: + { + color = "red"; + break; + } + case 3: + { + color = "grey"; + break; + } + case 4: + { + color = "cyan"; + break; + } + case 5: + { + color = "magenta"; + break; + } + case 6: + { + color = "yellow"; + break; + } + case 7: + { + color = "black"; + break; + } + case 8: + { + color = "indigo"; + break; + } + case 9: + { + color = "olive"; + break; + } + case 10: + { + color = "aqua"; + break; + } + case 11: + { + color = "violet"; + break; + } + default: + { + break; + } + } + + preview_svg.draw(display_polygon, color); + } + + preview_svg.Close(); + } + else + { + #ifdef DEBUG + { + printf("Polygon optimization FAILED.\n"); + } + #endif + } + + vector next_polygons; + vector next_unreachable_polygons; + + #ifdef DEBUG + { + for (unsigned int i = 0; i < polygon_index_map.size(); ++i) + { + printf(" %d\n", polygon_index_map[i]); + } + } + #endif + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + next_polygons.push_back(polygons[remaining_polygons[i]]); + next_unreachable_polygons.push_back(unreachable_polygons[remaining_polygons[i]]); + } + + polygons.clear(); + unreachable_polygons.clear(); + polygon_index_map.clear(); + + polygons = next_polygons; + unreachable_polygons = next_unreachable_polygons; + + for (unsigned int index = 0; index < polygons.size(); ++index) + { + polygon_index_map.push_back(index); + } + } + while (!remaining_polygons.empty()); + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing sequential 6 ... finished"); +} + + +TEST_CASE("Sequential test 7", "[Sequential Arrangement Core]") +{ + #ifdef DEBUG + clock_t start, finish; + #endif + + INFO("Testing polygon 7 ..."); + + #ifdef DEBUG + start = clock(); + #endif + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_QIDI_MK3S_X_SIZE / SEQ_SLICER_SCALE_FACTOR, SEQ_QIDI_MK3S_Y_SIZE / SEQ_SLICER_SCALE_FACTOR}); + + vector polygons; + vector > unreachable_polygons; + + vector remaining_polygons; + vector polygon_index_map; + vector decided_polygons; + + polygons.push_back(polygon_1); + unreachable_polygons.push_back(unreachable_polygons_1); + polygons.push_back(polygon_2); + unreachable_polygons.push_back(unreachable_polygons_2); + polygons.push_back(polygon_3); + unreachable_polygons.push_back(unreachable_polygons_3); + polygons.push_back(polygon_4); + unreachable_polygons.push_back(unreachable_polygons_4); + + polygons.push_back(polygon_1); + unreachable_polygons.push_back(unreachable_polygons_1); + polygons.push_back(polygon_2); + unreachable_polygons.push_back(unreachable_polygons_2); + polygons.push_back(polygon_3); + unreachable_polygons.push_back(unreachable_polygons_3); + + polygons.push_back(polygon_1); + unreachable_polygons.push_back(unreachable_polygons_1); + polygons.push_back(polygon_2); + unreachable_polygons.push_back(unreachable_polygons_2); + polygons.push_back(polygon_3); + unreachable_polygons.push_back(unreachable_polygons_3); + polygons.push_back(polygon_4); + unreachable_polygons.push_back(unreachable_polygons_4); + + #ifdef DEBUG + { + for (unsigned int j = 0; j < unreachable_polygons_1.size(); ++j) + { + for (unsigned int k = 0; k < unreachable_polygons_1[j].points.size(); ++k) + { + printf(" Ppxy: %d, %d\n", unreachable_polygons_1[j].points[k].x(), unreachable_polygons_1[j].points[k].y()); + } + } + } + #endif + + for (unsigned int index = 0; index < polygons.size(); ++index) + { + polygon_index_map.push_back(index); + } + + vector poly_positions_X; + vector poly_positions_Y; + vector times_T; + + do + { + decided_polygons.clear(); + remaining_polygons.clear(); + + bool optimized = optimize_SubglobalSequentialPolygonNonoverlapping(solver_configuration, + poly_positions_X, + poly_positions_Y, + times_T, + polygons, + unreachable_polygons, + polygon_index_map, + decided_polygons, + remaining_polygons); + REQUIRE(optimized); + + #ifdef DEBUG + { + printf("----> Optimization finished <----\n"); + } + #endif + + if (optimized) + { + #ifdef DEBUG + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + printf(" [%d] %.3f, %.3f (%.3f)\n", decided_polygons[i], poly_positions_X[decided_polygons[i]].as_double(), poly_positions_Y[decided_polygons[i]].as_double(), times_T[decided_polygons[i]].as_double()); + } + printf("Remaining polygons: %ld\n", remaining_polygons.size()); + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + printf(" %d\n", remaining_polygons[i]); + } + } + #endif + + SVG preview_svg("sequential_test_7.svg"); + + if (!unreachable_polygons.empty()) + { + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + #ifdef DEBUG + { + printf("----> %.3f,%.3f\n", poly_positions_X[decided_polygons[i]].as_double(), poly_positions_Y[decided_polygons[i]].as_double()); + for (unsigned int k = 0; k < polygons[decided_polygons[i]].points.size(); ++k) + { + printf(" xy: %d, %d\n", polygons[decided_polygons[i]].points[k].x(), polygons[decided_polygons[i]].points[k].y()); + } + } + #endif + + for (unsigned int j = 0; j < unreachable_polygons[decided_polygons[i]].size(); ++j) + { + #ifdef DEBUG + { + for (unsigned int k = 0; k < unreachable_polygons[decided_polygons[i]][j].points.size(); ++k) + { + printf(" Pxy: %d, %d\n", unreachable_polygons[decided_polygons[i]][j].points[k].x(), unreachable_polygons[decided_polygons[i]][j].points[k].y()); + } + } + #endif + + Polygon display_unreachable_polygon = scale_UP(unreachable_polygons[decided_polygons[i]][j], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double()); + preview_svg.draw(display_unreachable_polygon, "lightgrey"); + } + } + } + + for (unsigned int i = 0; i < decided_polygons.size(); ++i) + { + Polygon display_polygon = scale_UP(polygons[decided_polygons[i]], + poly_positions_X[decided_polygons[i]].as_double(), + poly_positions_Y[decided_polygons[i]].as_double()); + + string color; + + switch(i) + { + case 0: + { + color = "green"; + break; + } + case 1: + { + color = "blue"; + break; + } + case 2: + { + color = "red"; + break; + } + case 3: + { + color = "grey"; + break; + } + case 4: + { + color = "cyan"; + break; + } + case 5: + { + color = "magenta"; + break; + } + case 6: + { + color = "yellow"; + break; + } + case 7: + { + color = "black"; + break; + } + case 8: + { + color = "indigo"; + break; + } + case 9: + { + color = "olive"; + break; + } + case 10: + { + color = "aqua"; + break; + } + case 11: + { + color = "violet"; + break; + } + default: + { + break; + } + } + + preview_svg.draw(display_polygon, color); + } + + preview_svg.Close(); + } + else + { + #ifdef DEBUG + { + printf("Polygon optimization FAILED.\n"); + } + #endif + } + + vector next_polygons; + vector > next_unreachable_polygons; + + #ifdef DEBUG + { + for (unsigned int i = 0; i < polygon_index_map.size(); ++i) + { + printf(" %d\n", polygon_index_map[i]); + } + } + #endif + for (unsigned int i = 0; i < remaining_polygons.size(); ++i) + { + next_polygons.push_back(polygons[remaining_polygons[i]]); + next_unreachable_polygons.push_back(unreachable_polygons[remaining_polygons[i]]); + } + + polygons.clear(); + unreachable_polygons.clear(); + polygon_index_map.clear(); + + polygons = next_polygons; + unreachable_polygons = next_unreachable_polygons; + + for (unsigned int index = 0; index < polygons.size(); ++index) + { + polygon_index_map.push_back(index); + } + } + while (!remaining_polygons.empty()); + + #ifdef DEBUG + finish = clock(); + #endif + + #ifdef DEBUG + { + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + } + #endif + INFO("Testing sequential 7 ... finished"); +} + + + +/*----------------------------------------------------------------*/ diff --git a/src/libseqarrange/test/seq_test_sequential.hpp b/src/libseqarrange/test/seq_test_sequential.hpp new file mode 100644 index 0000000..c530bd4 --- /dev/null +++ b/src/libseqarrange/test/seq_test_sequential.hpp @@ -0,0 +1,7 @@ +#ifndef __SEQ_TEST_SEQUENTIAL_HPP__ +#define __SEQ_TEST_SEQUENTIAL_HPP__ + +/*----------------------------------------------------------------*/ + + +#endif /* __SEQ_TEST_SEQUENTIAL_HPP__ */ diff --git a/src/slic3r-arrange-wrapper/CMakeLists.txt b/src/slic3r-arrange-wrapper/CMakeLists.txt index 3f723e5..34b64fc 100644 --- a/src/slic3r-arrange-wrapper/CMakeLists.txt +++ b/src/slic3r-arrange-wrapper/CMakeLists.txt @@ -1,7 +1,7 @@ project(slic3r-arrange-wrapper) cmake_minimum_required(VERSION 3.13) -add_library(slic3r-arrange-wrapper +add_library(slic3r-arrange-wrapper STATIC include/arrange-wrapper/Arrange.hpp include/arrange-wrapper/ArrangeSettingsDb_AppCfg.hpp include/arrange-wrapper/ArrangeSettingsView.hpp diff --git a/src/slic3r-arrange/CMakeLists.txt b/src/slic3r-arrange/CMakeLists.txt index 98ab247..36a54ca 100644 --- a/src/slic3r-arrange/CMakeLists.txt +++ b/src/slic3r-arrange/CMakeLists.txt @@ -1,7 +1,7 @@ project(slic3r-arrange) cmake_minimum_required(VERSION 3.13) -add_library(slic3r-arrange +add_library(slic3r-arrange STATIC include/arrange/Beds.hpp include/arrange/ArrangeItemTraits.hpp include/arrange/PackingContext.hpp diff --git a/src/slic3r-arrange/include/arrange/DataStoreTraits.hpp b/src/slic3r-arrange/include/arrange/DataStoreTraits.hpp index 4aca486..32fcaa5 100644 --- a/src/slic3r-arrange/include/arrange/DataStoreTraits.hpp +++ b/src/slic3r-arrange/include/arrange/DataStoreTraits.hpp @@ -67,7 +67,7 @@ template using WritableDataStoreOnly = std::enable_if_t void set_data(ArrItem &itm, const std::string &key, T &&data) { - WritableDataStoreTraits::template set(itm, key, std::forward(data)); + WritableDataStoreTraits::template set<>(itm, key, std::forward(data)); } template constexpr bool IsReadWritableDataStore = IsDataStore && IsWritableDataStore; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8202755..142b584 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,9 @@ # TODO Add individual tests as executables in separate directories # add_subirectory() -find_package(Catch2 2.9 REQUIRED) +find_package(Catch2 3.8 REQUIRED) +slic3r_remap_configs(Catch2::Catch2 RelWithDebInfo Release) +slic3r_remap_configs(Catch2::Catch2WithMain RelWithDebInfo Release) include(Catch) @@ -13,7 +15,7 @@ set(CATCH_EXTRA_ARGS "" CACHE STRING "Extra arguments for catch2 test suites.") add_library(test_common INTERFACE) target_include_directories(test_common INTERFACE ${CMAKE_CURRENT_LIST_DIR}) target_compile_definitions(test_common INTERFACE TEST_DATA_DIR=R"\(${TEST_DATA_DIR}\)" CATCH_CONFIG_FAST_COMPILE) -target_link_libraries(test_common INTERFACE Catch2::Catch2) +target_link_libraries(test_common INTERFACE Catch2::Catch2WithMain) if (APPLE) target_link_libraries(test_common INTERFACE "-liconv -framework IOKit" "-framework CoreFoundation" -lc++) diff --git a/tests/arrange/test_arrange.cpp b/tests/arrange/test_arrange.cpp index 80b9060..27d134e 100644 --- a/tests/arrange/test_arrange.cpp +++ b/tests/arrange/test_arrange.cpp @@ -1,4 +1,7 @@ -#include +#include +#include +#include +#include #include "test_utils.hpp" #include @@ -36,6 +39,8 @@ #include +using namespace Catch; + template static std::vector qidi_parts(double infl = 0.) { using namespace Slic3r; diff --git a/tests/arrange/test_arrange_integration.cpp b/tests/arrange/test_arrange_integration.cpp index 0f91969..e19365c 100644 --- a/tests/arrange/test_arrange_integration.cpp +++ b/tests/arrange/test_arrange_integration.cpp @@ -1,4 +1,11 @@ -#include +#include +#include +#include +#include +#include +#include +#include + #include "test_utils.hpp" #include @@ -11,6 +18,8 @@ #include "libslic3r/Geometry/ConvexHull.hpp" #include "libslic3r/Format/3mf.hpp" +using namespace Catch; + static Slic3r::Model get_example_model_with_20mm_cube() { using namespace Slic3r; diff --git a/tests/catch_main.hpp b/tests/catch_main.hpp index ca5b47d..ef4bf2d 100644 --- a/tests/catch_main.hpp +++ b/tests/catch_main.hpp @@ -4,46 +4,53 @@ #define CATCH_CONFIG_EXTERNAL_INTERFACES #define CATCH_CONFIG_MAIN // #define CATCH_CONFIG_DEFAULT_REPORTER "verboseconsole" -#include +#include + +#include namespace Catch { -struct VerboseConsoleReporter : public ConsoleReporter { +struct VerboseConsoleReporter : public StreamingReporterBase { double duration = 0.; - using ConsoleReporter::ConsoleReporter; + using StreamingReporterBase::StreamingReporterBase; + + static std::string getDescription() { + return "Verbose Console Reporter"; + } + void testCaseStarting(TestCaseInfo const& _testInfo) override { - Colour::use(Colour::Cyan); - stream << "Testing "; - Colour::use(Colour::None); - stream << _testInfo.name << std::endl; - ConsoleReporter::testCaseStarting(_testInfo); + //Colour::use(Colour::Cyan); + m_stream << "Testing "; + //Colour::use(Colour::None); + m_stream << _testInfo.name << std::endl; + StreamingReporterBase::testCaseStarting(_testInfo); } void sectionStarting(const SectionInfo &_sectionInfo) override { if (_sectionInfo.name != currentTestCaseInfo->name) - stream << _sectionInfo.name << std::endl; + m_stream << _sectionInfo.name << std::endl; - ConsoleReporter::sectionStarting(_sectionInfo); + StreamingReporterBase::sectionStarting(_sectionInfo); } void sectionEnded(const SectionStats &_sectionStats) override { duration += _sectionStats.durationInSeconds; - ConsoleReporter::sectionEnded(_sectionStats); + StreamingReporterBase::sectionEnded(_sectionStats); } void testCaseEnded(TestCaseStats const& stats) override { if (stats.totals.assertions.allOk()) { - Colour::use(Colour::BrightGreen); - stream << "Passed"; - Colour::use(Colour::None); - stream << " in " << duration << " [seconds]\n" << std::endl; + //Colour::use(Colour::BrightGreen); + m_stream << "Passed"; + //Colour::use(Colour::None); + m_stream << " in " << duration << " [seconds]\n" << std::endl; } duration = 0.; - ConsoleReporter::testCaseEnded(stats); + StreamingReporterBase::testCaseEnded(stats); } }; diff --git a/tests/data/sla_islands/SPE-2674.svg b/tests/data/sla_islands/SPE-2674.svg new file mode 100644 index 0000000..c548517 --- /dev/null +++ b/tests/data/sla_islands/SPE-2674.svg @@ -0,0 +1,5 @@ + + + diff --git a/tests/data/sla_islands/SPE-2674_2.svg b/tests/data/sla_islands/SPE-2674_2.svg new file mode 100644 index 0000000..96c36ac --- /dev/null +++ b/tests/data/sla_islands/SPE-2674_2.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/tests/data/sla_islands/SPE-2709.svg b/tests/data/sla_islands/SPE-2709.svg new file mode 100644 index 0000000..3b31bc5 --- /dev/null +++ b/tests/data/sla_islands/SPE-2709.svg @@ -0,0 +1,1176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part +thin_part_change +thin_part +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_inner +thick_part_inner +thick_part_inner +thick_part_inner +thick_part_inner +thick_part_inner diff --git a/tests/data/sla_islands/lm_issue.svg b/tests/data/sla_islands/lm_issue.svg new file mode 100644 index 0000000..1424e64 --- /dev/null +++ b/tests/data/sla_islands/lm_issue.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt index 880b54a..f9feae6 100644 --- a/tests/fff_print/CMakeLists.txt +++ b/tests/fff_print/CMakeLists.txt @@ -14,6 +14,7 @@ add_executable(${_TEST_NAME}_tests test_gaps.cpp test_gcode.cpp test_gcode_travels.cpp + test_infill_above_bridges.cpp test_seam_perimeters.cpp test_seam_shells.cpp test_seam_geometry.cpp diff --git a/tests/fff_print/benchmark_seams.cpp b/tests/fff_print/benchmark_seams.cpp index 8eeeb9c..708e3c1 100644 --- a/tests/fff_print/benchmark_seams.cpp +++ b/tests/fff_print/benchmark_seams.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include "test_data.hpp" #include "libslic3r/GCode/SeamGeometry.hpp" diff --git a/tests/fff_print/test_avoid_crossing_perimeters.cpp b/tests/fff_print/test_avoid_crossing_perimeters.cpp index a76ac12..fb498c9 100644 --- a/tests/fff_print/test_avoid_crossing_perimeters.cpp +++ b/tests/fff_print/test_avoid_crossing_perimeters.cpp @@ -1,4 +1,4 @@ -#include +#include #include "test_data.hpp" diff --git a/tests/fff_print/test_bridges.cpp b/tests/fff_print/test_bridges.cpp index 91ab9b6..817ea7c 100644 --- a/tests/fff_print/test_bridges.cpp +++ b/tests/fff_print/test_bridges.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/fff_print/test_cancel_object.cpp b/tests/fff_print/test_cancel_object.cpp index 3e0b0e0..8c2abb3 100644 --- a/tests/fff_print/test_cancel_object.cpp +++ b/tests/fff_print/test_cancel_object.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include #include @@ -7,6 +8,7 @@ using namespace Slic3r; using namespace Test; +using namespace Catch; constexpr bool debug_files{false}; @@ -168,7 +170,7 @@ TEST_CASE_METHOD(CancelObjectFixture, "Single extruder", "[CancelObject]") { } TEST_CASE_METHOD(CancelObjectFixture, "Sequential print", "[CancelObject]") { - config.set_deserialize_strict({{"complete_objects", 1}}); + config.set_deserialize_strict({{"complete_objects", 1} }); Print print; print.apply(two_cubes, config); diff --git a/tests/fff_print/test_clipper.cpp b/tests/fff_print/test_clipper.cpp index 5968769..0e24235 100644 --- a/tests/fff_print/test_clipper.cpp +++ b/tests/fff_print/test_clipper.cpp @@ -1,4 +1,4 @@ -#include +#include #include "test_data.hpp" #include "libslic3r/ClipperZUtils.hpp" diff --git a/tests/fff_print/test_cooling.cpp b/tests/fff_print/test_cooling.cpp index 187d7f4..62b74cc 100644 --- a/tests/fff_print/test_cooling.cpp +++ b/tests/fff_print/test_cooling.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/fff_print/test_custom_gcode.cpp b/tests/fff_print/test_custom_gcode.cpp index 2dd97e9..bbac816 100644 --- a/tests/fff_print/test_custom_gcode.cpp +++ b/tests/fff_print/test_custom_gcode.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/fff_print/test_data.cpp b/tests/fff_print/test_data.cpp index 9dbd1c7..65ee9d9 100644 --- a/tests/fff_print/test_data.cpp +++ b/tests/fff_print/test_data.cpp @@ -1,3 +1,4 @@ +#include #include "test_data.hpp" #include "libslic3r/TriangleMesh.hpp" @@ -399,7 +400,6 @@ bool contains_regex(const std::string &data, const std::string &pattern) } } // namespace Slic3r::Test -#include SCENARIO("init_print functionality", "[test_data]") { GIVEN("A default config") { diff --git a/tests/fff_print/test_data.hpp b/tests/fff_print/test_data.hpp index 9eee9c9..ac0548b 100644 --- a/tests/fff_print/test_data.hpp +++ b/tests/fff_print/test_data.hpp @@ -14,7 +14,7 @@ #include "libslic3r/GCode/SeamPlacer.hpp" #include "libslic3r/GCode/SeamAligned.hpp" -#include +#include #include namespace Slic3r { namespace Test { @@ -159,7 +159,7 @@ std::string slice( bool contains(const std::string &data, const std::string &pattern); bool contains_regex(const std::string &data, const std::string &pattern); -inline std::unique_ptr process_3mf(const std::filesystem::path &path) { +inline std::unique_ptr process_3mf(const boost::filesystem::path &path) { DynamicPrintConfig config; auto print{std::make_unique()}; Model model; @@ -176,7 +176,7 @@ inline std::unique_ptr process_3mf(const std::filesystem::path &path) { static std::map> prints_3mfs; // Lazy getter, to avoid processing the 3mf multiple times, it already takes ages. -inline Print *get_print(const std::filesystem::path &file_path) { +inline Print *get_print(const boost::filesystem::path &file_path) { if (!prints_3mfs.count(file_path.string())) { prints_3mfs[file_path.string()] = process_3mf(file_path.string()); } @@ -204,8 +204,8 @@ inline void serialize_seam(std::ostream &output, const std::vectorobjects()[0]}; diff --git a/tests/fff_print/test_extrusion_entity.cpp b/tests/fff_print/test_extrusion_entity.cpp index 0698f5e..33ca3f4 100644 --- a/tests/fff_print/test_extrusion_entity.cpp +++ b/tests/fff_print/test_extrusion_entity.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include @@ -11,6 +12,7 @@ #include "test_data.hpp" using namespace Slic3r; +using namespace Catch; static inline Slic3r::Point random_point(float LO=-50, float HI=50) { diff --git a/tests/fff_print/test_fill.cpp b/tests/fff_print/test_fill.cpp index 94b6cab..2047d39 100644 --- a/tests/fff_print/test_fill.cpp +++ b/tests/fff_print/test_fill.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/fff_print/test_flow.cpp b/tests/fff_print/test_flow.cpp index b24b59c..037c17c 100644 --- a/tests/fff_print/test_flow.cpp +++ b/tests/fff_print/test_flow.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include #include @@ -12,6 +13,7 @@ using namespace Slic3r::Test; using namespace Slic3r; +using namespace Catch; SCENARIO("Extrusion width specifics", "[Flow]") { diff --git a/tests/fff_print/test_gaps.cpp b/tests/fff_print/test_gaps.cpp index a096087..d1f921c 100644 --- a/tests/fff_print/test_gaps.cpp +++ b/tests/fff_print/test_gaps.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/GCodeReader.hpp" #include "libslic3r/Geometry/ConvexHull.hpp" diff --git a/tests/fff_print/test_gcode.cpp b/tests/fff_print/test_gcode.cpp index 8af6fe4..7603fc6 100644 --- a/tests/fff_print/test_gcode.cpp +++ b/tests/fff_print/test_gcode.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include #include @@ -10,6 +11,7 @@ using namespace Slic3r; using namespace Test; +using namespace Catch; constexpr bool debug_files = false; @@ -61,7 +63,7 @@ TEST_CASE("Wiping speeds", "[GCode]") { INFO("Wipe moves don\'t retract faster than configured speed"); CHECK(retract_speed < expected_retract_speed); } - INFO("No wiping after layer change") + INFO("No wiping after layer change"); CHECK(!wiping_on_new_layer); } @@ -115,12 +117,12 @@ std::optional parse_axis(const std::string& line, const std::string& axi * - no travel moves go outside skirt * - temperatures are set correctly */ -TEST_CASE("Extrusion, travels, temeperatures", "[GCode]") { +TEST_CASE("Extrusion, travels, temperatures", "[GCode]") { DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); config.set_deserialize_strict({ { "gcode_comments", 1 }, { "complete_objects", 1 }, - { "extrusion_axis", 'A' }, + { "extrusion_axis", "A" }, { "start_gcode", "" }, // prevent any default extra Z move { "layer_height", 0.4 }, { "first_layer_height", 0.4 }, @@ -170,6 +172,11 @@ TEST_CASE("Extrusion, travels, temeperatures", "[GCode]") { } }); + // Remove last travel_moves returning to origin + if (travel_moves.back().x() == 0 && travel_moves.back().y() == 0) { + travel_moves.pop_back(); + } + const unsigned layer_count = 20 / 0.4; INFO("Complete_objects generates the correct number of Z moves."); CHECK(z_moves.size() == layer_count * 2); @@ -188,20 +195,30 @@ TEST_CASE("Extrusion, travels, temeperatures", "[GCode]") { TEST_CASE("Used filament", "[GCode]") { - DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); - config.set_deserialize_strict({ - { "retract_length", "1000000" }, + DynamicPrintConfig config1 = Slic3r::DynamicPrintConfig::full_print_config(); + config1.set_deserialize_strict({ + { "retract_length", "0" }, { "use_relative_e_distances", 1 }, { "layer_gcode", "G92 E0\n" }, }); - GCodeReader parser; - Print print; - Model model; - Test::init_print({TestMesh::cube_20x20x20}, print, model, config); - Test::gcode(print); + Print print1; + Model model1; + Test::init_print({TestMesh::cube_20x20x20}, print1, model1, config1); + Test::gcode(print1); + + DynamicPrintConfig config2 = Slic3r::DynamicPrintConfig::full_print_config(); + config2.set_deserialize_strict({ + { "retract_length", "999" }, + { "use_relative_e_distances", 1 }, + { "layer_gcode", "G92 E0\n" }, + }); + Print print2; + Model model2; + Test::init_print({TestMesh::cube_20x20x20}, print2, model2, config2); + Test::gcode(print2); INFO("Final retraction is not considered in total used filament"); - CHECK(print.print_statistics().total_used_filament > 0); + CHECK(print1.print_statistics().total_used_filament == print2.print_statistics().total_used_filament); } void check_m73s(Print& print){ diff --git a/tests/fff_print/test_gcode_travels.cpp b/tests/fff_print/test_gcode_travels.cpp index 895c415..95d9d64 100644 --- a/tests/fff_print/test_gcode_travels.cpp +++ b/tests/fff_print/test_gcode_travels.cpp @@ -1,4 +1,6 @@ -#include +#include +#include +#include #include #include #include @@ -6,8 +8,9 @@ using namespace Slic3r; using namespace Slic3r::GCode::Impl::Travels; +using namespace Catch; -struct ApproxEqualsPoints : public Catch::MatcherBase { +struct ApproxEqualsPoints : public Catch::Matchers::MatcherBase { ApproxEqualsPoints(const Points& expected, unsigned tolerance): expected(expected), tolerance(tolerance) {} bool match(const Points& points) const override { if (points.size() != expected.size()) { diff --git a/tests/fff_print/test_gcodefindreplace.cpp b/tests/fff_print/test_gcodefindreplace.cpp index 1d714d1..d6c72a8 100644 --- a/tests/fff_print/test_gcodefindreplace.cpp +++ b/tests/fff_print/test_gcodefindreplace.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/tests/fff_print/test_gcodewriter.cpp b/tests/fff_print/test_gcodewriter.cpp index 93888a9..a53b882 100644 --- a/tests/fff_print/test_gcodewriter.cpp +++ b/tests/fff_print/test_gcodewriter.cpp @@ -1,10 +1,15 @@ -#include +#include +#include +#include +#include #include #include "libslic3r/GCode/GCodeWriter.hpp" +#include "libslic3r/GCodeReader.hpp" using namespace Slic3r; +using Catch::Approx; SCENARIO("set_speed emits values with fixed-point output.", "[GCodeWriter]") { @@ -12,23 +17,523 @@ SCENARIO("set_speed emits values with fixed-point output.", "[GCodeWriter]") { GCodeWriter writer; WHEN("set_speed is called to set speed to 99999.123") { THEN("Output string is G1 F99999.123") { - REQUIRE_THAT(writer.set_speed(99999.123), Catch::Equals("G1 F99999.123\n")); + REQUIRE_THAT(writer.set_speed(99999.123), Catch::Matchers::Equals("G1 F99999.123\n")); } } WHEN("set_speed is called to set speed to 1") { THEN("Output string is G1 F1") { - REQUIRE_THAT(writer.set_speed(1.0), Catch::Equals("G1 F1\n")); + REQUIRE_THAT(writer.set_speed(1.0), Catch::Matchers::Equals("G1 F1\n")); } } WHEN("set_speed is called to set speed to 203.200022") { THEN("Output string is G1 F203.2") { - REQUIRE_THAT(writer.set_speed(203.200022), Catch::Equals("G1 F203.2\n")); + REQUIRE_THAT(writer.set_speed(203.200022), Catch::Matchers::Equals("G1 F203.2\n")); } } WHEN("set_speed is called to set speed to 203.200522") { THEN("Output string is G1 F203.201") { - REQUIRE_THAT(writer.set_speed(203.200522), Catch::Equals("G1 F203.201\n")); + REQUIRE_THAT(writer.set_speed(203.200522), Catch::Matchers::Equals("G1 F203.201\n")); } } } } + +void check_gcode_feedrate(const std::string& gcode, const GCodeConfig& config, double expected_speed) { + GCodeReader parser; + parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + + const double travel_speed = config.opt_float("travel_speed"); + + const double feedrate = line.has_f() ? line.f() : self.f(); + CHECK(feedrate == Approx(expected_speed * 60).epsilon(GCodeFormatter::XYZ_EPSILON)); + + if (line.dist_Z(self) != 0) { + // lift move or lift + change layer + const double travel_speed_z = config.opt_float("travel_speed_z"); + if (travel_speed_z) { + Vec3d move{line.dist_X(self), line.dist_Y(self), line.dist_Z(self)}; + double move_u_z = move.z() / move.norm(); + double travel_speed_ = std::abs(travel_speed_z / move_u_z); + INFO("move Z feedrate Z component is less than or equal to travel_speed_z"); + CHECK(feedrate * std::abs(move_u_z) <= Approx(travel_speed_z * 60).epsilon(GCodeFormatter::XYZ_EPSILON)); + if (travel_speed_ < travel_speed) { + INFO("move Z at travel speed Z"); + CHECK(feedrate == Approx(travel_speed_ * 60).epsilon(GCodeFormatter::XYZ_EPSILON)); + INFO("move Z feedrate Z component is equal to travel_speed_z"); + CHECK(feedrate * std::abs(move_u_z) == Approx(travel_speed_z * 60).epsilon(GCodeFormatter::XYZ_EPSILON)); + } else { + INFO("move Z at travel speed"); + CHECK(feedrate == Approx(travel_speed * 60).epsilon(GCodeFormatter::XYZ_EPSILON)); + } + } else { + INFO("move Z at travel speed"); + CHECK(feedrate == Approx(travel_speed * 60).epsilon(GCodeFormatter::XYZ_EPSILON)); + } + } else if (not line.extruding(self)) { + // normal move + INFO("move XY at travel speed"); + CHECK(feedrate == Approx(travel_speed * 60)); + } + }); +} + +SCENARIO("travel_speed_z is zero should use travel_speed.", "[GCodeWriter]") { + GIVEN("GCodeWriter instance") { + GCodeWriter writer; + WHEN("travel_speed_z is set to 0") { + writer.config.travel_speed.value = 1000; + writer.config.travel_speed_z.value = 0; + THEN("XYZ move feed rate should be equal to travel_speed") { + const Vec3d move{10, 10, 10}; + const double speed = writer.config.travel_speed.value; + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + } + } +} + +SCENARIO("travel_speed_z is respected in Z speed component.", "[GCodeWriter]") { + GIVEN("GCodeWriter instance") { + GCodeWriter writer; + WHEN("travel_speed_z is set to 10") { + writer.config.travel_speed.value = 1000; + writer.config.travel_speed_z.value = 10; + THEN("Z move feed rate should be equal to travel_speed_z") { + const Vec3d move{0, 0, 10}; + const double speed = writer.config.travel_speed_z.value; + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("-Z move feed rate should be equal to travel_speed_z") { + const Vec3d move{0, 0, -10}; + const double speed = writer.config.travel_speed_z.value; + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("XY move feed rate should be equal to travel_speed") { + const Vec3d move{10, 10, 0}; + const double speed = writer.config.travel_speed.value; + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("-XY move feed rate should be equal to travel_speed") { + const Vec3d move{-10, 10, 0}; + const double speed = writer.config.travel_speed.value; + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("X-Y move feed rate should be equal to travel_speed") { + const Vec3d move{10, -10, 0}; + const double speed = writer.config.travel_speed.value; + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("-X-Y move feed rate should be equal to travel_speed") { + const Vec3d move{-10, -10, 0}; + const double speed = writer.config.travel_speed.value; + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("XZ move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{10, 0, 10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + Vec3d p1 = writer.get_position(); + Vec3d p2 = p1 + move; + std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("-XZ move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{-10, 0, 10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("X-Z move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{10, 0, -10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("-X-Z move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{-10, 0, -10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("YZ move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{0, 10, 10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("-YZ move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{0, -10, 10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("Y-Z move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{0, 10, -10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("-Y-Z move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{0, -10, -10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("XYZ move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{10, 10, 10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("-XYZ move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{-10, 10, 10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("X-YZ move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{10, -10, 10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("-X-YZ move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{-10, -10, 10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("XY-Z move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{10, 10, -10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("-XY-Z move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{-10, 10, -10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("X-Y-Z move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{10, -10, -10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + THEN("-X-Y-Z move feed rate Z component should be equal to travel_speed_z") { + const Vec3d move{-10, -10, -10}; + const Vec3d move_u = move / move.norm(); + const double speed = std::abs(writer.config.travel_speed_z.value / move_u.z()); + const Vec3d p1 = writer.get_position(); + const Vec3d p2 = p1 + move; + const std::string result = writer.travel_to_xyz(p2); + check_gcode_feedrate(result, writer.config, speed); + } + } + } +} + +TEST_CASE("GCodeWriter emits G1 code correctly according to XYZF_EXPORT_DIGITS", "[GCodeWriter]") { + GCodeWriter writer; + + SECTION("Check quantize") { + CHECK(GCodeFormatter::quantize(1.0,0) == 1.); + CHECK(GCodeFormatter::quantize(0.0,0) == 0.); + CHECK(GCodeFormatter::quantize(0.1,0) == 0); + + CHECK(GCodeFormatter::quantize(1.0,1) == 1.); + CHECK(GCodeFormatter::quantize(0.0,1) == 0.); + CHECK(GCodeFormatter::quantize(0.1,1) == Approx(0.1)); + CHECK(GCodeFormatter::quantize(0.01,1) == 0.); + + CHECK(GCodeFormatter::quantize(1.0,2) == 1.); + CHECK(GCodeFormatter::quantize(0.0,2) == 0.); + CHECK(GCodeFormatter::quantize(0.1,2) == Approx(0.1)); + CHECK(GCodeFormatter::quantize(0.01,2) == Approx(0.01)); + CHECK(GCodeFormatter::quantize(0.001,2) == 0.); + + CHECK(GCodeFormatter::quantize(1.0,3) == 1.); + CHECK(GCodeFormatter::quantize(0.0,3) == 0.); + CHECK(GCodeFormatter::quantize(0.1,3) == Approx(0.1)); + CHECK(GCodeFormatter::quantize(0.01,3) == Approx(0.01)); + CHECK(GCodeFormatter::quantize(0.001,3) == Approx(0.001)); + CHECK(GCodeFormatter::quantize(0.0001,3) == 0.); + + CHECK(GCodeFormatter::quantize(1.0,4) == 1.); + CHECK(GCodeFormatter::quantize(0.0,4) == 0.); + CHECK(GCodeFormatter::quantize(0.1,4) == Approx(0.1)); + CHECK(GCodeFormatter::quantize(0.01,4) == Approx(0.01)); + CHECK(GCodeFormatter::quantize(0.001,4) == Approx(0.001)); + CHECK(GCodeFormatter::quantize(0.0001,4) == Approx(0.0001)); + CHECK(GCodeFormatter::quantize(0.00001,4) == 0.); + + CHECK(GCodeFormatter::quantize(1.0,5) == 1.); + CHECK(GCodeFormatter::quantize(0.0,5) == 0.); + CHECK(GCodeFormatter::quantize(0.1,5) == Approx(0.1)); + CHECK(GCodeFormatter::quantize(0.01,5) == Approx(0.01)); + CHECK(GCodeFormatter::quantize(0.001,5) == Approx(0.001)); + CHECK(GCodeFormatter::quantize(0.0001,5) == Approx(0.0001)); + CHECK(GCodeFormatter::quantize(0.00001,5) == Approx(0.00001)); + CHECK(GCodeFormatter::quantize(0.000001,5) == 0.); + + CHECK(GCodeFormatter::quantize(1.0,6) == 1.); + CHECK(GCodeFormatter::quantize(0.0,6) == 0.); + CHECK(GCodeFormatter::quantize(0.1,6) == Approx(0.1)); + CHECK(GCodeFormatter::quantize(0.01,6) == Approx(0.01)); + CHECK(GCodeFormatter::quantize(0.001,6) == Approx(0.001)); + CHECK(GCodeFormatter::quantize(0.0001,6) == Approx(0.0001)); + CHECK(GCodeFormatter::quantize(0.00001,6) == Approx(0.00001)); + CHECK(GCodeFormatter::quantize(0.000001,6) == Approx(0.000001)); + CHECK(GCodeFormatter::quantize(0.0000001,6) == 0.); + } + + SECTION("Check pow_10") { + // IEEE 754 floating point numbers can represent these numbers EXACTLY. + CHECK(GCodeFormatter::pow_10[0] == 1.); + CHECK(GCodeFormatter::pow_10[1] == 10.); + CHECK(GCodeFormatter::pow_10[2] == 100.); + CHECK(GCodeFormatter::pow_10[3] == 1000.); + CHECK(GCodeFormatter::pow_10[4] == 10000.); + CHECK(GCodeFormatter::pow_10[5] == 100000.); + CHECK(GCodeFormatter::pow_10[6] == 1000000.); + CHECK(GCodeFormatter::pow_10[7] == 10000000.); + CHECK(GCodeFormatter::pow_10[8] == 100000000.); + CHECK(GCodeFormatter::pow_10[9] == 1000000000.); + } + + SECTION("Check pow_10_inv") { + // IEEE 754 floating point numbers can NOT represent these numbers exactly. + CHECK(GCodeFormatter::pow_10_inv[0] == 1.); + CHECK(GCodeFormatter::pow_10_inv[1] == 0.1); + CHECK(GCodeFormatter::pow_10_inv[2] == 0.01); + CHECK(GCodeFormatter::pow_10_inv[3] == 0.001); + CHECK(GCodeFormatter::pow_10_inv[4] == 0.0001); + CHECK(GCodeFormatter::pow_10_inv[5] == 0.00001); + CHECK(GCodeFormatter::pow_10_inv[6] == 0.000001); + CHECK(GCodeFormatter::pow_10_inv[7] == 0.0000001); + CHECK(GCodeFormatter::pow_10_inv[8] == 0.00000001); + CHECK(GCodeFormatter::pow_10_inv[9] == 0.000000001); + } + + SECTION("travel_to_z Emit G1 code for very significant movement") { + double z1 = 10.0; + std::string result1{ writer.travel_to_z(z1) }; + CHECK(result1 == "G1 Z10 F7800\n"); + + double z2 = z1 * 2; + std::string result2{ writer.travel_to_z(z2) }; + CHECK(result2 == "G1 Z20 F7800\n"); + } + + SECTION("travel_to_z Emit G1 code for significant movement") { + double z1 = 10.0; + std::string result1{ writer.travel_to_z(z1) }; + CHECK(result1 == "G1 Z10 F7800\n"); + + // This should test with XYZ_EPSILON exactly, + // but IEEE 754 floating point numbers cannot pass the test. + double z2 = z1 + GCodeFormatter::XYZ_EPSILON * 1.001; + std::string result2{ writer.travel_to_z(z2) }; + + std::ostringstream oss; + oss << "G1 Z" + << GCodeFormatter::quantize_xyzf(z2) + << " F7800\n"; + + CHECK(result2 == oss.str()); + } + + SECTION("travel_to_z Do not emit G1 code for insignificant movement") { + double z1 = 10.0; + std::string result1{ writer.travel_to_z(z1) }; + CHECK(result1 == "G1 Z10 F7800\n"); + + // Movement smaller than XYZ_EPSILON + double z2 = z1 + (GCodeFormatter::XYZ_EPSILON * 0.999); + std::string result2{ writer.travel_to_z(z2) }; + CHECK(result2 == ""); + + double z3 = z1 + (GCodeFormatter::XYZ_EPSILON * 0.1); + std::string result3{ writer.travel_to_z(z3) }; + CHECK(result3 == ""); + } + + SECTION("travel_to_xyz Emit G1 code for very significant movement") { + Vec3d v1{10.0, 10.0, 10.0}; + std::string result1{ writer.travel_to_xyz(v1) }; + CHECK(result1 == "G1 X10 Y10 Z10 F7800\n"); + + Vec3d v2 = v1 * 2; + std::string result2{ writer.travel_to_xyz(v2) }; + CHECK(result2 == "G1 X20 Y20 Z20 F7800\n"); + } + + SECTION("travel_to_xyz Emit G1 code for significant XYZ movement") { + Vec3d v1{10.0, 10.0, 10.0}; + std::string result1{ writer.travel_to_xyz(v1) }; + CHECK(result1 == "G1 X10 Y10 Z10 F7800\n"); + + Vec3d v2 = v1; + // This should test with XYZ_EPSILON exactly, + // but IEEE 754 floating point numbers cannot pass the test. + v2.array() += GCodeFormatter::XYZ_EPSILON * 1.001; + std::string result2{ writer.travel_to_xyz(v2) }; + + std::ostringstream oss; + oss << "G1 X" + << GCodeFormatter::quantize_xyzf(v2.x()) + << " Y" + << GCodeFormatter::quantize_xyzf(v2.y()) + << " Z" + << GCodeFormatter::quantize_xyzf(v2.z()) + << " F7800\n"; + + CHECK(result2 == oss.str()); + } + + SECTION("travel_to_xyz Emit G1 code for significant X movement") { + Vec3d v1{10.0, 10.0, 10.0}; + std::string result1{ writer.travel_to_xyz(v1) }; + CHECK(result1 == "G1 X10 Y10 Z10 F7800\n"); + + Vec3d v2 = v1; + // This should test with XYZ_EPSILON exactly, + // but IEEE 754 floating point numbers cannot pass the test. + v2.x() += GCodeFormatter::XYZ_EPSILON * 1.001; + std::string result2{ writer.travel_to_xyz(v2) }; + + std::ostringstream oss; + // Only X needs to be emitted in this case, + // but this is how the code currently works. + oss << "G1 X" + << GCodeFormatter::quantize_xyzf(v2.x()) + << " Y" + << GCodeFormatter::quantize_xyzf(v2.y()) + << " F7800\n"; + + CHECK(result2 == oss.str()); + } + + SECTION("travel_to_xyz Emit G1 code for significant Y movement") { + Vec3d v1{10.0, 10.0, 10.0}; + std::string result1{ writer.travel_to_xyz(v1) }; + CHECK(result1 == "G1 X10 Y10 Z10 F7800\n"); + + Vec3d v2 = v1; + // This should test with XYZ_EPSILON exactly, + // but IEEE 754 floating point numbers cannot pass the test. + v2.y() += GCodeFormatter::XYZ_EPSILON * 1.001; + std::string result2{ writer.travel_to_xyz(v2) }; + + std::ostringstream oss; + // Only Y needs to be emitted in this case, + // but this is how the code currently works. + oss << "G1 X" + << GCodeFormatter::quantize_xyzf(v2.x()) + << " Y" + << GCodeFormatter::quantize_xyzf(v2.y()) + << " F7800\n"; + + CHECK(result2 == oss.str()); + } + + SECTION("travel_to_xyz Emit G1 code for significant Z movement") { + Vec3d v1{10.0, 10.0, 10.0}; + std::string result1{ writer.travel_to_xyz(v1) }; + CHECK(result1 == "G1 X10 Y10 Z10 F7800\n"); + + Vec3d v2 = v1; + // This should test with XYZ_EPSILON exactly, + // but IEEE 754 floating point numbers cannot pass the test. + v2.z() += GCodeFormatter::XYZ_EPSILON * 1.001; + std::string result2{ writer.travel_to_xyz(v2) }; + + std::ostringstream oss; + oss << "G1 Z" + << GCodeFormatter::quantize_xyzf(v2.z()) + << " F7800\n"; + + CHECK(result2 == oss.str()); + } + + SECTION("travel_to_xyz Do not emit G1 code for insignificant movement") { + Vec3d v1{10.0, 10.0, 10.0}; + std::string result1{ writer.travel_to_xyz(v1) }; + CHECK(result1 == "G1 X10 Y10 Z10 F7800\n"); + + // Movement smaller than XYZ_EPSILON + Vec3d v2 = v1; + v2.array() += GCodeFormatter::XYZ_EPSILON * 0.999; + std::string result2{ writer.travel_to_xyz(v2) }; + CHECK(result2 == ""); + + Vec3d v3 = v1; + v3.array() += GCodeFormatter::XYZ_EPSILON * 0.1; + std::string result3{ writer.travel_to_xyz(v3) }; + CHECK(result3 == ""); + } +} \ No newline at end of file diff --git a/tests/fff_print/test_infill_above_bridges.cpp b/tests/fff_print/test_infill_above_bridges.cpp new file mode 100644 index 0000000..a3d172b --- /dev/null +++ b/tests/fff_print/test_infill_above_bridges.cpp @@ -0,0 +1,83 @@ +#include +#include +#include + +using namespace Slic3r; +using Catch::Approx; + +const ExPolygon square{ + Point::new_scale(0, 0), + Point::new_scale(10, 0), + Point::new_scale(10, 10), + Point::new_scale(0, 10) +}; + +ExPolygon translate(const ExPolygon &polygon, const Point &offset) { + ExPolygons result{polygon}; + translate(result, offset); + return result.front(); +} + +constexpr bool debug_files{false}; + +void draw_surfaces(const PrepareInfill::SurfaceRefsByRegion &surfaces, std::string_view file_name) { + using PrepareInfill::SurfaceCollectionRef; + + SurfaceCollection to_display; + for (const SurfaceCollectionRef &surface_collection : surfaces) { + to_display.append(surface_collection.get()); + } + to_display.export_to_svg(file_name.data(), false); +} + +TEST_CASE("Separate infill above bridges", "[PrepareInfill]") { + ExPolygons layer_0_region_0_bridge{ + square + }; + ExPolygons layer_0_region_0_internal{ + translate(square, Point::new_scale(10, 0)) + }; + ExPolygons layer_0_region_1_internal{ + translate(square, Point::new_scale(0, 10)) + }; + ExPolygons layer_0_region_1_bridge{ + translate(square, Point::new_scale(10, 10)) + }; + SurfaceCollection layer_0_region_0; + layer_0_region_0.append(layer_0_region_0_bridge, stBottomBridge); + layer_0_region_0.append(layer_0_region_0_internal, stInternal); + SurfaceCollection layer_0_region_1; + layer_0_region_1.append(layer_0_region_1_bridge, stBottomBridge); + layer_0_region_1.append(layer_0_region_1_internal, stInternal); + + PrepareInfill::SurfaceRefsByRegion layer_0{layer_0_region_0, layer_0_region_1}; + + ExPolygons layer_1_region_0_solid{ + translate(square, Point::new_scale(5, 5)) + }; + SurfaceCollection layer_1_region_0; + layer_1_region_0.append(layer_1_region_0_solid, stInternalSolid); + PrepareInfill::SurfaceRefsByRegion layer_1{layer_1_region_0}; + + if constexpr (debug_files) { + draw_surfaces(layer_0, "layer_0.svg"); + } + + PrepareInfill::separate_infill_above_bridges({layer_0, layer_1}, 0); + + if constexpr (debug_files) { + draw_surfaces(layer_1, "layer_1.svg"); + } + + const Surfaces &result{layer_1.front().get().surfaces}; + REQUIRE(result.size() == 4); + const double expected_area{scale_(5.0) * scale_(5.0)}; + CHECK(result[0].expolygon.contour.area() == Approx(expected_area)); + CHECK(result[0].surface_type == stInternalSolid); + CHECK(result[1].expolygon.contour.area() == Approx(expected_area)); + CHECK(result[1].surface_type == stInternalSolid); + CHECK(result[2].expolygon.contour.area() == Approx(expected_area)); + CHECK(result[2].surface_type == stSolidOverBridge); + CHECK(result[3].expolygon.contour.area() == Approx(expected_area)); + CHECK(result[3].surface_type == stSolidOverBridge); +} diff --git a/tests/fff_print/test_layers.cpp b/tests/fff_print/test_layers.cpp index 87accd3..596a9f6 100644 --- a/tests/fff_print/test_layers.cpp +++ b/tests/fff_print/test_layers.cpp @@ -2,11 +2,13 @@ * Ported from t/layers.t */ -#include +#include +#include #include "test_data.hpp" using namespace Slic3r; using namespace Slic3r::Test; +using namespace Catch; void check_layers(const DynamicPrintConfig& config) { GCodeReader parser; @@ -27,10 +29,10 @@ void check_layers(const DynamicPrintConfig& config) { const double layer_height = config.opt_float("layer_height"); INFO("Correct first layer height."); CHECK(z.at(0) == Approx(first_layer_height + z_offset)); - INFO("Correct second layer height") + INFO("Correct second layer height"); CHECK(z.at(1) == Approx(first_layer_height + layer_height + z_offset)); - INFO("Correct layer height") + INFO("Correct layer height"); for (const double increment : tcb::span{increments}.subspan(1)) { CHECK(increment == Approx(layer_height)); } diff --git a/tests/fff_print/test_model.cpp b/tests/fff_print/test_model.cpp index 2f61425..8789025 100644 --- a/tests/fff_print/test_model.cpp +++ b/tests/fff_print/test_model.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/libslic3r.h" #include "libslic3r/Model.hpp" diff --git a/tests/fff_print/test_multi.cpp b/tests/fff_print/test_multi.cpp index 29a89af..797abb8 100644 --- a/tests/fff_print/test_multi.cpp +++ b/tests/fff_print/test_multi.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/fff_print/test_perimeters.cpp b/tests/fff_print/test_perimeters.cpp index 517d144..d85dcbc 100644 --- a/tests/fff_print/test_perimeters.cpp +++ b/tests/fff_print/test_perimeters.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/fff_print/test_print.cpp b/tests/fff_print/test_print.cpp index 204f3f8..f1579b3 100644 --- a/tests/fff_print/test_print.cpp +++ b/tests/fff_print/test_print.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/libslic3r.h" #include "libslic3r/Print.hpp" diff --git a/tests/fff_print/test_printgcode.cpp b/tests/fff_print/test_printgcode.cpp index 2a45bd2..d3be9c8 100644 --- a/tests/fff_print/test_printgcode.cpp +++ b/tests/fff_print/test_printgcode.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include "libslic3r/libslic3r.h" #include "libslic3r/GCodeReader.hpp" @@ -10,6 +11,7 @@ using namespace Slic3r; using namespace Slic3r::Test; +using namespace Catch; boost::regex perimeters_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; perimeter"); boost::regex infill_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; infill"); diff --git a/tests/fff_print/test_printobject.cpp b/tests/fff_print/test_printobject.cpp index cbc4734..d329b0f 100644 --- a/tests/fff_print/test_printobject.cpp +++ b/tests/fff_print/test_printobject.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include "libslic3r/libslic3r.h" #include "libslic3r/Print.hpp" @@ -8,6 +9,7 @@ using namespace Slic3r; using namespace Slic3r::Test; +using namespace Catch; SCENARIO("PrintObject: object layer heights", "[PrintObject]") { GIVEN("20mm cube and default initial config, initial layer height of 2mm") { diff --git a/tests/fff_print/test_retraction.cpp b/tests/fff_print/test_retraction.cpp index b8cf441..355b6a7 100644 --- a/tests/fff_print/test_retraction.cpp +++ b/tests/fff_print/test_retraction.cpp @@ -2,10 +2,12 @@ * Ported from t/retraction.t */ -#include +#include +#include -#include -#include +#include "libslic3r/GCodeReader.hpp" +#include "libslic3r/GCode/GCodeWriter.hpp" +#include "libslic3r/Config.hpp" #include "test_data.hpp" #include @@ -13,6 +15,7 @@ using namespace Slic3r; using namespace Test; +using namespace Catch; constexpr bool debug_files {false}; @@ -59,6 +62,10 @@ void check_gcode(std::initializer_list meshes, const DynamicPrintConfi const double retract_restart_extra = config.option("retract_restart_extra")->get_at(tool); const double retract_restart_extra_toolchange = config.option("retract_restart_extra_toolchange")->get_at(tool); + const double travel_speed = config.opt_float("travel_speed"); + + const double feedrate = line.has_f() ? line.f() : self.f(); + if (line.dist_Z(self) != 0) { // lift move or lift + change layer const double retract_lift = config.option("retract_lift")->get_at(tool); @@ -77,7 +84,7 @@ void check_gcode(std::initializer_list meshes, const DynamicPrintConfi lift_dist = line.dist_Z(self); } if (line.dist_Z(self) < 0) { - INFO("Must be lifted before going down.") + INFO("Must be lifted before going down."); CHECK(lifted); INFO("Going down by the same amount of the lift or by the amount needed to get to next layer"); CHECK(( @@ -87,9 +94,26 @@ void check_gcode(std::initializer_list meshes, const DynamicPrintConfi lift_dist = 0; lifted = false; } - const double feedrate = line.has_f() ? line.f() : self.f(); - INFO("move Z at travel speed"); - CHECK(feedrate == Approx(config.opt_float("travel_speed") * 60)); + const double travel_speed_z = config.opt_float("travel_speed_z"); + if (travel_speed_z) { + Vec3d move{line.dist_X(self), line.dist_Y(self), line.dist_Z(self)}; + const double move_u_z = move.z() / move.norm(); + const double travel_speed_ = std::abs(travel_speed_z / move_u_z); + INFO("move Z feedrate Z component is less than or equal to travel_speed_z"); + CHECK(feedrate * std::abs(move_u_z) <= Approx(travel_speed_z * 60).epsilon(GCodeFormatter::XYZ_EPSILON)); + if (travel_speed_ < travel_speed) { + INFO("move Z at travel speed Z"); + CHECK(feedrate == Approx(travel_speed_ * 60).epsilon(GCodeFormatter::XYZ_EPSILON)); + INFO("move Z feedrate Z component is equal to travel_speed_z"); + CHECK(feedrate * std::abs(move_u_z) == Approx(travel_speed_z * 60).epsilon(GCodeFormatter::XYZ_EPSILON)); + } else { + INFO("move Z at travel speed"); + CHECK(feedrate == Approx(travel_speed * 60).epsilon(GCodeFormatter::XYZ_EPSILON)); + } + } else { + INFO("move Z at travel speed"); + CHECK(feedrate == Approx(travel_speed * 60).epsilon(GCodeFormatter::XYZ_EPSILON)); + } } if (line.retracting(self)) { retracted[tool] = true; @@ -135,11 +159,6 @@ void test_slicing(std::initializer_list meshes, DynamicPrintConfig& co check_gcode(meshes, config, duplicate); } - SECTION("Negative restart extra length") { - config.set_deserialize_strict({{ "retract_restart_extra", "-1" }}); - check_gcode(meshes, config, duplicate); - } - SECTION("Retract_lift") { config.set_deserialize_strict({{ "retract_lift", "1,2" }}); check_gcode(meshes, config, duplicate); @@ -147,7 +166,7 @@ void test_slicing(std::initializer_list meshes, DynamicPrintConfig& co } -TEST_CASE("Slicing with retraction and lifing", "[retraction]") { +TEST_CASE("Slicing with retraction and lifting", "[retraction]") { DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); config.set_deserialize_strict({ { "nozzle_diameter", "0.6,0.6,0.6,0.6" }, @@ -176,6 +195,37 @@ TEST_CASE("Slicing with retraction and lifing", "[retraction]") { } } +TEST_CASE("Slicing with retraction and lifting with travel_speed_z=10", "[retraction]") { + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "nozzle_diameter", "0.6,0.6,0.6,0.6" }, + { "first_layer_height", config.opt_float("layer_height") }, + { "first_layer_speed", "100%" }, + { "start_gcode", "" }, // To avoid dealing with the nozzle lift in start G-code + { "retract_length", "1.5" }, + { "retract_before_travel", "3" }, + { "retract_layer_change", "1" }, + { "only_retract_when_crossing_perimeters", 0 }, + { "travel_speed", "600" }, + { "travel_speed_z", "10" }, + }); + + SECTION("Standard run") { + test_slicing({TestMesh::cube_20x20x20}, config); + } + SECTION("With duplicate cube") { + test_slicing({TestMesh::cube_20x20x20}, config, 2); + } + SECTION("Dual extruder with multiple skirt layers") { + config.set_deserialize_strict({ + {"infill_extruder", 2}, + {"skirts", 4}, + {"skirt_height", 3}, + }); + test_slicing({TestMesh::cube_20x20x20}, config); + } +} + TEST_CASE("Z moves", "[retraction]") { DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); diff --git a/tests/fff_print/test_seam_aligned.cpp b/tests/fff_print/test_seam_aligned.cpp index 33080e7..04d9a34 100644 --- a/tests/fff_print/test_seam_aligned.cpp +++ b/tests/fff_print/test_seam_aligned.cpp @@ -1,11 +1,13 @@ #include -#include +#include +#include #include #include "test_data.hpp" #include using namespace Slic3r; using namespace Slic3r::Seams; +using namespace Catch; constexpr bool debug_files{false}; diff --git a/tests/fff_print/test_seam_geometry.cpp b/tests/fff_print/test_seam_geometry.cpp index 67dcc3e..d6c3791 100644 --- a/tests/fff_print/test_seam_geometry.cpp +++ b/tests/fff_print/test_seam_geometry.cpp @@ -1,9 +1,12 @@ #include -#include +#include +#include +#include #include #include using namespace Slic3r; +using namespace Catch; TEST_CASE("Lists mapping", "[Seams][SeamGeometry]") { // clang-format off @@ -123,50 +126,3 @@ TEST_CASE("Vertex angle is rotation agnostic", "[Seams][SeamGeometry]") { std::vector rotated_angles = Seams::Geometry::get_vertex_angles(points, 0.1); CHECK(rotated_angles[1] == Approx(angles[1])); } - -TEST_CASE("Calculate overhangs", "[Seams][SeamGeometry]") { - const ExPolygon square{ - scaled(Vec2d{0.0, 0.0}), - scaled(Vec2d{1.0, 0.0}), - scaled(Vec2d{1.0, 1.0}), - scaled(Vec2d{0.0, 1.0}) - }; - const std::vector points{Seams::Geometry::unscaled(square.contour.points)}; - ExPolygon previous_layer{square}; - previous_layer.translate(scaled(Vec2d{-0.5, 0})); - AABBTreeLines::LinesDistancer previous_layer_distancer{ - to_unscaled_linesf({previous_layer})}; - const std::vector overhangs{ - Seams::Geometry::get_overhangs(points, previous_layer_distancer, 0.5)}; - REQUIRE(overhangs.size() == points.size()); - CHECK_THAT(overhangs, Catch::Matchers::Approx(std::vector{ - 0.0, M_PI / 4.0, M_PI / 4.0, 0.0 - })); -} - -const Linesf lines{to_unscaled_linesf({ExPolygon{ - scaled(Vec2d{0.0, 0.0}), - scaled(Vec2d{1.0, 0.0}), - scaled(Vec2d{1.0, 1.0}), - scaled(Vec2d{0.0, 1.0}) -}})}; - -TEST_CASE("Offset along loop lines forward", "[Seams][SeamGeometry]") { - const std::optional result{Seams::Geometry::offset_along_lines( - {0.5, 0.0}, 0, lines, 3.9, Seams::Geometry::Direction1D::forward - )}; - REQUIRE(result); - const auto &[point, line_index] = *result; - CHECK((scaled(point) - Point::new_scale(0.4, 0.0)).norm() < scaled(EPSILON)); - CHECK(line_index == 0); -} - -TEST_CASE("Offset along loop lines backward", "[Seams][SeamGeometry]") { - const std::optional result{Seams::Geometry::offset_along_lines( - {1.0, 0.5}, 1, lines, 1.8, Seams::Geometry::Direction1D::backward - )}; - REQUIRE(result); - const auto &[point, line_index] = *result; - CHECK((scaled(point) - Point::new_scale(0.0, 0.3)).norm() < scaled(EPSILON)); - CHECK(line_index == 3); -} diff --git a/tests/fff_print/test_seam_perimeters.cpp b/tests/fff_print/test_seam_perimeters.cpp index 245b3b3..a3b3fb9 100644 --- a/tests/fff_print/test_seam_perimeters.cpp +++ b/tests/fff_print/test_seam_perimeters.cpp @@ -2,7 +2,8 @@ #include "libslic3r/GCode/SeamPerimeters.hpp" #include "libslic3r/Layer.hpp" #include "libslic3r/Point.hpp" -#include +#include +#include #include #include #include @@ -11,26 +12,29 @@ using namespace Slic3r; using namespace Slic3r::Seams; +using namespace Catch; constexpr bool debug_files{false}; -const ExPolygon square{ - scaled(Vec2d{0.0, 0.0}), scaled(Vec2d{1.0, 0.0}), scaled(Vec2d{1.0, 1.0}), - scaled(Vec2d{0.0, 1.0})}; - TEST_CASE("Oversample painted", "[Seams][SeamPerimeters]") { + Perimeters::PerimeterPoints square(4); + square[0].position = Vec2d{0.0, 0.0}; + square[1].position = Vec2d{1.0, 0.0}; + square[2].position = Vec2d{1.0, 1.0}; + square[3].position = Vec2d{0.0, 1.0}; + auto is_painted{[](const Vec3f &position, float radius) { return (position - Vec3f{0.5, 0.0, 1.0}).norm() < radius; }}; - std::vector points{Perimeters::Impl::oversample_painted( - Seams::Geometry::unscaled(square.contour.points), is_painted, 1.0, 0.2 + Perimeters::PerimeterPoints points{Perimeters::Impl::oversample_painted( + square, is_painted, 1.0, 0.2 )}; REQUIRE(points.size() == 8); - CHECK((points[1] - Vec2d{0.2, 0.0}).norm() == Approx(0.0)); + CHECK((points[1].position - Vec2d{0.2, 0.0}).norm() == Approx(0.0)); points = Perimeters::Impl::oversample_painted( - Seams::Geometry::unscaled(square.contour.points), is_painted, 1.0, 0.199 + square, is_painted, 1.0, 0.199 ); CHECK(points.size() == 9); } @@ -39,24 +43,35 @@ TEST_CASE("Remove redundant points", "[Seams][SeamPerimeters]") { using Perimeters::PointType; using Perimeters::PointClassification; - std::vector points{{0.0, 0.0}, {1.0, 0.0}, {2.0, 0.0}, {3.0, 0.0}, - {3.0, 1.0}, {3.0, 2.0}, {0.0, 2.0}}; - std::vector point_types{PointType::common, - PointType::enforcer, // Should keep this. - PointType::enforcer, // Should keep this. - PointType::blocker, - PointType::blocker, // Should remove this. - PointType::blocker, PointType::common}; + Perimeters::PerimeterPoints points(9); + points[0].position = {0.0, 0.0}; + points[0].type = PointType::common; + points[1].position = {1.0, 0.0}; + points[1].type = PointType::enforcer; // Should keep + points[2].position = {2.0, 0.0}; + points[2].type = PointType::enforcer; // Should keep + points[3].position = {3.0, 0.0}; + points[3].type = PointType::blocker; + points[4].position = {3.0, 1.0}; + points[4].type = PointType::blocker; // Should remove + points[5].position = {3.0, 1.1}; + points[5].type = PointType::blocker; + points[6].position = {3.0, 1.2}; + points[6].type = PointType::blocker; + points[6].classification = PointClassification::overhang; // Should keep + points[7].position = {3.0, 2.0}; + points[7].type = PointType::blocker; + points[8].position = {0.0, 2.0}; + points[8].type = PointType::common; - const auto [resulting_points, resulting_point_types]{ - Perimeters::Impl::remove_redundant_points(points, point_types, 0.1)}; + Perimeters::PerimeterPoints result{ + Perimeters::Impl::remove_redundant_points(points, 0.1)}; - REQUIRE(resulting_points.size() == 6); - REQUIRE(resulting_point_types.size() == 6); - CHECK((resulting_points[3] - Vec2d{3.0, 0.0}).norm() == Approx(0.0)); - CHECK((resulting_points[4] - Vec2d{3.0, 2.0}).norm() == Approx(0.0)); - CHECK(resulting_point_types[3] == PointType::blocker); - CHECK(resulting_point_types[4] == PointType::blocker); + REQUIRE(result.size() == 8); + CHECK((result[3].position - Vec2d{3.0, 0.0}).norm() == Approx(0.0)); + CHECK((result[4].position - Vec2d{3.0, 1.1}).norm() == Approx(0.0)); + CHECK(result[3].type == PointType::blocker); + CHECK(result[4].type == PointType::blocker); } TEST_CASE("Perimeter constructs KD trees", "[Seams][SeamPerimeters]") { @@ -89,8 +104,6 @@ TEST_CASE("Perimeter constructs KD trees", "[Seams][SeamPerimeters]") { CHECK(perimeter.common_points.embedded_points); } -using std::filesystem::path; - constexpr const char *to_string(Perimeters::PointType point_type) { using Perimeters::PointType; @@ -182,3 +195,57 @@ TEST_CASE_METHOD(Test::SeamsFixture, "Create perimeters", "[Seams][SeamPerimeter serialize_shells(csv, shells); } } + +using Dir = Seams::Geometry::Direction1D; + +Perimeters::Perimeter get_perimeter(){ + Perimeters::Perimeter perimeter; + perimeter.positions = { + Vec2d{0.0, 0.0}, + Vec2d{1.0, 0.0}, + Vec2d{1.0, 1.0}, + Vec2d{0.0, 1.0} + }; + return perimeter; +} + +TEST_CASE("Offset along perimeter forward", "[Seams][SeamPerimeters]") { + const std::optional result{Perimeters::offset_along_perimeter( + {0, 1, {0.5, 0.0}}, get_perimeter(), 3.9, Dir::forward, + [](const Perimeters::Perimeter &, const std::size_t) { return false; } + )}; + REQUIRE(result); + const auto &[previous_index, next_index, point] = *result; + CHECK((scaled(point) - Point::new_scale(0.4, 0.0)).norm() < scaled(EPSILON)); + CHECK(previous_index == 0); + CHECK(next_index == 1); +} + +TEST_CASE("Offset along perimeter backward", "[Seams][SeamPerimeters]") { + const std::optional result{Perimeters::offset_along_perimeter( + {1, 2, {1.0, 0.5}}, get_perimeter(), 1.8, Dir::backward, + [](const Perimeters::Perimeter &, const std::size_t) { return false; } + )}; + REQUIRE(result); + const auto &[previous_index, next_index, point] = *result; + CHECK((scaled(point) - Point::new_scale(0.0, 0.3)).norm() < scaled(EPSILON)); + CHECK(previous_index == 3); + CHECK(next_index == 0); +} + +TEST_CASE("Offset along perimeter forward respects stop condition", "[Seams][SeamPerimeters]") { + Perimeters::Perimeter perimeter{get_perimeter()}; + perimeter.point_types = std::vector(perimeter.positions.size(), Perimeters::PointType::common); + perimeter.point_types[2] = Perimeters::PointType::blocker; + const std::optional result{Perimeters::offset_along_perimeter( + {0, 1, {0.5, 0.0}}, perimeter, 3.9, Dir::forward, + [](const Perimeters::Perimeter &perimeter, const std::size_t index) { + return perimeter.point_types[index] == Perimeters::PointType::blocker; + } + )}; + REQUIRE(result); + const auto &[previous_index, next_index, point] = *result; + CHECK((scaled(point) - Point::new_scale(1.0, 0.0)).norm() < scaled(EPSILON)); + CHECK(previous_index == 1); + CHECK(next_index == 1); +} \ No newline at end of file diff --git a/tests/fff_print/test_seam_random.cpp b/tests/fff_print/test_seam_random.cpp index cd95146..59341ec 100644 --- a/tests/fff_print/test_seam_random.cpp +++ b/tests/fff_print/test_seam_random.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include "test_data.hpp" #include @@ -32,7 +32,7 @@ Perimeters::Perimeter get_perimeter() { } } // namespace RandomTest -double get_chi2_uniform(const std::vector &data, double min, double max, const std::size_t bin_count) { +double get_chi2_uniform(const std::vector &data, const double min, const double max, const std::size_t bin_count) { std::vector bins(bin_count); const double bin_size{(max - min) / bin_count}; const double expected_frequncy{static_cast(data.size()) / bin_count}; @@ -62,7 +62,7 @@ TEST_CASE("Random is uniform", "[Seams][SeamRandom]") { return choice->position.x(); }); const std::size_t degrees_of_freedom{10}; - const double critical{18.307}; // dof 10, significance 0.05 + const double critical{29.588}; // dof 10, significance 0.001 CHECK(get_chi2_uniform(x_positions, 0.0, 1.0, degrees_of_freedom + 1) < critical); } diff --git a/tests/fff_print/test_seam_rear.cpp b/tests/fff_print/test_seam_rear.cpp index fc183a3..e23d742 100644 --- a/tests/fff_print/test_seam_rear.cpp +++ b/tests/fff_print/test_seam_rear.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include "test_data.hpp" #include diff --git a/tests/fff_print/test_seam_scarf.cpp b/tests/fff_print/test_seam_scarf.cpp index 2f9b727..f1a3770 100644 --- a/tests/fff_print/test_seam_scarf.cpp +++ b/tests/fff_print/test_seam_scarf.cpp @@ -1,9 +1,11 @@ -#include +#include +#include #include #include using namespace Slic3r; using Seams::Scarf::Impl::PathPoint; +using namespace Catch; TEST_CASE("Get path point", "[Seams][Scarf]") { using Seams::Scarf::Impl::get_path_point; diff --git a/tests/fff_print/test_seam_shells.cpp b/tests/fff_print/test_seam_shells.cpp index cbc0cfa..d18a59e 100644 --- a/tests/fff_print/test_seam_shells.cpp +++ b/tests/fff_print/test_seam_shells.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include #include #include "libslic3r/ClipperUtils.hpp" @@ -9,6 +10,7 @@ using namespace Slic3r; using namespace Slic3r::Seams; +using namespace Catch; struct ProjectionFixture { @@ -21,7 +23,12 @@ struct ProjectionFixture double extrusion_width{0.2}; ProjectionFixture() { - extrusions.emplace_back(Polygon{extrusion_path}, extrusion_path.bounding_box(), extrusion_width, island_boundary); + extrusions.emplace_back( + Polygon{extrusion_path}, + extrusion_path.bounding_box(), + extrusion_width, island_boundary, + Seams::Geometry::Overhangs{} + ); } }; diff --git a/tests/fff_print/test_shells.cpp b/tests/fff_print/test_shells.cpp index fcb3a49..ff696a9 100644 --- a/tests/fff_print/test_shells.cpp +++ b/tests/fff_print/test_shells.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/GCodeReader.hpp" diff --git a/tests/fff_print/test_skirt_brim.cpp b/tests/fff_print/test_skirt_brim.cpp index 6555172..3ee7b35 100644 --- a/tests/fff_print/test_skirt_brim.cpp +++ b/tests/fff_print/test_skirt_brim.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include "libslic3r/GCodeReader.hpp" #include "libslic3r/Config.hpp" @@ -10,6 +11,7 @@ using namespace Slic3r::Test; using namespace Slic3r; +using namespace Catch; /// Helper method to find the tool used for the brim (always the first extrusion) static int get_brim_tool(const std::string &gcode) diff --git a/tests/fff_print/test_support_material.cpp b/tests/fff_print/test_support_material.cpp index 0720b27..56ee30b 100644 --- a/tests/fff_print/test_support_material.cpp +++ b/tests/fff_print/test_support_material.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/GCodeReader.hpp" #include "libslic3r/Layer.hpp" diff --git a/tests/fff_print/test_thin_walls.cpp b/tests/fff_print/test_thin_walls.cpp index 59fb6b0..73201dd 100644 --- a/tests/fff_print/test_thin_walls.cpp +++ b/tests/fff_print/test_thin_walls.cpp @@ -1,7 +1,8 @@ -#include +#include #include #include +#include #include "test_data.hpp" // get access to init_print, etc diff --git a/tests/fff_print/test_trianglemesh.cpp b/tests/fff_print/test_trianglemesh.cpp index eff39ed..269b56d 100644 --- a/tests/fff_print/test_trianglemesh.cpp +++ b/tests/fff_print/test_trianglemesh.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/TriangleMeshSlicer.hpp" diff --git a/tests/libslic3r/test_3mf.cpp b/tests/libslic3r/test_3mf.cpp index eabf85a..1e648d1 100644 --- a/tests/libslic3r/test_3mf.cpp +++ b/tests/libslic3r/test_3mf.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/Model.hpp" #include "libslic3r/Format/3mf.hpp" diff --git a/tests/libslic3r/test_aabbindirect.cpp b/tests/libslic3r/test_aabbindirect.cpp index 3a93eb9..36b3593 100644 --- a/tests/libslic3r/test_aabbindirect.cpp +++ b/tests/libslic3r/test_aabbindirect.cpp @@ -1,5 +1,6 @@ #include -#include +#include +#include #include #include @@ -7,6 +8,7 @@ #include using namespace Slic3r; +using namespace Catch; TEST_CASE("Building a tree over a box, ray caster and closest query", "[AABBIndirect]") { diff --git a/tests/libslic3r/test_anyptr.cpp b/tests/libslic3r/test_anyptr.cpp index d7b00a0..f53e886 100644 --- a/tests/libslic3r/test_anyptr.cpp +++ b/tests/libslic3r/test_anyptr.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/libslic3r/test_arachne.cpp b/tests/libslic3r/test_arachne.cpp index 6ebdda2..86ef8bd 100644 --- a/tests/libslic3r/test_arachne.cpp +++ b/tests/libslic3r/test_arachne.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/Arachne/WallToolPaths.hpp" #include "libslic3r/ClipperUtils.hpp" diff --git a/tests/libslic3r/test_arc_welder.cpp b/tests/libslic3r/test_arc_welder.cpp index 35eda98..1724123 100644 --- a/tests/libslic3r/test_arc_welder.cpp +++ b/tests/libslic3r/test_arc_welder.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include #include @@ -12,6 +13,7 @@ #include using namespace Slic3r; +using namespace Catch; TEST_CASE("arc basics", "[ArcWelder]") { using namespace Slic3r::Geometry; diff --git a/tests/libslic3r/test_astar.cpp b/tests/libslic3r/test_astar.cpp index 4e540c3..6dc8ed6 100644 --- a/tests/libslic3r/test_astar.cpp +++ b/tests/libslic3r/test_astar.cpp @@ -1,4 +1,8 @@ -#include +#include +#include +#include + +#include #include "libslic3r/BoundingBox.hpp" #include "libslic3r/AStar.hpp" @@ -6,6 +10,7 @@ #include "libslic3r/PointGrid.hpp" using namespace Slic3r; +using namespace Catch; TEST_CASE("Testing basic invariants of AStar", "[AStar]") { struct DummyTracer { diff --git a/tests/libslic3r/test_clipper_offset.cpp b/tests/libslic3r/test_clipper_offset.cpp index 8209d99..dc64a04 100644 --- a/tests/libslic3r/test_clipper_offset.cpp +++ b/tests/libslic3r/test_clipper_offset.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include #include @@ -8,6 +9,7 @@ #include "libslic3r/SVG.hpp" using namespace Slic3r; +using namespace Catch; // #define TESTS_EXPORT_SVGS diff --git a/tests/libslic3r/test_clipper_utils.cpp b/tests/libslic3r/test_clipper_utils.cpp index 1f3bc0f..c5ab927 100644 --- a/tests/libslic3r/test_clipper_utils.cpp +++ b/tests/libslic3r/test_clipper_utils.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include #include @@ -9,6 +10,7 @@ #include "libslic3r/SVG.hpp" using namespace Slic3r; +using namespace Catch; SCENARIO("Various Clipper operations - xs/t/11_clipper.t", "[ClipperUtils]") { // CCW oriented contour diff --git a/tests/libslic3r/test_color.cpp b/tests/libslic3r/test_color.cpp index bb35f5e..2df18e0 100644 --- a/tests/libslic3r/test_color.cpp +++ b/tests/libslic3r/test_color.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/libslic3r.h" #include "libslic3r/Color.hpp" diff --git a/tests/libslic3r/test_config.cpp b/tests/libslic3r/test_config.cpp index fea5068..309893d 100644 --- a/tests/libslic3r/test_config.cpp +++ b/tests/libslic3r/test_config.cpp @@ -1,4 +1,6 @@ -#include +#include +#include +#include #include "libslic3r/Config.hpp" #include "libslic3r/PrintConfig.hpp" diff --git a/tests/libslic3r/test_curve_fitting.cpp b/tests/libslic3r/test_curve_fitting.cpp index faf7839..9510dcd 100644 --- a/tests/libslic3r/test_curve_fitting.cpp +++ b/tests/libslic3r/test_curve_fitting.cpp @@ -1,10 +1,13 @@ -#include +#include +#include #include #include #include #include +using namespace Catch; + TEST_CASE("Curves: cubic b spline fit test", "[Curves]") { using namespace Slic3r; using namespace Slic3r::Geometry; diff --git a/tests/libslic3r/test_cut_surface.cpp b/tests/libslic3r/test_cut_surface.cpp index d937619..6f30bb7 100644 --- a/tests/libslic3r/test_cut_surface.cpp +++ b/tests/libslic3r/test_cut_surface.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include // its_make_cube + its_merge diff --git a/tests/libslic3r/test_elephant_foot_compensation.cpp b/tests/libslic3r/test_elephant_foot_compensation.cpp index 09ad33f..a0f15e1 100644 --- a/tests/libslic3r/test_elephant_foot_compensation.cpp +++ b/tests/libslic3r/test_elephant_foot_compensation.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/libslic3r/test_emboss.cpp b/tests/libslic3r/test_emboss.cpp index 40f448f..9a11ec9 100644 --- a/tests/libslic3r/test_emboss.cpp +++ b/tests/libslic3r/test_emboss.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include // only debug visualization diff --git a/tests/libslic3r/test_expolygon.cpp b/tests/libslic3r/test_expolygon.cpp index ca914d3..aba67ca 100644 --- a/tests/libslic3r/test_expolygon.cpp +++ b/tests/libslic3r/test_expolygon.cpp @@ -1,10 +1,12 @@ -#include +#include +#include #include "libslic3r/Point.hpp" #include "libslic3r/Polygon.hpp" #include "libslic3r/ExPolygon.hpp" using namespace Slic3r; +using namespace Catch; static inline bool points_close(const Point &p1, const Point &p2) { diff --git a/tests/libslic3r/test_geometry.cpp b/tests/libslic3r/test_geometry.cpp index 81ac238..0ac6fe4 100644 --- a/tests/libslic3r/test_geometry.cpp +++ b/tests/libslic3r/test_geometry.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/Point.hpp" #include "libslic3r/BoundingBox.hpp" diff --git a/tests/libslic3r/test_hollowing.cpp b/tests/libslic3r/test_hollowing.cpp index ad4f8f2..1e8130f 100644 --- a/tests/libslic3r/test_hollowing.cpp +++ b/tests/libslic3r/test_hollowing.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include "libslic3r/SLA/Hollowing.hpp" diff --git a/tests/libslic3r/test_indexed_triangle_set.cpp b/tests/libslic3r/test_indexed_triangle_set.cpp index b6aad9d..1a8634d 100644 --- a/tests/libslic3r/test_indexed_triangle_set.cpp +++ b/tests/libslic3r/test_indexed_triangle_set.cpp @@ -1,6 +1,7 @@ #include #include -#include +#include +#include #include "libslic3r/TriangleMesh.hpp" diff --git a/tests/libslic3r/test_jump_point_search.cpp b/tests/libslic3r/test_jump_point_search.cpp index 76d2aac..d71acea 100644 --- a/tests/libslic3r/test_jump_point_search.cpp +++ b/tests/libslic3r/test_jump_point_search.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/BoundingBox.hpp" #include "libslic3r/JumpPointSearch.hpp" diff --git a/tests/libslic3r/test_kdtreeindirect.cpp b/tests/libslic3r/test_kdtreeindirect.cpp index bc6ace7..946c241 100644 --- a/tests/libslic3r/test_kdtreeindirect.cpp +++ b/tests/libslic3r/test_kdtreeindirect.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include "libslic3r/KDTreeIndirect.hpp" #include "libslic3r/Execution/ExecutionSeq.hpp" diff --git a/tests/libslic3r/test_layer_region.cpp b/tests/libslic3r/test_layer_region.cpp index 1351b8a..3fe849d 100644 --- a/tests/libslic3r/test_layer_region.cpp +++ b/tests/libslic3r/test_layer_region.cpp @@ -2,11 +2,13 @@ #include "libslic3r/Geometry.hpp" #include "libslic3r/Point.hpp" #include "libslic3r/SVG.hpp" -#include +#include +#include #include using namespace Slic3r; using namespace Slic3r::Algorithm; +using namespace Catch; constexpr bool export_svgs = false; diff --git a/tests/libslic3r/test_line.cpp b/tests/libslic3r/test_line.cpp index 4a8edf2..b3f0e04 100644 --- a/tests/libslic3r/test_line.cpp +++ b/tests/libslic3r/test_line.cpp @@ -1,8 +1,10 @@ /** * Ported from xs/t/10_line.t */ +#include +#include -#include +#include #include #include "test_utils.hpp" @@ -37,7 +39,7 @@ TEST_CASE("Parallel lines under angles", "[Line]") { CHECK(line.parallel_to(line.direction())); INFO("Line is parallel to its direction + PI"); line.parallel_to(line.direction() + M_PI); - INFO("line is parallel to its direction - PI") + INFO("line is parallel to its direction - PI"); line.parallel_to(line.direction() - M_PI); SECTION("Line is parallel within epsilon") { diff --git a/tests/libslic3r/test_marchingsquares.cpp b/tests/libslic3r/test_marchingsquares.cpp index 89a86f1..c060f0c 100644 --- a/tests/libslic3r/test_marchingsquares.cpp +++ b/tests/libslic3r/test_marchingsquares.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/libslic3r/test_meshboolean.cpp b/tests/libslic3r/test_meshboolean.cpp index 7587677..8b1e2a2 100644 --- a/tests/libslic3r/test_meshboolean.cpp +++ b/tests/libslic3r/test_meshboolean.cpp @@ -1,10 +1,12 @@ -#include +#include +#include #include #include #include using namespace Slic3r; +using namespace Catch; TEST_CASE("CGAL and TriangleMesh conversions", "[MeshBoolean]") { TriangleMesh sphere = make_sphere(1.); diff --git a/tests/libslic3r/test_multiple_beds.cpp b/tests/libslic3r/test_multiple_beds.cpp index 10640a4..f0098ca 100644 --- a/tests/libslic3r/test_multiple_beds.cpp +++ b/tests/libslic3r/test_multiple_beds.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/libslic3r/test_mutable_polygon.cpp b/tests/libslic3r/test_mutable_polygon.cpp index 5a3c144..6cb0748 100644 --- a/tests/libslic3r/test_mutable_polygon.cpp +++ b/tests/libslic3r/test_mutable_polygon.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/Point.hpp" #include "libslic3r/MutablePolygon.hpp" diff --git a/tests/libslic3r/test_mutable_priority_queue.cpp b/tests/libslic3r/test_mutable_priority_queue.cpp index 7e31b57..e8a2521 100644 --- a/tests/libslic3r/test_mutable_priority_queue.cpp +++ b/tests/libslic3r/test_mutable_priority_queue.cpp @@ -1,6 +1,8 @@ -#include +#include #include +#include +#include #include "libslic3r/MutablePriorityQueue.hpp" diff --git a/tests/libslic3r/test_optimizers.cpp b/tests/libslic3r/test_optimizers.cpp index 6e84f6a..533ac78 100644 --- a/tests/libslic3r/test_optimizers.cpp +++ b/tests/libslic3r/test_optimizers.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/libslic3r/test_placeholder_parser.cpp b/tests/libslic3r/test_placeholder_parser.cpp index 7a7e22c..7d87291 100644 --- a/tests/libslic3r/test_placeholder_parser.cpp +++ b/tests/libslic3r/test_placeholder_parser.cpp @@ -1,9 +1,11 @@ -#include +#include +#include #include "libslic3r/PlaceholderParser.hpp" #include "libslic3r/PrintConfig.hpp" using namespace Slic3r; +using namespace Catch; SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") { PlaceholderParser parser; diff --git a/tests/libslic3r/test_png_io.cpp b/tests/libslic3r/test_png_io.cpp index 97fa064..f5e0ae7 100644 --- a/tests/libslic3r/test_png_io.cpp +++ b/tests/libslic3r/test_png_io.cpp @@ -2,7 +2,7 @@ #define NOMINMAX #endif -#include +#include #include diff --git a/tests/libslic3r/test_point.cpp b/tests/libslic3r/test_point.cpp index 156995f..8f453a9 100644 --- a/tests/libslic3r/test_point.cpp +++ b/tests/libslic3r/test_point.cpp @@ -5,11 +5,13 @@ * and cross product uses doubles */ -#include +#include +#include #include #include "test_utils.hpp" using namespace Slic3r; +using namespace Catch; TEST_CASE("Nearest point", "[Point]") { const Point point{10, 15}; diff --git a/tests/libslic3r/test_polygon.cpp b/tests/libslic3r/test_polygon.cpp index b260888..d80ef88 100644 --- a/tests/libslic3r/test_polygon.cpp +++ b/tests/libslic3r/test_polygon.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/Point.hpp" #include "libslic3r/Polygon.hpp" diff --git a/tests/libslic3r/test_polyline.cpp b/tests/libslic3r/test_polyline.cpp index befad4b..cbf3a07 100644 --- a/tests/libslic3r/test_polyline.cpp +++ b/tests/libslic3r/test_polyline.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/Point.hpp" #include "libslic3r/Polyline.hpp" diff --git a/tests/libslic3r/test_quadric_edge_collapse.cpp b/tests/libslic3r/test_quadric_edge_collapse.cpp index 107cc9d..8d63648 100644 --- a/tests/libslic3r/test_quadric_edge_collapse.cpp +++ b/tests/libslic3r/test_quadric_edge_collapse.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/libslic3r/test_region_expansion.cpp b/tests/libslic3r/test_region_expansion.cpp index 9f8a6fd..4da6c19 100644 --- a/tests/libslic3r/test_region_expansion.cpp +++ b/tests/libslic3r/test_region_expansion.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include #include @@ -8,6 +9,7 @@ #include using namespace Slic3r; +using namespace Catch; //#define DEBUG_TEMP_DIR "d:\\temp\\" diff --git a/tests/libslic3r/test_static_map.cpp b/tests/libslic3r/test_static_map.cpp index 6722a30..ffee84f 100644 --- a/tests/libslic3r/test_static_map.cpp +++ b/tests/libslic3r/test_static_map.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "libslic3r/StaticMap.hpp" diff --git a/tests/libslic3r/test_stl.cpp b/tests/libslic3r/test_stl.cpp index 4c9c1bc..0e57a79 100644 --- a/tests/libslic3r/test_stl.cpp +++ b/tests/libslic3r/test_stl.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/Model.hpp" #include "libslic3r/Format/STL.hpp" diff --git a/tests/libslic3r/test_support_spots_generator.cpp b/tests/libslic3r/test_support_spots_generator.cpp index 7b8dd77..3c348b5 100644 --- a/tests/libslic3r/test_support_spots_generator.cpp +++ b/tests/libslic3r/test_support_spots_generator.cpp @@ -1,9 +1,12 @@ #include "libslic3r/Point.hpp" -#include +#include +#include +#include #include using namespace Slic3r; using namespace SupportSpotsGenerator; +using namespace Catch; namespace Rectangle { const float width = 10; diff --git a/tests/libslic3r/test_surface_mesh.cpp b/tests/libslic3r/test_surface_mesh.cpp index 34ff356..b9d3635 100644 --- a/tests/libslic3r/test_surface_mesh.cpp +++ b/tests/libslic3r/test_surface_mesh.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/tests/libslic3r/test_timeutils.cpp b/tests/libslic3r/test_timeutils.cpp index 6630d70..8cd3a5b 100644 --- a/tests/libslic3r/test_timeutils.cpp +++ b/tests/libslic3r/test_timeutils.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/Time.hpp" diff --git a/tests/libslic3r/test_triangulation.cpp b/tests/libslic3r/test_triangulation.cpp index 5a1f99f..1341e13 100644 --- a/tests/libslic3r/test_triangulation.cpp +++ b/tests/libslic3r/test_triangulation.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include // only debug visualization diff --git a/tests/libslic3r/test_utils.cpp b/tests/libslic3r/test_utils.cpp index 74d4094..2f696cf 100644 --- a/tests/libslic3r/test_utils.cpp +++ b/tests/libslic3r/test_utils.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/libslic3r.h" diff --git a/tests/libslic3r/test_voronoi.cpp b/tests/libslic3r/test_voronoi.cpp index f415dc7..1caaf7e 100644 --- a/tests/libslic3r/test_voronoi.cpp +++ b/tests/libslic3r/test_voronoi.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -6,6 +6,7 @@ #include #include +#include //#define VORONOI_DEBUG_OUT diff --git a/tests/sla_print/CMakeLists.txt b/tests/sla_print/CMakeLists.txt index a45b3a2..4f70f2d 100644 --- a/tests/sla_print/CMakeLists.txt +++ b/tests/sla_print/CMakeLists.txt @@ -4,6 +4,10 @@ add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp sla_test_utils.hpp sla_test_utils.cpp sla_supptgen_tests.cpp sla_raycast_tests.cpp + sla_parabola_tests.cpp + sla_voronoi_graph_tests.cpp + sla_vectorUtils_tests.cpp + sla_lineUtils_tests.cpp sla_supptreeutils_tests.cpp sla_archive_readwrite_tests.cpp sla_zcorrection_tests.cpp) @@ -18,3 +22,11 @@ endif() # catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests ${CATCH_EXTRA_ARGS}) + +if (WIN32) + # Adds a post-build copy of libgmp-10.dll + add_custom_command(TARGET ${_TEST_NAME}_tests POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_PREFIX_PATH}/bin/libgmp-10.dll" + $) +endif() \ No newline at end of file diff --git a/tests/sla_print/sla_archive_readwrite_tests.cpp b/tests/sla_print/sla_archive_readwrite_tests.cpp index fb1af3d..405877d 100644 --- a/tests/sla_print/sla_archive_readwrite_tests.cpp +++ b/tests/sla_print/sla_archive_readwrite_tests.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "libslic3r/SLAPrint.hpp" @@ -6,6 +6,7 @@ #include "libslic3r/Format/SLAArchiveFormatRegistry.hpp" #include "libslic3r/Format/SLAArchiveWriter.hpp" #include "libslic3r/Format/SLAArchiveReader.hpp" +#include "libslic3r/FileReader.hpp" #include @@ -20,7 +21,7 @@ TEST_CASE("Archive export test", "[sla_archives]") { SLAPrint print; SLAFullPrintConfig fullcfg; - auto m = Model::read_from_file(TEST_DATA_DIR PATH_SEPARATOR + std::string(pname) + ".obj", nullptr); + auto m = FileReader::load_model(TEST_DATA_DIR PATH_SEPARATOR + std::string(pname) + ".obj"); fullcfg.printer_technology.setInt(ptSLA); // FIXME this should be ensured fullcfg.set("sla_archive_format", entry.id); diff --git a/tests/sla_print/sla_lineUtils_tests.cpp b/tests/sla_print/sla_lineUtils_tests.cpp new file mode 100644 index 0000000..10616de --- /dev/null +++ b/tests/sla_print/sla_lineUtils_tests.cpp @@ -0,0 +1,59 @@ +#include +#include + +using namespace Slic3r; +using namespace Slic3r::sla; + +TEST_CASE("Intersection point", "[Utils], [LineUtils]") +{ + Point a1(0, 0); + Point b1(3, 6); + Line l1(a1, b1); + auto intersection = LineUtils::intersection(l1, Line(Point(0, 4), + Point(5, 4))); + CHECK(intersection.has_value()); + Point i_point = intersection->cast(); + CHECK(PointUtils::is_equal(i_point, Point(2, 4))); + + // same line + auto bad_intersection = LineUtils::intersection(l1, l1); + CHECK(!bad_intersection.has_value()); + + // oposit direction + bad_intersection = LineUtils::intersection(l1, Line(b1, a1)); + CHECK(!bad_intersection.has_value()); + + // parallel line + bad_intersection = LineUtils::intersection(l1, Line(a1 + Point(0, 1), + b1 + Point(0, 1))); + CHECK(!bad_intersection.has_value()); + + // out of line segment, but ray has intersection + Line l2(Point(0, 8), Point(6, 8)); + intersection = LineUtils::intersection(l1, l2); + auto intersection2 = LineUtils::intersection(l2, l1); + CHECK(intersection.has_value()); + CHECK(intersection2.has_value()); + i_point = intersection->cast(); + CHECK(PointUtils::is_equal(i_point, Point(4, 8))); + CHECK(PointUtils::is_equal(i_point, intersection2->cast())); + + Line l3(Point(-2, -2), Point(1, -2)); + intersection = LineUtils::intersection(l1, l3); + intersection2 = LineUtils::intersection(l3, l1); + CHECK(intersection.has_value()); + CHECK(intersection2.has_value()); + i_point = intersection->cast(); + CHECK(PointUtils::is_equal(i_point, Point(-1, -2))); + CHECK(PointUtils::is_equal(i_point, intersection2->cast())); +} + +TEST_CASE("Point belongs to line", "[Utils], [LineUtils]") +{ + Line l(Point(10, 10), Point(50, 30)); + CHECK(LineUtils::belongs(l, Point(30, 20))); + CHECK(!LineUtils::belongs(l, Point(30, 30))); + CHECK(LineUtils::belongs(l, Point(30, 30), 10.)); + CHECK(!LineUtils::belongs(l, Point(30, 10))); + CHECK(!LineUtils::belongs(l, Point(70, 40))); +} diff --git a/tests/sla_print/sla_parabola_tests.cpp b/tests/sla_print/sla_parabola_tests.cpp new file mode 100644 index 0000000..f3ab2ca --- /dev/null +++ b/tests/sla_print/sla_parabola_tests.cpp @@ -0,0 +1,50 @@ +#include "sla_test_utils.hpp" + +#include + +using namespace Slic3r; +using namespace Slic3r::sla; + +void parabola_check_length(const ParabolaSegment ¶bola) +{ + auto diffPoint = parabola.to - parabola.from; + double min = sqrt(diffPoint.x() * diffPoint.x() + + diffPoint.y() * diffPoint.y()); + double max = static_cast(diffPoint.x()) + diffPoint.y(); + double len = ParabolaUtils::length(parabola); + double len2 = ParabolaUtils::length_by_sampling(parabola, 1.); + CHECK(fabs(len2 - len) < 1.); + CHECK(len >= min); + CHECK(len <= max); +} + +// after generalization put to ParabolaUtils +double getParabolaY(const Parabola ¶bola, double x) +{ + double f = ParabolaUtils::focal_length(parabola); + Vec2d perp = parabola.directrix.normal().cast(); + // work only for test cases + if (perp.y() > 0.) perp *= -1.; + perp.normalize(); + Vec2d v = parabola.focus.cast() + perp * f; + return 1 / (4 * f) * (x - v.x()) * (x - v.x()) + v.y(); +} + +TEST_CASE("Parabola length", "[SupGen][Voronoi][Parabola]") +{ + using namespace Slic3r::sla; + double scale = 1e6; + // U shape parabola + Parabola parabola_x2(Line({-1. * scale, -.25 * scale}, + {1. * scale, -.25 * scale}), + Point(0. * scale, .25 * scale)); + + double from_x = 1 * scale; + double to_x = 3 * scale; + Point from(from_x, getParabolaY(parabola_x2, from_x)); + Point to(to_x, getParabolaY(parabola_x2, to_x)); + ParabolaSegment parabola_segment(parabola_x2, from, to); + parabola_check_length(parabola_segment); +} + + diff --git a/tests/sla_print/sla_print_tests.cpp b/tests/sla_print/sla_print_tests.cpp index ebefc0f..e94d25c 100644 --- a/tests/sla_print/sla_print_tests.cpp +++ b/tests/sla_print/sla_print_tests.cpp @@ -31,52 +31,6 @@ const char *const SUPPORT_TEST_MODELS[] = { } // namespace -TEST_CASE("Support point generator should be deterministic if seeded", - "[SLASupportGeneration], [SLAPointGen]") { - TriangleMesh mesh = load_model("A_upsidedown.obj"); - - AABBMesh emesh{mesh}; - - sla::SupportTreeConfig supportcfg; - sla::SupportPointGenerator::Config autogencfg; - autogencfg.head_diameter = float(2 * supportcfg.head_front_radius_mm); - sla::SupportPointGenerator point_gen{emesh, autogencfg, [] {}, [](int) {}}; - - auto bb = mesh.bounding_box(); - double zmin = bb.min.z(); - double zmax = bb.max.z(); - double gnd = zmin - supportcfg.object_elevation_mm; - auto layer_h = 0.05f; - - auto slicegrid = grid(float(gnd), float(zmax), layer_h); - std::vector slices = slice_mesh_ex(mesh.its, slicegrid, CLOSING_RADIUS); - - point_gen.seed(0); - point_gen.execute(slices, slicegrid); - - auto get_chksum = [](const std::vector &pts){ - int64_t chksum = 0; - for (auto &pt : pts) { - auto p = scaled(pt.pos); - chksum += p.x() + p.y() + p.z(); - } - - return chksum; - }; - - int64_t checksum = get_chksum(point_gen.output()); - size_t ptnum = point_gen.output().size(); - REQUIRE(point_gen.output().size() > 0); - - for (int i = 0; i < 20; ++i) { - point_gen.output().clear(); - point_gen.seed(0); - point_gen.execute(slices, slicegrid); - REQUIRE(point_gen.output().size() == ptnum); - REQUIRE(checksum == get_chksum(point_gen.output())); - } -} - TEST_CASE("Flat pad geometry is valid", "[SLASupportGeneration]") { sla::PadConfig padcfg; diff --git a/tests/sla_print/sla_raycast_tests.cpp b/tests/sla_print/sla_raycast_tests.cpp index 1f2962b..2802227 100644 --- a/tests/sla_print/sla_raycast_tests.cpp +++ b/tests/sla_print/sla_raycast_tests.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include #include @@ -7,6 +8,7 @@ #include "sla_test_utils.hpp" using namespace Slic3r; +using namespace Catch; // First do a simple test of the hole raycaster. TEST_CASE("Raycaster - find intersections of a line and cylinder") diff --git a/tests/sla_print/sla_supptgen_tests.cpp b/tests/sla_print/sla_supptgen_tests.cpp index e5e6024..f765961 100644 --- a/tests/sla_print/sla_supptgen_tests.cpp +++ b/tests/sla_print/sla_supptgen_tests.cpp @@ -1,20 +1,32 @@ -#include +#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include "nanosvg/nanosvg.h" // load SVG file #include "sla_test_utils.hpp" -namespace Slic3r { namespace sla { +using namespace Slic3r; +using namespace Slic3r::sla; + +//#define STORE_SAMPLE_INTO_SVG_FILES "C:/data/temp/test_islands/sample_" +//#define STORE_ISLAND_ISSUES "C:/data/temp/issues/" TEST_CASE("Overhanging point should be supported", "[SupGen]") { // Pyramid with 45 deg slope TriangleMesh mesh = make_pyramid(10.f, 10.f); mesh.rotate_y(float(PI)); - mesh.WriteOBJFile("Pyramid.obj"); + //mesh.WriteOBJFile("Pyramid.obj"); sla::SupportPoints pts = calc_support_pts(mesh); @@ -54,18 +66,11 @@ double min_point_distance(const sla::SupportPoints &pts) TEST_CASE("Overhanging horizontal surface should be supported", "[SupGen]") { double width = 10., depth = 10., height = 1.; - TriangleMesh mesh = make_cube(width, depth, height); + TriangleMesh mesh = make_cube(width, depth, height); mesh.translate(0., 0., 5.); // lift up - mesh.WriteOBJFile("Cuboid.obj"); - - sla::SupportPointGenerator::Config cfg; - sla::SupportPoints pts = calc_support_pts(mesh, cfg); - - double mm2 = width * depth; - + // mesh.WriteOBJFile("Cuboid.obj"); + sla::SupportPoints pts = calc_support_pts(mesh); REQUIRE(!pts.empty()); - REQUIRE(pts.size() * cfg.support_force() > mm2 * cfg.tear_pressure()); - REQUIRE(min_point_distance(pts) >= cfg.minimal_distance); } template auto&& center_around_bb(M &&mesh) @@ -84,8 +89,7 @@ TEST_CASE("Overhanging edge should be supported", "[SupGen]") { mesh.translate(0., 0., height); mesh.WriteOBJFile("Prism.obj"); - sla::SupportPointGenerator::Config cfg; - sla::SupportPoints pts = calc_support_pts(mesh, cfg); + sla::SupportPoints pts = calc_support_pts(mesh); Linef3 overh{ {0.f, -depth / 2.f, 0.f}, {0.f, depth / 2.f, 0.f}}; @@ -97,9 +101,8 @@ TEST_CASE("Overhanging edge should be supported", "[SupGen]") { return line_alg::distance_to(overh, Vec3d{pt.pos.cast()}) < 1.; }); - REQUIRE(overh_pts.size() * cfg.support_force() > overh.length() * cfg.tear_pressure()); - double ddiff = min_point_distance(pts) - cfg.minimal_distance; - REQUIRE(ddiff > - 0.1 * cfg.minimal_distance); + //double ddiff = min_point_distance(pts) - cfg.minimal_distance; + //REQUIRE(ddiff > - 0.1 * cfg.minimal_distance); } TEST_CASE("Hollowed cube should be supported from the inside", "[SupGen][Hollowed]") { @@ -114,9 +117,9 @@ TEST_CASE("Hollowed cube should be supported from the inside", "[SupGen][Hollowe Vec3f mv = bb.center().cast() - Vec3f{0.f, 0.f, 0.5f * h}; mesh.translate(-mv); - sla::SupportPointGenerator::Config cfg; - sla::SupportPoints pts = calc_support_pts(mesh, cfg); - sla::remove_bottom_points(pts, mesh.bounding_box().min.z() + EPSILON); + + sla::SupportPoints pts = calc_support_pts(mesh); + //sla::remove_bottom_points(pts, mesh.bounding_box().min.z() + EPSILON); REQUIRE(!pts.empty()); } @@ -132,11 +135,497 @@ TEST_CASE("Two parallel plates should be supported", "[SupGen][Hollowed]") mesh.WriteOBJFile("parallel_plates.obj"); - sla::SupportPointGenerator::Config cfg; - sla::SupportPoints pts = calc_support_pts(mesh, cfg); - sla::remove_bottom_points(pts, mesh.bounding_box().min.z() + EPSILON); + sla::SupportPoints pts = calc_support_pts(mesh); + //sla::remove_bottom_points(pts, mesh.bounding_box().min.z() + EPSILON); REQUIRE(!pts.empty()); } -}} // namespace Slic3r::sla +Slic3r::Polygon create_cross_roads(double size, double width) +{ + auto r1 = PolygonUtils::create_rect(5.3 * size, width); + r1.rotate(3.14/4); + r1.translate(2 * size, width / 2); + auto r2 = PolygonUtils::create_rect(6.1 * size, 3 / 4. * width); + r2.rotate(-3.14 / 5); + r2.translate(3 * size, width / 2); + auto r3 = PolygonUtils::create_rect(7.9 * size, 4 / 5. * width); + r3.translate(2*size, width/2); + auto r4 = PolygonUtils::create_rect(5 / 6. * width, 5.7 * size); + r4.translate(-size,3*size); + Polygons rr = union_(Polygons({r1, r2, r3, r4})); + return rr.front(); +} + +ExPolygon create_trinagle_with_hole(double size) +{ + auto hole = PolygonUtils::create_equilateral_triangle(size / 3); + hole.reverse(); + hole.rotate(3.14 / 4); + return ExPolygon(PolygonUtils::create_equilateral_triangle(size), hole); +} + +ExPolygon create_square_with_hole(double size, double hole_size) +{ + assert(sqrt(hole_size *hole_size / 2) < size); + auto hole = PolygonUtils::create_square(hole_size); + hole.rotate(M_PI / 4.); // 45 + hole.reverse(); + return ExPolygon(PolygonUtils::create_square(size), hole); +} + +ExPolygon create_square_with_4holes(double size, double hole_size) { + auto hole = PolygonUtils::create_square(hole_size); + hole.reverse(); + double size_4 = size / 4; + auto h1 = hole; + h1.translate(size_4, size_4); + auto h2 = hole; + h2.translate(-size_4, size_4); + auto h3 = hole; + h3.translate(size_4, -size_4); + auto h4 = hole; + h4.translate(-size_4, -size_4); + ExPolygon result(PolygonUtils::create_square(size)); + result.holes = Polygons({h1, h2, h3, h4}); + return result; +} + +// boudary of circle +ExPolygon create_disc(double radius, double width, size_t count_line_segments) +{ + double width_2 = width / 2; + auto hole = PolygonUtils::create_circle(radius - width_2, + count_line_segments); + hole.reverse(); + return ExPolygon(PolygonUtils::create_circle(radius + width_2, + count_line_segments), + hole); +} + +Slic3r::Polygon create_V_shape(double height, double line_width, double angle = M_PI/4) { + double angle_2 = angle / 2; + auto left_side = PolygonUtils::create_rect(line_width, height); + auto right_side = left_side; + right_side.rotate(-angle_2); + double small_move = cos(angle_2) * line_width / 2; + double side_move = sin(angle_2) * height / 2 + small_move; + right_side.translate(side_move,0); + left_side.rotate(angle_2); + left_side.translate(-side_move, 0); + auto bottom = PolygonUtils::create_rect(4 * small_move, line_width); + bottom.translate(0., -cos(angle_2) * height / 2 + line_width/2); + Polygons polygons = union_(Polygons({left_side, right_side, bottom})); + return polygons.front(); +} + +ExPolygon create_tiny_wide_test_1(double wide, double tiny) +{ + double hole_size = wide; + double width = 2 * wide + hole_size; + double height = wide + hole_size + tiny; + auto outline = PolygonUtils::create_rect(width, height); + auto hole = PolygonUtils::create_rect(hole_size, hole_size); + hole.reverse(); + int hole_move_y = height/2 - (hole_size/2 + tiny); + hole.translate(0, hole_move_y); + + ExPolygon result(outline); + result.holes = {hole}; + return result; +} + +ExPolygon create_tiny_wide_test_2(double wide, double tiny) +{ + double hole_size = wide; + double width = (3 + 1) * wide + 3 * hole_size; + double height = 2*wide + 2*tiny + 3*hole_size; + auto outline = PolygonUtils::create_rect( width, height); + auto hole = PolygonUtils::create_rect(hole_size, hole_size); + hole.reverse(); + auto hole2 = hole;// copy + auto hole3 = hole; // copy + auto hole4 = hole; // copy + + int hole_move_x = wide + hole_size; + int hole_move_y = wide + hole_size; + hole.translate(hole_move_x, hole_move_y); + hole2.translate(-hole_move_x, hole_move_y); + hole3.translate(hole_move_x, -hole_move_y); + hole4.translate(-hole_move_x, -hole_move_y); + + auto hole5 = PolygonUtils::create_circle(hole_size / 2, 16); + hole5.reverse(); + auto hole6 = hole5; // copy + hole5.translate(0, hole_move_y); + hole6.translate(0, -hole_move_y); + + auto hole7 = PolygonUtils::create_equilateral_triangle(hole_size); + hole7.reverse(); + auto hole8 = PolygonUtils::create_circle(hole_size/2, 7, Point(hole_move_x,0)); + hole8.reverse(); + auto hole9 = PolygonUtils::create_circle(hole_size/2, 5, Point(-hole_move_x,0)); + hole9.reverse(); + + ExPolygon result(outline); + result.holes = {hole, hole2, hole3, hole4, hole5, hole6, hole7, hole8, hole9}; + return result; +} + +ExPolygon create_tiny_between_holes(double wide, double tiny) +{ + double hole_size = wide; + double width = 2 * wide + 2*hole_size + tiny; + double height = 2 * wide + hole_size; + auto outline = PolygonUtils::create_rect(width, height); + auto holeL = PolygonUtils::create_rect(hole_size, hole_size); + holeL.reverse(); + auto holeR = holeL; + int hole_move_x = (hole_size + tiny)/2; + holeL.translate(-hole_move_x, 0); + holeR.translate(hole_move_x, 0); + + ExPolygon result(outline); + result.holes = {holeL, holeR}; + return result; +} + +// stress test for longest path +// needs reshape +ExPolygon create_mountains(double size) { + return ExPolygon({{0., 0.}, + {size, 0.}, + {5 * size / 6, size}, + {4 * size / 6, size / 6}, + {3 * size / 7, 2 * size}, + {2 * size / 7, size / 6}, + {size / 7, size}}); +} + +/// Neighbor points create trouble for voronoi - test of neccessary offseting(closing) of contour +ExPolygon create_cylinder_bottom_slice() { + indexed_triangle_set its_cylinder = its_make_cylinder(6.6551999999999998, 11.800000000000001); + MeshSlicingParams param; + Polygons polygons = slice_mesh(its_cylinder, 0.0125000002, param); + return ExPolygon{polygons.front()}; +} + +ExPolygon load_frog(){ + TriangleMesh mesh = load_model("frog_legs.obj"); + std::vector slices = slice_mesh_ex(mesh.its, {0.1f}); + return slices.front()[1]; +} + +ExPolygon load_svg(const std::string& svg_filepath) { + struct NSVGimage *image = nsvgParseFromFile(svg_filepath.c_str(), "px", 96); + ScopeGuard sg_image([&image] { nsvgDelete(image); }); + + auto to_polygon = [](NSVGpath *path) { + Polygon r; + r.points.reserve(path->npts); + for (int i = 0; i < path->npts; i++) + r.points.push_back(Point(path->pts[2 * i], path->pts[2 * i + 1])); + return r; + }; + + for (NSVGshape *shape_ptr = image->shapes; shape_ptr != NULL; shape_ptr = shape_ptr->next) { + const NSVGshape &shape = *shape_ptr; + if (!(shape.flags & NSVG_FLAGS_VISIBLE)) continue; // is visible + if (shape.fill.type != NSVG_PAINT_NONE) continue; // is not used fill + if (shape.stroke.type == NSVG_PAINT_NONE) continue; // exist stroke + //if (shape.strokeWidth < 1e-5f) continue; // is visible stroke width + //if (shape.stroke.color != 4278190261) continue; // is red + ExPolygon result; + for (NSVGpath *path = shape.paths; path != NULL; path = path->next) { + // Path order is reverse to path in file + if (path->next == NULL) // last path is contour + result.contour = to_polygon(path); + else + result.holes.push_back(to_polygon(path)); + } + return result; + } + REQUIRE(false); + return {}; +} + +ExPolygons createTestIslands(double size) +{ + std::string dir = std::string(TEST_DATA_DIR PATH_SEPARATOR) + "sla_islands/"; + bool useFrogLeg = false; + // need post reorganization of longest path + ExPolygons result = { + // one support point + ExPolygon(PolygonUtils::create_equilateral_triangle(size)), + ExPolygon(PolygonUtils::create_square(size)), + ExPolygon(PolygonUtils::create_rect(size / 2, size)), + ExPolygon(PolygonUtils::create_isosceles_triangle(size / 2, 3 * size / 2)), // small sharp triangle + ExPolygon(PolygonUtils::create_circle(size / 2, 10)), + create_square_with_4holes(size, size / 4), + create_disc(size/4, size / 4, 10), + ExPolygon(create_V_shape(2*size/3, size / 4)), + + // two support points + ExPolygon(PolygonUtils::create_isosceles_triangle(size / 2, 3 * size)), // small sharp triangle + ExPolygon(PolygonUtils::create_rect(size / 2, 3 * size)), + ExPolygon(create_V_shape(1.5*size, size/3)), + + // tiny line support points + ExPolygon(PolygonUtils::create_rect(size / 2, 10 * size)), // long line + ExPolygon(create_V_shape(size*4, size / 3)), + ExPolygon(create_cross_roads(size, size / 3)), + create_disc(3*size, size / 4, 30), + create_disc(2*size, size, 12), // 3 points + create_square_with_4holes(5 * size, 5 * size / 2 - size / 3), + + // Tiny and wide part together with holes + ExPolygon(PolygonUtils::create_isosceles_triangle(5. * size, 40. * size)), + create_tiny_wide_test_1(3 * size, 2 / 3. * size), + create_tiny_wide_test_2(3 * size, 2 / 3. * size), + create_tiny_between_holes(3 * size, 2 / 3. * size), + + ExPolygon(PolygonUtils::create_equilateral_triangle(scale_(18.6))), + create_cylinder_bottom_slice(), + load_svg(dir + "lm_issue.svg"), // change from thick to thin and vice versa on circle + load_svg(dir + "SPE-2674.svg"), // center of longest path lay inside of the VD node + load_svg(dir + "SPE-2674_2.svg"), // missing Voronoi vertex even after the rotation of input. + + // still problem + // three support points + ExPolygon(PolygonUtils::create_equilateral_triangle(3 * size)), + ExPolygon(PolygonUtils::create_circle(size, 20)), + + create_mountains(size), + create_trinagle_with_hole(size), + create_square_with_hole(size, size / 2), + create_square_with_hole(size, size / 3) + }; + if (useFrogLeg) + result.push_back(load_frog()); + return result; +} + +Points createNet(const BoundingBox& bounding_box, double distance) +{ + Point size = bounding_box.size(); + double distance_2 = distance / 2; + int cols1 = static_cast(floor(size.x() / distance))+1; + int cols2 = static_cast(floor((size.x() - distance_2) / distance))+1; + // equilateral triangle height with side distance + double h = sqrt(distance * distance - distance_2 * distance_2); + int rows = static_cast(floor(size.y() / h)) +1; + int rows_2 = rows / 2; + size_t count_points = rows_2 * (cols1 + static_cast(cols2)); + if (rows % 2 == 1) count_points += cols2; + Points result; + result.reserve(count_points); + bool isOdd = true; + Point offset = bounding_box.min; + double x_max = offset.x() + static_cast(size.x()); + double y_max = offset.y() + static_cast(size.y()); + for (double y = offset.y(); y <= y_max; y += h) { + double x_offset = offset.x(); + if (isOdd) x_offset += distance_2; + isOdd = !isOdd; + for (double x = x_offset; x <= x_max; x += distance) { + result.emplace_back(x, y); + } + } + assert(result.size() == count_points); + return result; +} + +// create uniform triangle net and return points laying inside island +Points rasterize(const ExPolygon &island, double distance) { + BoundingBox bb; + for (const Point &pt : island.contour.points) bb.merge(pt); + Points fullNet = createNet(bb, distance); + Points result; + result.reserve(fullNet.size()); + std::copy_if(fullNet.begin(), fullNet.end(), std::back_inserter(result), + [&island](const Point &p) { return island.contains(p); }); + return result; +} + +SupportIslandPoints test_island_sampling(const ExPolygon & island, + const SampleConfig &config) +{ + auto points = uniform_support_island(island, {}, config); + + Points chck_points = rasterize(island, config.head_radius); // TODO: Use resolution of printer + bool is_island_supported = true; // Check rasterized island points that exist support point in max_distance + double max_distance = config.thick_inner_max_distance; + std::vector point_distances(chck_points.size(), {max_distance + 1}); + for (size_t index = 0; index < chck_points.size(); ++index) { + const Point &chck_point = chck_points[index]; + double &min_distance = point_distances[index]; + bool exist_close_support_point = false; + for (const auto &island_point : points) { + const Point& p = island_point->point; + Point abs_diff(fabs(p.x() - chck_point.x()), + fabs(p.y() - chck_point.y())); + if (abs_diff.x() < min_distance && abs_diff.y() < min_distance) { + double distance = sqrt((double) abs_diff.x() * abs_diff.x() + + (double) abs_diff.y() * abs_diff.y()); + if (min_distance > distance) { + min_distance = distance; + exist_close_support_point = true; + } + } + } + if (!exist_close_support_point) is_island_supported = false; + } + + bool is_all_points_inside_island = true; + for (const auto &point : points) + if (!island.contains(point->point)) + is_all_points_inside_island = false; + +#ifdef STORE_ISLAND_ISSUES + if (!is_island_supported || !is_all_points_inside_island) { // visualize + static int counter = 0; + BoundingBox bb; + for (const Point &pt : island.contour.points) bb.merge(pt); + SVG svg(STORE_ISLAND_ISSUES + std::string("Error") + std::to_string(++counter) + ".svg", bb); + svg.draw(island, "blue", 0.5f); + for (auto& p : points) + svg.draw(p->point, island.contains(p->point) ? "lightgreen" : "red", config.head_radius); + for (size_t index = 0; index < chck_points.size(); ++index) { + const Point &chck_point = chck_points[index]; + double distance = point_distances[index]; + bool isOk = distance < max_distance; + std::string color = (isOk) ? "gray" : "red"; + svg.draw(chck_point, color, config.head_radius / 4); + } + } +#endif // STORE_ISLAND_ISSUES + + CHECK(!points.empty()); + CHECK(is_all_points_inside_island); + // CHECK(is_island_supported); // TODO: skip special cases with one point and 2 points + + return points; +} + +SampleConfig create_sample_config(double size) { + float head_diameter = .4f; + return SampleConfigFactory::create(head_diameter); + + //coord_t max_distance = 3 * size + 0.1; + //SampleConfig cfg; + //cfg.head_radius = size / 4; + //cfg.minimal_distance_from_outline = cfg.head_radius; + //cfg.maximal_distance_from_outline = max_distance/4; + //cfg.max_length_for_one_support_point = 2*size; + //cfg.max_length_for_two_support_points = 4*size; + //cfg.thin_max_width = size; + //cfg.thick_min_width = cfg.thin_max_width; + //cfg.thick_outline_max_distance = max_distance; + + //cfg.minimal_move = static_cast(size/30); + //cfg.count_iteration = 100; + //cfg.max_align_distance = 0; + //return cfg; +} + +#ifdef STORE_SAMPLE_INTO_SVG_FILES +namespace { +void store_sample(const SupportIslandPoints &samples, const ExPolygon &island) { + static int counter = 0; + BoundingBox bb(island.contour.points); + SVG svg((STORE_SAMPLE_INTO_SVG_FILES + std::to_string(counter++) + ".svg").c_str(), bb); + + double mm = scale_(1); + svg.draw(island, "lightgray"); + for (const auto &s : samples) + svg.draw(s->point, "blue", 0.2*mm); + + + // draw resolution + Point p(bb.min.x() + 1e6, bb.max.y() - 2e6); + svg.draw_text(p, (std::to_string(samples.size()) + " samples").c_str(), "black"); + svg.draw_text(p - Point(0., 1.8e6), "Scale 1 cm ", "black"); + Point start = p - Point(0., 2.3e6); + svg.draw(Line(start + Point(0., 5e5), start + Point(10*mm, 5e5)), "black", 2e5); + svg.draw(Line(start + Point(0., -5e5), start + Point(10*mm, -5e5)), "black", 2e5); + svg.draw(Line(start + Point(10*mm, 5e5), start + Point(10*mm, -5e5)), "black", 2e5); + for (int i=0; i<10;i+=2) + svg.draw(Line(start + Point(i*mm, 0.), start + Point((i+1)*mm, 0.)), "black", 1e6); +} +} // namespace +#endif // STORE_SAMPLE_INTO_SVG_FILES + +/// +/// Check for correct sampling of island +/// +TEST_CASE("Uniform sample test islands", "[SupGen], [VoronoiSkeleton]") +{ + //set_logging_level(5); + float head_diameter = .4f; + SampleConfig cfg = SampleConfigFactory::create(head_diameter); + //cfg.path = "C:/data/temp/islands/<>.svg"; + ExPolygons islands = createTestIslands(7 * scale_(head_diameter)); + for (ExPolygon &island : islands) { + // information for debug which island cause problem + [[maybe_unused]] size_t debug_index = &island - &islands.front(); + + SupportIslandPoints points = test_island_sampling(island, cfg); +#ifdef STORE_SAMPLE_INTO_SVG_FILES + store_sample(points, island); +#endif // STORE_SAMPLE_INTO_SVG_FILES + + double angle = 3.14 / 3; // cca 60 degree + + island.rotate(angle); + SupportIslandPoints pointsR = test_island_sampling(island, cfg); +#ifdef STORE_SAMPLE_INTO_SVG_FILES + store_sample(pointsR, island); +#endif // STORE_SAMPLE_INTO_SVG_FILES + + // points count should be the same + //CHECK(points.size() == pointsR.size()) + } +} + +TEST_CASE("Sample island with config", "[SupportIsland]") { + // set_logging_level(5); + SampleConfig cfg{ + /*thin_max_distance*/ 5832568, + /*thick_inner_max_distance*/ 7290710, + /*thick_outline_max_distance*/ 5468032, + /*head_radius*/ 250000, + /*minimal_distance_from_outline*/ 250000, + /*maximal_distance_from_outline*/ 1944189, + /*max_length_for_one_support_point*/ 1869413, + /*max_length_for_two_support_points*/ 7290710, + /*max_length_ratio_for_two_support_points*/ 0.250000000f, + /*thin_max_width*/ 4673532, + /*thick_min_width*/ 4019237, + /*min_part_length*/ 5832568, + /*minimal_move*/ 100000, + /*count_iteration*/ 30, + /*max_align_distance*/ 3645355, + /*simplification_tolerance*/ 50000.000000000007 + //*path*/, "C:/data/temp/islands/<>.svg" // need define OPTION_TO_STORE_ISLAND in SampleConfig.hpp + }; + std::string dir = std::string(TEST_DATA_DIR PATH_SEPARATOR) + "sla_islands/"; + ExPolygon island = load_svg(dir + "SPE-2709.svg"); // Bad field creation + SupportIslandPoints points = test_island_sampling(island, cfg); + // in time of write poins.size() == 39 + CHECK(points.size() > 22); // not only thin parts +} + +TEST_CASE("Disable visualization", "[hide]") +{ + CHECK(true); +#ifdef STORE_SAMPLE_INTO_SVG_FILES + CHECK(false); +#endif // STORE_SAMPLE_INTO_SVG_FILES +#ifdef STORE_ISLAND_ISSUES + CHECK(false); +#endif // STORE_ISLAND_ISSUES +#ifdef USE_ISLAND_GUI_FOR_SETTINGS + CHECK(false); +#endif // USE_ISLAND_GUI_FOR_SETTINGS + CHECK(is_uniform_support_island_visualization_disabled()); +} diff --git a/tests/sla_print/sla_supptreeutils_tests.cpp b/tests/sla_print/sla_supptreeutils_tests.cpp index c8abbb8..d7332ef 100644 --- a/tests/sla_print/sla_supptreeutils_tests.cpp +++ b/tests/sla_print/sla_supptreeutils_tests.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include #include @@ -7,6 +8,8 @@ #include "libslic3r/SLA/SupportTreeUtils.hpp" #include "libslic3r/SLA/SupportTreeUtilsLegacy.hpp" +using Catch::Approx; + // Test pair hash for 'nums' random number pairs. template void test_pairhash() { diff --git a/tests/sla_print/sla_test_utils.cpp b/tests/sla_print/sla_test_utils.cpp index f294abc..18b0b09 100644 --- a/tests/sla_print/sla_test_utils.cpp +++ b/tests/sla_print/sla_test_utils.cpp @@ -128,29 +128,27 @@ void test_supports(const std::string &obj_filename, // TODO: do the cgal hole cutting... // Create the support point generator - sla::SupportPointGenerator::Config autogencfg; - autogencfg.head_diameter = float(2 * supportcfg.head_front_radius_mm); - sla::SupportPointGenerator point_gen{sm.emesh, autogencfg, [] {}, [](int) {}}; - - point_gen.seed(0); // Make the test repeatable - point_gen.execute(out.model_slices, out.slicegrid); - + sla::SupportPointGeneratorConfig autogencfg; + sla::SupportPointGeneratorData gen_data = sla::prepare_generator_data(std::move(out.model_slices), out.slicegrid); + sla::LayerSupportPoints layer_support_points = sla::generate_support_points(gen_data, autogencfg); + double allowed_move = (out.slicegrid[1] - out.slicegrid[0]) + std::numeric_limits::epsilon(); // Get the calculated support points. - sm.pts = point_gen.output(); + sm.pts = sla::move_on_mesh_surface(layer_support_points, sm.emesh, allowed_move); + out.model_slices = std::move(gen_data.slices); // return ownership int validityflags = ASSUME_NO_REPAIR; // If there is no elevation, support points shall be removed from the // bottom of the object. - if (std::abs(supportcfg.object_elevation_mm) < EPSILON) { - sla::remove_bottom_points(sm.pts, zmin + supportcfg.base_height_mm); - } else { - // Should be support points at least on the bottom of the model - REQUIRE_FALSE(sm.pts.empty()); + //if (std::abs(supportcfg.object_elevation_mm) < EPSILON) { + // sla::remove_bottom_points(sm.pts, zmin + supportcfg.base_height_mm); + //} else { + // // Should be support points at least on the bottom of the model + // REQUIRE_FALSE(sm.pts.empty()); - // Also the support mesh should not be empty. - validityflags |= ASSUME_NO_EMPTY; - } + // // Also the support mesh should not be empty. + // validityflags |= ASSUME_NO_EMPTY; + //} // Generate the actual support tree sla::SupportTreeBuilder treebuilder; @@ -465,7 +463,7 @@ double predict_error(const ExPolygon &p, const sla::PixelDim &pd) sla::SupportPoints calc_support_pts( const TriangleMesh & mesh, - const sla::SupportPointGenerator::Config &cfg) + const sla::SupportPointGeneratorConfig &cfg) { // Prepare the slice grid and the slices auto bb = cast(mesh.bounding_box()); @@ -473,12 +471,10 @@ sla::SupportPoints calc_support_pts( std::vector slices = slice_mesh_ex(mesh.its, heights, CLOSING_RADIUS); // Prepare the support point calculator + sla::SupportPointGeneratorData gen_data = sla::prepare_generator_data(std::move(slices), heights); + sla::LayerSupportPoints layer_support_points = sla::generate_support_points(gen_data, cfg); AABBMesh emesh{mesh}; - sla::SupportPointGenerator spgen{emesh, cfg, []{}, [](int){}}; - - // Calculate the support points - spgen.seed(0); - spgen.execute(slices, heights); - - return spgen.output(); + double allowed_move = (heights[1] - heights[0]) + std::numeric_limits::epsilon(); + // Get the calculated support points. + return sla::move_on_mesh_surface(layer_support_points, emesh, allowed_move); } diff --git a/tests/sla_print/sla_test_utils.hpp b/tests/sla_print/sla_test_utils.hpp index 103b2f6..73e3c0e 100644 --- a/tests/sla_print/sla_test_utils.hpp +++ b/tests/sla_print/sla_test_utils.hpp @@ -1,7 +1,8 @@ #ifndef SLA_TEST_UTILS_HPP #define SLA_TEST_UTILS_HPP -#include +#include +#include #include // Debug @@ -22,6 +23,7 @@ #include "libslic3r/SVG.hpp" using namespace Slic3r; +using Catch::Approx; enum e_validity { ASSUME_NO_EMPTY = 1, @@ -134,6 +136,6 @@ double predict_error(const ExPolygon &p, const sla::PixelDim &pd); sla::SupportPoints calc_support_pts( const TriangleMesh & mesh, - const sla::SupportPointGenerator::Config &cfg = {}); + const sla::SupportPointGeneratorConfig &cfg = {}); #endif // SLA_TEST_UTILS_HPP diff --git a/tests/sla_print/sla_vectorUtils_tests.cpp b/tests/sla_print/sla_vectorUtils_tests.cpp new file mode 100644 index 0000000..aa0f4aa --- /dev/null +++ b/tests/sla_print/sla_vectorUtils_tests.cpp @@ -0,0 +1,25 @@ +#include +#include + +using namespace Slic3r::sla; + +TEST_CASE("Reorder", "[Utils], [VectorUtils]") +{ + std::vector data{0, 1, 3, 2, 4, 7, 6, 5, 8}; + std::vector order{0, 1, 3, 2, 4, 7, 6, 5, 8}; + + VectorUtils::reorder(order.begin(), order.end(), data.begin()); + for (size_t i = 0; i < data.size() - 1; ++i) { + CHECK(data[i] < data[i + 1]); + } +} + +TEST_CASE("Reorder destructive", "[Utils], [VectorUtils]"){ + std::vector data {0, 1, 3, 2, 4, 7, 6, 5, 8}; + std::vector order{0, 1, 3, 2, 4, 7, 6, 5, 8}; + + VectorUtils::reorder_destructive(order.begin(), order.end(), data.begin()); + for (size_t i = 0; i < data.size() - 1;++i) { + CHECK(data[i] < data[i + 1]); + } +} diff --git a/tests/sla_print/sla_voronoi_graph_tests.cpp b/tests/sla_print/sla_voronoi_graph_tests.cpp new file mode 100644 index 0000000..26fdf93 --- /dev/null +++ b/tests/sla_print/sla_voronoi_graph_tests.cpp @@ -0,0 +1,91 @@ +#include "sla_test_utils.hpp" +#include +#include + +using namespace Slic3r; +using namespace Slic3r::sla; + +TEST_CASE("Convert coordinate datatype", "[Voronoi]") +{ + using VD = Slic3r::Geometry::VoronoiDiagram; + VD::coordinate_type coord = 101197493902.64694; + coord_t coord2 = VoronoiGraphUtils::to_coord(coord); + CHECK(coord2 > 100); + + coord = -101197493902.64694; + coord2 = VoronoiGraphUtils::to_coord(coord); + CHECK(coord2 < -100); + + coord = 12345.1; + coord2 = VoronoiGraphUtils::to_coord(coord); + CHECK(coord2 == 12345); + + coord = -12345.1; + coord2 = VoronoiGraphUtils::to_coord(coord); + CHECK(coord2 == -12345); + + coord = 12345.9; + coord2 = VoronoiGraphUtils::to_coord(coord); + CHECK(coord2 == 12346); + + coord = -12345.9; + coord2 = VoronoiGraphUtils::to_coord(coord); + CHECK(coord2 == -12346); +} + +void check(Slic3r::Points points, double max_distance) { + using VD = Slic3r::Geometry::VoronoiDiagram; + VD vd; + vd.construct_voronoi(points.begin(), points.end()); + double max_area = M_PI * max_distance*max_distance; // circle = Pi * r^2 + for (const VD::cell_type &cell : vd.cells()) { + Slic3r::Polygon polygon = VoronoiGraphUtils::to_polygon(cell, points, max_distance); + CHECK(polygon.area() < max_area); + CHECK(polygon.contains(points[cell.source_index()])); + } +} + +TEST_CASE("Polygon from cell", "[Voronoi]") +{ + // for debug #define SLA_SVG_VISUALIZATION_CELL_2_POLYGON in VoronoiGraphUtils + double max_distance = 1e7; + coord_t size = (int) (4e6); + coord_t half_size = size/2; + + Slic3r::Points two_cols({Point(0, 0), Point(size, 0)}); + check(two_cols, max_distance); + + Slic3r::Points two_rows({Point(0, 0), Point(0, size)}); + check(two_rows, max_distance); + + Slic3r::Points two_diag({Point(0, 0), Point(size, size)}); + check(two_diag, max_distance); + + Slic3r::Points three({Point(0, 0), Point(size, 0), Point(half_size, size)}); + check(three, max_distance); + + Slic3r::Points middle_point({Point(0, 0), Point(size, half_size), + Point(-size, half_size), Point(0, -size)}); + check(middle_point, max_distance); + + Slic3r::Points middle_point2({Point(half_size, half_size), Point(-size, -size), Point(-size, size), + Point(size, -size), Point(size, size)}); + check(middle_point2, max_distance); + + Slic3r::Points diagonal_points({{-123473762, 71287970}, + {-61731535, 35684428}, + {0, 0}, + {61731535, -35684428}, + {123473762, -71287970}}); + double diagonal_max_distance = 5e7; + check(diagonal_points, diagonal_max_distance); + + int scale = 10; + Slic3r::Points diagonal_points2; + std::transform(diagonal_points.begin(), diagonal_points.end(), + std::back_inserter(diagonal_points2), + [&](const Slic3r::Point &p) { return p/scale; }); + check(diagonal_points2, diagonal_max_distance / scale); +} + + diff --git a/tests/sla_print/sla_zcorrection_tests.cpp b/tests/sla_print/sla_zcorrection_tests.cpp index 69734c2..cd5063f 100644 --- a/tests/sla_print/sla_zcorrection_tests.cpp +++ b/tests/sla_print/sla_zcorrection_tests.cpp @@ -1,4 +1,6 @@ -#include +#include +#include +#include #include #include @@ -8,6 +10,8 @@ #include "libslic3r/MTUtils.hpp" #include "libslic3r/SVG.hpp" +using Catch::Approx; + void print_depthmap(std::string_view prefix, const Slic3r::BoundingBox &bb, const Slic3r::sla::zcorr_detail::DepthMap &dm) diff --git a/tests/slic3rutils/CMakeLists.txt b/tests/slic3rutils/CMakeLists.txt index 85ce441..a49f91d 100644 --- a/tests/slic3rutils/CMakeLists.txt +++ b/tests/slic3rutils/CMakeLists.txt @@ -8,7 +8,7 @@ add_executable(${_TEST_NAME}_tests ) # mold linker for successful linking needs also to link TBB library and link it before libslic3r. -target_link_libraries(${_TEST_NAME}_tests test_common TBB::tbb TBB::tbbmalloc libslic3r_gui libslic3r) +target_link_libraries(${_TEST_NAME}_tests test_common TBB::tbb TBB::tbbmalloc libslic3r_gui libslic3r libseqarrange) if (MSVC) target_link_libraries(${_TEST_NAME}_tests Setupapi.lib) diff --git a/tests/slic3rutils/secretstore_tests.cpp b/tests/slic3rutils/secretstore_tests.cpp index 185ddb8..1219175 100644 --- a/tests/slic3rutils/secretstore_tests.cpp +++ b/tests/slic3rutils/secretstore_tests.cpp @@ -1,4 +1,4 @@ -#include "catch2/catch.hpp" +#include "catch2/catch_test_macros.hpp" #include "slic3r/Utils/Secrets.hpp" diff --git a/tests/slic3rutils/slic3r_arrangejob_tests.cpp b/tests/slic3rutils/slic3r_arrangejob_tests.cpp index 1cd35de..c569d75 100644 --- a/tests/slic3rutils/slic3r_arrangejob_tests.cpp +++ b/tests/slic3rutils/slic3r_arrangejob_tests.cpp @@ -1,4 +1,6 @@ -#include "catch2/catch.hpp" +#include +#include +#include #include "test_utils.hpp" #include @@ -9,10 +11,13 @@ #include "slic3r/GUI/Jobs/ArrangeJob2.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/FileReader.hpp" #include "libslic3r/SLAPrint.hpp" #include "libslic3r/Format/3mf.hpp" +using Catch::Approx; + class RandomArrangeSettings: public Slic3r::arr2::ArrangeSettingsView { Slic3r::arr2::ArrangeSettingsDb::Values m_v; @@ -84,7 +89,7 @@ TEST_CASE("Basic arrange with cube", "[arrangejob]") { DynamicPrintConfig cfg; cfg.load_from_ini(basepath + "default_fff.ini", ForwardCompatibilitySubstitutionRule::Enable); - Model m = Model::read_from_file(basepath + "20mm_cube.obj", &cfg); + Model m = FileReader::load_model(basepath + "20mm_cube.obj"); UIThreadWorker w; arr2::ArrangeSettings settings; diff --git a/tests/slic3rutils/slic3r_jobs_tests.cpp b/tests/slic3rutils/slic3r_jobs_tests.cpp index abb8b15..f9ac409 100644 --- a/tests/slic3rutils/slic3r_jobs_tests.cpp +++ b/tests/slic3rutils/slic3r_jobs_tests.cpp @@ -1,4 +1,5 @@ -#include "catch2/catch.hpp" +#include +#include #include #include diff --git a/tests/slic3rutils/slic3r_version_tests.cpp b/tests/slic3rutils/slic3r_version_tests.cpp index 14f4f5d..1b20f83 100644 --- a/tests/slic3rutils/slic3r_version_tests.cpp +++ b/tests/slic3rutils/slic3r_version_tests.cpp @@ -1,4 +1,4 @@ -#include "catch2/catch.hpp" +#include #include "slic3r/Config/Version.hpp" diff --git a/tests/thumbnails/test_thumbnails_ini_string.cpp b/tests/thumbnails/test_thumbnails_ini_string.cpp index 32ec5cb..1ab4964 100644 --- a/tests/thumbnails/test_thumbnails_ini_string.cpp +++ b/tests/thumbnails/test_thumbnails_ini_string.cpp @@ -1,4 +1,4 @@ -#include +#include #include "libslic3r/Config.hpp" #include "libslic3r/PrintConfig.hpp" diff --git a/tests/thumbnails/test_thumbnails_input_string.cpp b/tests/thumbnails/test_thumbnails_input_string.cpp index 4c623b2..b1b4b8b 100644 --- a/tests/thumbnails/test_thumbnails_input_string.cpp +++ b/tests/thumbnails/test_thumbnails_input_string.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include