diff --git a/deps/+z3/z3.cmake b/deps/+z3/z3.cmake new file mode 100644 index 0000000000..81736d3766 --- /dev/null +++ b/deps/+z3/z3.cmake @@ -0,0 +1,15 @@ +add_cmake_project(z3 + URL https://github.com/Z3Prover/z3/archive/refs/tags/z3-4.13.0.zip + URL_HASH SHA256=81543736dcbbbcb037a7df55d0be596245d509f3f69f56610df32728e48ee050 + CMAKE_ARGS + -DCMAKE_POSITION_INDEPENDENT_CODE=ON + -DZ3_INCLUDE_GIT_HASH=OFF + -DZ3_INCLUDE_GIT_DESCRIBE=OFF + -DZ3_USE_LIB_GMP=OFF + -DZ3_BUILD_LIBZ3_SHARED=OFF + -DZ3_ENABLE_EXAMPLE_TARGETS=OFF + -DZ3_ALWAYS_BUILD_DOCS=OFF + -DZ3_BUILD_EXECUTABLE=OFF + -DZ3_BUILD_TEST_EXECUTABLES=OFF +) + diff --git a/resources/data/printer_gantries/geometries.txt b/resources/data/printer_gantries/geometries.txt new file mode 100644 index 0000000000..dabf55f65b --- /dev/null +++ b/resources/data/printer_gantries/geometries.txt @@ -0,0 +1,286 @@ +{ + "printers": [ + { + "printer_notes_regex": ".*PRINTER_MODEL_MK4(?!S).*", + "gantry_model_filename": "prusa3d_mk4_gantry.stl", + "slices": [ + { + "height": "0", + "type": "convex", + "polygons": [ + "-5,-5;5,-5;5,5;-5,5" + ] + }, + { + "height": "3", + "type": "convex", + "polygons": [ + "-9,-17; 40,-17; 40,44; -9,44", + "-36,-44; 40,-44; 40,-13; -36,-13" + ] + }, + { + "height": "22", + "type": "convex", + "polygons": [ + "-41,-45; 16,-45; 16,22; -41,22", + "11,-45; 39,-45; 39,45; 11,45" + ] + }, + { + "height": "11", + "type": "box", + "polygons": [ + "-300,-23;300,-23;300,-35;-300,-35" + ] + }, + { + "height": "13", + "type": "box", + "polygons": [ + "-13,-84;11,-84;11,-38;-13,-38", + "11,-300;300,-300;300,-84;11,-84" + ] + } + ] + }, + { + "printer_notes_regex": ".*PRINTER_MODEL_MK4S.*", + "gantry_model_filename": "prusa3d_mk4s_gantry.stl", + "slices": [ + { + "height": "0", + "type": "convex", + "polygons": [ + "-29,-19; 28,-19; 28,37; -29,37" + + ] + }, + { + "height": "5", + "type": "convex", + "polygons": [ + "-37,-40; 34,-40; 34,43; -37,43" + ] + }, + { + "height": "7", + "type": "convex", + "polygons": [ + "-49,7; 27,7; 27,83; -49,83", + "-42,-46; 40,-46; 40,14; -42,14" + ] + }, + { + "height": "11", + "type": "box", + "polygons": [ + "-300,-38; 300,-38; 300,-22; -300,-22" + ] + }, + { + "height": "12", + "type": "box", + "polygons": [ + "-14,-85; 11,-85; 11,-39; -14,-39", + "-14,-300; 300,-300; 300,-39; -14,-39" + ] + } + ] + }, + { + "printer_notes_regex": ".*PRINTER_MODEL_MK3.*", + "gantry_model_filename": "prusa3d_mk3s_gantry.stl", + "slices": [ + { + "height": "0", + "type": "convex", + "polygons": [ + "-5,-5;5,-5;5,5;-5,5", + "-30,-12;-14,-12;-14,2;-30,2" + ] + }, + { + "height": "2", + "type": "convex", + "polygons": [ + "-20,-38;44,-38;44,18;-20,18" + ] + }, + { + "height": "6", + "type": "convex", + "polygons": [ + "-34,-43;37,-43;37,16;-34,16", + "-45,9;37,9;37,69;-45,69" + ] + }, + { + "height": "11", + "type": "box", + "polygons": [ + "-8,-82;8,-82;8,-36;-8,-36", + "-8,-82;250,-82;250,-300;-8,-300" + ] + }, + { + "height": "17", + "type": "box", + "polygons": [ + "-300,-35;300,-35;300,-21;-300,-21" + ] + } + ] + }, + { + "printer_notes_regex": ".*PRINTER_MODEL_MINI.*", + "gantry_model_filename": "prusa3d_mini_gantry.stl", + "slices": [ + { + "height": "0", + "type": "convex", + "polygons": [ + "-5,-5;5,-5;5,5;-5,5", + "24,-3;35,-3;35,10;24,10", + "-5,4;5,4;5,18;-5,18" + ] + }, + { + "height": "3", + "type": "convex", + "polygons": [ + "-16,-44;37,-44;37,31;-16,31" + ] + }, + { + "height": "10", + "type": "convex", + "polygons": [ + "-10,-88;10,-88;10,-38;-10,-38", + "-17,-44;43,-44;43,33;-17,33" + ] + }, + { + "height": "22", + "type": "box", + "polygons": [ + "-200,-28;200,-28;200,-14;-200,-14" + ] + }, + { + "height": "100", + "type": "box", + "polygons": [ + "-200,-200;10,-200;10,10;-200,10" + ] + } + ] + }, + { + "printer_notes_regex": ".*PRINTER_MODEL_XL.*", + "gantry_model_filename": "prusa3d_xl_gantry.stl", + "slices": [ + { + "height": "0", + "type": "convex", + "polygons": [ + "-5,-5;5,-5;5,5;-5,5" + ] + }, + { + "height": "2", + "type": "convex", + "polygons": [ + "-10,-47;34,-47;34,16;-10,16", + "-34,13;32,13;32,67;-34,67" + ] + }, + { + "height": "23", + "type": "convex", + "polygons": [ + "-42,11;32,11;32,66;-42,66", + "-33,-37;43,-37;43,18;-33,18", + "-13,-68;47,-68;47,-30;-13,-30" + ] + }, + { + "height": "19", + "type": "box", + "polygons": [ + "-400,24;400,24;400,50;-400,50" + ] + }, + { + "height": "220", + "type": "box", + "polygons": [ + "-400,-400;400,-400;400,10;-400,10" + ] + }, + { + "height": "280", + "type": "box", + "polygons": [ + "-400,-400;400,-400;400,400;-400,400" + ] + } + ] + }, + { + "printer_notes_regex": ".*PRINTER_MODEL_COREONE.*", + "gantry_model_filename": "prusa3d_coreone_gantry.stl", + "slices": [ + { + "height": "0", + "type": "convex", + "polygons": [ + "-33,-37; 27,-37; 27,19; -33,19" + ] + }, + { + "height": "2", + "type": "convex", + "polygons": [ + "-40,-69; 27,-69; 27,20; -40,20" + ] + }, + { + "height": "23", + "type": "convex", + "polygons": [ + "-44,-52; 35,-52; 35,23; -44,23" + ] + }, + { + "height": "23", + "type": "convex", + "polygons": [ + "-37,-98; 26,-98; 26,-47; -37,-47" + ] + }, + { + "height": "33", + "type": "box", + "polygons": [ + "-300,-49; 300,-49; 300,-24; -300,-24" + ] + }, + { + "height": "120", + "type": "box", + "polygons": [ + "-300,-300; 300,-300; 300,10; -300,10" + ] + }, + { + "height": "170", + "type": "box", + "polygons": [ + "-300,-300; 300,-300; 300,300; -300,300" + ] + } + ] + } + ] +} diff --git a/resources/data/printer_gantries/prusa3d_coreone_gantry.stl b/resources/data/printer_gantries/prusa3d_coreone_gantry.stl new file mode 100644 index 0000000000..e8e0294078 Binary files /dev/null and b/resources/data/printer_gantries/prusa3d_coreone_gantry.stl differ diff --git a/resources/data/printer_gantries/prusa3d_mini_gantry.stl b/resources/data/printer_gantries/prusa3d_mini_gantry.stl new file mode 100644 index 0000000000..1bf9cf1baf Binary files /dev/null and b/resources/data/printer_gantries/prusa3d_mini_gantry.stl differ diff --git a/resources/data/printer_gantries/prusa3d_mk3s_gantry.stl b/resources/data/printer_gantries/prusa3d_mk3s_gantry.stl new file mode 100644 index 0000000000..17aa91057c Binary files /dev/null and b/resources/data/printer_gantries/prusa3d_mk3s_gantry.stl differ diff --git a/resources/data/printer_gantries/prusa3d_mk4_gantry.stl b/resources/data/printer_gantries/prusa3d_mk4_gantry.stl new file mode 100644 index 0000000000..48c8b98dda Binary files /dev/null and b/resources/data/printer_gantries/prusa3d_mk4_gantry.stl differ diff --git a/resources/data/printer_gantries/prusa3d_mk4s_gantry.stl b/resources/data/printer_gantries/prusa3d_mk4s_gantry.stl new file mode 100644 index 0000000000..a0932b43ed Binary files /dev/null and b/resources/data/printer_gantries/prusa3d_mk4s_gantry.stl differ diff --git a/resources/data/printer_gantries/prusa3d_xl_gantry.stl b/resources/data/printer_gantries/prusa3d_xl_gantry.stl new file mode 100644 index 0000000000..0fb888d4e5 Binary files /dev/null and b/resources/data/printer_gantries/prusa3d_xl_gantry.stl differ diff --git a/resources/localization/list.txt b/resources/localization/list.txt index 1e3f94b9f8..849aff0267 100644 --- a/resources/localization/list.txt +++ b/resources/localization/list.txt @@ -79,6 +79,7 @@ src/slic3r/GUI/GUI_Preview.cpp src/slic3r/GUI/HintNotification.cpp src/slic3r/GUI/ImGuiWrapper.cpp src/slic3r/GUI/Jobs/ArrangeJob2.cpp +src/slic3r/GUI/Jobs/SeqArrangeJob.cpp src/slic3r/GUI/Jobs/EmbossJob.cpp src/slic3r/GUI/Jobs/PlaterWorker.hpp src/slic3r/GUI/Jobs/RotoptimizeJob.hpp diff --git a/resources/shaders/110/tool_marker.fs b/resources/shaders/110/tool_marker.fs new file mode 100644 index 0000000000..74e5ee75cb --- /dev/null +++ b/resources/shaders/110/tool_marker.fs @@ -0,0 +1,18 @@ +#version 110 + +const vec2 ZERO = vec2(0.0, 0.0); + +uniform vec4 uniform_color; + +// x = diffuse, y = specular; +varying vec2 intensity; +varying vec2 clipping_planes_dots; + + +void main() +{ + if (any(lessThan(clipping_planes_dots, ZERO))) + discard; + + gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a); +} diff --git a/resources/shaders/110/tool_marker.vs b/resources/shaders/110/tool_marker.vs new file mode 100644 index 0000000000..46c7d4af82 --- /dev/null +++ b/resources/shaders/110/tool_marker.vs @@ -0,0 +1,58 @@ +#version 110 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SHININESS 5.0 + +#define INTENSITY_AMBIENT 0.3 + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 view_normal_matrix; +uniform mat4 volume_world_matrix; + +// Clipping planes used to clip the tool marker model. +uniform vec4 clipping_planes[2]; + +attribute vec3 v_position; +attribute vec3 v_normal; + +// x = diffuse, y = specular; +varying vec2 intensity; +varying vec2 clipping_planes_dots; + +void main() +{ + // First transform the normal into camera space and normalize the result. + vec3 eye_normal = normalize(view_normal_matrix * v_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec4 position = view_model_matrix * vec4(v_position, 1.0); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + // Point in homogenous coordinates. + vec4 world_pos = volume_world_matrix * vec4(v_position, 1.0); + // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. + clipping_planes_dots.x = dot(world_pos, clipping_planes[0]); + clipping_planes_dots.y = dot(world_pos, clipping_planes[1]); + + gl_Position = projection_matrix * position; +} diff --git a/resources/shaders/140/tool_marker.fs b/resources/shaders/140/tool_marker.fs new file mode 100644 index 0000000000..c3357ae35f --- /dev/null +++ b/resources/shaders/140/tool_marker.fs @@ -0,0 +1,19 @@ +#version 140 + +const vec2 ZERO = vec2(0.0, 0.0); + +uniform vec4 uniform_color; + +// x = diffuse, y = specular; +in vec2 intensity; +in vec2 clipping_planes_dots; + +out vec4 out_color; + +void main() +{ + if (any(lessThan(clipping_planes_dots, ZERO))) + discard; + + out_color = vec4(vec3(intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a); +} diff --git a/resources/shaders/140/tool_marker.vs b/resources/shaders/140/tool_marker.vs new file mode 100644 index 0000000000..ec6401e8d9 --- /dev/null +++ b/resources/shaders/140/tool_marker.vs @@ -0,0 +1,58 @@ +#version 140 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SHININESS 5.0 + +#define INTENSITY_AMBIENT 0.3 + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 view_normal_matrix; +uniform mat4 volume_world_matrix; + +// Clipping planes used to clip the tool marker model. +uniform vec4 clipping_planes[2]; + +in vec3 v_position; +in vec3 v_normal; + +// x = diffuse, y = specular; +out vec2 intensity; +out vec2 clipping_planes_dots; + +void main() +{ + // First transform the normal into camera space and normalize the result. + vec3 eye_normal = normalize(view_normal_matrix * v_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec4 position = view_model_matrix * vec4(v_position, 1.0); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + // Point in homogenous coordinates. + vec4 world_pos = volume_world_matrix * vec4(v_position, 1.0); + // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. + clipping_planes_dots.x = dot(world_pos, clipping_planes[0]); + clipping_planes_dots.y = dot(world_pos, clipping_planes[1]); + + gl_Position = projection_matrix * position; +} diff --git a/resources/shaders/ES/tool_marker.fs b/resources/shaders/ES/tool_marker.fs new file mode 100644 index 0000000000..f8db1c0996 --- /dev/null +++ b/resources/shaders/ES/tool_marker.fs @@ -0,0 +1,19 @@ +#version 100 + +precision highp float; + +const vec2 ZERO = vec2(0.0, 0.0); + +uniform vec4 uniform_color; + +// x = diffuse, y = specular; +varying vec2 intensity; +varying vec2 clipping_planes_dots; + +void main() +{ + if (any(lessThan(clipping_planes_dots, ZERO))) + discard; + + gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a); +} diff --git a/resources/shaders/ES/tool_marker.vs b/resources/shaders/ES/tool_marker.vs new file mode 100644 index 0000000000..333c9dad06 --- /dev/null +++ b/resources/shaders/ES/tool_marker.vs @@ -0,0 +1,58 @@ +#version 100 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SHININESS 5.0 + +#define INTENSITY_AMBIENT 0.3 + +uniform mat4 view_model_matrix; +uniform mat4 projection_matrix; +uniform mat3 view_normal_matrix; +uniform mat4 volume_world_matrix; + +// Clipping planes used to clip the tool marker model. +uniform vec4 clipping_planes[2]; + +attribute vec3 v_position; +attribute vec3 v_normal; + +// x = diffuse, y = specular; +varying vec2 intensity; +varying vec2 clipping_planes_dots; + +void main() +{ + // First transform the normal into camera space and normalize the result. + vec3 eye_normal = normalize(view_normal_matrix * v_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec4 position = view_model_matrix * vec4(v_position, 1.0); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + // Point in homogenous coordinates. + vec4 world_pos = volume_world_matrix * vec4(v_position, 1.0); + // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. + clipping_planes_dots.x = dot(world_pos, clipping_planes[0]); + clipping_planes_dots.y = dot(world_pos, clipping_planes[1]); + + gl_Position = projection_matrix * position; +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7eea9168a2..ff579e82e7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,6 +20,8 @@ endif () add_subdirectory(slic3r-arrange) add_subdirectory(slic3r-arrange-wrapper) +add_subdirectory(libseqarrange) + if (SLIC3R_GUI) add_subdirectory(libvgcode) @@ -136,39 +138,39 @@ if (NOT WIN32 AND NOT APPLE) set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer") endif () -target_link_libraries(PrusaSlicer libslic3r libcereal slic3r-arrange-wrapper stb_image) + +target_link_libraries(PrusaSlicer 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(PrusaSlicer "-liconv -framework IOKit" "-framework CoreFoundation" -lc++) + target_link_libraries(PrusaSlicer PRIVATE "-liconv -framework IOKit" "-framework CoreFoundation" -lc++) elseif (MSVC) # Manifest is provided through PrusaSlicer.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(PrusaSlicer ${CMAKE_DL_LIBS} -lstdc++ Threads::Threads) + target_link_libraries(PrusaSlicer PRIVATE ${CMAKE_DL_LIBS} -lstdc++ Threads::Threads) endif () # Add the Slic3r GUI library, libcurl, OpenGL and GLU libraries. if (SLIC3R_GUI) -# target_link_libraries(PrusaSlicer ws2_32 uxtheme setupapi libslic3r_gui ${wxWidgets_LIBRARIES}) -target_link_libraries(PrusaSlicer libslic3r_gui) + target_link_libraries(PrusaSlicer PRIVATE libslic3r_gui) if (MSVC) # Generate debug symbols even in release mode. target_link_options(PrusaSlicer PUBLIC "$<$:/DEBUG>") - target_link_libraries(PrusaSlicer user32.lib Setupapi.lib) + target_link_libraries(PrusaSlicer PRIVATE user32.lib Setupapi.lib) elseif (MINGW) - target_link_libraries(PrusaSlicer ws2_32 uxtheme setupapi) + target_link_libraries(PrusaSlicer PRIVATE ws2_32 uxtheme setupapi) elseif (APPLE) - target_link_libraries(PrusaSlicer "-framework OpenGL") + target_link_libraries(PrusaSlicer PRIVATE "-framework OpenGL") else () - target_link_libraries(PrusaSlicer -ldl) + target_link_libraries(PrusaSlicer PRIVATE -ldl) endif () if (WIN32) find_library(PSAPI_LIB NAMES Psapi) - target_link_libraries(PrusaSlicer ${PSAPI_LIB}) + target_link_libraries(PrusaSlicer PRIVATE ${PSAPI_LIB}) endif () endif () diff --git a/src/libseqarrange/CMakeLists.txt b/src/libseqarrange/CMakeLists.txt new file mode 100644 index 0000000000..f0d393e1c0 --- /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/prusaparts.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 0000000000..cfca3f6d28 --- /dev/null +++ b/src/libseqarrange/include/libseqarrange/seq_interface.hpp @@ -0,0 +1,216 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2024 + * Company: Prusa Research + * + * File: seq_interface.hpp + * + * Interface of the sequential printing SMT model for Prusa Slic3r + */ +/*================================================================*/ + +#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) {}}; + class InternalErrorException : public std::runtime_error { public: explicit InternalErrorException(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 0000000000..32a9b9be16 --- /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 0000000000..89165ca9f4 --- /dev/null +++ b/src/libseqarrange/src/seq_interface.cpp @@ -0,0 +1,1360 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2025 + * Company: Prusa Research + * + * File: seq_interface.cpp + * + * Interface of the sequential printing SMT model for Prusa Slic3r + */ +/*================================================================*/ + +#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_PRUSA_MINI, + SEQ_PRINTER_TYPE_PRUSA_MK3S, + SEQ_PRINTER_TYPE_PRUSA_MK4, + SEQ_PRINTER_TYPE_PRUSA_XL +}; + + +const int SEQ_PRUSA_MK3S_X_SIZE = 2500; +const int SEQ_PRUSA_MK3S_Y_SIZE = 2100; + +const coord_t SEQ_PRUSA_MK3S_NOZZLE_LEVEL = 0; +const coord_t SEQ_PRUSA_MK3S_EXTRUDER_LEVEL = 2000000; +const coord_t SEQ_PRUSA_MK3S_HOSE_LEVEL = 18000000; +const coord_t SEQ_PRUSA_MK3S_GANTRY_LEVEL = 26000000; + +const int SEQ_PRUSA_MK4_X_SIZE = 2500; +const int SEQ_PRUSA_MK4_Y_SIZE = 2100; + +const coord_t SEQ_PRUSA_MK4_NOZZLE_LEVEL = 0; +const coord_t SEQ_PRUSA_MK4_EXTRUDER_LEVEL = 2000000; +const coord_t SEQ_PRUSA_MK4_HOSE_LEVEL = 18000000; +const coord_t SEQ_PRUSA_MK4_GANTRY_LEVEL = 26000000; + +const int SEQ_PRUSA_XL_X_SIZE = 3600; +const int SEQ_PRUSA_XL_Y_SIZE = 3600; + +const coord_t SEQ_PRUSA_XL_NOZZLE_LEVEL = 0; +const coord_t SEQ_PRUSA_XL_EXTRUDER_LEVEL = 2000000; +const coord_t SEQ_PRUSA_XL_HOSE_LEVEL = 18000000; +const coord_t SEQ_PRUSA_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)); + } + 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(objects_to_print[conflict.value().first].id, objects_to_print[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(objects_to_print[conflict.value().first].id, objects_to_print[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_PRUSA_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_PRUSA_MK3S: + { + switch (height) + { + case SEQ_PRUSA_MK3S_NOZZLE_LEVEL: // nozzle + { + nozzle_polygon = decimated_polygon; + break; + } + case SEQ_PRUSA_MK3S_EXTRUDER_LEVEL: // extruder + { + extruder_polygon = decimated_polygon; + break; + } + case SEQ_PRUSA_MK3S_HOSE_LEVEL: // hose + { + hose_polygon = decimated_polygon; + break; + } + case SEQ_PRUSA_MK3S_GANTRY_LEVEL: // gantry + { + gantry_polygon = decimated_polygon; + break; + } + default: + { + throw std::runtime_error("UNSUPPORTED POLYGON HEIGHT"); + break; + } + } + break; + } + case SEQ_PRINTER_TYPE_PRUSA_MK4: + { + switch (height) + { + case SEQ_PRUSA_MK4_NOZZLE_LEVEL: // nozzle + { + nozzle_polygon = decimated_polygon; + break; + } + case SEQ_PRUSA_MK4_EXTRUDER_LEVEL: // extruder + { + extruder_polygon = decimated_polygon; + break; + } + case SEQ_PRUSA_MK4_HOSE_LEVEL: // hose + { + hose_polygon = decimated_polygon; + break; + } + case SEQ_PRUSA_MK4_GANTRY_LEVEL: // gantry + { + gantry_polygon = decimated_polygon; + break; + } + default: + { + throw std::runtime_error("UNSUPPORTED POLYGON HEIGHT"); + break; + } + } + break; + } + case SEQ_PRINTER_TYPE_PRUSA_XL: + { + switch (height) + { + case SEQ_PRUSA_XL_NOZZLE_LEVEL: // nozzle + { + nozzle_polygon = decimated_polygon; + break; + } + case SEQ_PRUSA_XL_EXTRUDER_LEVEL: // extruder + { + extruder_polygon = decimated_polygon; + break; + } + case SEQ_PRUSA_XL_HOSE_LEVEL: // hose (no hose in XL) + { + hose_polygon = decimated_polygon; + break; + } + case SEQ_PRUSA_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_PRUSA_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_PRUSA_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_PRUSA_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_PRUSA_MK3S; + + switch (printer_type) + { + case SEQ_PRINTER_TYPE_PRUSA_MK3S: + { + convex_unreachable_zones = SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_MK3S; + box_unreachable_zones = SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_MK3S; + break; + } + case SEQ_PRINTER_TYPE_PRUSA_MK4: + { + convex_unreachable_zones = SEQ_UNREACHABLE_POLYGON_CONVEX_LEVELS_MK4; + box_unreachable_zones = SEQ_UNREACHABLE_POLYGON_BOX_LEVELS_MK4; + break; + } + case SEQ_PRINTER_TYPE_PRUSA_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 (unsgined 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 0000000000..aa3a846f06 --- /dev/null +++ b/src/libseqarrange/src/seq_preprocess.cpp @@ -0,0 +1,1232 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2025 + * Company: Prusa Research + * + * File: seq_preprocess.hpp + * + * Object preprocessing for the sequential printing SMT model. + */ +/*================================================================*/ + +#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 InternalErrorException("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.x_plate_bounding_box_size * scale_factor); + printf("Y: %d\n", solver_configuration.y_plate_bounding_box_size * 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 0000000000..6cd68641bd --- /dev/null +++ b/src/libseqarrange/src/seq_preprocess.hpp @@ -0,0 +1,234 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2025 + * Company: Prusa Research + * + * File: seq_preprocess.hpp + * + * Object preprocessing for the sequential printing SMT model. + */ +/*================================================================*/ + +#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 0000000000..7a104378b6 --- /dev/null +++ b/src/libseqarrange/src/seq_sequential.cpp @@ -0,0 +1,11663 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2025 + * Company: Prusa Research + * + * File: seq_sequential.cpp + * + * SMT models for sequential printing. + */ +/*================================================================*/ + +#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); + + 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]]); + } + } + 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]]); + } + } + 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]); + } + /* 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]]); + } + } + 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]]); + } + } + } + } + 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]); + } + /* 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]]); + } + } + } + } + + #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 %d,%d\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; + + z3::expr_vector bounding_box_assumptions(Context); + + 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; + + 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; + + z3::expr_vector bounding_box_assumptions(Context); + 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()); + } + 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("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()); + } + 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 0000000000..dbb15c3398 --- /dev/null +++ b/src/libseqarrange/src/seq_sequential.hpp @@ -0,0 +1,1688 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2025 + * Company: Prusa Research + * + * File: seq_sequential.hpp + * + * SMT models for sequential printing. + */ +/*================================================================*/ + +#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 0000000000..dd46cf40eb --- /dev/null +++ b/src/libseqarrange/src/seq_utilities.cpp @@ -0,0 +1,246 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2025 + * Company: Prusa Research + * + * File: seq_utilities.cpp + * + * Various utilities for sequential print. + */ +/*================================================================*/ + +#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 0000000000..d2264cee0d --- /dev/null +++ b/src/libseqarrange/src/seq_utilities.hpp @@ -0,0 +1,52 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2025 + * Company: Prusa Research + * + * File: seq_utilities.hpp + * + * Various utilities for sequential print. + */ +/*================================================================*/ + +#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 0000000000..a2330ebd6c --- /dev/null +++ b/src/libseqarrange/src/sequential_decimator.cpp @@ -0,0 +1,427 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2025 + * Company: Prusa Research + * + * File: sequential_decimator.cpp + * + * Polygon decimator utility (especially for extruder models). + */ +/*================================================================*/ + + +#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_PRUSA_MK3S_X_SIZE = 2500; +const int SEQ_PRUSA_MK3S_Y_SIZE = 2100; + + +/*----------------------------------------------------------------*/ + + +void print_IntroductoryMessage(void) +{ + printf("----------------------------------------------------------------\n"); + printf("Polygon decimation utility\n"); + printf("(C) 2024 Prusa Research \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_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_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 0000000000..7c4d9f5067 --- /dev/null +++ b/src/libseqarrange/src/sequential_decimator.hpp @@ -0,0 +1,73 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2025 + * Company: Prusa Research + * + * File: sequential_decimator.hpp + * + * Polygon decimator utility (especially for extruder models). + */ +/*================================================================*/ + +#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/prusaparts.cpp b/src/libseqarrange/test/prusaparts.cpp new file mode 100644 index 0000000000..72d5c7d9bc --- /dev/null +++ b/src/libseqarrange/test/prusaparts.cpp @@ -0,0 +1,5981 @@ +#include "prusaparts.hpp" + +const TestData PRUSA_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 PRUSA_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 PRUSA_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/prusaparts.hpp b/src/libseqarrange/test/prusaparts.hpp new file mode 100644 index 0000000000..e4fa33cf49 --- /dev/null +++ b/src/libseqarrange/test/prusaparts.hpp @@ -0,0 +1,14 @@ +#ifndef PRUSAPARTS_H +#define PRUSAPARTS_H + +#include +#include "libslic3r/ExPolygon.hpp" + +using TestData = std::vector; +using TestDataEx = std::vector; + +extern const TestData PRUSA_PART_POLYGONS; +extern const TestData PRUSA_STEGOSAUR_POLYGONS; +extern const TestDataEx PRUSA_PART_POLYGONS_EX; + +#endif // PRUSAPARTS_H diff --git a/src/libseqarrange/test/seq_test_interface.cpp b/src/libseqarrange/test/seq_test_interface.cpp new file mode 100644 index 0000000000..fa729c42f5 --- /dev/null +++ b/src/libseqarrange/test/seq_test_interface.cpp @@ -0,0 +1,931 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2024 + * Company: Prusa Research + * + * File: seq_test_interface.cpp + * + * Tests of the sequential printing interface for Prusa Slic3r + */ +/*================================================================*/ + +#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 int SEQ_PRUSA_MK3S_X_SIZE = 2500; +const int SEQ_PRUSA_MK3S_Y_SIZE = 2100; + + +/*----------------------------------------------------------------*/ + +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]") +{ + clock_t start, finish; + + printf("Testing interface 1 ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + solver_configuration.decimation_precision = SEQ_DECIMATION_PRECISION_HIGH; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_MK3S_Y_SIZE}); + + + printf("Loading objects ...\n"); + std::vector objects_to_print = load_exported_data_from_text(arrange_data_export_text); + REQUIRE(objects_to_print.size() > 0); + printf("Loading objects ... finished\n"); + + std::vector scheduled_plates; + printf("Scheduling objects for sequential print ...\n"); + + int result = schedule_ObjectsForSequentialPrint(solver_configuration, + objects_to_print, + scheduled_plates); + + REQUIRE(result == 0); + if (result == 0) + { + printf("Object scheduling for sequential print SUCCESSFUL !\n"); + + printf("Number of plates: %ld\n", scheduled_plates.size()); + REQUIRE(scheduled_plates.size() > 0); + + for (unsigned int plate = 0; plate < scheduled_plates.size(); ++plate) + { + printf(" Number of objects on plate: %ld\n", scheduled_plates[plate].scheduled_objects.size()); + REQUIRE(scheduled_plates[plate].scheduled_objects.size() > 0); + + for (const auto& scheduled_object: scheduled_plates[plate].scheduled_objects) + { + cout << " ID: " << scheduled_object.id << " X: " << scheduled_object.x << " Y: " << scheduled_object.y << endl; + REQUIRE(scheduled_object.x >= 0); + REQUIRE(scheduled_object.x <= solver_configuration.x_plate_bounding_box_size * SEQ_SLICER_SCALE_FACTOR); + REQUIRE(scheduled_object.y >= 0); + REQUIRE(scheduled_object.y <= solver_configuration.y_plate_bounding_box_size * SEQ_SLICER_SCALE_FACTOR); + } + } + } + else + { + printf("Something went WRONG during sequential scheduling (code: %d)\n", result); + } + + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing interface 1 ... finished\n"); +} + + +TEST_CASE("Interface test 2", "[Sequential Arrangement Interface]") +{ + clock_t start, finish; + + printf("Testing interface 2 ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + solver_configuration.decimation_precision = SEQ_DECIMATION_PRECISION_HIGH; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_MK3S_Y_SIZE}); + + printf("Loading objects ...\n"); + std::vector objects_to_print = load_exported_data_from_text(arrange_data_export_text); + + std::vector > convex_unreachable_zones; + std::vector > box_unreachable_zones; + + printf("Preparing extruder unreachable zones ...\n"); + setup_ExtruderUnreachableZones(solver_configuration, convex_unreachable_zones, box_unreachable_zones); + + std::vector scheduled_plates; + printf("Scheduling objects for sequential print ...\n"); + + int result = schedule_ObjectsForSequentialPrint(solver_configuration, + objects_to_print, + convex_unreachable_zones, + box_unreachable_zones, + scheduled_plates); + + REQUIRE(result == 0); + if (result == 0) + { + printf("Object scheduling for sequential print SUCCESSFUL !\n"); + + printf("Number of plates: %ld\n", scheduled_plates.size()); + REQUIRE(scheduled_plates.size() > 0); + + for (unsigned int plate = 0; plate < scheduled_plates.size(); ++plate) + { + printf(" Number of objects on plate: %ld\n", scheduled_plates[plate].scheduled_objects.size()); + REQUIRE(scheduled_plates[plate].scheduled_objects.size() > 0); + + for (const auto& scheduled_object: scheduled_plates[plate].scheduled_objects) + { + cout << " ID: " << scheduled_object.id << " X: " << scheduled_object.x << " Y: " << scheduled_object.y << endl; + REQUIRE(scheduled_object.x >= 0); + REQUIRE(scheduled_object.x <= solver_configuration.x_plate_bounding_box_size * SEQ_SLICER_SCALE_FACTOR); + REQUIRE(scheduled_object.y >= 0); + REQUIRE(scheduled_object.y <= solver_configuration.y_plate_bounding_box_size * SEQ_SLICER_SCALE_FACTOR); + } + } + } + else + { + printf("Something went WRONG during sequential scheduling (code: %d)\n", result); + } + + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing interface 2 ... finished\n"); +} + + +TEST_CASE("Interface test 3", "[Sequential Arrangement Interface]") +{ + clock_t start, finish; + + printf("Testing interface 3 ...\n"); + + start = clock(); + + PrinterGeometry printer_geometry; + int result = load_printer_geometry_from_text(printer_geometry_mk4_text, printer_geometry); + REQUIRE(result == 0); + + if (result != 0) + { + printf("Printer geometry load error.\n"); + return; + } + + REQUIRE(printer_geometry.plate.points.size() == 4); + + for (const auto& convex_height: printer_geometry.convex_heights) + { + cout << "convex_height:" << convex_height << endl; + } + + for (const auto& box_height: printer_geometry.box_heights) + { + cout << "box_height:" << box_height << endl; + } + printf("extruder slices:\n"); + REQUIRE(printer_geometry.extruder_slices.size() > 0); + + 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; + } + } + } + + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing interface 3 ... finished\n"); +} + + +TEST_CASE("Interface test 4", "[Sequential Arrangement Interface]") +{ + clock_t start, finish; + + printf("Testing interface 4 ...\n"); + + start = clock(); + + 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_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_MK3S_Y_SIZE}); + + printf("Loading objects ...\n"); + std::vector objects_to_print = load_exported_data_from_text(arrange_data_export_text); + printf("Loading objects ... finished\n"); + + PrinterGeometry printer_geometry; + + printf("Loading printer geometry ...\n"); + int result = load_printer_geometry_from_text(printer_geometry_mk4_compatibility_text, printer_geometry); + + REQUIRE(result == 0); + if (result != 0) + { + printf("Cannot load printer geometry (code: %d).\n", result); + return; + } + solver_configuration.setup(printer_geometry); + printf("Loading printer geometry ... finished\n"); + + std::vector scheduled_plates; + printf("Scheduling objects for sequential print ...\n"); + + scheduled_plates = schedule_ObjectsForSequentialPrint(solver_configuration, + printer_geometry, + objects_to_print); + + printf("Object scheduling for sequential print SUCCESSFUL !\n"); + + printf("Number of plates: %ld\n", scheduled_plates.size()); + REQUIRE(scheduled_plates.size() > 0); + + for (unsigned int plate = 0; plate < scheduled_plates.size(); ++plate) + { + printf(" Number of objects on plate: %ld\n", scheduled_plates[plate].scheduled_objects.size()); + REQUIRE(scheduled_plates[plate].scheduled_objects.size() > 0); + + for (const auto& scheduled_object: scheduled_plates[plate].scheduled_objects) + { + cout << " ID: " << scheduled_object.id << " X: " << scheduled_object.x << " Y: " << scheduled_object.y << endl; + + 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()); + } + } + + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing interface 4 ... finished\n"); +} + + +TEST_CASE("Interface test 5", "[Sequential Arrangement Interface]") +{ + clock_t start, finish; + + printf("Testing interface 5 ...\n"); + + start = clock(); + + 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_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_MK3S_Y_SIZE}); + + printf("Loading objects ...\n"); + std::vector objects_to_print = load_exported_data_from_text(arrange_data_export_text); + printf("Loading objects ... finished\n"); + + PrinterGeometry printer_geometry; + + printf("Loading printer geometry ...\n"); + int result = load_printer_geometry_from_text(printer_geometry_mk4_compatibility_text, printer_geometry); + + REQUIRE(result == 0); + if (result != 0) + { + printf("Cannot load printer geometry (code: %d).\n", result); + return; + } + solver_configuration.setup(printer_geometry); + printf("Loading printer geometry ... finished\n"); + + std::vector scheduled_plates; + printf("Scheduling objects for sequential print ...\n"); + + scheduled_plates = schedule_ObjectsForSequentialPrint(solver_configuration, + printer_geometry, + objects_to_print, + [](int progress) { printf("Progress: %d\n", progress); + REQUIRE(progress >= 0); + REQUIRE(progress <= 100); }); + + printf("Object scheduling for sequential print SUCCESSFUL !\n"); + + printf("Number of plates: %ld\n", scheduled_plates.size()); + REQUIRE(scheduled_plates.size() > 0); + + for (unsigned int plate = 0; plate < scheduled_plates.size(); ++plate) + { + printf(" Number of objects on plate: %ld\n", scheduled_plates[plate].scheduled_objects.size()); + REQUIRE(scheduled_plates[plate].scheduled_objects.size() > 0); + + for (const auto& scheduled_object: scheduled_plates[plate].scheduled_objects) + { + cout << " ID: " << scheduled_object.id << " X: " << scheduled_object.x << " Y: " << scheduled_object.y << endl; + + 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()); + } + } + + finish = clock(); + printf("Solving time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + + start = clock(); + + printf("Checking sequential printability ...\n"); + + bool printable = check_ScheduledObjectsForSequentialPrintability(solver_configuration, + printer_geometry, + objects_to_print, + scheduled_plates); + printf(" Scheduled/arranged objects are sequentially printable: %s\n", (printable ? "YES" : "NO")); + REQUIRE(printable); + + printf("Checking sequential printability ... finished\n"); + + finish = clock(); + printf("Checking time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + + printf("Testing interface 5 ... finished\n"); +} + + +TEST_CASE("Interface test 6", "[Sequential Arrangement Interface]") +{ + clock_t start, finish; + + printf("Testing interface 6 ...\n"); + + start = clock(); + + 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_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_MK3S_Y_SIZE}); + + printf("Loading objects ...\n"); + std::vector objects_to_print = load_exported_data_from_text(arrange_data_export_text); + REQUIRE(objects_to_print.size() > 0); + printf("Loading objects ... finished\n"); + + for (auto& object_to_print: objects_to_print) + { + object_to_print.glued_to_next = true; + } + + PrinterGeometry printer_geometry; + + printf("Loading printer geometry ...\n"); + int result = load_printer_geometry_from_text(printer_geometry_mk4_compatibility_text, printer_geometry); + REQUIRE(result == 0); + if (result != 0) + { + printf("Cannot load printer geometry (code: %d).\n", result); + return; + } + solver_configuration.setup(printer_geometry); + printf("Loading printer geometry ... finished\n"); + + std::vector scheduled_plates; + printf("Scheduling objects for sequential print ...\n"); + + scheduled_plates = schedule_ObjectsForSequentialPrint(solver_configuration, + printer_geometry, + objects_to_print, + [](int progress) { printf("Progress: %d\n", progress); + REQUIRE(progress >= 0); + REQUIRE(progress <= 100); }); + + printf("Object scheduling for sequential print SUCCESSFUL !\n"); + + printf("Number of plates: %ld\n", scheduled_plates.size()); + REQUIRE(scheduled_plates.size() > 0); + + for (unsigned int plate = 0; plate < scheduled_plates.size(); ++plate) + { + printf(" Number of objects on plate: %ld\n", scheduled_plates[plate].scheduled_objects.size()); + REQUIRE(scheduled_plates[plate].scheduled_objects.size() > 0); + + for (const auto& scheduled_object: scheduled_plates[plate].scheduled_objects) + { + cout << " ID: " << scheduled_object.id << " X: " << scheduled_object.x << " Y: " << scheduled_object.y << endl; + + 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()); + } + } + + finish = clock(); + printf("Solving time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + + start = clock(); + + printf("Checking sequential printability ...\n"); + + bool printable = check_ScheduledObjectsForSequentialPrintability(solver_configuration, + printer_geometry, + objects_to_print, + scheduled_plates); + + printf(" Scheduled/arranged objects are sequentially printable: %s\n", (printable ? "YES" : "NO")); + REQUIRE(printable); + + printf("Checking sequential printability ... finished\n"); + + finish = clock(); + printf("Checking time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + + printf("Testing interface 6 ... finished\n"); +} + + +/*----------------------------------------------------------------*/ + + diff --git a/src/libseqarrange/test/seq_test_interface.hpp b/src/libseqarrange/test/seq_test_interface.hpp new file mode 100644 index 0000000000..5292a70f2a --- /dev/null +++ b/src/libseqarrange/test/seq_test_interface.hpp @@ -0,0 +1,18 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2024 + * Company: Prusa Research + * + * File: seq_test_interface.hpp + * + * Tests of the sequential printing interface for Prusa Slic3r + */ +/*================================================================*/ + +#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 0000000000..22a2616104 --- /dev/null +++ b/src/libseqarrange/test/seq_test_polygon.cpp @@ -0,0 +1,2942 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2024 + * Company: Prusa Research + * + * File: seq_test_polygon.cpp + * + * Basic polygon tests. + */ +/*================================================================*/ + +#include +#include +#include + +#include +#include +#include + +#include +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Geometry/ConvexHull.hpp" +#include "libslic3r/SVG.hpp" + +#include + +#include "prusaparts.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_PRUSA_MK3S_X_SIZE = 2500; +const int SEQ_PRUSA_MK3S_Y_SIZE = 2100; + + +/*----------------------------------------------------------------*/ + +TEST_CASE("Polygon test 1", "[Polygon]") +{ + printf("Testing polygon 1 ...\n"); + + Polygon polygon_1 = {{-1000000, -1000000}, {1000000, -1000000}, {1000000, 1000000}, {-1000000, 1000000} }; + + for (unsigned int i = 0; i < polygon_1.size(); ++i) + { + Point point = polygon_1[i]; + printf("%d,%d\n", point.x(), point.y()); + } + REQUIRE(polygon_1.size() > 0); + + printf("Testing polygon 1 ... finished\n"); +} + + +TEST_CASE("Polygon test 2", "[Polygon]") +{ + printf("Testing polygon 2 ...\n"); + + for (unsigned int k = 0; k < PRUSA_PART_POLYGONS.size(); ++k) + { + printf("k = %d\n", k); + + const Polygon &polygon_1 = PRUSA_PART_POLYGONS[k]; + Polygon hull_1 = convex_hull(polygon_1); + + 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()); + } + + 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(); + printf("v: %d,%d\n", v.x(), v.y()); + cout << v << endl; + + Point u = v.normalized(); + printf("u: %d,%d\n", u.x(), u.y()); + cout << u << endl; + + printf("Ortho:\n"); + Point n(v.y(), -v.x()); + cout << n << endl; + + coord_t d = n.x() * point_1.x() + n.y() * point_1.y(); + printf("%d\n", d); + cout << d << endl; + + auto is_inside=[&](const Point &p) + { + coord_t d1 = n.x() * p.x() + n.y() * p.y() - d; + printf("d1: %d\n", d1); + + if (d1 >= 0) + { + return true; + } + else + { + return false; + } + }; + + bool ins1 = is_inside(point_1); + printf("%s\n", ins1 ? "yes" : "no"); + REQUIRE(ins1); + + bool ins2 = is_inside(point_2); + printf("%s\n", ins2 ? "yes" : "no"); + REQUIRE(ins2); + + bool ins3 = is_inside(point_1 + point_2); + printf("%s\n", ins3 ? "yes" : "no"); + + bool ins4 = is_inside(point_1 - point_2); + printf("%s\n", ins4 ? "yes" : "no"); + } + } + + printf("Testing polygon 2 ... finished\n"); +} + + +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]") +{ + clock_t start, finish; + + printf("Testing polygon 3 ...\n"); + + start = clock(); + + 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) + { + printf("i:%d\n", i); + string name = "x_pos-" + to_string(i); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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; + printf(" SATISFIABLE\n"); + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + return; + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + 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()); + + #ifdef DEBUG + { + 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; + } + } + } + #endif + } + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing polygon 3 ... finished\n"); +} + + +TEST_CASE("Polygon test 4", "[Polygon]") +{ + clock_t start, finish; + + printf("Testing polygon 4 ...\n"); + + start = clock(); + + 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) + { + printf("i:%d\n", i); + string name = "x_pos-" + to_string(i); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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]); + + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + + bool sat = false; + + switch (z_solver.check()) + { + case z3::sat: + { + sat = true; + printf(" SATISFIABLE\n"); + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + return; + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + 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); + printf("Testing polygon 4 ... finished\n"); +} + + +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]") +{ + clock_t start, finish; + + printf("Testing polygon 5 ...\n"); + + start = clock(); + + 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) + { + printf("i:%d\n", i); + string name = "x_pos-" + to_string(i); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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; + printf(" SATISFIABLE\n"); + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + return; + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + z3::model z_model(z_solver.get_model()); + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + 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()); + + #ifdef DEBUG + { + 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; + } + } + } + #endif + } + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing polygon 5 ... finished\n"); +} + +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]") +{ + clock_t start, finish; + + printf("Testing polygon 6 ...\n"); + + start = clock(); + + 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) + { + printf("i:%d\n", i); + string name = "x_pos-" + to_string(i); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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; + printf(" SATISFIABLE\n"); + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + return; + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + 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"; + + 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); + + #ifdef DEBUG + { + 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; + } + } + } + #endif + } + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing polygon 6 ... finished\n"); +} + + +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]") +{ + clock_t start, finish; + + printf("Testing polygon 7 ...\n"); + + start = clock(); + + 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) + { + printf("i:%d\n", i); + string name = "x_pos-" + to_string(i); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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; + printf(" SATISFIABLE\n"); + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + return; + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + 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; + + 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); + + 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; + } + + #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 + + } + + printf("Positions: %.3f, %.3f, %.3f, %.3f\n", poly_1_pos_x, poly_1_pos_y, poly_2_pos_x, poly_2_pos_y); + + #ifdef DEBUG + { + for (int i = 0; i < 2; ++i) + { + double value = X_positions[i].as_double(); + printf("Orig X: %.3f\n", value); + + value = Y_positi ons[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(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing polygon 7 ... finished\n"); +} + + +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]") +{ + clock_t start, finish; + + printf("Testing polygon 8 ...\n"); + + start = clock(); + + 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) + { + printf("i:%d\n", i); + string name = "x_pos-" + to_string(i); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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: + { + printf(" SATISFIABLE\n"); + last_solvable_decision_box_size = decision_box_size; + sat = true; + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + sat = false; + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + 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); + + 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 + { + 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 + + } + finish = clock(); + + REQUIRE(last_solvable_decision_box_size > 0); + + 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); + + #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(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing polygon 8 ... finished\n"); +} + + +TEST_CASE("Polygon test 9", "[Polygon]") +{ + clock_t start, finish; + + printf("Testing polygon 9 ...\n"); + + start = clock(); + + 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) + { + printf("i:%d\n", i); + string name = "x_pos-" + to_string(i); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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: + { + printf(" SATISFIABLE\n"); + last_solvable_bounding_box_size = bounding_box_size; + sat = true; + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + sat = false; + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + 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); + + 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 + { + 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 + } + finish = clock(); + + REQUIRE(last_solvable_bounding_box_size > 0); + 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); + + #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(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing polygon 9 ... finished\n"); +} + + +Polygon polygon_4 = {{20, 0}, {40, 0}, {60, 30}, {30, 50}, {0, 30}}; + +TEST_CASE("Polygon test 10", "[Polygon]") +{ + clock_t start, finish; + + printf("Testing polygon 10 ...\n"); + + start = clock(); + + 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) + { + printf("i:%d\n", i); + string name = "x_pos-" + to_string(i); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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: + { + printf(" SATISFIABLE\n"); + last_solvable_bounding_box_size = bounding_box_size; + sat = true; + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + sat = false; + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + 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); + + 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 + { + 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 + + } + finish = clock(); + + REQUIRE(last_solvable_bounding_box_size > 0); + + 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); + + #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(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing polygon 10 ... finished\n"); +} + + +TEST_CASE("Polygon test 11", "[Polygon]") +{ + clock_t start, finish; + + printf("Testing polygon 11 ...\n"); + + start = clock(); + + 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) + { + printf("i:%d\n", i); + string name = "x_pos-" + to_string(i); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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) + { + printf("BB: %d\n", bounding_box_size); + 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: + { + printf(" SATISFIABLE\n"); + sat = true; + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + sat = false; + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + 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); + + 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; + } + } + + 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); + + 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: + { + printf(" sat\n"); + refined_sat = true; + break; + } + case z3::unsat: + { + printf(" unsat\n"); + refined_sat = false; + break; + } + case z3::unknown: + { + printf(" unknown\n"); + 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; + } + } + 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); + } + else + { + break; + } + } + else + { + last_solvable_bounding_box_size = bounding_box_size; + break; + } + } + } + else + { + break; + } + + #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 + + } + finish = clock(); + + REQUIRE(last_solvable_bounding_box_size > 0); + + 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); + + #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(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing polygon 11 ... finished\n"); +} + + +TEST_CASE("Polygon test 12", "[Polygon]") +{ + clock_t start, finish; + + printf("Testing polygon 12 ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_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); + + finish = clock(); + REQUIRE(optimized); + + if (optimized) + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < polygons.size(); ++i) + { + printf(" %.3f, %.3f\n", X_values[i], Y_values[i]); + } + + 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 + { + printf("Polygon optimization FAILED.\n"); + } + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing polygon 12 ... finished\n"); +} + + +TEST_CASE("Polygon test 13", "[Polygon]") +{ + clock_t start, finish; + + printf("Testing polygon 13 ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_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); + + finish = clock(); + REQUIRE(optimized); + + if (optimized) + { + printf("Polygon positions:\n"); + for (unsigned int i = 0; i < polygons.size(); ++i) + { + printf(" %.3f, %.3f\n", X_values[i], Y_values[i]); + } + + 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 + { + printf("Polygon optimization FAILED.\n"); + } + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing polygon 13 ... finished\n"); +} + + +TEST_CASE("Polygon test 14", "[Polygon]") +{ + clock_t start, finish; + + printf("Testing polygon 14 ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_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]]; + } + + printf("Optimized 1: %d\n", 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()); + + 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); + printf("Optimized 2: %d\n", optimized); + + decided.push_back(4); + decided.push_back(5); + decided.push_back(6); + decided.push_back(7); + + finish = clock(); + + if (optimized) + { + 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()); + } + + 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 + { + printf("Polygon optimization FAILED.\n"); + } + + REQUIRE(optimized); + } + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing polygon 14 ... finished\n"); +} + + +TEST_CASE("Polygon test 15", "[Polygon]") +{ + clock_t start, finish; + + printf("Testing polygon 15 ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_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) + { + 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]); + } + + 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 + { + printf("Polygon optimization FAILED.\n"); + } + 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()); + + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing polygon 15 ... finished\n"); +} + + +TEST_CASE("Polygon test 16", "[Polygon]") +{ + clock_t start, finish; + + printf("Testing polygon 16 ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_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); + printf("Polygons area: %.3f\n", area); + + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing polygon 16 ... finished\n"); +} + + + +/*----------------------------------------------------------------*/ diff --git a/src/libseqarrange/test/seq_test_polygon.hpp b/src/libseqarrange/test/seq_test_polygon.hpp new file mode 100644 index 0000000000..a4badc72da --- /dev/null +++ b/src/libseqarrange/test/seq_test_polygon.hpp @@ -0,0 +1,18 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2024 + * Company: Prusa Research + * + * File: seq_test_polygon.hpp + * + * Basic polygon tests. + */ +/*================================================================*/ + +#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 0000000000..ba3ba902c1 --- /dev/null +++ b/src/libseqarrange/test/seq_test_preprocess.cpp @@ -0,0 +1,1129 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2024 + * Company: Prusa Research + * + * File: seq_test_preprocess.cpp + * + * Object preprocessing preprocess priting via SMT. + */ +/*================================================================*/ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Geometry/ConvexHull.hpp" +#include "libslic3r/SVG.hpp" + +#include + +#include "prusaparts.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 int SEQ_PRUSA_MK3S_X_SIZE = 2500; +const int SEQ_PRUSA_MK3S_Y_SIZE = 2100; + + +/*----------------------------------------------------------------*/ + + +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]") +{ + clock_t start, finish; + + printf("Testing preprocessing 1 ...\n"); + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_MK3S_Y_SIZE}); + + start = clock(); + for (unsigned int i = 0; i < PRUSA_PART_POLYGONS.size(); ++i) + { + Polygon scale_down_polygon; + scaleDown_PolygonForSequentialSolver(PRUSA_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(); + } + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing preprocessing 1 ... finished\n"); +} + + +TEST_CASE("Preprocessing test 2", "[Sequential Arrangement Preprocessing]") +{ + clock_t start, finish; + + printf("Testing preprocess 2 ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_MK3S_Y_SIZE}); + + vector polygons; + vector unreachable_polygons; + + for (unsigned int i = 0; i < PRUSA_PART_POLYGONS.size(); ++i) + { + Polygon scale_down_polygon; + scaleDown_PolygonForSequentialSolver(PRUSA_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); + + printf("----> Optimization finished <----\n"); + REQUIRE(optimized); + + if (optimized) + { + 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]); + } + + 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 (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 (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]], + 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 + { + printf("Polygon optimization FAILED.\n"); + } + finish = clock(); + + printf("Intermediate time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + + vector next_polygons; + vector next_unreachable_polygons; + + for (unsigned int i = 0; i < polygon_index_map.size(); ++i) + { + printf(" %d\n", polygon_index_map[i]); + } + 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()); + + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing preprocess 2 ... finished\n"); +} + + +TEST_CASE("Preprocessing test 3", "[Sequential Arrangement Preprocessing]") +{ + clock_t start, finish; + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_MK3S_Y_SIZE}); + + printf("Testing preprocessing 3 ...\n"); + + start = clock(); + + 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 < PRUSA_PART_POLYGONS.size(); ++p) + { + { + nozzle_unreachable_polygons.clear(); + + extend_PolygonConvexUnreachableZone(solver_configuration, + PRUSA_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(PRUSA_PART_POLYGONS[p], "blue"); + + preview_svg.Close(); + } + + { + nozzle_unreachable_polygons.clear(); + + extend_PolygonBoxUnreachableZone(solver_configuration, + PRUSA_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(PRUSA_PART_POLYGONS[p], "red"); + + preview_svg.Close(); + } + + { + extruder_unreachable_polygons.clear(); + + extend_PolygonConvexUnreachableZone(solver_configuration, + PRUSA_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(PRUSA_PART_POLYGONS[p], "green"); + + preview_svg.Close(); + } + + { + extruder_unreachable_polygons.clear(); + + extend_PolygonBoxUnreachableZone(solver_configuration, + PRUSA_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(PRUSA_PART_POLYGONS[p], "magenta"); + + preview_svg.Close(); + } + + { + hose_unreachable_polygons.clear(); + + extend_PolygonConvexUnreachableZone(solver_configuration, + PRUSA_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(PRUSA_PART_POLYGONS[p], "yellow"); + + preview_svg.Close(); + } + + { + hose_unreachable_polygons.clear(); + + extend_PolygonBoxUnreachableZone(solver_configuration, + PRUSA_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(PRUSA_PART_POLYGONS[p], "orange"); + + preview_svg.Close(); + } + + { + gantry_unreachable_polygons.clear(); + + extend_PolygonConvexUnreachableZone(solver_configuration, + PRUSA_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(PRUSA_PART_POLYGONS[p], "grey"); + + preview_svg.Close(); + } + + { + gantry_unreachable_polygons.clear(); + + extend_PolygonBoxUnreachableZone(solver_configuration, + PRUSA_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(PRUSA_PART_POLYGONS[p], "black"); + + preview_svg.Close(); + } + } + + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing preprocess 3 ... finished\n"); + +} + + +TEST_CASE("Preprocessing test 4", "[Sequential Arrangement Preprocessing]") +{ + clock_t start, finish; + + printf("Testing preprocess 4 ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_MK3S_Y_SIZE}); + + std::vector polygons; + std::vector > unreachable_polygons; + for (int i = 0; i < 12; ++i) + { + Polygon scale_down_polygon; + scaleDown_PolygonForSequentialSolver(PRUSA_PART_POLYGONS[i], scale_down_polygon); + polygons.push_back(scale_down_polygon); + + std::vector convex_level_polygons; + convex_level_polygons.push_back(PRUSA_PART_POLYGONS[i]); + convex_level_polygons.push_back(PRUSA_PART_POLYGONS[i]); + std::vector box_level_polygons; + box_level_polygons.push_back(PRUSA_PART_POLYGONS[i]); + box_level_polygons.push_back(PRUSA_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); + + printf("----> Optimization finished <----\n"); + REQUIRE(optimized); + + if (optimized) + { + 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]); + } + + 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 (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 (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 + { + printf("Polygon optimization FAILED.\n"); + } + finish = clock(); + printf("Intermediate time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + + vector next_polygons; + vector > next_unreachable_polygons; + + for (unsigned int i = 0; i < polygon_index_map.size(); ++i) + { + printf(" %d\n", polygon_index_map[i]); + } + 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()); + + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing preprocess 4 ... finished\n"); +} + + +TEST_CASE("Preprocessing test 5", "[Sequential Arrangement Preprocessing]") +{ + clock_t start, finish; + + printf("Testing preprocess 5 ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_MK3S_Y_SIZE}); + + std::vector polygons; + std::vector > unreachable_polygons; + + for (unsigned int i = 0; i < PRUSA_PART_POLYGONS.size(); ++i) + { + Polygon simplified_polygon, scale_down_polygon; + + decimate_PolygonForSequentialSolver(solver_configuration, + PRUSA_PART_POLYGONS[i], + simplified_polygon, + false); + REQUIRE(simplified_polygon.size() > 0); + + std::vector convex_level_polygons; + convex_level_polygons.push_back(PRUSA_PART_POLYGONS[i]); + convex_level_polygons.push_back(PRUSA_PART_POLYGONS[i]); + std::vector box_level_polygons; + box_level_polygons.push_back(PRUSA_PART_POLYGONS[i]); + box_level_polygons.push_back(PRUSA_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(PRUSA_PART_POLYGONS[i], "blue"); + + preview_svg.Close(); + } + + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing preprocess 5 ... finished\n"); +} + + +TEST_CASE("Preprocessing test 6", "[Sequential Arrangement Preprocessing]") +{ + clock_t start, finish; + + printf("Testing preprocess 6 ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_MK3S_Y_SIZE}); + + std::vector polygons; + std::vector > unreachable_polygons; + for (unsigned int i = 0; i < PRUSA_PART_POLYGONS.size(); ++i) + { + Polygon decimated_polygon; + decimate_PolygonForSequentialSolver(solver_configuration, + PRUSA_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(PRUSA_PART_POLYGONS[i]); + convex_level_polygons.push_back(PRUSA_PART_POLYGONS[i]); + std::vector box_level_polygons; + box_level_polygons.push_back(PRUSA_PART_POLYGONS[i]); + box_level_polygons.push_back(PRUSA_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); + + printf("----> Optimization finished <----\n"); + REQUIRE(optimized); + + if (optimized) + { + 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]); + } + + 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 (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 (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 + { + printf("Polygon optimization FAILED.\n"); + } + finish = clock(); + printf("Intermediate time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + + vector next_polygons; + vector > next_unreachable_polygons; + + for (unsigned int i = 0; i < polygon_index_map.size(); ++i) + { + printf(" %d\n", polygon_index_map[i]); + } + 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()); + + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing preprocess 6 ... finished\n"); +} + + +/*----------------------------------------------------------------*/ diff --git a/src/libseqarrange/test/seq_test_preprocess.hpp b/src/libseqarrange/test/seq_test_preprocess.hpp new file mode 100644 index 0000000000..789b4afed2 --- /dev/null +++ b/src/libseqarrange/test/seq_test_preprocess.hpp @@ -0,0 +1,18 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2024 + * Company: Prusa Research + * + * File: seq_test_preprocess.hpp + * + * Object preprocessing for sequential priting via SMT. + */ +/*================================================================*/ + +#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 0000000000..da1f562420 --- /dev/null +++ b/src/libseqarrange/test/seq_test_sequential.cpp @@ -0,0 +1,2207 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2024 + * Company: Prusa Research + * + * File: seq_test_sequential.cpp + * + * Basic steel plate sequential object scheduling via SMT. + */ +/*================================================================*/ + +#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_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_PRUSA_MK3S_X_SIZE = 2500; +const int SEQ_PRUSA_MK3S_Y_SIZE = 2100; + + +/*----------------------------------------------------------------*/ + + +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]") +{ + printf("Testing sequential scheduling 1 ...\n"); + + 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); + + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + printf("Printing smt status:\n"); + cout << z_solver.to_smt2() << "\n"; + + bool sat = false; + switch (z_solver.check()) + { + case z3::sat: + { + sat = true; + printf(" SATISFIABLE\n"); + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + z3::model z_model(z_solver.get_model()); + printf("Printing model:\n"); + cout << z_model << "\n"; + + 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"; + + if (z_model.get_const_interp(z_model[i]).is_bool()) + { + printf(" value: TRUE\n"); + } + else + { + printf(" value: FALSE\n"); + } + } + + printf("Testing sequential scheduling 1 ... finished\n"); +} + + +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) + { + printf("Generating random object %d ...\n", i); + + 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; + + printf("O %d: w:%d h:%d d:%d\n", i, complex_Obj_widths[i], complex_Obj_heights[i], complex_Obj_durations[i]); + } +} + + +typedef std::basic_string sString; + +TEST_CASE("Sequential test 2", "[Sequential Arrangement Core]") +{ + clock_t start, finish; + + printf("Testing sequential scheduling 2 ...\n"); + generate_random_complex_objects(); + + start = clock(); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name_L: %s\n", name_L.c_str()); + + sString name_R = "gantry_R-" + to_string(i); + printf("name_R: %s\n", name_R.c_str()); + + 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; + printf(" SATISFIABLE\n"); + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + REQUIRE(!sat); + + #ifdef DEBUG + { + z3::model z_model(z_solver.get_model()); + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + finish = clock(); + + #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) + { + double val; + printf("%s\n", z_model.get_const_interp(z_model[i]).get_string().c_str()); + } + } + #endif + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing sequential scheduling 2 ... finished\n"); +} + + +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) + { + printf("Generating random object %d ...\n", i); + + 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; + + printf("w: %d, h: %d\n", width, height); + + rotated_Obj_widths[i][r] = width; + rotated_Obj_heights[i][r] = height; + + angle += angle_step; + + 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]); + } + + complex_Obj_durations[i] = min_duration + rand() % duration_span; + } +} + + +TEST_CASE("Sequential test 3", "[Sequential Arrangement Core]") +{ + clock_t start, finish; + + printf("Testing sequential scheduling 3 ...\n"); + generate_random_rotated_complex_objects(); + + start = clock(); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name_L: %s\n", name_L.c_str()); + + sString name_R = "gantry_R-" + to_string(i); + printf("name_R: %s\n", name_R.c_str()); + + 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; + printf(" SATISFIABLE\n"); + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + REQUIRE(sat); + + #ifdef DEBUG + { + z3::model z_model(z_solver.get_model()); + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + finish = clock(); + + #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) + { + double val; + printf("%s\n", z_model.get_const_interp(z_model[i]).get_string().c_str()); + } + } + #endif + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing sequential scheduling 3 ... finished\n"); +} + +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]") +{ + clock_t start, finish; + + printf("Testing sequential 4 ...\n"); + + start = clock(); + + 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) + { + printf("i:%d\n", i); + string name = "x_pos-" + to_string(i); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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; + 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; + + for (int bounding_box_size = 200; bounding_box_size > 10; bounding_box_size -= 4) + { + printf("BB: %d\n", bounding_box_size); + 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: + { + printf(" SATISFIABLE\n"); + sat = true; + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + sat = false; + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + 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); + + 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; + } + } + + 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); + + 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: + { + printf(" sat\n"); + refined_sat = true; + break; + } + case z3::unsat: + { + printf(" unsat\n"); + refined_sat = false; + break; + } + case z3::unknown: + { + printf(" unknown\n"); + 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; + } + } + 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); + } + else + { + break; + } + } + else + { + 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; + + last_solvable_bounding_box_size = bounding_box_size; + break; + } + } + } + else + { + break; + } + } + finish = clock(); + + REQUIRE(last_solvable_bounding_box_size > 0); + + 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); + + #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(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing sequential 4 ... finished\n"); +} + + +TEST_CASE("Sequential test 5", "[Sequential Arrangement Core]") +{ + clock_t start, finish; + + printf("Testing sequential 5 ...\n"); + + start = clock(); + + 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) + { + printf("i:%d\n", i); + string name = "x_pos-" + to_string(i); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + printf("name: %s\n", name.c_str()); + + 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); + + 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()); + + 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); + + printf("Printing solver status:\n"); + cout << z_solver << "\n"; + + #ifdef DEBUG + { + 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) + { + printf("BB: %d\n", bounding_box_size); + 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: + { + printf(" SATISFIABLE\n"); + sat = true; + break; + } + case z3::unsat: + { + printf(" UNSATISFIABLE\n"); + sat = false; + break; + } + case z3::unknown: + { + printf(" UNKNOWN\n"); + break; + } + default: + { + break; + } + } + + if (sat) + { + z3::model z_model(z_solver.get_model()); + + #ifdef DEBUG + { + printf("Printing model:\n"); + cout << z_model << "\n"; + } + #endif + + 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); + + 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; + } + } + + 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()); + + 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: + { + printf(" sat\n"); + refined_sat = true; + break; + } + case z3::unsat: + { + printf(" unsat\n"); + refined_sat = false; + break; + } + case z3::unknown: + { + printf(" unknown\n"); + 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) + { + printf("Variable:%s ", z_model[i].name().str().c_str()); + double value = z_model.get_const_interp(z_model[i]).as_double(); + printf("value: %.3f\n", value); + + 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; + } + } + 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()); + } + else + { + break; + } + } + else + { + 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; + + last_solvable_bounding_box_size = bounding_box_size; + break; + } + } + } + else + { + break; + } + } + finish = clock(); + REQUIRE(last_solvable_bounding_box_size > 0); + + 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()); + + + #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(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing sequential 5 ... finished\n"); +} + + +TEST_CASE("Sequential test 6", "[Sequential Arrangement Core]") +{ + clock_t start, finish; + + printf("Testing polygon 6 ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_MK3S_Y_SIZE}); + + 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 (int j = 0; j < unreachable_polygons_1.size(); ++j) + { + for (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); + + printf("----> Optimization finished <----\n"); + + if (optimized) + { + 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]); + } + + 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 (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 + { + printf("Polygon optimization FAILED.\n"); + } + + vector next_polygons; + vector next_unreachable_polygons; + + for (unsigned int i = 0; i < polygon_index_map.size(); ++i) + { + printf(" %d\n", polygon_index_map[i]); + } + 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()); + + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing sequential 6 ... finished\n"); +} + + +TEST_CASE("Sequential test 7", "[Sequential Arrangement Core]") +{ + clock_t start, finish; + + printf("Testing polygon 7 ...\n"); + + start = clock(); + + SolverConfiguration solver_configuration; + solver_configuration.plate_bounding_box = BoundingBox({0,0}, {SEQ_PRUSA_MK3S_X_SIZE, SEQ_PRUSA_MK3S_Y_SIZE}); + + 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 (int j = 0; j < unreachable_polygons_1.size(); ++j) + { + for (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); + + printf("----> Optimization finished <----\n"); + + if (optimized) + { + 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]); + } + + 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 (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 (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 + { + printf("Polygon optimization FAILED.\n"); + } + + vector next_polygons; + vector > next_unreachable_polygons; + + for (unsigned int i = 0; i < polygon_index_map.size(); ++i) + { + printf(" %d\n", polygon_index_map[i]); + } + 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()); + + finish = clock(); + + printf("Time: %.3f\n", (finish - start) / (double)CLOCKS_PER_SEC); + printf("Testing sequential 7 ... finished\n"); +} + + + +/*----------------------------------------------------------------*/ diff --git a/src/libseqarrange/test/seq_test_sequential.hpp b/src/libseqarrange/test/seq_test_sequential.hpp new file mode 100644 index 0000000000..13cac6b4f1 --- /dev/null +++ b/src/libseqarrange/test/seq_test_sequential.hpp @@ -0,0 +1,18 @@ +/*================================================================*/ +/* + * Author: Pavel Surynek, 2023 - 2024 + * Company: Prusa Research + * + * File: seq_test_sequential.hpp + * + * Basic steel plate sequential object scheduling via SMT. + */ +/*================================================================*/ + +#ifndef __SEQ_TEST_SEQUENTIAL_HPP__ +#define __SEQ_TEST_SEQUENTIAL_HPP__ + +/*----------------------------------------------------------------*/ + + +#endif /* __SEQ_TEST_SEQUENTIAL_HPP__ */ diff --git a/src/libslic3r/ArrangeHelper.cpp b/src/libslic3r/ArrangeHelper.cpp new file mode 100644 index 0000000000..b34c7924ca --- /dev/null +++ b/src/libslic3r/ArrangeHelper.cpp @@ -0,0 +1,388 @@ +#include "ArrangeHelper.hpp" + +#include "libslic3r/Model.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/MultipleBeds.hpp" +#include "libslic3r/PresetBundle.hpp" +#include "libslic3r/BuildVolume.hpp" + +#include + +#include "boost/regex.hpp" +#include "boost/property_tree/json_parser.hpp" +#include "boost/algorithm/string/replace.hpp" +#include + + + +namespace Slic3r { + + +static bool can_arrange_selected_bed(const Model& model, int bed_idx) +{ + // When arranging a single bed, all instances of each object present must be on the same bed. + // Otherwise, the resulting order may not be possible to apply without messing up order + // on the other beds. + const auto map = s_multiple_beds.get_inst_map(); + for (const ModelObject* mo : model.objects) { + std::map used_beds; + bool mo_on_this_bed = false; + for (const ModelInstance* mi : mo->instances) { + int id = -1; + if (auto it = map.find(mi->id()); it != map.end()) + id = it->second; + if (id == bed_idx) + mo_on_this_bed = true; + used_beds[id] = true; + } + if (mo_on_this_bed && used_beds.size() != 1) + return false; + } + return true; +} + +static Sequential::PrinterGeometry get_printer_geometry(const ConfigBase& config) +{ + enum ShapeType { + BOX, + CONVEX + }; + struct ExtruderSlice { + coord_t height; + ShapeType shape_type; + std::vector polygons; + }; + + BuildVolume bv(config.opt("bed_shape")->values, 10.); + const BoundingBox& bb = bv.bounding_box(); + Polygon bed_polygon; + if (bv.type() == BuildVolume::Type::Circle) { + // Generate an inscribed octagon. + double r = bv.bounding_volume2d().size().x() / 2.; + for (double a = 2*M_PI; a > 0.1; a -= M_PI/4.) + bed_polygon.points.emplace_back(Point::new_scale(r * std::sin(a), r * std::cos(a))); + } else { + // Rectangle of Custom. Just use the bounding box. + bed_polygon = bb.polygon(); + } + + std::vector slices; + const std::string printer_notes = config.opt_string("printer_notes"); + { + if (! printer_notes.empty()) { + try { + boost::nowide::ifstream in(resources_dir() + "/data/printer_gantries/geometries.txt"); + boost::property_tree::ptree pt; + boost::property_tree::read_json(in, pt); + for (const auto& printer : pt.get_child("printers")) { + slices = {}; + std::string printer_notes_match = printer.second.get("printer_notes_regex"); + boost::regex rgx(printer_notes_match); + if (! boost::regex_match(printer_notes, rgx)) + continue; + + for (const auto& obj : printer.second.get_child("slices")) { + ExtruderSlice slice; + slice.height = scaled(obj.second.get("height")); + std::string type_str = obj.second.get("type"); + slice.shape_type = type_str == "box" ? BOX : CONVEX; + for (const auto& polygon : obj.second.get_child("polygons")) { + Polygon pgn; + std::string pgn_str = polygon.second.data(); + boost::replace_all(pgn_str, ";", " "); + boost::replace_all(pgn_str, ",", " "); + std::stringstream ss(pgn_str); + while (ss) { + double x = 0.; + double y = 0.; + ss >> x >> y; + if (ss) + pgn.points.emplace_back(Point::new_scale(x, y)); + } + if (! pgn.points.empty()) + slice.polygons.emplace_back(std::move(pgn)); + } + slices.emplace_back(std::move(slice)); + } + break; + } + } + catch (const boost::property_tree::json_parser_error&) { + // Failed to parse JSON. slices are empty, fallback will be used. + } + } + if (slices.empty()) { + // Fallback to primitive model using radius and height. + coord_t r = scaled(std::max(0.1, config.opt_float("extruder_clearance_radius"))); + coord_t h = scaled(std::max(0.1, config.opt_float("extruder_clearance_height"))); + double bed_x = bv.bounding_volume2d().size().x(); + double bed_y = bv.bounding_volume2d().size().y(); + slices.push_back(ExtruderSlice{ 0, CONVEX, { { { -5000000, -5000000 }, { 5000000, -5000000 }, { 5000000, 5000000 }, { -5000000, 5000000 } } } }); + slices.push_back(ExtruderSlice{ 1000000, BOX, { { { -r, -r }, { r, -r }, { r, r }, { -r, r } } } }); + slices.push_back(ExtruderSlice{ h, BOX, { { { -scaled(bed_x), -r }, { scaled(bed_x), -r }, { scaled(bed_x), r }, { -scaled(bed_x), r}}} }); + } + } + + // Convert the read data so libseqarrange understands them. + Sequential::PrinterGeometry out; + out.plate = bed_polygon; + for (const ExtruderSlice& slice : slices) { + (slice.shape_type == CONVEX ? out.convex_heights : out.box_heights).emplace(slice.height); + out.extruder_slices.insert(std::make_pair(slice.height, slice.polygons)); + } + return out; +} + +static Sequential::SolverConfiguration get_solver_config(const Sequential::PrinterGeometry& printer_geometry) +{ + return Sequential::SolverConfiguration(printer_geometry); +} + +static std::vector get_objects_to_print(const Model& model, const Sequential::PrinterGeometry& printer_geometry, int selected_bed) +{ + // First extract the heights of interest. + std::vector heights; + for (const auto& [height, pgns] : printer_geometry.extruder_slices) + heights.push_back(unscaled(height)); + Slic3r::sort_remove_duplicates(heights); + + // Now collect all objects and projections of convex hull above respective heights. + std::vector>> objects; // first = object id, the vector = ids of its instances + for (const ModelObject* mo : model.objects) { + const TriangleMesh& raw_mesh = mo->raw_mesh(); + coord_t height = scaled(mo->instance_bounding_box(0).size().z()); + std::vector instances; + for (const ModelInstance* mi : mo->instances) { + if (selected_bed != -1) { + auto it = s_multiple_beds.get_inst_map().find(mi->id()); + if (it == s_multiple_beds.get_inst_map().end() || it->second != selected_bed) + continue; + } + if (mi->printable) { + instances.emplace_back(Sequential::ObjectToPrint{int(mi->id().id), true, height, {}}); + + for (double height : heights) { + // It seems that zero level in the object instance is mi->get_offset().z(), however need to have bed as zero level, + // hence substracting mi->get_offset().z() from height seems to be an easy hack + Polygon pgn = its_convex_hull_2d_above(raw_mesh.its, mi->get_matrix_no_offset().cast(), height - mi->get_offset().z()); + instances.back().pgns_at_height.emplace_back(std::make_pair(scaled(height), pgn)); + } + } + } + + // Collect all instances of this object to be arranged, unglue it from the next object. + if (! instances.empty()) { + objects.emplace_back(instances.front(), instances); + objects.back().second.erase(objects.back().second.begin()); // pop_front + if (! objects.back().second.empty()) + objects.back().second.back().glued_to_next = false; + else + objects.back().first.glued_to_next = false; + } + } + + // Now order the objects so that the are always passed in the order of increasing id. + // That way, the algorithm will give the same result when called repeatedly. + // However, there is an exception: instances cannot be separated from their objects. + std::sort(objects.begin(), objects.end(), [](const auto& a, const auto& b) { return a.first.id < b.first.id; }); + std::vector objects_out; + for (const auto& o : objects) { + objects_out.emplace_back(o.first); + for (const auto& i : o.second) + objects_out.emplace_back(i); + } + + return objects_out; +} + + + + +void arrange_model_sequential(Model& model, const ConfigBase& config, bool current_bed_only) +{ + SeqArrange seq_arrange(model, config, current_bed_only); + seq_arrange.process_seq_arrange([](int) {}); + seq_arrange.apply_seq_arrange(model); +} + + + +SeqArrange::SeqArrange(const Model& model, const ConfigBase& config, bool current_bed_only) +{ + m_selected_bed = current_bed_only ? s_multiple_beds.get_active_bed() : -1; + if (m_selected_bed != -1 && ! can_arrange_selected_bed(model, m_selected_bed)) + throw ExceptionCannotAttemptSeqArrange(); + + m_printer_geometry = get_printer_geometry(config); + m_solver_configuration = get_solver_config(m_printer_geometry); + m_objects = get_objects_to_print(model, m_printer_geometry, m_selected_bed); +} + + + +void SeqArrange::process_seq_arrange(std::function progress_fn) +{ + m_plates = + Sequential::schedule_ObjectsForSequentialPrint( + m_solver_configuration, + m_printer_geometry, + m_objects, progress_fn); + + // If this was arrangement of a single bed, check that all instances of a single object + // ended up on the same bed. Otherwise we cannot apply the result (instances of a single + // object always follow one another in the object list and therefore the print). + if (m_selected_bed != -1 && s_multiple_beds.get_number_of_beds() > 1) { + int expected_plate = -1; + for (const Sequential::ObjectToPrint& otp : m_objects) { + auto it = std::find_if(m_plates.begin(), m_plates.end(), [&otp](const auto& plate) + { return std::any_of(plate.scheduled_objects.begin(), plate.scheduled_objects.end(), + [&otp](const auto& obj) { return otp.id == obj.id; + }); + }); + assert(it != m_plates.end()); + size_t plate_id = it - m_plates.begin(); + if (expected_plate != -1 && expected_plate != plate_id) + throw ExceptionCannotApplySeqArrange(); + expected_plate = otp.glued_to_next ? plate_id : -1; + } + } +} + + +// Extract the result and move the objects in Model accordingly. +void SeqArrange::apply_seq_arrange(Model& model) const +{ + struct MoveData { + Sequential::ScheduledObject scheduled_object; + size_t bed_idx; + ModelObject* mo; + }; + + // Iterate over the result and move the instances. + std::vector move_data_all; // Needed for the ordering. + size_t plate_idx = 0; + size_t new_number_of_beds = s_multiple_beds.get_number_of_beds(); + std::vector touched_beds; + for (const Sequential::ScheduledPlate& plate : m_plates) { + int real_bed = plate_idx; + if (m_selected_bed != -1) { + // Only a single bed was arranged. Move "first" bed to its position + // and everything else to newly created beds. + real_bed += (plate_idx == 0 ? m_selected_bed : s_multiple_beds.get_number_of_beds() - 1); + } + touched_beds.emplace_back(real_bed); + new_number_of_beds = std::max(new_number_of_beds, size_t(real_bed + 1)); + const Vec3d bed_offset = s_multiple_beds.get_bed_translation(real_bed); + + for (const Sequential::ScheduledObject& object : plate.scheduled_objects) + for (ModelObject* mo : model.objects) + for (ModelInstance* mi : mo->instances) + if (mi->id().id == object.id) { + move_data_all.push_back({ object, size_t(real_bed), mo }); + mi->set_offset(Vec3d(unscaled(object.x) + bed_offset.x(), unscaled(object.y) + bed_offset.y(), mi->get_offset().z())); + } + ++plate_idx; + } + + // Create a copy of ModelObject pointers, zero ones present in move_data_all. + // The point is to only reorder ModelObject which had actually been passed to the arrange algorithm. + std::vector objects_reordered = model.objects; + for (size_t i = 0; i < objects_reordered.size(); ++i) { + ModelObject* mo = objects_reordered[i]; + if (std::any_of(move_data_all.begin(), move_data_all.end(), [&mo](const MoveData& md) { return md.mo == mo; })) + objects_reordered[i] = nullptr; + } + // Fill the gaps with the arranged objects in the correct order. + for (size_t i = 0; i < objects_reordered.size(); ++i) { + if (! objects_reordered[i]) { + objects_reordered[i] = move_data_all[0].mo; + while (! move_data_all.empty() && move_data_all.front().mo == objects_reordered[i]) + move_data_all.erase(move_data_all.begin()); + } + } + + // Check that the old and new vectors only differ in order of elements. + auto a = model.objects; + auto b = objects_reordered; + std::sort(a.begin(), a.end()); + std::sort(b.begin(), b.end()); + if (a != b) + std::terminate(); // A bug in the code above. Better crash now than later. + + // Update objects order in the model. + std::swap(model.objects, objects_reordered); + + // One last thing. Move unprintable instances to new beds. It would be nicer to + // arrange them (non-sequentially) on just one bed - maybe one day. + std::map> instances_to_move; // bed to move from and list of instances + for (ModelObject* mo : model.objects) + for (ModelInstance* mi : mo->instances) + if (!mi->printable) { + auto it = s_multiple_beds.get_inst_map().find(mi->id()); + if (it == s_multiple_beds.get_inst_map().end() || (m_selected_bed != -1 && it->second != m_selected_bed)) + continue; + // Was something placed on this bed during arrange? If not, we should not move anything. + if (std::find(touched_beds.begin(), touched_beds.end(), it->second) != touched_beds.end()) + instances_to_move[it->second].emplace_back(mi); + } + // Now actually move them. + for (auto& [bed_idx, instances] : instances_to_move) { + Vec3d old_bed_offset = s_multiple_beds.get_bed_translation(bed_idx); + Vec3d new_bed_offset = s_multiple_beds.get_bed_translation(new_number_of_beds); + for (ModelInstance* mi : instances) + mi->set_offset(mi->get_offset() - old_bed_offset + new_bed_offset); + ++new_number_of_beds; + } +} + + + +std::optional > check_seq_conflict(const Model& model, const ConfigBase& config) +{ + Sequential::PrinterGeometry printer_geometry = get_printer_geometry(config); + Sequential::SolverConfiguration solver_config = get_solver_config(printer_geometry); + std::vector objects = get_objects_to_print(model, printer_geometry, -1); + + if (printer_geometry.extruder_slices.empty()) { + // If there are no data for extruder (such as extruder_clearance_radius set to 0), + // consider it printable. + return {}; + } + + Sequential::ScheduledPlate plate; + for (const ModelObject* mo : model.objects) { + int inst_id = -1; + for (const ModelInstance* mi : mo->instances) { + ++inst_id; + + auto it = s_multiple_beds.get_inst_map().find(mi->id()); + if (it == s_multiple_beds.get_inst_map().end() || it->second != s_multiple_beds.get_active_bed()) + continue; + + // Is this instance in objects to print? It may be unprintable or something. + auto it2 = std::find_if(objects.begin(), objects.end(), [&mi](const Sequential::ObjectToPrint& otp) { return otp.id == mi->id().id; }); + if (it2 == objects.end()) + continue; + + Vec3d offset = s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed()); + plate.scheduled_objects.emplace_back(mi->id().id, scaled(mi->get_offset().x() - offset.x()), scaled(mi->get_offset().y() - offset.y())); + } + } + + std::optional> conflict = Sequential::check_ScheduledObjectsForSequentialConflict(solver_config, printer_geometry, objects, std::vector(1, plate)); + if (conflict) { + std::pair names; + for (const ModelObject* mo : model.objects) + for (const ModelInstance* mi : mo->instances) { + if (mi->id().id == conflict->first) + names.first = mo->name; + if (mi->id().id == conflict->second) + names.second = mo->name; + } + return names; + } + return std::nullopt; +} + + +} // namespace Slic3r diff --git a/src/libslic3r/ArrangeHelper.hpp b/src/libslic3r/ArrangeHelper.hpp new file mode 100644 index 0000000000..912b841103 --- /dev/null +++ b/src/libslic3r/ArrangeHelper.hpp @@ -0,0 +1,42 @@ +#ifndef libslic3r_Arrange_Helper_hpp +#define libslic3r_Arrange_Helper_hpp + +#include "libseqarrange/seq_interface.hpp" + + + +namespace Slic3r { + + class Model; + class ConfigBase; + + class ExceptionCannotAttemptSeqArrange : public std::exception {}; + class ExceptionCannotApplySeqArrange : public std::exception {}; + + void arrange_model_sequential(Model& model, const ConfigBase& config); + + std::optional> check_seq_conflict(const Model& model, const ConfigBase& config); + + // This is just a helper class to collect data for seq. arrangement, running the arrangement + // and applying the results to model. It is here so the processing itself can be offloaded + // into a separate thread without copying the Model or sharing it with UI thread. + class SeqArrange { + public: + explicit SeqArrange(const Model& model, const ConfigBase& config, bool current_bed_only); + void process_seq_arrange(std::function progress_fn); + void apply_seq_arrange(Model& model) const; + + private: + // Following three are inputs, filled in by the constructor. + Sequential::PrinterGeometry m_printer_geometry; + Sequential::SolverConfiguration m_solver_configuration; + std::vector m_objects; + int m_selected_bed = -1; + + // This is the output, filled in by process_seq_arrange. + std::vector m_plates; + }; + +} + +#endif // slic3r_Arrange_Helper_hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 3d79437076..c3ab9c3a17 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -34,6 +34,8 @@ set(SLIC3R_SOURCES AABBTreeLines.hpp AABBMesh.hpp AABBMesh.cpp + ArrangeHelper.cpp + ArrangeHelper.hpp Algorithm/LineSegmentation/LineSegmentation.cpp Algorithm/LineSegmentation/LineSegmentation.hpp Algorithm/PathSorting.hpp @@ -603,6 +605,7 @@ target_link_libraries(libslic3r PUBLIC agg ankerl boost_headeronly + libseqarrange ) if (APPLE) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index b54e13c3ce..6c27390ea4 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1278,6 +1278,8 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail file.write(m_label_objects.maybe_stop_instance()); const double last_z{this->writer().get_position().z()}; file.write(this->writer().travel_to_z_force(last_z, "ensure z position")); + const double travel_z = std::max(last_z, double(m_max_layer_z)); + file.write(this->writer().travel_to_z_force(travel_z, "ensure z position to clear all already printed objects")); const Vec3crd from{to_3d(*this->last_position, scaled(this->m_last_layer_z))}; const Vec3crd to{0, 0, scaled(this->m_last_layer_z)}; file.write(this->travel_to(from, to, ExtrusionRole::None, "move to origin position for next object", [](){return "";})); diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index daf1b96c32..471b4cb3d3 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -538,6 +538,7 @@ void GCodeProcessorResult::reset() { custom_gcode_per_print_z = std::vector(); spiral_vase_mode = false; conflict_result = std::nullopt; + sequential_collision_detected = std::nullopt; } const std::vector> GCodeProcessor::Producers = { diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index b218c95dc0..690b10bc4f 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -163,6 +163,7 @@ namespace Slic3r { bool spiral_vase_mode; ConflictResultOpt conflict_result; + std::optional> sequential_collision_detected; void reset(); }; diff --git a/src/libslic3r/MultipleBeds.hpp b/src/libslic3r/MultipleBeds.hpp index 8f58e98f3a..10ab40f420 100644 --- a/src/libslic3r/MultipleBeds.hpp +++ b/src/libslic3r/MultipleBeds.hpp @@ -86,7 +86,11 @@ public: void update_build_volume(const BoundingBoxf& build_volume_bb) { m_build_volume_bb = build_volume_bb; } - Vec2d bed_gap() const; + Vec2d get_bed_size() const { return m_build_volume_bb.size(); } + BoundingBoxf get_build_volume_box() const { return m_build_volume_bb; } + BoundingBox get_bed_box() const { return BoundingBox({m_build_volume_bb.min.x(), m_build_volume_bb.min.y()}, + {m_build_volume_bb.max.x(), m_build_volume_bb.max.y()}); } + Vec2d bed_gap() const; Vec2crd get_bed_gap() const; void ensure_wipe_towers_on_beds(Model& model, const std::vector>& prints); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 79a7524c53..5ff7364e5c 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -497,8 +497,8 @@ static std::vector s_Preset_print_options { "support_material_buildplate_only", "support_tree_angle", "support_tree_angle_slow", "support_tree_branch_diameter", "support_tree_branch_diameter_angle", "support_tree_branch_diameter_double_wall", "support_tree_top_rate", "support_tree_branch_distance", "support_tree_tip_diameter", - "dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius", - "extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "gcode_substitutions", "perimeter_extruder", + "dont_support_bridges", "thick_bridges", "notes", "complete_objects", + "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "gcode_substitutions", "perimeter_extruder", "infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder", "ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width", "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", @@ -556,7 +556,7 @@ static std::vector s_Preset_printer_options { "max_print_height", "default_print_profile", "inherits", "remaining_times", "silent_mode", "machine_limits_usage", "thumbnails", "thumbnails_format", - "nozzle_high_flow" + "nozzle_high_flow", "extruder_clearance_radius", "extruder_clearance_height" }; static std::vector s_Preset_sla_print_options { diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 7097576f20..529fd604a8 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -37,6 +37,7 @@ #include "Utils.hpp" #include "BuildVolume.hpp" #include "format.hpp" +#include "ArrangeHelper.hpp" #include @@ -432,89 +433,6 @@ bool Print::has_brim() const return std::any_of(m_objects.begin(), m_objects.end(), [](PrintObject *object) { return object->has_brim(); }); } -bool Print::sequential_print_horizontal_clearance_valid(const Print& print, Polygons* polygons) -{ - Polygons convex_hulls_other; - if (polygons != nullptr) - polygons->clear(); - std::vector intersecting_idxs; - - std::map map_model_object_to_convex_hull; - for (const PrintObject *print_object : print.objects()) { - assert(! print_object->model_object()->instances.empty()); - assert(! print_object->instances().empty()); - ObjectID model_object_id = print_object->model_object()->id(); - auto it_convex_hull = map_model_object_to_convex_hull.find(model_object_id); - // Get convex hull of all printable volumes assigned to this print object. - ModelInstance *model_instance0 = print_object->model_object()->instances.front(); - if (it_convex_hull == map_model_object_to_convex_hull.end()) { - // Calculate the convex hull of a printable object. - // Grow convex hull with the clearance margin. - // FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2) - // which causes that the warning will be showed after arrangement with the - // appropriate object distance. Even if I set this to jtMiter the warning still shows up. - Geometry::Transformation trafo = model_instance0->get_transformation(); - trafo.set_offset({ 0.0, 0.0, model_instance0->get_offset().z() }); - Polygon ch2d = print_object->model_object()->convex_hull_2d(trafo.get_matrix()); - Polygons offs_ch2d = offset(ch2d, - // Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects - // exactly by satisfying the extruder_clearance_radius, this test will not trigger collision. - float(scale_(0.5 * print.config().extruder_clearance_radius.value - BuildVolume::BedEpsilon)), jtRound, scale_(0.1)); - // for invalid geometries the vector returned by offset() may be empty - if (!offs_ch2d.empty()) - it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id, offs_ch2d.front()); - } - if (it_convex_hull != map_model_object_to_convex_hull.end()) { - // Make a copy, so it may be rotated for instances. - Polygon convex_hull0 = it_convex_hull->second; - const double z_diff = Geometry::rotation_diff_z(model_instance0->get_matrix(), print_object->instances().front().model_instance->get_matrix()); - if (std::abs(z_diff) > EPSILON) - convex_hull0.rotate(z_diff); - // Now we check that no instance of convex_hull intersects any of the previously checked object instances. - for (const PrintInstance& instance : print_object->instances()) { - Polygon convex_hull = convex_hull0; - // instance.shift is a position of a centered object, while model object may not be centered. - // Convert the shift from the PrintObject's coordinates into ModelObject's coordinates by removing the centering offset. - convex_hull.translate(instance.shift - print_object->center_offset()); - // if output needed, collect indices (inside convex_hulls_other) of intersecting hulls - for (size_t i = 0; i < convex_hulls_other.size(); ++i) { - if (!intersection(convex_hulls_other[i], convex_hull).empty()) { - if (polygons == nullptr) - return false; - else { - intersecting_idxs.emplace_back(i); - intersecting_idxs.emplace_back(convex_hulls_other.size()); - } - } - } - convex_hulls_other.emplace_back(std::move(convex_hull)); - } - } - } - - if (!intersecting_idxs.empty()) { - // use collected indices (inside convex_hulls_other) to update output - std::sort(intersecting_idxs.begin(), intersecting_idxs.end()); - intersecting_idxs.erase(std::unique(intersecting_idxs.begin(), intersecting_idxs.end()), intersecting_idxs.end()); - for (size_t i : intersecting_idxs) { - polygons->emplace_back(std::move(convex_hulls_other[i])); - } - return false; - } - return true; -} - -static inline bool sequential_print_vertical_clearance_valid(const Print &print) -{ - std::vector print_instances_ordered = sort_object_instances_by_model_order(print); - // Ignore the last instance printed. - print_instances_ordered.pop_back(); - // Find the other highest instance. - auto it = std::max_element(print_instances_ordered.begin(), print_instances_ordered.end(), [](auto l, auto r) { - return l->print_object->height() < r->print_object->height(); - }); - return it == print_instances_ordered.end() || (*it)->print_object->height() <= scale_(print.config().extruder_clearance_height.value); -} // Matches "G92 E0" with various forms of writing the zero and with an optional comment. boost::regex regex_g92e0 { "^[ \\t]*[gG]92[ \\t]*[eE](0(\\.0*)?|\\.0+)[ \\t]*(;.*)?$" }; @@ -544,15 +462,6 @@ std::string Print::validate(std::vector* warnings) const if (extruders.empty()) return _u8L("The supplied settings will cause an empty print."); - if (m_config.complete_objects) { - if (!sequential_print_horizontal_clearance_valid(*this, const_cast(&m_sequential_print_clearance_contours))) - return _u8L("Some objects are too close; your extruder will collide with them."); - if (!sequential_print_vertical_clearance_valid(*this)) - return _u8L("Some objects are too tall and cannot be printed without extruder collisions."); - } - else - const_cast(&m_sequential_print_clearance_contours)->clear(); - if (m_config.avoid_crossing_perimeters && m_config.avoid_crossing_curled_overhangs) { return _u8L("Avoid crossing perimeters option and avoid crossing curled overhangs option cannot be both enabled together."); } @@ -1061,6 +970,8 @@ void Print::process() if (conflictRes.has_value()) BOOST_LOG_TRIVIAL(error) << boost::format("gcode path conflicts found between %1% and %2%") % conflictRes->_objName1 % conflictRes->_objName2; + m_sequential_collision_detected = config().complete_objects ? check_seq_conflict(model(), config()) : std::nullopt; + BOOST_LOG_TRIVIAL(info) << "Slicing process finished." << log_memory_info(); } @@ -1090,6 +1001,9 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor if (m_conflict_result.has_value()) result->conflict_result = *m_conflict_result; + if (result) + result->sequential_collision_detected = m_sequential_collision_detected; + return path.c_str(); } diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index c1efc63598..e6728cf69e 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -688,9 +688,6 @@ public: const PrintRegion& get_print_region(size_t idx) const { return *m_print_regions[idx]; } const ToolOrdering& get_tool_ordering() const { return m_wipe_tower_data.tool_ordering; } - const Polygons& get_sequential_print_clearance_contours() const { return m_sequential_print_clearance_contours; } - static bool sequential_print_horizontal_clearance_valid(const Print& print, Polygons* polygons = nullptr); - // Returns if all used filaments have same shrinkage compensations. bool has_same_shrinkage_compensations() const; @@ -744,9 +741,6 @@ private: // Estimated print time, filament consumed. PrintStatistics m_print_statistics; - // Cache to store sequential print clearance contours - Polygons m_sequential_print_clearance_contours; - // To allow GCode to set the Print's GCodeExport step status. friend class GCodeGenerator; // To allow GCodeProcessor to emit warnings. @@ -755,6 +749,7 @@ private: friend class PrintObject; ConflictResultOpt m_conflict_result; + std::optional> m_sequential_collision_detected; // names of objects (hit first when printing second) }; } /* slic3r_Print_hpp_ */ diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index f4a7625609..1bce82c2fd 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1117,10 +1117,10 @@ void PrintConfigDef::init_fff_params() def = this->add("extruder_clearance_height", coFloat); def->label = L("Height"); - def->tooltip = L("Set this to the vertical distance between your nozzle tip and (usually) the X carriage rods. " - "In other words, this is the height of the clearance cylinder around your extruder, " - "and it represents the maximum depth the extruder can peek before colliding with " - "other printed objects."); + def->tooltip = L("Only used when 'Print Settings -> Complete individual objects' is active. Set this to the vertical " + "distance between your nozzle tip and (usually) the X carriage rods so slicer can check for collisions " + "with previously printed objects and prevent them when arranging.\n" + "The value is ignored for most Prusa printers, which come with more detailed extruder model."); def->sidetext = L("mm"); def->min = 0; def->mode = comExpert; @@ -1128,10 +1128,9 @@ void PrintConfigDef::init_fff_params() def = this->add("extruder_clearance_radius", coFloat); def->label = L("Radius"); - def->tooltip = L("Set this to the clearance radius around your extruder. " - "If the extruder is not centered, choose the largest value for safety. " - "This setting is used to check for collisions and to display the graphical preview " - "in the plater."); + def->tooltip = L("Only used when 'Print Settings -> Complete individual objects' is active. Set this so slicer can " + "check for collisions with previously printed objects and prevent them when arranging.\n" + "The value is ignored for most Prusa printers, which come with more detailed extruder model."); def->sidetext = L("mm"); def->min = 0; def->mode = comExpert; diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 3e1a8eed41..1645f3ccad 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -248,6 +248,8 @@ set(SLIC3R_GUI_SOURCES GUI/Jobs/PlaterWorker.hpp GUI/Jobs/ArrangeJob2.hpp GUI/Jobs/ArrangeJob2.cpp + GUI/Jobs/SeqArrangeJob.hpp + GUI/Jobs/SeqArrangeJob.cpp GUI/Jobs/CreateFontNameImageJob.cpp GUI/Jobs/CreateFontNameImageJob.hpp GUI/Jobs/CreateFontStyleImagesJob.cpp diff --git a/src/slic3r/GUI/ArrangeSettingsDialogImgui.cpp b/src/slic3r/GUI/ArrangeSettingsDialogImgui.cpp index c294fd0ecd..ca74d02393 100644 --- a/src/slic3r/GUI/ArrangeSettingsDialogImgui.cpp +++ b/src/slic3r/GUI/ArrangeSettingsDialogImgui.cpp @@ -7,6 +7,11 @@ #include "slic3r/GUI/format.hpp" #include "slic3r/GUI/GUI.hpp" +// These two should not be here. 2.9.1 is getting near and we need a quick +// way of detecting if complete_objects is used. +#include "slic3r/GUI/GUI_App.hpp" +#include "libslic3r/PresetBundle.hpp" + namespace Slic3r { namespace GUI { struct Settings { @@ -44,92 +49,100 @@ void ArrangeSettingsDialogImgui::render(float pos_x, float pos_y, bool current_b ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); - Settings settings; - read_settings(settings, m_db.get()); + if (! wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("complete_objects")) { + Settings settings; + read_settings(settings, m_db.get()); - ImGuiPureWrap::text(GUI::format( - _L("Press %1%left mouse button to enter the exact value"), - shortkey_ctrl_prefix())); + ImGuiPureWrap::text(GUI::format( + _L("Press %1%left mouse button to enter the exact value"), + shortkey_ctrl_prefix())); - float dobj_min, dobj_max; - float dbed_min, dbed_max; + float dobj_min, dobj_max; + float dbed_min, dbed_max; - m_db->distance_from_obj_range(dobj_min, dobj_max); - m_db->distance_from_bed_range(dbed_min, dbed_max); + m_db->distance_from_obj_range(dobj_min, dobj_max); + m_db->distance_from_bed_range(dbed_min, dbed_max); - if(dobj_min > settings.d_obj) { - settings.d_obj = std::max(dobj_min, settings.d_obj); - m_db->set_distance_from_objects(settings.d_obj); + if (dobj_min > settings.d_obj) { + settings.d_obj = std::max(dobj_min, settings.d_obj); + m_db->set_distance_from_objects(settings.d_obj); + } + + if (dbed_min > settings.d_bed) { + settings.d_bed = std::max(dbed_min, settings.d_bed); + m_db->set_distance_from_bed(settings.d_bed); + } + + if (m_imgui->slider_float(_L("Spacing"), &settings.d_obj, dobj_min, + dobj_max, "%5.2f")) { + settings.d_obj = std::max(dobj_min, settings.d_obj); + m_db->set_distance_from_objects(settings.d_obj); + } + + if (m_imgui->slider_float(_L("Spacing from bed"), &settings.d_bed, + dbed_min, dbed_max, "%5.2f")) { + settings.d_bed = std::max(dbed_min, settings.d_bed); + m_db->set_distance_from_bed(settings.d_bed); + } + + if (ImGuiPureWrap::checkbox(_u8L("Enable rotations (slow)"), settings.rotations)) { + m_db->set_rotation_enabled(settings.rotations); + } + + if (m_show_xl_combo_predicate() && + settings.xl_align >= 0 && + ImGuiPureWrap::combo(_u8L("Alignment"), + { _u8L("Center"), _u8L("Rear left"), _u8L("Front left"), + _u8L("Front right"), _u8L("Rear right"), + _u8L("Random") }, + settings.xl_align)) { + if (settings.xl_align >= 0 && + settings.xl_align < ArrangeSettingsView::xlpCount) + m_db->set_xl_alignment(static_cast( + settings.xl_align)); + } + + // TRN ArrangeDialog + if (ImGuiPureWrap::combo(_u8L("Geometry handling"), + // TRN ArrangeDialog: Type of "Geometry handling" + { _u8L("Fast"), + // TRN ArrangeDialog: Type of "Geometry handling" + _u8L("Balanced"), + // TRN ArrangeDialog: Type of "Geometry handling" + _u8L("Accurate") }, + settings.geom_handling)) { + if (settings.geom_handling >= 0 && + settings.geom_handling < ArrangeSettingsView::ghCount) + m_db->set_geometry_handling( + static_cast( + settings.geom_handling)); + } + + ImGui::Separator(); + + if (ImGuiPureWrap::button(_u8L("Reset defaults"))) { + arr2::ArrangeSettingsDb::Values df = m_db->get_defaults(); + m_db->set_distance_from_objects(df.d_obj); + m_db->set_distance_from_bed(df.d_bed); + m_db->set_rotation_enabled(df.rotations); + if (m_show_xl_combo_predicate()) + m_db->set_xl_alignment(df.xl_align); + + m_db->set_geometry_handling(df.geom_handling); + m_db->set_arrange_strategy(df.arr_strategy); + + if (m_on_reset_btn) + m_on_reset_btn(); + } + ImGui::SameLine(); + } else { + ImGui::PushTextWrapPos(350.f); + ImGuiPureWrap::text(_u8L("Sequential printing is active. Arrange algorithm will use geometry of the printer " + "to optimize objects placement and avoid collisions with the gantry.")); + ImGui::PopTextWrapPos(); + ImGui::Separator(); } - if (dbed_min > settings.d_bed) { - settings.d_bed = std::max(dbed_min, settings.d_bed); - m_db->set_distance_from_bed(settings.d_bed); - } - - if (m_imgui->slider_float(_L("Spacing"), &settings.d_obj, dobj_min, - dobj_max, "%5.2f")) { - settings.d_obj = std::max(dobj_min, settings.d_obj); - m_db->set_distance_from_objects(settings.d_obj); - } - - if (m_imgui->slider_float(_L("Spacing from bed"), &settings.d_bed, - dbed_min, dbed_max, "%5.2f")) { - settings.d_bed = std::max(dbed_min, settings.d_bed); - m_db->set_distance_from_bed(settings.d_bed); - } - - if (ImGuiPureWrap::checkbox(_u8L("Enable rotations (slow)"), settings.rotations)) { - m_db->set_rotation_enabled(settings.rotations); - } - - if (m_show_xl_combo_predicate() && - settings.xl_align >= 0 && - ImGuiPureWrap::combo(_u8L("Alignment"), - {_u8L("Center"), _u8L("Rear left"), _u8L("Front left"), - _u8L("Front right"), _u8L("Rear right"), - _u8L("Random")}, - settings.xl_align)) { - if (settings.xl_align >= 0 && - settings.xl_align < ArrangeSettingsView::xlpCount) - m_db->set_xl_alignment(static_cast( - settings.xl_align)); - } - - // TRN ArrangeDialog - if (ImGuiPureWrap::combo(_u8L("Geometry handling"), - // TRN ArrangeDialog: Type of "Geometry handling" - {_u8L("Fast"), - // TRN ArrangeDialog: Type of "Geometry handling" - _u8L("Balanced"), - // TRN ArrangeDialog: Type of "Geometry handling" - _u8L("Accurate")}, - settings.geom_handling)) { - if (settings.geom_handling >= 0 && - settings.geom_handling < ArrangeSettingsView::ghCount) - m_db->set_geometry_handling( - static_cast( - settings.geom_handling)); - } - - ImGui::Separator(); - - if (ImGuiPureWrap::button(_u8L("Reset defaults"))) { - arr2::ArrangeSettingsDb::Values df = m_db->get_defaults(); - m_db->set_distance_from_objects(df.d_obj); - m_db->set_distance_from_bed(df.d_bed); - m_db->set_rotation_enabled(df.rotations); - if (m_show_xl_combo_predicate()) - m_db->set_xl_alignment(df.xl_align); - - m_db->set_geometry_handling(df.geom_handling); - m_db->set_arrange_strategy(df.arr_strategy); - - if (m_on_reset_btn) - m_on_reset_btn(); - } - - ImGui::SameLine(); if (!current_bed && ImGuiPureWrap::button(_u8L("Arrange")) && m_on_arrange_btn) { m_on_arrange_btn(); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 70c187107c..04b9e44ca3 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -388,10 +388,6 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) for (auto el : { "ironing_type", "ironing_flowrate", "ironing_spacing", "ironing_speed" }) toggle_field(el, has_ironing); - bool have_sequential_printing = config->opt_bool("complete_objects"); - for (auto el : { "extruder_clearance_radius", "extruder_clearance_height" }) - toggle_field(el, have_sequential_printing); - bool have_ooze_prevention = config->opt_bool("ooze_prevention"); toggle_field("standby_temperature_delta", have_ooze_prevention); diff --git a/src/slic3r/GUI/DoubleSliderForLayers.cpp b/src/slic3r/GUI/DoubleSliderForLayers.cpp index 1d6275e441..bead6e4a4e 100644 --- a/src/slic3r/GUI/DoubleSliderForLayers.cpp +++ b/src/slic3r/GUI/DoubleSliderForLayers.cpp @@ -773,6 +773,11 @@ void DSForLayers::render_cog_menu() if (m_cb_change_app_config) m_cb_change_app_config("show_estimated_times_in_dbl_slider", m_show_estimated_times ? "1" : "0"); } + if (ImGuiPureWrap::menu_item_with_icon(_u8L("Sequential slider applied only to top layer").c_str(), "", icon_sz, 0, m_seq_top_layer_only)) { + m_seq_top_layer_only = !m_seq_top_layer_only; + if (m_cb_change_app_config) + m_cb_change_app_config("seq_top_layer_only", m_seq_top_layer_only ? "1" : "0"); + } if (m_mode == MultiAsSingle && m_draw_mode == dmRegular && ImGuiPureWrap::menu_item_with_icon(_u8L("Set extruder sequence for the entire print").c_str(), "")) { if (m_ticks.edit_extruder_sequence(m_ctrl.GetMaxPos(), m_mode)) diff --git a/src/slic3r/GUI/DoubleSliderForLayers.hpp b/src/slic3r/GUI/DoubleSliderForLayers.hpp index cce1b84d33..ca00127ffb 100644 --- a/src/slic3r/GUI/DoubleSliderForLayers.hpp +++ b/src/slic3r/GUI/DoubleSliderForLayers.hpp @@ -91,6 +91,7 @@ public: void set_imgui_wrapper(Slic3r::GUI::ImGuiWrapper* imgui) { m_imgui = imgui; } void show_estimated_times(bool show) { m_show_estimated_times = show; } void show_ruler(bool show, bool show_bg) { m_show_ruler = show; m_show_ruler_bg = show_bg; } + void seq_top_layer_only(bool show) { m_seq_top_layer_only = show; } // manipulation with slider from keyboard @@ -151,6 +152,7 @@ private: bool m_show_ruler_bg { true }; bool m_show_cog_menu { false }; bool m_show_edit_menu { false }; + bool m_seq_top_layer_only { false }; int m_pos_on_move { -1 }; DrawMode m_draw_mode { dmRegular }; diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index e61360c777..86796dff5f 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -217,46 +217,83 @@ int GCodeViewer::SequentialView::ActualSpeedImguiWidget::plot(const char* label, } #endif // ENABLE_ACTUAL_SPEED_DEBUG -void GCodeViewer::SequentialView::Marker::init() -{ - m_model.init_from(stilized_arrow(16, 2.0f, 4.0f, 1.0f, 8.0f)); - m_model.set_color({ 1.0f, 1.0f, 1.0f, 0.5f }); -} +void GCodeViewer::SequentialView::Marker::init(std::optional>& model_opt) + { + if (! model_opt.has_value()) + return; + + m_model.reset(); + + m_generic_marker = (model_opt->get() == nullptr); + if (m_generic_marker) + m_model.init_from(stilized_arrow(16, 2.0f, 4.0f, 1.0f, 8.0f)); + else + m_model = **model_opt; + + m_model.set_color({ 1.0f, 1.0f, 1.0f, 0.5f }); + } void GCodeViewer::SequentialView::Marker::render() { if (!m_visible) return; - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + GLShaderProgram* shader = wxGetApp().get_shader("tool_marker"); if (shader == nullptr) return; glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + const bool curr_cull_face = glIsEnabled(GL_CULL_FACE); + glsafe(::glDisable(GL_CULL_FACE)); + shader->start_using(); - shader->set_uniform("emission_factor", 0.0f); const Camera& camera = wxGetApp().plater()->get_camera(); Transform3d view_matrix = camera.get_view_matrix(); - view_matrix.translate(s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed())); + Vec3d bed_inst_offset = s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed()); + view_matrix.translate(bed_inst_offset); + + std::array, 2> clip_planes; + if (m_generic_marker) + // dummy values, generic marker does not need clipping + clip_planes = {{ { 1.0f, 0.0f, 0.0f, FLT_MAX }, { 1.0f, 0.0f, 0.0f, FLT_MAX } }}; + else { + BoundingBoxf box = s_multiple_beds.get_build_volume_box(); + box.translate(to_2d(bed_inst_offset)); + // add a bit on both sides + box = box.inflated(40.0f); + clip_planes = {{ { 1.0f, 0.0f, 0.0f, -box.min.cast().x() } , { -1.0f, 0.0f, 0.0f, box.max.cast().x() }}}; + } float scale_factor = m_scale_factor; if (m_fixed_screen_size) scale_factor *= 10.0f * camera.get_inv_zoom(); - const Transform3d model_matrix = (Geometry::translation_transform((m_world_position + m_model_z_offset * Vec3f::UnitZ()).cast()) * - Geometry::translation_transform(scale_factor * m_model.get_bounding_box().size().z() * Vec3d::UnitZ()) * Geometry::rotation_transform({ M_PI, 0.0, 0.0 })) * - Geometry::scale_transform(scale_factor); + const Transform3d model_matrix = m_generic_marker + ? Geometry::translation_transform((m_world_position + m_model_z_offset * Vec3f::UnitZ()).cast()) * + Geometry::translation_transform(scale_factor * m_model.get_bounding_box().size().z() * Vec3d::UnitZ()) * + Geometry::rotation_transform({ M_PI, 0.0, 0.0 }) * + Geometry::scale_transform(scale_factor) + : Geometry::translation_transform(m_world_position.cast()); shader->set_uniform("view_model_matrix", view_matrix * model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); + Transform3d volume_world_matrix = model_matrix; + if (!m_generic_marker) + volume_world_matrix = Geometry::translation_transform(bed_inst_offset) * volume_world_matrix; + shader->set_uniform("volume_world_matrix", volume_world_matrix); + shader->set_uniform("clipping_planes[0]", clip_planes[0]); + shader->set_uniform("clipping_planes[1]", clip_planes[1]); m_model.render(); shader->stop_using(); + if (curr_cull_face) + glsafe(::glEnable(GL_CULL_FACE)); + glsafe(::glDisable(GL_BLEND)); } @@ -842,9 +879,6 @@ void GCodeViewer::init() if (m_gl_data_initialized) return; - // initializes tool marker - m_sequential_view.marker.init(); - m_gl_data_initialized = true; try @@ -1102,6 +1136,8 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const m_conflict_result = gcode_result.conflict_result; if (m_conflict_result.has_value()) m_conflict_result->layer = m_viewer.get_layer_id_at(static_cast(m_conflict_result->_height)); + + m_sequential_collision_detected = gcode_result.sequential_collision_detected; } void GCodeViewer::load_as_preview(libvgcode::GCodeInputData&& data) @@ -1166,6 +1202,13 @@ void GCodeViewer::render() const libvgcode::PathVertex& curr_vertex = m_viewer.get_current_vertex(); m_sequential_view.marker.set_world_position(libvgcode::convert(curr_vertex.position)); m_sequential_view.marker.set_z_offset(m_z_offset); + + // Following just makes sure that the shown marker is correct. + auto marker_model_opt = wxGetApp().plater()->get_current_canvas3D()->get_current_marker_model(); + m_sequential_view.marker.init(marker_model_opt); + if (marker_model_opt.has_value()) + m_max_bounding_box.reset(); + m_sequential_view.render(legend_height, &m_viewer, curr_vertex.gcode_id); } } diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 21ca5b81ba..f37cd8c70d 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -127,12 +127,13 @@ public: bool m_visible{ true }; bool m_fixed_screen_size{ false }; float m_scale_factor{ 1.0f }; + bool m_generic_marker{ true }; #if ENABLE_ACTUAL_SPEED_DEBUG ActualSpeedImguiWidget m_actual_speed_imgui_widget; #endif // ENABLE_ACTUAL_SPEED_DEBUG public: - void init(); + void init(std::optional>& model_opt); const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); } @@ -260,6 +261,7 @@ private: bool m_contained_in_bed{ true }; ConflictResultOpt m_conflict_result; + std::optional> m_sequential_collision_detected; libvgcode::Viewer m_viewer; bool m_loaded_as_preview{ false }; @@ -356,6 +358,7 @@ public: void invalidate_legend() { m_legend_resizer.reset(); } const ConflictResultOpt& get_conflict_result() const { return m_conflict_result; } + std::optional> get_sequential_collision_detected() const { return m_sequential_collision_detected; } void load_shells(const Print& print); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 51d6de463e..9e91642cd0 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -11,6 +11,11 @@ #include "libslic3r/libslic3r.h" #include "GLCanvas3D.hpp" +#include + +#include +#include + #include // IWYU pragma: keep #include #include @@ -44,6 +49,7 @@ #include "I18N.hpp" #include "NotificationManager.hpp" #include "format.hpp" +#include "libslic3r/ArrangeHelper.hpp" #include "slic3r/GUI/BitmapCache.hpp" #include "slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp" @@ -76,6 +82,7 @@ #include #include #include +#include #include #include @@ -122,8 +129,6 @@ void GLCanvas3D::select_bed(int i, bool triggered_by_user) } } wxGetApp().plater()->canvas3D()->m_process->stop(); - m_sequential_print_clearance.m_evaluating = true; - reset_sequential_print_clearance(); post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, is_sliceable(s_print_statuses[i]))); @@ -153,6 +158,69 @@ void GLCanvas3D::select_bed(int i, bool triggered_by_user) }); } +// Returns extruder model to visualize in the GCodeViewer: +// - nullopt = same as before +// - nullptr = none available, use generic +// - GLModel = the model to use +std::optional> GLCanvas3D::get_current_marker_model() const +{ + std::optional> out; + + static std::string last_printer_notes; + static double old_r = 0.; + static double old_h = 0.; + static bool old_seq = false; + + std::string printer_notes = m_config->opt_string("printer_notes"); + double r = m_config->opt_float("extruder_clearance_radius"); + double h = m_config->opt_float("extruder_clearance_height"); + bool seq = m_config->opt_bool("complete_objects"); + + if (last_printer_notes != printer_notes || r != old_r || h != old_h || seq != old_seq) { + last_printer_notes = printer_notes; + old_r = r; + old_h = h; + old_seq = seq; + + out = std::make_optional(nullptr); + if (! seq) + return out; + try { + boost::nowide::ifstream in(resources_dir() + "/data/printer_gantries/geometries.txt"); + boost::property_tree::ptree pt; + boost::property_tree::read_json(in, pt); + for (const auto& printer : pt.get_child("printers")) { + std::string printer_notes_match = printer.second.get("printer_notes_regex"); + boost::regex rgx(printer_notes_match); + if (boost::regex_match(printer_notes, rgx)) { + std::string filename = resources_dir() + "/data/printer_gantries/" + printer.second.get("gantry_model_filename"); + if (boost::filesystem::exists(filename)) { + std::unique_ptr m = std::make_unique(); + if (m->init_from_file(filename)) + out = std::make_optional(std::move(m)); + } + break; + } + } + } catch (...) { + // Whatever happened, ignore it. We will return nullptr. + } + if (*out == nullptr && seq) { + // Generic sequential extruder model. + double gantry_height = 10; + auto mesh = its_make_cylinder(r, h + gantry_height - 0.001); + double d = 3 * wxGetApp().plater()->build_volume().bounding_volume2d().size().x(); + auto mesh2 = its_make_cube(d,2*r, gantry_height); + its_translate(mesh2, Vec3f(-d/2, -r, h)); + its_merge(mesh, mesh2); + std::unique_ptr m = std::make_unique(); + m->init_from(mesh); + out = std::make_optional(std::move(m)); + } + } + return out; +} + #ifdef __WXGTK3__ // wxGTK3 seems to simulate OSX behavior in regard to HiDPI scaling support. RetinaHelper::RetinaHelper(wxWindow* window) : m_window(window), m_self(nullptr) {} @@ -923,141 +991,6 @@ void GLCanvas3D::Tooltip::render(const Vec2d& mouse_position, GLCanvas3D& canvas ImGui::PopStyleVar(2); } -void GLCanvas3D::SequentialPrintClearance::set_contours(const ContoursList& contours, bool generate_fill) -{ - m_contours.clear(); - m_instances.clear(); - m_fill.reset(); - - if (contours.empty()) - return; - - const Vec3d bed_offset = generate_fill ? s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed()) : Vec3d::Zero(); - - if (generate_fill) { - GLModel::Geometry fill_data; - fill_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; - fill_data.color = { 0.3333f, 0.0f, 0.0f, 0.5f }; - - // vertices + indices - const ExPolygons polygons_union = union_ex(contours.contours); - unsigned int vertices_counter = 0; - for (const ExPolygon& poly : polygons_union) { - const std::vector triangulation = triangulate_expolygon_3d(poly); - fill_data.reserve_vertices(fill_data.vertices_count() + triangulation.size()); - fill_data.reserve_indices(fill_data.indices_count() + triangulation.size()); - for (const Vec3d& v : triangulation) { - fill_data.add_vertex((Vec3f)((bed_offset + v).cast() + 0.0125f * Vec3f::UnitZ())); // add a small positive z to avoid z-fighting - ++vertices_counter; - if (vertices_counter % 3 == 0) - fill_data.add_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); - } - } - m_fill.init_from(std::move(fill_data)); - } - - const Transform3d bed_transform = Geometry::translation_transform(bed_offset); - - for (size_t i = 0; i < contours.contours.size(); ++i) { - GLModel& model = m_contours.emplace_back(GLModel()); - model.init_from(contours.contours[i], 0.025f); // add a small positive z to avoid z-fighting - } - - if (contours.trafos.has_value()) { - // create the requested instances - for (const auto& instance : *contours.trafos) { - m_instances.emplace_back(instance.first, bed_transform * instance.second); - } - } - else { - // no instances have been specified - // create one instance for every polygon - for (size_t i = 0; i < contours.contours.size(); ++i) { - m_instances.emplace_back(i, bed_transform); - } - } -} - -void GLCanvas3D::SequentialPrintClearance::update_instances_trafos(const std::vector& trafos) -{ - if (trafos.size() == m_instances.size()) { - for (size_t i = 0; i < trafos.size(); ++i) { - m_instances[i].second = trafos[i]; - } - } - else - assert(false); -} - -void GLCanvas3D::SequentialPrintClearance::render() -{ - static const ColorRGBA FILL_COLOR = { 1.0f, 0.0f, 0.0f, 0.5f }; - static const ColorRGBA NO_FILL_COLOR = { 1.0f, 1.0f, 1.0f, 0.75f }; - static const ColorRGBA NO_FILL_EVALUATING_COLOR = { 1.0f, 1.0f, 0.0f, 1.0f }; - - if (m_contours.empty() || m_instances.empty()) - return; - - GLShaderProgram* shader = wxGetApp().get_shader("flat"); - if (shader == nullptr) - return; - - shader->start_using(); - - const Camera& camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("view_model_matrix", camera.get_view_matrix()); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - - glsafe(::glEnable(GL_DEPTH_TEST)); - glsafe(::glDisable(GL_CULL_FACE)); - glsafe(::glEnable(GL_BLEND)); - glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - - if (!m_evaluating && !m_dragging) - m_fill.render(); - -#if !SLIC3R_OPENGL_ES - if (OpenGLManager::get_gl_info().is_core_profile()) { -#endif // !SLIC3R_OPENGL_ES - shader->stop_using(); - -#if SLIC3R_OPENGL_ES - shader = wxGetApp().get_shader("dashed_lines"); -#else - shader = wxGetApp().get_shader("dashed_thick_lines"); -#endif // SLIC3R_OPENGL_ES - if (shader == nullptr) - return; - - shader->start_using(); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - const std::array& viewport = camera.get_viewport(); - shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); - shader->set_uniform("width", 1.0f); - shader->set_uniform("gap_size", 0.0f); -#if !SLIC3R_OPENGL_ES - } - else - glsafe(::glLineWidth(2.0f)); -#endif // !SLIC3R_OPENGL_ES - - const ColorRGBA color = (!m_evaluating && !m_dragging && m_fill.is_initialized()) ? FILL_COLOR : - m_evaluating ? NO_FILL_EVALUATING_COLOR : NO_FILL_COLOR; - - for (const auto& [id, trafo] : m_instances) { - shader->set_uniform("view_model_matrix", camera.get_view_matrix() * trafo); - assert(id < m_contours.size()); - m_contours[id].set_color(color); - m_contours[id].render(); - } - - glsafe(::glDisable(GL_BLEND)); - glsafe(::glEnable(GL_CULL_FACE)); - glsafe(::glDisable(GL_DEPTH_TEST)); - - shader->stop_using(); -} - wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent); @@ -1410,10 +1343,10 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas *canvas, Bed3D &bed) return this->is_arrange_alignment_enabled(); }); m_arrange_settings_dialog.on_arrange_btn([]{ - wxGetApp().plater()->arrange(); + wxGetApp().plater()->arrange(false); }); m_arrange_settings_dialog.on_arrange_bed_btn([]{ - wxGetApp().plater()->arrange_current_bed(); + wxGetApp().plater()->arrange(true); }); } @@ -2216,10 +2149,6 @@ void GLCanvas3D::render() if (show_imgui_demo_window) ImGui::ShowDemoWindow(); #endif // SHOW_IMGUI_DEMO_WINDOW - - - - const bool is_looking_downward = camera.is_looking_downward(); // draw scene @@ -2237,7 +2166,6 @@ void GLCanvas3D::render() _render_gcode(); _render_objects(GLVolumeCollection::ERenderType::Transparent); - _render_sequential_clearance(); #if ENABLE_RENDER_SELECTION_CENTER _render_selection_center(); #endif // ENABLE_RENDER_SELECTION_CENTER @@ -2996,6 +2924,7 @@ void GLCanvas3D::load_gcode_preview(const GCodeProcessorResult& gcode_result, co if (wxGetApp().is_editor()) { _set_warning_notification_if_needed(EWarning::ToolpathOutside); _set_warning_notification_if_needed(EWarning::GCodeConflict); + _set_warning_notification_if_needed(EWarning::SequentialCollision); } set_as_dirty(); @@ -3888,8 +3817,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) c == GLGizmosManager::EType::Scale || c == GLGizmosManager::EType::Rotate) { show_sinking_contours(); - if (_is_sequential_print_enabled()) - update_sequential_clearance(true); } } else if (evt.LeftUp() && @@ -4048,10 +3975,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_selection.setup_cache(); if (!evt.CmdDown()) m_mouse.drag.start_position_3D = m_mouse.scene_position; - m_sequential_print_clearance.m_first_displacement = true; - if (_is_sequential_print_enabled()) - update_sequential_clearance(true); - m_sequential_print_clearance.start_dragging(); } } } @@ -4100,8 +4023,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) TransformationType trafo_type; trafo_type.set_relative(); m_selection.translate(cur_pos - m_mouse.drag.start_position_3D, trafo_type); - if (_is_sequential_print_enabled()) - update_sequential_clearance(false); wxGetApp().obj_manipul()->set_dirty(); m_dirty = true; @@ -4179,8 +4100,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) else if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) { m_mouse.position = pos.cast(); - if (evt.LeftUp() && m_sequential_print_clearance.is_dragging()) - m_sequential_print_clearance.stop_dragging(); if (evt.RightUp() && m_mouse.is_start_position_2D_defined()) { // forces camera target to be on the plane z = 0 Camera& camera = wxGetApp().plater()->get_camera(); @@ -4460,11 +4379,6 @@ void GLCanvas3D::do_move(const std::string& snapshot_type) post_event(SimpleEvent(EVT_GLCANVAS_WIPETOWER_TOUCHED)); } - if (_is_sequential_print_enabled()) { - update_sequential_clearance(true); - m_sequential_print_clearance.m_evaluating = true; - } - m_dirty = true; } @@ -4558,11 +4472,6 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type) if (!done.empty()) post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_ROTATED)); - if (_is_sequential_print_enabled()) { - update_sequential_clearance(true); - m_sequential_print_clearance.m_evaluating = true; - } - m_dirty = true; } @@ -4635,11 +4544,6 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type) if (!done.empty()) post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_SCALED)); - if (_is_sequential_print_enabled()) { - update_sequential_clearance(true); - m_sequential_print_clearance.m_evaluating = true; - } - m_dirty = true; } @@ -4893,137 +4797,6 @@ void GLCanvas3D::mouse_up_cleanup() m_canvas->ReleaseMouse(); } -void GLCanvas3D::update_sequential_clearance(bool force_contours_generation) -{ - if (!_is_sequential_print_enabled()) - return; - - if (m_layers_editing.is_enabled()) - return; - - auto instance_transform_from_volumes = [this](int object_idx, int instance_idx) { - for (const GLVolume* v : m_volumes.volumes) { - if (v->object_idx() == object_idx && v->instance_idx() == instance_idx) - return v->get_instance_transformation(); - } - assert(false); - return Geometry::Transformation(); - }; - - auto is_object_outside_printbed = [this](int object_idx) { - for (const GLVolume* v : m_volumes.volumes) { - if (v->object_idx() == object_idx && v->is_outside) - return true; - } - return false; - }; - - // collects instance transformations from volumes - // first: define temporary cache - unsigned int instances_count = 0; - std::vector>> instance_transforms; - for (size_t obj = 0; obj < m_model->objects.size(); ++obj) { - instance_transforms.emplace_back(std::vector>()); - const ModelObject* model_object = m_model->objects[obj]; - for (size_t i = 0; i < model_object->instances.size(); ++i) { - instance_transforms[obj].emplace_back(std::optional()); - ++instances_count; - } - } - - if (instances_count == 1) - return; - - // second: fill temporary cache with data from volumes - for (const GLVolume* v : m_volumes.volumes) { - if (v->is_wipe_tower()) - continue; - - const int object_idx = v->object_idx(); - const int instance_idx = v->instance_idx(); - auto& transform = instance_transforms[object_idx][instance_idx]; - if (!transform.has_value()) - transform = instance_transform_from_volumes(object_idx, instance_idx); - } - - // helper function to calculate the transformation to be applied to the sequential print clearance contours - auto instance_trafo = [](const Transform3d& hull_trafo, const Geometry::Transformation& inst_trafo) { - Vec3d offset = inst_trafo.get_offset() - hull_trafo.translation(); - offset.z() = 0.0; - return Geometry::translation_transform(offset) * - Geometry::rotation_transform(Geometry::rotation_diff_z(hull_trafo, inst_trafo.get_matrix()) * Vec3d::UnitZ()); - }; - - // calculates objects 2d hulls (see also: Print::sequential_print_horizontal_clearance_valid()) - // this is done only the first time this method is called while moving the mouse, - // the results are then cached for following displacements - if (force_contours_generation || m_sequential_print_clearance.m_first_displacement) { - m_sequential_print_clearance.m_evaluating = false; - m_sequential_print_clearance.m_hulls_2d_cache.clear(); - const float shrink_factor = static_cast(scale_(0.5 * fff_print()->config().extruder_clearance_radius.value - EPSILON)); - const double mitter_limit = scale_(0.1); - m_sequential_print_clearance.m_hulls_2d_cache.reserve(m_model->objects.size()); - for (size_t i = 0; i < m_model->objects.size(); ++i) { - ModelObject* model_object = m_model->objects[i]; - Geometry::Transformation trafo = instance_transform_from_volumes((int)i, 0); - trafo.set_offset({ 0.0, 0.0, trafo.get_offset().z() }); - Pointf3s& new_hull_2d = m_sequential_print_clearance.m_hulls_2d_cache.emplace_back(std::make_pair(Pointf3s(), trafo.get_matrix())).first; - if (is_object_outside_printbed((int)i)) - continue; - - Polygon hull_2d = model_object->convex_hull_2d(trafo.get_matrix()); - if (!hull_2d.empty()) { - // Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects - // exactly by satisfying the extruder_clearance_radius, this test will not trigger collision. - const Polygons offset_res = offset(hull_2d, shrink_factor, jtRound, mitter_limit); - if (!offset_res.empty()) - hull_2d = offset_res.front(); - } - - new_hull_2d.reserve(hull_2d.points.size()); - for (const Point& p : hull_2d.points) { - new_hull_2d.emplace_back(Vec3d(unscale(p.x()), unscale(p.y()), 0.0)); - } - } - - ContoursList contours; - contours.contours.reserve(instance_transforms.size()); - contours.trafos = std::vector>(); - (*contours.trafos).reserve(instances_count); - for (size_t i = 0; i < instance_transforms.size(); ++i) { - const auto& [hull, hull_trafo] = m_sequential_print_clearance.m_hulls_2d_cache[i]; - Points hull_pts; - hull_pts.reserve(hull.size()); - for (size_t j = 0; j < hull.size(); ++j) { - hull_pts.emplace_back(scaled(hull[j].x()), scaled(hull[j].y())); - } - contours.contours.emplace_back(Geometry::convex_hull(std::move(hull_pts))); - - const auto& instances = instance_transforms[i]; - for (const auto& instance : instances) { - (*contours.trafos).emplace_back(i, instance_trafo(hull_trafo, *instance)); - } - } - - set_sequential_print_clearance_contours(contours, false); - m_sequential_print_clearance.m_first_displacement = false; - } - else { - if (!m_sequential_print_clearance.empty()) { - std::vector trafos; - trafos.reserve(instances_count); - for (size_t i = 0; i < instance_transforms.size(); ++i) { - const auto& [hull, hull_trafo] = m_sequential_print_clearance.m_hulls_2d_cache[i]; - const auto& instances = instance_transforms[i]; - for (const auto& instance : instances) { - trafos.emplace_back(instance_trafo(hull_trafo, *instance)); - } - } - m_sequential_print_clearance.update_instances_trafos(trafos); - } - } -} - bool GLCanvas3D::is_object_sinking(int object_idx) const { for (const GLVolume* v : m_volumes.volumes) { @@ -6505,32 +6278,6 @@ void GLCanvas3D::_render_selection() #endif // ENABLE_MATRICES_DEBUG } -void GLCanvas3D::_render_sequential_clearance() -{ - if (!_is_sequential_print_enabled()) - return; - - if (m_layers_editing.is_enabled()) - return; - - switch (m_gizmos.get_current_type()) - { - case GLGizmosManager::EType::Flatten: - case GLGizmosManager::EType::Cut: - case GLGizmosManager::EType::MmSegmentation: - case GLGizmosManager::EType::Measure: - case GLGizmosManager::EType::Emboss: - case GLGizmosManager::EType::Simplify: - case GLGizmosManager::EType::FdmSupports: - case GLGizmosManager::EType::Seam: - case GLGizmosManager::EType::FuzzySkin: { return; } - default: { break; } - } - - m_sequential_print_clearance.render(); -} - - bool GLCanvas3D::check_toolbar_icon_size(float init_scale, float& new_scale_to_save, bool is_custom, int counter/* = 3*/) { const Size cnv_size = get_canvas_size(); @@ -6636,7 +6383,11 @@ void GLCanvas3D::_render_overlays() if (_is_sequential_print_enabled()) { for (ModelObject* model_object : m_model->objects) for (ModelInstance* model_instance : model_object->instances) { - sorted_instances.emplace_back(model_instance); + if (auto it = s_multiple_beds.get_inst_map().find(model_instance->id()); + it != s_multiple_beds.get_inst_map().end() + && it->second == s_multiple_beds.get_active_bed() + ) + sorted_instances.emplace_back(model_instance); } } m_labels.render(sorted_instances); @@ -7620,6 +7371,8 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning) show = m_gcode_viewer.has_data() && !m_gcode_viewer.is_contained_in_bed(); else if (warning == EWarning::GCodeConflict) show = m_gcode_viewer.has_data() && m_gcode_viewer.is_contained_in_bed() && m_gcode_viewer.get_conflict_result().has_value(); + else if (warning == EWarning::SequentialCollision) + show = m_gcode_viewer.has_data() && m_gcode_viewer.get_sequential_collision_detected().has_value(); } } } @@ -7659,6 +7412,16 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) error = ErrorType::SLICING_ERROR; break; } + case EWarning::SequentialCollision: { + auto conflict = m_gcode_viewer.get_sequential_collision_detected(); + if (! conflict.has_value()) + break; + // TRN: Placeholders contain names of the colliding objects. + text = format(_u8L("Extruder will crash into %1% while printing %2%."), + conflict->first, conflict->second); + error = ErrorType::SLICING_ERROR; + break; + } } auto& notification_manager = *wxGetApp().plater()->get_notification_manager(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 037637878d..0a75e241bb 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -373,7 +373,8 @@ class GLCanvas3D SlaSupportsOutside, SomethingNotShown, ObjectClashed, - GCodeConflict + GCodeConflict, + SequentialCollision }; class RenderStats @@ -624,34 +625,6 @@ public: private: - class SequentialPrintClearance - { - GLModel m_fill; - // list of unique contours - std::vector m_contours; - // list of transforms used to render the contours - std::vector> m_instances; - bool m_evaluating{ false }; - bool m_dragging{ false }; - bool m_first_displacement{ true }; - - std::vector> m_hulls_2d_cache; - - public: - void set_contours(const ContoursList& contours, bool generate_fill); - void update_instances_trafos(const std::vector& trafos); - void render(); - bool empty() const { return m_contours.empty(); } - - void start_dragging() { m_dragging = true; } - bool is_dragging() const { return m_dragging; } - void stop_dragging() { m_dragging = false; } - - friend class GLCanvas3D; - }; - - SequentialPrintClearance m_sequential_print_clearance; - struct ToolbarHighlighter { void set_timer_owner(wxEvtHandler* owner, int timerid = wxID_ANY) { m_timer.SetOwner(owner, timerid); } @@ -756,6 +729,8 @@ public: const libvgcode::Interval& get_gcode_view_visible_range() const { return m_gcode_viewer.get_gcode_view_visible_range(); } const libvgcode::PathVertex& get_gcode_vertex_at(size_t id) const { return m_gcode_viewer.get_gcode_vertex_at(id); } + std::optional> get_current_marker_model() const; + void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1); void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1, const ModelVolume* mv = nullptr); void update_instance_printable_state_for_object(size_t obj_idx); @@ -989,39 +964,6 @@ public: #endif } - void reset_sequential_print_clearance() { - m_sequential_print_clearance.m_evaluating = false; - if (m_sequential_print_clearance.is_dragging()) - m_sequential_print_clearance.m_first_displacement = true; - else - m_sequential_print_clearance.set_contours(ContoursList(), false); - set_as_dirty(); - request_extra_frame(); - } - - void set_sequential_print_clearance_contours(const ContoursList& contours, bool generate_fill) { - m_sequential_print_clearance.set_contours(contours, generate_fill); - if (generate_fill) - m_sequential_print_clearance.m_evaluating = false; - set_as_dirty(); - request_extra_frame(); - } - - bool is_sequential_print_clearance_empty() const { - return m_sequential_print_clearance.empty(); - } - - bool is_sequential_print_clearance_evaluating() const { - return m_sequential_print_clearance.m_evaluating; - } - - void update_sequential_clearance(bool force_contours_generation); - void set_sequential_clearance_as_evaluating() { - m_sequential_print_clearance.m_evaluating = true; - set_as_dirty(); - request_extra_frame(); - } - const Print* fff_print() const; const SLAPrint* sla_print() const; @@ -1067,7 +1009,6 @@ private: void _render_gcode() { m_gcode_viewer.render(); } void _render_gcode_cog() { m_gcode_viewer.render_cog(); } void _render_selection(); - void _render_sequential_clearance(); bool check_toolbar_icon_size(float init_scale, float& new_scale_to_save, bool is_custom, int counter = 3); #if ENABLE_RENDER_SELECTION_CENTER void _render_selection_center() { m_selection.render_center(m_gizmos.is_dragging()); } diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index a5221f8b0a..9c921c82fe 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -67,6 +67,8 @@ std::pair GLShadersManager::init() #endif // SLIC3R_OPENGL_ES // used to render toolpaths center of gravity valid &= append_shader("toolpaths_cog", { prefix + "toolpaths_cog.vs", prefix + "toolpaths_cog.fs" }); + // used to render tool marker + valid &= append_shader("tool_marker", { prefix + "tool_marker.vs", prefix + "tool_marker.fs" }); // used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview valid &= append_shader("gouraud_light", { prefix + "gouraud_light.vs", prefix + "gouraud_light.fs" }); // extend "gouraud_light" by adding clipping, used in sla gizmos diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 76619eeeab..36dd1c9208 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -301,6 +301,7 @@ void Preview::reload_print() m_loaded = false; load_print(); + m_layers_slider->seq_top_layer_only(wxGetApp().app_config->get_bool("seq_top_layer_only")); } void Preview::msw_rescale() @@ -403,6 +404,7 @@ void Preview::create_sliders() m_layers_slider->SetEmUnit(wxGetApp().em_unit()); m_layers_slider->set_imgui_wrapper(wxGetApp().imgui()); m_layers_slider->show_estimated_times(wxGetApp().app_config->get_bool("show_estimated_times_in_dbl_slider")); + m_layers_slider->seq_top_layer_only(wxGetApp().app_config->get_bool("seq_top_layer_only")); m_layers_slider->show_ruler(wxGetApp().app_config->get_bool("show_ruler_in_dbl_slider"), wxGetApp().app_config->get_bool("show_ruler_bg_in_dbl_slider")); m_layers_slider->SetDrawMode(wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA, @@ -410,8 +412,10 @@ void Preview::create_sliders() m_layers_slider->set_callback_on_thumb_move( [this]() -> void { Preview::on_layers_slider_scroll_changed(); } ); - m_layers_slider->set_callback_on_change_app_config([](const std::string& key, const std::string& val) -> void { + m_layers_slider->set_callback_on_change_app_config([this](const std::string& key, const std::string& val) -> void { wxGetApp().app_config->set(key, val); + if (key == "seq_top_layer_only") + reload_print(); }); if (wxGetApp().is_editor()) { diff --git a/src/slic3r/GUI/Jobs/SeqArrangeJob.cpp b/src/slic3r/GUI/Jobs/SeqArrangeJob.cpp new file mode 100644 index 0000000000..a9d15f0b5d --- /dev/null +++ b/src/slic3r/GUI/Jobs/SeqArrangeJob.cpp @@ -0,0 +1,84 @@ +#include "SeqArrangeJob.hpp" + +#include "libslic3r/ArrangeHelper.hpp" + +#include "slic3r/GUI/GLCanvas3D.hpp" +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/GUI_ObjectList.hpp" +#include "slic3r/GUI/I18N.hpp" +#include "slic3r/GUI/Plater.hpp" +#include "slic3r/GUI/MsgDialog.hpp" +#include "slic3r/GUI/format.hpp" + + + +namespace Slic3r { namespace GUI { + + +SeqArrangeJob::SeqArrangeJob(const Model& model, const DynamicPrintConfig& config, bool current_bed_only) +{ + m_seq_arrange.reset(new SeqArrange(model, config, current_bed_only)); +} + + +void SeqArrangeJob::process(Ctl& ctl) +{ + class SeqArrangeJobException : std::exception {}; + + try { + m_seq_arrange->process_seq_arrange([&](int progress) { + ctl.update_status(progress, _u8L("Arranging for sequential print")); + if (ctl.was_canceled()) + throw SeqArrangeJobException(); + } + ); + } catch (const SeqArrangeJobException&) { + // The task was canceled. Just make sure that the progress notification disappears. + ctl.update_status(100, ""); + } +} + + + +void SeqArrangeJob::finalize(bool canceled, std::exception_ptr& eptr) +{ + // If the task was cancelled, the stopping exception was already caught + // in 'process' function. Any other exception propagates through here. + bool error = false; + if (eptr) { + try { + std::rethrow_exception(eptr); + } catch (const ExceptionCannotApplySeqArrange&) { + ErrorDialog dlg(wxGetApp().plater(), _L("The result of the single-bed arrange would scatter " + "instances of a single object between several beds, possibly affecting order of printing " + "of the non-selected beds. Consider using global arrange across all beds."), false); + dlg.ShowModal(); + error = true; + eptr = nullptr; // The exception is handled. + } catch (const Sequential::ObjectTooLargeException&) { + ErrorDialog dlg(wxGetApp().plater(), _L("One of the objects is too large to fit the bed."), false); + dlg.ShowModal(); + error = true; + eptr = nullptr; // The exception is handled. + } catch (const Sequential::InternalErrorException& ex) { + ErrorDialog dlg(wxGetApp().plater(), GUI::format_wxstr(_L("Internal error: %1%"), ex.what()), false); + dlg.ShowModal(); + error = true; + eptr = nullptr; // The exception is handled. + } + } + + if (! canceled && ! error) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Arrange for sequential print")); + m_seq_arrange->apply_seq_arrange(wxGetApp().model()); + wxGetApp().plater()->canvas3D()->reload_scene(true, true); + wxGetApp().obj_list()->update_after_undo_redo(); + } + m_seq_arrange.reset(); +} + + + + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/Jobs/SeqArrangeJob.hpp b/src/slic3r/GUI/Jobs/SeqArrangeJob.hpp new file mode 100644 index 0000000000..c604ebb772 --- /dev/null +++ b/src/slic3r/GUI/Jobs/SeqArrangeJob.hpp @@ -0,0 +1,31 @@ +#ifndef SEQARRANGEJOB_HPP +#define SEQARRANGEJOB_HPP + +#include "Job.hpp" + +namespace Slic3r { + +class Model; + + +class SeqArrange; +class DynamicPrintConfig; + +namespace GUI { + + +class SeqArrangeJob : public Job +{ +public: + explicit SeqArrangeJob(const Model& model, const DynamicPrintConfig& config, bool current_bed_only); + virtual void process(Ctl &ctl) override; + virtual void finalize(bool /*canceled*/, std::exception_ptr&) override; + +private: + std::unique_ptr m_seq_arrange; +}; + +} // namespace GUI +} // namespace Slic3r + +#endif // ARRANGEJOB2_HPP diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5184d4d708..400eac81d1 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -106,6 +106,7 @@ #include "ConfigWizardWebViewPage.hpp" #include "Jobs/RotoptimizeJob.hpp" +#include "Jobs/SeqArrangeJob.hpp" #include "Jobs/SLAImportJob.hpp" #include "Jobs/SLAImportDialog.hpp" #include "Jobs/NotificationProgressIndicator.hpp" @@ -138,6 +139,8 @@ #include "PresetArchiveDatabase.hpp" #include "BulkExportDialog.hpp" +#include "libslic3r/ArrangeHelper.hpp" + #ifdef __APPLE__ #include "Gizmos/GLGizmosManager.hpp" #endif // __APPLE__ @@ -622,7 +625,7 @@ Plater::priv::priv(Plater* q, MainFrame* main_frame) : q(q) , main_frame(main_frame) , config(Slic3r::DynamicPrintConfig::new_from_defaults_keys({ - "bed_shape", "bed_custom_texture", "bed_custom_model", "complete_objects", "duplicate_distance", "extruder_clearance_radius", "skirts", "skirt_distance", + "bed_shape", "bed_custom_texture", "bed_custom_model", "complete_objects", "duplicate_distance", "extruder_clearance_radius", "extruder_clearance_height", "skirts", "skirt_distance", "brim_width", "brim_separation", "brim_type", "variable_layer_height", "nozzle_diameter", "single_extruder_multi_material", "wipe_tower", "wipe_tower_width", "wipe_tower_brim_width", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extra_flow", "wipe_tower_extruder", "extruder_colour", "filament_colour", "material_colour", "max_print_height", "printer_model", "printer_notes", "printer_technology", @@ -712,8 +715,8 @@ void Plater::priv::init() view3D_canvas->Bind(EVT_GLCANVAS_OBJECT_SELECT, &priv::on_object_select, this); view3D_canvas->Bind(EVT_GLCANVAS_RIGHT_CLICK, &priv::on_right_click, this); view3D_canvas->Bind(EVT_GLCANVAS_REMOVE_OBJECT, [this](SimpleEvent&) { q->remove_selected(); }); - view3D_canvas->Bind(EVT_GLCANVAS_ARRANGE, [this](SimpleEvent&) { this->q->arrange(); }); - view3D_canvas->Bind(EVT_GLCANVAS_ARRANGE_CURRENT_BED, [this](SimpleEvent&) { this->q->arrange_current_bed(); }); + view3D_canvas->Bind(EVT_GLCANVAS_ARRANGE, [this](SimpleEvent&) { this->q->arrange(false); }); + view3D_canvas->Bind(EVT_GLCANVAS_ARRANGE_CURRENT_BED, [this](SimpleEvent&) { this->q->arrange(true); }); view3D_canvas->Bind(EVT_GLCANVAS_SELECT_ALL, [this](SimpleEvent&) { this->q->select_all(); }); view3D_canvas->Bind(EVT_GLCANVAS_QUESTION_MARK, [](SimpleEvent&) { wxGetApp().keyboard_shortcuts(); }); view3D_canvas->Bind(EVT_GLCANVAS_INCREASE_INSTANCES, [this](Event& evt) @@ -744,8 +747,8 @@ void Plater::priv::init() view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE, [this](SimpleEvent&) { q->remove_selected(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE_ALL, [this](SimpleEvent&) { delete_all_objects_from_model(); }); // view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE_ALL, [q](SimpleEvent&) { q->reset_with_confirm(); }); - view3D_canvas->Bind(EVT_GLTOOLBAR_ARRANGE, [this](SimpleEvent&) { this->q->arrange(); }); - view3D_canvas->Bind(EVT_GLTOOLBAR_ARRANGE_CURRENT_BED, [this](SimpleEvent&) { this->q->arrange_current_bed(); }); + view3D_canvas->Bind(EVT_GLTOOLBAR_ARRANGE, [this](SimpleEvent&) { this->q->arrange(false); }); + view3D_canvas->Bind(EVT_GLTOOLBAR_ARRANGE_CURRENT_BED, [this](SimpleEvent&) { this->q->arrange(true); }); view3D_canvas->Bind(EVT_GLTOOLBAR_COPY, [this](SimpleEvent&) { q->copy_selection_to_clipboard(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_PASTE, [this](SimpleEvent&) { q->paste_from_clipboard(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_MORE, [this](SimpleEvent&) { q->increase_instances(); }); @@ -1964,7 +1967,6 @@ void Plater::priv::delete_all_objects_from_model() reset_gcode_toolpaths(); std::for_each(gcode_results.begin(), gcode_results.end(), [](auto& g) { g.reset(); }); - view3D->get_canvas3d()->reset_sequential_print_clearance(); view3D->get_canvas3d()->reset_all_gizmos(); m_worker.cancel_all(); @@ -1998,8 +2000,6 @@ void Plater::priv::reset() reset_gcode_toolpaths(); std::for_each(gcode_results.begin(), gcode_results.end(), [](auto& g) { g.reset(); }); - view3D->get_canvas3d()->reset_sequential_print_clearance(); - m_worker.cancel_all(); // Stop and reset the Print content. @@ -2354,9 +2354,6 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool if (view3D->is_layers_editing_enabled()) view3D->get_wxglcanvas()->Refresh(); - if (invalidated == Print::APPLY_STATUS_CHANGED || background_process.empty()) - view3D->get_canvas3d()->reset_sequential_print_clearance(); - if (invalidated == Print::APPLY_STATUS_INVALIDATED) { // Some previously calculated data on the Print was invalidated. // Hide the slicing results, as the current slicing status is no more valid. @@ -2394,7 +2391,6 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool process_validation_warning(warnings); if (printer_technology == ptFFF) { GLCanvas3D* canvas = view3D->get_canvas3d(); - canvas->reset_sequential_print_clearance(); canvas->set_as_dirty(); canvas->request_extra_frame(); } @@ -2404,41 +2400,14 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool // Show error as notification. notification_manager->push_validate_error_notification(err); return_state |= UPDATE_BACKGROUND_PROCESS_INVALID; - if (printer_technology == ptFFF) { - GLCanvas3D* canvas = view3D->get_canvas3d(); - if (canvas->is_sequential_print_clearance_empty() || canvas->is_sequential_print_clearance_evaluating()) { - GLCanvas3D::ContoursList contours; - contours.contours = background_process.fff_print()->get_sequential_print_clearance_contours(); - canvas->set_sequential_print_clearance_contours(contours, true); - } - } } } else { if (invalidated == Print::APPLY_STATUS_UNCHANGED && !background_process.empty()) { - if (printer_technology == ptFFF) { - // Object manipulation with gizmos may end up in a null transformation. - // In this case, we need to trigger the completion of the sequential print clearance contours evaluation - GLCanvas3D* canvas = view3D->get_canvas3d(); - if (canvas->is_sequential_print_clearance_evaluating()) { - GLCanvas3D::ContoursList contours; - contours.contours = background_process.fff_print()->get_sequential_print_clearance_contours(); - canvas->set_sequential_print_clearance_contours(contours, true); - } - } std::vector warnings; std::string err = background_process.validate(&warnings); - if (!err.empty()) { - if (s_multiple_beds.get_number_of_beds() > 1 && printer_technology == ptFFF) { - // user changed bed seletion, - // sequential print clearance contours were changed too - GLCanvas3D* canvas = view3D->get_canvas3d(); - GLCanvas3D::ContoursList contours; - contours.contours = background_process.fff_print()->get_sequential_print_clearance_contours(); - canvas->set_sequential_print_clearance_contours(contours, true); - } + if (!err.empty()) return return_state; - } } if (! this->delayed_error_message.empty()) @@ -6896,7 +6865,6 @@ void Plater::on_config_change(const DynamicPrintConfig &config) this->set_printer_technology(printer_technology); p->sidebar->show_sliced_info_sizer(false); p->reset_gcode_toolpaths(); - p->view3D->get_canvas3d()->reset_sequential_print_clearance(); p->view3D->get_canvas3d()->set_sla_view_type(GLCanvas3D::ESLAViewType::Original); p->preview->get_canvas3d()->reset_volumes(); } @@ -7143,30 +7111,29 @@ static std::string concat_strings(const std::set &strings, }); } -void Plater::arrange() +void Plater::arrange(bool current_bed_only) { - const auto mode{ - wxGetKeyState(WXK_SHIFT) ? - ArrangeSelectionMode::SelectionOnly : - ArrangeSelectionMode::Full - }; + ArrangeSelectionMode mode; + if (current_bed_only) + mode = wxGetKeyState(WXK_SHIFT) ? ArrangeSelectionMode::CurrentBedSelectionOnly : ArrangeSelectionMode::CurrentBedFull; + else + mode = wxGetKeyState(WXK_SHIFT) ? ArrangeSelectionMode::SelectionOnly : ArrangeSelectionMode::Full; + + const bool sequential = p->config->has("complete_objects") && p->config->opt_bool("complete_objects"); if (p->can_arrange()) { - auto &w = get_ui_job_worker(); - arrange(w, mode); - } -} - -void Plater::arrange_current_bed() -{ - const auto mode{ - wxGetKeyState(WXK_SHIFT) ? - ArrangeSelectionMode::CurrentBedSelectionOnly : - ArrangeSelectionMode::CurrentBedFull - }; - if (p->can_arrange()) { - auto &w = get_ui_job_worker(); - arrange(w, mode); + if (sequential) { + try { + replace_job(this->get_ui_job_worker(), std::make_unique(this->model(), *p->config, current_bed_only)); + } catch (const ExceptionCannotAttemptSeqArrange&) { + ErrorDialog dlg(this, _L("Sequential arrange for a single bed is only allowed when all instances of the affected objects are on the same bed."), false); + dlg.ShowModal(); + } + } + else { + auto& w = get_ui_job_worker(); + arrange(w, mode); + } } } @@ -7757,7 +7724,7 @@ PlaterAfterLoadAutoArrange::PlaterAfterLoadAutoArrange() PlaterAfterLoadAutoArrange::~PlaterAfterLoadAutoArrange() { if (m_enabled) - wxGetApp().plater()->arrange(); + wxGetApp().plater()->arrange(false); } }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 10e5d769fb..879a125f2b 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -305,8 +305,7 @@ public: void render_sliders(GLCanvas3D& canvas); - void arrange(); - void arrange_current_bed(); + void arrange(bool current_bed_only); void arrange(Worker &w, const ArrangeSelectionMode &selected); void set_current_canvas_as_dirty(); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index eafaa0b1b4..ae92250230 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -146,6 +146,7 @@ void PreferencesDialog::show(const std::string& highlight_opt_key /*= std::strin ,"default_action_on_select_preset" }) m_optgroup_general->set_value(opt_key, app_config->get(opt_key) == "none"); m_optgroup_general->set_value("default_action_on_dirty_project", app_config->get("default_action_on_dirty_project").empty()); + m_optgroup_gui->set_value("seq_top_layer_only", app_config->get_bool("seq_top_layer_only")); // update colors for color pickers of the labels update_color(m_sys_colour, wxGetApp().get_label_clr_sys()); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 4509403d9c..dbf233720c 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1625,8 +1625,6 @@ void Selection::erase() wxGetApp().obj_list()->delete_from_model_and_list(items); ensure_not_below_bed(); } - - wxGetApp().plater()->canvas3D()->set_sequential_clearance_as_evaluating(); } void Selection::render(float scale_factor) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index d5c268be42..623b4853c0 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1694,11 +1694,20 @@ void TabPrint::build() page = add_options_page(L("Output options"), "output+page_white"); optgroup = page->new_optgroup(L("Sequential printing")); optgroup->append_single_option_line("complete_objects", "sequential-printing_124589"); - line = { L("Extruder clearance"), "" }; - line.append_option(optgroup->get_option("extruder_clearance_radius")); - line.append_option(optgroup->get_option("extruder_clearance_height")); + + line = Line{ "", "" }; + line.full_width = 1; + line.widget = [this](wxWindow* parent) { + ogStaticText* stat_text; // Let the pointer die, we don't need it and the parent will free it. + wxSizer* sizer = description_line_widget(parent, &stat_text); + stat_text->SetText(from_u8("Note: When using this option, the Arrange function automatically " + "accounts for the printer geometry to prevent collisions. Extruder geometry is built-in for most " + "Prusa printers, the others use generic model defined by values in Printer Settings.")); + return sizer; + }; optgroup->append_line(line); + optgroup = page->new_optgroup(L("Output file")); optgroup->append_single_option_line("gcode_comments"); optgroup->append_single_option_line("gcode_label_objects"); @@ -2817,6 +2826,10 @@ void TabPrinter::build_fff() optgroup->append_single_option_line("variable_layer_height"); optgroup->append_single_option_line("prefer_clockwise_movements"); + optgroup = page->new_optgroup(L("Sequential printing limits")); + optgroup->append_single_option_line("extruder_clearance_radius"); + optgroup->append_single_option_line("extruder_clearance_height"); + const int gcode_field_height = 15; // 150 const int notes_field_height = 25; // 250 page = add_options_page(L("Custom G-code"), "cog"); diff --git a/tests/fff_print/test_cancel_object.cpp b/tests/fff_print/test_cancel_object.cpp index bd5ce8279a..8c2abb378d 100644 --- a/tests/fff_print/test_cancel_object.cpp +++ b/tests/fff_print/test_cancel_object.cpp @@ -170,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/slic3rutils/CMakeLists.txt b/tests/slic3rutils/CMakeLists.txt index ac025ce46c..83c320ec22 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)