From fbc174ad061a0c6dbbd2cc66455e4bd949517af3 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 14 Oct 2019 12:50:08 +0200 Subject: [PATCH 01/15] Fix cmake with msvc generator. * Remove unused libnest2d files. Make it use the global build script targets. * Modify FindTBB to address multi-config builds and take care of __TBB_NO_IMPLICIT_LINKAGE * Move FindNLopt to project common cmake module dir * Rename libnest.hpp to nester.hpp and libnest.h to libnest.hpp * Clean up common test suite build scripts --- CMakeLists.txt | 16 +- .../modules}/FindNLopt.cmake | 18 +- cmake/modules/FindTBB.cmake | 32 +- src/CMakeLists.txt | 1 - src/libnest2d/CMakeLists.txt | 129 +- .../cmake_modules/DownloadNLopt.cmake | 35 - .../DownloadProject.CMakeLists.cmake.in | 17 - .../cmake_modules/DownloadProject.cmake | 182 - src/libnest2d/cmake_modules/FindClipper.cmake | 58 - src/libnest2d/include/libnest2d.h | 134 - .../libnest2d/backends/clipper/CMakeLists.txt | 73 - .../include/libnest2d/geometry_traits_nfp.hpp | 451 ++- src/libnest2d/include/libnest2d/libnest2d.hpp | 949 +---- src/libnest2d/include/libnest2d/nester.hpp | 869 +++++ .../libnest2d/optimizers/nlopt/CMakeLists.txt | 61 - .../libnest2d/placers/placer_boilerplate.hpp | 2 +- .../selections/selection_boilerplate.hpp | 10 +- src/libnest2d/src/libnest2d.cpp | 15 +- src/libnest2d/tests/CMakeLists.txt | 60 - src/libnest2d/tests/printer_parts.cpp | 3175 ----------------- src/libnest2d/tests/printer_parts.h | 14 - src/libnest2d/tests/test.cpp | 1062 ------ src/libslic3r/CMakeLists.txt | 4 +- src/libslic3r/Time.cpp | 2 +- tests/CMakeLists.txt | 15 +- tests/example/CMakeLists.txt | 4 +- tests/libnest2d/CMakeLists.txt | 2 +- tests/libnest2d/libnest2d_tests_main.cpp | 46 +- tests/sla_print/CMakeLists.txt | 2 +- tests/timeutils/CMakeLists.txt | 8 +- 30 files changed, 1536 insertions(+), 5910 deletions(-) rename {src/libnest2d/cmake_modules => cmake/modules}/FindNLopt.cmake (92%) delete mode 100644 src/libnest2d/cmake_modules/DownloadNLopt.cmake delete mode 100644 src/libnest2d/cmake_modules/DownloadProject.CMakeLists.cmake.in delete mode 100644 src/libnest2d/cmake_modules/DownloadProject.cmake delete mode 100644 src/libnest2d/cmake_modules/FindClipper.cmake delete mode 100644 src/libnest2d/include/libnest2d.h delete mode 100644 src/libnest2d/include/libnest2d/backends/clipper/CMakeLists.txt create mode 100644 src/libnest2d/include/libnest2d/nester.hpp delete mode 100644 src/libnest2d/include/libnest2d/optimizers/nlopt/CMakeLists.txt delete mode 100644 src/libnest2d/tests/CMakeLists.txt delete mode 100644 src/libnest2d/tests/printer_parts.cpp delete mode 100644 src/libnest2d/tests/printer_parts.h delete mode 100644 src/libnest2d/tests/test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 93339eb0b..7b1d73f89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -291,14 +291,14 @@ if(SLIC3R_STATIC) endif() set(TBB_DEBUG 1) find_package(TBB REQUIRED) -include_directories(${TBB_INCLUDE_DIRS}) -add_definitions(${TBB_DEFINITIONS}) -if(MSVC) - # Suppress implicit linking of the TBB libraries by the Visual Studio compiler. - add_definitions(-D__TBB_NO_IMPLICIT_LINKAGE) -endif() +# include_directories(${TBB_INCLUDE_DIRS}) +# add_definitions(${TBB_DEFINITIONS}) +# if(MSVC) +# # Suppress implicit linking of the TBB libraries by the Visual Studio compiler. +# add_definitions(-D__TBB_NO_IMPLICIT_LINKAGE) +# endif() # The Intel TBB library will use the std::exception_ptr feature of C++11. -add_definitions(-DTBB_USE_CAPTURED_EXCEPTION=0) +# add_definitions(-DTBB_USE_CAPTURED_EXCEPTION=0) find_package(CURL REQUIRED) include_directories(${CURL_INCLUDE_DIRS}) @@ -375,6 +375,8 @@ add_custom_target(pot COMMENT "Generate pot file from strings in the source tree" ) +find_package(NLopt 1.4 REQUIRED) + # libslic3r, PrusaSlicer GUI and the PrusaSlicer executable. add_subdirectory(src) set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT PrusaSlicer_app_console) diff --git a/src/libnest2d/cmake_modules/FindNLopt.cmake b/cmake/modules/FindNLopt.cmake similarity index 92% rename from src/libnest2d/cmake_modules/FindNLopt.cmake rename to cmake/modules/FindNLopt.cmake index 2f813b6aa..912ce8d30 100644 --- a/src/libnest2d/cmake_modules/FindNLopt.cmake +++ b/cmake/modules/FindNLopt.cmake @@ -21,8 +21,7 @@ set(NLopt_FOUND FALSE) set(NLopt_ERROR_REASON "") set(NLopt_DEFINITIONS "") -set(NLopt_LIBS) - +unset(NLopt_LIBS CACHE) set(NLopt_DIR $ENV{NLOPT}) if(NOT NLopt_DIR) @@ -48,15 +47,14 @@ if(NOT NLopt_DIR) set(NLopt_ERROR_REASON "${NLopt_ERROR_REASON} Cannot find NLopt header file '${_NLopt_HEADER_FILE_NAME}'.") endif() unset(_NLopt_HEADER_FILE_NAME) - unset(_NLopt_HEADER_FILE) - + if(NOT NLopt_FOUND) set(NLopt_ERROR_REASON "${NLopt_ERROR_REASON} NLopt not found in system directories (and environment variable NLOPT is not set).") else() get_filename_component(NLopt_INCLUDE_DIR ${_NLopt_HEADER_FILE} DIRECTORY ) endif() - + unset(_NLopt_HEADER_FILE CACHE) else() @@ -95,7 +93,7 @@ else() set(NLopt_ERROR_REASON "${NLopt_ERROR_REASON} Cannot find NLopt header file '${_NLopt_HEADER_FILE_NAME}' in '${NLopt_INCLUDE_DIR}'.") endif() unset(_NLopt_HEADER_FILE_NAME) - unset(_NLopt_HEADER_FILE) + unset(_NLopt_HEADER_FILE CACHE) endif() @@ -114,10 +112,10 @@ if(NLopt_FOUND) message(STATUS "Found NLopt in '${NLopt_DIR}'.") message(STATUS "Using NLopt include directory '${NLopt_INCLUDE_DIR}'.") message(STATUS "Using NLopt library '${NLopt_LIBS}'.") - add_library(Nlopt::Nlopt INTERFACE IMPORTED) - set_target_properties(Nlopt::Nlopt PROPERTIES INTERFACE_LINK_LIBRARIES ${NLopt_LIBS}) - set_target_properties(Nlopt::Nlopt PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${NLopt_INCLUDE_DIR}) - set_target_properties(Nlopt::Nlopt PROPERTIES INTERFACE_COMPILE_DEFINITIONS "${NLopt_DEFINITIONS}") + add_library(NLopt::nlopt INTERFACE IMPORTED) + set_target_properties(NLopt::nlopt PROPERTIES INTERFACE_LINK_LIBRARIES ${NLopt_LIBS}) + set_target_properties(NLopt::nlopt PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${NLopt_INCLUDE_DIR}) + set_target_properties(NLopt::nlopt PROPERTIES INTERFACE_COMPILE_DEFINITIONS "${NLopt_DEFINITIONS}") # target_link_libraries(Nlopt::Nlopt INTERFACE ${NLopt_LIBS}) # target_include_directories(Nlopt::Nlopt INTERFACE ${NLopt_INCLUDE_DIR}) # target_compile_definitions(Nlopt::Nlopt INTERFACE ${NLopt_DEFINITIONS}) diff --git a/cmake/modules/FindTBB.cmake b/cmake/modules/FindTBB.cmake index e5115ab44..153e615eb 100644 --- a/cmake/modules/FindTBB.cmake +++ b/cmake/modules/FindTBB.cmake @@ -250,26 +250,23 @@ if(NOT TBB_FOUND) endif() endforeach() - unset(TBB_STATIC_SUFFIX) - ################################## # Set compile flags and libraries ################################## set(TBB_DEFINITIONS_RELEASE "") - set(TBB_DEFINITIONS_DEBUG "-DTBB_USE_DEBUG=1") + set(TBB_DEFINITIONS_DEBUG "TBB_USE_DEBUG=1") if(TBB_LIBRARIES_${TBB_BUILD_TYPE}) - set(TBB_DEFINITIONS "${TBB_DEFINITIONS_${TBB_BUILD_TYPE}}") set(TBB_LIBRARIES "${TBB_LIBRARIES_${TBB_BUILD_TYPE}}") - elseif(TBB_LIBRARIES_RELEASE) - set(TBB_DEFINITIONS "${TBB_DEFINITIONS_RELEASE}") - set(TBB_LIBRARIES "${TBB_LIBRARIES_RELEASE}") - elseif(TBB_LIBRARIES_DEBUG) - set(TBB_DEFINITIONS "${TBB_DEFINITIONS_DEBUG}") - set(TBB_LIBRARIES "${TBB_LIBRARIES_DEBUG}") endif() + if (MSVC AND TBB_STATIC) + set(TBB_DEFINITIONS __TBB_NO_IMPLICIT_LINKAGE) + endif () + + unset (TBB_STATIC_SUFFIX) + find_package_handle_standard_args(TBB REQUIRED_VARS TBB_INCLUDE_DIRS TBB_LIBRARIES HANDLE_COMPONENTS @@ -280,25 +277,18 @@ if(NOT TBB_FOUND) ################################## if(NOT CMAKE_VERSION VERSION_LESS 3.0 AND TBB_FOUND) - add_library(tbb UNKNOWN IMPORTED) - set_target_properties(tbb PROPERTIES + add_library(TBB::tbb UNKNOWN IMPORTED) + set_target_properties(TBB::tbb PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${TBB_INCLUDE_DIRS} IMPORTED_LOCATION ${TBB_LIBRARIES}) if(TBB_LIBRARIES_RELEASE AND TBB_LIBRARIES_DEBUG) - set_target_properties(tbb PROPERTIES - INTERFACE_COMPILE_DEFINITIONS "$<$,$>:TBB_USE_DEBUG=1>" + set_target_properties(TBB::tbb PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "${TBB_DEFINITIONS};$<$,$>:${TBB_DEFINITIONS_DEBUG}>;$<$:${TBB_DEFINITIONS_RELEASE}>" IMPORTED_LOCATION_DEBUG ${TBB_LIBRARIES_DEBUG} IMPORTED_LOCATION_RELWITHDEBINFO ${TBB_LIBRARIES_RELEASE} IMPORTED_LOCATION_RELEASE ${TBB_LIBRARIES_RELEASE} IMPORTED_LOCATION_MINSIZEREL ${TBB_LIBRARIES_RELEASE} ) - elseif(TBB_LIBRARIES_RELEASE) - set_target_properties(tbb PROPERTIES IMPORTED_LOCATION ${TBB_LIBRARIES_RELEASE}) - else() - set_target_properties(tbb PROPERTIES - INTERFACE_COMPILE_DEFINITIONS "${TBB_DEFINITIONS_DEBUG}" - IMPORTED_LOCATION ${TBB_LIBRARIES_DEBUG} - ) endif() endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 31cb24f24..1bf278722 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,7 +16,6 @@ add_subdirectory(semver) add_subdirectory(libigl) # Adding libnest2d project for bin packing... -set(LIBNEST2D_UNITTESTS ON CACHE BOOL "Force generating unittests for libnest2d") add_subdirectory(libnest2d) add_subdirectory(libslic3r) diff --git a/src/libnest2d/CMakeLists.txt b/src/libnest2d/CMakeLists.txt index 0d091c171..ea2910511 100644 --- a/src/libnest2d/CMakeLists.txt +++ b/src/libnest2d/CMakeLists.txt @@ -1,106 +1,31 @@ -cmake_minimum_required(VERSION 3.0) - -project(Libnest2D) - -if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) - # Update if necessary - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long ") -endif() - -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED) - -# Add our own cmake module path. -list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules/) - -option(LIBNEST2D_HEADER_ONLY "If enabled static library will not be built." ON) - -set(GEOMETRY_BACKENDS clipper boost eigen) -set(LIBNEST2D_GEOMETRIES clipper CACHE STRING "Geometry backend") -set_property(CACHE LIBNEST2D_GEOMETRIES PROPERTY STRINGS ${GEOMETRY_BACKENDS}) -list(FIND GEOMETRY_BACKENDS ${LIBNEST2D_GEOMETRIES} GEOMETRY_TYPE) -if(${GEOMETRY_TYPE} EQUAL -1) - message(FATAL_ERROR "Option ${LIBNEST2D_GEOMETRIES} not supported, valid entries are ${GEOMETRY_BACKENDS}") -endif() - -set(OPTIMIZERS nlopt optimlib) -set(LIBNEST2D_OPTIMIZER nlopt CACHE STRING "Optimization backend") -set_property(CACHE LIBNEST2D_OPTIMIZER PROPERTY STRINGS ${OPTIMIZERS}) -list(FIND OPTIMIZERS ${LIBNEST2D_OPTIMIZER} OPTIMIZER_TYPE) -if(${OPTIMIZER_TYPE} EQUAL -1) - message(FATAL_ERROR "Option ${LIBNEST2D_OPTIMIZER} not supported, valid entries are ${OPTIMIZERS}") -endif() - -add_library(libnest2d INTERFACE) - -set(SRC_DIR ${PROJECT_SOURCE_DIR}/include) - set(LIBNEST2D_SRCFILES - ${SRC_DIR}/libnest2d/libnest2d.hpp # Templates only - ${SRC_DIR}/libnest2d/geometry_traits.hpp - ${SRC_DIR}/libnest2d/geometry_traits_nfp.hpp - ${SRC_DIR}/libnest2d/common.hpp - ${SRC_DIR}/libnest2d/optimizer.hpp - ${SRC_DIR}/libnest2d/utils/metaloop.hpp - ${SRC_DIR}/libnest2d/utils/rotfinder.hpp - ${SRC_DIR}/libnest2d/utils/rotcalipers.hpp - ${SRC_DIR}/libnest2d/utils/bigint.hpp - ${SRC_DIR}/libnest2d/utils/rational.hpp - ${SRC_DIR}/libnest2d/placers/placer_boilerplate.hpp - ${SRC_DIR}/libnest2d/placers/bottomleftplacer.hpp - ${SRC_DIR}/libnest2d/placers/nfpplacer.hpp - ${SRC_DIR}/libnest2d/selections/selection_boilerplate.hpp - ${SRC_DIR}/libnest2d/selections/filler.hpp - ${SRC_DIR}/libnest2d/selections/firstfit.hpp - ${SRC_DIR}/libnest2d/selections/djd_heuristic.hpp + include/libnest2d/libnest2d.hpp + include/libnest2d/nester.hpp + include/libnest2d/geometry_traits.hpp + include/libnest2d/geometry_traits_nfp.hpp + include/libnest2d/common.hpp + include/libnest2d/optimizer.hpp + include/libnest2d/utils/metaloop.hpp + include/libnest2d/utils/rotfinder.hpp + include/libnest2d/utils/rotcalipers.hpp + include/libnest2d/placers/placer_boilerplate.hpp + include/libnest2d/placers/bottomleftplacer.hpp + include/libnest2d/placers/nfpplacer.hpp + include/libnest2d/selections/selection_boilerplate.hpp + #include/libnest2d/selections/filler.hpp + include/libnest2d/selections/firstfit.hpp + #include/libnest2d/selections/djd_heuristic.hpp + include/libnest2d/backends/clipper/geometries.hpp + include/libnest2d/backends/clipper/clipper_polygon.hpp + include/libnest2d/optimizers/nlopt/nlopt_boilerplate.hpp + include/libnest2d/optimizers/nlopt/simplex.hpp + include/libnest2d/optimizers/nlopt/subplex.hpp + include/libnest2d/optimizers/nlopt/genetic.hpp + src/libnest2d.cpp ) -set(TBB_STATIC ON) -find_package(TBB QUIET) -if(TBB_FOUND) - message(STATUS "Parallelization with Intel TBB") - target_include_directories(libnest2d INTERFACE ${TBB_INCLUDE_DIRS}) - target_compile_definitions(libnest2d INTERFACE ${TBB_DEFINITIONS} -DUSE_TBB) - if(MSVC) - # Suppress implicit linking of the TBB libraries by the Visual Studio compiler. - target_compile_definitions(libnest2d INTERFACE -D__TBB_NO_IMPLICIT_LINKAGE) - endif() - # The Intel TBB library will use the std::exception_ptr feature of C++11. - target_compile_definitions(libnest2d INTERFACE -DTBB_USE_CAPTURED_EXCEPTION=0) +add_library(libnest2d ${LIBNEST2D_SRCFILES}) - find_package(Threads REQUIRED) - target_link_libraries(libnest2d INTERFACE - tbb # VS debug mode needs linking this way: - # ${TBB_LIBRARIES} - ${CMAKE_DL_LIBS} - Threads::Threads - ) -else() - find_package(OpenMP QUIET) - - if(OpenMP_CXX_FOUND) - message(STATUS "Parallelization with OpenMP") - target_include_directories(libnest2d INTERFACE OpenMP::OpenMP_CXX) - target_link_libraries(libnest2d INTERFACE OpenMP::OpenMP_CXX) - else() - message("Parallelization with C++11 threads") - find_package(Threads REQUIRED) - target_link_libraries(libnest2d INTERFACE Threads::Threads) - endif() -endif() - -add_subdirectory(${SRC_DIR}/libnest2d/backends/${LIBNEST2D_GEOMETRIES}) -target_link_libraries(libnest2d INTERFACE ${LIBNEST2D_GEOMETRIES}Backend) - -add_subdirectory(${SRC_DIR}/libnest2d/optimizers/${LIBNEST2D_OPTIMIZER}) -target_link_libraries(libnest2d INTERFACE ${LIBNEST2D_OPTIMIZER}Optimizer) - -# target_sources(libnest2d INTERFACE ${LIBNEST2D_SRCFILES}) -target_include_directories(libnest2d INTERFACE ${SRC_DIR}) - -if(NOT LIBNEST2D_HEADER_ONLY) - set(LIBNAME libnest2d_${LIBNEST2D_GEOMETRIES}_${LIBNEST2D_OPTIMIZER}) - add_library(${LIBNAME} ${PROJECT_SOURCE_DIR}/src/libnest2d.cpp) - target_link_libraries(${LIBNAME} PUBLIC libnest2d) - target_compile_definitions(${LIBNAME} PUBLIC LIBNEST2D_STATIC) -endif() +target_include_directories(libnest2d PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) +target_link_libraries(libnest2d PUBLIC clipper NLopt::nlopt TBB::tbb Boost::boost) +target_compile_definitions(libnest2d PUBLIC LIBNEST2D_STATIC LIBNEST2D_OPTIMIZER_nlopt LIBNEST2D_GEOMETRIES_clipper) diff --git a/src/libnest2d/cmake_modules/DownloadNLopt.cmake b/src/libnest2d/cmake_modules/DownloadNLopt.cmake deleted file mode 100644 index 62b2b4c1a..000000000 --- a/src/libnest2d/cmake_modules/DownloadNLopt.cmake +++ /dev/null @@ -1,35 +0,0 @@ -include(DownloadProject) - -if (CMAKE_VERSION VERSION_LESS 3.2) - set(UPDATE_DISCONNECTED_IF_AVAILABLE "") -else() - set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1") -endif() - -set(URL_NLOPT "https://github.com/stevengj/nlopt.git" - CACHE STRING "Location of the nlopt git repository") - -# set(NLopt_DIR ${CMAKE_BINARY_DIR}/nlopt) -include(DownloadProject) -download_project( PROJ nlopt - GIT_REPOSITORY ${URL_NLOPT} - GIT_TAG v2.5.0 - # CMAKE_CACHE_ARGS -DBUILD_SHARED_LIBS:BOOL=OFF -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${NLopt_DIR} - ${UPDATE_DISCONNECTED_IF_AVAILABLE} -) - -set(SHARED_LIBS_STATE BUILD_SHARED_LIBS) -set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) -set(NLOPT_PYTHON OFF CACHE BOOL "" FORCE) -set(NLOPT_OCTAVE OFF CACHE BOOL "" FORCE) -set(NLOPT_MATLAB OFF CACHE BOOL "" FORCE) -set(NLOPT_GUILE OFF CACHE BOOL "" FORCE) -set(NLOPT_SWIG OFF CACHE BOOL "" FORCE) -set(NLOPT_LINK_PYTHON OFF CACHE BOOL "" FORCE) - -add_subdirectory(${nlopt_SOURCE_DIR} ${nlopt_BINARY_DIR}) - -set(NLopt_LIBS nlopt) -set(NLopt_INCLUDE_DIR ${nlopt_BINARY_DIR} - ${nlopt_BINARY_DIR}/src/api) -set(SHARED_LIBS_STATE ${SHARED_STATE}) \ No newline at end of file diff --git a/src/libnest2d/cmake_modules/DownloadProject.CMakeLists.cmake.in b/src/libnest2d/cmake_modules/DownloadProject.CMakeLists.cmake.in deleted file mode 100644 index d5cf3c1d9..000000000 --- a/src/libnest2d/cmake_modules/DownloadProject.CMakeLists.cmake.in +++ /dev/null @@ -1,17 +0,0 @@ -# Distributed under the OSI-approved MIT License. See accompanying -# file LICENSE or https://github.com/Crascit/DownloadProject for details. - -cmake_minimum_required(VERSION 2.8.2) - -project(${DL_ARGS_PROJ}-download NONE) - -include(ExternalProject) -ExternalProject_Add(${DL_ARGS_PROJ}-download - ${DL_ARGS_UNPARSED_ARGUMENTS} - SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" - BINARY_DIR "${DL_ARGS_BINARY_DIR}" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" -) \ No newline at end of file diff --git a/src/libnest2d/cmake_modules/DownloadProject.cmake b/src/libnest2d/cmake_modules/DownloadProject.cmake deleted file mode 100644 index 1709e09ad..000000000 --- a/src/libnest2d/cmake_modules/DownloadProject.cmake +++ /dev/null @@ -1,182 +0,0 @@ -# Distributed under the OSI-approved MIT License. See accompanying -# file LICENSE or https://github.com/Crascit/DownloadProject for details. -# -# MODULE: DownloadProject -# -# PROVIDES: -# download_project( PROJ projectName -# [PREFIX prefixDir] -# [DOWNLOAD_DIR downloadDir] -# [SOURCE_DIR srcDir] -# [BINARY_DIR binDir] -# [QUIET] -# ... -# ) -# -# Provides the ability to download and unpack a tarball, zip file, git repository, -# etc. at configure time (i.e. when the cmake command is run). How the downloaded -# and unpacked contents are used is up to the caller, but the motivating case is -# to download source code which can then be included directly in the build with -# add_subdirectory() after the call to download_project(). Source and build -# directories are set up with this in mind. -# -# The PROJ argument is required. The projectName value will be used to construct -# the following variables upon exit (obviously replace projectName with its actual -# value): -# -# projectName_SOURCE_DIR -# projectName_BINARY_DIR -# -# The SOURCE_DIR and BINARY_DIR arguments are optional and would not typically -# need to be provided. They can be specified if you want the downloaded source -# and build directories to be located in a specific place. The contents of -# projectName_SOURCE_DIR and projectName_BINARY_DIR will be populated with the -# locations used whether you provide SOURCE_DIR/BINARY_DIR or not. -# -# The DOWNLOAD_DIR argument does not normally need to be set. It controls the -# location of the temporary CMake build used to perform the download. -# -# The PREFIX argument can be provided to change the base location of the default -# values of DOWNLOAD_DIR, SOURCE_DIR and BINARY_DIR. If all of those three arguments -# are provided, then PREFIX will have no effect. The default value for PREFIX is -# CMAKE_BINARY_DIR. -# -# The QUIET option can be given if you do not want to show the output associated -# with downloading the specified project. -# -# In addition to the above, any other options are passed through unmodified to -# ExternalProject_Add() to perform the actual download, patch and update steps. -# The following ExternalProject_Add() options are explicitly prohibited (they -# are reserved for use by the download_project() command): -# -# CONFIGURE_COMMAND -# BUILD_COMMAND -# INSTALL_COMMAND -# TEST_COMMAND -# -# Only those ExternalProject_Add() arguments which relate to downloading, patching -# and updating of the project sources are intended to be used. Also note that at -# least one set of download-related arguments are required. -# -# If using CMake 3.2 or later, the UPDATE_DISCONNECTED option can be used to -# prevent a check at the remote end for changes every time CMake is run -# after the first successful download. See the documentation of the ExternalProject -# module for more information. It is likely you will want to use this option if it -# is available to you. Note, however, that the ExternalProject implementation contains -# bugs which result in incorrect handling of the UPDATE_DISCONNECTED option when -# using the URL download method or when specifying a SOURCE_DIR with no download -# method. Fixes for these have been created, the last of which is scheduled for -# inclusion in CMake 3.8.0. Details can be found here: -# -# https://gitlab.kitware.com/cmake/cmake/commit/bdca68388bd57f8302d3c1d83d691034b7ffa70c -# https://gitlab.kitware.com/cmake/cmake/issues/16428 -# -# If you experience build errors related to the update step, consider avoiding -# the use of UPDATE_DISCONNECTED. -# -# EXAMPLE USAGE: -# -# include(DownloadProject) -# download_project(PROJ googletest -# GIT_REPOSITORY https://github.com/google/googletest.git -# GIT_TAG master -# UPDATE_DISCONNECTED 1 -# QUIET -# ) -# -# add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR}) -# -#======================================================================================== - - -set(_DownloadProjectDir "${CMAKE_CURRENT_LIST_DIR}") - -include(CMakeParseArguments) - -function(download_project) - - set(options QUIET) - set(oneValueArgs - PROJ - PREFIX - DOWNLOAD_DIR - SOURCE_DIR - BINARY_DIR - # Prevent the following from being passed through - CONFIGURE_COMMAND - BUILD_COMMAND - INSTALL_COMMAND - TEST_COMMAND - ) - set(multiValueArgs "") - - cmake_parse_arguments(DL_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - # Hide output if requested - if (DL_ARGS_QUIET) - set(OUTPUT_QUIET "OUTPUT_QUIET") - else() - unset(OUTPUT_QUIET) - message(STATUS "Downloading/updating ${DL_ARGS_PROJ}") - endif() - - # Set up where we will put our temporary CMakeLists.txt file and also - # the base point below which the default source and binary dirs will be. - # The prefix must always be an absolute path. - if (NOT DL_ARGS_PREFIX) - set(DL_ARGS_PREFIX "${CMAKE_BINARY_DIR}") - else() - get_filename_component(DL_ARGS_PREFIX "${DL_ARGS_PREFIX}" ABSOLUTE - BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") - endif() - if (NOT DL_ARGS_DOWNLOAD_DIR) - set(DL_ARGS_DOWNLOAD_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-download") - endif() - - # Ensure the caller can know where to find the source and build directories - if (NOT DL_ARGS_SOURCE_DIR) - set(DL_ARGS_SOURCE_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-src") - endif() - if (NOT DL_ARGS_BINARY_DIR) - set(DL_ARGS_BINARY_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-build") - endif() - set(${DL_ARGS_PROJ}_SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" PARENT_SCOPE) - set(${DL_ARGS_PROJ}_BINARY_DIR "${DL_ARGS_BINARY_DIR}" PARENT_SCOPE) - - # The way that CLion manages multiple configurations, it causes a copy of - # the CMakeCache.txt to be copied across due to it not expecting there to - # be a project within a project. This causes the hard-coded paths in the - # cache to be copied and builds to fail. To mitigate this, we simply - # remove the cache if it exists before we configure the new project. It - # is safe to do so because it will be re-generated. Since this is only - # executed at the configure step, it should not cause additional builds or - # downloads. - file(REMOVE "${DL_ARGS_DOWNLOAD_DIR}/CMakeCache.txt") - - # Create and build a separate CMake project to carry out the download. - # If we've already previously done these steps, they will not cause - # anything to be updated, so extra rebuilds of the project won't occur. - # Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project - # has this set to something not findable on the PATH. - configure_file("${_DownloadProjectDir}/DownloadProject.CMakeLists.cmake.in" - "${DL_ARGS_DOWNLOAD_DIR}/CMakeLists.txt") - execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" - -D "CMAKE_MAKE_PROGRAM:FILE=${CMAKE_MAKE_PROGRAM}" - . - RESULT_VARIABLE result - ${OUTPUT_QUIET} - WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" - ) - if(result) - message(FATAL_ERROR "CMake step for ${DL_ARGS_PROJ} failed: ${result}") - endif() - execute_process(COMMAND ${CMAKE_COMMAND} --build . - RESULT_VARIABLE result - ${OUTPUT_QUIET} - WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" - ) - if(result) - message(FATAL_ERROR "Build step for ${DL_ARGS_PROJ} failed: ${result}") - endif() - -endfunction() \ No newline at end of file diff --git a/src/libnest2d/cmake_modules/FindClipper.cmake b/src/libnest2d/cmake_modules/FindClipper.cmake deleted file mode 100644 index 01b6b99d5..000000000 --- a/src/libnest2d/cmake_modules/FindClipper.cmake +++ /dev/null @@ -1,58 +0,0 @@ -# Find Clipper library (http://www.angusj.com/delphi/clipper.php). -# The following variables are set -# -# CLIPPER_FOUND -# CLIPPER_INCLUDE_DIRS -# CLIPPER_LIBRARIES -# -# It searches the environment variable $CLIPPER_PATH automatically. - -FIND_PATH(CLIPPER_INCLUDE_DIRS clipper.hpp - $ENV{CLIPPER_PATH} - $ENV{CLIPPER_PATH}/cpp/ - $ENV{CLIPPER_PATH}/include/ - $ENV{CLIPPER_PATH}/include/polyclipping/ - ${PROJECT_SOURCE_DIR}/python/pymesh/third_party/include/ - ${PROJECT_SOURCE_DIR}/python/pymesh/third_party/include/polyclipping/ - ${CMAKE_PREFIX_PATH}/include/polyclipping - ${CMAKE_PREFIX_PATH}/include/ - /opt/local/include/ - /opt/local/include/polyclipping/ - /usr/local/include/ - /usr/local/include/polyclipping/ - /usr/include - /usr/include/polyclipping/) - -FIND_LIBRARY(CLIPPER_LIBRARIES polyclipping - $ENV{CLIPPER_PATH} - $ENV{CLIPPER_PATH}/cpp/ - $ENV{CLIPPER_PATH}/cpp/build/ - $ENV{CLIPPER_PATH}/lib/ - $ENV{CLIPPER_PATH}/lib/polyclipping/ - ${PROJECT_SOURCE_DIR}/python/pymesh/third_party/lib/ - ${PROJECT_SOURCE_DIR}/python/pymesh/third_party/lib/polyclipping/ - ${CMAKE_PREFIX_PATH}/lib/ - ${CMAKE_PREFIX_PATH}/lib/polyclipping/ - /opt/local/lib/ - /opt/local/lib/polyclipping/ - /usr/local/lib/ - /usr/local/lib/polyclipping/ - /usr/lib/polyclipping) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Clipper - "Clipper library cannot be found. Consider set CLIPPER_PATH environment variable" - CLIPPER_INCLUDE_DIRS - CLIPPER_LIBRARIES) - -MARK_AS_ADVANCED( - CLIPPER_INCLUDE_DIRS - CLIPPER_LIBRARIES) - -if(CLIPPER_FOUND) - add_library(Clipper::Clipper INTERFACE IMPORTED) - set_target_properties(Clipper::Clipper PROPERTIES INTERFACE_LINK_LIBRARIES ${CLIPPER_LIBRARIES}) - set_target_properties(Clipper::Clipper PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CLIPPER_INCLUDE_DIRS}) - #target_link_libraries(Clipper::Clipper INTERFACE ${CLIPPER_LIBRARIES}) - #target_include_directories(Clipper::Clipper INTERFACE ${CLIPPER_INCLUDE_DIRS}) -endif() diff --git a/src/libnest2d/include/libnest2d.h b/src/libnest2d/include/libnest2d.h deleted file mode 100644 index 76b133f4b..000000000 --- a/src/libnest2d/include/libnest2d.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef LIBNEST2D_H -#define LIBNEST2D_H - -// The type of backend should be set conditionally by the cmake configuriation -// for now we set it statically to clipper backend -#ifdef LIBNEST2D_BACKEND_CLIPPER -#include -#endif - -#ifdef LIBNEST2D_OPTIMIZER_NLOPT -// We include the stock optimizers for local and global optimization -#include // Local subplex for NfpPlacer -#include // Genetic for min. bounding box -#endif - -#include -#include -#include -#include -#include -#include - -namespace libnest2d { - -using Point = PointImpl; -using Coord = TCoord; -using Box = _Box; -using Segment = _Segment; -using Circle = _Circle; - -using Item = _Item; -using Rectangle = _Rectangle; -using PackGroup = _PackGroup; - -using FillerSelection = selections::_FillerSelection; -using FirstFitSelection = selections::_FirstFitSelection; -using DJDHeuristic = selections::_DJDHeuristic; - -template // Generic placer for arbitrary bin types -using _NfpPlacer = placers::_NofitPolyPlacer; - -// NfpPlacer is with Box bin -using NfpPlacer = _NfpPlacer; - -// This supports only box shaped bins -using BottomLeftPlacer = placers::_BottomLeftPlacer; - -#ifdef LIBNEST2D_STATIC - -extern template class Nester; -extern template class Nester; -extern template std::size_t Nester::execute( - std::vector::iterator, std::vector::iterator); -extern template std::size_t Nester::execute( - std::vector::iterator, std::vector::iterator); - -#endif - -template -struct NestConfig { - typename Placer::Config placer_config; - typename Selector::Config selector_config; - using Placement = typename Placer::Config; - using Selection = typename Selector::Config; - - NestConfig() = default; - NestConfig(const typename Placer::Config &cfg) : placer_config{cfg} {} - NestConfig(const typename Selector::Config &cfg) : selector_config{cfg} {} - NestConfig(const typename Placer::Config & pcfg, - const typename Selector::Config &scfg) - : placer_config{pcfg}, selector_config{scfg} {} -}; - -struct NestControl { - ProgressFunction progressfn; - StopCondition stopcond = []{ return false; }; - - NestControl() = default; - NestControl(ProgressFunction pr) : progressfn{std::move(pr)} {} - NestControl(StopCondition sc) : stopcond{std::move(sc)} {} - NestControl(ProgressFunction pr, StopCondition sc) - : progressfn{std::move(pr)}, stopcond{std::move(sc)} - {} -}; - -template::iterator> -std::size_t nest(Iterator from, Iterator to, - const typename Placer::BinType & bin, - Coord dist = 0, - const NestConfig &cfg = {}, - NestControl ctl = {}) -{ - _Nester nester{bin, dist, cfg.placer_config, cfg.selector_config}; - if(ctl.progressfn) nester.progressIndicator(ctl.progressfn); - if(ctl.stopcond) nester.stopCondition(ctl.stopcond); - return nester.execute(from, to); -} - -#ifdef LIBNEST2D_STATIC - -extern template class Nester; -extern template class Nester; -extern template std::size_t nest(std::vector::iterator from, - std::vector::iterator from to, - const Box & bin, - Coord dist, - const NestConfig &cfg, - NestControl ctl); -extern template std::size_t nest(std::vector::iterator from, - std::vector::iterator from to, - const Box & bin, - Coord dist, - const NestConfig &cfg, - NestControl ctl); - -#endif - -template> -std::size_t nest(Container&& cont, - const typename Placer::BinType & bin, - Coord dist = 0, - const NestConfig &cfg = {}, - NestControl ctl = {}) -{ - return nest(cont.begin(), cont.end(), bin, dist, cfg, ctl); -} - -} - -#endif // LIBNEST2D_H diff --git a/src/libnest2d/include/libnest2d/backends/clipper/CMakeLists.txt b/src/libnest2d/include/libnest2d/backends/clipper/CMakeLists.txt deleted file mode 100644 index 202089356..000000000 --- a/src/libnest2d/include/libnest2d/backends/clipper/CMakeLists.txt +++ /dev/null @@ -1,73 +0,0 @@ -if(NOT TARGET clipper) # If there is a clipper target in the parent project we are good to go. - - find_package(Clipper 6.1) - - if(NOT CLIPPER_FOUND) - find_package(Subversion QUIET) - if(Subversion_FOUND) - - set(URL_CLIPPER "https://svn.code.sf.net/p/polyclipping/code/trunk/cpp" - CACHE STRING "Clipper source code repository location.") - - message(STATUS "Clipper not found so it will be downloaded.") - # Silently download and build the library in the build dir - - if (CMAKE_VERSION VERSION_LESS 3.2) - set(UPDATE_DISCONNECTED_IF_AVAILABLE "") - else() - set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1") - endif() - - include(DownloadProject) - download_project( PROJ clipper_library - SVN_REPOSITORY ${URL_CLIPPER} - SVN_REVISION -r540 - #SOURCE_SUBDIR cpp - INSTALL_COMMAND "" - CONFIGURE_COMMAND "" # Not working, I will just add the source files - ${UPDATE_DISCONNECTED_IF_AVAILABLE} - ) - - # This is not working and I dont have time to fix it - # add_subdirectory(${clipper_library_SOURCE_DIR}/cpp - # ${clipper_library_BINARY_DIR} - # ) - - add_library(clipperBackend STATIC - ${clipper_library_SOURCE_DIR}/clipper.cpp - ${clipper_library_SOURCE_DIR}/clipper.hpp) - - target_include_directories(clipperBackend INTERFACE ${clipper_library_SOURCE_DIR}) - else() - message(FATAL_ERROR "Can't find clipper library and no SVN client found to download. - You can download the clipper sources and define a clipper target in your project, that will work for libnest2d.") - endif() - else() - add_library(clipperBackend INTERFACE) - target_link_libraries(clipperBackend INTERFACE Clipper::Clipper) - endif() -else() - # set(CLIPPER_INCLUDE_DIRS "" PARENT_SCOPE) - # set(CLIPPER_LIBRARIES clipper PARENT_SCOPE) - add_library(clipperBackend INTERFACE) - target_link_libraries(clipperBackend INTERFACE clipper) -endif() - -# Clipper backend is not enough on its own, it still needs some functions -# from Boost geometry -if(NOT Boost_FOUND) - find_package(Boost 1.58 REQUIRED) - # TODO automatic download of boost geometry headers -endif() - -target_link_libraries(clipperBackend INTERFACE Boost::boost ) -#target_sources(ClipperBackend INTERFACE -# ${CMAKE_CURRENT_SOURCE_DIR}/geometries.hpp -# ${CMAKE_CURRENT_SOURCE_DIR}/clipper_polygon.hpp -# ${SRC_DIR}/libnest2d/utils/boost_alg.hpp ) - -target_compile_definitions(clipperBackend INTERFACE LIBNEST2D_BACKEND_CLIPPER) - -# And finally plug the clipperBackend into libnest2d -# target_link_libraries(libnest2d INTERFACE clipperBackend) - diff --git a/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp b/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp index 4a2c69bca..29a1ccd04 100644 --- a/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp +++ b/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp @@ -299,9 +299,456 @@ inline NfpResult nfpConvexOnly(const RawShape& sh, template NfpResult nfpSimpleSimple(const RawShape& cstationary, - const RawShape& cother) + const RawShape& cother) { - return {}; + + // Algorithms are from the original algorithm proposed in paper: + // https://eprints.soton.ac.uk/36850/1/CORMSIS-05-05.pdf + + // ///////////////////////////////////////////////////////////////////////// + // Algorithm 1: Obtaining the minkowski sum + // ///////////////////////////////////////////////////////////////////////// + + // I guess this is not a full minkowski sum of the two input polygons by + // definition. This yields a subset that is compatible with the next 2 + // algorithms. + + using Result = NfpResult; + using Vertex = TPoint; + using Coord = TCoord; + using Edge = _Segment; + namespace sl = shapelike; + using std::signbit; + using std::sort; + using std::vector; + using std::ref; + using std::reference_wrapper; + + // TODO The original algorithms expects the stationary polygon in + // counter clockwise and the orbiter in clockwise order. + // So for preventing any further complication, I will make the input + // the way it should be, than make my way around the orientations. + + // Reverse the stationary contour to counter clockwise + auto stcont = sl::contour(cstationary); + { + std::reverse(sl::begin(stcont), sl::end(stcont)); + stcont.pop_back(); + auto it = std::min_element(sl::begin(stcont), sl::end(stcont), + [](const Vertex& v1, const Vertex& v2) { + return getY(v1) < getY(v2); + }); + std::rotate(sl::begin(stcont), it, sl::end(stcont)); + sl::addVertex(stcont, sl::front(stcont)); + } + RawShape stationary; + sl::contour(stationary) = stcont; + + // Reverse the orbiter contour to counter clockwise + auto orbcont = sl::contour(cother); + { + std::reverse(orbcont.begin(), orbcont.end()); + + // Step 1: Make the orbiter reverse oriented + + orbcont.pop_back(); + auto it = std::min_element(orbcont.begin(), orbcont.end(), + [](const Vertex& v1, const Vertex& v2) { + return getY(v1) < getY(v2); + }); + + std::rotate(orbcont.begin(), it, orbcont.end()); + orbcont.emplace_back(orbcont.front()); + + for(auto &v : orbcont) v = -v; + + } + + // Copy the orbiter (contour only), we will have to work on it + RawShape orbiter; + sl::contour(orbiter) = orbcont; + + // An edge with additional data for marking it + struct MarkedEdge { + Edge e; Radians turn_angle = 0; bool is_turning_point = false; + MarkedEdge() = default; + MarkedEdge(const Edge& ed, Radians ta, bool tp): + e(ed), turn_angle(ta), is_turning_point(tp) {} + + // debug + std::string label; + }; + + // Container for marked edges + using EdgeList = vector; + + EdgeList A, B; + + // This is how an edge list is created from the polygons + auto fillEdgeList = [](EdgeList& L, const RawShape& ppoly, int dir) { + auto& poly = sl::contour(ppoly); + + L.reserve(sl::contourVertexCount(poly)); + + if(dir > 0) { + auto it = poly.begin(); + auto nextit = std::next(it); + + double turn_angle = 0; + bool is_turn_point = false; + + while(nextit != poly.end()) { + L.emplace_back(Edge(*it, *nextit), turn_angle, is_turn_point); + it++; nextit++; + } + } else { + auto it = sl::rbegin(poly); + auto nextit = std::next(it); + + double turn_angle = 0; + bool is_turn_point = false; + + while(nextit != sl::rend(poly)) { + L.emplace_back(Edge(*it, *nextit), turn_angle, is_turn_point); + it++; nextit++; + } + } + + auto getTurnAngle = [](const Edge& e1, const Edge& e2) { + auto phi = e1.angleToXaxis(); + auto phi_prev = e2.angleToXaxis(); + auto turn_angle = phi-phi_prev; + if(turn_angle > Pi) turn_angle -= TwoPi; + if(turn_angle < -Pi) turn_angle += TwoPi; + return turn_angle; + }; + + auto eit = L.begin(); + auto enext = std::next(eit); + + eit->turn_angle = getTurnAngle(L.front().e, L.back().e); + + while(enext != L.end()) { + enext->turn_angle = getTurnAngle( enext->e, eit->e); + eit->is_turning_point = + signbit(enext->turn_angle) != signbit(eit->turn_angle); + ++eit; ++enext; + } + + L.back().is_turning_point = signbit(L.back().turn_angle) != + signbit(L.front().turn_angle); + + }; + + // Step 2: Fill the edgelists + fillEdgeList(A, stationary, 1); + fillEdgeList(B, orbiter, 1); + + int i = 1; + for(MarkedEdge& me : A) { + std::cout << "a" << i << ":\n\t" + << getX(me.e.first()) << " " << getY(me.e.first()) << "\n\t" + << getX(me.e.second()) << " " << getY(me.e.second()) << "\n\t" + << "Turning point: " << (me.is_turning_point ? "yes" : "no") + << std::endl; + + me.label = "a"; me.label += std::to_string(i); + i++; + } + + i = 1; + for(MarkedEdge& me : B) { + std::cout << "b" << i << ":\n\t" + << getX(me.e.first()) << " " << getY(me.e.first()) << "\n\t" + << getX(me.e.second()) << " " << getY(me.e.second()) << "\n\t" + << "Turning point: " << (me.is_turning_point ? "yes" : "no") + << std::endl; + me.label = "b"; me.label += std::to_string(i); + i++; + } + + // A reference to a marked edge that also knows its container + struct MarkedEdgeRef { + reference_wrapper eref; + reference_wrapper> container; + Coord dir = 1; // Direction modifier + + inline Radians angleX() const { return eref.get().e.angleToXaxis(); } + inline const Edge& edge() const { return eref.get().e; } + inline Edge& edge() { return eref.get().e; } + inline bool isTurningPoint() const { + return eref.get().is_turning_point; + } + inline bool isFrom(const vector& cont ) { + return &(container.get()) == &cont; + } + inline bool eq(const MarkedEdgeRef& mr) { + return &(eref.get()) == &(mr.eref.get()); + } + + MarkedEdgeRef(reference_wrapper er, + reference_wrapper> ec): + eref(er), container(ec), dir(1) {} + + MarkedEdgeRef(reference_wrapper er, + reference_wrapper> ec, + Coord d): + eref(er), container(ec), dir(d) {} + }; + + using EdgeRefList = vector; + + // Comparing two marked edges + auto sortfn = [](const MarkedEdgeRef& e1, const MarkedEdgeRef& e2) { + return e1.angleX() < e2.angleX(); + }; + + EdgeRefList Aref, Bref; // We create containers for the references + Aref.reserve(A.size()); Bref.reserve(B.size()); + + // Fill reference container for the stationary polygon + std::for_each(A.begin(), A.end(), [&Aref](MarkedEdge& me) { + Aref.emplace_back( ref(me), ref(Aref) ); + }); + + // Fill reference container for the orbiting polygon + std::for_each(B.begin(), B.end(), [&Bref](MarkedEdge& me) { + Bref.emplace_back( ref(me), ref(Bref) ); + }); + + auto mink = [sortfn] // the Mink(Q, R, direction) sub-procedure + (const EdgeRefList& Q, const EdgeRefList& R, bool positive) + { + + // Step 1 "merge sort_list(Q) and sort_list(R) to form merge_list(Q,R)" + // Sort the containers of edge references and merge them. + // Q could be sorted only once and be reused here but we would still + // need to merge it with sorted(R). + + EdgeRefList merged; + EdgeRefList S, seq; + merged.reserve(Q.size() + R.size()); + + merged.insert(merged.end(), R.begin(), R.end()); + std::stable_sort(merged.begin(), merged.end(), sortfn); + merged.insert(merged.end(), Q.begin(), Q.end()); + std::stable_sort(merged.begin(), merged.end(), sortfn); + + // Step 2 "set i = 1, k = 1, direction = 1, s1 = q1" + // we don't use i, instead, q is an iterator into Q. k would be an index + // into the merged sequence but we use "it" as an iterator for that + + // here we obtain references for the containers for later comparisons + const auto& Rcont = R.begin()->container.get(); + const auto& Qcont = Q.begin()->container.get(); + + // Set the initial direction + Coord dir = 1; + + // roughly i = 1 (so q = Q.begin()) and s1 = q1 so S[0] = q; + if(positive) { + auto q = Q.begin(); + S.emplace_back(*q); + + // Roughly step 3 + + std::cout << "merged size: " << merged.size() << std::endl; + auto mit = merged.begin(); + for(bool finish = false; !finish && q != Q.end();) { + ++q; // "Set i = i + 1" + + while(!finish && mit != merged.end()) { + if(mit->isFrom(Rcont)) { + auto s = *mit; + s.dir = dir; + S.emplace_back(s); + } + + if(mit->eq(*q)) { + S.emplace_back(*q); + if(mit->isTurningPoint()) dir = -dir; + if(q == Q.begin()) finish = true; + break; + } + + mit += dir; + // __nfp::advance(mit, merged, dir > 0); + } + } + } else { + auto q = Q.rbegin(); + S.emplace_back(*q); + + // Roughly step 3 + + std::cout << "merged size: " << merged.size() << std::endl; + auto mit = merged.begin(); + for(bool finish = false; !finish && q != Q.rend();) { + ++q; // "Set i = i + 1" + + while(!finish && mit != merged.end()) { + if(mit->isFrom(Rcont)) { + auto s = *mit; + s.dir = dir; + S.emplace_back(s); + } + + if(mit->eq(*q)) { + S.emplace_back(*q); + S.back().dir = -1; + if(mit->isTurningPoint()) dir = -dir; + if(q == Q.rbegin()) finish = true; + break; + } + + mit += dir; + // __nfp::advance(mit, merged, dir > 0); + } + } + } + + + // Step 4: + + // "Let starting edge r1 be in position si in sequence" + // whaaat? I guess this means the following: + auto it = S.begin(); + while(!it->eq(*R.begin())) ++it; + + // "Set j = 1, next = 2, direction = 1, seq1 = si" + // we don't use j, seq is expanded dynamically. + dir = 1; + auto next = std::next(R.begin()); seq.emplace_back(*it); + + // Step 5: + // "If all si edges have been allocated to seqj" should mean that + // we loop until seq has equal size with S + auto send = it; //it == S.begin() ? it : std::prev(it); + while(it != S.end()) { + ++it; if(it == S.end()) it = S.begin(); + if(it == send) break; + + if(it->isFrom(Qcont)) { + seq.emplace_back(*it); // "If si is from Q, j = j + 1, seqj = si" + + // "If si is a turning point in Q, + // direction = - direction, next = next + direction" + if(it->isTurningPoint()) { + dir = -dir; + next += dir; +// __nfp::advance(next, R, dir > 0); + } + } + + if(it->eq(*next) /*&& dir == next->dir*/) { // "If si = direction.rnext" + // "j = j + 1, seqj = si, next = next + direction" + seq.emplace_back(*it); + next += dir; +// __nfp::advance(next, R, dir > 0); + } + } + + return seq; + }; + + std::vector seqlist; + seqlist.reserve(Bref.size()); + + EdgeRefList Bslope = Bref; // copy Bref, we will make a slope diagram + + // make the slope diagram of B + std::sort(Bslope.begin(), Bslope.end(), sortfn); + + auto slopeit = Bslope.begin(); // search for the first turning point + while(!slopeit->isTurningPoint() && slopeit != Bslope.end()) slopeit++; + + if(slopeit == Bslope.end()) { + // no turning point means convex polygon. + seqlist.emplace_back(mink(Aref, Bref, true)); + } else { + int dir = 1; + + auto firstturn = Bref.begin(); + while(!firstturn->eq(*slopeit)) ++firstturn; + + assert(firstturn != Bref.end()); + + EdgeRefList bgroup; bgroup.reserve(Bref.size()); + bgroup.emplace_back(*slopeit); + + auto b_it = std::next(firstturn); + while(b_it != firstturn) { + if(b_it == Bref.end()) b_it = Bref.begin(); + + while(!slopeit->eq(*b_it)) { + __nfp::advance(slopeit, Bslope, dir > 0); + } + + if(!slopeit->isTurningPoint()) { + bgroup.emplace_back(*slopeit); + } else { + if(!bgroup.empty()) { + if(dir > 0) bgroup.emplace_back(*slopeit); + for(auto& me : bgroup) { + std::cout << me.eref.get().label << ", "; + } + std::cout << std::endl; + seqlist.emplace_back(mink(Aref, bgroup, dir == 1 ? true : false)); + bgroup.clear(); + if(dir < 0) bgroup.emplace_back(*slopeit); + } else { + bgroup.emplace_back(*slopeit); + } + + dir *= -1; + } + ++b_it; + } + } + +// while(it != Bref.end()) // This is step 3 and step 4 in one loop +// if(it->isTurningPoint()) { +// R = {R.last, it++}; +// auto seq = mink(Q, R, orientation); + +// // TODO step 6 (should be 5 shouldn't it?): linking edges from A +// // I don't get this step + +// seqlist.insert(seqlist.end(), seq.begin(), seq.end()); +// orientation = !orientation; +// } else ++it; + +// if(seqlist.empty()) seqlist = mink(Q, {Bref.begin(), Bref.end()}, true); + + // ///////////////////////////////////////////////////////////////////////// + // Algorithm 2: breaking Minkowski sums into track line trips + // ///////////////////////////////////////////////////////////////////////// + + + // ///////////////////////////////////////////////////////////////////////// + // Algorithm 3: finding the boundary of the NFP from track line trips + // ///////////////////////////////////////////////////////////////////////// + + + for(auto& seq : seqlist) { + std::cout << "seqlist size: " << seq.size() << std::endl; + for(auto& s : seq) { + std::cout << (s.dir > 0 ? "" : "-") << s.eref.get().label << ", "; + } + std::cout << std::endl; + } + + auto& seq = seqlist.front(); + RawShape rsh; + Vertex top_nfp; + std::vector edgelist; edgelist.reserve(seq.size()); + for(auto& s : seq) { + edgelist.emplace_back(s.eref.get().e); + } + + __nfp::buildPolygon(edgelist, rsh, top_nfp); + + return Result(rsh, top_nfp); } // Specializable NFP implementation class. Specialize it if you have a faster diff --git a/src/libnest2d/include/libnest2d/libnest2d.hpp b/src/libnest2d/include/libnest2d/libnest2d.hpp index 91c98c62a..b6d7fcdcf 100644 --- a/src/libnest2d/include/libnest2d/libnest2d.hpp +++ b/src/libnest2d/include/libnest2d/libnest2d.hpp @@ -1,869 +1,134 @@ #ifndef LIBNEST2D_HPP #define LIBNEST2D_HPP -#include -#include -#include -#include -#include -#include +// The type of backend should be set conditionally by the cmake configuriation +// for now we set it statically to clipper backend +#ifdef LIBNEST2D_GEOMETRIES_clipper +#include +#endif -#include +#ifdef LIBNEST2D_OPTIMIZER_nlopt +// We include the stock optimizers for local and global optimization +#include // Local subplex for NfpPlacer +#include // Genetic for min. bounding box +#endif + +#include +#include +#include +#include +#include +#include namespace libnest2d { -static const constexpr int BIN_ID_UNSET = -1; +using Point = PointImpl; +using Coord = TCoord; +using Box = _Box; +using Segment = _Segment; +using Circle = _Circle; -/** - * \brief An item to be placed on a bin. - * - * It holds a copy of the original shape object but supports move construction - * from the shape objects if its an rvalue reference. This way we can construct - * the items without the cost of copying a potentially large amount of input. - * - * The results of some calculations are cached for maintaining fast run times. - * For this reason, memory demands are much higher but this should pay off. - */ -template -class _Item { - using Coord = TCoord>; - using Vertex = TPoint; - using Box = _Box; +using Item = _Item; +using Rectangle = _Rectangle; +using PackGroup = _PackGroup; - using VertexConstIterator = typename TContour::const_iterator; +using FillerSelection = selections::_FillerSelection; +using FirstFitSelection = selections::_FirstFitSelection; +using DJDHeuristic = selections::_DJDHeuristic; - // The original shape that gets encapsulated. - RawShape sh_; +template // Generic placer for arbitrary bin types +using _NfpPlacer = placers::_NofitPolyPlacer; - // Transformation data - Vertex translation_{0, 0}; - Radians rotation_{0.0}; - Coord inflation_{0}; +// NfpPlacer is with Box bin +using NfpPlacer = _NfpPlacer; - // Info about whether the transformations will have to take place - // This is needed because if floating point is used, it is hard to say - // that a zero angle is not a rotation because of testing for equality. - bool has_rotation_ = false, has_translation_ = false, has_inflation_ = false; +// This supports only box shaped bins +using BottomLeftPlacer = placers::_BottomLeftPlacer; - // For caching the calculations as they can get pretty expensive. - mutable RawShape tr_cache_; - mutable bool tr_cache_valid_ = false; - mutable double area_cache_ = 0; - mutable bool area_cache_valid_ = false; - mutable RawShape inflate_cache_; - mutable bool inflate_cache_valid_ = false; +#ifdef LIBNEST2D_STATIC - enum class Convexity: char { - UNCHECKED, - C_TRUE, - C_FALSE - }; +extern template class _Nester; +extern template class _Nester; +extern template std::size_t _Nester::execute( + std::vector::iterator, std::vector::iterator); +extern template std::size_t _Nester::execute( + std::vector::iterator, std::vector::iterator); - mutable Convexity convexity_ = Convexity::UNCHECKED; - mutable VertexConstIterator rmt_; // rightmost top vertex - mutable VertexConstIterator lmb_; // leftmost bottom vertex - mutable bool rmt_valid_ = false, lmb_valid_ = false; - mutable struct BBCache { - Box bb; bool valid; - BBCache(): valid(false) {} - } bb_cache_; +#endif + +template +struct NestConfig { + typename Placer::Config placer_config; + typename Selector::Config selector_config; + using Placement = typename Placer::Config; + using Selection = typename Selector::Config; - int binid_{BIN_ID_UNSET}, priority_{0}; - bool fixed_{false}; - -public: - - /// The type of the shape which was handed over as the template argument. - using ShapeType = RawShape; - - /** - * \brief Iterator type for the outer vertices. - * - * Only const iterators can be used. The _Item type is not intended to - * modify the carried shapes from the outside. The main purpose of this type - * is to cache the calculation results from the various operators it - * supports. Giving out a non const iterator would make it impossible to - * perform correct cache invalidation. - */ - using Iterator = VertexConstIterator; - - /** - * @brief Get the orientation of the polygon. - * - * The orientation have to be specified as a specialization of the - * OrientationType struct which has a Value constant. - * - * @return The orientation type identifier for the _Item type. - */ - static BP2D_CONSTEXPR Orientation orientation() { - return OrientationType::Value; - } - - /** - * @brief Constructing an _Item form an existing raw shape. The shape will - * be copied into the _Item object. - * @param sh The original shape object. - */ - explicit inline _Item(const RawShape& sh): sh_(sh) {} - - /** - * @brief Construction of an item by moving the content of the raw shape, - * assuming that it supports move semantics. - * @param sh The original shape object. - */ - explicit inline _Item(RawShape&& sh): sh_(std::move(sh)) {} - - /** - * @brief Create an item from an initializer list. - * @param il The initializer list of vertices. - */ - inline _Item(const std::initializer_list< Vertex >& il): - sh_(sl::create(il)) {} - - inline _Item(const TContour& contour, - const THolesContainer& holes = {}): - sh_(sl::create(contour, holes)) {} - - inline _Item(TContour&& contour, - THolesContainer&& holes): - sh_(sl::create(std::move(contour), std::move(holes))) {} - - inline bool isFixed() const noexcept { return fixed_; } - inline void markAsFixedInBin(int binid) - { - fixed_ = binid >= 0; - binid_ = binid; - } - - inline void binId(int idx) { binid_ = idx; } - inline int binId() const noexcept { return binid_; } - - inline void priority(int p) { priority_ = p; } - inline int priority() const noexcept { return priority_; } - - /** - * @brief Convert the polygon to string representation. The format depends - * on the implementation of the polygon. - * @return - */ - inline std::string toString() const - { - return sl::toString(sh_); - } - - /// Iterator tho the first contour vertex in the polygon. - inline Iterator begin() const - { - return sl::cbegin(sh_); - } - - /// Alias to begin() - inline Iterator cbegin() const - { - return sl::cbegin(sh_); - } - - /// Iterator to the last contour vertex. - inline Iterator end() const - { - return sl::cend(sh_); - } - - /// Alias to end() - inline Iterator cend() const - { - return sl::cend(sh_); - } - - /** - * @brief Get a copy of an outer vertex within the carried shape. - * - * Note that the vertex considered here is taken from the original shape - * that this item is constructed from. This means that no transformation is - * applied to the shape in this call. - * - * @param idx The index of the requested vertex. - * @return A copy of the requested vertex. - */ - inline Vertex vertex(unsigned long idx) const - { - return sl::vertex(sh_, idx); - } - - /** - * @brief Modify a vertex. - * - * Note that this method will invalidate every cached calculation result - * including polygon offset and transformations. - * - * @param idx The index of the requested vertex. - * @param v The new vertex data. - */ - inline void setVertex(unsigned long idx, const Vertex& v ) - { - invalidateCache(); - sl::vertex(sh_, idx) = v; - } - - /** - * @brief Calculate the shape area. - * - * The method returns absolute value and does not reflect polygon - * orientation. The result is cached, subsequent calls will have very little - * cost. - * @return The shape area in floating point double precision. - */ - inline double area() const { - double ret ; - if(area_cache_valid_) ret = area_cache_; - else { - ret = sl::area(infaltedShape()); - area_cache_ = ret; - area_cache_valid_ = true; - } - return ret; - } - - inline bool isContourConvex() const { - bool ret = false; - - switch(convexity_) { - case Convexity::UNCHECKED: - ret = sl::isConvex(sl::contour(transformedShape())); - convexity_ = ret? Convexity::C_TRUE : Convexity::C_FALSE; - break; - case Convexity::C_TRUE: ret = true; break; - case Convexity::C_FALSE:; - } - - return ret; - } - - inline bool isHoleConvex(unsigned /*holeidx*/) const { - return false; - } - - inline bool areHolesConvex() const { - return false; - } - - /// The number of the outer ring vertices. - inline size_t vertexCount() const { - return sl::contourVertexCount(sh_); - } - - inline size_t holeCount() const { - return sl::holeCount(sh_); - } - - /** - * @brief isPointInside - * @param p - * @return - */ - inline bool isInside(const Vertex& p) const - { - return sl::isInside(p, transformedShape()); - } - - inline bool isInside(const _Item& sh) const - { - return sl::isInside(transformedShape(), sh.transformedShape()); - } - - inline bool isInside(const RawShape& sh) const - { - return sl::isInside(transformedShape(), sh); - } - - inline bool isInside(const _Box>& box) const; - inline bool isInside(const _Circle>& box) const; - - inline void translate(const Vertex& d) BP2D_NOEXCEPT - { - translation(translation() + d); - } - - inline void rotate(const Radians& rads) BP2D_NOEXCEPT - { - rotation(rotation() + rads); - } - - inline void inflation(Coord distance) BP2D_NOEXCEPT - { - inflation_ = distance; - has_inflation_ = true; - invalidateCache(); - } - - inline Coord inflation() const BP2D_NOEXCEPT { - return inflation_; - } - - inline void inflate(Coord distance) BP2D_NOEXCEPT - { - inflation(inflation() + distance); - } - - inline Radians rotation() const BP2D_NOEXCEPT - { - return rotation_; - } - - inline TPoint translation() const BP2D_NOEXCEPT - { - return translation_; - } - - inline void rotation(Radians rot) BP2D_NOEXCEPT - { - if(rotation_ != rot) { - rotation_ = rot; has_rotation_ = true; tr_cache_valid_ = false; - rmt_valid_ = false; lmb_valid_ = false; - bb_cache_.valid = false; - } - } - - inline void translation(const TPoint& tr) BP2D_NOEXCEPT - { - if(translation_ != tr) { - translation_ = tr; has_translation_ = true; tr_cache_valid_ = false; - //bb_cache_.valid = false; - } - } - - inline const RawShape& transformedShape() const - { - if(tr_cache_valid_) return tr_cache_; - - RawShape cpy = infaltedShape(); - if(has_rotation_) sl::rotate(cpy, rotation_); - if(has_translation_) sl::translate(cpy, translation_); - tr_cache_ = cpy; tr_cache_valid_ = true; - rmt_valid_ = false; lmb_valid_ = false; - - return tr_cache_; - } - - inline operator RawShape() const - { - return transformedShape(); - } - - inline const RawShape& rawShape() const BP2D_NOEXCEPT - { - return sh_; - } - - inline void resetTransformation() BP2D_NOEXCEPT - { - has_translation_ = false; has_rotation_ = false; has_inflation_ = false; - invalidateCache(); - } - - inline Box boundingBox() const { - if(!bb_cache_.valid) { - if(!has_rotation_) - bb_cache_.bb = sl::boundingBox(infaltedShape()); - else { - // TODO make sure this works - auto rotsh = infaltedShape(); - sl::rotate(rotsh, rotation_); - bb_cache_.bb = sl::boundingBox(rotsh); - } - bb_cache_.valid = true; - } - - auto &bb = bb_cache_.bb; auto &tr = translation_; - return {bb.minCorner() + tr, bb.maxCorner() + tr }; - } - - inline Vertex referenceVertex() const { - return rightmostTopVertex(); - } - - inline Vertex rightmostTopVertex() const { - if(!rmt_valid_ || !tr_cache_valid_) { // find max x and max y vertex - auto& tsh = transformedShape(); - rmt_ = std::max_element(sl::cbegin(tsh), sl::cend(tsh), vsort); - rmt_valid_ = true; - } - return *rmt_; - } - - inline Vertex leftmostBottomVertex() const { - if(!lmb_valid_ || !tr_cache_valid_) { // find min x and min y vertex - auto& tsh = transformedShape(); - lmb_ = std::min_element(sl::cbegin(tsh), sl::cend(tsh), vsort); - lmb_valid_ = true; - } - return *lmb_; - } - - //Static methods: - - inline static bool intersects(const _Item& sh1, const _Item& sh2) - { - return sl::intersects(sh1.transformedShape(), - sh2.transformedShape()); - } - - inline static bool touches(const _Item& sh1, const _Item& sh2) - { - return sl::touches(sh1.transformedShape(), - sh2.transformedShape()); - } - -private: - - inline const RawShape& infaltedShape() const { - if(has_inflation_ ) { - if(inflate_cache_valid_) return inflate_cache_; - - inflate_cache_ = sh_; - sl::offset(inflate_cache_, inflation_); - inflate_cache_valid_ = true; - return inflate_cache_; - } - return sh_; - } - - inline void invalidateCache() const BP2D_NOEXCEPT - { - tr_cache_valid_ = false; - lmb_valid_ = false; rmt_valid_ = false; - area_cache_valid_ = false; - inflate_cache_valid_ = false; - bb_cache_.valid = false; - convexity_ = Convexity::UNCHECKED; - } - - static inline bool vsort(const Vertex& v1, const Vertex& v2) - { - TCompute x1 = getX(v1), x2 = getX(v2); - TCompute y1 = getY(v1), y2 = getY(v2); - return y1 == y2 ? x1 < x2 : y1 < y2; - } + NestConfig() = default; + NestConfig(const typename Placer::Config &cfg) : placer_config{cfg} {} + NestConfig(const typename Selector::Config &cfg) : selector_config{cfg} {} + NestConfig(const typename Placer::Config & pcfg, + const typename Selector::Config &scfg) + : placer_config{pcfg}, selector_config{scfg} {} }; -/** - * \brief Subclass of _Item for regular rectangle items. - */ -template -class _Rectangle: public _Item { - using _Item::vertex; - using TO = Orientation; -public: - - using Unit = TCoord>; - - template::Value> - inline _Rectangle(Unit width, Unit height, - // disable this ctor if o != CLOCKWISE - enable_if_t< o == TO::CLOCKWISE, int> = 0 ): - _Item( sl::create( { - {0, 0}, - {0, height}, - {width, height}, - {width, 0}, - {0, 0} - } )) - { - } - - template::Value> - inline _Rectangle(Unit width, Unit height, - // disable this ctor if o != COUNTER_CLOCKWISE - enable_if_t< o == TO::COUNTER_CLOCKWISE, int> = 0 ): - _Item( sl::create( { - {0, 0}, - {width, 0}, - {width, height}, - {0, height}, - {0, 0} - } )) - { - } - - inline Unit width() const BP2D_NOEXCEPT { - return getX(vertex(2)); - } - - inline Unit height() const BP2D_NOEXCEPT { - return getY(vertex(2)); - } +struct NestControl { + ProgressFunction progressfn; + StopCondition stopcond = []{ return false; }; + + NestControl() = default; + NestControl(ProgressFunction pr) : progressfn{std::move(pr)} {} + NestControl(StopCondition sc) : stopcond{std::move(sc)} {} + NestControl(ProgressFunction pr, StopCondition sc) + : progressfn{std::move(pr)}, stopcond{std::move(sc)} + {} }; -template -inline bool _Item::isInside(const _Box>& box) const { - return sl::isInside(boundingBox(), box); +template::iterator> +std::size_t nest(Iterator from, Iterator to, + const typename Placer::BinType & bin, + Coord dist = 0, + const NestConfig &cfg = {}, + NestControl ctl = {}) +{ + _Nester nester{bin, dist, cfg.placer_config, cfg.selector_config}; + if(ctl.progressfn) nester.progressIndicator(ctl.progressfn); + if(ctl.stopcond) nester.stopCondition(ctl.stopcond); + return nester.execute(from, to); } -template inline bool -_Item::isInside(const _Circle>& circ) const { - return sl::isInside(transformedShape(), circ); +#ifdef LIBNEST2D_STATIC + +extern template class _Nester; +extern template class _Nester; +extern template std::size_t nest(std::vector::iterator from, + std::vector::iterator to, + const Box & bin, + Coord dist, + const NestConfig &cfg, + NestControl ctl); +extern template std::size_t nest(std::vector::iterator from, + std::vector::iterator to, + const Box & bin, + Coord dist, + const NestConfig &cfg, + NestControl ctl); + +#endif + +template> +std::size_t nest(Container&& cont, + const typename Placer::BinType & bin, + Coord dist = 0, + const NestConfig &cfg = {}, + NestControl ctl = {}) +{ + return nest(cont.begin(), cont.end(), bin, dist, cfg, ctl); } -template using _ItemRef = std::reference_wrapper<_Item>; -template using _ItemGroup = std::vector<_ItemRef>; - -/** - * \brief A list of packed item vectors. Each vector represents a bin. - */ -template -using _PackGroup = std::vector>>; - -template -struct ConstItemRange { - Iterator from; - Iterator to; - bool valid = false; - - ConstItemRange() = default; - ConstItemRange(Iterator f, Iterator t): from(f), to(t), valid(true) {} -}; - -template -inline ConstItemRange -rem(typename Container::const_iterator it, const Container& cont) { - return {std::next(it), cont.end()}; -} - -/** - * \brief A wrapper interface (trait) class for any placement strategy provider. - * - * If a client wants to use its own placement algorithm, all it has to do is to - * specialize this class template and define all the ten methods it has. It can - * use the strategies::PlacerBoilerplace class for creating a new placement - * strategy where only the constructor and the trypack method has to be provided - * and it will work out of the box. - */ -template -class PlacementStrategyLike { - PlacementStrategy impl_; -public: - - using RawShape = typename PlacementStrategy::ShapeType; - - /// The item type that the placer works with. - using Item = _Item; - - /// The placer's config type. Should be a simple struct but can be anything. - using Config = typename PlacementStrategy::Config; - - /** - * \brief The type of the bin that the placer works with. - * - * Can be a box or an arbitrary shape or just a width or height without a - * second dimension if an infinite bin is considered. - */ - using BinType = typename PlacementStrategy::BinType; - - /** - * \brief Pack result that can be used to accept or discard it. See trypack - * method. - */ - using PackResult = typename PlacementStrategy::PackResult; - - using ItemGroup = _ItemGroup; - using DefaultIterator = typename ItemGroup::const_iterator; - - /** - * @brief Constructor taking the bin and an optional configuration. - * @param bin The bin object whose type is defined by the placement strategy. - * @param config The configuration for the particular placer. - */ - explicit PlacementStrategyLike(const BinType& bin, - const Config& config = Config()): - impl_(bin) - { - configure(config); - } - - /** - * @brief Provide a different configuration for the placer. - * - * Note that it depends on the particular placer implementation how it - * reacts to config changes in the middle of a calculation. - * - * @param config The configuration object defined by the placement strategy. - */ - inline void configure(const Config& config) { impl_.configure(config); } - - /** - * Try to pack an item with a result object that contains the packing - * information for later accepting it. - * - * \param item_store A container of items that are intended to be packed - * later. Can be used by the placer to switch tactics. When it's knows that - * many items will come a greedy strategy may not be the best. - * \param from The iterator to the item from which the packing should start, - * including the pointed item - * \param count How many items should be packed. If the value is 1, than - * just the item pointed to by "from" argument should be packed. - */ - template - inline PackResult trypack( - Item& item, - const ConstItemRange& remaining = ConstItemRange()) - { - return impl_.trypack(item, remaining); - } - - /** - * @brief A method to accept a previously tried item (or items). - * - * If the pack result is a failure the method should ignore it. - * @param r The result of a previous trypack call. - */ - inline void accept(PackResult& r) { impl_.accept(r); } - - /** - * @brief pack Try to pack and immediately accept it on success. - * - * A default implementation would be to call - * { auto&& r = trypack(...); accept(r); return r; } but we should let the - * implementor of the placement strategy to harvest any optimizations from - * the absence of an intermediate step. The above version can still be used - * in the implementation. - * - * @param item The item to pack. - * @return Returns true if the item was packed or false if it could not be - * packed. - */ - template> - inline bool pack( - Item& item, - const Range& remaining = Range()) - { - return impl_.pack(item, remaining); - } - - /** - * This method makes possible to "preload" some items into the placer. It - * will not move these items but will consider them as already packed. - */ - inline void preload(const ItemGroup& packeditems) - { - impl_.preload(packeditems); - } - - /// Unpack the last element (remove it from the list of packed items). - inline void unpackLast() { impl_.unpackLast(); } - - /// Get the bin object. - inline const BinType& bin() const { return impl_.bin(); } - - /// Set a new bin object. - inline void bin(const BinType& bin) { impl_.bin(bin); } - - /// Get the packed items. - inline ItemGroup getItems() { return impl_.getItems(); } - - /// Clear the packed items so a new session can be started. - inline void clearItems() { impl_.clearItems(); } - - inline double filledArea() const { return impl_.filledArea(); } - -}; - -// The progress function will be called with the number of placed items -using ProgressFunction = std::function; -using StopCondition = std::function; - -/** - * A wrapper interface (trait) class for any selections strategy provider. - */ -template -class SelectionStrategyLike { - SelectionStrategy impl_; -public: - using RawShape = typename SelectionStrategy::ShapeType; - using Item = _Item; - using PackGroup = _PackGroup; - using Config = typename SelectionStrategy::Config; - - - /** - * @brief Provide a different configuration for the selection strategy. - * - * Note that it depends on the particular placer implementation how it - * reacts to config changes in the middle of a calculation. - * - * @param config The configuration object defined by the selection strategy. - */ - inline void configure(const Config& config) { - impl_.configure(config); - } - - /** - * @brief A function callback which should be called whenever an item or - * a group of items where successfully packed. - * @param fn A function callback object taking one unsigned integer as the - * number of the remaining items to pack. - */ - void progressIndicator(ProgressFunction fn) { impl_.progressIndicator(fn); } - - void stopCondition(StopCondition cond) { impl_.stopCondition(cond); } - - /** - * \brief A method to start the calculation on the input sequence. - * - * \tparam TPlacer The only mandatory template parameter is the type of - * placer compatible with the PlacementStrategyLike interface. - * - * \param first, last The first and last iterator if the input sequence. It - * can be only an iterator of a type convertible to Item. - * \param bin. The shape of the bin. It has to be supported by the placement - * strategy. - * \param An optional config object for the placer. - */ - template::BinType, - class PConfig = typename PlacementStrategyLike::Config> - inline void packItems( - TIterator first, - TIterator last, - TBin&& bin, - PConfig&& config = PConfig() ) - { - impl_.template packItems(first, last, - std::forward(bin), - std::forward(config)); - } - - /** - * @brief Get the items for a particular bin. - * @param binIndex The index of the requested bin. - * @return Returns a list of all items packed into the requested bin. - */ - inline const PackGroup& getResult() const { - return impl_.getResult(); - } - - void clear() { impl_.clear(); } -}; - -/** - * The _Nester is the front-end class for the libnest2d library. It takes the - * input items and changes their transformations to be inside the provided bin. - */ -template -class _Nester { - using TSel = SelectionStrategyLike; - TSel selector_; - -public: - using Item = typename PlacementStrategy::Item; - using ShapeType = typename Item::ShapeType; - using ItemRef = std::reference_wrapper; - using TPlacer = PlacementStrategyLike; - using BinType = typename TPlacer::BinType; - using PlacementConfig = typename TPlacer::Config; - using SelectionConfig = typename TSel::Config; - using Coord = TCoord>; - using PackGroup = _PackGroup; - using ResultType = PackGroup; - -private: - BinType bin_; - PlacementConfig pconfig_; - Coord min_obj_distance_; - - using SItem = typename SelectionStrategy::Item; - using TPItem = remove_cvref_t; - using TSItem = remove_cvref_t; - - StopCondition stopfn_; - - template using TVal = remove_ref_t; - - template - using ItemIteratorOnly = - enable_if_t&, TPItem&>::value, Out>; - -public: - - /** - * \brief Constructor taking the bin as the only mandatory parameter. - * - * \param bin The bin shape that will be used by the placers. The type - * of the bin should be one that is supported by the placer type. - */ - template - _Nester(TBinType&& bin, Coord min_obj_distance = 0, - const PConf& pconfig = PConf(), const SConf& sconfig = SConf()): - bin_(std::forward(bin)), - pconfig_(pconfig), - min_obj_distance_(min_obj_distance) - { - static_assert( std::is_same::value, - "Incompatible placement and selection strategy!"); - - selector_.configure(sconfig); - } - - void configure(const PlacementConfig& pconf) { pconfig_ = pconf; } - void configure(const SelectionConfig& sconf) { selector_.configure(sconf); } - void configure(const PlacementConfig& pconf, const SelectionConfig& sconf) - { - pconfig_ = pconf; - selector_.configure(sconf); - } - void configure(const SelectionConfig& sconf, const PlacementConfig& pconf) - { - pconfig_ = pconf; - selector_.configure(sconf); - } - - /** - * \brief Arrange an input sequence of _Item-s. - * - * To get the result, call the translation(), rotation() and binId() - * methods of each item. If only the transformed polygon is needed, call - * transformedShape() to get the properly transformed shapes. - * - * The number of groups in the pack group is the number of bins opened by - * the selection algorithm. - */ - template - inline ItemIteratorOnly execute(It from, It to) - { - auto infl = static_cast(std::ceil(min_obj_distance_/2.0)); - if(infl > 0) std::for_each(from, to, [this, infl](Item& item) { - item.inflate(infl); - }); - - selector_.template packItems( - from, to, bin_, pconfig_); - - if(min_obj_distance_ > 0) std::for_each(from, to, [infl](Item& item) { - item.inflate(-infl); - }); - - return selector_.getResult().size(); - } - - /// Set a progress indicator function object for the selector. - inline _Nester& progressIndicator(ProgressFunction func) - { - selector_.progressIndicator(func); return *this; - } - - /// Set a predicate to tell when to abort nesting. - inline _Nester& stopCondition(StopCondition fn) - { - stopfn_ = fn; selector_.stopCondition(fn); return *this; - } - - inline const PackGroup& lastResult() const - { - return selector_.getResult(); - } -}; - } #endif // LIBNEST2D_HPP diff --git a/src/libnest2d/include/libnest2d/nester.hpp b/src/libnest2d/include/libnest2d/nester.hpp new file mode 100644 index 000000000..2f207d526 --- /dev/null +++ b/src/libnest2d/include/libnest2d/nester.hpp @@ -0,0 +1,869 @@ +#ifndef NESTER_HPP +#define NESTER_HPP + +#include +#include +#include +#include +#include +#include + +#include + +namespace libnest2d { + +static const constexpr int BIN_ID_UNSET = -1; + +/** + * \brief An item to be placed on a bin. + * + * It holds a copy of the original shape object but supports move construction + * from the shape objects if its an rvalue reference. This way we can construct + * the items without the cost of copying a potentially large amount of input. + * + * The results of some calculations are cached for maintaining fast run times. + * For this reason, memory demands are much higher but this should pay off. + */ +template +class _Item { + using Coord = TCoord>; + using Vertex = TPoint; + using Box = _Box; + + using VertexConstIterator = typename TContour::const_iterator; + + // The original shape that gets encapsulated. + RawShape sh_; + + // Transformation data + Vertex translation_{0, 0}; + Radians rotation_{0.0}; + Coord inflation_{0}; + + // Info about whether the transformations will have to take place + // This is needed because if floating point is used, it is hard to say + // that a zero angle is not a rotation because of testing for equality. + bool has_rotation_ = false, has_translation_ = false, has_inflation_ = false; + + // For caching the calculations as they can get pretty expensive. + mutable RawShape tr_cache_; + mutable bool tr_cache_valid_ = false; + mutable double area_cache_ = 0; + mutable bool area_cache_valid_ = false; + mutable RawShape inflate_cache_; + mutable bool inflate_cache_valid_ = false; + + enum class Convexity: char { + UNCHECKED, + C_TRUE, + C_FALSE + }; + + mutable Convexity convexity_ = Convexity::UNCHECKED; + mutable VertexConstIterator rmt_; // rightmost top vertex + mutable VertexConstIterator lmb_; // leftmost bottom vertex + mutable bool rmt_valid_ = false, lmb_valid_ = false; + mutable struct BBCache { + Box bb; bool valid; + BBCache(): valid(false) {} + } bb_cache_; + + int binid_{BIN_ID_UNSET}, priority_{0}; + bool fixed_{false}; + +public: + + /// The type of the shape which was handed over as the template argument. + using ShapeType = RawShape; + + /** + * \brief Iterator type for the outer vertices. + * + * Only const iterators can be used. The _Item type is not intended to + * modify the carried shapes from the outside. The main purpose of this type + * is to cache the calculation results from the various operators it + * supports. Giving out a non const iterator would make it impossible to + * perform correct cache invalidation. + */ + using Iterator = VertexConstIterator; + + /** + * @brief Get the orientation of the polygon. + * + * The orientation have to be specified as a specialization of the + * OrientationType struct which has a Value constant. + * + * @return The orientation type identifier for the _Item type. + */ + static BP2D_CONSTEXPR Orientation orientation() { + return OrientationType::Value; + } + + /** + * @brief Constructing an _Item form an existing raw shape. The shape will + * be copied into the _Item object. + * @param sh The original shape object. + */ + explicit inline _Item(const RawShape& sh): sh_(sh) {} + + /** + * @brief Construction of an item by moving the content of the raw shape, + * assuming that it supports move semantics. + * @param sh The original shape object. + */ + explicit inline _Item(RawShape&& sh): sh_(std::move(sh)) {} + + /** + * @brief Create an item from an initializer list. + * @param il The initializer list of vertices. + */ + inline _Item(const std::initializer_list< Vertex >& il): + sh_(sl::create(il)) {} + + inline _Item(const TContour& contour, + const THolesContainer& holes = {}): + sh_(sl::create(contour, holes)) {} + + inline _Item(TContour&& contour, + THolesContainer&& holes): + sh_(sl::create(std::move(contour), std::move(holes))) {} + + inline bool isFixed() const noexcept { return fixed_; } + inline void markAsFixedInBin(int binid) + { + fixed_ = binid >= 0; + binid_ = binid; + } + + inline void binId(int idx) { binid_ = idx; } + inline int binId() const noexcept { return binid_; } + + inline void priority(int p) { priority_ = p; } + inline int priority() const noexcept { return priority_; } + + /** + * @brief Convert the polygon to string representation. The format depends + * on the implementation of the polygon. + * @return + */ + inline std::string toString() const + { + return sl::toString(sh_); + } + + /// Iterator tho the first contour vertex in the polygon. + inline Iterator begin() const + { + return sl::cbegin(sh_); + } + + /// Alias to begin() + inline Iterator cbegin() const + { + return sl::cbegin(sh_); + } + + /// Iterator to the last contour vertex. + inline Iterator end() const + { + return sl::cend(sh_); + } + + /// Alias to end() + inline Iterator cend() const + { + return sl::cend(sh_); + } + + /** + * @brief Get a copy of an outer vertex within the carried shape. + * + * Note that the vertex considered here is taken from the original shape + * that this item is constructed from. This means that no transformation is + * applied to the shape in this call. + * + * @param idx The index of the requested vertex. + * @return A copy of the requested vertex. + */ + inline Vertex vertex(unsigned long idx) const + { + return sl::vertex(sh_, idx); + } + + /** + * @brief Modify a vertex. + * + * Note that this method will invalidate every cached calculation result + * including polygon offset and transformations. + * + * @param idx The index of the requested vertex. + * @param v The new vertex data. + */ + inline void setVertex(unsigned long idx, const Vertex& v ) + { + invalidateCache(); + sl::vertex(sh_, idx) = v; + } + + /** + * @brief Calculate the shape area. + * + * The method returns absolute value and does not reflect polygon + * orientation. The result is cached, subsequent calls will have very little + * cost. + * @return The shape area in floating point double precision. + */ + inline double area() const { + double ret ; + if(area_cache_valid_) ret = area_cache_; + else { + ret = sl::area(infaltedShape()); + area_cache_ = ret; + area_cache_valid_ = true; + } + return ret; + } + + inline bool isContourConvex() const { + bool ret = false; + + switch(convexity_) { + case Convexity::UNCHECKED: + ret = sl::isConvex(sl::contour(transformedShape())); + convexity_ = ret? Convexity::C_TRUE : Convexity::C_FALSE; + break; + case Convexity::C_TRUE: ret = true; break; + case Convexity::C_FALSE:; + } + + return ret; + } + + inline bool isHoleConvex(unsigned /*holeidx*/) const { + return false; + } + + inline bool areHolesConvex() const { + return false; + } + + /// The number of the outer ring vertices. + inline size_t vertexCount() const { + return sl::contourVertexCount(sh_); + } + + inline size_t holeCount() const { + return sl::holeCount(sh_); + } + + /** + * @brief isPointInside + * @param p + * @return + */ + inline bool isInside(const Vertex& p) const + { + return sl::isInside(p, transformedShape()); + } + + inline bool isInside(const _Item& sh) const + { + return sl::isInside(transformedShape(), sh.transformedShape()); + } + + inline bool isInside(const RawShape& sh) const + { + return sl::isInside(transformedShape(), sh); + } + + inline bool isInside(const _Box>& box) const; + inline bool isInside(const _Circle>& box) const; + + inline void translate(const Vertex& d) BP2D_NOEXCEPT + { + translation(translation() + d); + } + + inline void rotate(const Radians& rads) BP2D_NOEXCEPT + { + rotation(rotation() + rads); + } + + inline void inflation(Coord distance) BP2D_NOEXCEPT + { + inflation_ = distance; + has_inflation_ = true; + invalidateCache(); + } + + inline Coord inflation() const BP2D_NOEXCEPT { + return inflation_; + } + + inline void inflate(Coord distance) BP2D_NOEXCEPT + { + inflation(inflation() + distance); + } + + inline Radians rotation() const BP2D_NOEXCEPT + { + return rotation_; + } + + inline TPoint translation() const BP2D_NOEXCEPT + { + return translation_; + } + + inline void rotation(Radians rot) BP2D_NOEXCEPT + { + if(rotation_ != rot) { + rotation_ = rot; has_rotation_ = true; tr_cache_valid_ = false; + rmt_valid_ = false; lmb_valid_ = false; + bb_cache_.valid = false; + } + } + + inline void translation(const TPoint& tr) BP2D_NOEXCEPT + { + if(translation_ != tr) { + translation_ = tr; has_translation_ = true; tr_cache_valid_ = false; + //bb_cache_.valid = false; + } + } + + inline const RawShape& transformedShape() const + { + if(tr_cache_valid_) return tr_cache_; + + RawShape cpy = infaltedShape(); + if(has_rotation_) sl::rotate(cpy, rotation_); + if(has_translation_) sl::translate(cpy, translation_); + tr_cache_ = cpy; tr_cache_valid_ = true; + rmt_valid_ = false; lmb_valid_ = false; + + return tr_cache_; + } + + inline operator RawShape() const + { + return transformedShape(); + } + + inline const RawShape& rawShape() const BP2D_NOEXCEPT + { + return sh_; + } + + inline void resetTransformation() BP2D_NOEXCEPT + { + has_translation_ = false; has_rotation_ = false; has_inflation_ = false; + invalidateCache(); + } + + inline Box boundingBox() const { + if(!bb_cache_.valid) { + if(!has_rotation_) + bb_cache_.bb = sl::boundingBox(infaltedShape()); + else { + // TODO make sure this works + auto rotsh = infaltedShape(); + sl::rotate(rotsh, rotation_); + bb_cache_.bb = sl::boundingBox(rotsh); + } + bb_cache_.valid = true; + } + + auto &bb = bb_cache_.bb; auto &tr = translation_; + return {bb.minCorner() + tr, bb.maxCorner() + tr }; + } + + inline Vertex referenceVertex() const { + return rightmostTopVertex(); + } + + inline Vertex rightmostTopVertex() const { + if(!rmt_valid_ || !tr_cache_valid_) { // find max x and max y vertex + auto& tsh = transformedShape(); + rmt_ = std::max_element(sl::cbegin(tsh), sl::cend(tsh), vsort); + rmt_valid_ = true; + } + return *rmt_; + } + + inline Vertex leftmostBottomVertex() const { + if(!lmb_valid_ || !tr_cache_valid_) { // find min x and min y vertex + auto& tsh = transformedShape(); + lmb_ = std::min_element(sl::cbegin(tsh), sl::cend(tsh), vsort); + lmb_valid_ = true; + } + return *lmb_; + } + + //Static methods: + + inline static bool intersects(const _Item& sh1, const _Item& sh2) + { + return sl::intersects(sh1.transformedShape(), + sh2.transformedShape()); + } + + inline static bool touches(const _Item& sh1, const _Item& sh2) + { + return sl::touches(sh1.transformedShape(), + sh2.transformedShape()); + } + +private: + + inline const RawShape& infaltedShape() const { + if(has_inflation_ ) { + if(inflate_cache_valid_) return inflate_cache_; + + inflate_cache_ = sh_; + sl::offset(inflate_cache_, inflation_); + inflate_cache_valid_ = true; + return inflate_cache_; + } + return sh_; + } + + inline void invalidateCache() const BP2D_NOEXCEPT + { + tr_cache_valid_ = false; + lmb_valid_ = false; rmt_valid_ = false; + area_cache_valid_ = false; + inflate_cache_valid_ = false; + bb_cache_.valid = false; + convexity_ = Convexity::UNCHECKED; + } + + static inline bool vsort(const Vertex& v1, const Vertex& v2) + { + TCompute x1 = getX(v1), x2 = getX(v2); + TCompute y1 = getY(v1), y2 = getY(v2); + return y1 == y2 ? x1 < x2 : y1 < y2; + } +}; + +/** + * \brief Subclass of _Item for regular rectangle items. + */ +template +class _Rectangle: public _Item { + using _Item::vertex; + using TO = Orientation; +public: + + using Unit = TCoord>; + + template::Value> + inline _Rectangle(Unit width, Unit height, + // disable this ctor if o != CLOCKWISE + enable_if_t< o == TO::CLOCKWISE, int> = 0 ): + _Item( sl::create( { + {0, 0}, + {0, height}, + {width, height}, + {width, 0}, + {0, 0} + } )) + { + } + + template::Value> + inline _Rectangle(Unit width, Unit height, + // disable this ctor if o != COUNTER_CLOCKWISE + enable_if_t< o == TO::COUNTER_CLOCKWISE, int> = 0 ): + _Item( sl::create( { + {0, 0}, + {width, 0}, + {width, height}, + {0, height}, + {0, 0} + } )) + { + } + + inline Unit width() const BP2D_NOEXCEPT { + return getX(vertex(2)); + } + + inline Unit height() const BP2D_NOEXCEPT { + return getY(vertex(2)); + } +}; + +template +inline bool _Item::isInside(const _Box>& box) const { + return sl::isInside(boundingBox(), box); +} + +template inline bool +_Item::isInside(const _Circle>& circ) const { + return sl::isInside(transformedShape(), circ); +} + +template using _ItemRef = std::reference_wrapper<_Item>; +template using _ItemGroup = std::vector<_ItemRef>; + +/** + * \brief A list of packed item vectors. Each vector represents a bin. + */ +template +using _PackGroup = std::vector>>; + +template +struct ConstItemRange { + Iterator from; + Iterator to; + bool valid = false; + + ConstItemRange() = default; + ConstItemRange(Iterator f, Iterator t): from(f), to(t), valid(true) {} +}; + +template +inline ConstItemRange +rem(typename Container::const_iterator it, const Container& cont) { + return {std::next(it), cont.end()}; +} + +/** + * \brief A wrapper interface (trait) class for any placement strategy provider. + * + * If a client wants to use its own placement algorithm, all it has to do is to + * specialize this class template and define all the ten methods it has. It can + * use the strategies::PlacerBoilerplace class for creating a new placement + * strategy where only the constructor and the trypack method has to be provided + * and it will work out of the box. + */ +template +class PlacementStrategyLike { + PlacementStrategy impl_; +public: + + using RawShape = typename PlacementStrategy::ShapeType; + + /// The item type that the placer works with. + using Item = _Item; + + /// The placer's config type. Should be a simple struct but can be anything. + using Config = typename PlacementStrategy::Config; + + /** + * \brief The type of the bin that the placer works with. + * + * Can be a box or an arbitrary shape or just a width or height without a + * second dimension if an infinite bin is considered. + */ + using BinType = typename PlacementStrategy::BinType; + + /** + * \brief Pack result that can be used to accept or discard it. See trypack + * method. + */ + using PackResult = typename PlacementStrategy::PackResult; + + using ItemGroup = _ItemGroup; + using DefaultIterator = typename ItemGroup::const_iterator; + + /** + * @brief Constructor taking the bin and an optional configuration. + * @param bin The bin object whose type is defined by the placement strategy. + * @param config The configuration for the particular placer. + */ + explicit PlacementStrategyLike(const BinType& bin, + const Config& config = Config()): + impl_(bin) + { + configure(config); + } + + /** + * @brief Provide a different configuration for the placer. + * + * Note that it depends on the particular placer implementation how it + * reacts to config changes in the middle of a calculation. + * + * @param config The configuration object defined by the placement strategy. + */ + inline void configure(const Config& config) { impl_.configure(config); } + + /** + * Try to pack an item with a result object that contains the packing + * information for later accepting it. + * + * \param item_store A container of items that are intended to be packed + * later. Can be used by the placer to switch tactics. When it's knows that + * many items will come a greedy strategy may not be the best. + * \param from The iterator to the item from which the packing should start, + * including the pointed item + * \param count How many items should be packed. If the value is 1, than + * just the item pointed to by "from" argument should be packed. + */ + template + inline PackResult trypack( + Item& item, + const ConstItemRange& remaining = ConstItemRange()) + { + return impl_.trypack(item, remaining); + } + + /** + * @brief A method to accept a previously tried item (or items). + * + * If the pack result is a failure the method should ignore it. + * @param r The result of a previous trypack call. + */ + inline void accept(PackResult& r) { impl_.accept(r); } + + /** + * @brief pack Try to pack and immediately accept it on success. + * + * A default implementation would be to call + * { auto&& r = trypack(...); accept(r); return r; } but we should let the + * implementor of the placement strategy to harvest any optimizations from + * the absence of an intermediate step. The above version can still be used + * in the implementation. + * + * @param item The item to pack. + * @return Returns true if the item was packed or false if it could not be + * packed. + */ + template> + inline bool pack( + Item& item, + const Range& remaining = Range()) + { + return impl_.pack(item, remaining); + } + + /** + * This method makes possible to "preload" some items into the placer. It + * will not move these items but will consider them as already packed. + */ + inline void preload(const ItemGroup& packeditems) + { + impl_.preload(packeditems); + } + + /// Unpack the last element (remove it from the list of packed items). + inline void unpackLast() { impl_.unpackLast(); } + + /// Get the bin object. + inline const BinType& bin() const { return impl_.bin(); } + + /// Set a new bin object. + inline void bin(const BinType& bin) { impl_.bin(bin); } + + /// Get the packed items. + inline ItemGroup getItems() { return impl_.getItems(); } + + /// Clear the packed items so a new session can be started. + inline void clearItems() { impl_.clearItems(); } + + inline double filledArea() const { return impl_.filledArea(); } + +}; + +// The progress function will be called with the number of placed items +using ProgressFunction = std::function; +using StopCondition = std::function; + +/** + * A wrapper interface (trait) class for any selections strategy provider. + */ +template +class SelectionStrategyLike { + SelectionStrategy impl_; +public: + using RawShape = typename SelectionStrategy::ShapeType; + using Item = _Item; + using PackGroup = _PackGroup; + using Config = typename SelectionStrategy::Config; + + + /** + * @brief Provide a different configuration for the selection strategy. + * + * Note that it depends on the particular placer implementation how it + * reacts to config changes in the middle of a calculation. + * + * @param config The configuration object defined by the selection strategy. + */ + inline void configure(const Config& config) { + impl_.configure(config); + } + + /** + * @brief A function callback which should be called whenever an item or + * a group of items where successfully packed. + * @param fn A function callback object taking one unsigned integer as the + * number of the remaining items to pack. + */ + void progressIndicator(ProgressFunction fn) { impl_.progressIndicator(fn); } + + void stopCondition(StopCondition cond) { impl_.stopCondition(cond); } + + /** + * \brief A method to start the calculation on the input sequence. + * + * \tparam TPlacer The only mandatory template parameter is the type of + * placer compatible with the PlacementStrategyLike interface. + * + * \param first, last The first and last iterator if the input sequence. It + * can be only an iterator of a type convertible to Item. + * \param bin. The shape of the bin. It has to be supported by the placement + * strategy. + * \param An optional config object for the placer. + */ + template::BinType, + class PConfig = typename PlacementStrategyLike::Config> + inline void packItems( + TIterator first, + TIterator last, + TBin&& bin, + PConfig&& config = PConfig() ) + { + impl_.template packItems(first, last, + std::forward(bin), + std::forward(config)); + } + + /** + * @brief Get the items for a particular bin. + * @param binIndex The index of the requested bin. + * @return Returns a list of all items packed into the requested bin. + */ + inline const PackGroup& getResult() const { + return impl_.getResult(); + } + + void clear() { impl_.clear(); } +}; + +/** + * The _Nester is the front-end class for the libnest2d library. It takes the + * input items and changes their transformations to be inside the provided bin. + */ +template +class _Nester { + using TSel = SelectionStrategyLike; + TSel selector_; + +public: + using Item = typename PlacementStrategy::Item; + using ShapeType = typename Item::ShapeType; + using ItemRef = std::reference_wrapper; + using TPlacer = PlacementStrategyLike; + using BinType = typename TPlacer::BinType; + using PlacementConfig = typename TPlacer::Config; + using SelectionConfig = typename TSel::Config; + using Coord = TCoord>; + using PackGroup = _PackGroup; + using ResultType = PackGroup; + +private: + BinType bin_; + PlacementConfig pconfig_; + Coord min_obj_distance_; + + using SItem = typename SelectionStrategy::Item; + using TPItem = remove_cvref_t; + using TSItem = remove_cvref_t; + + StopCondition stopfn_; + + template using TVal = remove_ref_t; + + template + using ItemIteratorOnly = + enable_if_t&, TPItem&>::value, Out>; + +public: + + /** + * \brief Constructor taking the bin as the only mandatory parameter. + * + * \param bin The bin shape that will be used by the placers. The type + * of the bin should be one that is supported by the placer type. + */ + template + _Nester(TBinType&& bin, Coord min_obj_distance = 0, + const PConf& pconfig = PConf(), const SConf& sconfig = SConf()): + bin_(std::forward(bin)), + pconfig_(pconfig), + min_obj_distance_(min_obj_distance) + { + static_assert( std::is_same::value, + "Incompatible placement and selection strategy!"); + + selector_.configure(sconfig); + } + + void configure(const PlacementConfig& pconf) { pconfig_ = pconf; } + void configure(const SelectionConfig& sconf) { selector_.configure(sconf); } + void configure(const PlacementConfig& pconf, const SelectionConfig& sconf) + { + pconfig_ = pconf; + selector_.configure(sconf); + } + void configure(const SelectionConfig& sconf, const PlacementConfig& pconf) + { + pconfig_ = pconf; + selector_.configure(sconf); + } + + /** + * \brief Arrange an input sequence of _Item-s. + * + * To get the result, call the translation(), rotation() and binId() + * methods of each item. If only the transformed polygon is needed, call + * transformedShape() to get the properly transformed shapes. + * + * The number of groups in the pack group is the number of bins opened by + * the selection algorithm. + */ + template + inline ItemIteratorOnly execute(It from, It to) + { + auto infl = static_cast(std::ceil(min_obj_distance_/2.0)); + if(infl > 0) std::for_each(from, to, [this, infl](Item& item) { + item.inflate(infl); + }); + + selector_.template packItems( + from, to, bin_, pconfig_); + + if(min_obj_distance_ > 0) std::for_each(from, to, [infl](Item& item) { + item.inflate(-infl); + }); + + return selector_.getResult().size(); + } + + /// Set a progress indicator function object for the selector. + inline _Nester& progressIndicator(ProgressFunction func) + { + selector_.progressIndicator(func); return *this; + } + + /// Set a predicate to tell when to abort nesting. + inline _Nester& stopCondition(StopCondition fn) + { + stopfn_ = fn; selector_.stopCondition(fn); return *this; + } + + inline const PackGroup& lastResult() const + { + return selector_.getResult(); + } +}; + +} + +#endif // NESTER_HPP diff --git a/src/libnest2d/include/libnest2d/optimizers/nlopt/CMakeLists.txt b/src/libnest2d/include/libnest2d/optimizers/nlopt/CMakeLists.txt deleted file mode 100644 index 6f51718d8..000000000 --- a/src/libnest2d/include/libnest2d/optimizers/nlopt/CMakeLists.txt +++ /dev/null @@ -1,61 +0,0 @@ -find_package(NLopt 1.4) - -if(NOT NLopt_FOUND) - message(STATUS "NLopt not found so downloading " - "and automatic build is performed...") - - include(DownloadProject) - - if (CMAKE_VERSION VERSION_LESS 3.2) - set(UPDATE_DISCONNECTED_IF_AVAILABLE "") - else() - set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1") - endif() - - set(URL_NLOPT "https://github.com/stevengj/nlopt.git" - CACHE STRING "Location of the nlopt git repository") - - # set(NLopt_DIR ${CMAKE_BINARY_DIR}/nlopt) - include(DownloadProject) - download_project( PROJ nlopt - GIT_REPOSITORY ${URL_NLOPT} - GIT_TAG v2.5.0 - # CMAKE_CACHE_ARGS -DBUILD_SHARED_LIBS:BOOL=OFF -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${NLopt_DIR} - ${UPDATE_DISCONNECTED_IF_AVAILABLE} - ) - - set(SHARED_LIBS_STATE BUILD_SHARED_LIBS) - set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) - set(NLOPT_PYTHON OFF CACHE BOOL "" FORCE) - set(NLOPT_OCTAVE OFF CACHE BOOL "" FORCE) - set(NLOPT_MATLAB OFF CACHE BOOL "" FORCE) - set(NLOPT_GUILE OFF CACHE BOOL "" FORCE) - set(NLOPT_SWIG OFF CACHE BOOL "" FORCE) - set(NLOPT_LINK_PYTHON OFF CACHE BOOL "" FORCE) - - add_subdirectory(${nlopt_SOURCE_DIR} ${nlopt_BINARY_DIR}) - - set(NLopt_LIBS nlopt) - set(NLopt_INCLUDE_DIR ${nlopt_BINARY_DIR} ${nlopt_BINARY_DIR}/src/api) - set(SHARED_LIBS_STATE ${SHARED_STATE}) - - add_library(nloptOptimizer INTERFACE) - target_link_libraries(nloptOptimizer INTERFACE nlopt) - target_include_directories(nloptOptimizer INTERFACE ${NLopt_INCLUDE_DIR}) - -else() - add_library(nloptOptimizer INTERFACE) - target_link_libraries(nloptOptimizer INTERFACE Nlopt::Nlopt) -endif() - -#target_sources( nloptOptimizer INTERFACE -#${CMAKE_CURRENT_SOURCE_DIR}/simplex.hpp -#${CMAKE_CURRENT_SOURCE_DIR}/subplex.hpp -#${CMAKE_CURRENT_SOURCE_DIR}/genetic.hpp -#${CMAKE_CURRENT_SOURCE_DIR}/nlopt_boilerplate.hpp -#) - -target_compile_definitions(nloptOptimizer INTERFACE LIBNEST2D_OPTIMIZER_NLOPT) - -# And finally plug the nloptOptimizer into libnest2d -#target_link_libraries(libnest2d INTERFACE nloptOptimizer) diff --git a/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp b/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp index 26681aeec..dc1bbd4f1 100644 --- a/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp +++ b/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp @@ -1,7 +1,7 @@ #ifndef PLACER_BOILERPLATE_HPP #define PLACER_BOILERPLATE_HPP -#include +#include namespace libnest2d { namespace placers { diff --git a/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp b/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp index 36fec7164..8e65bafe9 100644 --- a/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp +++ b/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp @@ -2,7 +2,7 @@ #define SELECTION_BOILERPLATE_HPP #include -#include +#include namespace libnest2d { namespace selections { @@ -25,7 +25,7 @@ public: inline void clear() { packed_bins_.clear(); } protected: - + template void remove_unpackable_items(Container &c, const Bin &bin, const PCfg& pcfg) { @@ -33,14 +33,14 @@ protected: // then it should be removed from the list auto it = c.begin(); while (it != c.end() && !stopcond_()) { - + // WARNING: The copy of itm needs to be created before Placer. // Placer is working with references and its destructor still // manipulates the item this is why the order of stack creation - // matters here. + // matters here. const Item& itm = *it; Item cpy{itm}; - + Placer p{bin}; p.configure(pcfg); if (itm.area() <= 0 || !p.pack(cpy)) it = c.erase(it); diff --git a/src/libnest2d/src/libnest2d.cpp b/src/libnest2d/src/libnest2d.cpp index 740f6e18d..5a881541e 100644 --- a/src/libnest2d/src/libnest2d.cpp +++ b/src/libnest2d/src/libnest2d.cpp @@ -1,19 +1,24 @@ -#include +#include namespace libnest2d { -template class Nester; -template class Nester; +template class _Nester; +template class _Nester; + +template std::size_t _Nester::execute( + std::vector::iterator, std::vector::iterator); +template std::size_t _Nester::execute( + std::vector::iterator, std::vector::iterator); template std::size_t nest(std::vector::iterator from, - std::vector::iterator from to, + std::vector::iterator to, const Box & bin, Coord dist, const NestConfig &cfg, NestControl ctl); template std::size_t nest(std::vector::iterator from, - std::vector::iterator from to, + std::vector::iterator to, const Box & bin, Coord dist, const NestConfig &cfg, diff --git a/src/libnest2d/tests/CMakeLists.txt b/src/libnest2d/tests/CMakeLists.txt deleted file mode 100644 index 1b7d8e3ae..000000000 --- a/src/libnest2d/tests/CMakeLists.txt +++ /dev/null @@ -1,60 +0,0 @@ - -# Try to find existing GTest installation -find_package(GTest 1.7) - -if(NOT GTEST_FOUND) - set(URL_GTEST "https://github.com/google/googletest.git" - CACHE STRING "Google test source code repository location.") - - message(STATUS "GTest not found so downloading from ${URL_GTEST}") - # Go and download google test framework, integrate it with the build - set(GTEST_LIBS_TO_LINK gtest gtest_main) - - if (CMAKE_VERSION VERSION_LESS 3.2) - set(UPDATE_DISCONNECTED_IF_AVAILABLE "") - else() - set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1") - endif() - - include(DownloadProject) - download_project(PROJ googletest - GIT_REPOSITORY ${URL_GTEST} - GIT_TAG release-1.7.0 - ${UPDATE_DISCONNECTED_IF_AVAILABLE} - ) - - # Prevent GoogleTest from overriding our compiler/linker options - # when building with Visual Studio - set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) - - add_subdirectory(${googletest_SOURCE_DIR} - ${googletest_BINARY_DIR} - ) - - set(GTEST_INCLUDE_DIRS ${googletest_SOURCE_DIR}/include) - -else() - find_package(Threads REQUIRED) - set(GTEST_LIBS_TO_LINK ${GTEST_BOTH_LIBRARIES} Threads::Threads) -endif() - -add_executable(tests_clipper_nlopt - test.cpp - ../tools/svgtools.hpp -# ../tools/libnfpglue.hpp -# ../tools/libnfpglue.cpp - printer_parts.h - printer_parts.cpp -) - -target_link_libraries(tests_clipper_nlopt libnest2d ${GTEST_LIBS_TO_LINK} ) - -target_include_directories(tests_clipper_nlopt PRIVATE BEFORE ${GTEST_INCLUDE_DIRS}) - -if(NOT LIBNEST2D_HEADER_ONLY) - target_link_libraries(tests_clipper_nlopt ${LIBNAME}) -else() - target_link_libraries(tests_clipper_nlopt libnest2d) -endif() - -add_test(libnest2d_tests tests_clipper_nlopt) diff --git a/src/libnest2d/tests/printer_parts.cpp b/src/libnest2d/tests/printer_parts.cpp deleted file mode 100644 index bdc2a3d43..000000000 --- a/src/libnest2d/tests/printer_parts.cpp +++ /dev/null @@ -1,3175 +0,0 @@ -#include "printer_parts.h" - -const TestData PRINTER_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 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}, - }, -}; - -const TestDataEx PRINTER_PART_POLYGONS_EX = -{ - { - { - {533726562, 142141690}, - {532359712, 143386134}, - {530141290, 142155145}, - {528649729, 160091460}, - {533659500, 157607547}, - {538669739, 160091454}, - {537178168, 142155145}, - {534959534, 143386102}, - {533726562, 142141690}, - }, - { - }, - }, - { - { - {118305840, 11603332}, - {118311095, 26616786}, - {113311095, 26611146}, - {109311095, 29604752}, - {109300760, 44608489}, - {109311095, 49631801}, - {113300790, 52636806}, - {118311095, 52636806}, - {118308782, 103636810}, - {223830940, 103636981}, - {236845321, 90642174}, - {236832882, 11630488}, - {232825251, 11616786}, - {210149075, 11616786}, - {211308596, 13625149}, - {209315325, 17080886}, - {205326885, 17080886}, - {203334352, 13629720}, - {204493136, 11616786}, - {118305840, 11603332}, - }, - { - }, - }, - { - { - {365619370, 111280336}, - {365609100, 198818091}, - {387109100, 198804367}, - {387109100, 203279701}, - {471129120, 203279688}, - {471128689, 111283937}, - {365619370, 111280336}, - }, - { - }, - }, - { - { - {479997525, 19177632}, - {477473010, 21975778}, - {475272613, 21969219}, - {475267479, 32995796}, - {477026388, 32995796}, - {483041428, 22582411}, - {482560272, 20318630}, - {479997525, 19177632}, - }, - { - }, - }, - { - { - {476809080, 4972372}, - {475267479, 4975778}, - {475272613, 16002357}, - {481018177, 18281994}, - {482638044, 15466085}, - {476809080, 4972372}, - }, - { - }, - }, - { - { - {424866064, 10276075}, - {415113411, 10277960}, - {411723180, 13685293}, - {410473354, 18784347}, - {382490868, 18784008}, - {380996185, 17286945}, - {380996185, 11278161}, - {375976165, 11284347}, - {375976165, 56389754}, - {375169018, 57784347}, - {371996185, 57784347}, - {371996185, 53779177}, - {364976165, 53784347}, - {364969637, 56791976}, - {369214608, 61054367}, - {371474507, 61054367}, - {371473155, 98298160}, - {378476349, 105317193}, - {407491306, 105307497}, - {413509785, 99284903}, - {413496185, 48304367}, - {419496173, 48315719}, - {422501887, 45292801}, - {422500504, 39363184}, - {420425079, 37284347}, - {419476165, 43284347}, - {413496185, 43284347}, - {413497261, 30797428}, - {418986175, 25308513}, - {424005230, 25315076}, - {428496185, 20815924}, - {428512720, 13948847}, - {424866064, 10276075}, - }, - { - }, - }, - { - { - {723893066, 37354349}, - {717673034, 37370791}, - {717673034, 44872138}, - {715673034, 44867768}, - {715673034, 46055353}, - {699219526, 40066777}, - {697880758, 37748547}, - {691985477, 37748293}, - {689014018, 42869257}, - {691985477, 48016003}, - {697575093, 48003007}, - {715671494, 54589493}, - {715656800, 87142158}, - {759954611, 87142158}, - {764193054, 82897328}, - {764193054, 79872138}, - {757173034, 79866968}, - {757173034, 83872138}, - {754419422, 83869509}, - {753193054, 81739327}, - {753193054, 37360571}, - {723893066, 37354349}, - }, - { - }, - }, - { - { - {85607478, 4227596}, - {61739211, 4230337}, - {61739211, 13231393}, - {58725066, 13231405}, - {58721589, 27731406}, - {58738375, 30262521}, - {61739211, 30251413}, - {61736212, 38251411}, - {70759231, 38254724}, - {70905600, 33317391}, - {73749222, 31251468}, - {76592843, 33317393}, - {76739211, 38254516}, - {86765007, 38251411}, - {86759599, 4231393}, - {85607478, 4227596}, - }, - { - }, - }, - { - { - {534839721, 53437770}, - {534839721, 60849059}, - {539898273, 63773857}, - {545461140, 63757881}, - {544859741, 53447836}, - {541839721, 53437862}, - {541710836, 56353878}, - {540193984, 57229659}, - {538859741, 53437862}, - {534839721, 53437770}, - }, - { - }, - }, - { - { - {756086230, 136598477}, - {732054387, 136605752}, - {732052489, 172629505}, - {756091994, 172627853}, - {756086230, 136598477}, - }, - { - }, - }, - { - { - {100337034, 79731391}, - {70296833, 79731391}, - {70311095, 92263567}, - {74329808, 96264260}, - {96344976, 96257215}, - {100344419, 92232243}, - {100337034, 79731391}, - }, - { - }, - }, - { - { - {102331115, 44216643}, - {67311095, 44217252}, - {67311095, 69250964}, - {74329808, 76264260}, - {96334594, 76251411}, - {103335261, 69241401}, - {103345839, 44231404}, - {102331115, 44216643}, - }, - { - }, - }, - { - { - {93849749, 109613798}, - {91771666, 111698636}, - {91772404, 174626800}, - {96782902, 179645338}, - {241790509, 179645349}, - {246800716, 174626800}, - {246802574, 111699755}, - {243934250, 109616385}, - {93849749, 109613798}, - }, - { - }, - }, - { - { - {15856630, 87966835}, - {8414359, 91273170}, - {5891847, 99010553}, - {8403012, 104668172}, - {13739106, 107763252}, - {13739106, 116209175}, - {17959116, 116219127}, - {17959127, 107763252}, - {23952579, 103855773}, - {25806388, 96944174}, - {22553953, 90543787}, - {15856630, 87966835}, - }, - { - }, - }, - { - { - {503922805, 110421794}, - {491110107, 123244292}, - {479598157, 123244304}, - {479601067, 149264312}, - {494260327, 149265241}, - {502929782, 157948320}, - {506490250, 155806171}, - {502950518, 155094962}, - {507193172, 150852294}, - {504364680, 148023895}, - {535816833, 116571757}, - {538656617, 119411542}, - {542887886, 115157558}, - {543594970, 118693080}, - {545330008, 116966050}, - {540309189, 110425901}, - {503922805, 110421794}, - }, - { - }, - }, - { - { - {519310433, 62560296}, - {515749982, 64702434}, - {519289696, 65413661}, - {515047062, 69656303}, - {517875553, 72484703}, - {486423431, 103936848}, - {483595031, 101108448}, - {479352325, 105351055}, - {478645233, 101815525}, - {476917724, 103520870}, - {481923478, 110077233}, - {518337308, 110084297}, - {531130127, 97264312}, - {542630127, 97281049}, - {542639167, 71244292}, - {527979906, 71243363}, - {519310433, 62560296}, - }, - { - }, - }, - { - { - {528658425, 14775300}, - {525975568, 24475413}, - {522556814, 29181341}, - {517517474, 32090757}, - {511736147, 32698600}, - {506200465, 30901018}, - {501879743, 27011092}, - {497782491, 14775300}, - {492372374, 15588397}, - {489384268, 20795320}, - {491253082, 28537271}, - {495185363, 34469052}, - {495178475, 43927542}, - {502032399, 55796416}, - {524402581, 55807400}, - {531706434, 44295318}, - {531205383, 34469052}, - {536679415, 23789946}, - {535868173, 17264403}, - {532873348, 15073849}, - {528658425, 14775300}, - }, - { - }, - }, - { - { - {481122222, 166062916}, - {478115710, 166824472}, - {477103577, 169063247}, - {477106058, 192070670}, - {478623652, 194687013}, - {525109130, 195083267}, - {525117792, 198086965}, - {535129140, 198091624}, - {535129150, 195083267}, - {539038502, 194940807}, - {540865280, 193308821}, - {541132038, 169100183}, - {539614599, 166459484}, - {481122222, 166062916}, - }, - { - }, - }, - { - { - {23771404, 13005453}, - {24774973, 19182457}, - {31971050, 18727127}, - {32556286, 58337520}, - {25390683, 58337566}, - {25063762, 54707065}, - {20168811, 54707252}, - {20171550, 62917175}, - {70810377, 202895528}, - {74314421, 205588631}, - {88674817, 205515176}, - {91837376, 203083756}, - {92280287, 199307207}, - {40674807, 15904975}, - {36849630, 13006690}, - {23771404, 13005453}, - }, - { - }, - }, - { - { - {336421201, 2986256}, - {331176570, 6498191}, - {327552287, 5825511}, - {324913825, 2988891}, - {316226154, 2989990}, - {313040282, 6275291}, - {313040282, 23489990}, - {307126391, 23490002}, - {307140289, 25510010}, - {313040282, 25510010}, - {313040282, 28989990}, - {307126391, 28990002}, - {307140289, 31015515}, - {313040282, 31010010}, - {313040282, 35989990}, - {304534809, 37529785}, - {304524991, 73488855}, - {308554680, 77518546}, - {324040282, 77510010}, - {324040295, 93025333}, - {334574441, 93010010}, - {334574441, 90989990}, - {332560302, 90989990}, - {332560302, 85010010}, - {334560302, 85010010}, - {334561237, 82010010}, - {338540282, 82010010}, - {339540282, 83760010}, - {338540293, 93020012}, - {348060655, 93014679}, - {356564448, 84500000}, - {356560555, 28989990}, - {347334198, 29039989}, - {347334198, 25510010}, - {356510304, 25521084}, - {356510315, 23478922}, - {347560302, 23489990}, - {347560302, 5775291}, - {344874443, 2989990}, - {336421201, 2986256}, - }, - { - }, - }, - { - { - {465152221, 31684687}, - {457606880, 31688302}, - {452659362, 35508617}, - {449044605, 34734089}, - {446478972, 31692751}, - {437784814, 31692957}, - {435521210, 33956565}, - {435532195, 65697616}, - {426028494, 65691361}, - {426025938, 85049712}, - {435532195, 95717636}, - {435524445, 103754026}, - {436995898, 105225463}, - {447552204, 105226323}, - {447552215, 103197497}, - {444552215, 103197616}, - {444552215, 99217636}, - {452032195, 99217636}, - {452032195, 105221758}, - {465588513, 105225463}, - {467059965, 103754026}, - {467052215, 95717636}, - {478053039, 84511285}, - {478056214, 65697616}, - {468552215, 65697616}, - {468563959, 33957323}, - {465152221, 31684687}, - }, - { - }, - }, - { - { - {764927063, 92658416}, - {762115426, 94171595}, - {762122741, 131696443}, - {786415417, 132779578}, - {793690904, 129904572}, - {797383202, 124822853}, - {798269157, 120142660}, - {796710161, 114090278}, - {793387498, 110215980}, - {796094093, 103892242}, - {794107594, 96994001}, - {787445494, 92840355}, - {764927063, 92658416}, - }, - { - }, - }, - { - { - {27496331, 123147467}, - {3202195, 124246400}, - {3203433, 205768600}, - {20223453, 205775606}, - {20223644, 163243606}, - {31297341, 162189074}, - {36789517, 155659691}, - {36967183, 150566416}, - {34468182, 145711036}, - {38465496, 140400171}, - {38952460, 132613091}, - {34771593, 126022444}, - {27496331, 123147467}, - }, - { - }, - }, - { - { - {797556553, 39197820}, - {791313598, 39199767}, - {789506233, 39864015}, - {789522521, 48199767}, - {775974570, 48195721}, - {774022521, 50129235}, - {774008720, 76258022}, - {775974570, 78223833}, - {789522521, 78219787}, - {789522521, 86576919}, - {797556547, 87221747}, - {797556553, 39197820}, - }, - { - }, - }, - { - { - {676593113, 129820144}, - {676565322, 164844636}, - {701599609, 164858650}, - {701599609, 129823260}, - {676593113, 129820144}, - }, - { - }, - }, - { - { - {727646871, 93121321}, - {709122741, 93122138}, - {709122741, 125656310}, - {718769809, 135145243}, - {721622937, 135156111}, - {724152429, 132626619}, - {723734126, 112688301}, - {725837154, 107378546}, - {728976138, 104430846}, - {735847924, 102664848}, - {741289364, 104430846}, - {745202882, 108599767}, - {746590596, 114642158}, - {751137173, 114644887}, - {756151199, 109641674}, - {756149037, 94634278}, - {754642761, 93122138}, - {727646871, 93121321}, - }, - { - }, - }, - { - { - {135915724, 185598906}, - {131396265, 193419009}, - {131399444, 197643260}, - {140399444, 197636810}, - {140399444, 199138818}, - {157419464, 197643916}, - {157422805, 193210743}, - {153046747, 185604789}, - {149044579, 185614655}, - {147324399, 189850396}, - {144168954, 191108901}, - {141187892, 189479768}, - {139917659, 185615382}, - {135915724, 185598906}, - }, - { - }, - }, - { - { - {312619110, 154485844}, - {309601817, 157488332}, - {309599764, 203494810}, - {313109244, 207010010}, - {352900849, 207019221}, - {359629120, 200302405}, - {359638705, 159501827}, - {354621096, 154487830}, - {312619110, 154485844}, - }, - { - }, - }, - { - { - {313120315, 98984639}, - {309609100, 102486971}, - {309596977, 148492024}, - {312591195, 151510010}, - {354608772, 151524494}, - {359629120, 146515788}, - {359638123, 105715491}, - {352907860, 98987790}, - {313120315, 98984639}, - }, - { - }, - }, - { - { - {657746643, 86246732}, - {651722477, 92270881}, - {651720052, 131280884}, - {653947196, 131280884}, - {659746643, 125487816}, - {659746643, 119273826}, - {663742413, 112352691}, - {671726623, 112352691}, - {675733721, 119283349}, - {684745297, 119298573}, - {689758503, 114263168}, - {689752066, 91272158}, - {684746643, 86260871}, - {657746643, 86246732}, - }, - { - }, - }, - { - { - {653940791, 39260871}, - {651720052, 39260871}, - {651726623, 78280611}, - {657746631, 84295035}, - {684746643, 84280891}, - {689752066, 79269604}, - {689746643, 56247942}, - {684745283, 51243184}, - {675733721, 51258413}, - {671726623, 58189071}, - {663742413, 58189071}, - {659746643, 51267936}, - {659746643, 45053950}, - {653940791, 39260871}, - }, - { - }, - }, - { - { - {442365208, 3053303}, - {436408500, 5694021}, - {434342552, 11072741}, - {436986326, 17009033}, - {442365367, 19073360}, - {448299202, 16431441}, - {450365150, 11052721}, - {448299202, 5694021}, - {442365208, 3053303}, - }, - { - }, - }, -}; diff --git a/src/libnest2d/tests/printer_parts.h b/src/libnest2d/tests/printer_parts.h deleted file mode 100644 index 1e65826bd..000000000 --- a/src/libnest2d/tests/printer_parts.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef PRINTER_PARTS_H -#define PRINTER_PARTS_H - -#include -#include - -using TestData = std::vector; -using TestDataEx = std::vector; - -extern const TestData PRINTER_PART_POLYGONS; -extern const TestData STEGOSAUR_POLYGONS; -extern const TestDataEx PRINTER_PART_POLYGONS_EX; - -#endif // PRINTER_PARTS_H diff --git a/src/libnest2d/tests/test.cpp b/src/libnest2d/tests/test.cpp deleted file mode 100644 index 5ba28228a..000000000 --- a/src/libnest2d/tests/test.cpp +++ /dev/null @@ -1,1062 +0,0 @@ -#include -#include - -#include -#include "printer_parts.h" -//#include -#include "../tools/svgtools.hpp" -#include - -#if defined(_MSC_VER) && defined(__clang__) -#define BOOST_NO_CXX17_HDR_STRING_VIEW -#endif - -#include "boost/multiprecision/integer.hpp" -#include "boost/rational.hpp" - -//#include "../tools/libnfpglue.hpp" -//#include "../tools/nfp_svgnest_glue.hpp" - -namespace libnest2d { -#if !defined(_MSC_VER) && defined(__SIZEOF_INT128__) && !defined(__APPLE__) -using LargeInt = __int128; -#else -using LargeInt = boost::multiprecision::int128_t; -template<> struct _NumTag { using Type = ScalarTag; }; -#endif -template struct _NumTag> { using Type = RationalTag; }; - -namespace nfp { - -template -struct NfpImpl -{ - NfpResult operator()(const S &sh, const S &other) - { - return nfpConvexOnly>(sh, other); - } -}; - -} -} - -static std::vector& prusaParts() { - static std::vector ret; - - if(ret.empty()) { - ret.reserve(PRINTER_PART_POLYGONS.size()); - for(auto& inp : PRINTER_PART_POLYGONS) ret.emplace_back(inp); - } - - return ret; -} - -TEST(GeometryAlgorithms, Angles) -{ - - using namespace libnest2d; - - Degrees deg(180); - Radians rad(deg); - Degrees deg2(rad); - - ASSERT_DOUBLE_EQ(rad, Pi); - ASSERT_DOUBLE_EQ(deg, 180); - ASSERT_DOUBLE_EQ(deg2, 180); - ASSERT_DOUBLE_EQ(rad, Radians(deg)); - ASSERT_DOUBLE_EQ( Degrees(rad), deg); - - ASSERT_TRUE(rad == deg); - - Segment seg = {{0, 0}, {12, -10}}; - - ASSERT_TRUE(Degrees(seg.angleToXaxis()) > 270 && - Degrees(seg.angleToXaxis()) < 360); - - seg = {{0, 0}, {12, 10}}; - - ASSERT_TRUE(Degrees(seg.angleToXaxis()) > 0 && - Degrees(seg.angleToXaxis()) < 90); - - seg = {{0, 0}, {-12, 10}}; - - ASSERT_TRUE(Degrees(seg.angleToXaxis()) > 90 && - Degrees(seg.angleToXaxis()) < 180); - - seg = {{0, 0}, {-12, -10}}; - - ASSERT_TRUE(Degrees(seg.angleToXaxis()) > 180 && - Degrees(seg.angleToXaxis()) < 270); - - seg = {{0, 0}, {1, 0}}; - - ASSERT_DOUBLE_EQ(Degrees(seg.angleToXaxis()), 0); - - seg = {{0, 0}, {0, 1}}; - - ASSERT_DOUBLE_EQ(Degrees(seg.angleToXaxis()), 90); - - - seg = {{0, 0}, {-1, 0}}; - - ASSERT_DOUBLE_EQ(Degrees(seg.angleToXaxis()), 180); - - - seg = {{0, 0}, {0, -1}}; - - ASSERT_DOUBLE_EQ(Degrees(seg.angleToXaxis()), 270); - -} - -// Simple test, does not use gmock -TEST(Nesting, ItemCreationAndDestruction) -{ - using namespace libnest2d; - - Item sh = { {0, 0}, {1, 0}, {1, 1}, {0, 1} }; - - ASSERT_EQ(sh.vertexCount(), 4u); - - Item sh2 ({ {0, 0}, {1, 0}, {1, 1}, {0, 1} }); - - ASSERT_EQ(sh2.vertexCount(), 4u); - - // copy - Item sh3 = sh2; - - ASSERT_EQ(sh3.vertexCount(), 4u); - - sh2 = {}; - - ASSERT_EQ(sh2.vertexCount(), 0u); - ASSERT_EQ(sh3.vertexCount(), 4u); - -} - -TEST(GeometryAlgorithms, boundingCircle) { - using namespace libnest2d; - using placers::boundingCircle; - - PolygonImpl p = {{{0, 10}, {10, 0}, {0, -10}, {0, 10}}, {}}; - Circle c = boundingCircle(p); - - ASSERT_EQ(c.center().X, 0); - ASSERT_EQ(c.center().Y, 0); - ASSERT_DOUBLE_EQ(c.radius(), 10); - - shapelike::translate(p, PointImpl{10, 10}); - c = boundingCircle(p); - - ASSERT_EQ(c.center().X, 10); - ASSERT_EQ(c.center().Y, 10); - ASSERT_DOUBLE_EQ(c.radius(), 10); - - auto parts = prusaParts(); - - int i = 0; - for(auto& part : parts) { - c = boundingCircle(part.transformedShape()); - if(std::isnan(c.radius())) std::cout << "fail: radius is nan" << std::endl; - - else for(auto v : shapelike::contour(part.transformedShape()) ) { - auto d = pointlike::distance(v, c.center()); - if(d > c.radius() ) { - auto e = std::abs( 1.0 - d/c.radius()); - ASSERT_LE(e, 1e-3); - } - } - i++; - } - -} - -TEST(GeometryAlgorithms, Distance) { - using namespace libnest2d; - - Point p1 = {0, 0}; - - Point p2 = {10, 0}; - Point p3 = {10, 10}; - - ASSERT_DOUBLE_EQ(pointlike::distance(p1, p2), 10); - ASSERT_DOUBLE_EQ(pointlike::distance(p1, p3), sqrt(200)); - - Segment seg(p1, p3); - - // ASSERT_DOUBLE_EQ(pointlike::distance(p2, seg), 7.0710678118654755); - - auto result = pointlike::horizontalDistance(p2, seg); - - auto check = [](TCompute val, TCompute expected) { - if(std::is_floating_point>::value) - ASSERT_DOUBLE_EQ(static_cast(val), - static_cast(expected)); - else - ASSERT_EQ(val, expected); - }; - - ASSERT_TRUE(result.second); - check(result.first, 10); - - result = pointlike::verticalDistance(p2, seg); - ASSERT_TRUE(result.second); - check(result.first, -10); - - result = pointlike::verticalDistance(Point{10, 20}, seg); - ASSERT_TRUE(result.second); - check(result.first, 10); - - - Point p4 = {80, 0}; - Segment seg2 = { {0, 0}, {0, 40} }; - - result = pointlike::horizontalDistance(p4, seg2); - - ASSERT_TRUE(result.second); - check(result.first, 80); - - result = pointlike::verticalDistance(p4, seg2); - // Point should not be related to the segment - ASSERT_FALSE(result.second); - -} - -TEST(GeometryAlgorithms, Area) { - using namespace libnest2d; - - Rectangle rect(10, 10); - - ASSERT_EQ(rect.area(), 100); - - Rectangle rect2 = {100, 100}; - - ASSERT_EQ(rect2.area(), 10000); - - Item item = { - {61, 97}, - {70, 151}, - {176, 151}, - {189, 138}, - {189, 59}, - {70, 59}, - {61, 77}, - {61, 97} - }; - - ASSERT_TRUE(shapelike::area(item.transformedShape()) > 0 ); -} - -TEST(GeometryAlgorithms, IsPointInsidePolygon) { - using namespace libnest2d; - - Rectangle rect(10, 10); - - Point p = {1, 1}; - - ASSERT_TRUE(rect.isInside(p)); - - p = {11, 11}; - - ASSERT_FALSE(rect.isInside(p)); - - - p = {11, 12}; - - ASSERT_FALSE(rect.isInside(p)); - - - p = {3, 3}; - - ASSERT_TRUE(rect.isInside(p)); - -} - -//TEST(GeometryAlgorithms, Intersections) { -// using namespace binpack2d; - -// Rectangle rect(70, 30); - -// rect.translate({80, 60}); - -// Rectangle rect2(80, 60); -// rect2.translate({80, 0}); - -//// ASSERT_FALSE(Item::intersects(rect, rect2)); - -// Segment s1({0, 0}, {10, 10}); -// Segment s2({1, 1}, {11, 11}); -// ASSERT_FALSE(ShapeLike::intersects(s1, s1)); -// ASSERT_FALSE(ShapeLike::intersects(s1, s2)); -//} - -// Simple test, does not use gmock -TEST(GeometryAlgorithms, LeftAndDownPolygon) -{ - using namespace libnest2d; - using namespace libnest2d; - - Box bin(100, 100); - BottomLeftPlacer placer(bin); - - Item item = {{70, 75}, {88, 60}, {65, 50}, {60, 30}, {80, 20}, {42, 20}, - {35, 35}, {35, 55}, {40, 75}, {70, 75}}; - - Item leftControl = { {40, 75}, - {35, 55}, - {35, 35}, - {42, 20}, - {0, 20}, - {0, 75}, - {40, 75}}; - - Item downControl = {{88, 60}, - {88, 0}, - {35, 0}, - {35, 35}, - {42, 20}, - {80, 20}, - {60, 30}, - {65, 50}, - {88, 60}}; - - Item leftp(placer.leftPoly(item)); - - ASSERT_TRUE(shapelike::isValid(leftp.rawShape()).first); - ASSERT_EQ(leftp.vertexCount(), leftControl.vertexCount()); - - for(unsigned long i = 0; i < leftControl.vertexCount(); i++) { - ASSERT_EQ(getX(leftp.vertex(i)), getX(leftControl.vertex(i))); - ASSERT_EQ(getY(leftp.vertex(i)), getY(leftControl.vertex(i))); - } - - Item downp(placer.downPoly(item)); - - ASSERT_TRUE(shapelike::isValid(downp.rawShape()).first); - ASSERT_EQ(downp.vertexCount(), downControl.vertexCount()); - - for(unsigned long i = 0; i < downControl.vertexCount(); i++) { - ASSERT_EQ(getX(downp.vertex(i)), getX(downControl.vertex(i))); - ASSERT_EQ(getY(downp.vertex(i)), getY(downControl.vertex(i))); - } -} - -// Simple test, does not use gmock -TEST(GeometryAlgorithms, ArrangeRectanglesTight) -{ - using namespace libnest2d; - - std::vector rects = { - {80, 80}, - {60, 90}, - {70, 30}, - {80, 60}, - {60, 60}, - {60, 40}, - {40, 40}, - {10, 10}, - {10, 10}, - {10, 10}, - {10, 10}, - {10, 10}, - {5, 5}, - {5, 5}, - {5, 5}, - {5, 5}, - {5, 5}, - {5, 5}, - {5, 5}, - {20, 20} }; - - Box bin(210, 250, {105, 125}); - - ASSERT_EQ(bin.width(), 210); - ASSERT_EQ(bin.height(), 250); - ASSERT_EQ(getX(bin.center()), 105); - ASSERT_EQ(getY(bin.center()), 125); - - _Nester arrange(bin); - - arrange.execute(rects.begin(), rects.end()); - - auto max_group = std::max_element(rects.begin(), rects.end(), - [](const Item &i1, const Item &i2) { - return i1.binId() < i2.binId(); - }); - - int groups = max_group == rects.end() ? 0 : max_group->binId() + 1; - - ASSERT_EQ(groups, 1u); - ASSERT_TRUE( - std::all_of(rects.begin(), rects.end(), [](const Rectangle &itm) { - return itm.binId() != BIN_ID_UNSET; - })); - - // check for no intersections, no containment: - - bool valid = true; - for(Item& r1 : rects) { - for(Item& r2 : rects) { - if(&r1 != &r2 ) { - valid = !Item::intersects(r1, r2) || Item::touches(r1, r2); - ASSERT_TRUE(valid); - valid = (valid && !r1.isInside(r2) && !r2.isInside(r1)); - ASSERT_TRUE(valid); - } - } - } -} - -TEST(GeometryAlgorithms, ArrangeRectanglesLoose) -{ - using namespace libnest2d; - - // std::vector rects = { {40, 40}, {10, 10}, {20, 20} }; - std::vector rects = { - {80, 80}, - {60, 90}, - {70, 30}, - {80, 60}, - {60, 60}, - {60, 40}, - {40, 40}, - {10, 10}, - {10, 10}, - {10, 10}, - {10, 10}, - {10, 10}, - {5, 5}, - {5, 5}, - {5, 5}, - {5, 5}, - {5, 5}, - {5, 5}, - {5, 5}, - {20, 20} }; - - Box bin(210, 250, {105, 125}); - - ASSERT_EQ(bin.width(), 210); - ASSERT_EQ(bin.height(), 250); - ASSERT_EQ(getX(bin.center()), 105); - ASSERT_EQ(getY(bin.center()), 125); - - Coord min_obj_distance = 5; - - _Nester arrange(bin, min_obj_distance); - - arrange.execute(rects.begin(), rects.end()); - - auto max_group = std::max_element(rects.begin(), rects.end(), - [](const Item &i1, const Item &i2) { - return i1.binId() < i2.binId(); - }); - - size_t groups = max_group == rects.end() ? 0 : max_group->binId() + 1; - - ASSERT_EQ(groups, 1u); - ASSERT_TRUE( - std::all_of(rects.begin(), rects.end(), [](const Rectangle &itm) { - return itm.binId() != BIN_ID_UNSET; - })); - - // check for no intersections, no containment: - bool valid = true; - for(Item& r1 : rects) { - for(Item& r2 : rects) { - if(&r1 != &r2 ) { - valid = !Item::intersects(r1, r2); - valid = (valid && !r1.isInside(r2) && !r2.isInside(r1)); - ASSERT_TRUE(valid); - } - } - } - -} - -namespace { -using namespace libnest2d; - -template -void exportSVG(std::vector>& result, const Bin& bin, int idx = 0) { - - - std::string loc = "out"; - - static std::string svg_header = - R"raw( - - -)raw"; - - int i = idx; - auto r = result; - // for(auto r : result) { - std::fstream out(loc + std::to_string(i) + ".svg", std::fstream::out); - if(out.is_open()) { - out << svg_header; - Item rbin( Rectangle(bin.width(), bin.height()) ); - for(unsigned i = 0; i < rbin.vertexCount(); i++) { - auto v = rbin.vertex(i); - setY(v, -getY(v)/SCALE + 500 ); - setX(v, getX(v)/SCALE); - rbin.setVertex(i, v); - } - out << shapelike::serialize(rbin.rawShape()) << std::endl; - for(Item& sh : r) { - Item tsh(sh.transformedShape()); - for(unsigned i = 0; i < tsh.vertexCount(); i++) { - auto v = tsh.vertex(i); - setY(v, -getY(v)/SCALE + 500); - setX(v, getX(v)/SCALE); - tsh.setVertex(i, v); - } - out << shapelike::serialize(tsh.rawShape()) << std::endl; - } - out << "\n" << std::endl; - } - out.close(); - - // i++; - // } -} -} - -TEST(GeometryAlgorithms, BottomLeftStressTest) { - using namespace libnest2d; - - const Coord SCALE = 1000000; - auto& input = prusaParts(); - - Box bin(210*SCALE, 250*SCALE); - BottomLeftPlacer placer(bin); - - auto it = input.begin(); - auto next = it; - int i = 0; - while(it != input.end() && ++next != input.end()) { - placer.pack(*it); - placer.pack(*next); - - auto result = placer.getItems(); - bool valid = true; - - if(result.size() == 2) { - Item& r1 = result[0]; - Item& r2 = result[1]; - valid = !Item::intersects(r1, r2) || Item::touches(r1, r2); - valid = (valid && !r1.isInside(r2) && !r2.isInside(r1)); - if(!valid) { - std::cout << "error index: " << i << std::endl; - exportSVG(result, bin, i); - } - ASSERT_TRUE(valid); - } else { - std::cout << "something went terribly wrong!" << std::endl; - FAIL(); - } - - placer.clearItems(); - it++; - i++; - } -} - -TEST(GeometryAlgorithms, convexHull) { - using namespace libnest2d; - - ClipperLib::Path poly = PRINTER_PART_POLYGONS[0]; - - auto chull = sl::convexHull(poly); - - ASSERT_EQ(chull.size(), poly.size()); -} - - -TEST(Nesting, NestPrusaPartsShouldFitIntoTwoBins) { - - // Get the input items and define the bin. - std::vector input = prusaParts(); - auto bin = Box(250000000, 210000000); - - // Do the nesting. Check in each step if the remaining items are less than - // in the previous step. (Some algorithms can place more items in one step) - size_t pcount = input.size(); - libnest2d::nest(input, bin, [&pcount](unsigned cnt) { - ASSERT_TRUE(cnt < pcount); - pcount = cnt; - }); - - // Get the number of logical bins: search for the max binId... - auto max_binid_it = std::max_element(input.begin(), input.end(), - [](const Item &i1, const Item &i2) { - return i1.binId() < i2.binId(); - }); - - auto bins = size_t(max_binid_it == input.end() ? 0 : - max_binid_it->binId() + 1); - - // For prusa parts, 2 bins should be enough... - ASSERT_LE(bins, 2u); - - // All parts should be processed by the algorithm - ASSERT_TRUE( - std::all_of(input.begin(), input.end(), [](const Item &itm) { - return itm.binId() != BIN_ID_UNSET; - })); - - // Gather the items into piles of arranged polygons... - using Pile = TMultiShape; - std::vector piles(bins); - - for (auto &itm : input) - piles[size_t(itm.binId())].emplace_back(itm.transformedShape()); - - // Now check all the piles, the bounding box of each pile should be inside - // the defined bin. - for (auto &pile : piles) { - auto bb = sl::boundingBox(pile); - ASSERT_TRUE(sl::isInside(bb, bin)); - } -} - -TEST(Nesting, NestEmptyItemShouldBeUntouched) { - auto bin = Box(250000000, 210000000); // dummy bin - - std::vector items; - items.emplace_back(Item{}); // Emplace empty item - items.emplace_back(Item{0, 200, 0}); // Emplace zero area item - - libnest2d::nest(items, bin); - - for (auto &itm : items) ASSERT_EQ(itm.binId(), BIN_ID_UNSET); -} - -TEST(Nesting, NestLargeItemShouldBeUntouched) { - auto bin = Box(250000000, 210000000); // dummy bin - - std::vector items; - items.emplace_back(Rectangle{250000001, 210000001}); // Emplace large item - - libnest2d::nest(items, bin); - - ASSERT_EQ(items.front().binId(), BIN_ID_UNSET); -} - -namespace { - -struct ItemPair { - Item orbiter; - Item stationary; -}; - -std::vector nfp_testdata = { - { - { - {80, 50}, - {100, 70}, - {120, 50}, - {80, 50} - }, - { - {10, 10}, - {10, 40}, - {40, 40}, - {40, 10}, - {10, 10} - } - }, - { - { - {80, 50}, - {60, 70}, - {80, 90}, - {120, 90}, - {140, 70}, - {120, 50}, - {80, 50} - }, - { - {10, 10}, - {10, 40}, - {40, 40}, - {40, 10}, - {10, 10} - } - }, - { - { - {40, 10}, - {30, 10}, - {20, 20}, - {20, 30}, - {30, 40}, - {40, 40}, - {50, 30}, - {50, 20}, - {40, 10} - }, - { - {80, 0}, - {80, 30}, - {110, 30}, - {110, 0}, - {80, 0} - } - }, - { - { - {117, 107}, - {118, 109}, - {120, 112}, - {122, 113}, - {128, 113}, - {130, 112}, - {132, 109}, - {133, 107}, - {133, 103}, - {132, 101}, - {130, 98}, - {128, 97}, - {122, 97}, - {120, 98}, - {118, 101}, - {117, 103}, - {117, 107} - }, - { - {102, 116}, - {111, 126}, - {114, 126}, - {144, 106}, - {148, 100}, - {148, 85}, - {147, 84}, - {102, 84}, - {102, 116}, - } - }, - { - { - {99, 122}, - {108, 140}, - {110, 142}, - {139, 142}, - {151, 122}, - {151, 102}, - {142, 70}, - {139, 68}, - {111, 68}, - {108, 70}, - {99, 102}, - {99, 122}, - }, - { - {107, 124}, - {128, 125}, - {133, 125}, - {136, 124}, - {140, 121}, - {142, 119}, - {143, 116}, - {143, 109}, - {141, 93}, - {139, 89}, - {136, 86}, - {134, 85}, - {108, 85}, - {107, 86}, - {107, 124}, - } - }, - { - { - {91, 100}, - {94, 144}, - {117, 153}, - {118, 153}, - {159, 112}, - {159, 110}, - {156, 66}, - {133, 57}, - {132, 57}, - {91, 98}, - {91, 100}, - }, - { - {101, 90}, - {103, 98}, - {107, 113}, - {114, 125}, - {115, 126}, - {135, 126}, - {136, 125}, - {144, 114}, - {149, 90}, - {149, 89}, - {148, 87}, - {145, 84}, - {105, 84}, - {102, 87}, - {101, 89}, - {101, 90}, - } - } -}; - - std::vector nfp_concave_testdata = { - { // ItemPair - { - { - {533726, 142141}, - {532359, 143386}, - {530141, 142155}, - {528649, 160091}, - {533659, 157607}, - {538669, 160091}, - {537178, 142155}, - {534959, 143386}, - {533726, 142141}, - } - }, - { - { - {118305, 11603}, - {118311, 26616}, - {113311, 26611}, - {109311, 29604}, - {109300, 44608}, - {109311, 49631}, - {113300, 52636}, - {118311, 52636}, - {118308, 103636}, - {223830, 103636}, - {236845, 90642}, - {236832, 11630}, - {232825, 11616}, - {210149, 11616}, - {211308, 13625}, - {209315, 17080}, - {205326, 17080}, - {203334, 13629}, - {204493, 11616}, - {118305, 11603}, - } - }, - } -}; - -template -void testNfp(const std::vector& testdata) { - using namespace libnest2d; - - Box bin(210*SCALE, 250*SCALE); - - int testcase = 0; - - auto& exportfun = exportSVG; - - auto onetest = [&](Item& orbiter, Item& stationary, unsigned /*testidx*/){ - testcase++; - - orbiter.translate({210*SCALE, 0}); - - auto&& nfp = nfp::noFitPolygon(stationary.rawShape(), - orbiter.transformedShape()); - - placers::correctNfpPosition(nfp, stationary, orbiter); - - auto valid = shapelike::isValid(nfp.first); - - /*Item infp(nfp.first); - if(!valid.first) { - std::cout << "test instance: " << testidx << " " - << valid.second << std::endl; - std::vector> inp = {std::ref(infp)}; - exportfun(inp, bin, testidx); - }*/ - - ASSERT_TRUE(valid.first); - - Item infp(nfp.first); - - int i = 0; - auto rorbiter = orbiter.transformedShape(); - auto vo = nfp::referenceVertex(rorbiter); - - ASSERT_TRUE(stationary.isInside(infp)); - - for(auto v : infp) { - auto dx = getX(v) - getX(vo); - auto dy = getY(v) - getY(vo); - - Item tmp = orbiter; - - tmp.translate({dx, dy}); - - bool touching = Item::touches(tmp, stationary); - - if(!touching || !valid.first) { - std::vector> inp = { - std::ref(stationary), std::ref(tmp), std::ref(infp) - }; - - exportfun(inp, bin, testcase*i++); - } - - ASSERT_TRUE(touching); - } - }; - - unsigned tidx = 0; - for(auto& td : testdata) { - auto orbiter = td.orbiter; - auto stationary = td.stationary; - onetest(orbiter, stationary, tidx++); - } - - tidx = 0; - for(auto& td : testdata) { - auto orbiter = td.stationary; - auto stationary = td.orbiter; - onetest(orbiter, stationary, tidx++); - } -} -} - -TEST(GeometryAlgorithms, nfpConvexConvex) { - testNfp(nfp_testdata); -} - -//TEST(GeometryAlgorithms, nfpConcaveConcave) { -// testNfp(nfp_concave_testdata); -//} - -TEST(GeometryAlgorithms, pointOnPolygonContour) { - using namespace libnest2d; - - Rectangle input(10, 10); - - placers::EdgeCache ecache(input); - - auto first = *input.begin(); - ASSERT_TRUE(getX(first) == getX(ecache.coords(0))); - ASSERT_TRUE(getY(first) == getY(ecache.coords(0))); - - auto last = *std::prev(input.end()); - ASSERT_TRUE(getX(last) == getX(ecache.coords(1.0))); - ASSERT_TRUE(getY(last) == getY(ecache.coords(1.0))); - - for(int i = 0; i <= 100; i++) { - auto v = ecache.coords(i*(0.01)); - ASSERT_TRUE(shapelike::touches(v, input.transformedShape())); - } -} - -TEST(GeometryAlgorithms, mergePileWithPolygon) { - using namespace libnest2d; - - Rectangle rect1(10, 15); - Rectangle rect2(15, 15); - Rectangle rect3(20, 15); - - rect2.translate({10, 0}); - rect3.translate({25, 0}); - - TMultiShape pile; - pile.push_back(rect1.transformedShape()); - pile.push_back(rect2.transformedShape()); - - auto result = nfp::merge(pile, rect3.transformedShape()); - - ASSERT_EQ(result.size(), 1); - - Rectangle ref(45, 15); - - ASSERT_EQ(shapelike::area(result.front()), ref.area()); -} - -namespace { - -long double refMinAreaBox(const PolygonImpl& p) { - - auto it = sl::cbegin(p), itx = std::next(it); - - long double min_area = std::numeric_limits::max(); - - - auto update_min = [&min_area, &it, &itx, &p]() { - Segment s(*it, *itx); - - PolygonImpl rotated = p; - sl::rotate(rotated, -s.angleToXaxis()); - auto bb = sl::boundingBox(rotated); - auto area = cast(sl::area(bb)); - if(min_area > area) min_area = area; - }; - - while(itx != sl::cend(p)) { - update_min(); - ++it; ++itx; - } - - it = std::prev(sl::cend(p)); itx = sl::cbegin(p); - update_min(); - - return min_area; -} - -template struct BoostGCD { - T operator()(const T &a, const T &b) { return boost::gcd(a, b); } -}; - -using Unit = int64_t; -using Ratio = boost::rational; - -} - -//TEST(GeometryAlgorithms, MinAreaBBCClk) { -// auto u = [](ClipperLib::cInt n) { return n*1000000; }; -// PolygonImpl poly({ {u(0), u(0)}, {u(4), u(1)}, {u(2), u(4)}}); - -// long double arearef = refMinAreaBox(poly); -// long double area = minAreaBoundingBox(poly).area(); - -// ASSERT_LE(std::abs(area - arearef), 500e6 ); -//} - -TEST(GeometryAlgorithms, MinAreaBBWithRotatingCalipers) { - long double err_epsilon = 500e6l; - - for(ClipperLib::Path rinput : PRINTER_PART_POLYGONS) { - PolygonImpl poly(rinput); - - long double arearef = refMinAreaBox(poly); - auto bb = minAreaBoundingBox(rinput); - long double area = cast(bb.area()); - - bool succ = std::abs(arearef - area) < err_epsilon; - - ASSERT_TRUE(succ); - } - - for(ClipperLib::Path rinput : STEGOSAUR_POLYGONS) { - rinput.pop_back(); - std::reverse(rinput.begin(), rinput.end()); - - PolygonImpl poly(removeCollinearPoints(rinput, 1000000)); - - long double arearef = refMinAreaBox(poly); - auto bb = minAreaBoundingBox(poly); - long double area = cast(bb.area()); - - - bool succ = std::abs(arearef - area) < err_epsilon; - - ASSERT_TRUE(succ); - } -} - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 633549b42..cbaa24e9c 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -204,7 +204,7 @@ if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY) add_precompiled_header(libslic3r pchheader.hpp FORCEINCLUDE) endif () -target_compile_definitions(libslic3r PUBLIC -DUSE_TBB) +target_compile_definitions(libslic3r PUBLIC -DUSE_TBB -DTBB_USE_CAPTURED_EXCEPTION=0) target_include_directories(libslic3r PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${LIBNEST2D_INCLUDES} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(libslic3r libnest2d @@ -221,7 +221,7 @@ target_link_libraries(libslic3r poly2tri qhull semver - tbb + TBB::tbb ${CMAKE_DL_LIBS} ) diff --git a/src/libslic3r/Time.cpp b/src/libslic3r/Time.cpp index 063dbb41c..8faa14ade 100644 --- a/src/libslic3r/Time.cpp +++ b/src/libslic3r/Time.cpp @@ -11,7 +11,7 @@ #include #endif -#include "libslic3r/Utils.hpp" +// #include "libslic3r/Utils.hpp" namespace Slic3r { namespace Utils { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e2eaebfb8..d22c81f2f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,23 +10,14 @@ target_include_directories(Catch2 INTERFACE ${CMAKE_CURRENT_LIST_DIR}) add_library(Catch2::Catch2 ALIAS Catch2) include(Catch) -add_library(test_catch2_common INTERFACE) -target_compile_definitions(test_catch2_common INTERFACE TEST_DATA_DIR=R"\(${TEST_DATA_DIR}\)" CATCH_CONFIG_FAST_COMPILE) -target_link_libraries(test_catch2_common INTERFACE Catch2::Catch2) - add_library(test_common INTERFACE) +target_compile_definitions(test_common INTERFACE TEST_DATA_DIR=R"\(${TEST_DATA_DIR}\)" CATCH_CONFIG_FAST_COMPILE) +target_link_libraries(test_common INTERFACE Catch2::Catch2) + if (APPLE) target_link_libraries(test_common INTERFACE "-liconv -framework IOKit" "-framework CoreFoundation" -lc++) endif() -target_link_libraries(test_common INTERFACE test_catch2_common) - -# DEPRECATED: -#find_package(GTest REQUIRED) -#add_library(test_gtest_common INTERFACE) -#target_compile_definitions(test_gtest_common INTERFACE TEST_DATA_DIR=R"\(${TEST_DATA_DIR}\)") -#target_link_libraries(test_gtest_common INTERFACE GTest::GTest GTest::Main) - add_subdirectory(libnest2d) add_subdirectory(timeutils) add_subdirectory(sla_print) diff --git a/tests/example/CMakeLists.txt b/tests/example/CMakeLists.txt index 95f5e3762..45e4bb28e 100644 --- a/tests/example/CMakeLists.txt +++ b/tests/example/CMakeLists.txt @@ -1,5 +1,7 @@ get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp) -target_link_libraries(${_TEST_NAME}_tests test_common libslic3r ${Boost_LIBRARIES} ${TBB_LIBRARIES} ${Boost_LIBRARIES}) +target_link_libraries(${_TEST_NAME}_tests test_common libslic3r +#${Boost_LIBRARIES} ${TBB_LIBRARIES} ${Boost_LIBRARIES} +) catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") diff --git a/tests/libnest2d/CMakeLists.txt b/tests/libnest2d/CMakeLists.txt index ee38280b5..6b2cbd194 100644 --- a/tests/libnest2d/CMakeLists.txt +++ b/tests/libnest2d/CMakeLists.txt @@ -1,6 +1,6 @@ get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp printer_parts.cpp printer_parts.hpp) -target_link_libraries(${_TEST_NAME}_tests test_common libslic3r ${Boost_LIBRARIES} ${TBB_LIBRARIES} ${Boost_LIBRARIES}) +target_link_libraries(${_TEST_NAME}_tests test_common libnest2d ) # catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "--durations yes") diff --git a/tests/libnest2d/libnest2d_tests_main.cpp b/tests/libnest2d/libnest2d_tests_main.cpp index 1741bb8d6..4eecb7e58 100644 --- a/tests/libnest2d/libnest2d_tests_main.cpp +++ b/tests/libnest2d/libnest2d_tests_main.cpp @@ -3,7 +3,7 @@ #include -#include +#include #include "printer_parts.hpp" //#include #include "../tools/svgtools.hpp" @@ -225,11 +225,11 @@ TEST_CASE("Area", "[Geometry]") { using namespace libnest2d; RectangleItem rect(10, 10); - + REQUIRE(rect.area() == Approx(100)); RectangleItem rect2 = {100, 100}; - + REQUIRE(rect2.area() == Approx(10000)); Item item = { @@ -447,7 +447,7 @@ TEST_CASE("ArrangeRectanglesLoose", "[Nesting]") [](const Item &i1, const Item &i2) { return i1.binId() < i2.binId(); }); - + auto groups = size_t(max_group == rects.end() ? 0 : max_group->binId() + 1); REQUIRE(groups == 1u); @@ -615,7 +615,7 @@ TEST_CASE("EmptyItemShouldBeUntouched", "[Nesting]") { items.emplace_back(Item{0, 200, 0}); // Emplace zero area item size_t bins = libnest2d::nest(items, bin); - + REQUIRE(bins == 0u); for (auto &itm : items) REQUIRE(itm.binId() == BIN_ID_UNSET); } @@ -627,57 +627,57 @@ TEST_CASE("LargeItemShouldBeUntouched", "[Nesting]") { items.emplace_back(RectangleItem{250000001, 210000001}); // Emplace large item size_t bins = libnest2d::nest(items, bin); - + REQUIRE(bins == 0u); REQUIRE(items.front().binId() == BIN_ID_UNSET); } TEST_CASE("Items can be preloaded", "[Nesting]") { auto bin = Box({0, 0}, {250000000, 210000000}); // dummy bin - + std::vector items; items.reserve(2); - + NestConfig<> cfg; cfg.placer_config.alignment = NestConfig<>::Placement::Alignment::DONT_ALIGN; - + items.emplace_back(RectangleItem{10000000, 10000000}); Item &fixed_rect = items.back(); fixed_rect.translate(bin.center()); - + items.emplace_back(RectangleItem{20000000, 20000000}); Item &movable_rect = items.back(); movable_rect.translate(bin.center()); - + SECTION("Preloaded Item should be untouched") { fixed_rect.markAsFixedInBin(0); - + size_t bins = libnest2d::nest(items, bin, 0, cfg); - + REQUIRE(bins == 1); - + REQUIRE(fixed_rect.binId() == 0); REQUIRE(fixed_rect.translation().X == bin.center().X); REQUIRE(fixed_rect.translation().Y == bin.center().Y); - + REQUIRE(movable_rect.binId() == 0); REQUIRE(movable_rect.translation().X != bin.center().X); - REQUIRE(movable_rect.translation().Y != bin.center().Y); + REQUIRE(movable_rect.translation().Y != bin.center().Y); } - + SECTION("Preloaded Item should not affect free bins") { fixed_rect.markAsFixedInBin(1); - + size_t bins = libnest2d::nest(items, bin, 0, cfg); - + REQUIRE(bins == 2); - + REQUIRE(fixed_rect.binId() == 1); REQUIRE(fixed_rect.translation().X == bin.center().X); REQUIRE(fixed_rect.translation().Y == bin.center().Y); - + REQUIRE(movable_rect.binId() == 0); - + auto bb = movable_rect.boundingBox(); REQUIRE(bb.center().X == bin.center().X); REQUIRE(bb.center().Y == bin.center().Y); @@ -1013,7 +1013,7 @@ TEST_CASE("mergePileWithPolygon", "[Geometry]") { REQUIRE(result.size() == 1); RectangleItem ref(45, 15); - + REQUIRE(shapelike::area(result.front()) == Approx(ref.area())); } diff --git a/tests/sla_print/CMakeLists.txt b/tests/sla_print/CMakeLists.txt index 687096ee4..077654273 100644 --- a/tests/sla_print/CMakeLists.txt +++ b/tests/sla_print/CMakeLists.txt @@ -1,6 +1,6 @@ get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests.cpp) -target_link_libraries(${_TEST_NAME}_tests test_common libslic3r ${Boost_LIBRARIES} ${TBB_LIBRARIES} ${Boost_LIBRARIES}) +target_link_libraries(${_TEST_NAME}_tests test_common libslic3r) #catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "--durations yes") diff --git a/tests/timeutils/CMakeLists.txt b/tests/timeutils/CMakeLists.txt index c4b7c2029..8dce85801 100644 --- a/tests/timeutils/CMakeLists.txt +++ b/tests/timeutils/CMakeLists.txt @@ -1,6 +1,10 @@ get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) -add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp) -target_link_libraries(${_TEST_NAME}_tests test_common libslic3r ${Boost_LIBRARIES} ${TBB_LIBRARIES} ${Boost_LIBRARIES}) +add_executable(${_TEST_NAME}_tests + ${_TEST_NAME}_tests_main.cpp + ${PROJECT_SOURCE_DIR}/src/libslic3r/Time.cpp + ${PROJECT_SOURCE_DIR}/src/libslic3r/Time.hpp + ) +target_link_libraries(${_TEST_NAME}_tests test_common) # catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "--durations yes") From cdc9fb0d8fd0901b7171887f24b435499a6476a4 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 14 Oct 2019 13:42:09 +0200 Subject: [PATCH 02/15] Force using TBB on all platforms for libnest2d --- src/libnest2d/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libnest2d/CMakeLists.txt b/src/libnest2d/CMakeLists.txt index ea2910511..6484da3d0 100644 --- a/src/libnest2d/CMakeLists.txt +++ b/src/libnest2d/CMakeLists.txt @@ -28,4 +28,4 @@ add_library(libnest2d ${LIBNEST2D_SRCFILES}) target_include_directories(libnest2d PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) target_link_libraries(libnest2d PUBLIC clipper NLopt::nlopt TBB::tbb Boost::boost) -target_compile_definitions(libnest2d PUBLIC LIBNEST2D_STATIC LIBNEST2D_OPTIMIZER_nlopt LIBNEST2D_GEOMETRIES_clipper) +target_compile_definitions(libnest2d PUBLIC USE_TBB LIBNEST2D_STATIC LIBNEST2D_OPTIMIZER_nlopt LIBNEST2D_GEOMETRIES_clipper) From 05431c0e6d2278e680ce4590a13e4b7e304c83ab Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 14 Oct 2019 14:58:07 +0200 Subject: [PATCH 03/15] Group test targets into logical "tests" directory. Disable DJDHeuristic --- tests/CMakeLists.txt | 2 ++ tests/example/CMakeLists.txt | 3 ++- tests/libnest2d/CMakeLists.txt | 1 + tests/libnest2d/libnest2d_tests_main.cpp | 5 +++-- tests/sla_print/CMakeLists.txt | 3 ++- tests/timeutils/CMakeLists.txt | 1 + 6 files changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d22c81f2f..6cbfd5432 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,6 +18,8 @@ if (APPLE) target_link_libraries(test_common INTERFACE "-liconv -framework IOKit" "-framework CoreFoundation" -lc++) endif() +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + add_subdirectory(libnest2d) add_subdirectory(timeutils) add_subdirectory(sla_print) diff --git a/tests/example/CMakeLists.txt b/tests/example/CMakeLists.txt index 45e4bb28e..d62f0a96c 100644 --- a/tests/example/CMakeLists.txt +++ b/tests/example/CMakeLists.txt @@ -4,4 +4,5 @@ target_link_libraries(${_TEST_NAME}_tests test_common libslic3r #${Boost_LIBRARIES} ${TBB_LIBRARIES} ${Boost_LIBRARIES} ) -catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") +# catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") +add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "--durations yes") \ No newline at end of file diff --git a/tests/libnest2d/CMakeLists.txt b/tests/libnest2d/CMakeLists.txt index 6b2cbd194..91a2e7852 100644 --- a/tests/libnest2d/CMakeLists.txt +++ b/tests/libnest2d/CMakeLists.txt @@ -1,6 +1,7 @@ get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp printer_parts.cpp printer_parts.hpp) target_link_libraries(${_TEST_NAME}_tests test_common libnest2d ) +set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") # catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "--durations yes") diff --git a/tests/libnest2d/libnest2d_tests_main.cpp b/tests/libnest2d/libnest2d_tests_main.cpp index 4eecb7e58..252bea47f 100644 --- a/tests/libnest2d/libnest2d_tests_main.cpp +++ b/tests/libnest2d/libnest2d_tests_main.cpp @@ -3,6 +3,7 @@ #include + #include #include "printer_parts.hpp" //#include @@ -371,7 +372,7 @@ TEST_CASE("ArrangeRectanglesTight", "[Nesting]") REQUIRE(getX(bin.center()) == 105); REQUIRE(getY(bin.center()) == 125); - _Nester arrange(bin); + _Nester arrange(bin); arrange.execute(rects.begin(), rects.end()); @@ -439,7 +440,7 @@ TEST_CASE("ArrangeRectanglesLoose", "[Nesting]") Coord min_obj_distance = 5; - _Nester arrange(bin, min_obj_distance); + _Nester arrange(bin, min_obj_distance); arrange.execute(rects.begin(), rects.end()); diff --git a/tests/sla_print/CMakeLists.txt b/tests/sla_print/CMakeLists.txt index 077654273..d0b51a01d 100644 --- a/tests/sla_print/CMakeLists.txt +++ b/tests/sla_print/CMakeLists.txt @@ -1,6 +1,7 @@ get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests.cpp) target_link_libraries(${_TEST_NAME}_tests test_common libslic3r) +set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") -#catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") +# catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "--durations yes") diff --git a/tests/timeutils/CMakeLists.txt b/tests/timeutils/CMakeLists.txt index 8dce85801..b67ce85f1 100644 --- a/tests/timeutils/CMakeLists.txt +++ b/tests/timeutils/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(${_TEST_NAME}_tests ${PROJECT_SOURCE_DIR}/src/libslic3r/Time.hpp ) target_link_libraries(${_TEST_NAME}_tests test_common) +set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") # catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "--durations yes") From a7c843d2132c39fe699423af1a4fe44a86e4ff8d Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 14 Oct 2019 15:48:29 +0200 Subject: [PATCH 04/15] Fix the missing link dependencies for tbb on Linux --- cmake/modules/FindTBB.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/modules/FindTBB.cmake b/cmake/modules/FindTBB.cmake index 153e615eb..b09bafda3 100644 --- a/cmake/modules/FindTBB.cmake +++ b/cmake/modules/FindTBB.cmake @@ -290,6 +290,11 @@ if(NOT TBB_FOUND) IMPORTED_LOCATION_MINSIZEREL ${TBB_LIBRARIES_RELEASE} ) endif() + + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + find_package(Threads QUIET REQUIRED) + set_target_properties(TBB::tbb PROPERTIES INTERFACE_LINK_LIBRARIES "${CMAKE_DL_LIBS};Threads::Threads") + endif() endif() mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARIES) From 42a858b9999384272457f175849e15f80b65882c Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 15 Oct 2019 09:40:40 +0200 Subject: [PATCH 05/15] Added test projects for libslic3r and fff_print. Added test_geometry.cpp from upstream slic3r, thanks @lordofhyphens Added circle_taubin_newton() for circle center calculation, thanks @lordofhyphens --- src/libslic3r/Geometry.cpp | 88 +++++++ src/libslic3r/Geometry.hpp | 9 + src/libslic3r/Line.cpp | 6 +- src/libslic3r/Point.hpp | 24 +- src/libslic3r/Polygon.cpp | 10 +- tests/CMakeLists.txt | 3 +- tests/fff_print/CMakeLists.txt | 7 + tests/fff_print/fff_print_tests.cpp | 15 ++ tests/libslic3r/CMakeLists.txt | 10 + tests/libslic3r/libslic3r_tests.cpp | 15 ++ tests/libslic3r/test_geometry.cpp | 375 ++++++++++++++++++++++++++++ 11 files changed, 548 insertions(+), 14 deletions(-) create mode 100644 tests/fff_print/CMakeLists.txt create mode 100644 tests/fff_print/fff_print_tests.cpp create mode 100644 tests/libslic3r/CMakeLists.txt create mode 100644 tests/libslic3r/libslic3r_tests.cpp create mode 100644 tests/libslic3r/test_geometry.cpp diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 3adf8c670..e5dfacc09 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -16,6 +16,7 @@ #include #include +#include #ifdef SLIC3R_DEBUG #include "SVG.hpp" @@ -335,6 +336,93 @@ double rad2deg_dir(double angle) return rad2deg(angle); } +Point circle_taubin_newton(const Points::const_iterator& input_begin, const Points::const_iterator& input_end, size_t cycles) +{ + Vec2ds tmp; + tmp.reserve(std::distance(input_begin, input_end)); + std::transform(input_begin, input_end, std::back_inserter(tmp), [] (const Point& in) { return unscale(in); } ); + Vec2d center = circle_taubin_newton(tmp.cbegin(), tmp.end(), cycles); + return Point::new_scale(center.x(), center.y()); +} + +/// Adapted from work in "Circular and Linear Regression: Fitting circles and lines by least squares", pg 126 +/// Returns a point corresponding to the center of a circle for which all of the points from input_begin to input_end +/// lie on. +Vec2d circle_taubin_newton(const Vec2ds::const_iterator& input_begin, const Vec2ds::const_iterator& input_end, size_t cycles) +{ + // calculate the centroid of the data set + const Vec2d sum = std::accumulate(input_begin, input_end, Vec2d(0,0)); + const size_t n = std::distance(input_begin, input_end); + const double n_flt = static_cast(n); + const Vec2d centroid { sum / n_flt }; + + // Compute the normalized moments of the data set. + double Mxx = 0, Myy = 0, Mxy = 0, Mxz = 0, Myz = 0, Mzz = 0; + for (auto it = input_begin; it < input_end; ++it) { + // center/normalize the data. + double Xi {it->x() - centroid.x()}; + double Yi {it->y() - centroid.y()}; + double Zi {Xi*Xi + Yi*Yi}; + Mxy += (Xi*Yi); + Mxx += (Xi*Xi); + Myy += (Yi*Yi); + Mxz += (Xi*Zi); + Myz += (Yi*Zi); + Mzz += (Zi*Zi); + } + + // divide by number of points to get the moments + Mxx /= n_flt; + Myy /= n_flt; + Mxy /= n_flt; + Mxz /= n_flt; + Myz /= n_flt; + Mzz /= n_flt; + + // Compute the coefficients of the characteristic polynomial for the circle + // eq 5.60 + const double Mz {Mxx + Myy}; // xx + yy = z + const double Cov_xy {Mxx*Myy - Mxy*Mxy}; // this shows up a couple times so cache it here. + const double C3 {4.0*Mz}; + const double C2 {-3.0*(Mz*Mz) - Mzz}; + const double C1 {Mz*(Mzz - (Mz*Mz)) + 4.0*Mz*Cov_xy - (Mxz*Mxz) - (Myz*Myz)}; + const double C0 {(Mxz*Mxz)*Myy + (Myz*Myz)*Mxx - 2.0*Mxz*Myz*Mxy - Cov_xy*(Mzz - (Mz*Mz))}; + + const double C22 = {C2 + C2}; + const double C33 = {C3 + C3 + C3}; + + // solve the characteristic polynomial with Newton's method. + double xnew = 0.0; + double ynew = 1e20; + + for (size_t i = 0; i < cycles; ++i) { + const double yold {ynew}; + ynew = C0 + xnew * (C1 + xnew*(C2 + xnew * C3)); + if (std::abs(ynew) > std::abs(yold)) { + BOOST_LOG_TRIVIAL(error) << "Geometry: Fit is going in the wrong direction.\n"; + return Vec2d(std::nan(""), std::nan("")); + } + const double Dy {C1 + xnew*(C22 + xnew*C33)}; + + const double xold {xnew}; + xnew = xold - (ynew / Dy); + + if (std::abs((xnew-xold) / xnew) < 1e-12) i = cycles; // converged, we're done here + + if (xnew < 0) { + // reset, we went negative + xnew = 0.0; + } + } + + // compute the determinant and the circle's parameters now that we've solved. + double DET = xnew*xnew - xnew*Mz + Cov_xy; + + Vec2d center(Mxz * (Myy - xnew) - Myz * Mxy, Myz * (Mxx - xnew) - Mxz*Mxy); + center /= (DET * 2.); + return center + centroid; +} + void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval) { Polygons pp; diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 32b66663e..44303711b 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -162,6 +162,15 @@ template T angle_to_0_2PI(T angle) return angle; } + +/// Find the center of the circle corresponding to the vector of Points as an arc. +Point circle_taubin_newton(const Points::const_iterator& input_start, const Points::const_iterator& input_end, size_t cycles = 20); +inline Point circle_taubin_newton(const Points& input, size_t cycles = 20) { return circle_taubin_newton(input.cbegin(), input.cend(), cycles); } + +/// Find the center of the circle corresponding to the vector of Pointfs as an arc. +Vec2d circle_taubin_newton(const Vec2ds::const_iterator& input_start, const Vec2ds::const_iterator& input_end, size_t cycles = 20); +inline Vec2d circle_taubin_newton(const Vec2ds& input, size_t cycles = 20) { return circle_taubin_newton(input.cbegin(), input.cend(), cycles); } + void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval); double linint(double value, double oldmin, double oldmax, double newmin, double newmax); diff --git a/src/libslic3r/Line.cpp b/src/libslic3r/Line.cpp index baa04795a..e5f7b8fa9 100644 --- a/src/libslic3r/Line.cpp +++ b/src/libslic3r/Line.cpp @@ -86,10 +86,7 @@ bool Line::intersection(const Line &l2, Point *intersection) const const Line &l1 = *this; const Vec2d v1 = (l1.b - l1.a).cast(); const Vec2d v2 = (l2.b - l2.a).cast(); - const Vec2d v12 = (l1.a - l2.a).cast(); double denom = cross2(v1, v2); - double nume_a = cross2(v2, v12); - double nume_b = cross2(v1, v12); if (fabs(denom) < EPSILON) #if 0 // Lines are collinear. Return true if they are coincident (overlappign). @@ -97,6 +94,9 @@ bool Line::intersection(const Line &l2, Point *intersection) const #else return false; #endif + const Vec2d v12 = (l1.a - l2.a).cast(); + double nume_a = cross2(v2, v12); + double nume_b = cross2(v1, v12); double t1 = nume_a / denom; double t2 = nume_b / denom; if (t1 >= 0 && t1 <= 1.0f && t2 >= 0 && t2 <= 1.0f) { diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 994f45e59..5f5d86aa8 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -38,6 +38,7 @@ typedef std::vector PointPtrs; typedef std::vector PointConstPtrs; typedef std::vector Points3; typedef std::vector Pointfs; +typedef std::vector Vec2ds; typedef std::vector Pointf3s; typedef Eigen::Matrix Matrix2f; @@ -87,12 +88,13 @@ class Point : public Vec2crd public: typedef coord_t coord_type; - Point() : Vec2crd() { (*this)(0) = 0; (*this)(1) = 0; } - Point(coord_t x, coord_t y) { (*this)(0) = x; (*this)(1) = y; } - Point(int64_t x, int64_t y) { (*this)(0) = coord_t(x); (*this)(1) = coord_t(y); } // for Clipper - Point(double x, double y) { (*this)(0) = coord_t(lrint(x)); (*this)(1) = coord_t(lrint(y)); } + Point() : Vec2crd(0, 0) {} + Point(coord_t x, coord_t y) : Vec2crd(x, y) {} + Point(int64_t x, int64_t y) : Vec2crd(coord_t(x), coord_t(y)) {} // for Clipper + Point(double x, double y) : Vec2crd(coord_t(lrint(x)), coord_t(lrint(y))) {} Point(const Point &rhs) { *this = rhs; } - // This constructor allows you to construct Point from Eigen expressions + explicit Point(const Vec2d& rhs) : Vec2crd(coord_t(lrint(rhs.x())), coord_t(lrint(rhs.y()))) {} + // This constructor allows you to construct Point from Eigen expressions template Point(const Eigen::MatrixBase &other) : Vec2crd(other) {} static Point new_scale(coordf_t x, coordf_t y) { return Point(coord_t(scale_(x)), coord_t(scale_(y))); } @@ -126,6 +128,18 @@ public: Point projection_onto(const Line &line) const; }; +inline bool is_approx(const Point &p1, const Point &p2, coord_t epsilon = coord_t(SCALED_EPSILON)) +{ + Point d = (p2 - p1).cwiseAbs(); + return d.x() < epsilon && d.y() < epsilon; +} + +inline bool is_approx(const Vec2d &p1, const Vec2d &p2, double epsilon = EPSILON) +{ + Vec2d d = (p2 - p1).cwiseAbs(); + return d.x() < epsilon && d.y() < epsilon; +} + namespace int128 { // Exact orientation predicate, // returns +1: CCW, 0: collinear, -1: CW. diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp index 5ef5d0ceb..4c2db2848 100644 --- a/src/libslic3r/Polygon.cpp +++ b/src/libslic3r/Polygon.cpp @@ -175,16 +175,16 @@ Point Polygon::centroid() const Points Polygon::concave_points(double angle) const { Points points; - angle = 2*PI - angle; + angle = 2. * PI - angle + EPSILON; // check whether first point forms a concave angle if (this->points.front().ccw_angle(this->points.back(), *(this->points.begin()+1)) <= angle) points.push_back(this->points.front()); // check whether points 1..(n-1) form concave angles - for (Points::const_iterator p = this->points.begin()+1; p != this->points.end()-1; ++p) { - if (p->ccw_angle(*(p-1), *(p+1)) <= angle) points.push_back(*p); - } + for (Points::const_iterator p = this->points.begin()+1; p != this->points.end()-1; ++ p) + if (p->ccw_angle(*(p-1), *(p+1)) <= angle) + points.push_back(*p); // check whether last point forms a concave angle if (this->points.back().ccw_angle(*(this->points.end()-2), this->points.front()) <= angle) @@ -198,7 +198,7 @@ Points Polygon::concave_points(double angle) const Points Polygon::convex_points(double angle) const { Points points; - angle = 2*PI - angle; + angle = 2*PI - angle - EPSILON; // check whether first point forms a convex angle if (this->points.front().ccw_angle(this->points.back(), *(this->points.begin()+1)) >= angle) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6cbfd5432..e957c0c20 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,6 +21,7 @@ endif() set_property(GLOBAL PROPERTY USE_FOLDERS ON) add_subdirectory(libnest2d) +add_subdirectory(libslic3r) add_subdirectory(timeutils) +add_subdirectory(fff_print) add_subdirectory(sla_print) - diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt new file mode 100644 index 000000000..d0b51a01d --- /dev/null +++ b/tests/fff_print/CMakeLists.txt @@ -0,0 +1,7 @@ +get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) +add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests.cpp) +target_link_libraries(${_TEST_NAME}_tests test_common libslic3r) +set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") + +# catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") +add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "--durations yes") diff --git a/tests/fff_print/fff_print_tests.cpp b/tests/fff_print/fff_print_tests.cpp new file mode 100644 index 000000000..907304f57 --- /dev/null +++ b/tests/fff_print/fff_print_tests.cpp @@ -0,0 +1,15 @@ +#define CATCH_CONFIG_MAIN +#include + +#include "libslic3r/libslic3r.h" + +namespace { + +TEST_CASE("sort_remove_duplicates", "[utils]") { + std::vector data_src = { 3, 0, 2, 1, 15, 3, 5, 6, 3, 1, 0 }; + std::vector data_dst = { 0, 1, 2, 3, 5, 6, 15 }; + Slic3r::sort_remove_duplicates(data_src); + REQUIRE(data_src == data_dst); +} + +} diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt new file mode 100644 index 000000000..ea83bf089 --- /dev/null +++ b/tests/libslic3r/CMakeLists.txt @@ -0,0 +1,10 @@ +get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) +add_executable(${_TEST_NAME}_tests + ${_TEST_NAME}_tests.cpp + test_geometry.cpp + ) +target_link_libraries(${_TEST_NAME}_tests test_common libslic3r) +set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") + +# catch_discover_tests(${_TEST_NAME}_tests TEST_PREFIX "${_TEST_NAME}: ") +add_test(${_TEST_NAME}_tests ${_TEST_NAME}_tests "--durations yes") diff --git a/tests/libslic3r/libslic3r_tests.cpp b/tests/libslic3r/libslic3r_tests.cpp new file mode 100644 index 000000000..907304f57 --- /dev/null +++ b/tests/libslic3r/libslic3r_tests.cpp @@ -0,0 +1,15 @@ +#define CATCH_CONFIG_MAIN +#include + +#include "libslic3r/libslic3r.h" + +namespace { + +TEST_CASE("sort_remove_duplicates", "[utils]") { + std::vector data_src = { 3, 0, 2, 1, 15, 3, 5, 6, 3, 1, 0 }; + std::vector data_dst = { 0, 1, 2, 3, 5, 6, 15 }; + Slic3r::sort_remove_duplicates(data_src); + REQUIRE(data_src == data_dst); +} + +} diff --git a/tests/libslic3r/test_geometry.cpp b/tests/libslic3r/test_geometry.cpp new file mode 100644 index 000000000..7a3b84c7d --- /dev/null +++ b/tests/libslic3r/test_geometry.cpp @@ -0,0 +1,375 @@ +#include + +#include "libslic3r/Point.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/Geometry.hpp" +#include "libslic3r/ClipperUtils.hpp" +#include "libslic3r/ShortestPath.hpp" + +using namespace Slic3r; + +TEST_CASE("Polygon::contains works properly", ""){ + // this test was failing on Windows (GH #1950) + auto polygon = Slic3r::Polygon(std::vector({ + Point(207802834,-57084522), + Point(196528149,-37556190), + Point(173626821,-25420928), + Point(171285751,-21366123), + Point(118673592,-21366123), + Point(116332562,-25420928), + Point(93431208,-37556191), + Point(82156517,-57084523), + Point(129714478,-84542120), + Point(160244873,-84542120) + })); + auto point = Point(95706562, -57294774); + REQUIRE(polygon.contains(point)); +} + +SCENARIO("Intersections of line segments"){ + GIVEN("Integer coordinates"){ + auto line1 = Line(Point(5,15),Point(30,15)); + auto line2 = Line(Point(10,20), Point(10,10)); + THEN("The intersection is valid"){ + Point point; + line1.intersection(line2,&point); + REQUIRE(Point(10,15) == point); + } + } + + GIVEN("Scaled coordinates"){ + auto line1 = Line(Point(73.6310778185108 / 0.00001, 371.74239268924 / 0.00001), Point(73.6310778185108 / 0.00001, 501.74239268924 / 0.00001)); + auto line2 = Line(Point(75/0.00001, 437.9853/0.00001), Point(62.7484/0.00001, 440.4223/0.00001)); + THEN("There is still an intersection"){ + Point point; + REQUIRE(line1.intersection(line2,&point)); + } + } +} + +/* +Tests for unused methods still written in perl +{ + my $polygon = Slic3r::Polygon->new( + [45919000, 515273900], [14726100, 461246400], [14726100, 348753500], [33988700, 315389800], + [43749700, 343843000], [45422300, 352251500], [52362100, 362637800], [62748400, 369577600], + [75000000, 372014700], [87251500, 369577600], [97637800, 362637800], [104577600, 352251500], + [107014700, 340000000], [104577600, 327748400], [97637800, 317362100], [87251500, 310422300], + [82789200, 309534700], [69846100, 294726100], [254081000, 294726100], [285273900, 348753500], + [285273900, 461246400], [254081000, 515273900], + ); + + # this points belongs to $polyline + # note: it's actually a vertex, while we should better check an intermediate point + my $point = Slic3r::Point->new(104577600, 327748400); + + local $Slic3r::Geometry::epsilon = 1E-5; + is_deeply Slic3r::Geometry::polygon_segment_having_point($polygon, $point)->pp, + [ [107014700, 340000000], [104577600, 327748400] ], + 'polygon_segment_having_point'; +} +{ + auto point = Point(736310778.185108, 5017423926.8924); + auto line = Line(Point((long int) 627484000, (long int) 3695776000), Point((long int) 750000000, (long int)3720147000)); + //is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment'; +} + +// Possible to delete +{ + //my $p1 = [10, 10]; + //my $p2 = [10, 20]; + //my $p3 = [10, 30]; + //my $p4 = [20, 20]; + //my $p5 = [0, 20]; + + THEN("Points in a line give the correct angles"){ + //is Slic3r::Geometry::angle3points($p2, $p3, $p1), PI(), 'angle3points'; + //is Slic3r::Geometry::angle3points($p2, $p1, $p3), PI(), 'angle3points'; + } + THEN("Left turns give the correct angle"){ + //is Slic3r::Geometry::angle3points($p2, $p4, $p3), PI()/2, 'angle3points'; + //is Slic3r::Geometry::angle3points($p2, $p1, $p4), PI()/2, 'angle3points'; + } + THEN("Right turns give the correct angle"){ + //is Slic3r::Geometry::angle3points($p2, $p3, $p4), PI()/2*3, 'angle3points'; + //is Slic3r::Geometry::angle3points($p2, $p1, $p5), PI()/2*3, 'angle3points'; + } + //my $p1 = [30, 30]; + //my $p2 = [20, 20]; + //my $p3 = [10, 10]; + //my $p4 = [30, 10]; + + //is Slic3r::Geometry::angle3points($p2, $p1, $p3), PI(), 'angle3points'; + //is Slic3r::Geometry::angle3points($p2, $p1, $p4), PI()/2*3, 'angle3points'; + //is Slic3r::Geometry::angle3points($p2, $p1, $p1), 2*PI(), 'angle3points'; +} + +SCENARIO("polygon_is_convex works"){ + GIVEN("A square of dimension 10"){ + //my $cw_square = [ [0,0], [0,10], [10,10], [10,0] ]; + THEN("It is not convex clockwise"){ + //is polygon_is_convex($cw_square), 0, 'cw square is not convex'; + } + THEN("It is convex counter-clockwise"){ + //is polygon_is_convex([ reverse @$cw_square ]), 1, 'ccw square is convex'; + } + + } + GIVEN("A concave polygon"){ + //my $convex1 = [ [0,0], [10,0], [10,10], [0,10], [0,6], [4,6], [4,4], [0,4] ]; + THEN("It is concave"){ + //is polygon_is_convex($convex1), 0, 'concave polygon'; + } + } +}*/ + + +TEST_CASE("Creating a polyline generates the obvious lines"){ + auto polyline = Slic3r::Polyline(); + polyline.points = std::vector({Point(0, 0), Point(10, 0), Point(20, 0)}); + REQUIRE(polyline.lines().at(0).a == Point(0,0)); + REQUIRE(polyline.lines().at(0).b == Point(10,0)); + REQUIRE(polyline.lines().at(1).a == Point(10,0)); + REQUIRE(polyline.lines().at(1).b == Point(20,0)); +} + +TEST_CASE("Splitting a Polygon generates a polyline correctly"){ + auto polygon = Slic3r::Polygon(std::vector({Point(0, 0), Point(10, 0), Point(5, 5)})); + auto split = polygon.split_at_index(1); + REQUIRE(split.points[0]==Point(10,0)); + REQUIRE(split.points[1]==Point(5,5)); + REQUIRE(split.points[2]==Point(0,0)); + REQUIRE(split.points[3]==Point(10,0)); +} + + +TEST_CASE("Bounding boxes are scaled appropriately"){ + auto bb = BoundingBox(std::vector({Point(0, 1), Point(10, 2), Point(20, 2)})); + bb.scale(2); + REQUIRE(bb.min == Point(0,2)); + REQUIRE(bb.max == Point(40,4)); +} + + +TEST_CASE("Offseting a line generates a polygon correctly"){ + Slic3r::Polyline tmp = { Point(10,10), Point(20,10) }; + Slic3r::Polygon area = offset(tmp,5).at(0); + REQUIRE(area.area() == Slic3r::Polygon(std::vector({Point(10,5),Point(20,5),Point(20,15),Point(10,15)})).area()); +} + +SCENARIO("Circle Fit, TaubinFit with Newton's method") { + GIVEN("A vector of Vec2ds arranged in a half-circle with approximately the same distance R from some point") { + Vec2d expected_center(-6, 0); + Vec2ds sample {Vec2d(6.0, 0), Vec2d(5.1961524, 3), Vec2d(3 ,5.1961524), Vec2d(0, 6.0), Vec2d(3, 5.1961524), Vec2d(-5.1961524, 3), Vec2d(-6.0, 0)}; + std::transform(sample.begin(), sample.end(), sample.begin(), [expected_center] (const Vec2d& a) { return a + expected_center;}); + + WHEN("Circle fit is called on the entire array") { + Vec2d result_center(0,0); + result_center = Geometry::circle_taubin_newton(sample); + THEN("A center point of -6,0 is returned.") { + REQUIRE(is_approx(result_center, expected_center)); + } + } + WHEN("Circle fit is called on the first four points") { + Vec2d result_center(0,0); + result_center = Geometry::circle_taubin_newton(sample.cbegin(), sample.cbegin()+4); + THEN("A center point of -6,0 is returned.") { + REQUIRE(is_approx(result_center, expected_center)); + } + } + WHEN("Circle fit is called on the middle four points") { + Vec2d result_center(0,0); + result_center = Geometry::circle_taubin_newton(sample.cbegin()+2, sample.cbegin()+6); + THEN("A center point of -6,0 is returned.") { + REQUIRE(is_approx(result_center, expected_center)); + } + } + } + GIVEN("A vector of Vec2ds arranged in a half-circle with approximately the same distance R from some point") { + Vec2d expected_center(-3, 9); + Vec2ds sample {Vec2d(6.0, 0), Vec2d(5.1961524, 3), Vec2d(3 ,5.1961524), + Vec2d(0, 6.0), + Vec2d(3, 5.1961524), Vec2d(-5.1961524, 3), Vec2d(-6.0, 0)}; + + std::transform(sample.begin(), sample.end(), sample.begin(), [expected_center] (const Vec2d& a) { return a + expected_center;}); + + + WHEN("Circle fit is called on the entire array") { + Vec2d result_center(0,0); + result_center = Geometry::circle_taubin_newton(sample); + THEN("A center point of 3,9 is returned.") { + REQUIRE(is_approx(result_center, expected_center)); + } + } + WHEN("Circle fit is called on the first four points") { + Vec2d result_center(0,0); + result_center = Geometry::circle_taubin_newton(sample.cbegin(), sample.cbegin()+4); + THEN("A center point of 3,9 is returned.") { + REQUIRE(is_approx(result_center, expected_center)); + } + } + WHEN("Circle fit is called on the middle four points") { + Vec2d result_center(0,0); + result_center = Geometry::circle_taubin_newton(sample.cbegin()+2, sample.cbegin()+6); + THEN("A center point of 3,9 is returned.") { + REQUIRE(is_approx(result_center, expected_center)); + } + } + } + GIVEN("A vector of Points arranged in a half-circle with approximately the same distance R from some point") { + Point expected_center { Point::new_scale(-3, 9)}; + Points sample {Point::new_scale(6.0, 0), Point::new_scale(5.1961524, 3), Point::new_scale(3 ,5.1961524), + Point::new_scale(0, 6.0), + Point::new_scale(3, 5.1961524), Point::new_scale(-5.1961524, 3), Point::new_scale(-6.0, 0)}; + + std::transform(sample.begin(), sample.end(), sample.begin(), [expected_center] (const Point& a) { return a + expected_center;}); + + + WHEN("Circle fit is called on the entire array") { + Point result_center(0,0); + result_center = Geometry::circle_taubin_newton(sample); + THEN("A center point of scaled 3,9 is returned.") { + REQUIRE(is_approx(result_center, expected_center)); + } + } + WHEN("Circle fit is called on the first four points") { + Point result_center(0,0); + result_center = Geometry::circle_taubin_newton(sample.cbegin(), sample.cbegin()+4); + THEN("A center point of scaled 3,9 is returned.") { + REQUIRE(is_approx(result_center, expected_center)); + } + } + WHEN("Circle fit is called on the middle four points") { + Point result_center(0,0); + result_center = Geometry::circle_taubin_newton(sample.cbegin()+2, sample.cbegin()+6); + THEN("A center point of scaled 3,9 is returned.") { + REQUIRE(is_approx(result_center, expected_center)); + } + } + } +} + +TEST_CASE("Chained path working correctly"){ + // if chained_path() works correctly, these points should be joined with no diagonal paths + // (thus 26 units long) + std::vector points = {Point(26,26),Point(52,26),Point(0,26),Point(26,52),Point(26,0),Point(0,52),Point(52,52),Point(52,0)}; + std::vector indices = chain_points(points); + for (Points::size_type i = 0; i + 1 < indices.size(); ++ i) { + double dist = (points.at(indices.at(i)).cast() - points.at(indices.at(i+1)).cast()).norm(); + REQUIRE(std::abs(dist-26) <= EPSILON); + } +} + +SCENARIO("Line distances"){ + GIVEN("A line"){ + auto line = Line(Point(0, 0), Point(20, 0)); + THEN("Points on the line segment have 0 distance"){ + REQUIRE(line.distance_to(Point(0, 0)) == 0); + REQUIRE(line.distance_to(Point(20, 0)) == 0); + REQUIRE(line.distance_to(Point(10, 0)) == 0); + + } + THEN("Points off the line have the appropriate distance"){ + REQUIRE(line.distance_to(Point(10, 10)) == 10); + REQUIRE(line.distance_to(Point(50, 0)) == 30); + } + } +} + +SCENARIO("Polygon convex/concave detection"){ + GIVEN(("A Square with dimension 100")){ + auto square = Slic3r::Polygon /*new_scale*/(std::vector({ + Point(100,100), + Point(200,100), + Point(200,200), + Point(100,200)})); + THEN("It has 4 convex points counterclockwise"){ + REQUIRE(square.concave_points(PI*4/3).size() == 0); + REQUIRE(square.convex_points(PI*2/3).size() == 4); + } + THEN("It has 4 concave points clockwise"){ + square.make_clockwise(); + REQUIRE(square.concave_points(PI*4/3).size() == 4); + REQUIRE(square.convex_points(PI*2/3).size() == 0); + } + } + GIVEN("A Square with an extra colinearvertex"){ + auto square = Slic3r::Polygon /*new_scale*/(std::vector({ + Point(150,100), + Point(200,100), + Point(200,200), + Point(100,200), + Point(100,100)})); + THEN("It has 4 convex points counterclockwise"){ + REQUIRE(square.concave_points(PI*4/3).size() == 0); + REQUIRE(square.convex_points(PI*2/3).size() == 4); + } + } + GIVEN("A Square with an extra collinear vertex in different order"){ + auto square = Slic3r::Polygon /*new_scale*/(std::vector({ + Point(200,200), + Point(100,200), + Point(100,100), + Point(150,100), + Point(200,100)})); + THEN("It has 4 convex points counterclockwise"){ + REQUIRE(square.concave_points(PI*4/3).size() == 0); + REQUIRE(square.convex_points(PI*2/3).size() == 4); + } + } + + GIVEN("A triangle"){ + auto triangle = Slic3r::Polygon(std::vector({ + Point(16000170,26257364), + Point(714223,461012), + Point(31286371,461008) + })); + THEN("it has three convex vertices"){ + REQUIRE(triangle.concave_points(PI*4/3).size() == 0); + REQUIRE(triangle.convex_points(PI*2/3).size() == 3); + } + } + + GIVEN("A triangle with an extra collinear point"){ + auto triangle = Slic3r::Polygon(std::vector({ + Point(16000170,26257364), + Point(714223,461012), + Point(20000000,461012), + Point(31286371,461012) + })); + THEN("it has three convex vertices"){ + REQUIRE(triangle.concave_points(PI*4/3).size() == 0); + REQUIRE(triangle.convex_points(PI*2/3).size() == 3); + } + } + GIVEN("A polygon with concave vertices with angles of specifically 4/3pi"){ + // Two concave vertices of this polygon have angle = PI*4/3, so this test fails + // if epsilon is not used. + auto polygon = Slic3r::Polygon(std::vector({ + Point(60246458,14802768),Point(64477191,12360001), + Point(63727343,11060995),Point(64086449,10853608), + Point(66393722,14850069),Point(66034704,15057334), + Point(65284646,13758387),Point(61053864,16200839), + Point(69200258,30310849),Point(62172547,42483120), + Point(61137680,41850279),Point(67799985,30310848), + Point(51399866,1905506),Point(38092663,1905506), + Point(38092663,692699),Point(52100125,692699) + })); + THEN("the correct number of points are detected"){ + REQUIRE(polygon.concave_points(PI*4/3).size() == 6); + REQUIRE(polygon.convex_points(PI*2/3).size() == 10); + } + } +} + +TEST_CASE("Triangle Simplification does not result in less than 3 points"){ + auto triangle = Slic3r::Polygon(std::vector({ + Point(16000170,26257364), Point(714223,461012), Point(31286371,461008) + })); + REQUIRE(triangle.simplify(250000).at(0).points.size() == 3); +} + + From e538a06fb0b1bed29ee98f7fb5ac2249e7fc903f Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 15 Oct 2019 09:49:33 +0200 Subject: [PATCH 06/15] Added missing include (worked on MSVC) --- src/libslic3r/Geometry.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index e5dfacc09..e926b9997 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include From 67e1eba8e6aa573888d791aab83aa22427377034 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 15 Oct 2019 11:28:20 +0200 Subject: [PATCH 07/15] Ported test_data.cpp/hpp & test_flow.cpp from upstream slic3r, thanks @lordofhyphens --- tests/fff_print/CMakeLists.txt | 7 +- tests/fff_print/fff_print_tests.cpp | 11 -- tests/fff_print/test_data.cpp | 296 ++++++++++++++++++++++++++++ tests/fff_print/test_data.hpp | 77 ++++++++ tests/fff_print/test_flow.cpp | 203 +++++++++++++++++++ 5 files changed, 582 insertions(+), 12 deletions(-) create mode 100644 tests/fff_print/test_data.cpp create mode 100644 tests/fff_print/test_data.hpp create mode 100644 tests/fff_print/test_flow.cpp diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt index d0b51a01d..ee7e3fd1e 100644 --- a/tests/fff_print/CMakeLists.txt +++ b/tests/fff_print/CMakeLists.txt @@ -1,5 +1,10 @@ get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) -add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests.cpp) +add_executable(${_TEST_NAME}_tests + ${_TEST_NAME}_tests.cpp + test_data.cpp + test_data.hpp + test_flow.cpp + ) target_link_libraries(${_TEST_NAME}_tests test_common libslic3r) set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") diff --git a/tests/fff_print/fff_print_tests.cpp b/tests/fff_print/fff_print_tests.cpp index 907304f57..5e9b82f80 100644 --- a/tests/fff_print/fff_print_tests.cpp +++ b/tests/fff_print/fff_print_tests.cpp @@ -2,14 +2,3 @@ #include #include "libslic3r/libslic3r.h" - -namespace { - -TEST_CASE("sort_remove_duplicates", "[utils]") { - std::vector data_src = { 3, 0, 2, 1, 15, 3, 5, 6, 3, 1, 0 }; - std::vector data_dst = { 0, 1, 2, 3, 5, 6, 15 }; - Slic3r::sort_remove_duplicates(data_src); - REQUIRE(data_src == data_dst); -} - -} diff --git a/tests/fff_print/test_data.cpp b/tests/fff_print/test_data.cpp new file mode 100644 index 000000000..729e72626 --- /dev/null +++ b/tests/fff_print/test_data.cpp @@ -0,0 +1,296 @@ +#include "test_data.hpp" + +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/GCodeReader.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/Print.hpp" + +#include +#include + +#include +#include + +using namespace std::string_literals; +using namespace std; + +namespace Slic3r { namespace Test { + +// Mesh enumeration to name mapping +const std::unordered_map mesh_names { + std::pair(TestMesh::A,"A"), + std::pair(TestMesh::L,"L"), + std::pair(TestMesh::V,"V"), + std::pair(TestMesh::_40x10,"40x10"), + std::pair(TestMesh::cube_20x20x20,"cube_20x20x20"), + std::pair(TestMesh::sphere_50mm,"sphere_50mm"), + std::pair(TestMesh::bridge,"bridge"), + std::pair(TestMesh::bridge_with_hole,"bridge_with_hole"), + std::pair(TestMesh::cube_with_concave_hole,"cube_with_concave_hole"), + std::pair(TestMesh::cube_with_hole,"cube_with_hole"), + std::pair(TestMesh::gt2_teeth,"gt2_teeth"), + std::pair(TestMesh::ipadstand,"ipadstand"), + std::pair(TestMesh::overhang,"overhang"), + std::pair(TestMesh::pyramid,"pyramid"), + std::pair(TestMesh::sloping_hole,"sloping_hole"), + std::pair(TestMesh::slopy_cube,"slopy_cube"), + std::pair(TestMesh::small_dorito,"small_dorito"), + std::pair(TestMesh::step,"step"), + std::pair(TestMesh::two_hollow_squares,"two_hollow_squares") +}; + +TriangleMesh mesh(TestMesh m) +{ + std::vector facets; + std::vector vertices; + switch(m) { + case TestMesh::cube_with_hole: + vertices = { Vec3d(0,0,0), Vec3d(0,0,10), Vec3d(0,20,0), Vec3d(0,20,10), Vec3d(20,0,0), Vec3d(20,0,10), Vec3d(5,5,0), Vec3d(15,5,0), Vec3d(5,15,0), Vec3d(20,20,0), Vec3d(15,15,0), Vec3d(20,20,10), Vec3d(5,5,10), Vec3d(5,15,10), Vec3d(15,5,10), Vec3d(15,15,10) }; + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(2,1,3), Vec3crd(1,0,4), Vec3crd(5,1,4), Vec3crd(6,7,4), Vec3crd(8,2,9), Vec3crd(0,2,8), Vec3crd(10,8,9), Vec3crd(0,8,6), Vec3crd(0,6,4), Vec3crd(4,7,9), Vec3crd(7,10,9), Vec3crd(2,3,9), Vec3crd(9,3,11), Vec3crd(12,1,5), Vec3crd(13,3,12), Vec3crd(14,12,5), Vec3crd(3,1,12), Vec3crd(11,3,13), Vec3crd(11,15,5), Vec3crd(11,13,15), Vec3crd(15,14,5), Vec3crd(5,4,9), Vec3crd(11,5,9), Vec3crd(8,13,12), Vec3crd(6,8,12), Vec3crd(10,15,13), Vec3crd(8,10,13), Vec3crd(15,10,14), Vec3crd(14,10,7), Vec3crd(14,7,12), Vec3crd(12,7,6) + }); + break; + case TestMesh::cube_with_concave_hole: + vertices = std::vector({ + Vec3d(-10,-10,-5), Vec3d(-10,-10,5), Vec3d(-10,10,-5), Vec3d(-10,10,5), Vec3d(10,-10,-5), Vec3d(10,-10,5), Vec3d(-5,-5,-5), Vec3d(5,-5,-5), Vec3d(5,5,-5), Vec3d(5,10,-5), Vec3d(-5,5,-5), Vec3d(3.06161699911402e-16,5,-5), Vec3d(5,0,-5), Vec3d(0,0,-5), Vec3d(10,5,-5), Vec3d(5,10,5), Vec3d(-5,-5,5), Vec3d(5,0,5), Vec3d(5,-5,5), Vec3d(-5,5,5), Vec3d(10,5,5), Vec3d(5,5,5), Vec3d(3.06161699911402e-16,5,5), Vec3d(0,0,5) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(2,1,3), Vec3crd(1,0,4), Vec3crd(5,1,4), Vec3crd(6,7,4), Vec3crd(8,2,9), Vec3crd(10,2,11), Vec3crd(11,12,13), Vec3crd(0,2,10), Vec3crd(0,10,6), Vec3crd(0,6,4), Vec3crd(11,2,8), Vec3crd(4,7,12), Vec3crd(4,12,8), Vec3crd(12,11,8), Vec3crd(14,4,8), Vec3crd(2,3,9), Vec3crd(9,3,15), Vec3crd(16,1,5), Vec3crd(17,18,5), Vec3crd(19,3,16), Vec3crd(20,21,5), Vec3crd(18,16,5), Vec3crd(3,1,16), Vec3crd(22,3,19), Vec3crd(21,3,22), Vec3crd(21,17,5), Vec3crd(21,22,17), Vec3crd(21,15,3), Vec3crd(23,17,22), Vec3crd(5,4,14), Vec3crd(20,5,14), Vec3crd(20,14,21), Vec3crd(21,14,8), Vec3crd(9,15,21), Vec3crd(8,9,21), Vec3crd(10,19,16), Vec3crd(6,10,16), Vec3crd(11,22,19), Vec3crd(10,11,19), Vec3crd(13,23,11), Vec3crd(11,23,22), Vec3crd(23,13,12), Vec3crd(17,23,12), Vec3crd(17,12,18), Vec3crd(18,12,7), Vec3crd(18,7,16), Vec3crd(16,7,6) + }); + break; + case TestMesh::V: + vertices = std::vector({ + Vec3d(-14,0,20), Vec3d(-14,15,20), Vec3d(0,0,0), Vec3d(0,15,0), Vec3d(-4,0,20), Vec3d(-4,15,20), Vec3d(5,0,7.14286), Vec3d(10,0,0), Vec3d(24,0,20), Vec3d(14,0,20), Vec3d(10,15,0), Vec3d(5,15,7.14286), Vec3d(14,15,20), Vec3d(24,15,20) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(2,1,3), Vec3crd(1,0,4), Vec3crd(5,1,4), Vec3crd(4,0,2), Vec3crd(6,4,2), Vec3crd(7,6,2), Vec3crd(8,9,7), Vec3crd(9,6,7), Vec3crd(2,3,7), Vec3crd(7,3,10), Vec3crd(1,5,3), Vec3crd(3,5,11), Vec3crd(11,12,13), Vec3crd(11,13,3), Vec3crd(3,13,10), Vec3crd(5,4,6), Vec3crd(11,5,6), Vec3crd(6,9,11), Vec3crd(11,9,12), Vec3crd(12,9,8), Vec3crd(13,12,8), Vec3crd(8,7,10), Vec3crd(13,8,10) + }); + break; + case TestMesh::L: + vertices = std::vector({ + Vec3d(0,10,0), Vec3d(0,10,10), Vec3d(0,20,0), Vec3d(0,20,10), Vec3d(10,10,0), Vec3d(10,10,10), Vec3d(20,20,0), Vec3d(20,0,0), Vec3d(10,0,0), Vec3d(20,20,10), Vec3d(10,0,10), Vec3d(20,0,10) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(2,1,3), Vec3crd(4,5,1), Vec3crd(0,4,1), Vec3crd(0,2,4), Vec3crd(4,2,6), Vec3crd(4,6,7), Vec3crd(4,7,8), Vec3crd(2,3,6), Vec3crd(6,3,9), Vec3crd(3,1,5), Vec3crd(9,3,5), Vec3crd(10,11,5), Vec3crd(11,9,5), Vec3crd(5,4,10), Vec3crd(10,4,8), Vec3crd(10,8,7), Vec3crd(11,10,7), Vec3crd(11,7,6), Vec3crd(9,11,6) + }); + break; + case TestMesh::overhang: + vertices = std::vector({ + Vec3d(1364.68505859375,614.398010253906,20.002498626709), Vec3d(1389.68505859375,614.398010253906,20.002498626709), Vec3d(1377.18505859375,589.398986816406,20.002498626709), Vec3d(1389.68505859375,589.398986816406,20.002498626709), Vec3d(1389.68505859375,564.398986816406,20.0014991760254), Vec3d(1364.68505859375,589.398986816406,20.002498626709), Vec3d(1364.68505859375,564.398986816406,20.0014991760254), Vec3d(1360.93505859375,589.398986816406,17.0014991760254), Vec3d(1360.93505859375,585.64697265625,17.0014991760254), Vec3d(1357.18505859375,564.398986816406,17.0014991760254), Vec3d(1364.68505859375,589.398986816406,17.0014991760254), Vec3d(1364.68505859375,571.899963378906,17.0014991760254), Vec3d(1364.68505859375,564.398986816406,17.0014991760254), Vec3d(1348.43603515625,564.398986816406,17.0014991760254), Vec3d(1352.80908203125,589.398986816406,17.0014991760254), Vec3d(1357.18408203125,589.398986816406,17.0014991760254), Vec3d(1357.18310546875,614.398010253906,17.0014991760254), Vec3d(1364.68505859375,606.89599609375,17.0014991760254), Vec3d(1364.68505859375,614.398010253906,17.0014991760254), Vec3d(1352.18603515625,564.398986816406,20.0014991760254), Vec3d(1363.65405273438,589.398986816406,23.3004989624023), Vec3d(1359.46704101562,589.398986816406,23.3004989624023), Vec3d(1358.37109375,564.398986816406,23.3004989624023), Vec3d(1385.56103515625,564.398986816406,23.3004989624023), Vec3d(1373.06311035156,589.398986816406,23.3004989624023), Vec3d(1368.80810546875,564.398986816406,23.3004989624023), Vec3d(1387.623046875,589.398986816406,23.3004989624023), Vec3d(1387.623046875,585.276000976562,23.3004989624023), Vec3d(1389.68505859375,589.398986816406,23.3004989624023), Vec3d(1389.68505859375,572.64599609375,23.3004989624023), Vec3d(1389.68505859375,564.398986816406,23.3004989624023), Vec3d(1367.77709960938,589.398986816406,23.3004989624023), Vec3d(1366.7470703125,564.398986816406,23.3004989624023), Vec3d(1354.31201171875,589.398986816406,23.3004989624023), Vec3d(1352.18603515625,564.398986816406,23.3004989624023), Vec3d(1389.68505859375,614.398010253906,23.3004989624023), Vec3d(1377.31701660156,614.398010253906,23.3004989624023), Vec3d(1381.43908691406,589.398986816406,23.3004989624023), Vec3d(1368.80700683594,614.398010253906,23.3004989624023), Vec3d(1368.80810546875,589.398986816406,23.3004989624023), Vec3d(1356.43908691406,614.398010253906,23.3004989624023), Vec3d(1357.40502929688,589.398986816406,23.3004989624023), Vec3d(1360.56201171875,614.398010253906,23.3004989624023), Vec3d(1348.705078125,614.398010253906,23.3004989624023), Vec3d(1350.44506835938,589.398986816406,23.3004989624023), Vec3d(1389.68505859375,606.153015136719,23.3004989624023), Vec3d(1347.35205078125,589.398986816406,23.3004989624023), Vec3d(1346.56005859375,589.398986816406,23.3004989624023), Vec3d(1346.56005859375,594.159912109375,17.0014991760254), Vec3d(1346.56005859375,589.398986816406,17.0014991760254), Vec3d(1346.56005859375,605.250427246094,23.3004989624023), Vec3d(1346.56005859375,614.398010253906,23.3004989624023), Vec3d(1346.56005859375,614.398010253906,20.8258285522461), Vec3d(1346.56005859375,614.398010253906,17.0014991760254), Vec3d(1346.56005859375,564.398986816406,19.10133934021), Vec3d(1346.56005859375,567.548583984375,23.3004989624023), Vec3d(1346.56005859375,564.398986816406,17.0020332336426), Vec3d(1346.56005859375,564.398986816406,23.0018501281738), Vec3d(1346.56005859375,564.398986816406,23.3004989624023), Vec3d(1346.56005859375,575.118957519531,17.0014991760254), Vec3d(1346.56005859375,574.754028320312,23.3004989624023) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(2,3,4), Vec3crd(2,5,0), Vec3crd(4,6,2), Vec3crd(2,6,5), Vec3crd(2,1,3), Vec3crd(7,8,9), Vec3crd(10,9,8), Vec3crd(11,9,10), Vec3crd(12,9,11), Vec3crd(9,13,14), Vec3crd(7,15,16), Vec3crd(10,17,0), Vec3crd(10,0,5), Vec3crd(12,11,6), Vec3crd(18,16,0), Vec3crd(6,19,13), Vec3crd(6,13,9), Vec3crd(9,12,6), Vec3crd(17,18,0), Vec3crd(11,10,5), Vec3crd(11,5,6), Vec3crd(14,16,15), Vec3crd(17,7,18), Vec3crd(16,18,7), Vec3crd(14,15,9), Vec3crd(7,9,15), Vec3crd(7,17,8), Vec3crd(10,8,17), Vec3crd(20,21,22), Vec3crd(23,24,25), Vec3crd(26,23,27), Vec3crd(28,27,23), Vec3crd(29,28,23), Vec3crd(30,29,23), Vec3crd(25,31,32), Vec3crd(22,33,34), Vec3crd(35,36,37), Vec3crd(24,38,39), Vec3crd(21,40,41), Vec3crd(38,42,20), Vec3crd(33,43,44), Vec3crd(6,4,23), Vec3crd(6,23,25), Vec3crd(36,35,1), Vec3crd(1,0,38), Vec3crd(1,38,36), Vec3crd(29,30,4), Vec3crd(25,32,6), Vec3crd(40,42,0), Vec3crd(35,45,1), Vec3crd(4,3,28), Vec3crd(4,28,29), Vec3crd(3,1,45), Vec3crd(3,45,28), Vec3crd(22,34,19), Vec3crd(19,6,32), Vec3crd(19,32,22), Vec3crd(42,38,0), Vec3crd(30,23,4), Vec3crd(0,16,43), Vec3crd(0,43,40), Vec3crd(24,37,36), Vec3crd(38,24,36), Vec3crd(24,23,37), Vec3crd(37,23,26), Vec3crd(22,32,20), Vec3crd(20,32,31), Vec3crd(33,41,40), Vec3crd(43,33,40), Vec3crd(45,35,26), Vec3crd(37,26,35), Vec3crd(33,44,34), Vec3crd(44,43,46), Vec3crd(20,42,21), Vec3crd(40,21,42), Vec3crd(31,39,38), Vec3crd(20,31,38), Vec3crd(33,22,41), Vec3crd(21,41,22), Vec3crd(31,25,39), Vec3crd(24,39,25), Vec3crd(26,27,45), Vec3crd(28,45,27), Vec3crd(47,48,49), Vec3crd(47,50,48), Vec3crd(51,48,50), Vec3crd(52,48,51), Vec3crd(53,48,52), Vec3crd(54,55,56), Vec3crd(57,55,54), Vec3crd(58,55,57), Vec3crd(49,59,47), Vec3crd(60,56,55), Vec3crd(59,56,60), Vec3crd(60,47,59), Vec3crd(48,53,16), Vec3crd(56,13,19), Vec3crd(54,56,19), Vec3crd(56,59,13), Vec3crd(59,49,14), Vec3crd(59,14,13), Vec3crd(49,48,16), Vec3crd(49,16,14), Vec3crd(44,46,60), Vec3crd(44,60,55), Vec3crd(51,50,43), Vec3crd(19,34,58), Vec3crd(19,58,57), Vec3crd(53,52,16), Vec3crd(43,16,52), Vec3crd(43,52,51), Vec3crd(57,54,19), Vec3crd(47,60,46), Vec3crd(55,58,34), Vec3crd(55,34,44), Vec3crd(50,47,46), Vec3crd(50,46,43) + }); + break; + case TestMesh::_40x10: + vertices = std::vector({ + Vec3d(12.8680295944214,29.5799007415771,12), Vec3d(11.7364797592163,29.8480796813965,12), Vec3d(11.1571502685547,29.5300102233887,12), Vec3d(10.5814504623413,29.9830799102783,12), Vec3d(10,29.6000003814697,12), Vec3d(9.41855144500732,29.9830799102783,12), Vec3d(8.84284687042236,29.5300102233887,12), Vec3d(8.26351833343506,29.8480796813965,12), Vec3d(7.70256900787354,29.3210391998291,12), Vec3d(7.13196802139282,29.5799007415771,12), Vec3d(6.59579277038574,28.9761600494385,12), Vec3d(6.03920221328735,29.1821594238281,12), Vec3d(5.53865718841553,28.5003795623779,12), Vec3d(5,28.6602592468262,12), Vec3d(4.54657793045044,27.9006500244141,12), Vec3d(4.02841377258301,28.0212306976318,12), Vec3d(3.63402199745178,27.1856994628906,12), Vec3d(3.13758301734924,27.2737407684326,12), Vec3d(2.81429696083069,26.3659801483154,12), Vec3d(2.33955597877502,26.4278793334961,12), Vec3d(2.0993549823761,25.4534206390381,12), Vec3d(1.64512205123901,25.4950904846191,12), Vec3d(1.49962198734283,24.4613399505615,12), Vec3d(1.0636739730835,24.4879894256592,12), Vec3d(1.02384400367737,23.4042091369629,12), Vec3d(0.603073298931122,23.4202003479004,12), Vec3d(0.678958415985107,22.2974300384521,12), Vec3d(0.269550800323486,22.3061599731445,12), Vec3d(0.469994693994522,21.1571502685547,12), Vec3d(0.067615881562233,21.1609306335449,12), Vec3d(0.399999290704727,20,12), Vec3d(0,20,12), Vec3d(0.399999290704727,5,12), Vec3d(0,5,12), Vec3d(0.456633001565933,4.2804012298584,12), Vec3d(0.0615576282143593,4.21782684326172,12), Vec3d(0.625140011310577,3.5785219669342,12), Vec3d(0.244717106223106,3.45491504669189,12), Vec3d(0.901369392871857,2.91164398193359,12), Vec3d(0.544967114925385,2.73004698753357,12), Vec3d(1.27852201461792,2.29618692398071,12), Vec3d(0.954914808273315,2.06107401847839,12), Vec3d(1.74730801582336,1.74730801582336,12), Vec3d(1.46446597576141,1.46446597576141,12), Vec3d(2.29618692398071,1.27852201461792,12), Vec3d(2.06107401847839,0.954914808273315,12), Vec3d(2.91164398193359,0.901369392871857,12), Vec3d(2.73004698753357,0.544967114925385,12), Vec3d(3.5785219669342,0.625140011310577,12), Vec3d(3.45491504669189,0.244717106223106,12), Vec3d(4.2804012298584,0.456633001565933,12), Vec3d(4.21782684326172,0.0615576282143593,12), Vec3d(5,0.399999290704727,12), Vec3d(5,0,12), Vec3d(19.6000003814697,0.399999290704727,12), Vec3d(20,0,12), Vec3d(19.6000003814697,20,12), Vec3d(20,20,12), Vec3d(19.5300102233887,21.1571502685547,12), Vec3d(19.9323806762695,21.1609306335449,12), Vec3d(19.3210391998291,22.2974300384521,12), Vec3d(19.7304496765137,22.3061599731445,12), Vec3d(18.9761600494385,23.4042091369629,12), Vec3d(19.3969306945801,23.4202003479004,12), Vec3d(18.5003795623779,24.4613399505615,12), Vec3d(18.9363307952881,24.4879894256592,12), Vec3d(17.9006500244141,25.4534206390381,12), Vec3d(18.3548793792725,25.4950904846191,12), Vec3d(17.1856994628906,26.3659801483154,12), Vec3d(17.6604404449463,26.4278793334961,12), Vec3d(16.3659801483154,27.1856994628906,12), Vec3d(16.862419128418,27.2737407684326,12), Vec3d(15.4534196853638,27.9006500244141,12), Vec3d(15.9715900421143,28.0212306976318,12), Vec3d(14.4613399505615,28.5003795623779,12), Vec3d(15,28.6602592468262,12), Vec3d(13.4042100906372,28.9761600494385,12), Vec3d(13.9608001708984,29.1821594238281,12), Vec3d(12.2974300384521,29.3210391998291,12), Vec3d(7.13196802139282,29.5799007415771,0), Vec3d(8.26351833343506,29.8480796813965,0), Vec3d(8.84284687042236,29.5300102233887,0), Vec3d(9.41855144500732,29.9830799102783,0), Vec3d(10,29.6000003814697,0), Vec3d(10.5814504623413,29.9830799102783,0), Vec3d(11.1571502685547,29.5300102233887,0), Vec3d(11.7364797592163,29.8480796813965,0), Vec3d(12.2974300384521,29.3210391998291,0), Vec3d(12.8680295944214,29.5799007415771,0), Vec3d(13.4042100906372,28.9761600494385,0), Vec3d(13.9608001708984,29.1821594238281,0), Vec3d(14.4613399505615,28.5003795623779,0), Vec3d(15,28.6602592468262,0), Vec3d(15.4534196853638,27.9006500244141,0), Vec3d(15.9715900421143,28.0212306976318,0), Vec3d(16.3659801483154,27.1856994628906,0), Vec3d(16.862419128418,27.2737407684326,0), Vec3d(17.1856994628906,26.3659801483154,0), Vec3d(17.6604404449463,26.4278793334961,0), Vec3d(17.9006500244141,25.4534206390381,0), Vec3d(18.3548793792725,25.4950904846191,0), Vec3d(18.5003795623779,24.4613399505615,0), Vec3d(18.9363307952881,24.4879894256592,0), Vec3d(18.9761600494385,23.4042091369629,0), Vec3d(19.3969306945801,23.4202003479004,0), Vec3d(19.3210391998291,22.2974300384521,0), Vec3d(19.7304496765137,22.3061599731445,0), Vec3d(19.5300102233887,21.1571502685547,0), Vec3d(19.9323806762695,21.1609306335449,0), Vec3d(19.6000003814697,20,0), Vec3d(20,20,0), Vec3d(19.6000003814697,0.399999290704727,0), Vec3d(20,0,0), Vec3d(5,0.399999290704727,0), Vec3d(5,0,0), Vec3d(4.2804012298584,0.456633001565933,0), Vec3d(4.21782684326172,0.0615576282143593,0), Vec3d(3.5785219669342,0.625140011310577,0), Vec3d(3.45491504669189,0.244717106223106,0), Vec3d(2.91164398193359,0.901369392871857,0), Vec3d(2.73004698753357,0.544967114925385,0), Vec3d(2.29618692398071,1.27852201461792,0), Vec3d(2.06107401847839,0.954914808273315,0), Vec3d(1.74730801582336,1.74730801582336,0), Vec3d(1.46446597576141,1.46446597576141,0), Vec3d(1.27852201461792,2.29618692398071,0), Vec3d(0.954914808273315,2.06107401847839,0), Vec3d(0.901369392871857,2.91164398193359,0), Vec3d(0.544967114925385,2.73004698753357,0), Vec3d(0.625140011310577,3.5785219669342,0), Vec3d(0.244717106223106,3.45491504669189,0), Vec3d(0.456633001565933,4.2804012298584,0), Vec3d(0.0615576282143593,4.21782684326172,0), Vec3d(0.399999290704727,5,0), Vec3d(0,5,0), Vec3d(0.399999290704727,20,0), Vec3d(0,20,0), Vec3d(0.469994693994522,21.1571502685547,0), Vec3d(0.067615881562233,21.1609306335449,0), Vec3d(0.678958415985107,22.2974300384521,0), Vec3d(0.269550800323486,22.3061599731445,0), Vec3d(1.02384400367737,23.4042091369629,0), Vec3d(0.603073298931122,23.4202003479004,0), Vec3d(1.49962198734283,24.4613399505615,0), Vec3d(1.0636739730835,24.4879894256592,0), Vec3d(2.0993549823761,25.4534206390381,0), Vec3d(1.64512205123901,25.4950904846191,0), Vec3d(2.81429696083069,26.3659801483154,0), Vec3d(2.33955597877502,26.4278793334961,0), Vec3d(3.63402199745178,27.1856994628906,0), Vec3d(3.13758301734924,27.2737407684326,0), Vec3d(4.54657793045044,27.9006500244141,0), Vec3d(4.02841377258301,28.0212306976318,0), Vec3d(5.53865718841553,28.5003795623779,0), Vec3d(5,28.6602592468262,0), Vec3d(6.59579277038574,28.9761600494385,0), Vec3d(6.03920221328735,29.1821594238281,0), Vec3d(7.70256900787354,29.3210391998291,0) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(2,1,3), Vec3crd(2,3,4), Vec3crd(4,3,5), Vec3crd(4,5,6), Vec3crd(6,5,7), Vec3crd(6,7,8), Vec3crd(8,7,9), Vec3crd(8,9,10), Vec3crd(10,9,11), Vec3crd(10,11,12), Vec3crd(12,11,13), Vec3crd(12,13,14), Vec3crd(14,13,15), Vec3crd(14,15,16), Vec3crd(16,15,17), Vec3crd(16,17,18), Vec3crd(18,17,19), Vec3crd(18,19,20), Vec3crd(20,19,21), Vec3crd(20,21,22), Vec3crd(22,21,23), Vec3crd(22,23,24), Vec3crd(24,23,25), Vec3crd(24,25,26), Vec3crd(26,25,27), Vec3crd(26,27,28), Vec3crd(28,27,29), Vec3crd(28,29,30), Vec3crd(30,29,31), Vec3crd(30,31,32), Vec3crd(32,31,33), Vec3crd(32,33,34), Vec3crd(34,33,35), Vec3crd(34,35,36), Vec3crd(36,35,37), Vec3crd(36,37,38), Vec3crd(38,37,39), Vec3crd(38,39,40), Vec3crd(40,39,41), Vec3crd(40,41,42), Vec3crd(42,41,43), Vec3crd(42,43,44), Vec3crd(44,43,45), Vec3crd(44,45,46), Vec3crd(46,45,47), Vec3crd(46,47,48), Vec3crd(48,47,49), Vec3crd(48,49,50), Vec3crd(50,49,51), Vec3crd(50,51,52), Vec3crd(52,51,53), Vec3crd(52,53,54), Vec3crd(54,53,55), Vec3crd(54,55,56), Vec3crd(56,55,57), Vec3crd(56,57,58), Vec3crd(58,57,59), Vec3crd(58,59,60), Vec3crd(60,59,61), Vec3crd(60,61,62), Vec3crd(62,61,63), Vec3crd(62,63,64), Vec3crd(64,63,65), Vec3crd(64,65,66), Vec3crd(66,65,67), Vec3crd(66,67,68), Vec3crd(68,67,69), Vec3crd(68,69,70), Vec3crd(70,69,71), Vec3crd(70,71,72), Vec3crd(72,71,73), Vec3crd(72,73,74), Vec3crd(74,73,75), Vec3crd(74,75,76), Vec3crd(76,75,77), Vec3crd(76,77,78), Vec3crd(78,77,0), Vec3crd(78,0,2), Vec3crd(79,80,81), Vec3crd(81,80,82), Vec3crd(81,82,83), Vec3crd(83,82,84), Vec3crd(83,84,85), Vec3crd(85,84,86), Vec3crd(85,86,87), Vec3crd(87,86,88), Vec3crd(87,88,89), Vec3crd(89,88,90), Vec3crd(89,90,91), Vec3crd(91,90,92), Vec3crd(91,92,93), Vec3crd(93,92,94), Vec3crd(93,94,95), Vec3crd(95,94,96), Vec3crd(95,96,97), Vec3crd(97,96,98), Vec3crd(97,98,99), Vec3crd(99,98,100), Vec3crd(99,100,101), Vec3crd(101,100,102), Vec3crd(101,102,103), Vec3crd(103,102,104), Vec3crd(103,104,105), Vec3crd(105,104,106), Vec3crd(105,106,107), Vec3crd(107,106,108), Vec3crd(107,108,109), Vec3crd(109,108,110), Vec3crd(109,110,111), Vec3crd(111,110,112), Vec3crd(111,112,113), Vec3crd(113,112,114), Vec3crd(113,114,115), Vec3crd(115,114,116), Vec3crd(115,116,117), Vec3crd(117,116,118), Vec3crd(117,118,119), Vec3crd(119,118,120), Vec3crd(119,120,121), Vec3crd(121,120,122), Vec3crd(121,122,123), Vec3crd(123,122,124), Vec3crd(123,124,125), Vec3crd(125,124,126), Vec3crd(125,126,127), Vec3crd(127,126,128), Vec3crd(127,128,129), Vec3crd(129,128,130), Vec3crd(129,130,131), Vec3crd(131,130,132), Vec3crd(131,132,133), Vec3crd(133,132,134), Vec3crd(133,134,135), Vec3crd(135,134,136), Vec3crd(135,136,137), Vec3crd(137,136,138), Vec3crd(137,138,139), Vec3crd(139,138,140), Vec3crd(139,140,141), Vec3crd(141,140,142), Vec3crd(141,142,143), Vec3crd(143,142,144), Vec3crd(143,144,145), Vec3crd(145,144,146), Vec3crd(145,146,147), Vec3crd(147,146,148), Vec3crd(147,148,149), Vec3crd(149,148,150), Vec3crd(149,150,151), Vec3crd(151,150,152), Vec3crd(151,152,153), Vec3crd(153,152,154), Vec3crd(153,154,155), Vec3crd(155,154,156), Vec3crd(155,156,157), Vec3crd(157,156,79), Vec3crd(157,79,81), Vec3crd(57,110,108), Vec3crd(57,108,59), Vec3crd(59,108,106), Vec3crd(59,106,61), Vec3crd(61,106,104), Vec3crd(61,104,63), Vec3crd(63,104,102), Vec3crd(63,102,65), Vec3crd(65,102,100), Vec3crd(65,100,67), Vec3crd(67,100,98), Vec3crd(67,98,69), Vec3crd(69,98,96), Vec3crd(69,96,71), Vec3crd(71,96,94), Vec3crd(71,94,73), Vec3crd(73,94,92), Vec3crd(73,92,75), Vec3crd(75,92,90), Vec3crd(75,90,77), Vec3crd(77,90,88), Vec3crd(77,88,0), Vec3crd(0,88,86), Vec3crd(0,86,1), Vec3crd(1,86,84), Vec3crd(1,84,3), Vec3crd(3,84,82), Vec3crd(3,82,5), Vec3crd(5,82,80), Vec3crd(5,80,7), Vec3crd(7,80,79), Vec3crd(7,79,9), Vec3crd(9,79,156), Vec3crd(9,156,11), Vec3crd(11,156,154), Vec3crd(11,154,13), Vec3crd(13,154,152), Vec3crd(13,152,15), Vec3crd(15,152,150), Vec3crd(15,150,17), Vec3crd(17,150,148), Vec3crd(17,148,19), Vec3crd(19,148,146), Vec3crd(19,146,21), Vec3crd(21,146,144), Vec3crd(21,144,23), Vec3crd(23,144,142), Vec3crd(23,142,25), Vec3crd(25,142,140), Vec3crd(25,140,27), Vec3crd(27,140,138), Vec3crd(27,138,29), Vec3crd(29,138,136), Vec3crd(29,136,31), Vec3crd(33,31,134), Vec3crd(134,31,136), Vec3crd(33,134,132), Vec3crd(33,132,35), Vec3crd(35,132,130), Vec3crd(35,130,37), Vec3crd(37,130,128), Vec3crd(37,128,39), Vec3crd(39,128,126), Vec3crd(39,126,41), Vec3crd(41,126,124), Vec3crd(41,124,43), Vec3crd(43,124,122), Vec3crd(43,122,45), Vec3crd(45,122,120), Vec3crd(45,120,47), Vec3crd(47,120,118), Vec3crd(47,118,49), Vec3crd(49,118,116), Vec3crd(49,116,51), Vec3crd(51,116,114), Vec3crd(51,114,53), Vec3crd(55,53,112), Vec3crd(112,53,114), Vec3crd(57,55,110), Vec3crd(110,55,112), Vec3crd(30,135,137), Vec3crd(30,137,28), Vec3crd(28,137,139), Vec3crd(28,139,26), Vec3crd(26,139,141), Vec3crd(26,141,24), Vec3crd(24,141,143), Vec3crd(24,143,22), Vec3crd(22,143,145), Vec3crd(22,145,20), Vec3crd(20,145,147), Vec3crd(20,147,18), Vec3crd(18,147,149), Vec3crd(18,149,16), Vec3crd(16,149,151), Vec3crd(16,151,14), Vec3crd(14,151,153), Vec3crd(14,153,12), Vec3crd(12,153,155), Vec3crd(12,155,10), Vec3crd(10,155,157), Vec3crd(10,157,8), Vec3crd(8,157,81), Vec3crd(8,81,6), Vec3crd(6,81,83), Vec3crd(6,83,4), Vec3crd(4,83,85), Vec3crd(4,85,2), Vec3crd(2,85,87), Vec3crd(2,87,78), Vec3crd(78,87,89), Vec3crd(78,89,76), Vec3crd(76,89,91), Vec3crd(76,91,74), Vec3crd(74,91,93), Vec3crd(74,93,72), Vec3crd(72,93,95), Vec3crd(72,95,70), Vec3crd(70,95,97), Vec3crd(70,97,68), Vec3crd(68,97,99), Vec3crd(68,99,66), Vec3crd(66,99,101), Vec3crd(66,101,64), Vec3crd(64,101,103), Vec3crd(64,103,62), Vec3crd(62,103,105), Vec3crd(62,105,60), Vec3crd(60,105,107), Vec3crd(60,107,58), Vec3crd(58,107,109), Vec3crd(58,109,56), Vec3crd(30,32,135), Vec3crd(135,32,133), Vec3crd(52,113,115), Vec3crd(52,115,50), Vec3crd(50,115,117), Vec3crd(50,117,48), Vec3crd(48,117,119), Vec3crd(48,119,46), Vec3crd(46,119,121), Vec3crd(46,121,44), Vec3crd(44,121,123), Vec3crd(44,123,42), Vec3crd(42,123,125), Vec3crd(42,125,40), Vec3crd(40,125,127), Vec3crd(40,127,38), Vec3crd(38,127,129), Vec3crd(38,129,36), Vec3crd(36,129,131), Vec3crd(36,131,34), Vec3crd(34,131,133), Vec3crd(34,133,32), Vec3crd(52,54,113), Vec3crd(113,54,111), Vec3crd(54,56,111), Vec3crd(111,56,109) + }); + break; + case TestMesh::sloping_hole: + vertices = std::vector({ + Vec3d(-20,-20,-5), Vec3d(-20,-20,5), Vec3d(-20,20,-5), Vec3d(-20,20,5), Vec3d(20,-20,-5), Vec3d(20,-20,5), Vec3d(4.46294021606445,7.43144989013672,-5), Vec3d(20,20,-5), Vec3d(-19.1420993804932,0,-5), Vec3d(-18.8330993652344,-2.07911992073059,-5), Vec3d(-17.9195003509521,-4.06736993789673,-5), Vec3d(-16.4412002563477,-5.87785005569458,-5), Vec3d(-14.4629001617432,-7.43144989013672,-5), Vec3d(-12.0711002349854,-8.66024971008301,-5), Vec3d(-9.37016010284424,-9.51056003570557,-5), Vec3d(-3.5217399597168,-9.94521999359131,-5), Vec3d(-6.4782600402832,-9.94521999359131,-5), Vec3d(-0.629840016365051,-9.51056003570557,-5), Vec3d(2.07106995582581,-8.66024971008301,-5), Vec3d(6.44122982025146,-5.87785005569458,-5), Vec3d(4.46294021606445,-7.43144989013672,-5), Vec3d(-12.0711002349854,8.66024971008301,-5), Vec3d(-9.37016010284424,9.51056003570557,-5), Vec3d(7.91947984695435,-4.06736993789673,-5), Vec3d(8.83310031890869,-2.07911992073059,-5), Vec3d(-6.4782600402832,9.94521999359131,-5), Vec3d(-0.629840016365051,9.51056003570557,-5), Vec3d(2.07106995582581,8.66024971008301,-5), Vec3d(9.14214038848877,0,-5), Vec3d(8.83310031890869,2.07911992073059,-5), Vec3d(-3.5217399597168,9.94521999359131,-5), Vec3d(7.91947984695435,4.06736993789673,-5), Vec3d(6.44122982025146,5.87785005569458,-5), Vec3d(-14.4629001617432,7.43144989013672,-5), Vec3d(-16.4412002563477,5.87785005569458,-5), Vec3d(-17.9195003509521,4.06736993789673,-5), Vec3d(-18.8330993652344,2.07911992073059,-5), Vec3d(20,20,5), Vec3d(3.5217399597168,-9.94521999359131,5), Vec3d(-8.83310031890869,-2.07911992073059,5), Vec3d(-9.14214038848877,0,5), Vec3d(-8.83310031890869,2.07911992073059,5), Vec3d(6.4782600402832,-9.94521999359131,5), Vec3d(-7.91947984695435,4.06736993789673,5), Vec3d(-6.44122982025146,5.87785005569458,5), Vec3d(-4.46294021606445,7.43144989013672,5), Vec3d(-2.07106995582581,8.66024971008301,5), Vec3d(0.629840016365051,9.51056003570557,5), Vec3d(12.0711002349854,-8.66024971008301,5), Vec3d(9.37016010284424,-9.51056003570557,5), Vec3d(3.5217399597168,9.94521999359131,5), Vec3d(6.4782600402832,9.94521999359131,5), Vec3d(9.37016010284424,9.51056003570557,5), Vec3d(12.0711002349854,8.66024971008301,5), Vec3d(14.4629001617432,7.43144989013672,5), Vec3d(16.4412002563477,-5.87785005569458,5), Vec3d(14.4629001617432,-7.43144989013672,5), Vec3d(16.4412002563477,5.87785005569458,5), Vec3d(17.9195003509521,4.06736993789673,5), Vec3d(18.8330993652344,-2.07911992073059,5), Vec3d(17.9195003509521,-4.06736993789673,5), Vec3d(18.8330993652344,2.07911992073059,5), Vec3d(19.1420993804932,0,5), Vec3d(0.629840016365051,-9.51056003570557,5), Vec3d(-2.07106995582581,-8.66024971008301,5), Vec3d(-4.46294021606445,-7.43144989013672,5), Vec3d(-6.44122982025146,-5.87785005569458,5), Vec3d(-7.91947984695435,-4.06736993789673,5) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(2,1,3), Vec3crd(1,0,4), Vec3crd(5,1,4), Vec3crd(6,2,7), Vec3crd(0,2,8), Vec3crd(0,8,9), Vec3crd(0,9,10), Vec3crd(0,10,11), Vec3crd(0,11,12), Vec3crd(0,12,13), Vec3crd(0,13,4), Vec3crd(13,14,4), Vec3crd(15,4,16), Vec3crd(17,4,15), Vec3crd(18,4,17), Vec3crd(19,4,20), Vec3crd(18,20,4), Vec3crd(21,2,22), Vec3crd(4,19,23), Vec3crd(4,23,7), Vec3crd(23,24,7), Vec3crd(22,2,25), Vec3crd(26,2,27), Vec3crd(28,29,7), Vec3crd(25,2,30), Vec3crd(29,31,7), Vec3crd(30,2,26), Vec3crd(31,32,7), Vec3crd(27,2,6), Vec3crd(32,6,7), Vec3crd(28,7,24), Vec3crd(33,2,21), Vec3crd(34,2,33), Vec3crd(35,2,34), Vec3crd(36,2,35), Vec3crd(8,2,36), Vec3crd(16,4,14), Vec3crd(2,3,7), Vec3crd(7,3,37), Vec3crd(38,1,5), Vec3crd(3,1,39), Vec3crd(3,39,40), Vec3crd(3,40,41), Vec3crd(42,38,5), Vec3crd(3,41,43), Vec3crd(3,43,44), Vec3crd(37,3,45), Vec3crd(37,45,46), Vec3crd(37,46,47), Vec3crd(48,49,5), Vec3crd(37,47,50), Vec3crd(49,42,5), Vec3crd(37,50,51), Vec3crd(37,51,52), Vec3crd(37,52,53), Vec3crd(37,53,54), Vec3crd(55,56,5), Vec3crd(37,54,57), Vec3crd(37,57,58), Vec3crd(59,60,5), Vec3crd(37,58,61), Vec3crd(37,62,5), Vec3crd(37,61,62), Vec3crd(62,59,5), Vec3crd(60,55,5), Vec3crd(63,1,38), Vec3crd(64,1,63), Vec3crd(65,1,64), Vec3crd(66,1,65), Vec3crd(67,1,66), Vec3crd(39,1,67), Vec3crd(44,45,3), Vec3crd(56,48,5), Vec3crd(5,4,7), Vec3crd(37,5,7), Vec3crd(41,40,36), Vec3crd(36,40,8), Vec3crd(39,9,40), Vec3crd(40,9,8), Vec3crd(43,41,35), Vec3crd(35,41,36), Vec3crd(44,43,34), Vec3crd(34,43,35), Vec3crd(33,45,44), Vec3crd(34,33,44), Vec3crd(21,46,45), Vec3crd(33,21,45), Vec3crd(22,47,46), Vec3crd(21,22,46), Vec3crd(25,50,47), Vec3crd(22,25,47), Vec3crd(30,51,50), Vec3crd(25,30,50), Vec3crd(26,52,51), Vec3crd(30,26,51), Vec3crd(27,53,52), Vec3crd(26,27,52), Vec3crd(6,54,53), Vec3crd(27,6,53), Vec3crd(32,57,54), Vec3crd(6,32,54), Vec3crd(31,58,57), Vec3crd(32,31,57), Vec3crd(29,61,58), Vec3crd(31,29,58), Vec3crd(28,62,61), Vec3crd(29,28,61), Vec3crd(59,62,28), Vec3crd(24,59,28), Vec3crd(60,59,24), Vec3crd(23,60,24), Vec3crd(55,60,23), Vec3crd(19,55,23), Vec3crd(55,19,56), Vec3crd(56,19,20), Vec3crd(56,20,48), Vec3crd(48,20,18), Vec3crd(48,18,49), Vec3crd(49,18,17), Vec3crd(49,17,42), Vec3crd(42,17,15), Vec3crd(42,15,38), Vec3crd(38,15,16), Vec3crd(38,16,63), Vec3crd(63,16,14), Vec3crd(63,14,64), Vec3crd(64,14,13), Vec3crd(64,13,65), Vec3crd(65,13,12), Vec3crd(65,12,66), Vec3crd(66,12,11), Vec3crd(66,11,67), Vec3crd(67,11,10), Vec3crd(67,10,39), Vec3crd(39,10,9) + }); + break; + case TestMesh::ipadstand: + vertices = std::vector({ + Vec3d(17.4344673156738,-2.69879599481136e-16,9.5), Vec3d(14.2814798355103,10,9.5), Vec3d(0,0,9.5), Vec3d(31.7159481048584,10,9.5), Vec3d(62.2344741821289,2.06667568800577e-16,20), Vec3d(31.7159481048584,10,20), Vec3d(17.4344673156738,-2.69879599481136e-16,20), Vec3d(62.2344741821289,10,20), Vec3d(98.2079696655273,10,0), Vec3d(98.2079696655273,8.56525380796383e-16,10), Vec3d(98.2079696655273,0,0), Vec3d(98.2079696655273,10,20), Vec3d(98.2079696655273,0,20), Vec3d(81.6609649658203,-4.39753856997999e-16,10), Vec3d(90.0549850463867,10,10), Vec3d(78.5079803466797,10,10), Vec3d(93.2079696655273,8.56525380796383e-16,10), Vec3d(14.2814798355103,10,20), Vec3d(0,0,20), Vec3d(87.4344711303711,2.81343962782118e-15,20), Vec3d(84.2814788818359,10,20), Vec3d(0,10,20), Vec3d(0,0,0), Vec3d(0,10,0), Vec3d(62.2344741821289,2.06667568800577e-16,30), Vec3d(66.9609756469727,10,30), Vec3d(62.2344741821289,10,30), Vec3d(70.1139602661133,8.5525763717214e-16,30), Vec3d(67.7053375244141,10,28.7107200622559), Vec3d(71.6787109375,1.24046736339707e-15,27.2897701263428) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(1,0,3), Vec3crd(4,5,6), Vec3crd(5,4,7), Vec3crd(8,9,10), Vec3crd(9,11,12), Vec3crd(11,9,8), Vec3crd(13,14,15), Vec3crd(14,13,16), Vec3crd(17,2,1), Vec3crd(2,17,18), Vec3crd(19,11,20), Vec3crd(11,19,12), Vec3crd(17,21,18), Vec3crd(21,2,18), Vec3crd(2,21,22), Vec3crd(22,21,23), Vec3crd(8,22,23), Vec3crd(22,8,10), Vec3crd(24,25,26), Vec3crd(25,24,27), Vec3crd(23,1,8), Vec3crd(1,23,21), Vec3crd(1,21,17), Vec3crd(5,15,3), Vec3crd(15,5,7), Vec3crd(15,7,28), Vec3crd(28,7,26), Vec3crd(28,26,25), Vec3crd(8,14,11), Vec3crd(14,8,3), Vec3crd(3,8,1), Vec3crd(14,3,15), Vec3crd(11,14,20), Vec3crd(26,4,24), Vec3crd(4,26,7), Vec3crd(12,16,9), Vec3crd(16,12,19), Vec3crd(29,4,13), Vec3crd(4,29,24), Vec3crd(24,29,27), Vec3crd(9,22,10), Vec3crd(22,9,0), Vec3crd(0,9,16), Vec3crd(0,16,13), Vec3crd(0,13,6), Vec3crd(6,13,4), Vec3crd(2,22,0), Vec3crd(19,14,16), Vec3crd(14,19,20), Vec3crd(15,29,13), Vec3crd(29,25,27), Vec3crd(25,29,15), Vec3crd(25,15,28), Vec3crd(6,3,0), Vec3crd(3,6,5) + }); + break; + case TestMesh::A: + vertices = std::vector({ + Vec3d(513.075988769531,51.6074333190918,36.0009002685547), Vec3d(516.648803710938,51.7324333190918,36.0009002685547), Vec3d(513.495178222656,51.7324333190918,36.0009002685547), Vec3d(489.391204833984,51.4824333190918,24.0011005401611), Vec3d(488.928588867188,51.7324333190918,24.0011005401611), Vec3d(492.06201171875,51.7324333190918,24.0011005401611), Vec3d(496.840393066406,51.2324333190918,24.0011005401611), Vec3d(495.195404052734,51.7324333190918,24.0011005401611), Vec3d(498.981994628906,51.7324333190918,24.0011005401611), Vec3d(506.966613769531,51.6074333190918,24.0011005401611), Vec3d(510.342010498047,51.7324333190918,24.0011005401611), Vec3d(507.163818359375,51.6074333190918,24.0011005401611), Vec3d(512.515380859375,54.7190322875977,36.0009002685547), Vec3d(514.161987304688,54.5058326721191,36.0009002685547), Vec3d(493.06201171875,54.7190322875977,36.0009002685547), Vec3d(495.195404052734,51.7324333190918,36.0009002685547), Vec3d(496.195404052734,54.7190322875977,36.0009002685547), Vec3d(497.195404052734,57.7058334350586,36.0009002685547), Vec3d(500.851989746094,60.2658309936523,36.0009002685547), Vec3d(498.915405273438,62.8258323669434,36.0009002685547), Vec3d(506.701995849609,62.8258323669434,36.0009002685547), Vec3d(503.648590087891,60.2658309936523,36.0009002685547), Vec3d(508.381805419922,57.7058334350586,36.0009002685547), Vec3d(496.418792724609,60.052433013916,36.0009002685547), Vec3d(506.515197753906,72.2124328613281,36.0009002685547), Vec3d(502.808807373047,74.5324325561523,36.0009002685547), Vec3d(503.781982421875,71.6058349609375,36.0009002685547), Vec3d(515.358764648438,55.4658317565918,36.0009002685547), Vec3d(499.375183105469,76.9058380126953,36.0009002685547), Vec3d(501.168792724609,78.0658340454102,36.0009002685547), Vec3d(504.568786621094,78.0658340454102,36.0009002685547), Vec3d(506.32861328125,81.599235534668,36.0009002685547), Vec3d(502.928588867188,81.599235534668,36.0009002685547), Vec3d(499.528594970703,81.599235534668,36.0009002685547), Vec3d(498.20361328125,77.8658294677734,36.0009002685547), Vec3d(495.195404052734,51.7324333190918,30.0011005401611), Vec3d(498.981994628906,51.7324333190918,27.0011005401611), Vec3d(506.555206298828,51.7324333190918,33.0009002685547), Vec3d(506.555206298828,51.7324333190918,36.0009002685547), Vec3d(510.342010498047,51.7324333190918,36.0009002685547), Vec3d(512.515380859375,54.7190322875977,24.0011005401611), Vec3d(509.361999511719,54.7190322875977,24.0011005401611), Vec3d(508.381805419922,57.7058334350586,24.0011005401611), Vec3d(506.701995849609,62.8258323669434,24.0011005401611), Vec3d(509.188812255859,60.052433013916,24.0011005401611), Vec3d(493.06201171875,54.7190322875977,24.0011005401611), Vec3d(503.648590087891,60.2658309936523,24.0011005401611), Vec3d(500.851989746094,60.2658309936523,24.0011005401611), Vec3d(498.915405273438,62.8258323669434,24.0011005401611), Vec3d(502.808807373047,62.8258323669434,24.0011005401611), Vec3d(491.425201416016,54.5058326721191,24.0011005401611), Vec3d(506.421813964844,76.9058380126953,24.0011005401611), Vec3d(502.808807373047,74.5324325561523,24.0011005401611), Vec3d(504.568786621094,78.0658340454102,24.0011005401611), Vec3d(506.32861328125,81.599235534668,24.0011005401611), Vec3d(507.618804931641,77.8658294677734,24.0011005401611), Vec3d(499.221801757812,72.2124328613281,24.0011005401611), Vec3d(501.835388183594,71.6058349609375,24.0011005401611), Vec3d(501.168792724609,78.0658340454102,24.0011005401611), Vec3d(499.528594970703,81.599235534668,24.0011005401611), Vec3d(502.048583984375,79.8324356079102,24.0011005401611), Vec3d(490.253601074219,55.4658317565918,24.0011005401611), Vec3d(488.928588867188,51.7324333190918,30.0011005401611), Vec3d(488.928588867188,51.7324333190918,36.0009002685547), Vec3d(490.253601074219,55.4658317565918,31.5009002685547), Vec3d(498.20361328125,77.8658294677734,34.5009002685547), Vec3d(508.381805419922,57.7058334350586,30.0011005401611), Vec3d(505.585388183594,57.7058334350586,27.0011005401611), Vec3d(502.788818359375,57.7058334350586,36.0009002685547), Vec3d(499.992004394531,57.7058334350586,33.0009002685547), Vec3d(509.851989746094,53.2258338928223,33.0009002685547), Vec3d(509.361999511719,54.7190322875977,36.0009002685547), Vec3d(508.871795654297,56.2124328613281,27.0011005401611), Vec3d(496.695404052734,56.2124328613281,33.0009002685547), Vec3d(495.695404052734,53.2258338928223,27.0011005401611), Vec3d(506.32861328125,81.599235534668,30.0011005401611), Vec3d(507.618804931641,77.8658294677734,25.5011005401611), Vec3d(515.358764648438,55.4658317565918,34.5009002685547), Vec3d(501.228607177734,81.599235534668,33.0009002685547), Vec3d(504.628601074219,81.599235534668,27.0011005401611), Vec3d(503.781982421875,71.6058349609375,33.0009002685547), Vec3d(502.808807373047,74.5324325561523,30.0011005401611), Vec3d(498.915405273438,62.8258323669434,30.0011005401611), Vec3d(500.861999511719,62.8258323669434,27.0011005401611), Vec3d(502.808807373047,62.8258323669434,36.0009002685547), Vec3d(504.755187988281,62.8258323669434,33.0009002685547), Vec3d(501.835388183594,71.6058349609375,33.0009002685547), Vec3d(499.888793945312,65.7524337768555,33.0009002685547), Vec3d(499.888793945312,65.7524337768555,36.0009002685547), Vec3d(513.128601074219,51.4824333190918,36.0009002685547), Vec3d(513.075988769531,51.6074333190918,24.0011005401611), Vec3d(516.648803710938,51.7324333190918,24.0011005401611), Vec3d(513.128601074219,51.4824333190918,24.0011005401611), Vec3d(513.495178222656,51.7324333190918,24.0011005401611), Vec3d(506.966613769531,51.6074333190918,36.0009002685547), Vec3d(507.163818359375,51.6074333190918,36.0009002685547), Vec3d(490.337799072266,51.4824333190918,24.0011005401611), Vec3d(489.391204833984,51.4824333190918,36.0009002685547), Vec3d(492.06201171875,51.7324333190918,36.0009002685547), Vec3d(490.337799072266,51.4824333190918,36.0009002685547), Vec3d(513.233764648438,51.2324333190918,24.0011005401611), Vec3d(513.233764648438,51.2324333190918,36.0009002685547), Vec3d(504.773803710938,51.4824333190918,36.0009002685547), Vec3d(504.773803710938,51.4824333190918,24.0011005401611), Vec3d(489.266998291016,51.2324333190918,24.0011005401611), Vec3d(489.266998291016,51.2324333190918,36.0009002685547), Vec3d(490.253601074219,55.4658317565918,25.5011005401611), Vec3d(499.528594970703,81.599235534668,30.0011005401611), Vec3d(498.20361328125,77.8658294677734,31.5009002685547), Vec3d(515.358764648438,55.4658317565918,28.5011005401611), Vec3d(515.358764648438,55.4658317565918,25.5011005401611), Vec3d(495.246795654297,61.0124320983887,36.0009002685547), Vec3d(490.253601074219,55.4658317565918,34.5009002685547), Vec3d(490.253601074219,55.4658317565918,36.0009002685547), Vec3d(494.228607177734,66.6658325195312,24.0011005401611), Vec3d(499.068786621094,67.5192337036133,24.0011005401611), Vec3d(498.20361328125,77.8658294677734,25.5011005401611), Vec3d(498.20361328125,77.8658294677734,24.0011005401611), Vec3d(506.608795166016,67.5192337036133,36.0009002685547), Vec3d(509.09521484375,64.7458343505859,36.0009002685547), Vec3d(507.618804931641,77.8658294677734,34.5009002685547), Vec3d(507.618804931641,77.8658294677734,36.0009002685547), Vec3d(510.385406494141,61.0124320983887,24.0011005401611), Vec3d(515.358764648438,55.4658317565918,24.0011005401611), Vec3d(489.32861328125,47.7324333190918,31.5009002685547), Vec3d(492.95361328125,47.7324333190918,33.5634994506836), Vec3d(489.32861328125,47.7324333190918,34.5009002685547), Vec3d(489.32861328125,47.7324333190918,28.5011005401611), Vec3d(489.32861328125,47.7324333190918,25.5011005401611), Vec3d(492.95361328125,47.7324333190918,26.4385013580322), Vec3d(492.95361328125,47.7324333190918,30.5635013580322), Vec3d(492.95361328125,47.7324333190918,32.0634994506836), Vec3d(492.95361328125,47.7324333190918,31.3135013580322), Vec3d(492.95361328125,47.7324333190918,35.4384994506836), Vec3d(489.32861328125,47.7324333190918,36.0009002685547), Vec3d(492.95361328125,47.7324333190918,34.3134994506836), Vec3d(492.95361328125,47.7324333190918,34.6884994506836), Vec3d(492.95361328125,47.7324333190918,27.9385013580322), Vec3d(492.95361328125,47.7324333190918,28.6885013580322), Vec3d(492.95361328125,47.7324333190918,29.0635013580322), Vec3d(489.32861328125,47.7324333190918,24.0011005401611), Vec3d(492.95361328125,47.7324333190918,24.5635013580322), Vec3d(492.95361328125,47.7324333190918,25.6885013580322), Vec3d(492.95361328125,47.7324333190918,25.3135013580322), Vec3d(492.95361328125,47.7324333190918,24.1885013580322), Vec3d(492.95361328125,47.7324333190918,24.0011005401611), Vec3d(513.443786621094,50.7324333190918,24.0011005401611), Vec3d(492.95361328125,47.7324333190918,35.8134994506836), Vec3d(492.95361328125,47.7324333190918,36.0009002685547), Vec3d(513.443786621094,50.7324333190918,36.0009002685547), Vec3d(506.350402832031,51.4824333190918,36.0009002685547), Vec3d(506.350402832031,51.4824333190918,24.0011005401611), Vec3d(492.743804931641,48.2324333190918,24.0011005401611), Vec3d(492.638793945312,48.4824333190918,24.0011005401611), Vec3d(492.743804931641,48.2324333190918,36.0009002685547), Vec3d(492.638793945312,48.4824333190918,36.0009002685547), Vec3d(490.089599609375,50.9824333190918,36.0009002685547), Vec3d(490.089599609375,50.9824333190918,24.0011005401611), Vec3d(510.342010498047,51.7324333190918,30.0011005401611), Vec3d(499.068786621094,67.5192337036133,36.0009002685547), Vec3d(494.228607177734,66.6658325195312,36.0009002685547), Vec3d(499.375183105469,76.9058380126953,24.0011005401611), Vec3d(506.421813964844,76.9058380126953,36.0009002685547), Vec3d(506.608795166016,67.5192337036133,24.0011005401611), Vec3d(505.728607177734,65.7524337768555,24.0011005401611), Vec3d(509.09521484375,64.7458343505859,24.0011005401611), Vec3d(506.701995849609,62.8258323669434,30.0011005401611), Vec3d(505.728607177734,65.7524337768555,27.0011005401611), Vec3d(501.835388183594,71.6058349609375,27.0011005401611), Vec3d(499.888793945312,65.7524337768555,27.0011005401611), Vec3d(494.228607177734,66.6658325195312,30.0011005401611), Vec3d(495.553588867188,70.3992309570312,28.5011005401611), Vec3d(492.903594970703,62.9324340820312,28.5011005401611), Vec3d(495.553588867188,70.3992309570312,31.5009002685547), Vec3d(492.903594970703,62.9324340820312,31.5009002685547), Vec3d(511.488800048828,66.6658325195312,24.0011005401611), Vec3d(511.488800048828,66.6658325195312,30.0011005401611), Vec3d(512.778564453125,62.9324340820312,28.5011005401611), Vec3d(515.358764648438,55.4658317565918,31.5009002685547), Vec3d(507.618804931641,77.8658294677734,31.5009002685547), Vec3d(510.198791503906,70.3992309570312,28.5011005401611), Vec3d(511.488800048828,66.6658325195312,36.0009002685547), Vec3d(512.778564453125,62.9324340820312,31.5009002685547), Vec3d(510.198791503906,70.3992309570312,31.5009002685547), Vec3d(502.788818359375,57.7058334350586,24.0011005401611), Vec3d(497.195404052734,57.7058334350586,30.0011005401611), Vec3d(492.903594970703,62.9324340820312,34.5009002685547), Vec3d(492.903594970703,62.9324340820312,36.0009002685547), Vec3d(495.553588867188,70.3992309570312,24.0011005401611), Vec3d(496.725189208984,69.4392318725586,24.0011005401611), Vec3d(495.553588867188,70.3992309570312,25.5011005401611), Vec3d(495.246795654297,61.0124320983887,24.0011005401611), Vec3d(492.903594970703,62.9324340820312,25.5011005401611), Vec3d(492.903594970703,62.9324340820312,24.0011005401611), Vec3d(495.553588867188,70.3992309570312,36.0009002685547), Vec3d(496.725189208984,69.4392318725586,36.0009002685547), Vec3d(495.553588867188,70.3992309570312,34.5009002685547), Vec3d(510.198791503906,70.3992309570312,36.0009002685547), Vec3d(509.002014160156,69.4392318725586,36.0009002685547), Vec3d(510.198791503906,70.3992309570312,34.5009002685547), Vec3d(512.778564453125,62.9324340820312,25.5011005401611), Vec3d(512.778564453125,62.9324340820312,24.0011005401611), Vec3d(510.198791503906,70.3992309570312,24.0011005401611), Vec3d(509.002014160156,69.4392318725586,24.0011005401611), Vec3d(510.198791503906,70.3992309570312,25.5011005401611), Vec3d(510.385406494141,61.0124320983887,36.0009002685547), Vec3d(512.778564453125,62.9324340820312,34.5009002685547), Vec3d(512.778564453125,62.9324340820312,36.0009002685547), Vec3d(496.840393066406,51.2324333190918,36.0009002685547), Vec3d(498.981994628906,51.7324333190918,36.0009002685547), Vec3d(498.981994628906,51.7324333190918,33.0009002685547), Vec3d(506.555206298828,51.7324333190918,24.0011005401611), Vec3d(506.555206298828,51.7324333190918,27.0011005401611), Vec3d(503.82861328125,47.7324333190918,30.7509002685547), Vec3d(507.45361328125,47.7324333190918,32.8134994506836), Vec3d(503.82861328125,47.7324333190918,33.7509002685547), Vec3d(503.82861328125,47.7324333190918,29.2511005401611), Vec3d(503.82861328125,47.7324333190918,26.2511005401611), Vec3d(507.45361328125,47.7324333190918,27.1885013580322), Vec3d(493.921813964844,57.2792320251465,36.0009002685547), Vec3d(491.425201416016,54.5058326721191,36.0009002685547), Vec3d(497.195404052734,57.7058334350586,24.0011005401611), Vec3d(496.418792724609,60.052433013916,24.0011005401611), Vec3d(509.188812255859,60.052433013916,36.0009002685547), Vec3d(511.675415039062,57.2792320251465,24.0011005401611), Vec3d(514.161987304688,54.5058326721191,24.0011005401611), Vec3d(507.45361328125,47.7324333190918,34.3134994506836), Vec3d(503.82861328125,47.7324333190918,35.2509002685547), Vec3d(507.45361328125,47.7324333190918,25.6885013580322), Vec3d(503.82861328125,47.7324333190918,24.7511005401611), Vec3d(500.20361328125,47.7324333190918,31.6885013580322), Vec3d(500.20361328125,47.7324333190918,28.3135013580322), Vec3d(500.20361328125,47.7324333190918,30.1885013580322), Vec3d(507.45361328125,47.7324333190918,29.8135013580322), Vec3d(507.45361328125,47.7324333190918,31.3135013580322), Vec3d(507.45361328125,47.7324333190918,30.5635013580322), Vec3d(503.82861328125,47.7324333190918,36.0009002685547), Vec3d(507.45361328125,47.7324333190918,35.4384994506836), Vec3d(507.45361328125,47.7324333190918,35.0634994506836), Vec3d(507.45361328125,47.7324333190918,28.6885013580322), Vec3d(507.45361328125,47.7324333190918,29.4385013580322), Vec3d(503.82861328125,47.7324333190918,24.0011005401611), Vec3d(507.45361328125,47.7324333190918,24.5635013580322), Vec3d(507.45361328125,47.7324333190918,24.9385013580322), Vec3d(500.20361328125,47.7324333190918,34.6884994506836), Vec3d(500.20361328125,47.7324333190918,33.1884994506836), Vec3d(500.20361328125,47.7324333190918,33.9384994506836), Vec3d(500.20361328125,47.7324333190918,25.3135013580322), Vec3d(500.20361328125,47.7324333190918,26.8135013580322), Vec3d(500.20361328125,47.7324333190918,26.0635013580322), Vec3d(500.20361328125,47.7324333190918,30.9385013580322), Vec3d(500.20361328125,47.7324333190918,35.0634994506836), Vec3d(500.20361328125,47.7324333190918,35.4384994506836), Vec3d(500.20361328125,47.7324333190918,29.0635013580322), Vec3d(500.20361328125,47.7324333190918,29.4385013580322), Vec3d(500.20361328125,47.7324333190918,24.9385013580322), Vec3d(500.20361328125,47.7324333190918,24.5635013580322), Vec3d(507.45361328125,47.7324333190918,24.1885013580322), Vec3d(507.45361328125,47.7324333190918,24.0011005401611), Vec3d(513.86376953125,49.7324333190918,24.0011005401611), Vec3d(507.45361328125,47.7324333190918,35.8134994506836), Vec3d(507.45361328125,47.7324333190918,36.0009002685547), Vec3d(513.86376953125,49.7324333190918,36.0009002685547), Vec3d(500.20361328125,47.7324333190918,24.1885013580322), Vec3d(500.20361328125,47.7324333190918,24.0011005401611), Vec3d(502.988800048828,49.7324333190918,24.0011005401611), Vec3d(500.20361328125,47.7324333190918,35.8134994506836), Vec3d(500.20361328125,47.7324333190918,36.0009002685547), Vec3d(502.988800048828,49.7324333190918,36.0009002685547), Vec3d(504.755187988281,62.8258323669434,27.0011005401611), Vec3d(499.205383300781,51.2324333190918,36.0009002685547), Vec3d(498.786193847656,51.1074333190918,36.0009002685547), Vec3d(502.358795166016,51.2324333190918,36.0009002685547), Vec3d(499.205383300781,51.2324333190918,24.0011005401611), Vec3d(502.358795166016,51.2324333190918,24.0011005401611), Vec3d(498.786193847656,51.1074333190918,24.0011005401611), Vec3d(502.568786621094,50.7324333190918,24.0011005401611), Vec3d(505.931213378906,51.3574333190918,24.0011005401611), Vec3d(509.503601074219,51.4824333190918,24.0011005401611), Vec3d(502.568786621094,50.7324333190918,36.0009002685547), Vec3d(505.931213378906,51.3574333190918,36.0009002685547), Vec3d(509.503601074219,51.4824333190918,36.0009002685547), Vec3d(499.048583984375,50.4824333190918,36.0009002685547), Vec3d(492.428588867188,48.9824333190918,36.0009002685547), Vec3d(499.048583984375,50.4824333190918,24.0011005401611), Vec3d(492.428588867188,48.9824333190918,24.0011005401611), Vec3d(506.088806152344,50.9824333190918,24.0011005401611), Vec3d(506.036010742188,51.1074333190918,24.0011005401611), Vec3d(506.088806152344,50.9824333190918,36.0009002685547), Vec3d(506.036010742188,51.1074333190918,36.0009002685547), Vec3d(498.891204833984,50.8574333190918,36.0009002685547), Vec3d(498.943786621094,50.7324333190918,36.0009002685547), Vec3d(498.891204833984,50.8574333190918,24.0011005401611), Vec3d(498.943786621094,50.7324333190918,24.0011005401611), Vec3d(499.573608398438,49.2324333190918,24.0011005401611), Vec3d(499.783813476562,48.7324333190918,24.0011005401611), Vec3d(499.573608398438,49.2324333190918,36.0009002685547), Vec3d(499.783813476562,48.7324333190918,36.0009002685547), Vec3d(506.403594970703,50.2324333190918,24.0011005401611), Vec3d(506.298797607422,50.4824333190918,24.0011005401611), Vec3d(506.403594970703,50.2324333190918,36.0009002685547), Vec3d(506.298797607422,50.4824333190918,36.0009002685547), Vec3d(501.228607177734,81.599235534668,27.0011005401611), Vec3d(502.928588867188,81.599235534668,24.0011005401611), Vec3d(499.2587890625,49.9824333190918,36.0009002685547), Vec3d(499.363800048828,49.7324333190918,36.0009002685547), Vec3d(499.2587890625,49.9824333190918,24.0011005401611), Vec3d(499.363800048828,49.7324333190918,24.0011005401611), Vec3d(496.695404052734,56.2124328613281,27.0011005401611), Vec3d(496.195404052734,54.7190322875977,24.0011005401611), Vec3d(509.851989746094,53.2258338928223,27.0011005401611), Vec3d(493.464782714844,51.1074333190918,36.0009002685547), Vec3d(493.464782714844,51.1074333190918,24.0011005401611), Vec3d(502.768798828125,51.7324333190918,24.0011005401611), Vec3d(500.215789794922,51.3574333190918,24.0011005401611), Vec3d(497.628601074219,51.2324333190918,24.0011005401611), Vec3d(502.768798828125,51.7324333190918,36.0009002685547), Vec3d(500.215789794922,51.3574333190918,36.0009002685547), Vec3d(497.628601074219,51.2324333190918,36.0009002685547), Vec3d(507.033813476562,48.7324333190918,24.0011005401611), Vec3d(506.823791503906,49.2324333190918,24.0011005401611), Vec3d(507.033813476562,48.7324333190918,36.0009002685547), Vec3d(506.823791503906,49.2324333190918,36.0009002685547), Vec3d(494.4501953125,51.1074333190918,24.0011005401611), Vec3d(494.4501953125,51.1074333190918,36.0009002685547), Vec3d(500.807006835938,51.3574333190918,36.0009002685547), Vec3d(503.591186523438,51.4824333190918,36.0009002685547), Vec3d(503.591186523438,51.4824333190918,24.0011005401611), Vec3d(500.807006835938,51.3574333190918,24.0011005401611), Vec3d(505.728607177734,65.7524337768555,36.0009002685547), Vec3d(505.728607177734,65.7524337768555,33.0009002685547), Vec3d(499.221801757812,72.2124328613281,36.0009002685547), Vec3d(501.835388183594,71.6058349609375,36.0009002685547), Vec3d(506.515197753906,72.2124328613281,24.0011005401611), Vec3d(503.781982421875,71.6058349609375,24.0011005401611), Vec3d(503.781982421875,71.6058349609375,27.0011005401611), Vec3d(499.888793945312,65.7524337768555,24.0011005401611), Vec3d(495.695404052734,53.2258338928223,33.0009002685547), Vec3d(516.648803710938,51.7324333190918,30.0011005401611), Vec3d(498.20361328125,77.8658294677734,28.5011005401611), Vec3d(505.585388183594,57.7058334350586,33.0009002685547), Vec3d(508.871795654297,56.2124328613281,33.0009002685547), Vec3d(499.992004394531,57.7058334350586,27.0011005401611), Vec3d(504.628601074219,81.599235534668,33.0009002685547), Vec3d(500.861999511719,62.8258323669434,33.0009002685547), Vec3d(496.878601074219,74.1324310302734,27.0011005401611), Vec3d(496.878601074219,74.1324310302734,33.0009002685547), Vec3d(491.57861328125,59.199031829834,27.0011005401611), Vec3d(490.253601074219,55.4658317565918,28.5011005401611), Vec3d(491.57861328125,59.199031829834,33.0009002685547), Vec3d(514.068786621094,59.199031829834,27.0011005401611), Vec3d(514.068786621094,59.199031829834,33.0009002685547), Vec3d(508.908813476562,74.1324310302734,27.0011005401611), Vec3d(507.618804931641,77.8658294677734,28.5011005401611), Vec3d(508.908813476562,74.1324310302734,33.0009002685547), Vec3d(491.271789550781,50.9824333190918,36.0009002685547), Vec3d(490.877807617188,50.9824333190918,36.0009002685547), Vec3d(491.271789550781,50.9824333190918,24.0011005401611), Vec3d(490.877807617188,50.9824333190918,24.0011005401611), Vec3d(495.213806152344,50.9824333190918,36.0009002685547), Vec3d(493.636993408203,50.9824333190918,36.0009002685547), Vec3d(495.213806152344,50.9824333190918,24.0011005401611), Vec3d(493.636993408203,50.9824333190918,24.0011005401611), Vec3d(503.985412597656,51.4824333190918,36.0009002685547), Vec3d(503.985412597656,51.4824333190918,24.0011005401611), Vec3d(511.675415039062,57.2792320251465,36.0009002685547), Vec3d(493.921813964844,57.2792320251465,24.0011005401611), Vec3d(502.768798828125,51.7324333190918,30.0011005401611), Vec3d(506.555206298828,51.7324333190918,30.0011005401611), Vec3d(498.981994628906,51.7324333190918,30.0011005401611), Vec3d(492.848815917969,50.9824333190918,24.0011005401611), Vec3d(492.848815917969,50.9824333190918,36.0009002685547), Vec3d(500.861999511719,68.6792297363281,36.0009002685547), Vec3d(500.861999511719,68.6792297363281,24.0011005401611), Vec3d(496.878601074219,74.1324310302734,24.0011005401611), Vec3d(496.878601074219,74.1324310302734,36.0009002685547), Vec3d(504.755187988281,68.6792297363281,24.0011005401611), Vec3d(504.755187988281,68.6792297363281,36.0009002685547), Vec3d(508.908813476562,74.1324310302734,36.0009002685547), Vec3d(508.908813476562,74.1324310302734,24.0011005401611), Vec3d(505.728607177734,65.7524337768555,30.0011005401611), Vec3d(504.755187988281,68.6792297363281,30.0011005401611), Vec3d(503.781982421875,71.6058349609375,30.0011005401611), Vec3d(500.861999511719,68.6792297363281,30.0011005401611), Vec3d(499.888793945312,65.7524337768555,30.0011005401611), Vec3d(501.835388183594,71.6058349609375,30.0011005401611), Vec3d(491.57861328125,59.199031829834,24.0011005401611), Vec3d(491.57861328125,59.199031829834,36.0009002685547), Vec3d(514.068786621094,59.199031829834,36.0009002685547), Vec3d(514.068786621094,59.199031829834,24.0011005401611), Vec3d(511.07861328125,47.7324333190918,34.8759002685547), Vec3d(511.07861328125,47.7324333190918,31.8759002685547), Vec3d(514.70361328125,47.7324333190918,33.9384994506836), Vec3d(511.07861328125,47.7324333190918,25.1261005401611), Vec3d(514.70361328125,47.7324333190918,26.0635013580322), Vec3d(511.07861328125,47.7324333190918,28.1261005401611), Vec3d(502.788818359375,57.7058334350586,30.0011005401611), Vec3d(502.048583984375,79.8324356079102,36.0009002685547), Vec3d(514.70361328125,47.7324333190918,30.9385013580322), Vec3d(511.07861328125,47.7324333190918,30.3759002685547), Vec3d(514.70361328125,47.7324333190918,29.0635013580322), Vec3d(511.07861328125,47.7324333190918,29.6261005401611), Vec3d(496.57861328125,47.7324333190918,31.1259002685547), Vec3d(496.57861328125,47.7324333190918,32.6259002685547), Vec3d(496.57861328125,47.7324333190918,34.1259002685547), Vec3d(496.57861328125,47.7324333190918,28.8761005401611), Vec3d(496.57861328125,47.7324333190918,27.3761005401611), Vec3d(496.57861328125,47.7324333190918,25.8761005401611), Vec3d(496.57861328125,47.7324333190918,29.6261005401611), Vec3d(514.70361328125,47.7324333190918,35.4384994506836), Vec3d(511.07861328125,47.7324333190918,35.6259002685547), Vec3d(514.70361328125,47.7324333190918,24.5635013580322), Vec3d(511.07861328125,47.7324333190918,24.3761005401611), Vec3d(496.57861328125,47.7324333190918,34.8759002685547), Vec3d(496.57861328125,47.7324333190918,25.1261005401611), Vec3d(496.57861328125,47.7324333190918,35.6259002685547), Vec3d(496.57861328125,47.7324333190918,24.3761005401611), Vec3d(511.07861328125,47.7324333190918,36.0009002685547), Vec3d(511.07861328125,47.7324333190918,24.0011005401611), Vec3d(514.70361328125,47.7324333190918,30.1885013580322), Vec3d(514.70361328125,47.7324333190918,35.8134994506836), Vec3d(514.70361328125,47.7324333190918,29.8135013580322), Vec3d(514.70361328125,47.7324333190918,24.1885013580322), Vec3d(496.57861328125,47.7324333190918,36.0009002685547), Vec3d(496.57861328125,47.7324333190918,24.0011005401611), Vec3d(510.238800048828,49.7324333190918,24.0011005401611), Vec3d(510.238800048828,49.7324333190918,36.0009002685547), Vec3d(514.70361328125,47.7324333190918,24.0011005401611), Vec3d(514.70361328125,47.7324333190918,36.0009002685547), Vec3d(496.158813476562,48.7324333190918,36.0009002685547), Vec3d(496.158813476562,48.7324333190918,24.0011005401611), Vec3d(502.808807373047,62.8258323669434,30.0011005401611), Vec3d(509.608795166016,51.2324333190918,24.0011005401611), Vec3d(509.608795166016,51.2324333190918,36.0009002685547), Vec3d(491.641204833984,50.8574333190918,24.0011005401611), Vec3d(495.423797607422,50.4824333190918,36.0009002685547), Vec3d(495.423797607422,50.4824333190918,24.0011005401611), Vec3d(491.641204833984,50.8574333190918,36.0009002685547), Vec3d(495.528594970703,50.2324333190918,24.0011005401611), Vec3d(492.0087890625,49.9824333190918,24.0011005401611), Vec3d(509.818786621094,50.7324333190918,24.0011005401611), Vec3d(495.948608398438,49.2324333190918,36.0009002685547), Vec3d(495.528594970703,50.2324333190918,36.0009002685547), Vec3d(495.948608398438,49.2324333190918,24.0011005401611), Vec3d(509.818786621094,50.7324333190918,36.0009002685547), Vec3d(492.0087890625,49.9824333190918,36.0009002685547), Vec3d(491.956207275391,50.1074333190918,24.0011005401611), Vec3d(491.956207275391,50.1074333190918,36.0009002685547), Vec3d(502.928588867188,81.599235534668,30.0011005401611), Vec3d(491.851013183594,50.3574333190918,36.0009002685547), Vec3d(491.851013183594,50.3574333190918,24.0011005401611), Vec3d(496.195404052734,54.7190322875977,30.0011005401611), Vec3d(509.361999511719,54.7190322875977,30.0011005401611), Vec3d(488.632598876953,51.7256317138672,30.0011005401611), Vec3d(488.632598876953,51.7256317138672,29.5091018676758), Vec3d(488.632598876953,51.7188339233398,24.0011005401611), Vec3d(488.632598876953,51.7256317138672,27.4929008483887), Vec3d(488.632598876953,51.7324333190918,30.0011005401611), Vec3d(488.632598876953,51.7324333190918,29.0175018310547), Vec3d(488.632598876953,51.7324333190918,24.9847011566162), Vec3d(488.632598876953,51.7324333190918,24.0011005401611), Vec3d(488.632598876953,51.7188339233398,30.0011005401611), Vec3d(488.632598876953,51.7176322937012,24.0011005401611), Vec3d(488.632598876953,51.7182312011719,30.0011005401611), Vec3d(488.632598876953,51.7176322937012,30.0011005401611), Vec3d(488.632598876953,51.715030670166,24.0011005401611), Vec3d(488.632598876953,51.7162322998047,30.0011005401611), Vec3d(488.632598876953,50.761833190918,24.0011005401611), Vec3d(488.632598876953,50.7578315734863,24.0011005401611), Vec3d(488.632598876953,50.7598342895508,30.0011005401611), Vec3d(488.632598876953,50.7522315979004,24.0011005401611), Vec3d(488.632598876953,49.7838325500488,24.0011005401611), Vec3d(488.632598876953,50.2680320739746,30.0011005401611), Vec3d(488.632598876953,51.7046318054199,24.0011005401611), Vec3d(488.632598876953,51.709831237793,30.0011005401611), Vec3d(488.632598876953,50.9120330810547,24.0011005401611), Vec3d(488.632598876953,50.8882331848145,24.0011005401611), Vec3d(488.632598876953,50.9002304077148,30.0011005401611), Vec3d(488.632598876953,47.7324333190918,24.0370998382568), Vec3d(488.632598876953,48.5612335205078,30.0011005401611), Vec3d(488.632598876953,47.7324333190918,24.0011005401611), Vec3d(488.632598876953,47.7324333190918,24.1091003417969), Vec3d(488.632598876953,48.5612335205078,30.0189018249512), Vec3d(488.632598876953,47.7324333190918,25.3211002349854), Vec3d(488.632598876953,48.5612335205078,30.0551013946533), Vec3d(488.632598876953,47.7324333190918,25.4651012420654), Vec3d(488.632598876953,48.5612335205078,30.6609001159668), Vec3d(488.632598876953,47.7324333190918,25.5371017456055), Vec3d(488.632598876953,48.5612335205078,30.7329006195068), Vec3d(488.632598876953,47.7324333190918,25.6091003417969), Vec3d(488.632598876953,48.5612335205078,30.7689018249512), Vec3d(488.632598876953,47.7324333190918,25.8971004486084), Vec3d(488.632598876953,48.5612335205078,30.8051013946533), Vec3d(488.632598876953,47.7324333190918,28.321102142334), Vec3d(488.632598876953,48.5612335205078,30.9491004943848), Vec3d(488.632598876953,47.7324333190918,28.4651012420654), Vec3d(488.632598876953,48.5612335205078,32.1609001159668), Vec3d(488.632598876953,47.7324333190918,28.5371017456055), Vec3d(488.632598876953,48.5612335205078,32.2329025268555), Vec3d(488.632598876953,47.7324333190918,28.6811008453369), Vec3d(488.632598876953,48.5612335205078,32.2689018249512), Vec3d(488.632598876953,47.7324333190918,31.1049003601074), Vec3d(488.632598876953,48.5612335205078,32.3411026000977), Vec3d(488.632598876953,47.7324333190918,31.3929004669189), Vec3d(488.632598876953,49.3900299072266,36.0009002685547), Vec3d(488.632598876953,47.7324333190918,31.536901473999), Vec3d(488.632598876953,47.7324333190918,31.6809005737305), Vec3d(488.632598876953,47.7324333190918,34.1049003601074), Vec3d(488.632598876953,47.7324333190918,34.3929023742676), Vec3d(488.632598876953,47.7324333190918,34.464900970459), Vec3d(488.632598876953,47.7324333190918,34.5369033813477), Vec3d(488.632598876953,47.7324333190918,34.6809005737305), Vec3d(488.632598876953,47.7324333190918,35.8929023742676), Vec3d(488.632598876953,47.7324333190918,35.964900970459), Vec3d(488.632598876953,47.7324333190918,36.0009002685547), Vec3d(488.632598876953,50.8816299438477,24.0011005401611), Vec3d(488.632598876953,50.8850326538086,30.0011005401611), Vec3d(488.632598876953,49.7480316162109,24.0011005401611), Vec3d(488.632598876953,49.7426300048828,24.0011005401611), Vec3d(488.632598876953,49.745231628418,30.0011005401611), Vec3d(488.632598876953,49.7592315673828,24.0011005401611), Vec3d(488.632598876953,49.7536315917969,30.0011005401611), Vec3d(488.632598876953,49.3900299072266,24.0011005401611), Vec3d(488.632598876953,49.5664329528809,30.0011005401611), Vec3d(488.632598876953,50.8786315917969,24.0011005401611), Vec3d(488.632598876953,50.7764320373535,24.0011005401611), Vec3d(488.632598876953,50.8274307250977,30.0011005401611), Vec3d(488.632598876953,50.7550315856934,30.0011005401611), Vec3d(488.632598876953,50.7692337036133,30.0011005401611), Vec3d(488.632598876953,50.9284324645996,24.0011005401611), Vec3d(488.632598876953,50.9202308654785,30.0011005401611), Vec3d(488.632598876953,51.1788330078125,24.0011005401611), Vec3d(488.632598876953,51.139232635498,24.0011005401611), Vec3d(488.632598876953,51.1590309143066,30.0011005401611), Vec3d(488.632598876953,51.2324333190918,24.0011005401611), Vec3d(488.632598876953,51.2056312561035,30.0011005401611), Vec3d(488.632598876953,51.4340324401855,24.0011005401611), Vec3d(488.632598876953,51.3946304321289,24.0011005401611), Vec3d(488.632598876953,51.4142303466797,30.0011005401611), Vec3d(488.632598876953,51.4498329162598,24.0011005401611), Vec3d(488.632598876953,51.5772323608398,30.0011005401611), Vec3d(488.632598876953,51.4418334960938,30.0011005401611), Vec3d(488.632598876953,51.3136329650879,30.0011005401611), Vec3d(488.632598876953,49.7714309692383,30.0011005401611), Vec3d(488.632598876953,51.0338325500488,30.0011005401611), Vec3d(488.632598876953,50.8816299438477,30.0011005401611), Vec3d(488.632598876953,50.8800315856934,30.0011005401611), Vec3d(488.632598876953,51.7188339233398,36.0009002685547), Vec3d(488.632598876953,51.7176322937012,36.0009002685547), Vec3d(488.632598876953,49.3900299072266,30.0011005401611), Vec3d(488.632598876953,50.7522315979004,30.0011005401611), Vec3d(488.632598876953,50.7522315979004,36.0009002685547), Vec3d(488.632598876953,49.7426300048828,30.0011005401611), Vec3d(488.632598876953,49.7426300048828,36.0009002685547), Vec3d(488.632598876953,49.7480316162109,30.0011005401611), Vec3d(488.632598876953,49.7480316162109,36.0009002685547), Vec3d(488.632598876953,51.715030670166,30.0011005401611), Vec3d(488.632598876953,51.715030670166,36.0009002685547), Vec3d(488.632598876953,50.7578315734863,30.0011005401611), Vec3d(488.632598876953,50.7578315734863,36.0009002685547), Vec3d(488.632598876953,50.761833190918,30.0011005401611), Vec3d(488.632598876953,50.761833190918,36.0009002685547), Vec3d(488.632598876953,50.8882331848145,30.0011005401611), Vec3d(488.632598876953,50.8882331848145,36.0009002685547), Vec3d(488.632598876953,49.7592315673828,30.0011005401611), Vec3d(488.632598876953,49.7592315673828,36.0009002685547), Vec3d(488.632598876953,51.1788330078125,30.0011005401611), Vec3d(488.632598876953,51.1788330078125,36.0009002685547), Vec3d(488.632598876953,50.9120330810547,30.0011005401611), Vec3d(488.632598876953,50.9120330810547,36.0009002685547), Vec3d(488.632598876953,51.4498329162598,30.0011005401611), Vec3d(488.632598876953,51.4498329162598,36.0009002685547), Vec3d(488.632598876953,51.7046318054199,30.0011005401611), Vec3d(488.632598876953,51.7046318054199,36.0009002685547), Vec3d(488.632598876953,51.2324333190918,30.0011005401611), Vec3d(488.632598876953,51.2324333190918,36.0009002685547), Vec3d(488.632598876953,51.3946304321289,30.0011005401611), Vec3d(488.632598876953,51.3946304321289,36.0009002685547), Vec3d(488.632598876953,51.4340324401855,30.0011005401611), Vec3d(488.632598876953,51.4340324401855,36.0009002685547), Vec3d(488.632598876953,49.7838325500488,30.0011005401611), Vec3d(488.632598876953,49.7838325500488,36.0009002685547), Vec3d(488.632598876953,50.7764320373535,30.0011005401611), Vec3d(488.632598876953,50.7764320373535,36.0009002685547), Vec3d(488.632598876953,51.139232635498,30.0011005401611), Vec3d(488.632598876953,51.139232635498,36.0009002685547), Vec3d(488.632598876953,50.9284324645996,30.0011005401611), Vec3d(488.632598876953,50.9284324645996,36.0009002685547), Vec3d(488.632598876953,50.8816299438477,36.0009002685547), Vec3d(488.632598876953,50.8786315917969,30.0011005401611), Vec3d(488.632598876953,50.8786315917969,36.0009002685547), Vec3d(488.632598876953,51.7324333190918,35.0173034667969), Vec3d(488.632598876953,51.7324333190918,36.0009002685547), Vec3d(488.632598876953,51.7324333190918,30.9847011566162), Vec3d(517.188415527344,51.7140884399414,24.0011005401611), Vec3d(517.188415527344,51.7140884399414,36.0009002685547), Vec3d(517.188415527344,50.4475173950195,24.0011005401611), Vec3d(517.188415527344,51.7324333190918,35.3734130859375), Vec3d(517.188415527344,51.7324333190918,36.0009002685547), Vec3d(517.188415527344,51.7324333190918,34.1185760498047), Vec3d(517.188415527344,51.7324333190918,31.88330078125), Vec3d(517.188415527344,51.7324333190918,30.0011005401611), Vec3d(517.188415527344,51.7324333190918,28.1187744140625), Vec3d(517.188415527344,51.7324333190918,25.8834266662598), Vec3d(517.188415527344,51.7324333190918,24.6285915374756), Vec3d(517.188415527344,51.7324333190918,24.0011005401611), Vec3d(517.188415527344,47.7324333190918,24.0600452423096), Vec3d(517.188415527344,47.7324333190918,24.0011005401611), Vec3d(517.188415527344,50.4475173950195,36.0009002685547), Vec3d(517.188415527344,47.7324333190918,24.1779975891113), Vec3d(517.188415527344,47.7324333190918,24.6498031616211), Vec3d(517.188415527344,47.7324333190918,28.7625770568848), Vec3d(517.188415527344,47.7324333190918,29.7061901092529), Vec3d(517.188415527344,47.7324333190918,29.9420928955078), Vec3d(517.188415527344,47.7324333190918,30.0600452423096), Vec3d(517.188415527344,47.7324333190918,30.2959480285645), Vec3d(517.188415527344,47.7324333190918,31.2395629882812), Vec3d(517.188415527344,47.7324333190918,35.3521995544434), Vec3d(517.188415527344,47.7324333190918,35.8240051269531), Vec3d(517.188415527344,47.7324333190918,35.9419555664062), Vec3d(517.188415527344,47.7324333190918,36.0009002685547) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(3,4,5), Vec3crd(6,7,8), Vec3crd(9,10,11), Vec3crd(12,2,1), Vec3crd(12,1,13), Vec3crd(14,15,16), Vec3crd(17,18,19), Vec3crd(20,21,22), Vec3crd(17,19,23), Vec3crd(24,25,26), Vec3crd(27,13,1), Vec3crd(28,25,29), Vec3crd(30,31,32), Vec3crd(28,33,34), Vec3crd(35,36,7), Vec3crd(37,38,39), Vec3crd(40,10,41), Vec3crd(42,43,44), Vec3crd(45,5,4), Vec3crd(46,47,48), Vec3crd(46,48,49), Vec3crd(45,4,50), Vec3crd(51,52,53), Vec3crd(51,54,55), Vec3crd(56,52,57), Vec3crd(58,59,60), Vec3crd(61,50,4), Vec3crd(62,63,64), Vec3crd(65,34,33), Vec3crd(66,67,42), Vec3crd(68,17,69), Vec3crd(70,71,22), Vec3crd(66,42,72), Vec3crd(73,16,15), Vec3crd(35,7,74), Vec3crd(75,76,54), Vec3crd(77,27,1), Vec3crd(78,32,31), Vec3crd(75,54,79), Vec3crd(80,26,25), Vec3crd(81,80,25), Vec3crd(82,83,48), Vec3crd(84,20,85), Vec3crd(81,25,86), Vec3crd(87,88,19), Vec3crd(0,89,1), Vec3crd(90,91,92), Vec3crd(90,10,93), Vec3crd(38,94,39), Vec3crd(94,95,39), Vec3crd(3,7,96), Vec3crd(97,15,98), Vec3crd(97,99,15), Vec3crd(92,91,100), Vec3crd(89,101,1), Vec3crd(102,39,95), Vec3crd(103,11,10), Vec3crd(104,96,7), Vec3crd(105,15,99), Vec3crd(106,61,4), Vec3crd(107,108,33), Vec3crd(76,55,54), Vec3crd(109,91,110), Vec3crd(111,23,19), Vec3crd(112,63,113), Vec3crd(114,115,48), Vec3crd(116,59,117), Vec3crd(118,20,119), Vec3crd(120,31,121), Vec3crd(122,44,43), Vec3crd(110,91,123), Vec3crd(124,125,126), Vec3crd(127,128,129), Vec3crd(127,130,124), Vec3crd(131,124,132), Vec3crd(126,133,134), Vec3crd(135,136,126), Vec3crd(137,138,127), Vec3crd(139,127,138), Vec3crd(128,140,141), Vec3crd(142,128,143), Vec3crd(144,140,145), Vec3crd(100,91,146), Vec3crd(147,148,134), Vec3crd(101,149,1), Vec3crd(102,150,39), Vec3crd(103,10,151), Vec3crd(145,140,152), Vec3crd(152,140,153), Vec3crd(148,154,134), Vec3crd(154,155,134), Vec3crd(156,15,105), Vec3crd(157,104,7), Vec3crd(36,8,7), Vec3crd(158,37,39), Vec3crd(159,19,88), Vec3crd(160,19,159), Vec3crd(161,59,58), Vec3crd(161,117,59), Vec3crd(162,31,30), Vec3crd(162,121,31), Vec3crd(163,43,164), Vec3crd(163,165,43), Vec3crd(166,167,43), Vec3crd(167,164,43), Vec3crd(168,57,52), Vec3crd(82,48,169), Vec3crd(114,170,171), Vec3crd(108,65,33), Vec3crd(64,63,112), Vec3crd(114,172,170), Vec3crd(160,173,170), Vec3crd(171,170,173), Vec3crd(172,174,170), Vec3crd(160,170,174), Vec3crd(175,176,177), Vec3crd(178,77,1), Vec3crd(179,31,120), Vec3crd(175,180,176), Vec3crd(181,182,176), Vec3crd(177,176,182), Vec3crd(180,183,176), Vec3crd(181,176,183), Vec3crd(184,42,67), Vec3crd(185,69,17), Vec3crd(160,111,19), Vec3crd(186,187,160), Vec3crd(188,189,114), Vec3crd(190,188,114), Vec3crd(114,48,191), Vec3crd(192,114,193), Vec3crd(194,160,195), Vec3crd(196,160,194), Vec3crd(197,198,181), Vec3crd(199,197,181), Vec3crd(122,43,165), Vec3crd(200,201,175), Vec3crd(202,175,203), Vec3crd(204,175,202), Vec3crd(205,119,20), Vec3crd(206,181,207), Vec3crd(208,209,15), Vec3crd(210,15,209), Vec3crd(211,10,9), Vec3crd(212,10,211), Vec3crd(213,214,215), Vec3crd(216,217,218), Vec3crd(219,14,17), Vec3crd(113,63,220), Vec3crd(221,222,48), Vec3crd(191,48,222), Vec3crd(22,223,20), Vec3crd(205,20,223), Vec3crd(224,40,42), Vec3crd(123,91,225), Vec3crd(214,226,215), Vec3crd(227,215,226), Vec3crd(218,217,228), Vec3crd(229,228,217), Vec3crd(215,230,213), Vec3crd(125,135,126), Vec3crd(217,216,231), Vec3crd(129,128,142), Vec3crd(216,213,232), Vec3crd(130,132,124), Vec3crd(213,216,233), Vec3crd(234,213,235), Vec3crd(236,227,237), Vec3crd(238,237,227), Vec3crd(239,240,216), Vec3crd(233,216,240), Vec3crd(241,242,229), Vec3crd(243,229,242), Vec3crd(215,227,244), Vec3crd(245,215,246), Vec3crd(217,247,229), Vec3crd(248,249,217), Vec3crd(232,213,250), Vec3crd(230,250,213), Vec3crd(133,147,134), Vec3crd(244,227,251), Vec3crd(236,252,227), Vec3crd(251,227,252), Vec3crd(231,216,253), Vec3crd(254,253,216), Vec3crd(141,140,144), Vec3crd(247,255,229), Vec3crd(241,229,256), Vec3crd(255,256,229), Vec3crd(257,241,258), Vec3crd(259,146,91), Vec3crd(260,261,236), Vec3crd(262,1,149), Vec3crd(263,264,241), Vec3crd(265,241,264), Vec3crd(266,236,267), Vec3crd(268,267,236), Vec3crd(49,48,83), Vec3crd(166,43,269), Vec3crd(270,271,272), Vec3crd(273,274,275), Vec3crd(276,274,277), Vec3crd(278,151,10), Vec3crd(279,280,272), Vec3crd(281,39,150), Vec3crd(272,282,279), Vec3crd(155,283,134), Vec3crd(274,276,284), Vec3crd(153,140,285), Vec3crd(286,276,287), Vec3crd(265,276,286), Vec3crd(288,289,279), Vec3crd(268,288,279), Vec3crd(290,291,272), Vec3crd(271,290,272), Vec3crd(292,274,293), Vec3crd(275,274,292), Vec3crd(294,265,295), Vec3crd(276,265,294), Vec3crd(296,297,268), Vec3crd(279,296,268), Vec3crd(241,265,298), Vec3crd(298,265,299), Vec3crd(236,300,268), Vec3crd(300,301,268), Vec3crd(107,33,78), Vec3crd(302,303,59), Vec3crd(304,305,279), Vec3crd(282,304,279), Vec3crd(306,276,307), Vec3crd(284,276,306), Vec3crd(185,17,73), Vec3crd(308,309,221), Vec3crd(158,39,70), Vec3crd(310,41,10), Vec3crd(15,311,208), Vec3crd(7,6,312), Vec3crd(313,314,6), Vec3crd(315,6,314), Vec3crd(316,208,317), Vec3crd(318,317,208), Vec3crd(258,241,319), Vec3crd(319,241,320), Vec3crd(261,321,236), Vec3crd(321,322,236), Vec3crd(6,315,323), Vec3crd(208,324,318), Vec3crd(270,325,318), Vec3crd(326,318,325), Vec3crd(327,328,315), Vec3crd(273,315,328), Vec3crd(118,329,20), Vec3crd(330,20,329), Vec3crd(331,332,25), Vec3crd(86,25,332), Vec3crd(333,334,52), Vec3crd(335,52,334), Vec3crd(115,336,48), Vec3crd(169,48,336), Vec3crd(62,106,4), Vec3crd(35,15,210), Vec3crd(35,337,15), Vec3crd(158,10,212), Vec3crd(158,310,10), Vec3crd(338,178,1), Vec3crd(339,59,116), Vec3crd(107,302,59), Vec3crd(66,22,340), Vec3crd(66,341,22), Vec3crd(185,221,342), Vec3crd(185,308,221), Vec3crd(75,31,179), Vec3crd(75,343,31), Vec3crd(166,20,330), Vec3crd(166,85,20), Vec3crd(81,52,335), Vec3crd(81,168,52), Vec3crd(82,19,344), Vec3crd(82,87,19), Vec3crd(108,339,345), Vec3crd(346,108,345), Vec3crd(64,347,348), Vec3crd(349,347,64), Vec3crd(178,109,350), Vec3crd(351,178,350), Vec3crd(179,352,353), Vec3crd(354,352,179), Vec3crd(355,208,356), Vec3crd(356,208,311), Vec3crd(357,358,6), Vec3crd(358,312,6), Vec3crd(68,22,21), Vec3crd(68,340,22), Vec3crd(221,48,47), Vec3crd(184,342,221), Vec3crd(359,270,360), Vec3crd(318,360,270), Vec3crd(361,362,273), Vec3crd(315,273,362), Vec3crd(272,102,270), Vec3crd(363,270,102), Vec3crd(274,273,103), Vec3crd(364,103,273), Vec3crd(21,19,18), Vec3crd(21,20,84), Vec3crd(184,46,42), Vec3crd(43,42,46), Vec3crd(12,22,71), Vec3crd(365,22,12), Vec3crd(14,98,15), Vec3crd(14,220,63), Vec3crd(40,93,10), Vec3crd(40,225,91), Vec3crd(45,221,309), Vec3crd(366,221,45), Vec3crd(313,367,212), Vec3crd(212,367,368), Vec3crd(36,369,367), Vec3crd(313,36,367), Vec3crd(316,37,367), Vec3crd(37,368,367), Vec3crd(210,367,369), Vec3crd(316,367,210), Vec3crd(362,370,315), Vec3crd(370,323,315), Vec3crd(360,318,371), Vec3crd(371,318,324), Vec3crd(372,331,159), Vec3crd(159,195,160), Vec3crd(373,115,56), Vec3crd(115,114,189), Vec3crd(52,56,161), Vec3crd(374,161,56), Vec3crd(25,28,331), Vec3crd(375,331,28), Vec3crd(376,333,163), Vec3crd(163,203,175), Vec3crd(377,118,24), Vec3crd(118,181,198), Vec3crd(25,24,162), Vec3crd(378,162,24), Vec3crd(52,51,333), Vec3crd(379,333,51), Vec3crd(167,380,381), Vec3crd(376,167,381), Vec3crd(377,381,330), Vec3crd(330,381,380), Vec3crd(335,381,382), Vec3crd(376,381,335), Vec3crd(373,383,169), Vec3crd(169,383,384), Vec3crd(168,385,383), Vec3crd(373,168,383), Vec3crd(372,87,383), Vec3crd(87,384,383), Vec3crd(377,80,381), Vec3crd(80,382,381), Vec3crd(86,383,385), Vec3crd(372,383,86), Vec3crd(106,348,347), Vec3crd(386,106,347), Vec3crd(375,65,346), Vec3crd(108,346,65), Vec3crd(64,112,349), Vec3crd(387,349,112), Vec3crd(171,190,114), Vec3crd(346,345,171), Vec3crd(374,190,345), Vec3crd(171,345,190), Vec3crd(349,172,347), Vec3crd(172,114,192), Vec3crd(386,347,192), Vec3crd(172,192,347), Vec3crd(173,160,196), Vec3crd(171,173,346), Vec3crd(375,346,196), Vec3crd(173,196,346), Vec3crd(172,349,174), Vec3crd(174,186,160), Vec3crd(387,186,349), Vec3crd(174,349,186), Vec3crd(64,348,62), Vec3crd(106,62,348), Vec3crd(108,107,339), Vec3crd(59,339,107), Vec3crd(374,345,116), Vec3crd(339,116,345), Vec3crd(76,353,352), Vec3crd(379,76,352), Vec3crd(388,77,351), Vec3crd(178,351,77), Vec3crd(179,120,354), Vec3crd(378,354,120), Vec3crd(177,200,175), Vec3crd(351,350,177), Vec3crd(389,200,350), Vec3crd(177,350,200), Vec3crd(354,180,352), Vec3crd(180,175,204), Vec3crd(379,352,204), Vec3crd(180,204,352), Vec3crd(182,181,206), Vec3crd(177,182,351), Vec3crd(388,351,206), Vec3crd(182,206,351), Vec3crd(180,354,183), Vec3crd(183,199,181), Vec3crd(378,199,354), Vec3crd(183,354,199), Vec3crd(91,109,338), Vec3crd(178,338,109), Vec3crd(76,75,353), Vec3crd(179,353,75), Vec3crd(389,350,110), Vec3crd(109,110,350), Vec3crd(390,391,392), Vec3crd(393,394,395), Vec3crd(224,122,389), Vec3crd(122,175,201), Vec3crd(365,388,205), Vec3crd(205,207,181), Vec3crd(66,340,396), Vec3crd(68,396,340), Vec3crd(184,396,342), Vec3crd(185,342,396), Vec3crd(66,396,67), Vec3crd(184,67,396), Vec3crd(68,69,396), Vec3crd(185,396,69), Vec3crd(219,111,387), Vec3crd(111,160,187), Vec3crd(366,386,191), Vec3crd(191,193,114), Vec3crd(150,272,280), Vec3crd(102,272,150), Vec3crd(151,277,274), Vec3crd(103,151,274), Vec3crd(161,374,117), Vec3crd(116,117,374), Vec3crd(366,61,386), Vec3crd(106,386,61), Vec3crd(111,187,387), Vec3crd(186,387,187), Vec3crd(56,188,374), Vec3crd(190,374,188), Vec3crd(191,386,193), Vec3crd(192,193,386), Vec3crd(331,375,194), Vec3crd(196,194,375), Vec3crd(28,34,375), Vec3crd(65,375,34), Vec3crd(219,387,113), Vec3crd(112,113,387), Vec3crd(224,389,123), Vec3crd(110,123,389), Vec3crd(51,55,379), Vec3crd(76,379,55), Vec3crd(24,197,378), Vec3crd(199,378,197), Vec3crd(122,201,389), Vec3crd(200,389,201), Vec3crd(333,379,202), Vec3crd(204,202,379), Vec3crd(205,388,207), Vec3crd(206,207,388), Vec3crd(365,27,388), Vec3crd(77,388,27), Vec3crd(162,378,121), Vec3crd(120,121,378), Vec3crd(162,30,25), Vec3crd(30,29,25), Vec3crd(51,53,54), Vec3crd(303,60,59), Vec3crd(28,29,33), Vec3crd(29,397,33), Vec3crd(161,58,52), Vec3crd(53,52,58), Vec3crd(21,84,19), Vec3crd(84,344,19), Vec3crd(46,49,43), Vec3crd(49,269,43), Vec3crd(208,316,209), Vec3crd(210,209,316), Vec3crd(327,313,211), Vec3crd(212,211,313), Vec3crd(36,35,369), Vec3crd(210,369,35), Vec3crd(37,158,368), Vec3crd(212,368,158), Vec3crd(6,8,313), Vec3crd(36,313,8), Vec3crd(326,38,316), Vec3crd(37,316,38), Vec3crd(392,391,398), Vec3crd(399,398,391), Vec3crd(394,400,395), Vec3crd(401,395,400), Vec3crd(390,214,391), Vec3crd(214,213,234), Vec3crd(393,395,218), Vec3crd(218,239,216), Vec3crd(402,230,403), Vec3crd(230,215,245), Vec3crd(125,124,131), Vec3crd(404,125,403), Vec3crd(405,406,231), Vec3crd(231,248,217), Vec3crd(129,137,127), Vec3crd(407,406,129), Vec3crd(130,127,139), Vec3crd(402,130,408), Vec3crd(194,195,331), Vec3crd(159,331,195), Vec3crd(115,189,56), Vec3crd(188,56,189), Vec3crd(14,219,220), Vec3crd(113,220,219), Vec3crd(45,50,366), Vec3crd(61,366,50), Vec3crd(221,366,222), Vec3crd(191,222,366), Vec3crd(17,23,219), Vec3crd(111,219,23), Vec3crd(118,198,24), Vec3crd(197,24,198), Vec3crd(202,203,333), Vec3crd(163,333,203), Vec3crd(40,224,225), Vec3crd(123,225,224), Vec3crd(12,13,365), Vec3crd(27,365,13), Vec3crd(22,365,223), Vec3crd(205,223,365), Vec3crd(42,44,224), Vec3crd(122,224,44), Vec3crd(399,391,234), Vec3crd(214,234,391), Vec3crd(401,239,395), Vec3crd(218,395,239), Vec3crd(214,390,226), Vec3crd(226,238,227), Vec3crd(218,228,393), Vec3crd(228,229,243), Vec3crd(401,399,233), Vec3crd(233,235,213), Vec3crd(392,409,390), Vec3crd(410,390,409), Vec3crd(394,393,411), Vec3crd(412,411,393), Vec3crd(402,403,131), Vec3crd(125,131,403), Vec3crd(405,137,406), Vec3crd(129,406,137), Vec3crd(405,408,139), Vec3crd(130,139,408), Vec3crd(230,245,403), Vec3crd(404,403,245), Vec3crd(231,406,248), Vec3crd(407,248,406), Vec3crd(232,254,216), Vec3crd(402,408,232), Vec3crd(413,404,244), Vec3crd(244,246,215), Vec3crd(414,247,407), Vec3crd(247,217,249), Vec3crd(133,126,136), Vec3crd(415,133,413), Vec3crd(141,143,128), Vec3crd(416,414,141), Vec3crd(410,238,390), Vec3crd(226,390,238), Vec3crd(412,393,243), Vec3crd(228,243,393), Vec3crd(233,399,235), Vec3crd(234,235,399), Vec3crd(237,260,236), Vec3crd(238,410,237), Vec3crd(417,260,410), Vec3crd(237,410,260), Vec3crd(239,401,240), Vec3crd(233,240,401), Vec3crd(242,241,257), Vec3crd(243,242,412), Vec3crd(418,412,257), Vec3crd(242,257,412), Vec3crd(401,419,399), Vec3crd(398,399,419), Vec3crd(417,410,420), Vec3crd(409,420,410), Vec3crd(400,421,401), Vec3crd(419,401,421), Vec3crd(418,422,412), Vec3crd(411,412,422), Vec3crd(413,135,404), Vec3crd(125,404,135), Vec3crd(414,407,142), Vec3crd(129,142,407), Vec3crd(130,402,132), Vec3crd(131,132,402), Vec3crd(133,136,413), Vec3crd(135,413,136), Vec3crd(423,147,415), Vec3crd(133,415,147), Vec3crd(137,405,138), Vec3crd(139,138,405), Vec3crd(141,414,143), Vec3crd(142,143,414), Vec3crd(424,416,144), Vec3crd(141,144,416), Vec3crd(405,254,408), Vec3crd(232,408,254), Vec3crd(244,404,246), Vec3crd(245,246,404), Vec3crd(247,249,407), Vec3crd(248,407,249), Vec3crd(232,250,402), Vec3crd(230,402,250), Vec3crd(415,413,251), Vec3crd(244,251,413), Vec3crd(252,236,266), Vec3crd(251,252,415), Vec3crd(423,415,266), Vec3crd(252,266,415), Vec3crd(231,253,405), Vec3crd(254,405,253), Vec3crd(416,255,414), Vec3crd(247,414,255), Vec3crd(256,263,241), Vec3crd(255,416,256), Vec3crd(424,263,416), Vec3crd(256,416,263), Vec3crd(257,258,418), Vec3crd(425,418,258), Vec3crd(260,417,261), Vec3crd(426,261,417), Vec3crd(422,418,427), Vec3crd(427,259,91), Vec3crd(420,428,417), Vec3crd(428,1,262), Vec3crd(147,423,148), Vec3crd(429,148,423), Vec3crd(263,424,264), Vec3crd(264,295,265), Vec3crd(266,267,423), Vec3crd(267,268,297), Vec3crd(144,145,424), Vec3crd(430,424,145), Vec3crd(49,431,269), Vec3crd(166,269,431), Vec3crd(82,431,83), Vec3crd(49,83,431), Vec3crd(84,85,431), Vec3crd(166,431,85), Vec3crd(82,344,431), Vec3crd(84,431,344), Vec3crd(432,278,90), Vec3crd(10,90,278), Vec3crd(433,0,281), Vec3crd(39,281,0), Vec3crd(362,361,434), Vec3crd(435,271,359), Vec3crd(270,359,271), Vec3crd(436,361,275), Vec3crd(273,275,361), Vec3crd(360,437,359), Vec3crd(277,287,276), Vec3crd(151,278,277), Vec3crd(280,279,289), Vec3crd(150,280,281), Vec3crd(436,438,439), Vec3crd(439,285,140), Vec3crd(90,92,432), Vec3crd(440,432,92), Vec3crd(282,272,291), Vec3crd(441,282,442), Vec3crd(284,293,274), Vec3crd(443,438,284), Vec3crd(278,432,286), Vec3crd(286,299,265), Vec3crd(281,288,433), Vec3crd(288,268,301), Vec3crd(0,433,89), Vec3crd(444,89,433), Vec3crd(435,445,442), Vec3crd(445,134,283), Vec3crd(439,446,436), Vec3crd(361,436,446), Vec3crd(442,290,435), Vec3crd(271,435,290), Vec3crd(438,436,292), Vec3crd(275,292,436), Vec3crd(445,435,447), Vec3crd(359,447,435), Vec3crd(286,287,278), Vec3crd(277,278,287), Vec3crd(288,281,289), Vec3crd(280,289,281), Vec3crd(145,152,430), Vec3crd(443,430,152), Vec3crd(148,429,154), Vec3crd(441,154,429), Vec3crd(424,430,294), Vec3crd(294,307,276), Vec3crd(423,296,429), Vec3crd(296,279,305), Vec3crd(425,440,100), Vec3crd(92,100,440), Vec3crd(290,442,291), Vec3crd(282,291,442), Vec3crd(292,293,438), Vec3crd(284,438,293), Vec3crd(298,320,241), Vec3crd(432,440,298), Vec3crd(300,236,322), Vec3crd(433,300,444), Vec3crd(426,101,444), Vec3crd(89,444,101), Vec3crd(107,448,302), Vec3crd(302,79,54), Vec3crd(78,31,343), Vec3crd(107,78,448), Vec3crd(75,79,448), Vec3crd(302,448,79), Vec3crd(78,343,448), Vec3crd(75,448,343), Vec3crd(427,418,259), Vec3crd(425,259,418), Vec3crd(428,262,417), Vec3crd(426,417,262), Vec3crd(437,449,359), Vec3crd(447,359,449), Vec3crd(434,361,450), Vec3crd(446,450,361), Vec3crd(32,33,397), Vec3crd(78,33,32), Vec3crd(53,303,54), Vec3crd(302,54,303), Vec3crd(152,153,443), Vec3crd(438,443,153), Vec3crd(429,304,441), Vec3crd(282,441,304), Vec3crd(430,443,306), Vec3crd(284,306,443), Vec3crd(154,441,155), Vec3crd(442,155,441), Vec3crd(298,299,432), Vec3crd(286,432,299), Vec3crd(300,433,301), Vec3crd(288,301,433), Vec3crd(185,451,308), Vec3crd(308,74,7), Vec3crd(73,15,337), Vec3crd(185,73,451), Vec3crd(35,74,451), Vec3crd(308,451,74), Vec3crd(73,337,451), Vec3crd(35,451,337), Vec3crd(158,452,310), Vec3crd(310,72,42), Vec3crd(70,22,341), Vec3crd(158,70,452), Vec3crd(66,72,452), Vec3crd(310,452,72), Vec3crd(70,341,452), Vec3crd(66,452,341), Vec3crd(313,327,314), Vec3crd(315,314,327), Vec3crd(316,317,326), Vec3crd(318,326,317), Vec3crd(15,156,311), Vec3crd(356,311,156), Vec3crd(7,312,157), Vec3crd(358,157,312), Vec3crd(211,9,327), Vec3crd(364,327,9), Vec3crd(38,326,94), Vec3crd(363,94,326), Vec3crd(294,295,424), Vec3crd(264,424,295), Vec3crd(296,423,297), Vec3crd(267,297,423), Vec3crd(262,149,426), Vec3crd(101,426,149), Vec3crd(258,319,425), Vec3crd(440,425,319), Vec3crd(261,426,321), Vec3crd(444,321,426), Vec3crd(259,425,146), Vec3crd(100,146,425), Vec3crd(306,307,430), Vec3crd(294,430,307), Vec3crd(304,429,305), Vec3crd(296,305,429), Vec3crd(319,320,440), Vec3crd(298,440,320), Vec3crd(321,444,322), Vec3crd(300,322,444), Vec3crd(445,283,442), Vec3crd(155,442,283), Vec3crd(439,438,285), Vec3crd(153,285,438), Vec3crd(17,68,18), Vec3crd(21,18,68), Vec3crd(46,184,47), Vec3crd(221,47,184), Vec3crd(102,95,363), Vec3crd(94,363,95), Vec3crd(9,11,364), Vec3crd(103,364,11), Vec3crd(6,323,357), Vec3crd(370,357,323), Vec3crd(371,324,355), Vec3crd(208,355,324), Vec3crd(270,363,325), Vec3crd(326,325,363), Vec3crd(327,364,328), Vec3crd(273,328,364), Vec3crd(0,2,39), Vec3crd(12,39,2), Vec3crd(90,93,91), Vec3crd(40,91,93), Vec3crd(14,16,17), Vec3crd(73,17,16), Vec3crd(45,309,7), Vec3crd(308,7,309), Vec3crd(12,71,39), Vec3crd(70,39,71), Vec3crd(40,41,42), Vec3crd(310,42,41), Vec3crd(97,98,63), Vec3crd(14,63,98), Vec3crd(3,5,7), Vec3crd(45,7,5), Vec3crd(118,377,329), Vec3crd(330,329,377), Vec3crd(331,372,332), Vec3crd(86,332,372), Vec3crd(333,376,334), Vec3crd(335,334,376), Vec3crd(115,373,336), Vec3crd(169,336,373), Vec3crd(167,166,380), Vec3crd(330,380,166), Vec3crd(80,81,382), Vec3crd(335,382,81), Vec3crd(86,385,81), Vec3crd(168,81,385), Vec3crd(169,384,82), Vec3crd(87,82,384), Vec3crd(159,88,372), Vec3crd(87,372,88), Vec3crd(163,164,376), Vec3crd(167,376,164), Vec3crd(24,26,377), Vec3crd(80,377,26), Vec3crd(56,57,373), Vec3crd(168,373,57), Vec3crd(32,397,30), Vec3crd(29,30,397), Vec3crd(58,60,53), Vec3crd(303,53,60), Vec3crd(205,181,119), Vec3crd(118,119,181), Vec3crd(163,175,165), Vec3crd(122,165,175), Vec3crd(453,454,455), Vec3crd(454,456,455), Vec3crd(457,455,456), Vec3crd(458,455,457), Vec3crd(459,455,458), Vec3crd(460,455,459), Vec3crd(461,462,463), Vec3crd(464,465,466), Vec3crd(467,468,469), Vec3crd(470,471,472), Vec3crd(465,473,474), Vec3crd(475,476,477), Vec3crd(478,479,480), Vec3crd(481,482,478), Vec3crd(483,484,481), Vec3crd(485,486,483), Vec3crd(487,488,485), Vec3crd(489,490,487), Vec3crd(491,492,489), Vec3crd(493,494,491), Vec3crd(495,496,493), Vec3crd(497,498,495), Vec3crd(499,500,497), Vec3crd(501,502,499), Vec3crd(503,504,501), Vec3crd(505,504,503), Vec3crd(506,504,505), Vec3crd(507,504,506), Vec3crd(508,504,507), Vec3crd(509,504,508), Vec3crd(510,504,509), Vec3crd(511,504,510), Vec3crd(512,504,511), Vec3crd(513,504,512), Vec3crd(514,504,513), Vec3crd(476,515,516), Vec3crd(517,518,519), Vec3crd(520,517,521), Vec3crd(518,522,523), Vec3crd(522,480,479), Vec3crd(524,525,526), Vec3crd(468,470,527), Vec3crd(525,467,528), Vec3crd(529,475,530), Vec3crd(531,532,533), Vec3crd(534,531,535), Vec3crd(536,537,538), Vec3crd(473,539,540), Vec3crd(539,536,541), Vec3crd(537,534,542), Vec3crd(471,520,543), Vec3crd(532,529,544), Vec3crd(545,524,546), Vec3crd(453,461,547), Vec3crd(463,464,548), Vec3crd(523,549,504), Vec3crd(527,550,551), Vec3crd(519,552,553), Vec3crd(521,554,555), Vec3crd(466,556,557), Vec3crd(469,558,559), Vec3crd(528,560,561), Vec3crd(477,562,563), Vec3crd(543,564,565), Vec3crd(535,566,567), Vec3crd(530,568,569), Vec3crd(540,570,571), Vec3crd(474,572,573), Vec3crd(542,574,575), Vec3crd(538,576,577), Vec3crd(541,578,579), Vec3crd(472,580,581), Vec3crd(526,582,583), Vec3crd(533,584,585), Vec3crd(544,586,587), Vec3crd(516,545,588), Vec3crd(588,589,590), Vec3crd(455,460,4), Vec3crd(591,592,63), Vec3crd(462,455,4), Vec3crd(592,547,63), Vec3crd(547,548,63), Vec3crd(465,462,4), Vec3crd(548,557,63), Vec3crd(127,124,501), Vec3crd(127,501,499), Vec3crd(505,503,124), Vec3crd(124,126,507), Vec3crd(124,507,506), Vec3crd(509,508,126), Vec3crd(126,134,512), Vec3crd(126,512,511), Vec3crd(510,509,126), Vec3crd(128,127,493), Vec3crd(128,493,491), Vec3crd(497,495,127), Vec3crd(489,487,128), Vec3crd(140,128,483), Vec3crd(140,483,481), Vec3crd(487,485,128), Vec3crd(478,480,140), Vec3crd(480,522,140), Vec3crd(514,513,134), Vec3crd(504,514,134), Vec3crd(551,581,437), Vec3crd(471,470,434), Vec3crd(445,447,555), Vec3crd(445,555,553), Vec3crd(134,445,553), Vec3crd(134,553,504), Vec3crd(446,439,518), Vec3crd(446,518,517), Vec3crd(439,140,522), Vec3crd(439,522,518), Vec3crd(515,476,358), Vec3crd(563,588,356), Vec3crd(557,573,63), Vec3crd(473,465,4), Vec3crd(437,360,559), Vec3crd(437,559,551), Vec3crd(360,371,561), Vec3crd(360,561,559), Vec3crd(362,434,470), Vec3crd(362,470,468), Vec3crd(370,362,468), Vec3crd(370,468,467), Vec3crd(499,497,127), Vec3crd(506,505,124), Vec3crd(495,493,127), Vec3crd(513,512,134), Vec3crd(481,478,140), Vec3crd(447,449,565), Vec3crd(447,565,555), Vec3crd(450,446,517), Vec3crd(450,517,520), Vec3crd(356,156,569), Vec3crd(356,569,563), Vec3crd(157,358,476), Vec3crd(157,476,475), Vec3crd(357,370,467), Vec3crd(357,467,525), Vec3crd(371,355,583), Vec3crd(371,583,561), Vec3crd(460,459,4), Vec3crd(63,62,593), Vec3crd(63,593,591), Vec3crd(62,4,459), Vec3crd(62,459,458), Vec3crd(532,531,104), Vec3crd(531,534,104), Vec3crd(567,585,105), Vec3crd(575,567,105), Vec3crd(4,3,539), Vec3crd(4,539,473), Vec3crd(536,539,3), Vec3crd(97,63,573), Vec3crd(97,573,571), Vec3crd(571,579,97), Vec3crd(99,97,579), Vec3crd(99,579,577), Vec3crd(105,99,577), Vec3crd(105,577,575), Vec3crd(96,104,534), Vec3crd(96,534,537), Vec3crd(3,96,537), Vec3crd(3,537,536), Vec3crd(503,501,124), Vec3crd(508,507,126), Vec3crd(491,489,128), Vec3crd(511,510,126), Vec3crd(485,483,128), Vec3crd(434,450,520), Vec3crd(434,520,471), Vec3crd(449,437,581), Vec3crd(449,581,565), Vec3crd(156,105,585), Vec3crd(156,585,587), Vec3crd(587,569,156), Vec3crd(104,157,529), Vec3crd(104,529,532), Vec3crd(475,529,157), Vec3crd(590,583,355), Vec3crd(355,356,588), Vec3crd(355,588,590), Vec3crd(358,357,524), Vec3crd(358,524,515), Vec3crd(525,524,357), Vec3crd(458,457,62), Vec3crd(457,593,62), Vec3crd(479,478,482), Vec3crd(479,504,549), Vec3crd(479,482,504), Vec3crd(482,481,484), Vec3crd(472,551,550), Vec3crd(581,551,472), Vec3crd(482,484,504), Vec3crd(484,483,486), Vec3crd(523,553,552), Vec3crd(504,553,523), Vec3crd(540,573,572), Vec3crd(571,573,540), Vec3crd(544,585,584), Vec3crd(587,585,544), Vec3crd(542,577,576), Vec3crd(575,577,542), Vec3crd(526,590,589), Vec3crd(583,590,526), Vec3crd(535,575,574), Vec3crd(567,575,535), Vec3crd(533,567,566), Vec3crd(585,567,533), Vec3crd(538,579,578), Vec3crd(577,579,538), Vec3crd(543,581,580), Vec3crd(565,581,543), Vec3crd(477,569,568), Vec3crd(563,569,477), Vec3crd(530,587,586), Vec3crd(569,587,530), Vec3crd(541,571,570), Vec3crd(579,571,541), Vec3crd(528,583,582), Vec3crd(561,583,528), Vec3crd(591,453,592), Vec3crd(547,592,453), Vec3crd(521,565,564), Vec3crd(555,565,521), Vec3crd(474,557,556), Vec3crd(573,557,474), Vec3crd(516,563,562), Vec3crd(588,563,516), Vec3crd(519,555,554), Vec3crd(553,555,519), Vec3crd(527,559,558), Vec3crd(551,559,527), Vec3crd(469,561,560), Vec3crd(559,561,469), Vec3crd(462,461,455), Vec3crd(453,455,461), Vec3crd(461,463,547), Vec3crd(548,547,463), Vec3crd(465,464,462), Vec3crd(463,462,464), Vec3crd(464,466,548), Vec3crd(557,548,466), Vec3crd(469,560,467), Vec3crd(528,467,560), Vec3crd(472,550,470), Vec3crd(527,470,550), Vec3crd(474,556,465), Vec3crd(466,465,556), Vec3crd(477,568,475), Vec3crd(530,475,568), Vec3crd(516,562,476), Vec3crd(477,476,562), Vec3crd(519,554,517), Vec3crd(521,517,554), Vec3crd(521,564,520), Vec3crd(543,520,564), Vec3crd(523,552,518), Vec3crd(519,518,552), Vec3crd(479,549,522), Vec3crd(523,522,549), Vec3crd(526,589,524), Vec3crd(589,546,524), Vec3crd(527,558,468), Vec3crd(469,468,558), Vec3crd(528,582,525), Vec3crd(526,525,582), Vec3crd(530,586,529), Vec3crd(544,529,586), Vec3crd(533,566,531), Vec3crd(535,531,566), Vec3crd(535,574,534), Vec3crd(542,534,574), Vec3crd(538,578,536), Vec3crd(541,536,578), Vec3crd(540,572,473), Vec3crd(474,473,572), Vec3crd(541,570,539), Vec3crd(540,539,570), Vec3crd(542,576,537), Vec3crd(538,537,576), Vec3crd(543,580,471), Vec3crd(472,471,580), Vec3crd(544,584,532), Vec3crd(533,532,584), Vec3crd(524,545,515), Vec3crd(516,515,545), Vec3crd(545,546,588), Vec3crd(589,588,546), Vec3crd(453,591,454), Vec3crd(593,454,591), Vec3crd(484,486,504), Vec3crd(486,485,488), Vec3crd(486,488,504), Vec3crd(488,487,490), Vec3crd(488,490,504), Vec3crd(490,489,492), Vec3crd(490,492,504), Vec3crd(492,491,494), Vec3crd(492,494,504), Vec3crd(494,493,496), Vec3crd(494,496,504), Vec3crd(496,495,498), Vec3crd(496,498,504), Vec3crd(498,497,500), Vec3crd(498,500,504), Vec3crd(500,499,502), Vec3crd(500,502,504), Vec3crd(501,504,502), Vec3crd(454,593,456), Vec3crd(457,456,593), Vec3crd(594,595,596), Vec3crd(597,598,594), Vec3crd(599,597,594), Vec3crd(600,599,594), Vec3crd(601,600,594), Vec3crd(602,601,594), Vec3crd(603,602,594), Vec3crd(604,603,594), Vec3crd(605,604,594), Vec3crd(606,607,608), Vec3crd(609,606,608), Vec3crd(610,609,608), Vec3crd(611,610,608), Vec3crd(612,611,608), Vec3crd(613,612,608), Vec3crd(614,613,608), Vec3crd(615,614,608), Vec3crd(616,615,608), Vec3crd(617,616,608), Vec3crd(618,617,608), Vec3crd(619,618,608), Vec3crd(620,619,608), Vec3crd(596,608,607), Vec3crd(595,594,598), Vec3crd(608,596,595), Vec3crd(605,594,91), Vec3crd(91,338,602), Vec3crd(91,602,603), Vec3crd(598,597,1), Vec3crd(594,596,91), Vec3crd(608,595,1), Vec3crd(595,598,1), Vec3crd(616,617,392), Vec3crd(610,611,394), Vec3crd(419,421,613), Vec3crd(419,613,614), Vec3crd(422,427,607), Vec3crd(422,607,606), Vec3crd(427,91,596), Vec3crd(427,596,607), Vec3crd(428,420,619), Vec3crd(428,619,620), Vec3crd(1,428,620), Vec3crd(1,620,608), Vec3crd(420,409,618), Vec3crd(420,618,619), Vec3crd(411,422,606), Vec3crd(411,606,609), Vec3crd(398,419,614), Vec3crd(398,614,615), Vec3crd(421,400,612), Vec3crd(421,612,613), Vec3crd(409,392,617), Vec3crd(409,617,618), Vec3crd(394,411,609), Vec3crd(394,609,610), Vec3crd(604,605,91), Vec3crd(338,1,599), Vec3crd(338,599,600), Vec3crd(392,398,615), Vec3crd(392,615,616), Vec3crd(400,394,611), Vec3crd(400,611,612), Vec3crd(603,604,91), Vec3crd(601,602,338), Vec3crd(597,599,1), Vec3crd(600,601,338) + }); + break; + case TestMesh::gt2_teeth: + vertices = std::vector({ + Vec3d(15.8899993896484,19.444055557251,2.67489433288574), Vec3d(15.9129991531372,19.1590557098389,2.67489433288574), Vec3d(15.9039993286133,19.1500549316406,2.67489433288574), Vec3d(15.9489994049072,19.2490558624268,2.67489433288574), Vec3d(15.9579992294312,19.3570556640625,2.67489433288574), Vec3d(15.8819999694824,18.690055847168,2.67489433288574), Vec3d(15.8319997787476,17.7460556030273,2.67489433288574), Vec3d(15.8489999771118,18.819055557251,2.67489433288574), Vec3d(15.8589992523193,17.7190551757812,2.67489433288574), Vec3d(15.8769998550415,19.0490550994873,2.67489433288574), Vec3d(15.7529993057251,17.8080558776855,2.67489433288574), Vec3d(15.7869997024536,19.5010547637939,2.67489433288574), Vec3d(14.0329990386963,18.7170543670654,2.67489433288574), Vec3d(13.9599990844727,18.7460556030273,2.67489433288574), Vec3d(13.9869995117188,20.2840557098389,2.67489433288574), Vec3d(14.2029991149902,20.149055480957,2.67489433288574), Vec3d(14.1939992904663,19.9560546875,2.67489433288574), Vec3d(14.1939992904663,20.1670551300049,2.67489433288574), Vec3d(14.2119998931885,20.0590553283691,2.67489433288574), Vec3d(12.1899995803833,19.1840553283691,2.67489433288574), Vec3d(12.096999168396,19.1950550079346,2.67489433288574), Vec3d(12.1099996566772,20.6690559387207,2.67489433288574), Vec3d(11.382999420166,19.9750556945801,2.67489433288574), Vec3d(11.2599992752075,19.2490558624268,2.67489433288574), Vec3d(11.2369995117188,19.9320545196533,2.67489433288574), Vec3d(11.5349998474121,20.0640544891357,2.67489433288574), Vec3d(11.6259994506836,20.1550559997559,2.67489433288574), Vec3d(11.6829986572266,20.2390556335449,2.67489433288574), Vec3d(11.7369995117188,20.3570556640625,2.67489433288574), Vec3d(11.8449993133545,20.645055770874,2.67489433288574), Vec3d(11.7729988098145,20.4640560150146,2.67489433288574), Vec3d(11.7799987792969,20.5370559692383,9.41389465332031), Vec3d(11.7639999389648,20.4470558166504,2.67489433288574), Vec3d(11.9559993743896,20.6810550689697,2.67489433288574), Vec3d(12.3079996109009,20.6020545959473,2.67489433288574), Vec3d(12.1959991455078,19.1860542297363,2.67489433288574), Vec3d(12.2059993743896,20.6540546417236,2.67489433288574), Vec3d(12.3489990234375,20.3740558624268,2.67489433288574), Vec3d(12.3579998016357,20.2750549316406,2.67489433288574), Vec3d(12.3669996261597,20.266056060791,2.67489433288574), Vec3d(12.3849992752075,20.1670551300049,2.67489433288574), Vec3d(12.4269990921021,20.0680541992188,2.67489433288574), Vec3d(12.5029993057251,19.9540557861328,2.67489433288574), Vec3d(12.6169996261597,19.8550548553467,2.67489433288574), Vec3d(12.7449989318848,19.7800559997559,2.67489433288574), Vec3d(12.7629995346069,19.7800559997559,2.67489433288574), Vec3d(12.8799991607666,19.7350559234619,2.67489433288574), Vec3d(13.0369997024536,19.7250556945801,2.67489433288574), Vec3d(13.0149993896484,19.0340557098389,2.67489433288574), Vec3d(11.1699991226196,19.2580547332764,2.67489433288574), Vec3d(11.0959987640381,19.2580547332764,2.67489433288574), Vec3d(11.1209993362427,19.9230556488037,2.67489433288574), Vec3d(13.0599994659424,19.024055480957,2.67489433288574), Vec3d(14.9049997329712,18.3170547485352,2.67489433288574), Vec3d(14.8779993057251,18.3400554656982,2.67489433288574), Vec3d(14.8779993057251,19.149055480957,2.67489433288574), Vec3d(13.3039989471436,19.77805519104,2.67489433288574), Vec3d(13.1589994430542,18.9890556335449,2.67489433288574), Vec3d(13.1559991836548,19.7350559234619,2.67489433288574), Vec3d(13.4269990921021,19.8600559234619,2.67489433288574), Vec3d(13.5339994430542,19.9700546264648,2.67389440536499), Vec3d(13.6359996795654,20.1220550537109,2.67489433288574), Vec3d(13.6359996795654,20.1400547027588,2.67489433288574), Vec3d(13.6719989776611,20.2210559844971,2.67489433288574), Vec3d(13.6899995803833,20.2300548553467,2.67489433288574), Vec3d(13.7509994506836,20.3010559082031,2.67489433288574), Vec3d(13.8539991378784,20.3180541992188,2.67489433288574), Vec3d(14.8329992294312,18.3580551147461,2.67489433288574), Vec3d(14.1849994659424,19.8530559539795,2.67489433288574), Vec3d(14.0769996643066,18.7000541687012,2.67489433288574), Vec3d(14.1099996566772,20.2400550842285,2.67489433288574), Vec3d(14.2009992599487,19.6230545043945,2.67489433288574), Vec3d(14.2729997634888,19.4670543670654,2.67489433288574), Vec3d(14.3379993438721,19.3790550231934,2.67489433288574), Vec3d(14.4549999237061,19.2770557403564,2.67489433288574), Vec3d(14.5899991989136,19.2040557861328,2.67489433288574), Vec3d(14.6079998016357,19.2040557861328,2.67489433288574), Vec3d(14.7209997177124,19.1600551605225,2.67489433288574), Vec3d(15.1379995346069,19.210054397583,2.67489433288574), Vec3d(14.9949998855591,18.2680549621582,2.67489433288574), Vec3d(15.0029993057251,19.1580543518066,2.67489433288574), Vec3d(15.2369995117188,19.2760543823242,2.67489433288574), Vec3d(15.3779993057251,19.4060554504395,2.67489433288574), Vec3d(15.4539995193481,19.520055770874,2.67489433288574), Vec3d(15.471999168396,19.52805519104,2.67489433288574), Vec3d(15.5449991226196,19.5830554962158,2.67489433288574), Vec3d(15.6529998779297,19.573055267334,2.67489433288574), Vec3d(15.7059993743896,17.8360557556152,2.67489433288574), Vec3d(15.9449996948242,18.5560550689697,2.67489433288574), Vec3d(15.8589992523193,18.9380550384521,2.67489433288574), Vec3d(14.9589996337891,18.2950553894043,2.67489433288574), Vec3d(15.7779998779297,19.5100555419922,2.67489433288574), Vec3d(14.0049991607666,20.2750549316406,2.67489433288574), Vec3d(12.3489990234375,20.5000553131104,2.67489433288574), Vec3d(13.0689992904663,19.0150547027588,2.67489433288574), Vec3d(13.0999994277954,19.0100555419922,2.67489433288574), Vec3d(15.9489994049072,19.3670558929443,9.41489505767822), Vec3d(15.9489994049072,19.2490558624268,9.41489505767822), Vec3d(15.75,17.8080558776855,9.41489505767822), Vec3d(15.6639995574951,19.5710544586182,9.41489505767822), Vec3d(15.5709991455078,17.9260559082031,9.41489505767822), Vec3d(15.8769998550415,18.690055847168,9.41489505767822), Vec3d(15.8499994277954,18.8170547485352,9.41489505767822), Vec3d(15.9459991455078,18.5520553588867,9.41489505767822), Vec3d(15.914999961853,17.6890544891357,9.41489505767822), Vec3d(15.3999996185303,19.4290542602539,9.41489505767822), Vec3d(15.3099994659424,19.339054107666,9.41489505767822), Vec3d(15.3729991912842,18.0440559387207,9.41489505767822), Vec3d(15.4579992294312,19.5170555114746,9.41489505767822), Vec3d(15.5469999313354,19.5820541381836,9.41489505767822), Vec3d(13.2309989929199,19.7610549926758,9.41489505767822), Vec3d(13.168999671936,19.7360553741455,9.41489505767822), Vec3d(13.096999168396,19.0140552520752,9.41489505767822), Vec3d(13.1999988555908,18.9870548248291,9.41489505767822), Vec3d(15.1399993896484,19.2080554962158,9.41489505767822), Vec3d(15.0159997940063,19.1600551605225,9.41489505767822), Vec3d(14.9859991073608,18.2770557403564,9.41489505767822), Vec3d(15.1749992370605,18.1690559387207,9.41489505767822), Vec3d(15.9039993286133,19.1320552825928,9.41489505767822), Vec3d(15.8949995040894,19.4460544586182,9.41489505767822), Vec3d(15.8769998550415,19.0420551300049,9.41489505767822), Vec3d(12.2169990539551,20.6500549316406,9.41489505767822), Vec3d(11.9379997253418,20.6810550689697,9.41489505767822), Vec3d(11.8629989624023,19.2130546569824,9.41489505767822), Vec3d(12.096999168396,19.1950550079346,9.41489505767822), Vec3d(14.1669998168945,18.6640548706055,9.41489505767822), Vec3d(14.1039991378784,20.2460556030273,9.41489505767822), Vec3d(13.9849996566772,18.7360553741455,9.41489505767822), Vec3d(14.7349996566772,19.1590557098389,9.41489505767822), Vec3d(14.5849990844727,19.2050552368164,9.41489505767822), Vec3d(14.5719995498657,18.4850559234619,9.41489505767822), Vec3d(14.1939992904663,19.6760559082031,9.41489505767822), Vec3d(14.1849994659424,19.9330558776855,9.41489505767822), Vec3d(14.1759996414185,18.6640548706055,9.41489505767822), Vec3d(14.261999130249,19.4890556335449,9.41489505767822), Vec3d(14.3539991378784,19.3610553741455,9.41489505767822), Vec3d(14.3559989929199,18.5830554962158,9.41489505767822), Vec3d(11.6039991378784,20.1250553131104,9.41489505767822), Vec3d(11.5209999084473,20.0520553588867,9.41489505767822), Vec3d(11.4209995269775,19.2480545043945,9.41489505767822), Vec3d(11.6989994049072,20.2690544128418,9.41389465332031), Vec3d(11.7609996795654,20.4310550689697,9.41489505767822), Vec3d(11.8359994888306,19.2130546569824,9.41489505767822), Vec3d(14.1889991760254,20.1710548400879,9.41489505767822), Vec3d(13.9689998626709,20.2840557098389,9.41489505767822), Vec3d(13.8739995956421,20.315055847168,9.41489505767822), Vec3d(13.7799997329712,18.8080558776855,9.41489505767822), Vec3d(13.9869995117188,20.2750549316406,9.41489505767822), Vec3d(12.3129997253418,20.5980548858643,9.41489505767822), Vec3d(12.3399991989136,20.5090560913086,9.41489505767822), Vec3d(12.3489990234375,20.3830547332764,9.41489505767822), Vec3d(12.3599996566772,20.2680549621582,9.41489505767822), Vec3d(12.3849992752075,20.1850547790527,9.41489505767822), Vec3d(12.3849992752075,20.1670551300049,9.41489505767822), Vec3d(12.4249992370605,20.065055847168,9.41489505767822), Vec3d(12.4729995727539,19.1350555419922,9.41489505767822), Vec3d(14.4399995803833,19.2900543212891,9.41489505767822), Vec3d(14.3649997711182,18.5740547180176,9.41489505767822), Vec3d(13.5729999542236,20.0310554504395,9.41489505767822), Vec3d(13.4889993667603,19.9140548706055,9.41489505767822), Vec3d(13.5639991760254,18.8710556030273,9.41489505767822), Vec3d(13.6389999389648,20.1310558319092,9.41489505767822), Vec3d(13.6719989776611,20.2130546569824,9.41489505767822), Vec3d(13.75,20.3020553588867,9.41489505767822), Vec3d(12.7399997711182,19.7810554504395,9.41489505767822), Vec3d(12.6189994812012,19.8520545959473,9.41489505767822), Vec3d(12.5799999237061,19.1200542449951,9.41489505767822), Vec3d(12.8349990844727,19.069055557251,9.41489505767822), Vec3d(11.2669992446899,19.9350547790527,9.41489505767822), Vec3d(11.1029987335205,19.9230556488037,9.41489505767822), Vec3d(11.0209999084473,19.2600555419922,9.41489505767822), Vec3d(11.3819999694824,19.9710559844971,9.41489505767822), Vec3d(13.418999671936,19.8530559539795,9.41489505767822), Vec3d(13.4329996109009,18.9160556793213,9.41489505767822), Vec3d(11.8399991989136,20.6430549621582,9.41489505767822), Vec3d(13.3119993209839,19.7800559997559,9.41489505767822), Vec3d(15.2189998626709,19.2600555419922,9.41489505767822), Vec3d(15.1839990615845,18.1600551605225,9.41489505767822), Vec3d(15.3639993667603,18.0520553588867,9.41489505767822), Vec3d(13.0189990997314,19.7250556945801,9.41489505767822), Vec3d(12.8949995040894,19.7350559234619,9.41489505767822), Vec3d(15.9039993286133,19.1500549316406,9.41489505767822), Vec3d(15.7699995040894,19.5140552520752,9.41489505767822), Vec3d(15.8589992523193,18.9340553283691,9.41489505767822), Vec3d(14.1939992904663,19.9510555267334,9.41489505767822), Vec3d(14.2119998931885,20.0630550384521,9.41489505767822), Vec3d(14.8589992523193,19.149055480957,9.41489505767822), Vec3d(14.8159999847412,18.3670558929443,9.41489505767822), Vec3d(14.8959999084473,18.3220558166504,9.41489505767822), Vec3d(12.5189990997314,19.9360542297363,9.41489505767822), Vec3d(11.0209999084473,19.9290542602539,9.41489505767822), Vec3d(11.0209999084473,19.2530555725098,2.67489433288574), Vec3d(11.0209999084473,19.9300556182861,2.67489433288574), Vec3d(15.9799995422363,18.505931854248,5.58724021911621), Vec3d(15.9799995422363,18.5044555664062,9.41489505767822), Vec3d(15.9799995422363,18.5041732788086,2.67489433288574), Vec3d(15.9799995422363,18.1684837341309,2.67489433288574), Vec3d(15.9799995422363,18.1288299560547,9.41489505767822), Vec3d(15.9799995422363,17.9876575469971,2.67489433288574), Vec3d(15.9799995422363,17.6247596740723,3.91620373725891), Vec3d(15.9799995422363,17.6247596740723,2.67489433288574), Vec3d(15.9799995422363,17.6254329681396,4.32245063781738), Vec3d(15.9799995422363,17.8920269012451,9.41489505767822), Vec3d(15.9799995422363,17.8795108795166,2.67489433288574), Vec3d(15.9799995422363,17.629810333252,4.58585262298584), Vec3d(15.9799995422363,17.6336059570312,5.27938556671143), Vec3d(15.9799995422363,17.8311748504639,2.67489433288574), Vec3d(15.9799995422363,17.638355255127,9.41489505767822), Vec3d(15.9799995422363,17.6346111297607,5.98653984069824), Vec3d(15.9799995422363,17.8728256225586,2.67489433288574), Vec3d(15.9799995422363,18.2221603393555,2.67489433288574) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(0,3,1), Vec3crd(0,4,3), Vec3crd(5,6,7), Vec3crd(8,6,5), Vec3crd(2,9,0), Vec3crd(6,10,11), Vec3crd(12,13,14), Vec3crd(15,16,17), Vec3crd(18,16,15), Vec3crd(19,20,21), Vec3crd(22,23,24), Vec3crd(25,23,22), Vec3crd(26,23,25), Vec3crd(27,23,26), Vec3crd(28,23,27), Vec3crd(29,30,31), Vec3crd(29,32,30), Vec3crd(29,28,32), Vec3crd(33,28,29), Vec3crd(33,23,28), Vec3crd(21,23,33), Vec3crd(20,23,21), Vec3crd(34,35,36), Vec3crd(37,35,34), Vec3crd(38,35,37), Vec3crd(39,35,38), Vec3crd(40,35,39), Vec3crd(41,35,40), Vec3crd(42,35,41), Vec3crd(43,35,42), Vec3crd(44,35,43), Vec3crd(45,35,44), Vec3crd(46,35,45), Vec3crd(47,35,46), Vec3crd(48,35,47), Vec3crd(49,50,51), Vec3crd(52,48,47), Vec3crd(23,49,24), Vec3crd(53,54,55), Vec3crd(56,57,58), Vec3crd(59,57,56), Vec3crd(60,57,59), Vec3crd(61,57,60), Vec3crd(62,57,61), Vec3crd(63,57,62), Vec3crd(64,57,63), Vec3crd(65,57,64), Vec3crd(66,57,65), Vec3crd(13,57,66), Vec3crd(54,67,55), Vec3crd(68,69,70), Vec3crd(71,69,68), Vec3crd(72,69,71), Vec3crd(73,69,72), Vec3crd(74,69,73), Vec3crd(75,69,74), Vec3crd(76,69,75), Vec3crd(77,69,76), Vec3crd(67,69,77), Vec3crd(70,16,68), Vec3crd(70,17,16), Vec3crd(78,79,80), Vec3crd(81,79,78), Vec3crd(82,79,81), Vec3crd(83,79,82), Vec3crd(84,79,83), Vec3crd(85,79,84), Vec3crd(86,79,85), Vec3crd(87,79,86), Vec3crd(88,8,5), Vec3crd(11,7,6), Vec3crd(11,89,7), Vec3crd(11,9,89), Vec3crd(11,0,9), Vec3crd(55,90,53), Vec3crd(55,79,90), Vec3crd(55,80,79), Vec3crd(91,11,10), Vec3crd(92,69,12), Vec3crd(92,70,69), Vec3crd(34,93,37), Vec3crd(47,94,52), Vec3crd(47,95,94), Vec3crd(47,57,95), Vec3crd(47,58,57), Vec3crd(51,24,49), Vec3crd(21,35,19), Vec3crd(21,36,35), Vec3crd(14,92,12), Vec3crd(86,10,87), Vec3crd(86,91,10), Vec3crd(77,55,67), Vec3crd(66,14,13), Vec3crd(96,97,4), Vec3crd(98,99,100), Vec3crd(101,102,98), Vec3crd(103,101,98), Vec3crd(104,103,98), Vec3crd(105,106,107), Vec3crd(108,105,107), Vec3crd(109,108,107), Vec3crd(100,109,107), Vec3crd(110,111,112), Vec3crd(113,110,112), Vec3crd(114,115,116), Vec3crd(117,114,116), Vec3crd(118,119,120), Vec3crd(121,122,123), Vec3crd(124,121,123), Vec3crd(125,126,127), Vec3crd(128,129,130), Vec3crd(131,132,133), Vec3crd(71,131,133), Vec3crd(134,71,133), Vec3crd(135,134,133), Vec3crd(136,135,133), Vec3crd(137,138,139), Vec3crd(140,137,139), Vec3crd(141,140,139), Vec3crd(142,31,141), Vec3crd(142,141,139), Vec3crd(143,126,132), Vec3crd(144,145,146), Vec3crd(147,144,146), Vec3crd(127,147,146), Vec3crd(148,121,124), Vec3crd(149,148,124), Vec3crd(150,149,124), Vec3crd(151,150,124), Vec3crd(152,151,124), Vec3crd(153,152,124), Vec3crd(154,153,124), Vec3crd(155,154,124), Vec3crd(129,156,157), Vec3crd(130,129,157), Vec3crd(158,159,160), Vec3crd(161,158,160), Vec3crd(162,161,160), Vec3crd(163,162,160), Vec3crd(146,163,160), Vec3crd(164,165,166), Vec3crd(167,164,166), Vec3crd(168,169,170), Vec3crd(171,168,170), Vec3crd(139,171,170), Vec3crd(159,172,173), Vec3crd(123,174,142), Vec3crd(175,110,113), Vec3crd(173,175,113), Vec3crd(106,176,177), Vec3crd(178,106,177), Vec3crd(179,180,167), Vec3crd(112,179,167), Vec3crd(175,173,172), Vec3crd(119,118,181), Vec3crd(119,181,97), Vec3crd(119,97,96), Vec3crd(182,98,102), Vec3crd(182,102,183), Vec3crd(182,183,120), Vec3crd(182,120,119), Vec3crd(143,132,184), Vec3crd(184,185,143), Vec3crd(147,127,126), Vec3crd(174,123,122), Vec3crd(159,173,160), Vec3crd(126,125,133), Vec3crd(126,133,132), Vec3crd(186,187,188), Vec3crd(186,188,116), Vec3crd(186,116,115), Vec3crd(99,98,182), Vec3crd(109,100,99), Vec3crd(106,178,107), Vec3crd(114,117,177), Vec3crd(114,177,176), Vec3crd(128,130,187), Vec3crd(128,187,186), Vec3crd(135,136,157), Vec3crd(135,157,156), Vec3crd(163,146,145), Vec3crd(164,167,180), Vec3crd(179,112,111), Vec3crd(171,139,138), Vec3crd(189,155,166), Vec3crd(189,166,165), Vec3crd(149,150,93), Vec3crd(154,155,189), Vec3crd(31,142,174), Vec3crd(114,176,78), Vec3crd(81,78,176), Vec3crd(7,89,183), Vec3crd(89,9,120), Vec3crd(89,120,183), Vec3crd(78,80,114), Vec3crd(176,106,81), Vec3crd(88,5,103), Vec3crd(183,102,7), Vec3crd(118,120,9), Vec3crd(9,2,181), Vec3crd(9,181,118), Vec3crd(115,114,80), Vec3crd(82,81,106), Vec3crd(101,103,5), Vec3crd(102,101,5), Vec3crd(5,7,102), Vec3crd(97,181,2), Vec3crd(2,1,97), Vec3crd(1,3,97), Vec3crd(80,55,115), Vec3crd(172,159,59), Vec3crd(59,56,172), Vec3crd(3,4,97), Vec3crd(4,0,96), Vec3crd(105,108,82), Vec3crd(186,115,55), Vec3crd(82,106,105), Vec3crd(83,82,108), Vec3crd(60,59,159), Vec3crd(175,172,56), Vec3crd(119,96,0), Vec3crd(0,11,119), Vec3crd(108,109,84), Vec3crd(84,83,108), Vec3crd(55,77,186), Vec3crd(56,58,110), Vec3crd(56,110,175), Vec3crd(60,159,158), Vec3crd(11,91,182), Vec3crd(182,119,11), Vec3crd(91,86,182), Vec3crd(85,84,109), Vec3crd(86,85,99), Vec3crd(128,186,77), Vec3crd(58,111,110), Vec3crd(158,161,60), Vec3crd(26,25,137), Vec3crd(138,137,25), Vec3crd(99,182,86), Vec3crd(109,99,85), Vec3crd(77,76,128), Vec3crd(58,47,111), Vec3crd(61,60,161), Vec3crd(137,140,26), Vec3crd(27,26,140), Vec3crd(25,22,138), Vec3crd(129,128,76), Vec3crd(76,75,129), Vec3crd(75,74,129), Vec3crd(74,73,156), Vec3crd(73,72,135), Vec3crd(68,16,184), Vec3crd(68,184,132), Vec3crd(16,18,185), Vec3crd(161,162,62), Vec3crd(62,61,161), Vec3crd(179,111,47), Vec3crd(171,138,22), Vec3crd(156,129,74), Vec3crd(135,156,73), Vec3crd(134,135,72), Vec3crd(72,71,134), Vec3crd(68,132,131), Vec3crd(185,184,16), Vec3crd(18,15,185), Vec3crd(63,62,162), Vec3crd(28,27,140), Vec3crd(22,24,171), Vec3crd(71,68,131), Vec3crd(15,17,143), Vec3crd(15,143,185), Vec3crd(17,70,143), Vec3crd(70,92,126), Vec3crd(162,163,64), Vec3crd(64,63,162), Vec3crd(180,179,47), Vec3crd(47,46,180), Vec3crd(140,141,28), Vec3crd(168,171,24), Vec3crd(126,143,70), Vec3crd(92,14,147), Vec3crd(147,126,92), Vec3crd(14,66,144), Vec3crd(14,144,147), Vec3crd(65,64,163), Vec3crd(66,65,145), Vec3crd(46,45,180), Vec3crd(32,28,141), Vec3crd(24,51,168), Vec3crd(145,144,66), Vec3crd(163,145,65), Vec3crd(164,180,45), Vec3crd(45,44,164), Vec3crd(44,43,164), Vec3crd(43,42,165), Vec3crd(38,37,151), Vec3crd(150,151,37), Vec3crd(37,93,150), Vec3crd(141,31,30), Vec3crd(30,32,141), Vec3crd(169,168,51), Vec3crd(165,164,43), Vec3crd(189,165,42), Vec3crd(42,41,189), Vec3crd(40,39,152), Vec3crd(40,152,153), Vec3crd(151,152,39), Vec3crd(39,38,151), Vec3crd(93,34,149), Vec3crd(154,189,41), Vec3crd(153,154,41), Vec3crd(41,40,153), Vec3crd(148,149,34), Vec3crd(34,36,148), Vec3crd(36,21,121), Vec3crd(31,174,29), Vec3crd(121,148,36), Vec3crd(21,33,122), Vec3crd(21,122,121), Vec3crd(33,29,122), Vec3crd(174,122,29), Vec3crd(116,188,53), Vec3crd(104,98,10), Vec3crd(87,10,98), Vec3crd(98,100,87), Vec3crd(79,87,100), Vec3crd(79,100,107), Vec3crd(90,79,107), Vec3crd(90,107,178), Vec3crd(178,177,90), Vec3crd(53,90,177), Vec3crd(53,177,117), Vec3crd(117,116,53), Vec3crd(54,53,188), Vec3crd(54,188,187), Vec3crd(67,54,187), Vec3crd(67,187,130), Vec3crd(69,67,130), Vec3crd(69,130,157), Vec3crd(12,69,157), Vec3crd(12,157,136), Vec3crd(136,133,12), Vec3crd(12,133,125), Vec3crd(125,127,12), Vec3crd(13,12,127), Vec3crd(127,146,13), Vec3crd(57,13,146), Vec3crd(57,146,160), Vec3crd(95,57,160), Vec3crd(95,160,173), Vec3crd(173,113,95), Vec3crd(94,95,113), Vec3crd(113,112,94), Vec3crd(52,94,112), Vec3crd(48,52,112), Vec3crd(112,167,48), Vec3crd(35,48,167), Vec3crd(35,167,166), Vec3crd(19,35,166), Vec3crd(139,170,50), Vec3crd(50,49,139), Vec3crd(166,155,19), Vec3crd(20,19,155), Vec3crd(155,124,20), Vec3crd(23,20,124), Vec3crd(23,124,123), Vec3crd(49,23,123), Vec3crd(49,123,142), Vec3crd(142,139,49), Vec3crd(190,191,170), Vec3crd(192,191,190), Vec3crd(191,192,51), Vec3crd(191,51,50), Vec3crd(170,169,190), Vec3crd(169,51,192), Vec3crd(169,192,190), Vec3crd(170,191,50), Vec3crd(193,194,195), Vec3crd(196,197,198), Vec3crd(199,200,201), Vec3crd(198,202,203), Vec3crd(204,201,200), Vec3crd(205,204,200), Vec3crd(206,207,208), Vec3crd(206,208,205), Vec3crd(206,205,200), Vec3crd(207,206,209), Vec3crd(207,209,203), Vec3crd(207,203,202), Vec3crd(202,198,197), Vec3crd(197,196,210), Vec3crd(197,210,195), Vec3crd(197,195,194), Vec3crd(8,88,195), Vec3crd(8,195,210), Vec3crd(210,196,8), Vec3crd(196,198,8), Vec3crd(198,203,8), Vec3crd(203,209,8), Vec3crd(209,206,8), Vec3crd(206,200,8), Vec3crd(202,197,104), Vec3crd(207,202,104), Vec3crd(103,104,197), Vec3crd(103,197,194), Vec3crd(193,195,88), Vec3crd(88,103,194), Vec3crd(88,194,193), Vec3crd(200,199,8), Vec3crd(199,201,8), Vec3crd(204,205,6), Vec3crd(6,8,201), Vec3crd(6,201,204), Vec3crd(10,6,205), Vec3crd(10,205,208), Vec3crd(104,10,208), Vec3crd(104,208,207) + }); + break; + case TestMesh::pyramid: + vertices = std::vector({ + Vec3d(10,10,40), Vec3d(0,0,0), Vec3d(20,0,0), Vec3d(20,20,0), Vec3d(0,20,0) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(0,3,4), Vec3crd(3,1,4), Vec3crd(1,3,2), Vec3crd(3,0,2), Vec3crd(4,1,0) + }); + break; + case TestMesh::two_hollow_squares: + vertices = std::vector({ + Vec3d(66.7133483886719,104.286666870117,0), Vec3d(66.7133483886719,95.7133331298828,0), Vec3d(65.6666870117188,94.6666717529297,0), Vec3d(75.2866821289062,95.7133331298828,0), Vec3d(76.3333435058594,105.333335876465,0), Vec3d(76.3333435058594,94.6666717529297,0), Vec3d(65.6666870117188,105.33332824707,0), Vec3d(75.2866821289062,104.286666870117,0), Vec3d(71.1066818237305,104.58666229248,2.79999995231628), Vec3d(66.4133529663086,104.58666229248,2.79999995231628), Vec3d(75.5866851806641,104.58666229248,2.79999995231628), Vec3d(66.4133529663086,99.8933334350586,2.79999995231628), Vec3d(66.4133529663086,95.4133377075195,2.79999995231628), Vec3d(71.1066818237305,95.4133377075195,2.79999995231628), Vec3d(75.5866851806641,95.4133377075195,2.79999995231628), Vec3d(75.5866851806641,100.106666564941,2.79999995231628), Vec3d(74.5400161743164,103.540000915527,2.79999995231628), Vec3d(70.0320129394531,103.540000915527,2.79999995231628), Vec3d(67.4600067138672,103.540000915527,2.79999995231628), Vec3d(67.4600067138672,100.968002319336,2.79999995231628), Vec3d(67.4600067138672,96.4599990844727,2.79999995231628), Vec3d(74.5400161743164,99.0319976806641,2.79999995231628), Vec3d(74.5400161743164,96.4599990844727,2.79999995231628), Vec3d(70.0320129394531,96.4599990844727,2.79999995231628), Vec3d(123.666717529297,94.6666717529297,0), Vec3d(134.333312988281,94.6666717529297,0), Vec3d(124.413360595703,95.4133377075195,2.79999995231628), Vec3d(129.106674194336,95.4133377075195,2.79999995231628), Vec3d(133.586669921875,95.4133377075195,2.79999995231628), Vec3d(123.666717529297,105.33332824707,0), Vec3d(124.413360595703,104.58666229248,2.79999995231628), Vec3d(124.413360595703,99.8933334350586,2.79999995231628), Vec3d(134.333312988281,105.33332824707,0), Vec3d(129.106674194336,104.58666229248,2.79999995231628), Vec3d(133.586669921875,104.58666229248,2.79999995231628), Vec3d(133.586669921875,100.106666564941,2.79999995231628), Vec3d(124.713317871094,104.286666870117,0), Vec3d(124.713317871094,95.7133331298828,0), Vec3d(133.286712646484,95.7133331298828,0), Vec3d(133.286712646484,104.286666870117,0), Vec3d(132.540023803711,103.540000915527,2.79999995231628), Vec3d(128.032028198242,103.540008544922,2.79999995231628), Vec3d(125.460006713867,103.540000915527,2.79999995231628), Vec3d(125.460006713867,100.968002319336,2.79999995231628), Vec3d(125.460006713867,96.4599990844727,2.79999995231628), Vec3d(132.540023803711,99.0319976806641,2.79999995231628), Vec3d(132.540023803711,96.4599990844727,2.79999995231628), Vec3d(128.032028198242,96.4599990844727,2.79999995231628) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(3,4,5), Vec3crd(6,4,0), Vec3crd(6,0,2), Vec3crd(2,1,5), Vec3crd(7,4,3), Vec3crd(1,3,5), Vec3crd(0,4,7), Vec3crd(4,6,8), Vec3crd(6,9,8), Vec3crd(4,8,10), Vec3crd(6,2,9), Vec3crd(2,11,9), Vec3crd(2,12,11), Vec3crd(2,5,12), Vec3crd(5,13,12), Vec3crd(5,14,13), Vec3crd(4,10,15), Vec3crd(5,4,14), Vec3crd(4,15,14), Vec3crd(7,16,17), Vec3crd(0,7,18), Vec3crd(7,17,18), Vec3crd(1,19,20), Vec3crd(1,0,19), Vec3crd(0,18,19), Vec3crd(7,3,21), Vec3crd(3,22,21), Vec3crd(7,21,16), Vec3crd(3,23,22), Vec3crd(3,1,23), Vec3crd(1,20,23), Vec3crd(24,25,26), Vec3crd(25,27,26), Vec3crd(25,28,27), Vec3crd(29,24,30), Vec3crd(24,31,30), Vec3crd(24,26,31), Vec3crd(32,29,33), Vec3crd(29,30,33), Vec3crd(32,33,34), Vec3crd(32,34,35), Vec3crd(25,32,28), Vec3crd(32,35,28), Vec3crd(36,37,24), Vec3crd(38,32,25), Vec3crd(29,32,36), Vec3crd(29,36,24), Vec3crd(24,37,25), Vec3crd(39,32,38), Vec3crd(37,38,25), Vec3crd(36,32,39), Vec3crd(39,40,41), Vec3crd(36,39,42), Vec3crd(39,41,42), Vec3crd(37,43,44), Vec3crd(37,36,43), Vec3crd(36,42,43), Vec3crd(39,38,45), Vec3crd(38,46,45), Vec3crd(39,45,40), Vec3crd(38,47,46), Vec3crd(38,37,47), Vec3crd(37,44,47), Vec3crd(16,8,9), Vec3crd(16,10,8), Vec3crd(10,16,15), Vec3crd(15,16,21), Vec3crd(22,15,21), Vec3crd(15,22,14), Vec3crd(22,23,14), Vec3crd(23,20,14), Vec3crd(17,16,9), Vec3crd(18,17,9), Vec3crd(19,18,9), Vec3crd(19,9,11), Vec3crd(19,11,20), Vec3crd(13,14,20), Vec3crd(20,11,12), Vec3crd(13,20,12), Vec3crd(41,40,30), Vec3crd(42,41,30), Vec3crd(43,42,30), Vec3crd(43,30,31), Vec3crd(43,31,44), Vec3crd(27,28,44), Vec3crd(44,31,26), Vec3crd(27,44,26), Vec3crd(40,33,30), Vec3crd(40,34,33), Vec3crd(34,40,35), Vec3crd(35,40,45), Vec3crd(46,35,45), Vec3crd(35,46,28), Vec3crd(46,47,28), Vec3crd(47,44,28) , + }); + break; + case TestMesh::small_dorito: + vertices = std::vector({ + Vec3d(6.00058937072754,-22.9982089996338,0), Vec3d(22.0010242462158,-49.9998741149902,0), Vec3d(-9.99957847595215,-49.999870300293,0), Vec3d(6.00071382522583,-32.2371635437012,28.0019245147705), Vec3d(11.1670551300049,-37.9727020263672,18.9601669311523), Vec3d(6.00060224533081,-26.5392456054688,10.7321853637695) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(3,4,5), Vec3crd(2,1,4), Vec3crd(2,4,3), Vec3crd(2,3,5), Vec3crd(2,5,0), Vec3crd(5,4,1), Vec3crd(5,1,0) + }); + break; + case TestMesh::bridge: + vertices = std::vector({ + Vec3d(75,84.5,8), Vec3d(125,84.5,8), Vec3d(75,94.5,8), Vec3d(120,84.5,5), Vec3d(125,94.5,8), Vec3d(75,84.5,0), Vec3d(80,84.5,5), Vec3d(125,84.5,0), Vec3d(125,94.5,0), Vec3d(80,94.5,5), Vec3d(75,94.5,0), Vec3d(120,94.5,5), Vec3d(120,84.5,0), Vec3d(80,94.5,0), Vec3d(80,84.5,0), Vec3d(120,94.5,0) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(1,0,3), Vec3crd(2,1,4), Vec3crd(2,5,0), Vec3crd(0,6,3), Vec3crd(1,3,7), Vec3crd(1,8,4), Vec3crd(4,9,2), Vec3crd(10,5,2), Vec3crd(5,6,0), Vec3crd(6,11,3), Vec3crd(3,12,7), Vec3crd(7,8,1), Vec3crd(4,8,11), Vec3crd(4,11,9), Vec3crd(9,10,2), Vec3crd(10,13,5), Vec3crd(14,6,5), Vec3crd(9,11,6), Vec3crd(11,12,3), Vec3crd(12,8,7), Vec3crd(11,8,15), Vec3crd(13,10,9), Vec3crd(5,13,14), Vec3crd(14,13,6), Vec3crd(6,13,9), Vec3crd(15,12,11), Vec3crd(15,8,12) + }); + break; + case TestMesh::bridge_with_hole: + vertices = std::vector({ + Vec3d(75,69.5,8), Vec3d(80,76.9091644287109,8), Vec3d(75,94.5,8), Vec3d(125,69.5,8), Vec3d(120,76.9091644287109,8), Vec3d(120,87.0908355712891,8), Vec3d(80,87.0908355712891,8), Vec3d(125,94.5,8), Vec3d(80,87.0908355712891,5), Vec3d(120,87.0908355712891,5), Vec3d(125,94.5,0), Vec3d(120,69.5,0), Vec3d(120,94.5,0), Vec3d(125,69.5,0), Vec3d(120,94.5,5), Vec3d(80,94.5,5), Vec3d(80,94.5,0), Vec3d(75,94.5,0), Vec3d(80,69.5,5), Vec3d(80,69.5,0), Vec3d(80,76.9091644287109,5), Vec3d(120,69.5,5), Vec3d(75,69.5,0), Vec3d(120,76.9091644287109,5) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(1,0,3), Vec3crd(1,3,4), Vec3crd(4,3,5), Vec3crd(2,6,7), Vec3crd(6,2,1), Vec3crd(7,6,5), Vec3crd(7,5,3), Vec3crd(5,8,9), Vec3crd(8,5,6), Vec3crd(10,11,12), Vec3crd(11,10,13), Vec3crd(14,8,15), Vec3crd(8,14,9), Vec3crd(2,16,17), Vec3crd(16,2,15), Vec3crd(15,2,14), Vec3crd(14,10,12), Vec3crd(10,14,7), Vec3crd(7,14,2), Vec3crd(16,18,19), Vec3crd(18,16,20), Vec3crd(20,16,1), Vec3crd(1,16,8), Vec3crd(8,16,15), Vec3crd(6,1,8), Vec3crd(3,11,13), Vec3crd(11,3,21), Vec3crd(21,3,18), Vec3crd(18,22,19), Vec3crd(22,18,0), Vec3crd(0,18,3), Vec3crd(16,22,17), Vec3crd(22,16,19), Vec3crd(2,22,0), Vec3crd(22,2,17), Vec3crd(5,23,4), Vec3crd(23,11,21), Vec3crd(11,23,12), Vec3crd(12,23,9), Vec3crd(9,23,5), Vec3crd(12,9,14), Vec3crd(23,18,20), Vec3crd(18,23,21), Vec3crd(10,3,13), Vec3crd(3,10,7), Vec3crd(1,23,20), Vec3crd(23,1,4) + }); + break; + case TestMesh::step: + vertices = std::vector({ + Vec3d(0,20,5), Vec3d(0,20,0), Vec3d(0,0,5), Vec3d(0,0,0), Vec3d(20,0,0), Vec3d(20,0,5), Vec3d(1,19,5), Vec3d(1,1,5), Vec3d(19,1,5), Vec3d(20,20,5), Vec3d(19,19,5), Vec3d(20,20,0), Vec3d(19,19,10), Vec3d(1,19,10), Vec3d(1,1,10), Vec3d(19,1,10) + }); + facets = std::vector({ + Vec3crd(0,1,2), Vec3crd(1,3,2), Vec3crd(3,4,5), Vec3crd(2,3,5), Vec3crd(6,0,2), Vec3crd(6,2,7), Vec3crd(5,8,7), Vec3crd(5,7,2), Vec3crd(9,10,8), Vec3crd(9,8,5), Vec3crd(9,0,6), Vec3crd(9,6,10), Vec3crd(9,11,1), Vec3crd(9,1,0), Vec3crd(3,1,11), Vec3crd(4,3,11), Vec3crd(5,11,9), Vec3crd(5,4,11), Vec3crd(12,10,6), Vec3crd(12,6,13), Vec3crd(6,7,14), Vec3crd(13,6,14), Vec3crd(7,8,15), Vec3crd(14,7,15), Vec3crd(15,8,10), Vec3crd(15,10,12), Vec3crd(12,13,14), Vec3crd(12,14,15) + }); + break; + case TestMesh::slopy_cube: + vertices = std::vector({ + Vec3d(-10,-10,0) , Vec3d(-10,-10,20) , Vec3d(-10,10,0) , Vec3d(-10,10,20) , Vec3d(0,-10,10) , Vec3d(10,-10,0) , Vec3d(2.92893,-10,10) , Vec3d(10,-10,2.92893) , + Vec3d(0,-10,20) , Vec3d(10,10,0) , Vec3d(0,10,10) , Vec3d(0,10,20) , Vec3d(2.92893,10,10) , Vec3d(10,10,2.92893) + }); + facets = std::vector({ + Vec3crd(0,1,2) , Vec3crd(2,1,3) , Vec3crd(4,0,5) , Vec3crd(4,1,0) , Vec3crd(6,4,7) , Vec3crd(7,4,5) , Vec3crd(4,8,1) , Vec3crd(0,2,5) , Vec3crd(5,2,9) , Vec3crd(2,10,9) , Vec3crd(10,3,11) , + Vec3crd(2,3,10) , Vec3crd(9,10,12) , Vec3crd(13,9,12) , Vec3crd(3,1,8) , Vec3crd(11,3,8) , Vec3crd(10,11,8) , Vec3crd(4,10,8) , Vec3crd(6,12,10) , Vec3crd(4,6,10) , + Vec3crd(7,13,12) , Vec3crd(6,7,12) , Vec3crd(7,5,9) , Vec3crd(13,7,9) + }); + break; + default: + break; + } + TriangleMesh _mesh; + if (vertices.size() == 0) { + switch(m) { + case TestMesh::cube_20x20x20: + _mesh = Slic3r::make_cube(20,20,20); + break; + case TestMesh::sphere_50mm: + _mesh = Slic3r::make_sphere(50, PI / 243.0); + break; + default: + break; + } + } else { + _mesh = TriangleMesh(vertices, facets); + } + + _mesh.repair(); + return _mesh; +} + +std::shared_ptr init_print(std::initializer_list meshes, Slic3r::Model& model, std::shared_ptr _config, bool comments) +{ + std::shared_ptr config(Slic3r::DynamicPrintConfig::new_from_defaults()); + config->apply(*_config); + + const char* v {std::getenv("SLIC3R_TESTS_GCODE")}; + auto tests_gcode {(v == nullptr ? ""s : std::string(v))}; + + if (tests_gcode != "") + config->set_key_value("gcode_comments", new ConfigOptionBool(true)); + + std::shared_ptr print {std::make_shared()}; + + for (const TestMesh &t : meshes) { + ModelObject *object = model.add_object(); + object->name += std::string(mesh_names.at(t)) + ".stl"; + object->add_volume(mesh(t)); + object->add_instance(); + } + + model.arrange_objects(PrintConfig::min_object_distance(config.get())); + model.center_instances_around_point(Slic3r::Vec2d(100,100)); + for (ModelObject *mo : model.objects) + print->auto_assign_extruders(mo); + + print->apply(model, *config); + print->validate(); + return print; +} + +std::shared_ptr init_print(std::initializer_list meshes, Slic3r::Model& model, std::shared_ptr _config, bool comments) +{ + std::shared_ptr config(Slic3r::DynamicPrintConfig::new_from_defaults()); + config->apply(*_config); + + const char* v {std::getenv("SLIC3R_TESTS_GCODE")}; + auto tests_gcode {(v == nullptr ? ""s : std::string(v))}; + + if (tests_gcode != ""s) + config->set_key_value("gcode_comments", new ConfigOptionBool(true)); + + std::shared_ptr print { std::make_shared() }; + + for (const TriangleMesh &t : meshes) { + ModelObject *object = model.add_object(); + object->name += "object.stl"; + object->add_volume(t); + object->add_instance(); + } + model.arrange_objects(PrintConfig::min_object_distance(config.get())); + model.center_instances_around_point(Slic3r::Vec2d(100, 100)); + for (ModelObject *mo : model.objects) + print->auto_assign_extruders(mo); + + print->apply(model, *config); + print->validate(); + return print; +} + +std::string gcode(std::shared_ptr _print) +{ + boost::filesystem::path temp = boost::filesystem::unique_path(); + _print->set_status_silent(); + _print->process(); + _print->export_gcode(temp.string(), nullptr); + std::ifstream t(temp.string()); + std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); + boost::nowide::remove(temp.string().c_str()); + return str; +} + +Slic3r::Model model(const std::string& model_name, TriangleMesh&& _mesh) +{ + Slic3r::Model result; + ModelObject *object = result.add_object(); + object->name += model_name + ".stl"s; + object->add_volume(_mesh); + object->add_instance(); + return result; +} + +void add_testmesh_to_model(Slic3r::Model& result, const std::string& model_name, TriangleMesh&& _mesh) +{ + ModelObject *object = result.add_object(); + object->name += model_name + ".stl"; + object->add_volume(_mesh); + object->add_instance(); +} + +} } // namespace Slic3r::Test diff --git a/tests/fff_print/test_data.hpp b/tests/fff_print/test_data.hpp new file mode 100644 index 000000000..77c2eea3c --- /dev/null +++ b/tests/fff_print/test_data.hpp @@ -0,0 +1,77 @@ +#ifndef SLIC3R_TEST_DATA_HPP +#define SLIC3R_TEST_DATA_HPP + +#include "libslic3r/Point.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/Geometry.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/Print.hpp" +#include "libslic3r/Config.hpp" + +#include + +namespace Slic3r { namespace Test { + +constexpr double MM_PER_MIN = 60.0; + +/// Enumeration of test meshes +enum class TestMesh { + A, + L, + V, + _40x10, + cube_20x20x20, + sphere_50mm, + bridge, + bridge_with_hole, + cube_with_concave_hole, + cube_with_hole, + gt2_teeth, + ipadstand, + overhang, + pyramid, + sloping_hole, + slopy_cube, + small_dorito, + step, + two_hollow_squares +}; + +// Neccessary for (tm); + } +}; + +/// Mesh enumeration to name mapping +extern const std::unordered_map mesh_names; + +/// Port of Slic3r::Test::mesh +/// Basic cubes/boxes should call TriangleMesh::make_cube() directly and rescale/translate it +TriangleMesh mesh(TestMesh m); + +TriangleMesh mesh(TestMesh m, Vec3d translate, Vec3d scale = Vec3d(1.0, 1.0, 1.0)); +TriangleMesh mesh(TestMesh m, Vec3d translate, double scale = 1.0); + +/// Templated function to see if two values are equivalent (+/- epsilon) +template +bool _equiv(const T& a, const T& b) { return abs(a - b) < Slic3r::Geometry::epsilon; } + +template +bool _equiv(const T& a, const T& b, double epsilon) { return abs(a - b) < epsilon; } + +//Slic3r::Model model(const std::string& model_name, TestMesh m, Vec3d translate = Vec3d(0,0,0), Vec3d scale = Vec3d(1.0,1.0,1.0)); +//Slic3r::Model model(const std::string& model_name, TestMesh m, Vec3d translate = Vec3d(0,0,0), double scale = 1.0); + +Slic3r::Model model(const std::string& model_name, TriangleMesh&& _mesh); + +std::shared_ptr init_print(std::initializer_list meshes, Slic3r::Model& model, std::shared_ptr _config = std::shared_ptr(Slic3r::DynamicPrintConfig::new_from_defaults()), bool comments = false); +std::shared_ptr init_print(std::initializer_list meshes, Slic3r::Model& model, std::shared_ptr _config = std::shared_ptr(Slic3r::DynamicPrintConfig::new_from_defaults()), bool comments = false); + +std::string gcode(std::shared_ptr print); + +} } // namespace Slic3r::Test + + +#endif // SLIC3R_TEST_DATA_HPP diff --git a/tests/fff_print/test_flow.cpp b/tests/fff_print/test_flow.cpp new file mode 100644 index 000000000..eef47b943 --- /dev/null +++ b/tests/fff_print/test_flow.cpp @@ -0,0 +1,203 @@ +#include + +#include +#include + +#include "test_data.hpp" // get access to init_print, etc + +#include "libslic3r/Config.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/GCodeReader.hpp" +#include "libslic3r/Flow.hpp" +#include "libslic3r/libslic3r.h" + +using namespace Slic3r::Test; +using namespace Slic3r; + +SCENARIO("Extrusion width specifics", "[!mayfail]") { + GIVEN("A config with a skirt, brim, some fill density, 3 perimeters, and 1 bottom solid layer and a 20mm cube mesh") { + // this is a sharedptr + std::shared_ptr config(Slic3r::DynamicPrintConfig::new_from_defaults()); + config->opt_int("skirts") = 1; + config->opt_float("brim_width") = 2.; + config->opt_int("perimeters") = 3; + config->set_deserialize("fill_density", "40%"); + config->set_deserialize("first_layer_height", "100%"); + + WHEN("first layer width set to 2mm") { + Slic3r::Model model; + config->set_deserialize("first_layer_extrusion_width", "2"); + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + + std::vector E_per_mm_bottom; + std::string gcode = ::Test::gcode(print); + auto parser {Slic3r::GCodeReader()}; + const auto layer_height { config->opt_float("layer_height") }; + parser.parse_buffer(gcode, [&E_per_mm_bottom, layer_height] (Slic3r::GCodeReader& self, const Slic3r::GCodeReader::GCodeLine& line) + { + if (self.z() == Approx(layer_height).margin(0.01)) { // only consider first layer + if (line.extruding(self) && line.dist_XY(self) > 0) { + E_per_mm_bottom.emplace_back(line.dist_E(self) / line.dist_XY(self)); + } + } + }); + THEN(" First layer width applies to everything on first layer.") { + bool pass = false; + auto avg_E {std::accumulate(E_per_mm_bottom.cbegin(), E_per_mm_bottom.cend(), 0.0) / static_cast(E_per_mm_bottom.size())}; + + pass = (std::count_if(E_per_mm_bottom.cbegin(), E_per_mm_bottom.cend(), [avg_E] (const double& v) { return v == Approx(avg_E); }) == 0); + REQUIRE(pass == true); + REQUIRE(E_per_mm_bottom.size() > 0); // make sure it actually passed because of extrusion + } + THEN(" First layer width does not apply to upper layer.") { + } + } + } +} +// needs gcode export +SCENARIO(" Bridge flow specifics.", "[!mayfail]") { + GIVEN("A default config with no cooling and a fixed bridge speed, flow ratio and an overhang mesh.") { + WHEN("bridge_flow_ratio is set to 1.0") { + THEN("Output flow is as expected.") { + } + } + WHEN("bridge_flow_ratio is set to 0.5") { + THEN("Output flow is as expected.") { + } + } + WHEN("bridge_flow_ratio is set to 2.0") { + THEN("Output flow is as expected.") { + } + } + } + GIVEN("A default config with no cooling and a fixed bridge speed, flow ratio, fixed extrusion width of 0.4mm and an overhang mesh.") { + WHEN("bridge_flow_ratio is set to 1.0") { + THEN("Output flow is as expected.") { + } + } + WHEN("bridge_flow_ratio is set to 0.5") { + THEN("Output flow is as expected.") { + } + } + WHEN("bridge_flow_ratio is set to 2.0") { + THEN("Output flow is as expected.") { + } + } + } +} + +/// Test the expected behavior for auto-width, +/// spacing, etc +SCENARIO("Flow: Flow math for non-bridges", "[!mayfail]") { + GIVEN("Nozzle Diameter of 0.4, a desired width of 1mm and layer height of 0.5") { + auto width {ConfigOptionFloatOrPercent(1.0, false)}; + float spacing {0.4}; + float nozzle_diameter {0.4}; + float bridge_flow {1.0}; + float layer_height {0.5}; + + // Spacing for non-bridges is has some overlap + THEN("External perimeter flow has spacing fixed to 1.1*nozzle_diameter") { + auto flow {Flow::new_from_config_width(frExternalPerimeter, ConfigOptionFloatOrPercent(0, false), nozzle_diameter, layer_height, 0.0f)}; + REQUIRE(flow.spacing() == Approx((1.1*nozzle_diameter) - layer_height * (1.0 - PI / 4.0))); + } + + THEN("Internal perimeter flow has spacing of 1.05 (minimum)") { + auto flow {Flow::new_from_config_width(frPerimeter, ConfigOptionFloatOrPercent(0, false), nozzle_diameter, layer_height, 0.0f)}; + REQUIRE(flow.spacing() == Approx((1.05*nozzle_diameter) - layer_height * (1.0 - PI / 4.0))); + } + THEN("Spacing for supplied width is 0.8927f") { + auto flow {Flow::new_from_config_width(frExternalPerimeter, width, nozzle_diameter, layer_height, 0.0f)}; + REQUIRE(flow.spacing() == Approx(width.value - layer_height * (1.0 - PI / 4.0))); + flow = Flow::new_from_config_width(frPerimeter, width, nozzle_diameter, layer_height, 0.0f); + REQUIRE(flow.spacing() == Approx(width.value - layer_height * (1.0 - PI / 4.0))); + } + } + /// Check the min/max + GIVEN("Nozzle Diameter of 0.25") { + float spacing {0.4}; + float nozzle_diameter {0.25}; + float bridge_flow {0.0}; + float layer_height {0.5}; + WHEN("layer height is set to 0.2") { + layer_height = 0.15f; + THEN("Max width is set.") { + auto flow {Flow::new_from_config_width(frPerimeter, ConfigOptionFloatOrPercent(0, false), nozzle_diameter, layer_height, 0.0f)}; + REQUIRE(flow.width == Approx(1.4*nozzle_diameter)); + } + } + WHEN("Layer height is set to 0.2") { + layer_height = 0.3f; + THEN("Min width is set.") { + auto flow {Flow::new_from_config_width(frPerimeter, ConfigOptionFloatOrPercent(0, false), nozzle_diameter, layer_height, 0.0f)}; + REQUIRE(flow.width == Approx(1.05*nozzle_diameter)); + } + } + } + + +#if 0 + /// Check for an edge case in the maths where the spacing could be 0; original + /// math is 0.99. Slic3r issue #4654 + GIVEN("Input spacing of 0.414159 and a total width of 2") { + double in_spacing = 0.414159; + double total_width = 2.0; + auto flow {Flow::new_from_spacing(1.0, 0.4, 0.3, false)}; + WHEN("solid_spacing() is called") { + double result = flow.solid_spacing(total_width, in_spacing); + THEN("Yielded spacing is greater than 0") { + REQUIRE(result > 0); + } + } + } +#endif + +} + +/// Spacing, width calculation for bridge extrusions +SCENARIO("Flow: Flow math for bridges", "[!mayfail]") { + GIVEN("Nozzle Diameter of 0.4, a desired width of 1mm and layer height of 0.5") { + auto width {ConfigOptionFloatOrPercent(1.0, false)}; + auto spacing {0.4}; + auto nozzle_diameter {0.4}; + auto bridge_flow {1.0}; + auto layer_height {0.5}; + WHEN("Flow role is frExternalPerimeter") { + auto flow {Flow::new_from_config_width(frExternalPerimeter, width, nozzle_diameter, layer_height, bridge_flow)}; + THEN("Bridge width is same as nozzle diameter") { + REQUIRE(flow.width == Approx(nozzle_diameter)); + } + THEN("Bridge spacing is same as nozzle diameter + BRIDGE_EXTRA_SPACING") { + REQUIRE(flow.spacing() == Approx(nozzle_diameter + BRIDGE_EXTRA_SPACING)); + } + } + WHEN("Flow role is frInfill") { + auto flow {Flow::new_from_config_width(frInfill, width, nozzle_diameter, layer_height, bridge_flow)}; + THEN("Bridge width is same as nozzle diameter") { + REQUIRE(flow.width == Approx(nozzle_diameter)); + } + THEN("Bridge spacing is same as nozzle diameter + BRIDGE_EXTRA_SPACING") { + REQUIRE(flow.spacing() == Approx(nozzle_diameter + BRIDGE_EXTRA_SPACING)); + } + } + WHEN("Flow role is frPerimeter") { + auto flow {Flow::new_from_config_width(frPerimeter, width, nozzle_diameter, layer_height, bridge_flow)}; + THEN("Bridge width is same as nozzle diameter") { + REQUIRE(flow.width == Approx(nozzle_diameter)); + } + THEN("Bridge spacing is same as nozzle diameter + BRIDGE_EXTRA_SPACING") { + REQUIRE(flow.spacing() == Approx(nozzle_diameter + BRIDGE_EXTRA_SPACING)); + } + } + WHEN("Flow role is frSupportMaterial") { + auto flow {Flow::new_from_config_width(frSupportMaterial, width, nozzle_diameter, layer_height, bridge_flow)}; + THEN("Bridge width is same as nozzle diameter") { + REQUIRE(flow.width == Approx(nozzle_diameter)); + } + THEN("Bridge spacing is same as nozzle diameter + BRIDGE_EXTRA_SPACING") { + REQUIRE(flow.spacing() == Approx(nozzle_diameter + BRIDGE_EXTRA_SPACING)); + } + } + } +} From c99e7cb0dfac109989f641313255904f493c7153 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 15 Oct 2019 13:49:28 +0200 Subject: [PATCH 08/15] Ported test_trianglemesh from upstream slic3r, thanks @lordofhyphens --- src/libslic3r/Point.hpp | 18 ++ src/libslic3r/TriangleMesh.cpp | 24 +- src/libslic3r/TriangleMesh.hpp | 6 + tests/fff_print/CMakeLists.txt | 1 + tests/fff_print/test_data.cpp | 31 +- tests/fff_print/test_data.hpp | 2 +- tests/fff_print/test_trianglemesh.cpp | 433 ++++++++++++++++++++++++++ 7 files changed, 506 insertions(+), 9 deletions(-) create mode 100644 tests/fff_print/test_trianglemesh.cpp diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 5f5d86aa8..dced5c02a 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -134,12 +134,30 @@ inline bool is_approx(const Point &p1, const Point &p2, coord_t epsilon = coord_ return d.x() < epsilon && d.y() < epsilon; } +inline bool is_approx(const Vec2f &p1, const Vec2f &p2, float epsilon = float(EPSILON)) +{ + Vec2f d = (p2 - p1).cwiseAbs(); + return d.x() < epsilon && d.y() < epsilon; +} + inline bool is_approx(const Vec2d &p1, const Vec2d &p2, double epsilon = EPSILON) { Vec2d d = (p2 - p1).cwiseAbs(); return d.x() < epsilon && d.y() < epsilon; } +inline bool is_approx(const Vec3f &p1, const Vec3f &p2, float epsilon = float(EPSILON)) +{ + Vec3f d = (p2 - p1).cwiseAbs(); + return d.x() < epsilon && d.y() < epsilon && d.z() < epsilon; +} + +inline bool is_approx(const Vec3d &p1, const Vec3d &p2, double epsilon = EPSILON) +{ + Vec3d d = (p2 - p1).cwiseAbs(); + return d.x() < epsilon && d.y() < epsilon && d.z() < epsilon; +} + namespace int128 { // Exact orientation predicate, // returns +1: CCW, 0: collinear, -1: CW. diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 16d289d9c..5cd97522d 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -593,6 +593,16 @@ TriangleMesh TriangleMesh::convex_hull_3d() const return output_mesh; } +std::vector TriangleMesh::slice(const std::vector &z) +{ + // convert doubles to floats + std::vector z_f(z.begin(), z.end()); + TriangleMeshSlicer mslicer(this); + std::vector layers; + mslicer.slice(z_f, 0.0004f, &layers, [](){}); + return layers; +} + void TriangleMesh::require_shared_vertices() { BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - start"; @@ -1861,7 +1871,8 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) } // Generate the vertex list for a cube solid of arbitrary size in X/Y/Z. -TriangleMesh make_cube(double x, double y, double z) { +TriangleMesh make_cube(double x, double y, double z) +{ Vec3d pv[8] = { Vec3d(x, y, 0), Vec3d(x, 0, 0), Vec3d(0, 0, 0), Vec3d(0, y, 0), Vec3d(x, y, z), Vec3d(0, y, z), @@ -1878,7 +1889,8 @@ TriangleMesh make_cube(double x, double y, double z) { Pointf3s vertices(&pv[0], &pv[0]+8); TriangleMesh mesh(vertices ,facets); - return mesh; + mesh.repair(); + return mesh; } // Generate the mesh for a cylinder and return it, using @@ -1922,7 +1934,9 @@ TriangleMesh make_cylinder(double r, double h, double fa) facets.emplace_back(Vec3crd(id, 2, 3)); facets.emplace_back(Vec3crd(id, id - 1, 2)); - return TriangleMesh(std::move(vertices), std::move(facets)); + TriangleMesh mesh(std::move(vertices), std::move(facets)); + mesh.repair(); + return mesh; } // Generates mesh for a sphere centered about the origin, using the generated angle @@ -1978,7 +1992,9 @@ TriangleMesh make_sphere(double radius, double fa) k2 = k2_next; } } - return TriangleMesh(std::move(vertices), std::move(facets)); + TriangleMesh mesh(std::move(vertices), std::move(facets)); + mesh.repair(); + return mesh; } } diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 86ca1625e..9c9f82040 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -58,8 +58,14 @@ public: BoundingBoxf3 bounding_box() const; // Returns the bbox of this TriangleMesh transformed by the given transformation BoundingBoxf3 transformed_bounding_box(const Transform3d &trafo) const; + // Return the size of the mesh in coordinates. + Vec3d size() const { return stl.stats.size.cast(); } + /// Return the center of the related bounding box. + Vec3d center() const { return this->bounding_box().center(); } // Returns the convex hull of this TriangleMesh TriangleMesh convex_hull_3d() const; + // Slice this mesh at the provided Z levels and return the vector + std::vector slice(const std::vector& z); void reset_repair_stats(); bool needed_repair() const; void require_shared_vertices(); diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt index ee7e3fd1e..bd5623a22 100644 --- a/tests/fff_print/CMakeLists.txt +++ b/tests/fff_print/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable(${_TEST_NAME}_tests test_data.cpp test_data.hpp test_flow.cpp + test_trianglemesh.cpp ) target_link_libraries(${_TEST_NAME}_tests test_common libslic3r) set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") diff --git a/tests/fff_print/test_data.cpp b/tests/fff_print/test_data.cpp index 729e72626..a8d3d0d03 100644 --- a/tests/fff_print/test_data.cpp +++ b/tests/fff_print/test_data.cpp @@ -210,7 +210,7 @@ std::shared_ptr init_print(std::initializer_list meshes, Slic3r config->apply(*_config); const char* v {std::getenv("SLIC3R_TESTS_GCODE")}; - auto tests_gcode {(v == nullptr ? ""s : std::string(v))}; + auto tests_gcode {(v == nullptr ? "" : std::string(v))}; if (tests_gcode != "") config->set_key_value("gcode_comments", new ConfigOptionBool(true)); @@ -240,9 +240,9 @@ std::shared_ptr init_print(std::initializer_list meshes, Sl config->apply(*_config); const char* v {std::getenv("SLIC3R_TESTS_GCODE")}; - auto tests_gcode {(v == nullptr ? ""s : std::string(v))}; + auto tests_gcode {(v == nullptr ? "" : std::string(v))}; - if (tests_gcode != ""s) + if (tests_gcode != "") config->set_key_value("gcode_comments", new ConfigOptionBool(true)); std::shared_ptr print { std::make_shared() }; @@ -279,7 +279,7 @@ Slic3r::Model model(const std::string& model_name, TriangleMesh&& _mesh) { Slic3r::Model result; ModelObject *object = result.add_object(); - object->name += model_name + ".stl"s; + object->name += model_name + ".stl"; object->add_volume(_mesh); object->add_instance(); return result; @@ -294,3 +294,26 @@ void add_testmesh_to_model(Slic3r::Model& result, const std::string& model_name, } } } // namespace Slic3r::Test + +#include + +SCENARIO("init_print functionality") { + GIVEN("A default config") { + std::shared_ptr config(Slic3r::DynamicPrintConfig::new_from_defaults()); + std::stringstream gcode; + WHEN("init_print is called with a single mesh.") { + Slic3r::Model model; + auto print = Slic3r::Test::init_print({ Slic3r::Test::TestMesh::cube_20x20x20 }, model, config, true); + gcode.clear(); + THEN("One mesh/printobject is in the resulting Print object.") { + REQUIRE(print->objects().size() == 1); + } + THEN("print->process() doesn't crash.") { + REQUIRE_NOTHROW(print->process()); + } + THEN("Export gcode functions outputs text.") { + REQUIRE(!Slic3r::Test::gcode(print).empty()); + } + } + } +} diff --git a/tests/fff_print/test_data.hpp b/tests/fff_print/test_data.hpp index 77c2eea3c..e67e400f2 100644 --- a/tests/fff_print/test_data.hpp +++ b/tests/fff_print/test_data.hpp @@ -56,7 +56,7 @@ TriangleMesh mesh(TestMesh m, Vec3d translate, double scale = 1.0); /// Templated function to see if two values are equivalent (+/- epsilon) template -bool _equiv(const T& a, const T& b) { return abs(a - b) < Slic3r::Geometry::epsilon; } +bool _equiv(const T& a, const T& b) { return std::abs(a - b) < EPSILON; } template bool _equiv(const T& a, const T& b, double epsilon) { return abs(a - b) < epsilon; } diff --git a/tests/fff_print/test_trianglemesh.cpp b/tests/fff_print/test_trianglemesh.cpp new file mode 100644 index 000000000..8e099db75 --- /dev/null +++ b/tests/fff_print/test_trianglemesh.cpp @@ -0,0 +1,433 @@ +#include + +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/libslic3r.h" + +#include +#include +#include + +//#include "test_options.hpp" +#include "test_data.hpp" + +using namespace Slic3r; +using namespace std; + +SCENARIO( "TriangleMesh: Basic mesh statistics") { + GIVEN( "A 20mm cube, built from constexpr std::array" ) { + std::vector vertices { Vec3d(20,20,0), Vec3d(20,0,0), Vec3d(0,0,0), Vec3d(0,20,0), Vec3d(20,20,20), Vec3d(0,20,20), Vec3d(0,0,20), Vec3d(20,0,20) }; + std::vector facets { Vec3crd(0,1,2), Vec3crd(0,2,3), Vec3crd(4,5,6), Vec3crd(4,6,7), Vec3crd(0,4,7), Vec3crd(0,7,1), Vec3crd(1,7,6), Vec3crd(1,6,2), Vec3crd(2,6,5), Vec3crd(2,5,3), Vec3crd(4,0,3), Vec3crd(4,3,5) }; + TriangleMesh cube(vertices, facets); + cube.repair(); + + THEN( "Volume is appropriate for 20mm square cube.") { + REQUIRE(abs(cube.volume() - 20.0*20.0*20.0) < 1e-2); + } + + THEN( "Vertices array matches input.") { + for (auto i = 0U; i < cube.its.vertices.size(); i++) { + REQUIRE(cube.its.vertices.at(i) == vertices.at(i).cast()); + } + for (auto i = 0U; i < vertices.size(); i++) { + REQUIRE(vertices.at(i).cast() == cube.its.vertices.at(i)); + } + } + THEN( "Vertex count matches vertex array size.") { + REQUIRE(cube.facets_count() == facets.size()); + } + + THEN( "Facet array matches input.") { + for (auto i = 0U; i < cube.its.indices.size(); i++) { + REQUIRE(cube.its.indices.at(i) == facets.at(i)); + } + + for (auto i = 0U; i < facets.size(); i++) { + REQUIRE(facets.at(i) == cube.its.indices.at(i)); + } + } + THEN( "Facet count matches facet array size.") { + REQUIRE(cube.facets_count() == facets.size()); + } + +#if 0 + THEN( "Number of normals is equal to the number of facets.") { + REQUIRE(cube.normals().size() == facets.size()); + } +#endif + + THEN( "center() returns the center of the object.") { + REQUIRE(cube.center() == Vec3d(10.0,10.0,10.0)); + } + + THEN( "Size of cube is (20,20,20)") { + REQUIRE(cube.size() == Vec3d(20,20,20)); + } + + } + GIVEN( "A 20mm cube with one corner on the origin") { + const std::vector vertices { Vec3d(20,20,0), Vec3d(20,0,0), Vec3d(0,0,0), Vec3d(0,20,0), Vec3d(20,20,20), Vec3d(0,20,20), Vec3d(0,0,20), Vec3d(20,0,20) }; + const std::vector facets { Vec3crd(0,1,2), Vec3crd(0,2,3), Vec3crd(4,5,6), Vec3crd(4,6,7), Vec3crd(0,4,7), Vec3crd(0,7,1), Vec3crd(1,7,6), Vec3crd(1,6,2), Vec3crd(2,6,5), Vec3crd(2,5,3), Vec3crd(4,0,3), Vec3crd(4,3,5) }; + + TriangleMesh cube(vertices, facets); + cube.repair(); + + THEN( "Volume is appropriate for 20mm square cube.") { + REQUIRE(abs(cube.volume() - 20.0*20.0*20.0) < 1e-2); + } + + THEN( "Vertices array matches input.") { + for (auto i = 0U; i < cube.its.vertices.size(); i++) { + REQUIRE(cube.its.vertices.at(i) == vertices.at(i).cast()); + } + for (auto i = 0U; i < vertices.size(); i++) { + REQUIRE(vertices.at(i).cast() == cube.its.vertices.at(i)); + } + } + THEN( "Vertex count matches vertex array size.") { + REQUIRE(cube.facets_count() == facets.size()); + } + + THEN( "Facet array matches input.") { + for (auto i = 0U; i < cube.its.indices.size(); i++) { + REQUIRE(cube.its.indices.at(i) == facets.at(i)); + } + + for (auto i = 0U; i < facets.size(); i++) { + REQUIRE(facets.at(i) == cube.its.indices.at(i)); + } + } + THEN( "Facet count matches facet array size.") { + REQUIRE(cube.facets_count() == facets.size()); + } + +#if 0 + THEN( "Number of normals is equal to the number of facets.") { + REQUIRE(cube.normals().size() == facets.size()); + } +#endif + + THEN( "center() returns the center of the object.") { + REQUIRE(cube.center() == Vec3d(10.0,10.0,10.0)); + } + + THEN( "Size of cube is (20,20,20)") { + REQUIRE(cube.size() == Vec3d(20,20,20)); + } + } +} + +SCENARIO( "TriangleMesh: Transformation functions affect mesh as expected.") { + GIVEN( "A 20mm cube with one corner on the origin") { + const std::vector vertices { Vec3d(20,20,0), Vec3d(20,0,0), Vec3d(0,0,0), Vec3d(0,20,0), Vec3d(20,20,20), Vec3d(0,20,20), Vec3d(0,0,20), Vec3d(20,0,20) }; + const std::vector facets { Vec3crd(0,1,2), Vec3crd(0,2,3), Vec3crd(4,5,6), Vec3crd(4,6,7), Vec3crd(0,4,7), Vec3crd(0,7,1), Vec3crd(1,7,6), Vec3crd(1,6,2), Vec3crd(2,6,5), Vec3crd(2,5,3), Vec3crd(4,0,3), Vec3crd(4,3,5) }; + TriangleMesh cube(vertices, facets); + cube.repair(); + + WHEN( "The cube is scaled 200% uniformly") { + cube.scale(2.0); + THEN( "The volume is equivalent to 40x40x40 (all dimensions increased by 200%") { + REQUIRE(abs(cube.volume() - 40.0*40.0*40.0) < 1e-2); + } + } + WHEN( "The resulting cube is scaled 200% in the X direction") { + cube.scale(Vec3d(2.0, 1, 1)); + THEN( "The volume is doubled.") { + REQUIRE(abs(cube.volume() - 2*20.0*20.0*20.0) < 1e-2); + } + THEN( "The X coordinate size is 200%.") { + REQUIRE(cube.its.vertices.at(0).x() == 40.0); + } + } + + WHEN( "The cube is scaled 25% in the X direction") { + cube.scale(Vec3d(0.25, 1, 1)); + THEN( "The volume is 25% of the previous volume.") { + REQUIRE(abs(cube.volume() - 0.25*20.0*20.0*20.0) < 1e-2); + } + THEN( "The X coordinate size is 25% from previous.") { + REQUIRE(cube.its.vertices.at(0).x() == 5.0); + } + } + + WHEN( "The cube is rotated 45 degrees.") { + cube.rotate_z(float(M_PI / 4.)); + THEN( "The X component of the size is sqrt(2)*20") { + REQUIRE(abs(cube.size().x() - sqrt(2.0)*20) < 1e-2); + } + } + + WHEN( "The cube is translated (5, 10, 0) units with a Vec3f ") { + cube.translate(Vec3f(5.0, 10.0, 0.0)); + THEN( "The first vertex is located at 25, 30, 0") { + REQUIRE(cube.its.vertices.at(0) == Vec3f(25.0, 30.0, 0.0)); + } + } + + WHEN( "The cube is translated (5, 10, 0) units with 3 doubles") { + cube.translate(5.0, 10.0, 0.0); + THEN( "The first vertex is located at 25, 30, 0") { + REQUIRE(cube.its.vertices.at(0) == Vec3f(25.0, 30.0, 0.0)); + } + } + WHEN( "The cube is translated (5, 10, 0) units and then aligned to origin") { + cube.translate(5.0, 10.0, 0.0); + cube.align_to_origin(); + THEN( "The third vertex is located at 0,0,0") { + REQUIRE(cube.its.vertices.at(2) == Vec3f(0.0, 0.0, 0.0)); + } + } + } +} + +SCENARIO( "TriangleMesh: slice behavior.") { + GIVEN( "A 20mm cube with one corner on the origin") { + const std::vector vertices { Vec3d(20,20,0), Vec3d(20,0,0), Vec3d(0,0,0), Vec3d(0,20,0), Vec3d(20,20,20), Vec3d(0,20,20), Vec3d(0,0,20), Vec3d(20,0,20) }; + const std::vector facets { Vec3crd(0,1,2), Vec3crd(0,2,3), Vec3crd(4,5,6), Vec3crd(4,6,7), Vec3crd(0,4,7), Vec3crd(0,7,1), Vec3crd(1,7,6), Vec3crd(1,6,2), Vec3crd(2,6,5), Vec3crd(2,5,3), Vec3crd(4,0,3), Vec3crd(4,3,5) }; + TriangleMesh cube(vertices, facets); + cube.repair(); + + WHEN("Cube is sliced with z = [0+EPSILON,2,4,8,6,8,10,12,14,16,18,20]") { + std::vector z { 0+EPSILON,2,4,8,6,8,10,12,14,16,18,20 }; + auto result {cube.slice(z)}; + THEN( "The correct number of polygons are returned per layer.") { + for (auto i = 0U; i < z.size(); i++) { + REQUIRE(result.at(i).size() == 1); + } + } + THEN( "The area of the returned polygons is correct.") { + for (auto i = 0U; i < z.size(); i++) { + REQUIRE(result.at(i).at(0).area() == 20.0*20/(std::pow(SCALING_FACTOR,2))); + } + } + } + } + GIVEN( "A STL with an irregular shape.") { + const std::vector vertices {Vec3d(0,0,0),Vec3d(0,0,20),Vec3d(0,5,0),Vec3d(0,5,20),Vec3d(50,0,0),Vec3d(50,0,20),Vec3d(15,5,0),Vec3d(35,5,0),Vec3d(15,20,0),Vec3d(50,5,0),Vec3d(35,20,0),Vec3d(15,5,10),Vec3d(50,5,20),Vec3d(35,5,10),Vec3d(35,20,10),Vec3d(15,20,10)}; + const std::vector facets {Vec3crd(0,1,2),Vec3crd(2,1,3),Vec3crd(1,0,4),Vec3crd(5,1,4),Vec3crd(0,2,4),Vec3crd(4,2,6),Vec3crd(7,6,8),Vec3crd(4,6,7),Vec3crd(9,4,7),Vec3crd(7,8,10),Vec3crd(2,3,6),Vec3crd(11,3,12),Vec3crd(7,12,9),Vec3crd(13,12,7),Vec3crd(6,3,11),Vec3crd(11,12,13),Vec3crd(3,1,5),Vec3crd(12,3,5),Vec3crd(5,4,9),Vec3crd(12,5,9),Vec3crd(13,7,10),Vec3crd(14,13,10),Vec3crd(8,15,10),Vec3crd(10,15,14),Vec3crd(6,11,8),Vec3crd(8,11,15),Vec3crd(15,11,13),Vec3crd(14,15,13)}; + + TriangleMesh cube(vertices, facets); + cube.repair(); + WHEN(" a top tangent plane is sliced") { + auto slices {cube.slice({5.0, 10.0})}; + THEN( "its area is included") { + REQUIRE(slices.at(0).at(0).area() > 0); + REQUIRE(slices.at(1).at(0).area() > 0); + } + } + WHEN(" a model that has been transformed is sliced") { + cube.mirror_z(); + auto slices {cube.slice({-5.0, -10.0})}; + THEN( "it is sliced properly (mirrored bottom plane area is included)") { + REQUIRE(slices.at(0).at(0).area() > 0); + REQUIRE(slices.at(1).at(0).area() > 0); + } + } + } +} + +SCENARIO( "make_xxx functions produce meshes.") { + GIVEN("make_cube() function") { + WHEN("make_cube() is called with arguments 20,20,20") { + TriangleMesh cube = make_cube(20,20,20); + THEN("The resulting mesh has one and only one vertex at 0,0,0") { + auto verts {cube.its.vertices}; + REQUIRE(std::count_if(verts.begin(), verts.end(), [](const Vec3f& t) { return t.x() == 0 && t.y() == 0 && t.z() == 0; } ) == 1); + } + THEN("The mesh volume is 20*20*20") { + REQUIRE(abs(cube.volume() - 20.0*20.0*20.0) < 1e-2); + } + THEN("The resulting mesh is in the repaired state.") { + REQUIRE(cube.repaired == true); + } + THEN("There are 12 facets.") { + REQUIRE(cube.its.indices.size() == 12); + } + } + } + GIVEN("make_cylinder() function") { + WHEN("make_cylinder() is called with arguments 10,10, PI / 3") { + TriangleMesh cyl = make_cylinder(10, 10, PI / 243.0); + double angle = (2*PI / floor(2*PI / (PI / 243.0))); + THEN("The resulting mesh has one and only one vertex at 0,0,0") { + auto verts {cyl.its.vertices}; + REQUIRE(std::count_if(verts.begin(), verts.end(), [](const Vec3f& t) { return t.x() == 0 && t.y() == 0 && t.z() == 0; } ) == 1); + } + THEN("The resulting mesh has one and only one vertex at 0,0,10") { + auto verts {cyl.its.vertices}; + REQUIRE(std::count_if(verts.begin(), verts.end(), [](const Vec3f& t) { return t.x() == 0 && t.y() == 0 && t.z() == 10; } ) == 1); + } + THEN("Resulting mesh has 2 + (2*PI/angle * 2) vertices.") { + REQUIRE(cyl.its.vertices.size() == (2 + ((2*PI/angle)*2))); + } + THEN("Resulting mesh has 2*PI/angle * 4 facets") { + REQUIRE(cyl.its.indices.size() == (2*PI/angle)*4); + } + THEN("The resulting mesh is in the repaired state.") { + REQUIRE(cyl.repaired == true); + } + THEN( "The mesh volume is approximately 10pi * 10^2") { + REQUIRE(abs(cyl.volume() - (10.0 * M_PI * std::pow(10,2))) < 1); + } + } + } + + GIVEN("make_sphere() function") { + WHEN("make_sphere() is called with arguments 10, PI / 3") { + TriangleMesh sph = make_sphere(10, PI / 243.0); + double angle = (2.0*PI / floor(2.0*PI / (PI / 243.0))); + THEN("Resulting mesh has one point at 0,0,-10 and one at 0,0,10") { + const std::vector &verts = sph.its.vertices; + REQUIRE(std::count_if(verts.begin(), verts.end(), [](const Vec3f& t) { return is_approx(t, Vec3f(0.f, 0.f, 10.f)); } ) == 1); + REQUIRE(std::count_if(verts.begin(), verts.end(), [](const Vec3f& t) { return is_approx(t, Vec3f(0.f, 0.f, -10.f)); } ) == 1); + } + THEN("The resulting mesh is in the repaired state.") { + REQUIRE(sph.repaired == true); + } + THEN( "The mesh volume is approximately 4/3 * pi * 10^3") { + REQUIRE(abs(sph.volume() - (4.0/3.0 * M_PI * std::pow(10,3))) < 1); // 1% tolerance? + } + } + } +} + +SCENARIO( "TriangleMesh: split functionality.") { + GIVEN( "A 20mm cube with one corner on the origin") { + const std::vector vertices { Vec3d(20,20,0), Vec3d(20,0,0), Vec3d(0,0,0), Vec3d(0,20,0), Vec3d(20,20,20), Vec3d(0,20,20), Vec3d(0,0,20), Vec3d(20,0,20) }; + const std::vector facets { Vec3crd(0,1,2), Vec3crd(0,2,3), Vec3crd(4,5,6), Vec3crd(4,6,7), Vec3crd(0,4,7), Vec3crd(0,7,1), Vec3crd(1,7,6), Vec3crd(1,6,2), Vec3crd(2,6,5), Vec3crd(2,5,3), Vec3crd(4,0,3), Vec3crd(4,3,5) }; + + TriangleMesh cube(vertices, facets); + cube.repair(); + WHEN( "The mesh is split into its component parts.") { + auto meshes {cube.split()}; + THEN(" The bounding box statistics are propagated to the split copies") { + REQUIRE(meshes.size() == 1); + REQUIRE((meshes.at(0)->bounding_box() == cube.bounding_box())); + } + } + } + GIVEN( "Two 20mm cubes, each with one corner on the origin, merged into a single TriangleMesh") { + const std::vector vertices { Vec3d(20,20,0), Vec3d(20,0,0), Vec3d(0,0,0), Vec3d(0,20,0), Vec3d(20,20,20), Vec3d(0,20,20), Vec3d(0,0,20), Vec3d(20,0,20) }; + const std::vector facets { Vec3crd(0,1,2), Vec3crd(0,2,3), Vec3crd(4,5,6), Vec3crd(4,6,7), Vec3crd(0,4,7), Vec3crd(0,7,1), Vec3crd(1,7,6), Vec3crd(1,6,2), Vec3crd(2,6,5), Vec3crd(2,5,3), Vec3crd(4,0,3), Vec3crd(4,3,5) }; + + TriangleMesh cube(vertices, facets); + cube.repair(); + TriangleMesh cube2(vertices, facets); + cube2.repair(); + + cube.merge(cube2); + cube.repair(); + WHEN( "The combined mesh is split") { + auto meshes {cube.split()}; + THEN( "Two meshes are in the output vector.") { + REQUIRE(meshes.size() == 2); + } + } + } +} + +SCENARIO( "TriangleMesh: Mesh merge functions") { + GIVEN( "Two 20mm cubes, each with one corner on the origin") { + const std::vector vertices { Vec3d(20,20,0), Vec3d(20,0,0), Vec3d(0,0,0), Vec3d(0,20,0), Vec3d(20,20,20), Vec3d(0,20,20), Vec3d(0,0,20), Vec3d(20,0,20) }; + const std::vector facets { Vec3crd(0,1,2), Vec3crd(0,2,3), Vec3crd(4,5,6), Vec3crd(4,6,7), Vec3crd(0,4,7), Vec3crd(0,7,1), Vec3crd(1,7,6), Vec3crd(1,6,2), Vec3crd(2,6,5), Vec3crd(2,5,3), Vec3crd(4,0,3), Vec3crd(4,3,5) }; + + TriangleMesh cube(vertices, facets); + cube.repair(); + TriangleMesh cube2(vertices, facets); + cube2.repair(); + + WHEN( "The two meshes are merged") { + cube.merge(cube2); + cube.repair(); + THEN( "There are twice as many facets in the merged mesh as the original.") { + REQUIRE(cube.stl.stats.number_of_facets == 2 * cube2.stl.stats.number_of_facets); + } + } + } +} + +SCENARIO( "TriangleMeshSlicer: Cut behavior.") { + GIVEN( "A 20mm cube with one corner on the origin") { + const std::vector vertices { Vec3d(20,20,0), Vec3d(20,0,0), Vec3d(0,0,0), Vec3d(0,20,0), Vec3d(20,20,20), Vec3d(0,20,20), Vec3d(0,0,20), Vec3d(20,0,20) }; + const std::vector facets { Vec3crd(0,1,2), Vec3crd(0,2,3), Vec3crd(4,5,6), Vec3crd(4,6,7), Vec3crd(0,4,7), Vec3crd(0,7,1), Vec3crd(1,7,6), Vec3crd(1,6,2), Vec3crd(2,6,5), Vec3crd(2,5,3), Vec3crd(4,0,3), Vec3crd(4,3,5) }; + + TriangleMesh cube(vertices, facets); + cube.repair(); + WHEN( "Object is cut at the bottom") { + TriangleMesh upper {}; + TriangleMesh lower {}; + TriangleMeshSlicer slicer(&cube); + slicer.cut(0, &upper, &lower); + THEN("Upper mesh has all facets except those belonging to the slicing plane.") { + REQUIRE(upper.facets_count() == 12); + } + THEN("Lower mesh has no facets.") { + REQUIRE(lower.facets_count() == 0); + } + } + WHEN( "Object is cut at the center") { + TriangleMesh upper {}; + TriangleMesh lower {}; + TriangleMeshSlicer slicer(&cube); + slicer.cut(10, &upper, &lower); + THEN("Upper mesh has 2 external horizontal facets, 3 facets on each side, and 6 facets on the triangulated side (2 + 12 + 6).") { + REQUIRE(upper.facets_count() == 2+12+6); + } + THEN("Lower mesh has 2 external horizontal facets, 3 facets on each side, and 6 facets on the triangulated side (2 + 12 + 6).") { + REQUIRE(lower.facets_count() == 2+12+6); + } + } + } +} +#ifdef TEST_PERFORMANCE +TEST_CASE("Regression test for issue #4486 - files take forever to slice") { + TriangleMesh mesh; + auto config {Slic3r::Config::new_from_defaults()}; + mesh.ReadSTLFile(std::string(testfile_dir) + "test_trianglemesh/4486/100_000.stl"); + mesh.repair(); + + config->set("layer_height", 500); + config->set("first_layer_height", 250); + config->set("nozzle_diameter", 500); + + Slic3r::Model model; + auto print {Slic3r::Test::init_print({mesh}, model, config)}; + + print->status_cb = [] (int ln, const std::string& msg) { Slic3r::Log::info("Print") << ln << " " << msg << "\n";}; + + std::future fut = std::async([&print] () { print->process(); }); + std::chrono::milliseconds span {120000}; + bool timedout {false}; + if(fut.wait_for(span) == std::future_status::timeout) { + timedout = true; + } + REQUIRE(timedout == false); + +} +#endif // TEST_PERFORMANCE + +#ifdef BUILD_PROFILE +TEST_CASE("Profile test for issue #4486 - files take forever to slice") { + TriangleMesh mesh; + auto config {Slic3r::Config::new_from_defaults()}; + mesh.ReadSTLFile(std::string(testfile_dir) + "test_trianglemesh/4486/10_000.stl"); + mesh.repair(); + + config->set("layer_height", 500); + config->set("first_layer_height", 250); + config->set("nozzle_diameter", 500); + config->set("fill_density", "5%"); + + Slic3r::Model model; + auto print {Slic3r::Test::init_print({mesh}, model, config)}; + + print->status_cb = [] (int ln, const std::string& msg) { Slic3r::Log::info("Print") << ln << " " << msg << "\n";}; + + print->process(); + + REQUIRE(true); + +} +#endif //BUILD_PROFILE From 50448bf4dd178ce60b0e18aa2388ce29614715dc Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 15 Oct 2019 15:10:52 +0200 Subject: [PATCH 09/15] CMakeLists.txt: turning off Wno-ignored-attributes on GCC and Clang again Eigen still produces tons of those warnings on newer gcc --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b1d73f89..3efc18b8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,9 +174,10 @@ if (NOT MSVC AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMP add_compile_options(-Werror=return-type) #removes LOTS of extraneous Eigen warnings (GCC only supports it since 6.1) - #if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6.1) - # add_compile_options(-Wno-ignored-attributes) # Tamas: Eigen include dirs are marked as SYSTEM - #endif() + #https://eigen.tuxfamily.org/bz/show_bug.cgi?id=1221 + if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6.1) + add_compile_options(-Wno-ignored-attributes) + endif() #GCC generates loads of -Wunknown-pragmas when compiling igl. The fix is not easy due to a bug in gcc, see # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66943 or From 1964ac2e899e51c595cebe57db1b1b82f0d8bc17 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 15 Oct 2019 16:31:20 +0200 Subject: [PATCH 10/15] Ported test_skirt_brim from upstream Slic3r, thanks @lordofhyphens --- src/libslic3r/GCodeReader.hpp | 2 + src/libslic3r/PrintConfig.cpp | 27 ++- src/libslic3r/PrintConfig.hpp | 7 +- src/slic3r/GUI/Preset.cpp | 26 +-- src/slic3r/GUI/Preset.hpp | 4 +- tests/fff_print/CMakeLists.txt | 1 + tests/fff_print/test_data.cpp | 10 +- tests/fff_print/test_skirt_brim.cpp | 263 ++++++++++++++++++++++++++++ 8 files changed, 308 insertions(+), 32 deletions(-) create mode 100644 tests/fff_print/test_skirt_brim.cpp diff --git a/src/libslic3r/GCodeReader.hpp b/src/libslic3r/GCodeReader.hpp index f64605a9c..24f979267 100644 --- a/src/libslic3r/GCodeReader.hpp +++ b/src/libslic3r/GCodeReader.hpp @@ -29,6 +29,8 @@ public: float value(Axis axis) const { return m_axis[axis]; } bool has(char axis) const; bool has_value(char axis, float &value) const; + float new_X(const GCodeReader &reader) const { return this->has(X) ? this->x() : reader.x(); } + float new_Y(const GCodeReader &reader) const { return this->has(Y) ? this->y() : reader.y(); } float new_Z(const GCodeReader &reader) const { return this->has(Z) ? this->z() : reader.z(); } float new_E(const GCodeReader &reader) const { return this->has(E) ? this->e() : reader.e(); } float new_F(const GCodeReader &reader) const { return this->has(F) ? this->f() : reader.f(); } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index b3957218d..c5fd80b55 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -29,7 +29,7 @@ PrintConfigDef::PrintConfigDef() this->init_common_params(); assign_printer_technology_to_unknown(this->options, ptAny); this->init_fff_params(); - this->init_extruder_retract_keys(); + this->init_extruder_option_keys(); assign_printer_technology_to_unknown(this->options, ptFFF); this->init_sla_params(); assign_printer_technology_to_unknown(this->options, ptSLA); @@ -2270,8 +2270,17 @@ void PrintConfigDef::init_fff_params() } } -void PrintConfigDef::init_extruder_retract_keys() +void PrintConfigDef::init_extruder_option_keys() { + // ConfigOptionFloats, ConfigOptionPercents, ConfigOptionBools, ConfigOptionStrings + m_extruder_option_keys = { + "nozzle_diameter", "min_layer_height", "max_layer_height", "extruder_offset", + "retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", + "retract_before_wipe", "retract_restart_extra", "retract_before_travel", "wipe", + "retract_layer_change", "retract_length_toolchange", "retract_restart_extra_toolchange", "extruder_colour", + "default_filament_profile" + }; + m_extruder_retract_keys = { "deretract_speed", "retract_before_travel", @@ -2938,6 +2947,20 @@ void DynamicPrintConfig::normalize() } } +void DynamicPrintConfig::set_num_extruders(unsigned int num_extruders) +{ + const auto &defaults = FullPrintConfig::defaults(); + for (const std::string &key : print_config_def.extruder_option_keys()) { + if (key == "default_filament_profile") + continue; + auto *opt = this->option(key, false); + assert(opt != nullptr); + assert(opt->is_vector()); + if (opt != nullptr && opt->is_vector()) + static_cast(opt)->resize(num_extruders, defaults.option(key)); + } +} + std::string DynamicPrintConfig::validate() { // Full print config is initialized from the defaults. diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 372e70e34..ce051b05b 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -193,6 +193,8 @@ public: static void handle_legacy(t_config_option_key &opt_key, std::string &value); + // Array options growing with the number of extruders + const std::vector& extruder_option_keys() const { return m_extruder_option_keys; } // Options defining the extruder retract properties. These keys are sorted lexicographically. // The extruder retract keys could be overidden by the same values defined at the Filament level // (then the key is further prefixed with the "filament_" prefix). @@ -201,9 +203,10 @@ public: private: void init_common_params(); void init_fff_params(); - void init_extruder_retract_keys(); + void init_extruder_option_keys(); void init_sla_params(); + std::vector m_extruder_option_keys; std::vector m_extruder_retract_keys; }; @@ -231,6 +234,8 @@ public: void normalize(); + void set_num_extruders(unsigned int num_extruders); + // Validate the PrintConfig. Returns an empty string on success, otherwise an error message is returned. std::string validate(); diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index ae995aa44..a360aaf1a 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -245,27 +245,13 @@ std::string Preset::remove_suffix_modified(const std::string &name) name; } -void Preset::set_num_extruders(DynamicPrintConfig &config, unsigned int num_extruders) -{ - const auto &defaults = FullPrintConfig::defaults(); - for (const std::string &key : Preset::nozzle_options()) { - if (key == "default_filament_profile") - continue; - auto *opt = config.option(key, false); - assert(opt != nullptr); - assert(opt->is_vector()); - if (opt != nullptr && opt->is_vector()) - static_cast(opt)->resize(num_extruders, defaults.option(key)); - } -} - // Update new extruder fields at the printer profile. void Preset::normalize(DynamicPrintConfig &config) { auto *nozzle_diameter = dynamic_cast(config.option("nozzle_diameter")); if (nozzle_diameter != nullptr) // Loaded the FFF Printer settings. Verify, that all extruder dependent values have enough values. - set_num_extruders(config, (unsigned int)nozzle_diameter->values.size()); + config.set_num_extruders((unsigned int)nozzle_diameter->values.size()); if (config.option("filament_diameter") != nullptr) { // This config contains single or multiple filament presets. // Ensure that the filament preset vector options contain the correct number of values. @@ -469,15 +455,7 @@ const std::vector& Preset::printer_options() // of the nozzle_diameter vector. const std::vector& Preset::nozzle_options() { - // ConfigOptionFloats, ConfigOptionPercents, ConfigOptionBools, ConfigOptionStrings - static std::vector s_opts { - "nozzle_diameter", "min_layer_height", "max_layer_height", "extruder_offset", - "retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", - "retract_before_wipe", "retract_restart_extra", "retract_before_travel", "wipe", - "retract_layer_change", "retract_length_toolchange", "retract_restart_extra_toolchange", "extruder_colour", - "default_filament_profile" - }; - return s_opts; + return print_config_def.extruder_option_keys(); } const std::vector& Preset::sla_print_options() diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index 6ed818719..e2e4baa88 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -202,7 +202,7 @@ public: void set_visible_from_appconfig(const AppConfig &app_config); // Resize the extruder specific fields, initialize them with the content of the 1st extruder. - void set_num_extruders(unsigned int n) { set_num_extruders(this->config, n); } + void set_num_extruders(unsigned int n) { this->config.set_num_extruders(n); } // Sort lexicographically by a preset name. The preset name shall be unique across a single PresetCollection. bool operator<(const Preset &other) const { return this->name < other.name; } @@ -227,8 +227,6 @@ public: protected: friend class PresetCollection; friend class PresetBundle; - // Resize the extruder specific vectors () - static void set_num_extruders(DynamicPrintConfig &config, unsigned int n); static std::string remove_suffix_modified(const std::string &name); }; diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt index bd5623a22..3c47d637e 100644 --- a/tests/fff_print/CMakeLists.txt +++ b/tests/fff_print/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable(${_TEST_NAME}_tests test_data.cpp test_data.hpp test_flow.cpp + test_skirt_brim.cpp test_trianglemesh.cpp ) target_link_libraries(${_TEST_NAME}_tests test_common libslic3r) diff --git a/tests/fff_print/test_data.cpp b/tests/fff_print/test_data.cpp index a8d3d0d03..a07360af7 100644 --- a/tests/fff_print/test_data.cpp +++ b/tests/fff_print/test_data.cpp @@ -226,11 +226,14 @@ std::shared_ptr init_print(std::initializer_list meshes, Slic3r model.arrange_objects(PrintConfig::min_object_distance(config.get())); model.center_instances_around_point(Slic3r::Vec2d(100,100)); - for (ModelObject *mo : model.objects) + for (ModelObject *mo : model.objects) { + mo->ensure_on_bed(); print->auto_assign_extruders(mo); + } print->apply(model, *config); print->validate(); + print->set_status_silent(); return print; } @@ -255,11 +258,14 @@ std::shared_ptr init_print(std::initializer_list meshes, Sl } model.arrange_objects(PrintConfig::min_object_distance(config.get())); model.center_instances_around_point(Slic3r::Vec2d(100, 100)); - for (ModelObject *mo : model.objects) + for (ModelObject *mo : model.objects) { + mo->ensure_on_bed(); print->auto_assign_extruders(mo); + } print->apply(model, *config); print->validate(); + print->set_status_silent(); return print; } diff --git a/tests/fff_print/test_skirt_brim.cpp b/tests/fff_print/test_skirt_brim.cpp new file mode 100644 index 000000000..0bef2b627 --- /dev/null +++ b/tests/fff_print/test_skirt_brim.cpp @@ -0,0 +1,263 @@ +#include + +#include "libslic3r/GCodeReader.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/Geometry.hpp" + +#include + +#include "test_data.hpp" // get access to init_print, etc + +using namespace Slic3r::Test; +using namespace Slic3r; + +/// Helper method to find the tool used for the brim (always the first extrusion) +int get_brim_tool(std::string &gcode, Slic3r::GCodeReader& parser) { + int brim_tool = -1; + int tool = -1; + + parser.parse_buffer(gcode, [&tool, &brim_tool] (Slic3r::GCodeReader& self, const Slic3r::GCodeReader::GCodeLine& line) + { + // if the command is a T command, set the the current tool + if (boost::starts_with(line.cmd(), "T")) { + tool = atoi(line.cmd().data() + 1); + } else if (line.cmd() == "G1" && line.extruding(self) && line.dist_XY(self) > 0 && brim_tool < 0) { + brim_tool = tool; + } + }); + + return brim_tool; +} + +TEST_CASE("Skirt height is honored") { + std::shared_ptr config(Slic3r::DynamicPrintConfig::new_from_defaults()); + config->opt_int("skirts") = 1; + config->opt_int("skirt_height") = 5; + config->opt_int("perimeters") = 0; + config->opt_float("support_material_speed") = 99; + + // avoid altering speeds unexpectedly + config->set_deserialize("cooling", "0"); + config->set_deserialize("first_layer_speed", "100%"); + auto support_speed = config->opt("support_material_speed")->value * MM_PER_MIN; + + std::map layers_with_skirt; + std::string gcode; + GCodeReader parser; + Slic3r::Model model; + + SECTION("printing a single object") { + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + gcode = Slic3r::Test::gcode(print); + } + + SECTION("printing multiple objects") { + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20, TestMesh::cube_20x20x20}, model, config)}; + gcode = Slic3r::Test::gcode(print); + } + parser.parse_buffer(gcode, [&layers_with_skirt, &support_speed] (Slic3r::GCodeReader& self, const Slic3r::GCodeReader::GCodeLine& line) + { + if (line.extruding(self) && self.f() == Approx(support_speed)) { + layers_with_skirt[self.z()] = 1; + } + }); + + REQUIRE(layers_with_skirt.size() == (size_t)config->opt_int("skirt_height")); +} + +SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { + auto parser {Slic3r::GCodeReader()}; + Slic3r::Model model; + std::string gcode; + GIVEN("A default configuration") { + std::shared_ptr config(Slic3r::DynamicPrintConfig::new_from_defaults()); + config->set_num_extruders(4); + config->opt_float("support_material_speed") = 99; + config->set_deserialize("first_layer_height", "0.3"); + config->set_deserialize("gcode_comments", "1"); + + // avoid altering speeds unexpectedly + config->set_deserialize("cooling", "0"); + config->set_deserialize("first_layer_speed", "100%"); + // remove noise from top/solid layers + config->opt_int("top_solid_layers") = 0; + config->opt_int("bottom_solid_layers") = 1; + + WHEN("Brim width is set to 5") { + config->opt_int("perimeters") = 0; + config->opt_int("skirts") = 0; + config->opt_float("brim_width") = 5; + THEN("Brim is generated") { + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + gcode = Slic3r::Test::gcode(print); + bool brim_generated = false; + auto support_speed = config->opt("support_material_speed")->value * MM_PER_MIN; + parser.parse_buffer(gcode, [&brim_generated, support_speed] (Slic3r::GCodeReader& self, const Slic3r::GCodeReader::GCodeLine& line) + { + if (self.z() == Approx(0.3) || line.new_Z(self) == Approx(0.3)) { + if (line.extruding(self) && self.f() == Approx(support_speed)) { + brim_generated = true; + } + } + }); + REQUIRE(brim_generated); + } + } + + WHEN("Skirt area is smaller than the brim") { + config->opt_int("skirts") = 1; + config->opt_float("brim_width") = 10; + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + THEN("Gcode generates") { + REQUIRE(! Slic3r::Test::gcode(print).empty()); + } + } + + WHEN("Skirt height is 0 and skirts > 0") { + config->opt_int("skirts") = 2; + config->opt_int("skirt_height") = 0; + + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + THEN("Gcode generates") { + REQUIRE(! Slic3r::Test::gcode(print).empty()); + } + } + + WHEN("Perimeter extruder = 2 and support extruders = 3") { + config->opt_int("skirts") = 0; + config->opt_float("brim_width") = 5; + config->opt_int("perimeter_extruder") = 2; + config->opt_int("support_material_extruder") = 3; + THEN("Brim is printed with the extruder used for the perimeters of first object") { + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + gcode = Slic3r::Test::gcode(print); + int tool = get_brim_tool(gcode, parser); + REQUIRE(tool == config->opt_int("perimeter_extruder") - 1); + } + } + WHEN("Perimeter extruder = 2, support extruders = 3, raft is enabled") { + config->opt_int("skirts") = 0; + config->opt_float("brim_width") = 5; + config->opt_int("perimeter_extruder") = 2; + config->opt_int("support_material_extruder") = 3; + config->opt_int("raft_layers") = 1; + THEN("brim is printed with same extruder as skirt") { + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + gcode = Slic3r::Test::gcode(print); + int tool = get_brim_tool(gcode, parser); + REQUIRE(tool == config->opt_int("support_material_extruder") - 1); + } + } + WHEN("brim width to 1 with layer_width of 0.5") { + config->opt_int("skirts") = 0; + config->set_deserialize("first_layer_extrusion_width", "0.5"); + config->opt_float("brim_width") = 1; + + THEN("2 brim lines") { + Slic3r::Model model; + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + print->process(); + REQUIRE(print->brim().entities.size() == 2); + } + } + +#if 0 + WHEN("brim ears on a square") { + config->opt_int("skirts") = 0); + config->set_deserialize("first_layer_extrusion_width", "0.5"); + config->opt_float("brim_width") = 1; + config->set("brim_ears", true); + config->set("brim_ears_max_angle", 91); + + Slic3r::Model model; + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + print->process(); + + THEN("Four brim ears") { + REQUIRE(print->brim.size() == 4); + } + } + + WHEN("brim ears on a square but with a too small max angle") { + config->set("skirts", 0); + config->set("first_layer_extrusion_width", 0.5); + config->set("brim_width", 1); + config->set("brim_ears", true); + config->set("brim_ears_max_angle", 89); + + THEN("no brim") { + Slic3r::Model model; + auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + print->process(); + REQUIRE(print->brim.size() == 0); + } + } +#endif + + WHEN("Object is plated with overhang support and a brim") { + config->opt_float("layer_height") = 0.4; + config->set_deserialize("first_layer_height", "0.4"); + config->opt_int("skirts") = 1; + config->opt_float("skirt_distance") = 0; + config->opt_float("support_material_speed") = 99; + config->opt_int("perimeter_extruder") = 1; + config->opt_int("support_material_extruder") = 2; + config->opt_int("infill_extruder") = 3; // ensure that a tool command gets emitted. + config->set_deserialize("cooling", "0"); // to prevent speeds to be altered + config->set_deserialize("first_layer_speed", "100%"); // to prevent speeds to be altered + + Slic3r::Model model; + auto print {Slic3r::Test::init_print({TestMesh::overhang}, model, config)}; + print->process(); + + // config->set("support_material", true); // to prevent speeds to be altered + + THEN("skirt length is large enough to contain object with support") { + CHECK(config->opt_bool("support_material")); // test is not valid if support material is off + double skirt_length = 0.0; + Points extrusion_points; + int tool = -1; + + auto print = Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config); + std::string gcode = Slic3r::Test::gcode(print); + + auto support_speed = config->opt("support_material_speed")->value * MM_PER_MIN; + parser.parse_buffer(gcode, [config, &extrusion_points, &tool, &skirt_length, support_speed] (Slic3r::GCodeReader& self, const Slic3r::GCodeReader::GCodeLine& line) + { + // std::cerr << line.cmd() << "\n"; + if (boost::starts_with(line.cmd(), "T")) { + tool = atoi(line.cmd().data() + 1); + } else if (self.z() == Approx(config->opt("first_layer_height")->value)) { + // on first layer + if (line.extruding(self) && line.dist_XY(self) > 0) { + auto speed = ( self.f() > 0 ? self.f() : line.new_F(self)); + // std::cerr << "Tool " << tool << "\n"; + if (speed == Approx(support_speed) && tool == config->opt_int("perimeter_extruder") - 1) { + // Skirt uses first material extruder, support material speed. + skirt_length += line.dist_XY(self); + } else { + extrusion_points.push_back(Slic3r::Point::new_scale(line.new_X(self), line.new_Y(self))); + } + } + } + + if (self.z() == Approx(0.3) || line.new_Z(self) == Approx(0.3)) { + if (line.extruding(self) && self.f() == Approx(support_speed)) { + } + } + }); + Slic3r::Polygon convex_hull = Slic3r::Geometry::convex_hull(extrusion_points); + double hull_perimeter = unscale(convex_hull.split_at_first_point().length()); + REQUIRE(skirt_length > hull_perimeter); + } + } + WHEN("Large minimum skirt length is used.") { + config->opt_float("min_skirt_length") = 20; + Slic3r::Model model; + auto print = Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config); + THEN("Gcode generation doesn't crash") { + REQUIRE(! Slic3r::Test::gcode(print).empty()); + } + } + } +} From de45be5f299d70a04f37d03cff35a16e86fe2df2 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 15 Oct 2019 17:35:19 +0200 Subject: [PATCH 11/15] Ported test_gcodewriter from upstream Slic3r, thanks @lordofhyphens. The format for G1 Fxxx was changed to fixed three decimal digits. --- src/libslic3r/GCodeWriter.cpp | 2 +- .../test_gcodewriter/config_lift_unlift.ini | 30 +++++ tests/fff_print/CMakeLists.txt | 1 + tests/fff_print/test_data.cpp | 1 - tests/fff_print/test_gcodewriter.cpp | 124 ++++++++++++++++++ 5 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 tests/data/fff_print_tests/test_gcodewriter/config_lift_unlift.ini create mode 100644 tests/fff_print/test_gcodewriter.cpp diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 51fca58f6..364ba12ae 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -269,7 +269,7 @@ std::string GCodeWriter::set_speed(double F, const std::string &comment, const s assert(F > 0.); assert(F < 100000.); std::ostringstream gcode; - gcode << "G1 F" << F; + gcode << "G1 F" << XYZF_NUM(F); COMMENT(comment); gcode << cooling_marker; gcode << "\n"; diff --git a/tests/data/fff_print_tests/test_gcodewriter/config_lift_unlift.ini b/tests/data/fff_print_tests/test_gcodewriter/config_lift_unlift.ini new file mode 100644 index 000000000..9d44cd43e --- /dev/null +++ b/tests/data/fff_print_tests/test_gcodewriter/config_lift_unlift.ini @@ -0,0 +1,30 @@ +before_layer_gcode = +between_objects_gcode = +end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n" +end_gcode = M104 S0 ; turn off temperature\nG28 X0 ; home X axis\nM84 ; disable motors\n +extrusion_axis = E +extrusion_multiplier = 1 +filament_cost = 0 +filament_density = 0 +filament_diameter = 3 +filament_max_volumetric_speed = 0 +gcode_comments = 0 +gcode_flavor = reprap +layer_gcode = +max_print_speed = 80 +max_volumetric_speed = 0 +retract_length = 2 +retract_length_toolchange = 10 +retract_lift = 1.5 +retract_lift_above = 0 +retract_lift_below = 0 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 40 +start_filament_gcode = "; Filament gcode\n" +start_gcode = G28 ; home all axes\nG1 Z5 F5000 ; lift nozzle\n +toolchange_gcode = +travel_speed = 130 +use_firmware_retraction = 0 +use_relative_e_distances = 0 +use_volumetric_e = 0 diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt index 3c47d637e..1ba953b8b 100644 --- a/tests/fff_print/CMakeLists.txt +++ b/tests/fff_print/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable(${_TEST_NAME}_tests test_data.cpp test_data.hpp test_flow.cpp + test_gcodewriter.cpp test_skirt_brim.cpp test_trianglemesh.cpp ) diff --git a/tests/fff_print/test_data.cpp b/tests/fff_print/test_data.cpp index a07360af7..7144ce5de 100644 --- a/tests/fff_print/test_data.cpp +++ b/tests/fff_print/test_data.cpp @@ -11,7 +11,6 @@ #include #include -using namespace std::string_literals; using namespace std; namespace Slic3r { namespace Test { diff --git a/tests/fff_print/test_gcodewriter.cpp b/tests/fff_print/test_gcodewriter.cpp new file mode 100644 index 000000000..4f1c550eb --- /dev/null +++ b/tests/fff_print/test_gcodewriter.cpp @@ -0,0 +1,124 @@ +#include + +#include + +#include "libslic3r/GCodeWriter.hpp" + +using namespace Slic3r; + +SCENARIO("lift() and unlift() behavior with large values of Z", "[!shouldfail]") { + GIVEN("A config from a file and a single extruder.") { + GCodeWriter writer; + GCodeConfig &config = writer.config; + config.load(std::string(TEST_DATA_DIR) + "/fff_print_tests/test_gcodewriter/config_lift_unlift.ini"); + + std::vector extruder_ids {0}; + writer.set_extruders(extruder_ids); + writer.set_extruder(0); + + WHEN("Z is set to 9007199254740992") { + double trouble_Z = 9007199254740992; + writer.travel_to_z(trouble_Z); + AND_WHEN("GcodeWriter::Lift() is called") { + REQUIRE(writer.lift().size() > 0); + AND_WHEN("Z is moved post-lift to the same delta as the config Z lift") { + REQUIRE(writer.travel_to_z(trouble_Z + config.retract_lift.values[0]).size() == 0); + AND_WHEN("GCodeWriter::Unlift() is called") { + REQUIRE(writer.unlift().size() == 0); // we're the same height so no additional move happens. + THEN("GCodeWriter::Lift() emits gcode.") { + REQUIRE(writer.lift().size() > 0); + } + } + } + } + } + } +} + +SCENARIO("lift() is not ignored after unlift() at normal values of Z") { + GIVEN("A config from a file and a single extruder.") { + GCodeWriter writer; + GCodeConfig &config = writer.config; + config.load(std::string(TEST_DATA_DIR) + "/fff_print_tests/test_gcodewriter/config_lift_unlift.ini"); + + std::vector extruder_ids {0}; + writer.set_extruders(extruder_ids); + writer.set_extruder(0); + + WHEN("Z is set to 203") { + double trouble_Z = 203; + writer.travel_to_z(trouble_Z); + AND_WHEN("GcodeWriter::Lift() is called") { + REQUIRE(writer.lift().size() > 0); + AND_WHEN("Z is moved post-lift to the same delta as the config Z lift") { + REQUIRE(writer.travel_to_z(trouble_Z + config.retract_lift.values[0]).size() == 0); + AND_WHEN("GCodeWriter::Unlift() is called") { + REQUIRE(writer.unlift().size() == 0); // we're the same height so no additional move happens. + THEN("GCodeWriter::Lift() emits gcode.") { + REQUIRE(writer.lift().size() > 0); + } + } + } + } + } + WHEN("Z is set to 500003") { + double trouble_Z = 500003; + writer.travel_to_z(trouble_Z); + AND_WHEN("GcodeWriter::Lift() is called") { + REQUIRE(writer.lift().size() > 0); + AND_WHEN("Z is moved post-lift to the same delta as the config Z lift") { + REQUIRE(writer.travel_to_z(trouble_Z + config.retract_lift.values[0]).size() == 0); + AND_WHEN("GCodeWriter::Unlift() is called") { + REQUIRE(writer.unlift().size() == 0); // we're the same height so no additional move happens. + THEN("GCodeWriter::Lift() emits gcode.") { + REQUIRE(writer.lift().size() > 0); + } + } + } + } + } + WHEN("Z is set to 10.3") { + double trouble_Z = 10.3; + writer.travel_to_z(trouble_Z); + AND_WHEN("GcodeWriter::Lift() is called") { + REQUIRE(writer.lift().size() > 0); + AND_WHEN("Z is moved post-lift to the same delta as the config Z lift") { + REQUIRE(writer.travel_to_z(trouble_Z + config.retract_lift.values[0]).size() == 0); + AND_WHEN("GCodeWriter::Unlift() is called") { + REQUIRE(writer.unlift().size() == 0); // we're the same height so no additional move happens. + THEN("GCodeWriter::Lift() emits gcode.") { + REQUIRE(writer.lift().size() > 0); + } + } + } + } + } + } +} + +SCENARIO("set_speed emits values with fixed-point output.") { + + GIVEN("GCodeWriter instance") { + GCodeWriter writer; + WHEN("set_speed is called to set speed to 99999.123") { + THEN("Output string is G1 F99999.123") { + REQUIRE_THAT(writer.set_speed(99999.123), Catch::Equals("G1 F99999.123\n")); + } + } + WHEN("set_speed is called to set speed to 1") { + THEN("Output string is G1 F1.000") { + REQUIRE_THAT(writer.set_speed(1.0), Catch::Equals("G1 F1.000\n")); + } + } + WHEN("set_speed is called to set speed to 203.200022") { + THEN("Output string is G1 F203.200") { + REQUIRE_THAT(writer.set_speed(203.200022), Catch::Equals("G1 F203.200\n")); + } + } + WHEN("set_speed is called to set speed to 203.200522") { + THEN("Output string is G1 F203.201") { + REQUIRE_THAT(writer.set_speed(203.200522), Catch::Equals("G1 F203.201\n")); + } + } + } +} From abe856f9fe86582e1c717204bf6f8058eee85590 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 15 Oct 2019 18:08:32 +0200 Subject: [PATCH 12/15] Ported remove_collinear(Polygon) and test_polygon from upstream slic3r. --- src/libslic3r/GCode/CoolingBuffer.hpp | 2 +- src/libslic3r/Polygon.cpp | 43 +++++++++++++++++++++++++- src/libslic3r/Polygon.hpp | 2 ++ tests/libslic3r/CMakeLists.txt | 1 + tests/libslic3r/test_polygon.cpp | 44 +++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 tests/libslic3r/test_polygon.cpp diff --git a/src/libslic3r/GCode/CoolingBuffer.hpp b/src/libslic3r/GCode/CoolingBuffer.hpp index 511089ad0..b0c35ecc5 100644 --- a/src/libslic3r/GCode/CoolingBuffer.hpp +++ b/src/libslic3r/GCode/CoolingBuffer.hpp @@ -1,7 +1,7 @@ #ifndef slic3r_CoolingBuffer_hpp_ #define slic3r_CoolingBuffer_hpp_ -#include "libslic3r.h" +#include "../libslic3r.h" #include #include diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp index 4c2db2848..bd5ec3de5 100644 --- a/src/libslic3r/Polygon.cpp +++ b/src/libslic3r/Polygon.cpp @@ -15,7 +15,7 @@ Polyline Polygon::split_at_vertex(const Point &point) const // find index of point for (const Point &pt : this->points) if (pt == point) - return this->split_at_index(&pt - &this->points.front()); + return this->split_at_index(int(&pt - &this->points.front())); throw std::invalid_argument("Point not found"); return Polyline(); } @@ -394,4 +394,45 @@ bool remove_small(Polygons &polys, double min_area) return modified; } +void remove_collinear(Polygon &poly) +{ + if (poly.points.size() > 2) { + // copy points and append both 1 and last point in place to cover the boundaries + Points pp; + pp.reserve(poly.points.size()+2); + pp.push_back(poly.points.back()); + pp.insert(pp.begin()+1, poly.points.begin(), poly.points.end()); + pp.push_back(poly.points.front()); + // delete old points vector. Will be re-filled in the loop + poly.points.clear(); + + size_t i = 0; + size_t k = 0; + while (i < pp.size()-2) { + k = i+1; + const Point &p1 = pp[i]; + while (k < pp.size()-1) { + const Point &p2 = pp[k]; + const Point &p3 = pp[k+1]; + Line l(p1, p3); + if(l.distance_to(p2) < SCALED_EPSILON) { + k++; + } else { + if(i > 0) poly.points.push_back(p1); // implicitly removes the first point we appended above + i = k; + break; + } + } + if(k > pp.size()-2) break; // all remaining points are collinear and can be skipped + } + poly.points.push_back(pp[i]); + } +} + +void remove_collinear(Polygons &polys) +{ + for (Polygon &poly : polys) + remove_collinear(poly); +} + } diff --git a/src/libslic3r/Polygon.hpp b/src/libslic3r/Polygon.hpp index 42f938c72..19be3068b 100644 --- a/src/libslic3r/Polygon.hpp +++ b/src/libslic3r/Polygon.hpp @@ -86,6 +86,8 @@ extern bool remove_sticks(Polygons &polys); // Remove polygons with less than 3 edges. extern bool remove_degenerate(Polygons &polys); extern bool remove_small(Polygons &polys, double min_area); +extern void remove_collinear(Polygon &poly); +extern void remove_collinear(Polygons &polys); // Append a vector of polygons at the end of another vector of polygons. inline void polygons_append(Polygons &dst, const Polygons &src) { dst.insert(dst.end(), src.begin(), src.end()); } diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index ea83bf089..cfc7ea833 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -2,6 +2,7 @@ get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests.cpp test_geometry.cpp + test_polygon.cpp ) target_link_libraries(${_TEST_NAME}_tests test_common libslic3r) set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") diff --git a/tests/libslic3r/test_polygon.cpp b/tests/libslic3r/test_polygon.cpp new file mode 100644 index 000000000..8e9975843 --- /dev/null +++ b/tests/libslic3r/test_polygon.cpp @@ -0,0 +1,44 @@ +#include + +#include "libslic3r/Point.hpp" +#include "libslic3r/Polygon.hpp" + +using namespace Slic3r; + +// This test currently only covers remove_collinear_points. +// All remaining tests are to be ported from xs/t/06_polygon.t + +Slic3r::Points collinear_circle({ + Slic3r::Point::new_scale(0, 0), // 3 collinear points at beginning + Slic3r::Point::new_scale(10, 0), + Slic3r::Point::new_scale(20, 0), + Slic3r::Point::new_scale(30, 10), + Slic3r::Point::new_scale(40, 20), // 2 collinear points + Slic3r::Point::new_scale(40, 30), + Slic3r::Point::new_scale(30, 40), // 3 collinear points + Slic3r::Point::new_scale(20, 40), + Slic3r::Point::new_scale(10, 40), + Slic3r::Point::new_scale(-10, 20), + Slic3r::Point::new_scale(-20, 10), + Slic3r::Point::new_scale(-20, 0), // 3 collinear points at end + Slic3r::Point::new_scale(-10, 0), + Slic3r::Point::new_scale(-5, 0) +}); + +SCENARIO("Remove collinear points from Polygon") { + GIVEN("Polygon with collinear points"){ + Slic3r::Polygon p(collinear_circle); + WHEN("collinear points are removed") { + remove_collinear(p); + THEN("Leading collinear points are removed") { + REQUIRE(p.points.front() == Slic3r::Point::new_scale(20, 0)); + } + THEN("Trailing collinear points are removed") { + REQUIRE(p.points.back() == Slic3r::Point::new_scale(-20, 0)); + } + THEN("Number of remaining points is correct") { + REQUIRE(p.points.size() == 7); + } + } + } +} From 72e99cf35f7d5b5aeb1c476b0806f66d31e16e6e Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 15 Oct 2019 18:38:40 +0200 Subject: [PATCH 13/15] Fixing some compilation issues of the C++ test cases on OSX. --- tests/fff_print/test_data.cpp | 19 +++++++++++-------- tests/fff_print/test_flow.cpp | 6 +++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/fff_print/test_data.cpp b/tests/fff_print/test_data.cpp index 7144ce5de..a02b7d1bb 100644 --- a/tests/fff_print/test_data.cpp +++ b/tests/fff_print/test_data.cpp @@ -203,15 +203,21 @@ TriangleMesh mesh(TestMesh m) return _mesh; } +static bool verbose_gcode() +{ + const char *v = std::getenv("SLIC3R_TESTS_GCODE"); + if (v == nullptr) + return false; + std::string s(v); + return s == "1" || s == "on" || s == "yes"; +} + std::shared_ptr init_print(std::initializer_list meshes, Slic3r::Model& model, std::shared_ptr _config, bool comments) { std::shared_ptr config(Slic3r::DynamicPrintConfig::new_from_defaults()); config->apply(*_config); - const char* v {std::getenv("SLIC3R_TESTS_GCODE")}; - auto tests_gcode {(v == nullptr ? "" : std::string(v))}; - - if (tests_gcode != "") + if (verbose_gcode()) config->set_key_value("gcode_comments", new ConfigOptionBool(true)); std::shared_ptr print {std::make_shared()}; @@ -241,10 +247,7 @@ std::shared_ptr init_print(std::initializer_list meshes, Sl std::shared_ptr config(Slic3r::DynamicPrintConfig::new_from_defaults()); config->apply(*_config); - const char* v {std::getenv("SLIC3R_TESTS_GCODE")}; - auto tests_gcode {(v == nullptr ? "" : std::string(v))}; - - if (tests_gcode != "") + if (verbose_gcode()) config->set_key_value("gcode_comments", new ConfigOptionBool(true)); std::shared_ptr print { std::make_shared() }; diff --git a/tests/fff_print/test_flow.cpp b/tests/fff_print/test_flow.cpp index eef47b943..810e97729 100644 --- a/tests/fff_print/test_flow.cpp +++ b/tests/fff_print/test_flow.cpp @@ -28,11 +28,11 @@ SCENARIO("Extrusion width specifics", "[!mayfail]") { WHEN("first layer width set to 2mm") { Slic3r::Model model; config->set_deserialize("first_layer_extrusion_width", "2"); - auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + std::shared_ptr print = Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config); std::vector E_per_mm_bottom; - std::string gcode = ::Test::gcode(print); - auto parser {Slic3r::GCodeReader()}; + std::string gcode = Test::gcode(print); + Slic3r::GCodeReader parser; const auto layer_height { config->opt_float("layer_height") }; parser.parse_buffer(gcode, [&E_per_mm_bottom, layer_height] (Slic3r::GCodeReader& self, const Slic3r::GCodeReader::GCodeLine& line) { From 21837ceb855ae2f16f09c948642470217b80f2c8 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 15 Oct 2019 19:04:02 +0200 Subject: [PATCH 14/15] Trying to fix compilation issues of the test cases on OSX. --- tests/fff_print/test_flow.cpp | 36 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/fff_print/test_flow.cpp b/tests/fff_print/test_flow.cpp index 810e97729..36ff3c7e7 100644 --- a/tests/fff_print/test_flow.cpp +++ b/tests/fff_print/test_flow.cpp @@ -33,7 +33,7 @@ SCENARIO("Extrusion width specifics", "[!mayfail]") { std::vector E_per_mm_bottom; std::string gcode = Test::gcode(print); Slic3r::GCodeReader parser; - const auto layer_height { config->opt_float("layer_height") }; + const double layer_height = config->opt_float("layer_height"); parser.parse_buffer(gcode, [&E_per_mm_bottom, layer_height] (Slic3r::GCodeReader& self, const Slic3r::GCodeReader::GCodeLine& line) { if (self.z() == Approx(layer_height).margin(0.01)) { // only consider first layer @@ -44,7 +44,7 @@ SCENARIO("Extrusion width specifics", "[!mayfail]") { }); THEN(" First layer width applies to everything on first layer.") { bool pass = false; - auto avg_E {std::accumulate(E_per_mm_bottom.cbegin(), E_per_mm_bottom.cend(), 0.0) / static_cast(E_per_mm_bottom.size())}; + double avg_E = std::accumulate(E_per_mm_bottom.cbegin(), E_per_mm_bottom.cend(), 0.0) / static_cast(E_per_mm_bottom.size()); pass = (std::count_if(E_per_mm_bottom.cbegin(), E_per_mm_bottom.cend(), [avg_E] (const double& v) { return v == Approx(avg_E); }) == 0); REQUIRE(pass == true); @@ -91,7 +91,7 @@ SCENARIO(" Bridge flow specifics.", "[!mayfail]") { /// spacing, etc SCENARIO("Flow: Flow math for non-bridges", "[!mayfail]") { GIVEN("Nozzle Diameter of 0.4, a desired width of 1mm and layer height of 0.5") { - auto width {ConfigOptionFloatOrPercent(1.0, false)}; + ConfigOptionFloatOrPercent width(1.0, false); float spacing {0.4}; float nozzle_diameter {0.4}; float bridge_flow {1.0}; @@ -99,16 +99,16 @@ SCENARIO("Flow: Flow math for non-bridges", "[!mayfail]") { // Spacing for non-bridges is has some overlap THEN("External perimeter flow has spacing fixed to 1.1*nozzle_diameter") { - auto flow {Flow::new_from_config_width(frExternalPerimeter, ConfigOptionFloatOrPercent(0, false), nozzle_diameter, layer_height, 0.0f)}; + auto flow = Flow::new_from_config_width(frExternalPerimeter, ConfigOptionFloatOrPercent(0, false), nozzle_diameter, layer_height, 0.0f); REQUIRE(flow.spacing() == Approx((1.1*nozzle_diameter) - layer_height * (1.0 - PI / 4.0))); } THEN("Internal perimeter flow has spacing of 1.05 (minimum)") { - auto flow {Flow::new_from_config_width(frPerimeter, ConfigOptionFloatOrPercent(0, false), nozzle_diameter, layer_height, 0.0f)}; + auto flow = Flow::new_from_config_width(frPerimeter, ConfigOptionFloatOrPercent(0, false), nozzle_diameter, layer_height, 0.0f); REQUIRE(flow.spacing() == Approx((1.05*nozzle_diameter) - layer_height * (1.0 - PI / 4.0))); } THEN("Spacing for supplied width is 0.8927f") { - auto flow {Flow::new_from_config_width(frExternalPerimeter, width, nozzle_diameter, layer_height, 0.0f)}; + auto flow = Flow::new_from_config_width(frExternalPerimeter, width, nozzle_diameter, layer_height, 0.0f); REQUIRE(flow.spacing() == Approx(width.value - layer_height * (1.0 - PI / 4.0))); flow = Flow::new_from_config_width(frPerimeter, width, nozzle_diameter, layer_height, 0.0f); REQUIRE(flow.spacing() == Approx(width.value - layer_height * (1.0 - PI / 4.0))); @@ -123,14 +123,14 @@ SCENARIO("Flow: Flow math for non-bridges", "[!mayfail]") { WHEN("layer height is set to 0.2") { layer_height = 0.15f; THEN("Max width is set.") { - auto flow {Flow::new_from_config_width(frPerimeter, ConfigOptionFloatOrPercent(0, false), nozzle_diameter, layer_height, 0.0f)}; + auto flow = Flow::new_from_config_width(frPerimeter, ConfigOptionFloatOrPercent(0, false), nozzle_diameter, layer_height, 0.0f); REQUIRE(flow.width == Approx(1.4*nozzle_diameter)); } } WHEN("Layer height is set to 0.2") { layer_height = 0.3f; THEN("Min width is set.") { - auto flow {Flow::new_from_config_width(frPerimeter, ConfigOptionFloatOrPercent(0, false), nozzle_diameter, layer_height, 0.0f)}; + auto flow = Flow::new_from_config_width(frPerimeter, ConfigOptionFloatOrPercent(0, false), nozzle_diameter, layer_height, 0.0f); REQUIRE(flow.width == Approx(1.05*nozzle_diameter)); } } @@ -143,7 +143,7 @@ SCENARIO("Flow: Flow math for non-bridges", "[!mayfail]") { GIVEN("Input spacing of 0.414159 and a total width of 2") { double in_spacing = 0.414159; double total_width = 2.0; - auto flow {Flow::new_from_spacing(1.0, 0.4, 0.3, false)}; + auto flow = Flow::new_from_spacing(1.0, 0.4, 0.3, false); WHEN("solid_spacing() is called") { double result = flow.solid_spacing(total_width, in_spacing); THEN("Yielded spacing is greater than 0") { @@ -158,13 +158,13 @@ SCENARIO("Flow: Flow math for non-bridges", "[!mayfail]") { /// Spacing, width calculation for bridge extrusions SCENARIO("Flow: Flow math for bridges", "[!mayfail]") { GIVEN("Nozzle Diameter of 0.4, a desired width of 1mm and layer height of 0.5") { - auto width {ConfigOptionFloatOrPercent(1.0, false)}; - auto spacing {0.4}; - auto nozzle_diameter {0.4}; - auto bridge_flow {1.0}; - auto layer_height {0.5}; + auto width = ConfigOptionFloatOrPercent(1.0, false); + double spacing = 0.4; + double nozzle_diameter = 0.4; + double bridge_flow = 1.0; + double layer_height = 0.5; WHEN("Flow role is frExternalPerimeter") { - auto flow {Flow::new_from_config_width(frExternalPerimeter, width, nozzle_diameter, layer_height, bridge_flow)}; + auto flow = Flow::new_from_config_width(frExternalPerimeter, width, nozzle_diameter, layer_height, bridge_flow); THEN("Bridge width is same as nozzle diameter") { REQUIRE(flow.width == Approx(nozzle_diameter)); } @@ -173,7 +173,7 @@ SCENARIO("Flow: Flow math for bridges", "[!mayfail]") { } } WHEN("Flow role is frInfill") { - auto flow {Flow::new_from_config_width(frInfill, width, nozzle_diameter, layer_height, bridge_flow)}; + auto flow = Flow::new_from_config_width(frInfill, width, nozzle_diameter, layer_height, bridge_flow); THEN("Bridge width is same as nozzle diameter") { REQUIRE(flow.width == Approx(nozzle_diameter)); } @@ -182,7 +182,7 @@ SCENARIO("Flow: Flow math for bridges", "[!mayfail]") { } } WHEN("Flow role is frPerimeter") { - auto flow {Flow::new_from_config_width(frPerimeter, width, nozzle_diameter, layer_height, bridge_flow)}; + auto flow = Flow::new_from_config_width(frPerimeter, width, nozzle_diameter, layer_height, bridge_flow); THEN("Bridge width is same as nozzle diameter") { REQUIRE(flow.width == Approx(nozzle_diameter)); } @@ -191,7 +191,7 @@ SCENARIO("Flow: Flow math for bridges", "[!mayfail]") { } } WHEN("Flow role is frSupportMaterial") { - auto flow {Flow::new_from_config_width(frSupportMaterial, width, nozzle_diameter, layer_height, bridge_flow)}; + auto flow = Flow::new_from_config_width(frSupportMaterial, width, nozzle_diameter, layer_height, bridge_flow); THEN("Bridge width is same as nozzle diameter") { REQUIRE(flow.width == Approx(nozzle_diameter)); } From 90d57120911074b7976ece156d35190c7d71c40c Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 16 Oct 2019 09:28:27 +0200 Subject: [PATCH 15/15] Filling in the autos in the tests so it is readible and it compiles on OSX --- tests/fff_print/test_skirt_brim.cpp | 32 +++++++++---------- tests/fff_print/test_trianglemesh.cpp | 44 +++++++++++++-------------- tests/libslic3r/test_geometry.cpp | 22 +++++++------- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/tests/fff_print/test_skirt_brim.cpp b/tests/fff_print/test_skirt_brim.cpp index 0bef2b627..64c548d3f 100644 --- a/tests/fff_print/test_skirt_brim.cpp +++ b/tests/fff_print/test_skirt_brim.cpp @@ -39,7 +39,7 @@ TEST_CASE("Skirt height is honored") { // avoid altering speeds unexpectedly config->set_deserialize("cooling", "0"); config->set_deserialize("first_layer_speed", "100%"); - auto support_speed = config->opt("support_material_speed")->value * MM_PER_MIN; + double support_speed = config->opt("support_material_speed")->value * MM_PER_MIN; std::map layers_with_skirt; std::string gcode; @@ -47,12 +47,12 @@ TEST_CASE("Skirt height is honored") { Slic3r::Model model; SECTION("printing a single object") { - auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + auto print = Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config); gcode = Slic3r::Test::gcode(print); } SECTION("printing multiple objects") { - auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20, TestMesh::cube_20x20x20}, model, config)}; + auto print = Slic3r::Test::init_print({TestMesh::cube_20x20x20, TestMesh::cube_20x20x20}, model, config); gcode = Slic3r::Test::gcode(print); } parser.parse_buffer(gcode, [&layers_with_skirt, &support_speed] (Slic3r::GCodeReader& self, const Slic3r::GCodeReader::GCodeLine& line) @@ -66,7 +66,7 @@ TEST_CASE("Skirt height is honored") { } SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { - auto parser {Slic3r::GCodeReader()}; + Slic3r::GCodeReader parser; Slic3r::Model model; std::string gcode; GIVEN("A default configuration") { @@ -88,10 +88,10 @@ SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { config->opt_int("skirts") = 0; config->opt_float("brim_width") = 5; THEN("Brim is generated") { - auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + auto print = Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config); gcode = Slic3r::Test::gcode(print); bool brim_generated = false; - auto support_speed = config->opt("support_material_speed")->value * MM_PER_MIN; + double support_speed = config->opt("support_material_speed")->value * MM_PER_MIN; parser.parse_buffer(gcode, [&brim_generated, support_speed] (Slic3r::GCodeReader& self, const Slic3r::GCodeReader::GCodeLine& line) { if (self.z() == Approx(0.3) || line.new_Z(self) == Approx(0.3)) { @@ -107,7 +107,7 @@ SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { WHEN("Skirt area is smaller than the brim") { config->opt_int("skirts") = 1; config->opt_float("brim_width") = 10; - auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + auto print = Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config); THEN("Gcode generates") { REQUIRE(! Slic3r::Test::gcode(print).empty()); } @@ -117,7 +117,7 @@ SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { config->opt_int("skirts") = 2; config->opt_int("skirt_height") = 0; - auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + auto print = Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config); THEN("Gcode generates") { REQUIRE(! Slic3r::Test::gcode(print).empty()); } @@ -129,7 +129,7 @@ SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { config->opt_int("perimeter_extruder") = 2; config->opt_int("support_material_extruder") = 3; THEN("Brim is printed with the extruder used for the perimeters of first object") { - auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + auto print = Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config); gcode = Slic3r::Test::gcode(print); int tool = get_brim_tool(gcode, parser); REQUIRE(tool == config->opt_int("perimeter_extruder") - 1); @@ -142,7 +142,7 @@ SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { config->opt_int("support_material_extruder") = 3; config->opt_int("raft_layers") = 1; THEN("brim is printed with same extruder as skirt") { - auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + auto print = Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config); gcode = Slic3r::Test::gcode(print); int tool = get_brim_tool(gcode, parser); REQUIRE(tool == config->opt_int("support_material_extruder") - 1); @@ -155,7 +155,7 @@ SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { THEN("2 brim lines") { Slic3r::Model model; - auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + auto print = Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config); print->process(); REQUIRE(print->brim().entities.size() == 2); } @@ -170,7 +170,7 @@ SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { config->set("brim_ears_max_angle", 91); Slic3r::Model model; - auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + auto print = Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config); print->process(); THEN("Four brim ears") { @@ -187,7 +187,7 @@ SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { THEN("no brim") { Slic3r::Model model; - auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)}; + auto print = Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config); print->process(); REQUIRE(print->brim.size() == 0); } @@ -207,7 +207,7 @@ SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { config->set_deserialize("first_layer_speed", "100%"); // to prevent speeds to be altered Slic3r::Model model; - auto print {Slic3r::Test::init_print({TestMesh::overhang}, model, config)}; + auto print = Slic3r::Test::init_print({TestMesh::overhang}, model, config); print->process(); // config->set("support_material", true); // to prevent speeds to be altered @@ -221,7 +221,7 @@ SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { auto print = Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config); std::string gcode = Slic3r::Test::gcode(print); - auto support_speed = config->opt("support_material_speed")->value * MM_PER_MIN; + double support_speed = config->opt("support_material_speed")->value * MM_PER_MIN; parser.parse_buffer(gcode, [config, &extrusion_points, &tool, &skirt_length, support_speed] (Slic3r::GCodeReader& self, const Slic3r::GCodeReader::GCodeLine& line) { // std::cerr << line.cmd() << "\n"; @@ -230,7 +230,7 @@ SCENARIO("Original Slic3r Skirt/Brim tests", "[!mayfail]") { } else if (self.z() == Approx(config->opt("first_layer_height")->value)) { // on first layer if (line.extruding(self) && line.dist_XY(self) > 0) { - auto speed = ( self.f() > 0 ? self.f() : line.new_F(self)); + float speed = ( self.f() > 0 ? self.f() : line.new_F(self)); // std::cerr << "Tool " << tool << "\n"; if (speed == Approx(support_speed) && tool == config->opt_int("perimeter_extruder") - 1) { // Skirt uses first material extruder, support material speed. diff --git a/tests/fff_print/test_trianglemesh.cpp b/tests/fff_print/test_trianglemesh.cpp index 8e099db75..e24a77e7f 100644 --- a/tests/fff_print/test_trianglemesh.cpp +++ b/tests/fff_print/test_trianglemesh.cpp @@ -28,10 +28,10 @@ SCENARIO( "TriangleMesh: Basic mesh statistics") { } THEN( "Vertices array matches input.") { - for (auto i = 0U; i < cube.its.vertices.size(); i++) { + for (size_t i = 0U; i < cube.its.vertices.size(); i++) { REQUIRE(cube.its.vertices.at(i) == vertices.at(i).cast()); } - for (auto i = 0U; i < vertices.size(); i++) { + for (size_t i = 0U; i < vertices.size(); i++) { REQUIRE(vertices.at(i).cast() == cube.its.vertices.at(i)); } } @@ -40,11 +40,11 @@ SCENARIO( "TriangleMesh: Basic mesh statistics") { } THEN( "Facet array matches input.") { - for (auto i = 0U; i < cube.its.indices.size(); i++) { + for (size_t i = 0U; i < cube.its.indices.size(); i++) { REQUIRE(cube.its.indices.at(i) == facets.at(i)); } - for (auto i = 0U; i < facets.size(); i++) { + for (size_t i = 0U; i < facets.size(); i++) { REQUIRE(facets.at(i) == cube.its.indices.at(i)); } } @@ -79,10 +79,10 @@ SCENARIO( "TriangleMesh: Basic mesh statistics") { } THEN( "Vertices array matches input.") { - for (auto i = 0U; i < cube.its.vertices.size(); i++) { + for (size_t i = 0U; i < cube.its.vertices.size(); i++) { REQUIRE(cube.its.vertices.at(i) == vertices.at(i).cast()); } - for (auto i = 0U; i < vertices.size(); i++) { + for (size_t i = 0U; i < vertices.size(); i++) { REQUIRE(vertices.at(i).cast() == cube.its.vertices.at(i)); } } @@ -91,11 +91,11 @@ SCENARIO( "TriangleMesh: Basic mesh statistics") { } THEN( "Facet array matches input.") { - for (auto i = 0U; i < cube.its.indices.size(); i++) { + for (size_t i = 0U; i < cube.its.indices.size(); i++) { REQUIRE(cube.its.indices.at(i) == facets.at(i)); } - for (auto i = 0U; i < facets.size(); i++) { + for (size_t i = 0U; i < facets.size(); i++) { REQUIRE(facets.at(i) == cube.its.indices.at(i)); } } @@ -191,14 +191,14 @@ SCENARIO( "TriangleMesh: slice behavior.") { WHEN("Cube is sliced with z = [0+EPSILON,2,4,8,6,8,10,12,14,16,18,20]") { std::vector z { 0+EPSILON,2,4,8,6,8,10,12,14,16,18,20 }; - auto result {cube.slice(z)}; + std::vector result = cube.slice(z); THEN( "The correct number of polygons are returned per layer.") { - for (auto i = 0U; i < z.size(); i++) { + for (size_t i = 0U; i < z.size(); i++) { REQUIRE(result.at(i).size() == 1); } } THEN( "The area of the returned polygons is correct.") { - for (auto i = 0U; i < z.size(); i++) { + for (size_t i = 0U; i < z.size(); i++) { REQUIRE(result.at(i).at(0).area() == 20.0*20/(std::pow(SCALING_FACTOR,2))); } } @@ -211,7 +211,7 @@ SCENARIO( "TriangleMesh: slice behavior.") { TriangleMesh cube(vertices, facets); cube.repair(); WHEN(" a top tangent plane is sliced") { - auto slices {cube.slice({5.0, 10.0})}; + std::vector slices = cube.slice({5.0, 10.0}); THEN( "its area is included") { REQUIRE(slices.at(0).at(0).area() > 0); REQUIRE(slices.at(1).at(0).area() > 0); @@ -219,7 +219,7 @@ SCENARIO( "TriangleMesh: slice behavior.") { } WHEN(" a model that has been transformed is sliced") { cube.mirror_z(); - auto slices {cube.slice({-5.0, -10.0})}; + std::vector slices = cube.slice({-5.0, -10.0}); THEN( "it is sliced properly (mirrored bottom plane area is included)") { REQUIRE(slices.at(0).at(0).area() > 0); REQUIRE(slices.at(1).at(0).area() > 0); @@ -233,7 +233,7 @@ SCENARIO( "make_xxx functions produce meshes.") { WHEN("make_cube() is called with arguments 20,20,20") { TriangleMesh cube = make_cube(20,20,20); THEN("The resulting mesh has one and only one vertex at 0,0,0") { - auto verts {cube.its.vertices}; + const std::vector &verts = cube.its.vertices; REQUIRE(std::count_if(verts.begin(), verts.end(), [](const Vec3f& t) { return t.x() == 0 && t.y() == 0 && t.z() == 0; } ) == 1); } THEN("The mesh volume is 20*20*20") { @@ -252,11 +252,11 @@ SCENARIO( "make_xxx functions produce meshes.") { TriangleMesh cyl = make_cylinder(10, 10, PI / 243.0); double angle = (2*PI / floor(2*PI / (PI / 243.0))); THEN("The resulting mesh has one and only one vertex at 0,0,0") { - auto verts {cyl.its.vertices}; + const std::vector &verts = cyl.its.vertices; REQUIRE(std::count_if(verts.begin(), verts.end(), [](const Vec3f& t) { return t.x() == 0 && t.y() == 0 && t.z() == 0; } ) == 1); } THEN("The resulting mesh has one and only one vertex at 0,0,10") { - auto verts {cyl.its.vertices}; + const std::vector &verts = cyl.its.vertices; REQUIRE(std::count_if(verts.begin(), verts.end(), [](const Vec3f& t) { return t.x() == 0 && t.y() == 0 && t.z() == 10; } ) == 1); } THEN("Resulting mesh has 2 + (2*PI/angle * 2) vertices.") { @@ -301,7 +301,7 @@ SCENARIO( "TriangleMesh: split functionality.") { TriangleMesh cube(vertices, facets); cube.repair(); WHEN( "The mesh is split into its component parts.") { - auto meshes {cube.split()}; + std::vector meshes = cube.split(); THEN(" The bounding box statistics are propagated to the split copies") { REQUIRE(meshes.size() == 1); REQUIRE((meshes.at(0)->bounding_box() == cube.bounding_box())); @@ -320,7 +320,7 @@ SCENARIO( "TriangleMesh: split functionality.") { cube.merge(cube2); cube.repair(); WHEN( "The combined mesh is split") { - auto meshes {cube.split()}; + std::vector meshes = cube.split(); THEN( "Two meshes are in the output vector.") { REQUIRE(meshes.size() == 2); } @@ -384,7 +384,7 @@ SCENARIO( "TriangleMeshSlicer: Cut behavior.") { #ifdef TEST_PERFORMANCE TEST_CASE("Regression test for issue #4486 - files take forever to slice") { TriangleMesh mesh; - auto config {Slic3r::Config::new_from_defaults()}; + std::shared_ptr config = Slic3r::DynamicPrintConfig::new_from_defaults(); mesh.ReadSTLFile(std::string(testfile_dir) + "test_trianglemesh/4486/100_000.stl"); mesh.repair(); @@ -393,7 +393,7 @@ TEST_CASE("Regression test for issue #4486 - files take forever to slice") { config->set("nozzle_diameter", 500); Slic3r::Model model; - auto print {Slic3r::Test::init_print({mesh}, model, config)}; + auto print = Slic3r::Test::init_print({mesh}, model, config); print->status_cb = [] (int ln, const std::string& msg) { Slic3r::Log::info("Print") << ln << " " << msg << "\n";}; @@ -411,7 +411,7 @@ TEST_CASE("Regression test for issue #4486 - files take forever to slice") { #ifdef BUILD_PROFILE TEST_CASE("Profile test for issue #4486 - files take forever to slice") { TriangleMesh mesh; - auto config {Slic3r::Config::new_from_defaults()}; + std::shared_ptr config = Slic3r::DynamicPrintConfig::new_from_defaults(); mesh.ReadSTLFile(std::string(testfile_dir) + "test_trianglemesh/4486/10_000.stl"); mesh.repair(); @@ -421,7 +421,7 @@ TEST_CASE("Profile test for issue #4486 - files take forever to slice") { config->set("fill_density", "5%"); Slic3r::Model model; - auto print {Slic3r::Test::init_print({mesh}, model, config)}; + auto print = Slic3r::Test::init_print({mesh}, model, config); print->status_cb = [] (int ln, const std::string& msg) { Slic3r::Log::info("Print") << ln << " " << msg << "\n";}; diff --git a/tests/libslic3r/test_geometry.cpp b/tests/libslic3r/test_geometry.cpp index 7a3b84c7d..fce6a476c 100644 --- a/tests/libslic3r/test_geometry.cpp +++ b/tests/libslic3r/test_geometry.cpp @@ -13,7 +13,7 @@ using namespace Slic3r; TEST_CASE("Polygon::contains works properly", ""){ // this test was failing on Windows (GH #1950) - auto polygon = Slic3r::Polygon(std::vector({ + Slic3r::Polygon polygon(std::vector({ Point(207802834,-57084522), Point(196528149,-37556190), Point(173626821,-25420928), @@ -25,14 +25,14 @@ TEST_CASE("Polygon::contains works properly", ""){ Point(129714478,-84542120), Point(160244873,-84542120) })); - auto point = Point(95706562, -57294774); + Point point(95706562, -57294774); REQUIRE(polygon.contains(point)); } SCENARIO("Intersections of line segments"){ GIVEN("Integer coordinates"){ - auto line1 = Line(Point(5,15),Point(30,15)); - auto line2 = Line(Point(10,20), Point(10,10)); + Line line1(Point(5,15),Point(30,15)); + Line line2(Point(10,20), Point(10,10)); THEN("The intersection is valid"){ Point point; line1.intersection(line2,&point); @@ -41,8 +41,8 @@ SCENARIO("Intersections of line segments"){ } GIVEN("Scaled coordinates"){ - auto line1 = Line(Point(73.6310778185108 / 0.00001, 371.74239268924 / 0.00001), Point(73.6310778185108 / 0.00001, 501.74239268924 / 0.00001)); - auto line2 = Line(Point(75/0.00001, 437.9853/0.00001), Point(62.7484/0.00001, 440.4223/0.00001)); + Line line1(Point(73.6310778185108 / 0.00001, 371.74239268924 / 0.00001), Point(73.6310778185108 / 0.00001, 501.74239268924 / 0.00001)); + Line line2(Point(75/0.00001, 437.9853/0.00001), Point(62.7484/0.00001, 440.4223/0.00001)); THEN("There is still an intersection"){ Point point; REQUIRE(line1.intersection(line2,&point)); @@ -128,7 +128,7 @@ SCENARIO("polygon_is_convex works"){ TEST_CASE("Creating a polyline generates the obvious lines"){ - auto polyline = Slic3r::Polyline(); + Slic3r::Polyline polyline; polyline.points = std::vector({Point(0, 0), Point(10, 0), Point(20, 0)}); REQUIRE(polyline.lines().at(0).a == Point(0,0)); REQUIRE(polyline.lines().at(0).b == Point(10,0)); @@ -137,8 +137,8 @@ TEST_CASE("Creating a polyline generates the obvious lines"){ } TEST_CASE("Splitting a Polygon generates a polyline correctly"){ - auto polygon = Slic3r::Polygon(std::vector({Point(0, 0), Point(10, 0), Point(5, 5)})); - auto split = polygon.split_at_index(1); + Slic3r::Polygon polygon(std::vector({Point(0, 0), Point(10, 0), Point(5, 5)})); + Slic3r::Polyline split = polygon.split_at_index(1); REQUIRE(split.points[0]==Point(10,0)); REQUIRE(split.points[1]==Point(5,5)); REQUIRE(split.points[2]==Point(0,0)); @@ -147,7 +147,7 @@ TEST_CASE("Splitting a Polygon generates a polyline correctly"){ TEST_CASE("Bounding boxes are scaled appropriately"){ - auto bb = BoundingBox(std::vector({Point(0, 1), Point(10, 2), Point(20, 2)})); + BoundingBox bb(std::vector({Point(0, 1), Point(10, 2), Point(20, 2)})); bb.scale(2); REQUIRE(bb.min == Point(0,2)); REQUIRE(bb.max == Point(40,4)); @@ -265,7 +265,7 @@ TEST_CASE("Chained path working correctly"){ SCENARIO("Line distances"){ GIVEN("A line"){ - auto line = Line(Point(0, 0), Point(20, 0)); + Line line(Point(0, 0), Point(20, 0)); THEN("Points on the line segment have 0 distance"){ REQUIRE(line.distance_to(Point(0, 0)) == 0); REQUIRE(line.distance_to(Point(20, 0)) == 0);