diff --git a/CMakeLists.txt b/CMakeLists.txt index d61cab58e..58afbef21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,13 +13,13 @@ if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) endif() if(DEFINED ENV{SLIC3R_STATIC}) - set(SLIC3R_STATIC_INITIAL $ENV{SLIC3R_STATIC}) + set(SLIC3R_STATIC_INITIAL $ENV{SLIC3R_STATIC}) else() - if (MSVC OR MINGW OR APPLE) - set(SLIC3R_STATIC_INITIAL 1) - else() - set(SLIC3R_STATIC_INITIAL 0) - endif() + if (MSVC OR MINGW OR APPLE) + set(SLIC3R_STATIC_INITIAL 1) + else() + set(SLIC3R_STATIC_INITIAL 0) + endif() endif() option(SLIC3R_STATIC "Compile Slic3r with static libraries (Boost, TBB, glew)" ${SLIC3R_STATIC_INITIAL}) @@ -52,9 +52,21 @@ if (SLIC3R_GUI) add_definitions(-DSLIC3R_GUI) endif () +if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set(IS_CLANG_CL TRUE) + + # clang-cl can interpret SYSTEM header paths if -imsvc is used + set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-imsvc") + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall \ + -Wno-old-style-cast -Wno-reserved-id-macro -Wno-c++98-compat-pedantic") +else () + set(IS_CLANG_CL FALSE) +endif () + if (MSVC) - if (SLIC3R_MSVC_COMPILE_PARALLEL) - add_compile_options(/MP) + if (SLIC3R_MSVC_COMPILE_PARALLEL AND NOT IS_CLANG_CL) + add_compile_options(/MP) endif () # /bigobj (Increase Number of Sections in .Obj file) # error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater @@ -62,6 +74,10 @@ if (MSVC) add_compile_options(-bigobj -Zm520 /Zi) endif () +if (MINGW) + add_compile_options(-Wa,-mbig-obj) +endif () + # Display and check CMAKE_PREFIX_PATH message(STATUS "SLIC3R_STATIC: ${SLIC3R_STATIC}") if (NOT "${CMAKE_PREFIX_PATH}" STREQUAL "") @@ -101,17 +117,17 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) # WIN10SDK_PATH is used to point CMake to the WIN10 SDK installation directory. # We pick it from environment if it is not defined in another way if(WIN32) - if(NOT DEFINED WIN10SDK_PATH) - if(DEFINED ENV{WIN10SDK_PATH}) - set(WIN10SDK_PATH "$ENV{WIN10SDK_PATH}") - endif() - endif() - if(DEFINED WIN10SDK_PATH AND NOT EXISTS "${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h") - message("WIN10SDK_PATH is invalid: ${WIN10SDK_PATH}") - message("${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h was not found") - message("STL fixing by the Netfabb service will not be compiled") - unset(WIN10SDK_PATH) - endif() + if(NOT DEFINED WIN10SDK_PATH) + if(DEFINED ENV{WIN10SDK_PATH}) + set(WIN10SDK_PATH "$ENV{WIN10SDK_PATH}") + endif() + endif() + if(DEFINED WIN10SDK_PATH AND NOT EXISTS "${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h") + message("WIN10SDK_PATH is invalid: ${WIN10SDK_PATH}") + message("${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h was not found") + message("STL fixing by the Netfabb service will not be compiled") + unset(WIN10SDK_PATH) + endif() if(WIN10SDK_PATH) message("Building with Win10 Netfabb STL fixing service support") add_definitions(-DHAS_WIN10SDK) @@ -148,8 +164,10 @@ if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals" ) endif() -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" ) +if (NOT MSVC AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) + if (NOT MINGW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" ) + endif () set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder" ) # On GCC and Clang, no return from a non-void function is a warning only. Here, we make it an error. @@ -168,7 +186,6 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATC add_compile_options(-Wno-unknown-pragmas) endif() - if (SLIC3R_ASAN) add_compile_options(-fsanitize=address -fno-omit-frame-pointer) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") @@ -196,9 +213,12 @@ include_directories(${LIBDIR_BIN}/platform) include_directories(${LIBDIR}/clipper ${LIBDIR}/polypartition) if(WIN32) - # BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking. - add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -DBOOST_ALL_NO_LIB -DBOOST_USE_WINAPI_VERSION=0x601 -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) -endif() + add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) + if(MSVC) + # BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking. + add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_USE_WINAPI_VERSION=0x601 ) + endif(MSVC) +endif(WIN32) add_definitions(-DwxUSE_UNICODE -D_UNICODE -DUNICODE -DWXINTL_NO_GETTEXT_MACRO) @@ -229,7 +249,7 @@ if(SLIC3R_STATIC) # set(Boost_USE_STATIC_RUNTIME ON) endif() #set(Boost_DEBUG ON) -# set(Boost_COMPILER "-vc120") +# set(Boost_COMPILER "-mgw81") if(NOT WIN32) # boost::process was introduced first in version 1.64.0 set(MINIMUM_BOOST_VERSION "1.64.0") @@ -251,7 +271,7 @@ endif() if(TARGET Boost::system) message(STATUS "Boost::boost exists") target_link_libraries(boost_headeronly INTERFACE Boost::boost) - target_link_libraries(boost_libs INTERFACE + target_link_libraries(boost_libs INTERFACE boost_headeronly # includes the custom compile definitions as well Boost::system Boost::filesystem diff --git a/cmake/modules/PrecompiledHeader.cmake b/cmake/modules/PrecompiledHeader.cmake index e46302144..2f62a7dbe 100644 --- a/cmake/modules/PrecompiledHeader.cmake +++ b/cmake/modules/PrecompiledHeader.cmake @@ -105,6 +105,9 @@ function(add_precompiled_header _target _input) cmake_parse_arguments(_PCH "FORCEINCLUDE" "SOURCE_CXX;SOURCE_C" "" ${ARGN}) get_filename_component(_input_we ${_input} NAME_WE) + get_filename_component(_input_full ${_input} ABSOLUTE) + file(TO_NATIVE_PATH "${_input_full}" _input_fullpath) + if(NOT _PCH_SOURCE_CXX) set(_PCH_SOURCE_CXX "${_input_we}.cpp") endif() @@ -138,16 +141,16 @@ function(add_precompiled_header _target _input) set_source_files_properties("${_source}" PROPERTIES OBJECT_OUTPUTS "${_pch_c_pch}") else() if(_source MATCHES \\.\(cpp|cxx|cc\)$) - set(_pch_compile_flags "${_pch_compile_flags} \"/Fp${_pch_cxx_pch}\" \"/Yu${_input}\"") + set(_pch_compile_flags "${_pch_compile_flags} \"/Fp${_pch_cxx_pch}\" \"/Yu${_input_fullpath}\"") set(_pch_source_cxx_needed TRUE) set_source_files_properties("${_source}" PROPERTIES OBJECT_DEPENDS "${_pch_cxx_pch}") else() - set(_pch_compile_flags "${_pch_compile_flags} \"/Fp${_pch_c_pch}\" \"/Yu${_input}\"") + set(_pch_compile_flags "${_pch_compile_flags} \"/Fp${_pch_c_pch}\" \"/Yu${_input_fullpath}\"") set(_pch_source_c_needed TRUE) set_source_files_properties("${_source}" PROPERTIES OBJECT_DEPENDS "${_pch_c_pch}") endif() if(_PCH_FORCEINCLUDE) - set(_pch_compile_flags "${_pch_compile_flags} /FI${_input}") + set(_pch_compile_flags "${_pch_compile_flags} /FI${_input_fullpath}") endif(_PCH_FORCEINCLUDE) endif() diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index ba01c0a7e..9da42446d 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -75,7 +75,10 @@ elseif (APPLE) endif () include("deps-macos.cmake") -else () +elseif (MINGW) + message(STATUS "Building for MinGW...") + include("deps-mingw.cmake") +else() include("deps-linux.cmake") endif() diff --git a/deps/deps-mingw.cmake b/deps/deps-mingw.cmake new file mode 100644 index 000000000..bfe5f9fe4 --- /dev/null +++ b/deps/deps-mingw.cmake @@ -0,0 +1,76 @@ +set(DEP_CMAKE_OPTS "-DCMAKE_POSITION_INDEPENDENT_CODE=ON") +set(DEP_BOOST_TOOLSET "gcc") +set(DEP_BITS 64) + +find_package(Git REQUIRED) + +# TODO make sure to build tbb with -flifetime-dse=1 +include("deps-unix-common.cmake") + +ExternalProject_Add(dep_boost + EXCLUDE_FROM_ALL 1 + URL "https://dl.bintray.com/boostorg/release/1.70.0/source/boost_1_70_0.tar.gz" + URL_HASH SHA256=882b48708d211a5f48e60b0124cf5863c1534cd544ecd0664bb534a4b5d506e9 + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND bootstrap.bat + BUILD_COMMAND b2.exe + -j "${NPROC}" + --with-system + --with-filesystem + --with-thread + --with-log + --with-locale + --with-regex + "--prefix=${DESTDIR}/usr/local" + "address-model=${DEPS_BITS}" + "toolset=${DEP_BOOST_TOOLSET}" + link=static + define=BOOST_USE_WINAPI_VERSION=0x0502 + variant=release + threading=multi + boost.locale.icu=off + "${DEP_BOOST_DEBUG}" release install + INSTALL_COMMAND "" # b2 does that already +) + +ExternalProject_Add(dep_libcurl + EXCLUDE_FROM_ALL 1 + URL "https://curl.haxx.se/download/curl-7.58.0.tar.gz" + URL_HASH SHA256=cc245bf9a1a42a45df491501d97d5593392a03f7b4f07b952793518d97666115 + CMAKE_ARGS + -DBUILD_SHARED_LIBS=OFF + -DBUILD_TESTING=OFF + -DCURL_STATICLIB=ON + -DCURL_STATIC_CRT=ON + -DENABLE_THREADED_RESOLVER=ON + -DCURL_DISABLE_FTP=ON + -DCURL_DISABLE_LDAP=ON + -DCURL_DISABLE_LDAPS=ON + -DCURL_DISABLE_TELNET=ON + -DCURL_DISABLE_DICT=ON + -DCURL_DISABLE_FILE=ON + -DCURL_DISABLE_TFTP=ON + -DCURL_DISABLE_RTSP=ON + -DCURL_DISABLE_POP3=ON + -DCURL_DISABLE_IMAP=ON + -DCURL_DISABLE_SMTP=ON + -DCURL_DISABLE_GOPHER=ON + -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local + ${DEP_CMAKE_OPTS} +) + +ExternalProject_Add(dep_wxwidgets + EXCLUDE_FROM_ALL 1 + GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets" + GIT_TAG v3.1.1-patched +# URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.1/wxWidgets-3.1.1.tar.bz2" +# URL_HASH SHA256=c925dfe17e8f8b09eb7ea9bfdcfcc13696a3e14e92750effd839f5e10726159e +# PATCH_COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}\\wxwidgets-pngprefix.h" src\\png\\pngprefix.h + CMAKE_ARGS + -DBUILD_SHARED_LIBS=OFF + -DwxUSE_LIBPNG=builtin + -DwxUSE_ZLIB=builtin + -DwxUSE_OPENGL=ON + -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local + ${DEP_CMAKE_OPTS} +) \ No newline at end of file diff --git a/deps/deps-unix-common.cmake b/deps/deps-unix-common.cmake index e323460a6..6e559d05a 100644 --- a/deps/deps-unix-common.cmake +++ b/deps/deps-unix-common.cmake @@ -1,6 +1,12 @@ # The unix common part expects DEP_CMAKE_OPTS to be set +if (MINGW) + set(TBB_MINGW_WORKAROUND "-flifetime-dse=1") +else () + set(TBB_MINGW_WORKAROUND "") +endif () + ExternalProject_Add(dep_tbb EXCLUDE_FROM_ALL 1 URL "https://github.com/wjakob/tbb/archive/a0dc9bf76d0120f917b641ed095360448cabc85b.tar.gz" @@ -8,6 +14,7 @@ ExternalProject_Add(dep_tbb CMAKE_ARGS -DTBB_BUILD_SHARED=OFF -DTBB_BUILD_TESTS=OFF + -DCMAKE_CXX_FLAGS=${TBB_MINGW_WORKAROUND} -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local ${DEP_CMAKE_OPTS} ) diff --git a/deps/deps-windows.cmake b/deps/deps-windows.cmake index 4162488cd..2c65fc81f 100644 --- a/deps/deps-windows.cmake +++ b/deps/deps-windows.cmake @@ -19,6 +19,10 @@ else () message(FATAL_ERROR "Unsupported MSVC version") endif () +if (CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set(DEP_BOOST_TOOLSET "clang-win") +endif () + if (${DEPS_BITS} EQUAL 32) set(DEP_MSVC_GEN "Visual Studio ${DEP_VS_VER}") # set(DEP_PLATFORM "Win32") diff --git a/resources/icons/edit_layers_all.svg b/resources/icons/edit_layers_all.svg index 4fccc1388..fe4f26c52 100644 --- a/resources/icons/edit_layers_all.svg +++ b/resources/icons/edit_layers_all.svg @@ -3,39 +3,23 @@ - - - - - - - - - - - - - - - - - + + + + + + + diff --git a/resources/icons/edit_layers_some.svg b/resources/icons/edit_layers_some.svg index 7db56b3f0..fb1e7f8b1 100644 --- a/resources/icons/edit_layers_some.svg +++ b/resources/icons/edit_layers_some.svg @@ -2,68 +2,13 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + diff --git a/resources/icons/eye_closed.svg b/resources/icons/eye_closed.svg new file mode 100644 index 000000000..127d53ca3 --- /dev/null +++ b/resources/icons/eye_closed.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/resources/icons/eye_open.svg b/resources/icons/eye_open.svg new file mode 100644 index 000000000..a87cf3a83 --- /dev/null +++ b/resources/icons/eye_open.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/resources/icons/lock_closed_f.svg b/resources/icons/lock_closed_f.svg new file mode 100644 index 000000000..2920ea0aa --- /dev/null +++ b/resources/icons/lock_closed_f.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/resources/icons/lock_open_f.svg b/resources/icons/lock_open_f.svg new file mode 100644 index 000000000..9440d9266 --- /dev/null +++ b/resources/icons/lock_open_f.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/resources/icons/mirroring_off.svg b/resources/icons/mirroring_off.svg index b68748e90..4ed9da748 100644 --- a/resources/icons/mirroring_off.svg +++ b/resources/icons/mirroring_off.svg @@ -4,19 +4,19 @@ viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> - + - + - + - - + + diff --git a/resources/icons/mirroring_on.svg b/resources/icons/mirroring_on.svg index 55ea49516..8481246a3 100644 --- a/resources/icons/mirroring_on.svg +++ b/resources/icons/mirroring_on.svg @@ -2,21 +2,21 @@ - + - + - + - + - - + + diff --git a/resources/localization/PrusaSlicer.pot b/resources/localization/PrusaSlicer.pot index 30c41434f..bdad4a76d 100644 --- a/resources/localization/PrusaSlicer.pot +++ b/resources/localization/PrusaSlicer.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-05-20 15:59+0200\n" +"POT-Creation-Date: 2019-08-06 09:54+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,46 +17,46 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/slic3r/GUI/AboutDialog.cpp:39 src/slic3r/GUI/AboutDialog.cpp:286 +#: src/slic3r/GUI/AboutDialog.cpp:39 src/slic3r/GUI/AboutDialog.cpp:289 msgid "Portions copyright" msgstr "" -#: src/slic3r/GUI/AboutDialog.cpp:122 src/slic3r/GUI/AboutDialog.cpp:251 +#: src/slic3r/GUI/AboutDialog.cpp:125 src/slic3r/GUI/AboutDialog.cpp:254 msgid "Copyright" msgstr "" #. TRN "Slic3r _is licensed under the_ License" -#: src/slic3r/GUI/AboutDialog.cpp:124 +#: src/slic3r/GUI/AboutDialog.cpp:127 msgid "" "License agreements of all following programs (libraries) are part of " "application license agreement" msgstr "" -#: src/slic3r/GUI/AboutDialog.cpp:194 +#: src/slic3r/GUI/AboutDialog.cpp:197 #, possible-c-format msgid "About %s" msgstr "" -#: src/slic3r/GUI/AboutDialog.cpp:226 src/slic3r/GUI/MainFrame.cpp:59 +#: src/slic3r/GUI/AboutDialog.cpp:229 src/slic3r/GUI/MainFrame.cpp:60 msgid "Version" msgstr "" #. TRN "Slic3r _is licensed under the_ License" -#: src/slic3r/GUI/AboutDialog.cpp:253 +#: src/slic3r/GUI/AboutDialog.cpp:256 msgid "is licensed under the" msgstr "" -#: src/slic3r/GUI/AboutDialog.cpp:254 +#: src/slic3r/GUI/AboutDialog.cpp:257 msgid "GNU Affero General Public License, version 3" msgstr "" -#: src/slic3r/GUI/AboutDialog.cpp:255 +#: src/slic3r/GUI/AboutDialog.cpp:258 msgid "" "PrusaSlicer is based on Slic3r by Alessandro Ranellucci and the RepRap " "community." msgstr "" -#: src/slic3r/GUI/AboutDialog.cpp:256 +#: src/slic3r/GUI/AboutDialog.cpp:259 msgid "" "Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, " "Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Vojtech Bubnik and " @@ -64,8 +64,9 @@ msgid "" msgstr "" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:92 -#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:408 -msgid "Copying of the temporary G-code to the output G-code failed" +msgid "" +"Copying of the temporary G-code to the output G-code failed. Maybe the SD " +"card is write locked?" msgstr "" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:93 @@ -86,115 +87,152 @@ msgstr "" msgid "Masked SLA file exported to %1%" msgstr "" +#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:408 +msgid "Copying of the temporary G-code to the output G-code failed" +msgstr "" + #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:417 msgid "Scheduling upload to `%1%`. See Window -> Print Host Upload Queue" msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:60 +#: src/slic3r/GUI/BedShapeDialog.cpp:65 msgid "Shape" msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:68 +#: src/slic3r/GUI/BedShapeDialog.cpp:72 msgid "Rectangular" msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:72 -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:232 src/slic3r/GUI/Plater.cpp:136 -#: src/slic3r/GUI/Tab.cpp:2294 +#: src/slic3r/GUI/BedShapeDialog.cpp:76 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:391 src/slic3r/GUI/Plater.cpp:145 +#: src/slic3r/GUI/Tab.cpp:2469 msgid "Size" msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:73 +#: src/slic3r/GUI/BedShapeDialog.cpp:77 msgid "Size in X and Y of the rectangular plate." msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:79 +#: src/slic3r/GUI/BedShapeDialog.cpp:83 msgid "Origin" msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:80 +#: src/slic3r/GUI/BedShapeDialog.cpp:84 msgid "" "Distance of the 0,0 G-code coordinate from the front left corner of the " "rectangle." msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:84 +#: src/slic3r/GUI/BedShapeDialog.cpp:88 msgid "Circular" msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:87 src/slic3r/GUI/ConfigWizard.cpp:118 -#: src/slic3r/GUI/ConfigWizard.cpp:565 src/slic3r/GUI/ConfigWizard.cpp:579 -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:229 -#: src/slic3r/GUI/WipeTowerDialog.cpp:84 src/libslic3r/PrintConfig.cpp:60 -#: src/libslic3r/PrintConfig.cpp:67 src/libslic3r/PrintConfig.cpp:76 -#: src/libslic3r/PrintConfig.cpp:211 src/libslic3r/PrintConfig.cpp:286 -#: src/libslic3r/PrintConfig.cpp:294 src/libslic3r/PrintConfig.cpp:344 -#: src/libslic3r/PrintConfig.cpp:354 src/libslic3r/PrintConfig.cpp:474 -#: src/libslic3r/PrintConfig.cpp:485 src/libslic3r/PrintConfig.cpp:503 -#: src/libslic3r/PrintConfig.cpp:681 src/libslic3r/PrintConfig.cpp:1201 -#: src/libslic3r/PrintConfig.cpp:1262 src/libslic3r/PrintConfig.cpp:1280 -#: src/libslic3r/PrintConfig.cpp:1298 src/libslic3r/PrintConfig.cpp:1350 -#: src/libslic3r/PrintConfig.cpp:1360 src/libslic3r/PrintConfig.cpp:1481 -#: src/libslic3r/PrintConfig.cpp:1489 src/libslic3r/PrintConfig.cpp:1530 -#: src/libslic3r/PrintConfig.cpp:1538 src/libslic3r/PrintConfig.cpp:1548 -#: src/libslic3r/PrintConfig.cpp:1556 src/libslic3r/PrintConfig.cpp:1564 -#: src/libslic3r/PrintConfig.cpp:1647 src/libslic3r/PrintConfig.cpp:1863 -#: src/libslic3r/PrintConfig.cpp:1933 src/libslic3r/PrintConfig.cpp:1967 -#: src/libslic3r/PrintConfig.cpp:2160 src/libslic3r/PrintConfig.cpp:2167 -#: src/libslic3r/PrintConfig.cpp:2174 src/libslic3r/PrintConfig.cpp:2204 -#: src/libslic3r/PrintConfig.cpp:2214 src/libslic3r/PrintConfig.cpp:2224 -#: src/libslic3r/PrintConfig.cpp:2332 src/libslic3r/PrintConfig.cpp:2407 -#: src/libslic3r/PrintConfig.cpp:2416 src/libslic3r/PrintConfig.cpp:2425 -#: src/libslic3r/PrintConfig.cpp:2435 src/libslic3r/PrintConfig.cpp:2479 -#: src/libslic3r/PrintConfig.cpp:2489 src/libslic3r/PrintConfig.cpp:2508 -#: src/libslic3r/PrintConfig.cpp:2518 src/libslic3r/PrintConfig.cpp:2527 -#: src/libslic3r/PrintConfig.cpp:2545 src/libslic3r/PrintConfig.cpp:2560 -#: src/libslic3r/PrintConfig.cpp:2574 src/libslic3r/PrintConfig.cpp:2587 -#: src/libslic3r/PrintConfig.cpp:2597 +#: src/slic3r/GUI/BedShapeDialog.cpp:91 src/slic3r/GUI/ConfigWizard.cpp:118 +#: src/slic3r/GUI/ConfigWizard.cpp:571 src/slic3r/GUI/ConfigWizard.cpp:585 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:388 +#: src/slic3r/GUI/WipeTowerDialog.cpp:84 src/slic3r/GUI/wxExtensions.cpp:486 +#: src/libslic3r/PrintConfig.cpp:70 src/libslic3r/PrintConfig.cpp:77 +#: src/libslic3r/PrintConfig.cpp:86 src/libslic3r/PrintConfig.cpp:220 +#: src/libslic3r/PrintConfig.cpp:295 src/libslic3r/PrintConfig.cpp:303 +#: src/libslic3r/PrintConfig.cpp:353 src/libslic3r/PrintConfig.cpp:363 +#: src/libslic3r/PrintConfig.cpp:488 src/libslic3r/PrintConfig.cpp:499 +#: src/libslic3r/PrintConfig.cpp:517 src/libslic3r/PrintConfig.cpp:695 +#: src/libslic3r/PrintConfig.cpp:1215 src/libslic3r/PrintConfig.cpp:1276 +#: src/libslic3r/PrintConfig.cpp:1294 src/libslic3r/PrintConfig.cpp:1312 +#: src/libslic3r/PrintConfig.cpp:1364 src/libslic3r/PrintConfig.cpp:1374 +#: src/libslic3r/PrintConfig.cpp:1495 src/libslic3r/PrintConfig.cpp:1503 +#: src/libslic3r/PrintConfig.cpp:1544 src/libslic3r/PrintConfig.cpp:1552 +#: src/libslic3r/PrintConfig.cpp:1562 src/libslic3r/PrintConfig.cpp:1570 +#: src/libslic3r/PrintConfig.cpp:1578 src/libslic3r/PrintConfig.cpp:1661 +#: src/libslic3r/PrintConfig.cpp:1878 src/libslic3r/PrintConfig.cpp:1948 +#: src/libslic3r/PrintConfig.cpp:1982 src/libslic3r/PrintConfig.cpp:2176 +#: src/libslic3r/PrintConfig.cpp:2183 src/libslic3r/PrintConfig.cpp:2190 +#: src/libslic3r/PrintConfig.cpp:2220 src/libslic3r/PrintConfig.cpp:2230 +#: src/libslic3r/PrintConfig.cpp:2240 src/libslic3r/PrintConfig.cpp:2403 +#: src/libslic3r/PrintConfig.cpp:2478 src/libslic3r/PrintConfig.cpp:2487 +#: src/libslic3r/PrintConfig.cpp:2496 src/libslic3r/PrintConfig.cpp:2506 +#: src/libslic3r/PrintConfig.cpp:2550 src/libslic3r/PrintConfig.cpp:2560 +#: src/libslic3r/PrintConfig.cpp:2572 src/libslic3r/PrintConfig.cpp:2592 +#: src/libslic3r/PrintConfig.cpp:2602 src/libslic3r/PrintConfig.cpp:2613 +#: src/libslic3r/PrintConfig.cpp:2631 src/libslic3r/PrintConfig.cpp:2646 +#: src/libslic3r/PrintConfig.cpp:2660 src/libslic3r/PrintConfig.cpp:2673 +#: src/libslic3r/PrintConfig.cpp:2683 src/libslic3r/PrintConfig.cpp:2704 +#: src/libslic3r/PrintConfig.cpp:2715 src/libslic3r/PrintConfig.cpp:2725 +#: src/libslic3r/PrintConfig.cpp:2735 msgid "mm" msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:88 src/libslic3r/PrintConfig.cpp:678 +#: src/slic3r/GUI/BedShapeDialog.cpp:92 src/libslic3r/PrintConfig.cpp:692 msgid "Diameter" msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:89 +#: src/slic3r/GUI/BedShapeDialog.cpp:93 msgid "" "Diameter of the print bed. It is assumed that origin (0,0) is located in the " "center." msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:93 src/slic3r/GUI/GUI_Preview.cpp:245 +#: src/slic3r/GUI/BedShapeDialog.cpp:97 src/slic3r/GUI/GUI_Preview.cpp:246 #: src/libslic3r/GCode/PreviewData.cpp:175 msgid "Custom" msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:97 +#: src/slic3r/GUI/BedShapeDialog.cpp:101 msgid "Load shape from STL..." msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:143 +#: src/slic3r/GUI/BedShapeDialog.cpp:154 msgid "Settings" msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:316 -msgid "Choose a file to import bed shape from (STL/OBJ/AMF/3MF/PRUSA):" +#: src/slic3r/GUI/BedShapeDialog.cpp:171 +msgid "Texture" msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:333 src/slic3r/GUI/GUI_ObjectList.cpp:1442 -msgid "Error!" +#: src/slic3r/GUI/BedShapeDialog.cpp:181 src/slic3r/GUI/BedShapeDialog.cpp:249 +msgid "Load..." msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:342 +#: src/slic3r/GUI/BedShapeDialog.cpp:189 src/slic3r/GUI/BedShapeDialog.cpp:257 +#: src/slic3r/GUI/Tab.cpp:3204 +msgid "Remove" +msgstr "" + +#: src/slic3r/GUI/BedShapeDialog.cpp:239 +msgid "Model" +msgstr "" + +#: src/slic3r/GUI/BedShapeDialog.cpp:464 +msgid "Choose an STL file to import bed shape from:" +msgstr "" + +#: src/slic3r/GUI/BedShapeDialog.cpp:471 src/slic3r/GUI/BedShapeDialog.cpp:520 +#: src/slic3r/GUI/BedShapeDialog.cpp:543 +msgid "Invalid file format." +msgstr "" + +#: src/slic3r/GUI/BedShapeDialog.cpp:482 +msgid "Error! Invalid model" +msgstr "" + +#: src/slic3r/GUI/BedShapeDialog.cpp:490 msgid "The selected file contains no geometry." msgstr "" -#: src/slic3r/GUI/BedShapeDialog.cpp:346 +#: src/slic3r/GUI/BedShapeDialog.cpp:494 msgid "" "The selected file contains several disjoint areas. This is not supported." msgstr "" -#: src/slic3r/GUI/BedShapeDialog.hpp:45 src/slic3r/GUI/ConfigWizard.cpp:530 +#: src/slic3r/GUI/BedShapeDialog.cpp:509 +msgid "Choose a file to import bed texture from (PNG/SVG):" +msgstr "" + +#: src/slic3r/GUI/BedShapeDialog.cpp:532 +msgid "Choose an STL file to import bed model from:" +msgstr "" + +#: src/slic3r/GUI/BedShapeDialog.hpp:59 src/slic3r/GUI/ConfigWizard.cpp:530 msgid "Bed Shape" msgstr "" @@ -268,7 +306,7 @@ msgstr "" msgid "slic3r version" msgstr "" -#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:46 src/slic3r/GUI/Preset.cpp:1282 +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:46 src/slic3r/GUI/Preset.cpp:1307 msgid "print" msgstr "" @@ -276,11 +314,11 @@ msgstr "" msgid "filaments" msgstr "" -#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:48 src/slic3r/GUI/Preset.cpp:1286 +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:48 src/slic3r/GUI/Preset.cpp:1311 msgid "printer" msgstr "" -#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:52 src/slic3r/GUI/Tab.cpp:934 +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:52 src/slic3r/GUI/Tab.cpp:939 msgid "vendor" msgstr "" @@ -329,11 +367,11 @@ msgstr "" msgid "All standard" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:189 src/slic3r/GUI/Tab.cpp:3038 +#: src/slic3r/GUI/ConfigWizard.cpp:189 src/slic3r/GUI/Tab.cpp:3254 msgid "All" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:190 src/slic3r/GUI/Plater.cpp:432 +#: src/slic3r/GUI/ConfigWizard.cpp:190 src/slic3r/GUI/Plater.cpp:470 #: src/libslic3r/GCode/PreviewData.cpp:162 msgid "None" msgstr "" @@ -352,7 +390,7 @@ msgstr "" msgid "Welcome" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:304 src/slic3r/GUI/GUI_App.cpp:713 +#: src/slic3r/GUI/ConfigWizard.cpp:304 src/slic3r/GUI/GUI_App.cpp:747 #, possible-c-format msgid "Run %s" msgstr "" @@ -399,7 +437,7 @@ msgstr "" msgid "Updates" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:415 src/slic3r/GUI/Preferences.cpp:61 +#: src/slic3r/GUI/ConfigWizard.cpp:415 src/slic3r/GUI/Preferences.cpp:69 msgid "Check for application updates" msgstr "" @@ -412,7 +450,7 @@ msgid "" "notification mechanisms, no automatic installation is done." msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:425 src/slic3r/GUI/Preferences.cpp:69 +#: src/slic3r/GUI/ConfigWizard.cpp:425 src/slic3r/GUI/Preferences.cpp:77 msgid "Update built-in Presets automatically" msgstr "" @@ -450,7 +488,7 @@ msgstr "" msgid "Firmware Type" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:492 src/slic3r/GUI/Tab.cpp:1957 +#: src/slic3r/GUI/ConfigWizard.cpp:492 src/slic3r/GUI/Tab.cpp:2100 msgid "Firmware" msgstr "" @@ -466,180 +504,183 @@ msgstr "" msgid "Set the shape of your printer's bed." msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:547 +#: src/slic3r/GUI/ConfigWizard.cpp:553 msgid "Filament and Nozzle Diameters" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:547 +#: src/slic3r/GUI/ConfigWizard.cpp:553 msgid "Print Diameters" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:561 +#: src/slic3r/GUI/ConfigWizard.cpp:567 msgid "Enter the diameter of your printer's hot end nozzle." msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:564 +#: src/slic3r/GUI/ConfigWizard.cpp:570 msgid "Nozzle Diameter:" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:574 +#: src/slic3r/GUI/ConfigWizard.cpp:580 msgid "Enter the diameter of your filament." msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:575 +#: src/slic3r/GUI/ConfigWizard.cpp:581 msgid "" "Good precision is required, so use a caliper and do multiple measurements " "along the filament, then compute the average." msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:578 +#: src/slic3r/GUI/ConfigWizard.cpp:584 msgid "Filament Diameter:" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:612 +#: src/slic3r/GUI/ConfigWizard.cpp:618 msgid "Extruder and Bed Temperatures" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:612 +#: src/slic3r/GUI/ConfigWizard.cpp:618 msgid "Temperatures" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:628 +#: src/slic3r/GUI/ConfigWizard.cpp:634 msgid "Enter the temperature needed for extruding your filament." msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:629 +#: src/slic3r/GUI/ConfigWizard.cpp:635 msgid "A rule of thumb is 160 to 230 °C for PLA, and 215 to 250 °C for ABS." msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:632 +#: src/slic3r/GUI/ConfigWizard.cpp:638 msgid "Extrusion Temperature:" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:633 src/slic3r/GUI/ConfigWizard.cpp:647 +#: src/slic3r/GUI/ConfigWizard.cpp:639 src/slic3r/GUI/ConfigWizard.cpp:653 msgid "°C" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:642 +#: src/slic3r/GUI/ConfigWizard.cpp:648 msgid "" "Enter the bed temperature needed for getting your filament to stick to your " "heated bed." msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:643 +#: src/slic3r/GUI/ConfigWizard.cpp:649 msgid "" "A rule of thumb is 60 °C for PLA and 110 °C for ABS. Leave zero if you have " "no heated bed." msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:646 +#: src/slic3r/GUI/ConfigWizard.cpp:652 msgid "Bed Temperature:" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:1109 +#: src/slic3r/GUI/ConfigWizard.cpp:1115 msgid "Select all standard printers" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:1112 +#: src/slic3r/GUI/ConfigWizard.cpp:1118 msgid "< &Back" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:1113 +#: src/slic3r/GUI/ConfigWizard.cpp:1119 msgid "&Next >" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:1114 +#: src/slic3r/GUI/ConfigWizard.cpp:1120 msgid "&Finish" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:1115 src/slic3r/GUI/FirmwareDialog.cpp:147 -#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:37 -#: src/slic3r/GUI/ProgressStatusBar.cpp:28 +#: src/slic3r/GUI/ConfigWizard.cpp:1121 src/slic3r/GUI/FirmwareDialog.cpp:151 +#: src/slic3r/GUI/ProgressStatusBar.cpp:27 msgid "Cancel" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:1129 +#: src/slic3r/GUI/ConfigWizard.cpp:1135 msgid "Prusa FFF Technology Printers" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:1132 +#: src/slic3r/GUI/ConfigWizard.cpp:1138 msgid "Prusa MSLA Technology Printers" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:1201 +#: src/slic3r/GUI/ConfigWizard.cpp:1207 msgid "Configuration Assistant" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:1202 +#: src/slic3r/GUI/ConfigWizard.cpp:1208 msgid "Configuration &Assistant" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:1204 +#: src/slic3r/GUI/ConfigWizard.cpp:1210 msgid "Configuration Wizard" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:1205 +#: src/slic3r/GUI/ConfigWizard.cpp:1211 msgid "Configuration &Wizard" msgstr "" -#: src/slic3r/GUI/Field.cpp:117 +#: src/slic3r/GUI/Field.cpp:125 msgid "default value" msgstr "" -#: src/slic3r/GUI/Field.cpp:120 +#: src/slic3r/GUI/Field.cpp:128 msgid "parameter name" msgstr "" -#: src/slic3r/GUI/Field.cpp:148 +#: src/slic3r/GUI/Field.cpp:139 +msgid "N/A" +msgstr "" + +#: src/slic3r/GUI/Field.cpp:158 #, possible-c-format msgid "%s doesn't support percentage" msgstr "" -#: src/slic3r/GUI/Field.cpp:162 src/slic3r/GUI/Field.cpp:185 +#: src/slic3r/GUI/Field.cpp:174 src/slic3r/GUI/Field.cpp:197 msgid "Invalid numeric input." msgstr "" -#: src/slic3r/GUI/Field.cpp:167 +#: src/slic3r/GUI/Field.cpp:179 msgid "Input value is out of range" msgstr "" -#: src/slic3r/GUI/Field.cpp:193 +#: src/slic3r/GUI/Field.cpp:206 #, possible-c-format msgid "" -"Do you mean %d%% instead of %d %s?\n" -"Select YES if you want to change this value to %d%%, \n" -"or NO if you are sure that %d %s is a correct value." +"Do you mean %s%% instead of %s %s?\n" +"Select YES if you want to change this value to %s%%, \n" +"or NO if you are sure that %s %s is a correct value." msgstr "" -#: src/slic3r/GUI/Field.cpp:196 +#: src/slic3r/GUI/Field.cpp:209 msgid "Parameter validation" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:146 +#: src/slic3r/GUI/FirmwareDialog.cpp:150 msgid "Flash!" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:148 +#: src/slic3r/GUI/FirmwareDialog.cpp:152 msgid "Flashing in progress. Please do not disconnect the printer!" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:192 +#: src/slic3r/GUI/FirmwareDialog.cpp:199 msgid "Flashing failed" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:273 +#: src/slic3r/GUI/FirmwareDialog.cpp:282 msgid "Flashing succeeded!" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:274 +#: src/slic3r/GUI/FirmwareDialog.cpp:283 msgid "Flashing failed. Please see the avrdude log below." msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:275 +#: src/slic3r/GUI/FirmwareDialog.cpp:284 msgid "Flashing cancelled." msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:313 +#: src/slic3r/GUI/FirmwareDialog.cpp:332 #, possible-c-format msgid "" "This firmware hex file does not match the printer model.\n" @@ -650,13 +691,13 @@ msgid "" "Please only continue if you are sure this is the right thing to do." msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:400 src/slic3r/GUI/FirmwareDialog.cpp:436 +#: src/slic3r/GUI/FirmwareDialog.cpp:419 src/slic3r/GUI/FirmwareDialog.cpp:454 #, possible-c-format msgid "" "Multiple %s devices found. Please only connect one at a time for flashing." msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:417 +#: src/slic3r/GUI/FirmwareDialog.cpp:436 #, possible-c-format msgid "" "The %s device was not found.\n" @@ -664,947 +705,1198 @@ msgid "" "connector ..." msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:530 +#: src/slic3r/GUI/FirmwareDialog.cpp:548 #, possible-c-format msgid "The %s device could not have been found" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:608 +#: src/slic3r/GUI/FirmwareDialog.cpp:645 #, possible-c-format msgid "Error accessing port at %s: %s" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:610 +#: src/slic3r/GUI/FirmwareDialog.cpp:647 #, possible-c-format msgid "Error: %s" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:740 +#: src/slic3r/GUI/FirmwareDialog.cpp:777 msgid "Firmware flasher" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:765 +#: src/slic3r/GUI/FirmwareDialog.cpp:802 msgid "Firmware image:" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:768 src/slic3r/GUI/Tab.cpp:1718 -#: src/slic3r/GUI/Tab.cpp:1774 +#: src/slic3r/GUI/FirmwareDialog.cpp:805 src/slic3r/GUI/Tab.cpp:1824 +#: src/slic3r/GUI/Tab.cpp:1880 msgid "Browse" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:770 +#: src/slic3r/GUI/FirmwareDialog.cpp:807 msgid "Serial port:" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:772 +#: src/slic3r/GUI/FirmwareDialog.cpp:809 msgid "Autodetected" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:773 +#: src/slic3r/GUI/FirmwareDialog.cpp:810 msgid "Rescan" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:780 +#: src/slic3r/GUI/FirmwareDialog.cpp:817 msgid "Progress:" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:783 +#: src/slic3r/GUI/FirmwareDialog.cpp:820 msgid "Status:" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:784 +#: src/slic3r/GUI/FirmwareDialog.cpp:821 msgid "Ready" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:804 +#: src/slic3r/GUI/FirmwareDialog.cpp:841 msgid "Advanced: Output log" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:815 +#: src/slic3r/GUI/FirmwareDialog.cpp:852 #: src/slic3r/GUI/PrintHostDialogs.cpp:161 msgid "Close" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:863 +#: src/slic3r/GUI/FirmwareDialog.cpp:903 msgid "" "Are you sure you want to cancel firmware flashing?\n" "This could leave your printer in an unusable state!" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:864 +#: src/slic3r/GUI/FirmwareDialog.cpp:904 msgid "Confirmation" msgstr "" -#: src/slic3r/GUI/FirmwareDialog.cpp:867 +#: src/slic3r/GUI/FirmwareDialog.cpp:907 msgid "Cancelling..." msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:720 +#: src/slic3r/GUI/GLCanvas3D.cpp:526 +msgid "Layers heights" +msgstr "" + +#: src/slic3r/GUI/GLCanvas3D.cpp:623 msgid "An object outside the print area was detected" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:721 +#: src/slic3r/GUI/GLCanvas3D.cpp:624 msgid "A toolpath outside the print area was detected" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:722 +#: src/slic3r/GUI/GLCanvas3D.cpp:625 msgid "SLA supports outside the print area were detected" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:723 +#: src/slic3r/GUI/GLCanvas3D.cpp:626 msgid "Some objects are not visible when editing supports" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:725 +#: src/slic3r/GUI/GLCanvas3D.cpp:628 msgid "" "An object outside the print area was detected\n" "Resolve the current problem to continue slicing" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:1694 -msgid "Last frame" +#: src/slic3r/GUI/GLCanvas3D.cpp:1711 +msgid "Mirror Object" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:1698 -msgid "ms" +#: src/slic3r/GUI/GLCanvas3D.cpp:2872 +msgid "Move Object" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:3434 +#: src/slic3r/GUI/GLCanvas3D.cpp:3389 src/slic3r/GUI/GLCanvas3D.cpp:3609 +#: src/slic3r/GUI/MainFrame.cpp:559 +msgid "Undo" +msgstr "" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3389 src/slic3r/GUI/GLCanvas3D.cpp:3639 +#: src/slic3r/GUI/MainFrame.cpp:562 +msgid "Redo" +msgstr "" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3395 +#, possible-c-format +msgid "%s Stack" +msgstr "" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3413 +#, possible-c-format +msgid "%s %d Action" +msgstr "" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3460 msgid "Add..." msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:3444 src/slic3r/GUI/GUI_ObjectList.cpp:1277 -#: src/slic3r/GUI/Plater.cpp:2994 src/slic3r/GUI/Plater.cpp:3013 -#: src/slic3r/GUI/Tab.cpp:2988 +#: src/slic3r/GUI/GLCanvas3D.cpp:3468 src/slic3r/GUI/GUI_ObjectList.cpp:1434 +#: src/slic3r/GUI/Plater.cpp:3467 src/slic3r/GUI/Plater.cpp:3486 +#: src/slic3r/GUI/Tab.cpp:3204 msgid "Delete" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:3455 src/slic3r/GUI/Plater.cpp:3375 +#: src/slic3r/GUI/GLCanvas3D.cpp:3477 src/slic3r/GUI/Plater.cpp:4075 msgid "Delete all" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:3466 src/slic3r/GUI/KBShortcutsDialog.cpp:134 +#: src/slic3r/GUI/GLCanvas3D.cpp:3486 src/slic3r/GUI/KBShortcutsDialog.cpp:134 +#: src/slic3r/GUI/Plater.cpp:2636 msgid "Arrange" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:3480 +#: src/slic3r/GUI/GLCanvas3D.cpp:3486 +msgid "Arrange selection" +msgstr "" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3498 msgid "Copy" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:3491 +#: src/slic3r/GUI/GLCanvas3D.cpp:3507 msgid "Paste" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:3505 +#: src/slic3r/GUI/GLCanvas3D.cpp:3519 msgid "Add instance" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:3517 +#: src/slic3r/GUI/GLCanvas3D.cpp:3530 msgid "Remove instance" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:3532 +#: src/slic3r/GUI/GLCanvas3D.cpp:3543 msgid "Split to objects" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:3544 src/slic3r/GUI/GUI_ObjectList.cpp:1129 +#: src/slic3r/GUI/GLCanvas3D.cpp:3553 src/slic3r/GUI/GUI_ObjectList.cpp:1280 msgid "Split to parts" msgstr "" -#: src/slic3r/GUI/GLCanvas3D.cpp:3559 +#: src/slic3r/GUI/GLCanvas3D.cpp:3566 msgid "Layers editing" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:35 -#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:195 -msgid "Rotate lower part upwards" +#: src/slic3r/GUI/GLCanvas3D.cpp:5623 +msgid "Selection-Add from rectangle" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:36 -#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:198 -msgid "Perform cut" +#: src/slic3r/GUI/GLCanvas3D.cpp:5642 +msgid "Selection-Remove from rectangle" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:43 -msgid "Cut object:" -msgstr "" - -#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:88 -#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:188 src/libslic3r/PrintConfig.cpp:3049 +#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:40 +#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:144 src/libslic3r/PrintConfig.cpp:3176 msgid "Cut" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:193 +#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:149 msgid "Keep upper part" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:194 +#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:150 msgid "Keep lower part" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp:32 +#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:151 +msgid "Rotate lower part upwards" +msgstr "" + +#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:154 +msgid "Perform cut" +msgstr "" + +#: src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp:45 msgid "Place on face" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoMove.cpp:52 +#: src/slic3r/GUI/Gizmos/GLGizmoMove.cpp:48 msgid "Move" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoMove.cpp:178 +#: src/slic3r/GUI/Gizmos/GLGizmoMove.cpp:177 msgid "Position (mm)" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoMove.cpp:178 +#: src/slic3r/GUI/Gizmos/GLGizmoMove.cpp:177 msgid "Displacement (mm)" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp:458 -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:305 -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:324 -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:342 -#: src/libslic3r/PrintConfig.cpp:3098 +#: src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp:449 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:466 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:485 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:503 +#: src/libslic3r/PrintConfig.cpp:3225 msgid "Rotate" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp:491 +#: src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp:482 msgid "Rotation (deg)" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoScale.cpp:53 -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:231 -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:325 -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:343 -#: src/libslic3r/PrintConfig.cpp:3113 +#: src/slic3r/GUI/Gizmos/GLGizmoScale.cpp:47 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:390 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:486 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:504 +#: src/libslic3r/PrintConfig.cpp:3240 msgid "Scale" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoScale.cpp:291 +#: src/slic3r/GUI/Gizmos/GLGizmoScale.cpp:292 msgid "Scale (%)" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:840 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:44 msgid "Head diameter" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:856 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:45 msgid "Lock supports under new islands" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:860 -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1249 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:46 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1427 msgid "Remove selected points" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:864 -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:921 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:47 msgid "Remove all points" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:869 -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1252 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:48 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1430 msgid "Apply changes" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:874 -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1253 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:49 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1431 msgid "Discard changes" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:881 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:50 msgid "Minimal points distance" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:882 -#: src/libslic3r/PrintConfig.cpp:2534 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:51 +#: src/libslic3r/PrintConfig.cpp:2620 msgid "Support points density" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:911 -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1255 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:52 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1433 msgid "Auto-generate points" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:917 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:53 msgid "Manual editing" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:934 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:54 msgid "Clipping of view" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:935 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:55 msgid "Reset direction" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1007 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:531 +msgid "Add support point" +msgstr "" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:720 +msgid "Delete support point" +msgstr "" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:925 +msgid "Change point head diameter" +msgstr "" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:991 +msgid "Support parameter change" +msgstr "" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1099 msgid "SLA Support Points" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1034 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1138 msgid "Do you want to save your manually edited support points?" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1035 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1139 msgid "Save changes?" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1178 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1183 +msgid "Move support point" +msgstr "" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1282 +msgid "Support points edit" +msgstr "" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1333 msgid "" "Autogeneration will erase all manually edited points.\n" "\n" "Are you sure you want to do it?\n" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1180 src/slic3r/GUI/GUI.cpp:283 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1335 src/slic3r/GUI/GUI.cpp:289 #: src/slic3r/GUI/WipeTowerDialog.cpp:44 src/slic3r/GUI/WipeTowerDialog.cpp:328 msgid "Warning" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1212 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1338 +msgid "Autogenerate support points" +msgstr "" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1390 msgid "SLA gizmo keyboard shortcuts" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1223 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1401 msgid "Note: some shortcuts work in (non)editing mode only." msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1241 -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1244 -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1245 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1419 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1422 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1423 msgid "Left click" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1241 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1419 msgid "Add point" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1242 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1420 msgid "Right click" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1242 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1420 msgid "Remove point" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1243 -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1246 -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1247 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1421 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1424 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1425 msgid "Drag" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1243 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1421 msgid "Move point" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1244 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1422 msgid "Add point to selection" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1245 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1423 msgid "Remove point from selection" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1246 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1424 msgid "Select by rectangle" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1247 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1425 msgid "Deselect by rectangle" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1248 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1426 msgid "Select all points" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1250 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1428 msgid "Mouse wheel" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1250 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1428 msgid "Move clipping plane" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1251 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1429 msgid "Reset clipping plane" msgstr "" -#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1254 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1432 msgid "Switch to editing mode" msgstr "" -#: src/slic3r/GUI/GUI.cpp:142 src/slic3r/GUI/Tab.cpp:2847 +#: src/slic3r/GUI/GUI.cpp:141 src/slic3r/GUI/Tab.cpp:3063 msgid "It's impossible to print multi-part object(s) with SLA technology." msgstr "" -#: src/slic3r/GUI/GUI.cpp:143 +#: src/slic3r/GUI/GUI.cpp:142 msgid "Please check and fix your object list." msgstr "" -#: src/slic3r/GUI/GUI.cpp:144 src/slic3r/GUI/Tab.cpp:2849 +#: src/slic3r/GUI/GUI.cpp:143 src/slic3r/GUI/Plater.cpp:2213 +#: src/slic3r/GUI/Tab.cpp:3065 msgid "Attention!" msgstr "" -#: src/slic3r/GUI/GUI.cpp:277 +#: src/slic3r/GUI/GUI.cpp:283 msgid "Notice" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:401 +#: src/slic3r/GUI/GUI_App.cpp:435 msgid "Changing of an application language" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:409 src/slic3r/GUI/GUI_App.cpp:418 +#: src/slic3r/GUI/GUI_App.cpp:443 src/slic3r/GUI/GUI_App.cpp:452 msgid "Recreating" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:422 +#: src/slic3r/GUI/GUI_App.cpp:456 msgid "Loading of current presets" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:430 +#: src/slic3r/GUI/GUI_App.cpp:464 msgid "Loading of a mode view" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:510 +#: src/slic3r/GUI/GUI_App.cpp:544 msgid "Choose one file (3MF/AMF):" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:522 +#: src/slic3r/GUI/GUI_App.cpp:556 msgid "Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:564 +#: src/slic3r/GUI/GUI_App.cpp:598 msgid "Select the language" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:565 +#: src/slic3r/GUI/GUI_App.cpp:599 msgid "Language" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:716 +#: src/slic3r/GUI/GUI_App.cpp:750 msgid "&Configuration Snapshots" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:716 +#: src/slic3r/GUI/GUI_App.cpp:750 msgid "Inspect / activate configuration snapshots" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:717 +#: src/slic3r/GUI/GUI_App.cpp:751 msgid "Take Configuration &Snapshot" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:717 +#: src/slic3r/GUI/GUI_App.cpp:751 msgid "Capture a configuration snapshot" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:720 +#: src/slic3r/GUI/GUI_App.cpp:754 msgid "&Preferences" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:726 +#: src/slic3r/GUI/GUI_App.cpp:760 msgid "Application preferences" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:729 src/slic3r/GUI/wxExtensions.cpp:2555 +#: src/slic3r/GUI/GUI_App.cpp:763 src/slic3r/GUI/wxExtensions.cpp:2882 msgid "Simple" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:729 +#: src/slic3r/GUI/GUI_App.cpp:763 msgid "Simple View Mode" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:730 src/slic3r/GUI/GUI_ObjectList.cpp:85 -#: src/slic3r/GUI/GUI_ObjectList.cpp:541 src/slic3r/GUI/Tab.cpp:1032 -#: src/slic3r/GUI/Tab.cpp:1047 src/slic3r/GUI/Tab.cpp:1145 -#: src/slic3r/GUI/Tab.cpp:1148 src/slic3r/GUI/Tab.cpp:1551 -#: src/slic3r/GUI/Tab.cpp:1977 src/slic3r/GUI/Tab.cpp:3492 -#: src/slic3r/GUI/wxExtensions.cpp:2556 src/libslic3r/PrintConfig.cpp:73 -#: src/libslic3r/PrintConfig.cpp:188 src/libslic3r/PrintConfig.cpp:351 -#: src/libslic3r/PrintConfig.cpp:999 src/libslic3r/PrintConfig.cpp:2210 +#: src/slic3r/GUI/GUI_App.cpp:764 src/slic3r/GUI/GUI_ObjectList.cpp:93 +#: src/slic3r/GUI/GUI_ObjectList.cpp:567 src/slic3r/GUI/Tab.cpp:1037 +#: src/slic3r/GUI/Tab.cpp:1052 src/slic3r/GUI/Tab.cpp:1150 +#: src/slic3r/GUI/Tab.cpp:1153 src/slic3r/GUI/Tab.cpp:1649 +#: src/slic3r/GUI/Tab.cpp:2120 src/slic3r/GUI/Tab.cpp:3699 +#: src/slic3r/GUI/wxExtensions.cpp:2883 src/libslic3r/PrintConfig.cpp:83 +#: src/libslic3r/PrintConfig.cpp:197 src/libslic3r/PrintConfig.cpp:360 +#: src/libslic3r/PrintConfig.cpp:1013 src/libslic3r/PrintConfig.cpp:2226 msgid "Advanced" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:730 +#: src/slic3r/GUI/GUI_App.cpp:764 msgid "Advanced View Mode" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:731 src/slic3r/GUI/wxExtensions.cpp:2557 +#: src/slic3r/GUI/GUI_App.cpp:765 src/slic3r/GUI/wxExtensions.cpp:2884 msgid "Expert" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:731 +#: src/slic3r/GUI/GUI_App.cpp:765 msgid "Expert View Mode" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:736 +#: src/slic3r/GUI/GUI_App.cpp:770 msgid "Mode" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:736 +#: src/slic3r/GUI/GUI_App.cpp:770 #, possible-c-format msgid "%s View Mode" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:738 +#: src/slic3r/GUI/GUI_App.cpp:772 msgid "Change Application &Language" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:740 +#: src/slic3r/GUI/GUI_App.cpp:774 msgid "Flash printer &firmware" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:740 +#: src/slic3r/GUI/GUI_App.cpp:774 msgid "Upload a firmware image into an Arduino based printer" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:752 +#: src/slic3r/GUI/GUI_App.cpp:786 msgid "Taking configuration snapshot" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:752 +#: src/slic3r/GUI/GUI_App.cpp:786 msgid "Snapshot name" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:795 +#: src/slic3r/GUI/GUI_App.cpp:829 msgid "" "Switching the language will trigger application restart.\n" "You will lose content of the plater." msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:797 +#: src/slic3r/GUI/GUI_App.cpp:831 msgid "Do you want to proceed?" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:798 +#: src/slic3r/GUI/GUI_App.cpp:832 msgid "Language selection" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:817 +#: src/slic3r/GUI/GUI_App.cpp:855 msgid "&Configuration" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:837 +#: src/slic3r/GUI/GUI_App.cpp:877 msgid "The presets on the following tabs were modified" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:837 src/slic3r/GUI/Tab.cpp:2835 +#: src/slic3r/GUI/GUI_App.cpp:877 src/slic3r/GUI/Tab.cpp:3051 msgid "Discard changes and continue anyway?" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:838 +#: src/slic3r/GUI/GUI_App.cpp:880 msgid "Unsaved Presets" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:28 src/slic3r/GUI/GUI_ObjectList.cpp:77 -#: src/slic3r/GUI/GUI_ObjectList.cpp:533 src/libslic3r/PrintConfig.cpp:57 -#: src/libslic3r/PrintConfig.cpp:151 src/libslic3r/PrintConfig.cpp:382 -#: src/libslic3r/PrintConfig.cpp:439 src/libslic3r/PrintConfig.cpp:447 -#: src/libslic3r/PrintConfig.cpp:853 src/libslic3r/PrintConfig.cpp:1037 -#: src/libslic3r/PrintConfig.cpp:1340 src/libslic3r/PrintConfig.cpp:1406 -#: src/libslic3r/PrintConfig.cpp:1587 src/libslic3r/PrintConfig.cpp:2022 -#: src/libslic3r/PrintConfig.cpp:2079 +#: src/slic3r/GUI/GUI_ObjectList.cpp:30 src/slic3r/GUI/GUI_ObjectList.cpp:84 +#: src/slic3r/GUI/GUI_ObjectList.cpp:558 src/libslic3r/PrintConfig.cpp:67 +#: src/libslic3r/PrintConfig.cpp:160 src/libslic3r/PrintConfig.cpp:392 +#: src/libslic3r/PrintConfig.cpp:453 src/libslic3r/PrintConfig.cpp:461 +#: src/libslic3r/PrintConfig.cpp:867 src/libslic3r/PrintConfig.cpp:1051 +#: src/libslic3r/PrintConfig.cpp:1354 src/libslic3r/PrintConfig.cpp:1420 +#: src/libslic3r/PrintConfig.cpp:1601 src/libslic3r/PrintConfig.cpp:2037 +#: src/libslic3r/PrintConfig.cpp:2095 msgid "Layers and Perimeters" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:29 src/slic3r/GUI/GUI_ObjectList.cpp:78 -#: src/slic3r/GUI/GUI_ObjectList.cpp:534 src/slic3r/GUI/Plater.cpp:446 -#: src/slic3r/GUI/Tab.cpp:1036 src/slic3r/GUI/Tab.cpp:1037 -#: src/slic3r/GUI/Tab.cpp:1395 src/libslic3r/PrintConfig.cpp:168 -#: src/libslic3r/PrintConfig.cpp:390 src/libslic3r/PrintConfig.cpp:740 -#: src/libslic3r/PrintConfig.cpp:754 src/libslic3r/PrintConfig.cpp:791 -#: src/libslic3r/PrintConfig.cpp:944 src/libslic3r/PrintConfig.cpp:954 -#: src/libslic3r/PrintConfig.cpp:972 src/libslic3r/PrintConfig.cpp:990 -#: src/libslic3r/PrintConfig.cpp:1009 src/libslic3r/PrintConfig.cpp:1694 -#: src/libslic3r/PrintConfig.cpp:1711 +#: src/slic3r/GUI/GUI_ObjectList.cpp:31 src/slic3r/GUI/GUI_ObjectList.cpp:85 +#: src/slic3r/GUI/GUI_ObjectList.cpp:559 src/slic3r/GUI/Plater.cpp:498 +#: src/slic3r/GUI/Tab.cpp:1041 src/slic3r/GUI/Tab.cpp:1042 +#: src/slic3r/GUI/Tab.cpp:1394 src/libslic3r/PrintConfig.cpp:177 +#: src/libslic3r/PrintConfig.cpp:400 src/libslic3r/PrintConfig.cpp:420 +#: src/libslic3r/PrintConfig.cpp:754 src/libslic3r/PrintConfig.cpp:768 +#: src/libslic3r/PrintConfig.cpp:805 src/libslic3r/PrintConfig.cpp:958 +#: src/libslic3r/PrintConfig.cpp:968 src/libslic3r/PrintConfig.cpp:986 +#: src/libslic3r/PrintConfig.cpp:1004 src/libslic3r/PrintConfig.cpp:1023 +#: src/libslic3r/PrintConfig.cpp:1708 src/libslic3r/PrintConfig.cpp:1725 msgid "Infill" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:30 src/slic3r/GUI/GUI_ObjectList.cpp:79 -#: src/slic3r/GUI/GUI_ObjectList.cpp:535 src/slic3r/GUI/GUI_Preview.cpp:242 -#: src/slic3r/GUI/Tab.cpp:1065 src/slic3r/GUI/Tab.cpp:1066 -#: src/libslic3r/PrintConfig.cpp:335 src/libslic3r/PrintConfig.cpp:1467 -#: src/libslic3r/PrintConfig.cpp:1815 src/libslic3r/PrintConfig.cpp:1821 -#: src/libslic3r/PrintConfig.cpp:1829 src/libslic3r/PrintConfig.cpp:1841 -#: src/libslic3r/PrintConfig.cpp:1851 src/libslic3r/PrintConfig.cpp:1859 -#: src/libslic3r/PrintConfig.cpp:1874 src/libslic3r/PrintConfig.cpp:1895 -#: src/libslic3r/PrintConfig.cpp:1906 src/libslic3r/PrintConfig.cpp:1922 -#: src/libslic3r/PrintConfig.cpp:1931 src/libslic3r/PrintConfig.cpp:1940 -#: src/libslic3r/PrintConfig.cpp:1951 src/libslic3r/PrintConfig.cpp:1965 -#: src/libslic3r/PrintConfig.cpp:1973 src/libslic3r/PrintConfig.cpp:1974 -#: src/libslic3r/PrintConfig.cpp:1983 src/libslic3r/PrintConfig.cpp:1991 -#: src/libslic3r/PrintConfig.cpp:2005 src/libslic3r/GCode/PreviewData.cpp:172 +#: src/slic3r/GUI/GUI_ObjectList.cpp:32 src/slic3r/GUI/GUI_ObjectList.cpp:86 +#: src/slic3r/GUI/GUI_ObjectList.cpp:560 src/slic3r/GUI/GUI_Preview.cpp:243 +#: src/slic3r/GUI/Tab.cpp:1070 src/slic3r/GUI/Tab.cpp:1071 +#: src/libslic3r/PrintConfig.cpp:344 src/libslic3r/PrintConfig.cpp:1481 +#: src/libslic3r/PrintConfig.cpp:1830 src/libslic3r/PrintConfig.cpp:1836 +#: src/libslic3r/PrintConfig.cpp:1844 src/libslic3r/PrintConfig.cpp:1856 +#: src/libslic3r/PrintConfig.cpp:1866 src/libslic3r/PrintConfig.cpp:1874 +#: src/libslic3r/PrintConfig.cpp:1889 src/libslic3r/PrintConfig.cpp:1910 +#: src/libslic3r/PrintConfig.cpp:1921 src/libslic3r/PrintConfig.cpp:1937 +#: src/libslic3r/PrintConfig.cpp:1946 src/libslic3r/PrintConfig.cpp:1955 +#: src/libslic3r/PrintConfig.cpp:1966 src/libslic3r/PrintConfig.cpp:1980 +#: src/libslic3r/PrintConfig.cpp:1988 src/libslic3r/PrintConfig.cpp:1989 +#: src/libslic3r/PrintConfig.cpp:1998 src/libslic3r/PrintConfig.cpp:2006 +#: src/libslic3r/PrintConfig.cpp:2020 src/libslic3r/GCode/PreviewData.cpp:172 msgid "Support material" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:33 src/slic3r/GUI/GUI_ObjectList.cpp:81 -#: src/slic3r/GUI/GUI_ObjectList.cpp:537 src/slic3r/GUI/Tab.cpp:1125 -#: src/slic3r/GUI/Tab.cpp:1881 src/libslic3r/PrintConfig.cpp:457 -#: src/libslic3r/PrintConfig.cpp:965 src/libslic3r/PrintConfig.cpp:1375 -#: src/libslic3r/PrintConfig.cpp:1703 src/libslic3r/PrintConfig.cpp:1887 -#: src/libslic3r/PrintConfig.cpp:1913 src/libslic3r/PrintConfig.cpp:2186 -#: src/libslic3r/PrintConfig.cpp:2194 -msgid "Extruders" +#: src/slic3r/GUI/GUI_ObjectList.cpp:35 src/slic3r/GUI/GUI_ObjectList.cpp:90 +#: src/slic3r/GUI/GUI_ObjectList.cpp:564 src/libslic3r/PrintConfig.cpp:2202 +#: src/libslic3r/PrintConfig.cpp:2210 +msgid "Wipe options" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:39 +#: src/slic3r/GUI/GUI_ObjectList.cpp:41 msgid "Pad and Support" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:45 +#: src/slic3r/GUI/GUI_ObjectList.cpp:47 msgid "Add part" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:46 +#: src/slic3r/GUI/GUI_ObjectList.cpp:48 msgid "Add modifier" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:47 +#: src/slic3r/GUI/GUI_ObjectList.cpp:49 msgid "Add support enforcer" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:48 +#: src/slic3r/GUI/GUI_ObjectList.cpp:50 msgid "Add support blocker" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:80 src/slic3r/GUI/GUI_ObjectList.cpp:536 -#: src/slic3r/GUI/GUI_Preview.cpp:221 src/slic3r/GUI/Tab.cpp:1090 -#: src/libslic3r/PrintConfig.cpp:200 src/libslic3r/PrintConfig.cpp:427 -#: src/libslic3r/PrintConfig.cpp:882 src/libslic3r/PrintConfig.cpp:1010 -#: src/libslic3r/PrintConfig.cpp:1396 src/libslic3r/PrintConfig.cpp:1633 -#: src/libslic3r/PrintConfig.cpp:1682 src/libslic3r/PrintConfig.cpp:1733 -#: src/libslic3r/PrintConfig.cpp:2064 +#: src/slic3r/GUI/GUI_ObjectList.cpp:87 src/slic3r/GUI/GUI_ObjectList.cpp:561 +#: src/slic3r/GUI/GUI_Preview.cpp:222 src/slic3r/GUI/Tab.cpp:1095 +#: src/libslic3r/PrintConfig.cpp:209 src/libslic3r/PrintConfig.cpp:441 +#: src/libslic3r/PrintConfig.cpp:896 src/libslic3r/PrintConfig.cpp:1024 +#: src/libslic3r/PrintConfig.cpp:1410 src/libslic3r/PrintConfig.cpp:1647 +#: src/libslic3r/PrintConfig.cpp:1696 src/libslic3r/PrintConfig.cpp:1747 +#: src/libslic3r/PrintConfig.cpp:2080 msgid "Speed" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:82 src/slic3r/GUI/GUI_ObjectList.cpp:538 -#: src/libslic3r/PrintConfig.cpp:417 src/libslic3r/PrintConfig.cpp:524 -#: src/libslic3r/PrintConfig.cpp:841 src/libslic3r/PrintConfig.cpp:973 -#: src/libslic3r/PrintConfig.cpp:1384 src/libslic3r/PrintConfig.cpp:1723 -#: src/libslic3r/PrintConfig.cpp:1896 src/libslic3r/PrintConfig.cpp:2053 +#: src/slic3r/GUI/GUI_ObjectList.cpp:88 src/slic3r/GUI/GUI_ObjectList.cpp:562 +#: src/slic3r/GUI/Tab.cpp:1130 src/slic3r/GUI/Tab.cpp:1997 +#: src/libslic3r/PrintConfig.cpp:471 src/libslic3r/PrintConfig.cpp:979 +#: src/libslic3r/PrintConfig.cpp:1389 src/libslic3r/PrintConfig.cpp:1717 +#: src/libslic3r/PrintConfig.cpp:1902 src/libslic3r/PrintConfig.cpp:1928 +msgid "Extruders" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:89 src/slic3r/GUI/GUI_ObjectList.cpp:563 +#: src/libslic3r/PrintConfig.cpp:431 src/libslic3r/PrintConfig.cpp:538 +#: src/libslic3r/PrintConfig.cpp:855 src/libslic3r/PrintConfig.cpp:987 +#: src/libslic3r/PrintConfig.cpp:1398 src/libslic3r/PrintConfig.cpp:1737 +#: src/libslic3r/PrintConfig.cpp:1911 src/libslic3r/PrintConfig.cpp:2069 msgid "Extrusion Width" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:87 src/slic3r/GUI/GUI_ObjectList.cpp:543 -#: src/slic3r/GUI/Plater.cpp:428 src/slic3r/GUI/Tab.cpp:3454 -#: src/slic3r/GUI/Tab.cpp:3455 src/libslic3r/PrintConfig.cpp:2398 -#: src/libslic3r/PrintConfig.cpp:2405 src/libslic3r/PrintConfig.cpp:2414 -#: src/libslic3r/PrintConfig.cpp:2423 src/libslic3r/PrintConfig.cpp:2433 -#: src/libslic3r/PrintConfig.cpp:2459 src/libslic3r/PrintConfig.cpp:2466 -#: src/libslic3r/PrintConfig.cpp:2477 src/libslic3r/PrintConfig.cpp:2487 -#: src/libslic3r/PrintConfig.cpp:2496 src/libslic3r/PrintConfig.cpp:2506 -#: src/libslic3r/PrintConfig.cpp:2515 src/libslic3r/PrintConfig.cpp:2525 -#: src/libslic3r/PrintConfig.cpp:2535 src/libslic3r/PrintConfig.cpp:2543 +#: src/slic3r/GUI/GUI_ObjectList.cpp:95 src/slic3r/GUI/GUI_ObjectList.cpp:569 +#: src/slic3r/GUI/Plater.cpp:466 src/slic3r/GUI/Tab.cpp:3655 +#: src/slic3r/GUI/Tab.cpp:3656 src/libslic3r/PrintConfig.cpp:2469 +#: src/libslic3r/PrintConfig.cpp:2476 src/libslic3r/PrintConfig.cpp:2485 +#: src/libslic3r/PrintConfig.cpp:2494 src/libslic3r/PrintConfig.cpp:2504 +#: src/libslic3r/PrintConfig.cpp:2530 src/libslic3r/PrintConfig.cpp:2537 +#: src/libslic3r/PrintConfig.cpp:2548 src/libslic3r/PrintConfig.cpp:2558 +#: src/libslic3r/PrintConfig.cpp:2567 src/libslic3r/PrintConfig.cpp:2580 +#: src/libslic3r/PrintConfig.cpp:2590 src/libslic3r/PrintConfig.cpp:2599 +#: src/libslic3r/PrintConfig.cpp:2609 src/libslic3r/PrintConfig.cpp:2621 +#: src/libslic3r/PrintConfig.cpp:2629 msgid "Supports" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:88 src/slic3r/GUI/GUI_ObjectList.cpp:544 -#: src/slic3r/GUI/Tab.cpp:3482 src/slic3r/GUI/Tab.cpp:3483 -#: src/libslic3r/PrintConfig.cpp:2551 src/libslic3r/PrintConfig.cpp:2558 -#: src/libslic3r/PrintConfig.cpp:2572 src/libslic3r/PrintConfig.cpp:2582 -#: src/libslic3r/PrintConfig.cpp:2595 src/libslic3r/PrintConfig.cpp:2604 +#: src/slic3r/GUI/GUI_ObjectList.cpp:96 src/slic3r/GUI/GUI_ObjectList.cpp:570 +#: src/slic3r/GUI/Tab.cpp:3684 src/slic3r/GUI/Tab.cpp:3685 +#: src/libslic3r/PrintConfig.cpp:2637 src/libslic3r/PrintConfig.cpp:2644 +#: src/libslic3r/PrintConfig.cpp:2658 src/libslic3r/PrintConfig.cpp:2668 +#: src/libslic3r/PrintConfig.cpp:2681 src/libslic3r/PrintConfig.cpp:2690 +#: src/libslic3r/PrintConfig.cpp:2701 src/libslic3r/PrintConfig.cpp:2712 +#: src/libslic3r/PrintConfig.cpp:2722 src/libslic3r/PrintConfig.cpp:2732 msgid "Pad" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:205 +#: src/slic3r/GUI/GUI_ObjectList.cpp:217 msgid "Name" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:259 +#: src/slic3r/GUI/GUI_ObjectList.cpp:271 #, possible-c-format msgid "Auto-repaired (%d errors):\n" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:266 +#: src/slic3r/GUI/GUI_ObjectList.cpp:278 msgid "degenerate facets" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:267 +#: src/slic3r/GUI/GUI_ObjectList.cpp:279 msgid "edges fixed" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:268 +#: src/slic3r/GUI/GUI_ObjectList.cpp:280 msgid "facets removed" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:269 +#: src/slic3r/GUI/GUI_ObjectList.cpp:281 msgid "facets added" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:270 +#: src/slic3r/GUI/GUI_ObjectList.cpp:282 msgid "facets reversed" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:271 +#: src/slic3r/GUI/GUI_ObjectList.cpp:283 msgid "backwards edges" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:279 +#: src/slic3r/GUI/GUI_ObjectList.cpp:291 msgid "Right button click the icon to fix STL through Netfabb" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:308 +#: src/slic3r/GUI/GUI_ObjectList.cpp:325 msgid "Right button click the icon to change the object settings" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:359 src/slic3r/GUI/GUI_ObjectList.cpp:380 -#: src/slic3r/GUI/GUI_ObjectList.cpp:392 src/slic3r/GUI/GUI_ObjectList.cpp:2850 -#: src/slic3r/GUI/GUI_ObjectList.cpp:2860 -#: src/slic3r/GUI/GUI_ObjectList.cpp:2892 src/slic3r/GUI/wxExtensions.cpp:543 -#: src/slic3r/GUI/wxExtensions.cpp:568 +#: src/slic3r/GUI/GUI_ObjectList.cpp:375 src/slic3r/GUI/GUI_ObjectList.cpp:396 +#: src/slic3r/GUI/GUI_ObjectList.cpp:408 src/slic3r/GUI/GUI_ObjectList.cpp:3508 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3518 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3550 src/slic3r/GUI/wxExtensions.cpp:576 +#: src/slic3r/GUI/wxExtensions.cpp:633 src/slic3r/GUI/wxExtensions.cpp:658 +#: src/slic3r/GUI/wxExtensions.cpp:794 msgid "default" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:364 src/slic3r/GUI/Tab.cpp:1515 -#: src/libslic3r/PrintConfig.cpp:456 +#: src/slic3r/GUI/GUI_ObjectList.cpp:380 src/slic3r/GUI/Tab.cpp:1613 +#: src/libslic3r/PrintConfig.cpp:470 msgid "Extruder" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:883 src/slic3r/GUI/GUI_ObjectList.cpp:1159 -#: src/slic3r/GUI/GUI_ObjectList.cpp:1165 -#: src/slic3r/GUI/GUI_ObjectList.cpp:1388 +#: src/slic3r/GUI/GUI_ObjectList.cpp:493 +msgid "Rename Object" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:493 +msgid "Rename Sub-object" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:934 src/slic3r/GUI/GUI_ObjectList.cpp:3346 +msgid "Instances to Separated Objects" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:952 +msgid "Remove Volume(s)" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1007 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1316 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1322 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1556 #, possible-c-format msgid "Quick Add Settings (%s)" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:946 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1077 msgid "Select showing settings" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1079 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1126 +msgid "Add Settings for Layers" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1127 +msgid "Add Settings for Sub-object" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1128 +msgid "Add Settings for Object" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1189 +msgid "Add Settings Bundle for Layers" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1190 +msgid "Add Settings Bundle for Sub-object" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1191 +msgid "Add Settings Bundle for Object" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1230 msgid "Load" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1084 -#: src/slic3r/GUI/GUI_ObjectList.cpp:1109 -#: src/slic3r/GUI/GUI_ObjectList.cpp:1112 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1235 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1260 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1263 msgid "Box" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1084 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1235 msgid "Cylinder" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1084 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1235 msgid "Sphere" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1084 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1235 msgid "Slab" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1138 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1287 +msgid "Edit Layers" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1295 msgid "Add settings" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1205 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1362 msgid "Change type" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1212 -#: src/slic3r/GUI/GUI_ObjectList.cpp:1342 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1369 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1510 msgid "Set as a Separated Object" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1218 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1375 msgid "Rename" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1229 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1386 msgid "Fix through the Netfabb" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1239 src/slic3r/GUI/Plater.cpp:3023 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1396 src/slic3r/GUI/Plater.cpp:3496 msgid "Export as STL" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1246 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1403 msgid "Change extruder" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1265 src/libslic3r/PrintConfig.cpp:300 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1422 src/libslic3r/PrintConfig.cpp:309 msgid "Default" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1271 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1428 msgid "Select new extruder for the object/part" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1342 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1440 +msgid "Scale to print volume" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1440 +msgid "Scale the selected object to fit the print volume" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1510 msgid "Set as a Separated Objects" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1555 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1585 +msgid "Load Part" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1617 +msgid "Error!" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1662 +msgid "Add Generic Subobject" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1669 msgid "Generic" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1698 -msgid "You can't delete the last solid part from object." +#: src/slic3r/GUI/GUI_ObjectList.cpp:1770 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1872 +msgid "Last instance of an object cannot be deleted." msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1715 -msgid "You can't delete the last intance from object." +#: src/slic3r/GUI/GUI_ObjectList.cpp:1782 +msgid "Delete Settings" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1741 src/slic3r/GUI/Plater.cpp:2343 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1806 +msgid "Delete All Instances from Object" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1822 +msgid "Delete Layers Range" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1853 +msgid "From Object List You can't delete the last solid part from object." +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1857 +msgid "Delete Subobject" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1876 +msgid "Delete Instance" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1900 src/slic3r/GUI/Plater.cpp:2793 msgid "" "The selected object couldn't be split because it contains only one part." msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1850 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1904 +msgid "Split to Parts" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1950 +msgid "Add Layers" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2075 msgid "Group manipulation" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1862 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2087 msgid "Object manipulation" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1872 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2100 msgid "Object Settings to modify" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1876 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2104 msgid "Part Settings to modify" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1885 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2109 +msgid "Layer range Settings to modify" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2115 msgid "Part manipulation" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1891 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2121 msgid "Instance manipulation" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2416 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2128 +msgid "Layers Editing" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2128 +msgid "Layer Editing" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2303 +msgid "Delete Selected Item" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2415 +msgid "Delete Selected" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2484 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2513 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2531 +msgid "Add New Layers Range" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2590 +msgid "Edit Layers Range" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2867 +msgid "Selection-Remove from list" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2875 +msgid "Selection-Add from list" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2993 msgid "Object or Instance" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2416 -#: src/slic3r/GUI/GUI_ObjectList.cpp:2547 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2994 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3127 msgid "Part" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2418 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2994 +msgid "Layer" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2996 msgid "Unsupported selection" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2419 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2997 #, possible-c-format msgid "You started your selection with %s Item." msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2420 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2998 #, possible-c-format msgid "In this mode you can select only other %s Items%s" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2423 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3001 msgid "of a current Object" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2428 -#: src/slic3r/GUI/GUI_ObjectList.cpp:2501 src/slic3r/GUI/Plater.cpp:117 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3006 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3081 src/slic3r/GUI/Plater.cpp:126 msgid "Info" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2542 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3122 msgid "You can't change a type of the last solid part of the object." msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2547 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3127 msgid "Modifier" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2547 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3127 msgid "Support Enforcer" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2547 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3127 msgid "Support Blocker" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2549 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3129 msgid "Type:" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2549 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3129 msgid "Select type of part" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2713 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3134 +msgid "Change Part Type" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3368 msgid "Enter new name" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2713 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3368 msgid "Renaming" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2729 -#: src/slic3r/GUI/GUI_ObjectList.cpp:2823 src/slic3r/GUI/Tab.cpp:3335 -#: src/slic3r/GUI/Tab.cpp:3339 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3384 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3480 src/slic3r/GUI/Tab.cpp:3536 +#: src/slic3r/GUI/Tab.cpp:3540 msgid "The supplied name is not valid;" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2730 -#: src/slic3r/GUI/GUI_ObjectList.cpp:2824 src/slic3r/GUI/Tab.cpp:3336 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3385 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3481 src/slic3r/GUI/Tab.cpp:3537 msgid "the following characters are not allowed:" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2840 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3498 msgid "Set extruder for selected items" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2841 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3499 msgid "Select extruder number for selected objects and/or parts" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2854 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3512 msgid "Select extruder number:" msgstr "" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2855 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3513 msgid "This extruder will be set for selected items" msgstr "" -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:40 -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:83 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:62 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:105 msgid "World coordinates" msgstr "" -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:41 -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:84 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:63 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:106 msgid "Local coordinates" msgstr "" -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:60 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:82 msgid "Select coordinate space, in which the transformation will be performed." msgstr "" -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:102 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:125 msgid "Object Manipulation" msgstr "" -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:153 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:176 msgid "Object name" msgstr "" -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:229 -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:282 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:212 +#, possible-c-format +msgid "Toggle %c axis mirroring" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:245 +msgid "Set Mirror" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:285 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:290 +msgid "Reset scale" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:303 +msgid "Reset rotation" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:328 +msgid "Reset Rotation" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:340 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:355 +msgid "Drop to bed" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:388 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:443 msgid "Position" msgstr "" -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:230 -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:283 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:389 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:444 msgid "Rotation" msgstr "" -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:284 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:445 msgid "Scale factors" msgstr "" -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:341 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:502 msgid "Translate" msgstr "" -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:640 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:554 +msgid "" +"You cann't use non-uniform scaling mode for multiple objects/parts selection" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:715 +msgid "Set Position" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:746 +msgid "Set Orientation" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:811 +msgid "Set Scale" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:895 msgid "" "The currently manipulated object is tilted (rotation angles are not " "multiples of 90°).\n" @@ -1613,7 +1905,7 @@ msgid "" "once the rotation is embedded into the object coordinates." msgstr "" -#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:643 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:898 msgid "" "This operation is irreversible.\n" "Do you want to proceed?" @@ -1623,117 +1915,127 @@ msgstr "" msgid "Additional Settings" msgstr "" -#: src/slic3r/GUI/GUI_ObjectSettings.cpp:83 +#: src/slic3r/GUI/GUI_ObjectSettings.cpp:94 msgid "Remove parameter" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:215 +#: src/slic3r/GUI/GUI_ObjectSettings.cpp:100 +#, possible-c-format +msgid "Delete Option %s" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectSettings.cpp:144 +#, possible-c-format +msgid "Change Option %s" +msgstr "" + +#: src/slic3r/GUI/GUI_Preview.cpp:216 msgid "View" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:218 src/slic3r/GUI/GUI_Preview.cpp:544 +#: src/slic3r/GUI/GUI_Preview.cpp:219 src/slic3r/GUI/GUI_Preview.cpp:554 #: src/libslic3r/GCode/PreviewData.cpp:394 msgid "Feature type" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:219 src/libslic3r/PrintConfig.cpp:469 +#: src/slic3r/GUI/GUI_Preview.cpp:220 src/libslic3r/PrintConfig.cpp:483 msgid "Height" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:220 src/libslic3r/PrintConfig.cpp:2172 +#: src/slic3r/GUI/GUI_Preview.cpp:221 src/libslic3r/PrintConfig.cpp:2188 msgid "Width" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:222 +#: src/slic3r/GUI/GUI_Preview.cpp:223 msgid "Volumetric flow rate" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:223 src/slic3r/GUI/GUI_Preview.cpp:321 -#: src/slic3r/GUI/GUI_Preview.cpp:487 src/slic3r/GUI/GUI_Preview.cpp:544 -#: src/slic3r/GUI/GUI_Preview.cpp:720 src/libslic3r/GCode/PreviewData.cpp:404 +#: src/slic3r/GUI/GUI_Preview.cpp:224 src/slic3r/GUI/GUI_Preview.cpp:328 +#: src/slic3r/GUI/GUI_Preview.cpp:506 src/slic3r/GUI/GUI_Preview.cpp:553 +#: src/slic3r/GUI/GUI_Preview.cpp:749 src/libslic3r/GCode/PreviewData.cpp:404 msgid "Tool" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:224 src/slic3r/GUI/GUI_Preview.cpp:542 +#: src/slic3r/GUI/GUI_Preview.cpp:225 src/slic3r/GUI/GUI_Preview.cpp:551 #: src/libslic3r/GCode/PreviewData.cpp:406 msgid "Color Print" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:227 +#: src/slic3r/GUI/GUI_Preview.cpp:228 msgid "Show" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:230 src/slic3r/GUI/GUI_Preview.cpp:231 +#: src/slic3r/GUI/GUI_Preview.cpp:231 src/slic3r/GUI/GUI_Preview.cpp:232 msgid "Feature types" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:233 src/libslic3r/GCode/PreviewData.cpp:163 +#: src/slic3r/GUI/GUI_Preview.cpp:234 src/libslic3r/GCode/PreviewData.cpp:163 msgid "Perimeter" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:234 src/libslic3r/GCode/PreviewData.cpp:164 +#: src/slic3r/GUI/GUI_Preview.cpp:235 src/libslic3r/GCode/PreviewData.cpp:164 msgid "External perimeter" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:235 src/libslic3r/GCode/PreviewData.cpp:165 +#: src/slic3r/GUI/GUI_Preview.cpp:236 src/libslic3r/GCode/PreviewData.cpp:165 msgid "Overhang perimeter" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:236 src/libslic3r/GCode/PreviewData.cpp:166 +#: src/slic3r/GUI/GUI_Preview.cpp:237 src/libslic3r/GCode/PreviewData.cpp:166 msgid "Internal infill" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:237 src/libslic3r/PrintConfig.cpp:1722 -#: src/libslic3r/PrintConfig.cpp:1732 src/libslic3r/GCode/PreviewData.cpp:167 +#: src/slic3r/GUI/GUI_Preview.cpp:238 src/libslic3r/PrintConfig.cpp:1736 +#: src/libslic3r/PrintConfig.cpp:1746 src/libslic3r/GCode/PreviewData.cpp:167 msgid "Solid infill" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:238 src/libslic3r/PrintConfig.cpp:2052 -#: src/libslic3r/PrintConfig.cpp:2063 src/libslic3r/GCode/PreviewData.cpp:168 +#: src/slic3r/GUI/GUI_Preview.cpp:239 src/libslic3r/PrintConfig.cpp:2068 +#: src/libslic3r/PrintConfig.cpp:2079 src/libslic3r/GCode/PreviewData.cpp:168 msgid "Top solid infill" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:239 src/libslic3r/GCode/PreviewData.cpp:169 +#: src/slic3r/GUI/GUI_Preview.cpp:240 src/libslic3r/GCode/PreviewData.cpp:169 msgid "Bridge infill" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:240 src/libslic3r/PrintConfig.cpp:881 +#: src/slic3r/GUI/GUI_Preview.cpp:241 src/libslic3r/PrintConfig.cpp:895 #: src/libslic3r/GCode/PreviewData.cpp:170 msgid "Gap fill" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:241 src/slic3r/GUI/Tab.cpp:1056 +#: src/slic3r/GUI/GUI_Preview.cpp:242 src/slic3r/GUI/Tab.cpp:1061 #: src/libslic3r/GCode/PreviewData.cpp:171 msgid "Skirt" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:243 src/libslic3r/PrintConfig.cpp:1939 +#: src/slic3r/GUI/GUI_Preview.cpp:244 src/libslic3r/PrintConfig.cpp:1954 #: src/libslic3r/GCode/PreviewData.cpp:173 msgid "Support material interface" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:244 src/slic3r/GUI/Tab.cpp:1136 +#: src/slic3r/GUI/GUI_Preview.cpp:245 src/slic3r/GUI/Tab.cpp:1141 #: src/libslic3r/GCode/PreviewData.cpp:174 msgid "Wipe tower" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:249 src/libslic3r/PrintConfig.cpp:2086 +#: src/slic3r/GUI/GUI_Preview.cpp:250 src/libslic3r/PrintConfig.cpp:2102 msgid "Travel" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:250 +#: src/slic3r/GUI/GUI_Preview.cpp:251 msgid "Retractions" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:251 +#: src/slic3r/GUI/GUI_Preview.cpp:252 msgid "Unretractions" msgstr "" -#: src/slic3r/GUI/GUI_Preview.cpp:252 +#: src/slic3r/GUI/GUI_Preview.cpp:253 msgid "Shells" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:13 src/slic3r/GUI/MainFrame.cpp:608 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:13 src/slic3r/GUI/MainFrame.cpp:672 msgid "Keyboard Shortcuts" msgstr "" @@ -1749,8 +2051,8 @@ msgstr "" msgid "Load Config from .ini/amf/3mf/gcode" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:107 src/slic3r/GUI/Plater.cpp:740 -#: src/slic3r/GUI/Plater.cpp:3907 src/libslic3r/PrintConfig.cpp:3000 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:107 src/slic3r/GUI/Plater.cpp:822 +#: src/slic3r/GUI/Plater.cpp:4687 src/libslic3r/PrintConfig.cpp:3127 msgid "Export G-code" msgstr "" @@ -1877,642 +2179,675 @@ msgstr "" #: src/slic3r/GUI/KBShortcutsDialog.cpp:147 msgid "" +"Press to scale selection to fit print volume\n" +"in Gizmo scale" +msgstr "" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:148 +msgid "" "Press to activate deselection rectangle\n" "or to scale or rotate selected objects\n" "around their own center" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:148 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:149 msgid "Press to activate one direction scaling in Gizmo scale" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:149 -msgid "Zoom to Bed" -msgstr "" - #: src/slic3r/GUI/KBShortcutsDialog.cpp:150 -msgid "Zoom to all objects in scene, if none selected" +msgid "Change camera type" msgstr "" #: src/slic3r/GUI/KBShortcutsDialog.cpp:151 -msgid "Zoom to selected object" +msgid "Zoom to Bed" msgstr "" #: src/slic3r/GUI/KBShortcutsDialog.cpp:152 -msgid "Zoom in" +msgid "Zoom to all objects in scene, if none selected" msgstr "" #: src/slic3r/GUI/KBShortcutsDialog.cpp:153 -msgid "Zoom out" +msgid "Zoom to selected object" msgstr "" #: src/slic3r/GUI/KBShortcutsDialog.cpp:154 -msgid "Unselect gizmo / Clear selection" +msgid "Zoom in" +msgstr "" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:155 +msgid "Zoom out" msgstr "" #: src/slic3r/GUI/KBShortcutsDialog.cpp:156 +msgid "Unselect gizmo / Clear selection" +msgstr "" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:158 +msgid "Toggle picking pass texture rendering on/off" +msgstr "" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:161 msgid "Plater Shortcuts" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:171 -#: src/slic3r/GUI/KBShortcutsDialog.cpp:182 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:176 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:187 msgid "Arrow Up" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:171 -#: src/slic3r/GUI/KBShortcutsDialog.cpp:173 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:176 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:178 msgid "Upper Layer" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:172 -#: src/slic3r/GUI/KBShortcutsDialog.cpp:183 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:177 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:188 msgid "Arrow Down" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:172 -#: src/slic3r/GUI/KBShortcutsDialog.cpp:174 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:177 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:179 msgid "Lower Layer" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:176 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:181 msgid "Preview Shortcuts" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:182 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:187 msgid "Move current slider thumb Up" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:183 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:188 msgid "Move current slider thumb Down" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:184 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:189 msgid "Arrow Left" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:184 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:189 msgid "Set upper thumb to current slider thumb" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:185 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:190 msgid "Arrow Right" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:185 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:190 msgid "Set lower thumb to current slider thumb" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:186 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:191 msgid "Add color change marker for current layer" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:187 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:192 msgid "Delete color change marker for current layer" msgstr "" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:189 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:194 msgid "Layers Slider Shortcuts" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:61 +#: src/slic3r/GUI/MainFrame.cpp:62 msgid "" " - Remember to check for updates at http://github.com/prusa3d/PrusaSlicer/" "releases" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:150 +#: src/slic3r/GUI/MainFrame.cpp:157 msgid "based on Slic3r" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:180 +#: src/slic3r/GUI/MainFrame.cpp:187 msgid "Plater" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:374 +#: src/slic3r/GUI/MainFrame.cpp:393 msgid "&New Project" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:374 +#: src/slic3r/GUI/MainFrame.cpp:393 msgid "Start a new project" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:377 +#: src/slic3r/GUI/MainFrame.cpp:396 msgid "&Open Project" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:377 +#: src/slic3r/GUI/MainFrame.cpp:396 msgid "Open a project file" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:380 +#: src/slic3r/GUI/MainFrame.cpp:401 +msgid "Recent projects" +msgstr "" + +#: src/slic3r/GUI/MainFrame.cpp:410 +msgid "The selected project is no more available" +msgstr "" + +#: src/slic3r/GUI/MainFrame.cpp:410 src/slic3r/GUI/MainFrame.cpp:747 +#: src/slic3r/GUI/PrintHostDialogs.cpp:231 +msgid "Error" +msgstr "" + +#: src/slic3r/GUI/MainFrame.cpp:434 msgid "&Save Project" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:380 +#: src/slic3r/GUI/MainFrame.cpp:434 msgid "Save current project file" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:384 src/slic3r/GUI/MainFrame.cpp:386 +#: src/slic3r/GUI/MainFrame.cpp:438 src/slic3r/GUI/MainFrame.cpp:440 msgid "Save Project &as" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:384 src/slic3r/GUI/MainFrame.cpp:386 +#: src/slic3r/GUI/MainFrame.cpp:438 src/slic3r/GUI/MainFrame.cpp:440 msgid "Save current project file as" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:394 +#: src/slic3r/GUI/MainFrame.cpp:448 msgid "Import STL/OBJ/AM&F/3MF" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:394 +#: src/slic3r/GUI/MainFrame.cpp:448 msgid "Load a model" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:398 +#: src/slic3r/GUI/MainFrame.cpp:452 msgid "Import &Config" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:398 +#: src/slic3r/GUI/MainFrame.cpp:452 msgid "Load exported configuration file" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:400 +#: src/slic3r/GUI/MainFrame.cpp:454 msgid "Import Config from &project" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:400 +#: src/slic3r/GUI/MainFrame.cpp:454 msgid "Load configuration from project file" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:403 +#: src/slic3r/GUI/MainFrame.cpp:457 msgid "Import Config &Bundle" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:403 +#: src/slic3r/GUI/MainFrame.cpp:457 msgid "Load presets from a bundle" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:405 +#: src/slic3r/GUI/MainFrame.cpp:459 msgid "&Import" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:408 src/slic3r/GUI/MainFrame.cpp:644 +#: src/slic3r/GUI/MainFrame.cpp:462 src/slic3r/GUI/MainFrame.cpp:708 msgid "Export &G-code" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:408 +#: src/slic3r/GUI/MainFrame.cpp:462 msgid "Export current plate as G-code" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:413 +#: src/slic3r/GUI/MainFrame.cpp:466 src/slic3r/GUI/MainFrame.cpp:709 +msgid "S&end G-code" +msgstr "" + +#: src/slic3r/GUI/MainFrame.cpp:466 +msgid "Send to print current plate as G-code" +msgstr "" + +#: src/slic3r/GUI/MainFrame.cpp:471 msgid "Export plate as &STL" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:413 +#: src/slic3r/GUI/MainFrame.cpp:471 msgid "Export current plate as STL" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:416 +#: src/slic3r/GUI/MainFrame.cpp:474 msgid "Export plate as STL including supports" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:416 +#: src/slic3r/GUI/MainFrame.cpp:474 msgid "Export current plate as STL including supports" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:419 +#: src/slic3r/GUI/MainFrame.cpp:477 msgid "Export plate as &AMF" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:419 +#: src/slic3r/GUI/MainFrame.cpp:477 msgid "Export current plate as AMF" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:423 +#: src/slic3r/GUI/MainFrame.cpp:481 msgid "Export &Config" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:423 +#: src/slic3r/GUI/MainFrame.cpp:481 msgid "Export current configuration to file" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:425 +#: src/slic3r/GUI/MainFrame.cpp:483 msgid "Export Config &Bundle" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:425 +#: src/slic3r/GUI/MainFrame.cpp:483 msgid "Export all presets to file" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:427 +#: src/slic3r/GUI/MainFrame.cpp:485 msgid "&Export" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:433 +#: src/slic3r/GUI/MainFrame.cpp:491 msgid "Quick Slice" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:433 +#: src/slic3r/GUI/MainFrame.cpp:491 msgid "Slice a file into a G-code" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:439 +#: src/slic3r/GUI/MainFrame.cpp:497 msgid "Quick Slice and Save As" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:439 +#: src/slic3r/GUI/MainFrame.cpp:497 msgid "Slice a file into a G-code, save as" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:445 +#: src/slic3r/GUI/MainFrame.cpp:503 msgid "Repeat Last Quick Slice" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:445 +#: src/slic3r/GUI/MainFrame.cpp:503 msgid "Repeat last quick slice" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:453 +#: src/slic3r/GUI/MainFrame.cpp:511 msgid "(Re)Slice No&w" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:453 +#: src/slic3r/GUI/MainFrame.cpp:511 msgid "Start new slicing process" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:457 +#: src/slic3r/GUI/MainFrame.cpp:515 msgid "&Repair STL file" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:457 +#: src/slic3r/GUI/MainFrame.cpp:515 msgid "Automatically repair an STL file" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:460 +#: src/slic3r/GUI/MainFrame.cpp:518 msgid "&Quit" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:460 +#: src/slic3r/GUI/MainFrame.cpp:518 #, possible-c-format msgid "Quit %s" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:485 +#: src/slic3r/GUI/MainFrame.cpp:543 msgid "&Select all" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:488 +#: src/slic3r/GUI/MainFrame.cpp:544 msgid "Selects all objects" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:491 +#: src/slic3r/GUI/MainFrame.cpp:546 msgid "D&eselect all" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:492 +#: src/slic3r/GUI/MainFrame.cpp:547 msgid "Deselects all objects" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:496 +#: src/slic3r/GUI/MainFrame.cpp:550 msgid "&Delete selected" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:497 +#: src/slic3r/GUI/MainFrame.cpp:551 msgid "Deletes the current selection" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:499 +#: src/slic3r/GUI/MainFrame.cpp:553 msgid "Delete &all" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:500 +#: src/slic3r/GUI/MainFrame.cpp:554 msgid "Deletes all objects" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:504 +#: src/slic3r/GUI/MainFrame.cpp:558 +msgid "&Undo" +msgstr "" + +#: src/slic3r/GUI/MainFrame.cpp:561 +msgid "&Redo" +msgstr "" + +#: src/slic3r/GUI/MainFrame.cpp:566 msgid "&Copy" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:505 +#: src/slic3r/GUI/MainFrame.cpp:567 msgid "Copy selection to clipboard" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:507 +#: src/slic3r/GUI/MainFrame.cpp:569 msgid "&Paste" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:508 +#: src/slic3r/GUI/MainFrame.cpp:570 msgid "Paste clipboard" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:517 +#: src/slic3r/GUI/MainFrame.cpp:579 msgid "&Plater Tab" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:517 +#: src/slic3r/GUI/MainFrame.cpp:579 msgid "Show the plater" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:524 +#: src/slic3r/GUI/MainFrame.cpp:586 msgid "P&rint Settings Tab" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:524 +#: src/slic3r/GUI/MainFrame.cpp:586 msgid "Show the print settings" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:526 src/slic3r/GUI/MainFrame.cpp:648 +#: src/slic3r/GUI/MainFrame.cpp:588 src/slic3r/GUI/MainFrame.cpp:711 msgid "&Filament Settings Tab" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:526 +#: src/slic3r/GUI/MainFrame.cpp:588 msgid "Show the filament settings" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:529 +#: src/slic3r/GUI/MainFrame.cpp:591 msgid "Print&er Settings Tab" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:529 +#: src/slic3r/GUI/MainFrame.cpp:591 msgid "Show the printer settings" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:533 +#: src/slic3r/GUI/MainFrame.cpp:595 msgid "3&D" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:533 +#: src/slic3r/GUI/MainFrame.cpp:595 msgid "Show the 3D editing view" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:536 +#: src/slic3r/GUI/MainFrame.cpp:598 msgid "Pre&view" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:536 +#: src/slic3r/GUI/MainFrame.cpp:598 msgid "Show the 3D slices preview" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:555 +#: src/slic3r/GUI/MainFrame.cpp:617 msgid "Print &Host Upload Queue" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:555 +#: src/slic3r/GUI/MainFrame.cpp:617 msgid "Display the Print Host Upload Queue window" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:564 +#: src/slic3r/GUI/MainFrame.cpp:626 msgid "Iso" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:564 +#: src/slic3r/GUI/MainFrame.cpp:626 msgid "Iso View" msgstr "" #. TRN To be shown in the main menu View->Top -#: src/slic3r/GUI/MainFrame.cpp:568 -msgid "Top" -msgstr "" - #. TRN To be shown in Print Settings "Top solid layers" -#: src/libslic3r/PrintConfig.cpp:2078 -msgctxt "Layers" +#: src/slic3r/GUI/MainFrame.cpp:630 src/libslic3r/PrintConfig.cpp:2094 msgid "Top" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:568 +#: src/slic3r/GUI/MainFrame.cpp:630 msgid "Top View" msgstr "" #. TRN To be shown in the main menu View->Bottom -#: src/slic3r/GUI/MainFrame.cpp:571 -msgid "Bottom" -msgstr "" - #. TRN To be shown in Print Settings "Bottom solid layers" -#: src/libslic3r/PrintConfig.cpp:150 -msgctxt "Layers" +#: src/slic3r/GUI/MainFrame.cpp:633 src/libslic3r/PrintConfig.cpp:159 msgid "Bottom" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:571 +#: src/slic3r/GUI/MainFrame.cpp:633 msgid "Bottom View" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:573 +#: src/slic3r/GUI/MainFrame.cpp:635 msgid "Front" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:573 +#: src/slic3r/GUI/MainFrame.cpp:635 msgid "Front View" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:575 src/libslic3r/PrintConfig.cpp:1597 +#: src/slic3r/GUI/MainFrame.cpp:637 src/libslic3r/PrintConfig.cpp:1611 msgid "Rear" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:575 +#: src/slic3r/GUI/MainFrame.cpp:637 msgid "Rear View" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:577 +#: src/slic3r/GUI/MainFrame.cpp:639 msgid "Left" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:577 +#: src/slic3r/GUI/MainFrame.cpp:639 msgid "Left View" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:579 +#: src/slic3r/GUI/MainFrame.cpp:641 msgid "Right" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:579 +#: src/slic3r/GUI/MainFrame.cpp:641 msgid "Right View" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:586 +#: src/slic3r/GUI/MainFrame.cpp:648 msgid "Prusa 3D &Drivers" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:586 +#: src/slic3r/GUI/MainFrame.cpp:648 msgid "Open the Prusa3D drivers download page in your browser" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:588 +#: src/slic3r/GUI/MainFrame.cpp:650 msgid "Software &Releases" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:588 +#: src/slic3r/GUI/MainFrame.cpp:650 msgid "Open the software releases page in your browser" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:594 +#: src/slic3r/GUI/MainFrame.cpp:656 #, possible-c-format msgid "%s &Website" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:595 +#: src/slic3r/GUI/MainFrame.cpp:657 #, possible-c-format msgid "Open the %s website in your browser" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:601 +#: src/slic3r/GUI/MainFrame.cpp:663 msgid "System &Info" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:601 +#: src/slic3r/GUI/MainFrame.cpp:663 msgid "Show system information" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:603 +#: src/slic3r/GUI/MainFrame.cpp:665 msgid "Show &Configuration Folder" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:603 +#: src/slic3r/GUI/MainFrame.cpp:665 msgid "Show user configuration folder (datadir)" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:605 +#: src/slic3r/GUI/MainFrame.cpp:667 msgid "Report an I&ssue" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:605 +#: src/slic3r/GUI/MainFrame.cpp:667 #, possible-c-format msgid "Report an issue on %s" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:607 +#: src/slic3r/GUI/MainFrame.cpp:669 #, possible-c-format msgid "&About %s" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:607 +#: src/slic3r/GUI/MainFrame.cpp:669 msgid "Show about dialog" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:610 +#: src/slic3r/GUI/MainFrame.cpp:672 msgid "Show the list of the keyboard shortcuts" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:618 +#: src/slic3r/GUI/MainFrame.cpp:680 msgid "&File" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:619 +#: src/slic3r/GUI/MainFrame.cpp:681 msgid "&Edit" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:620 +#: src/slic3r/GUI/MainFrame.cpp:682 msgid "&Window" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:621 +#: src/slic3r/GUI/MainFrame.cpp:683 msgid "&View" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:624 +#: src/slic3r/GUI/MainFrame.cpp:686 msgid "&Help" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:646 src/slic3r/GUI/Plater.cpp:3907 -msgid "Export" +#: src/slic3r/GUI/MainFrame.cpp:708 +msgid "E&xport" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:648 +#: src/slic3r/GUI/MainFrame.cpp:709 +msgid "S&end to print" +msgstr "" + +#: src/slic3r/GUI/MainFrame.cpp:711 msgid "Mate&rial Settings Tab" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:669 +#: src/slic3r/GUI/MainFrame.cpp:732 msgid "Choose a file to slice (STL/OBJ/AMF/3MF/PRUSA):" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:683 +#: src/slic3r/GUI/MainFrame.cpp:746 msgid "No previously sliced file." msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:684 src/slic3r/GUI/PrintHostDialogs.cpp:231 -msgid "Error" -msgstr "" - -#: src/slic3r/GUI/MainFrame.cpp:689 +#: src/slic3r/GUI/MainFrame.cpp:752 msgid "Previously sliced file (" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:689 +#: src/slic3r/GUI/MainFrame.cpp:752 msgid ") not found." msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:690 +#: src/slic3r/GUI/MainFrame.cpp:753 msgid "File Not Found" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:725 +#: src/slic3r/GUI/MainFrame.cpp:788 #, possible-c-format msgid "Save %s file as:" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:725 +#: src/slic3r/GUI/MainFrame.cpp:788 msgid "SVG" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:725 +#: src/slic3r/GUI/MainFrame.cpp:788 msgid "G-code" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:740 +#: src/slic3r/GUI/MainFrame.cpp:803 msgid "Save zip file as:" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:750 src/slic3r/GUI/Plater.cpp:2476 -#: src/slic3r/GUI/Plater.cpp:3695 src/slic3r/GUI/Tab.cpp:1165 -#: src/slic3r/GUI/Tab.cpp:3493 +#: src/slic3r/GUI/MainFrame.cpp:815 src/slic3r/GUI/Plater.cpp:2933 +#: src/slic3r/GUI/Plater.cpp:4418 src/slic3r/GUI/Tab.cpp:1170 +#: src/slic3r/GUI/Tab.cpp:3700 msgid "Slicing" msgstr "" #. TRN "Processing input_file_basename" -#: src/slic3r/GUI/MainFrame.cpp:754 +#: src/slic3r/GUI/MainFrame.cpp:817 #, possible-c-format msgid "Processing %s" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:777 +#: src/slic3r/GUI/MainFrame.cpp:840 msgid " was successfully sliced." msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:779 +#: src/slic3r/GUI/MainFrame.cpp:842 msgid "Slicing Done!" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:794 +#: src/slic3r/GUI/MainFrame.cpp:857 msgid "Select the STL file to repair:" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:807 +#: src/slic3r/GUI/MainFrame.cpp:870 msgid "Save OBJ file (less prone to coordinate errors than STL) as:" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:822 +#: src/slic3r/GUI/MainFrame.cpp:885 msgid "Your file was repaired." msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:822 src/libslic3r/PrintConfig.cpp:3094 +#: src/slic3r/GUI/MainFrame.cpp:885 src/libslic3r/PrintConfig.cpp:3221 msgid "Repair" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:836 +#: src/slic3r/GUI/MainFrame.cpp:899 msgid "Save configuration as:" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:856 src/slic3r/GUI/MainFrame.cpp:920 +#: src/slic3r/GUI/MainFrame.cpp:919 src/slic3r/GUI/MainFrame.cpp:983 msgid "Select configuration to load:" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:893 +#: src/slic3r/GUI/MainFrame.cpp:956 msgid "Save presets bundle as:" msgstr "" -#: src/slic3r/GUI/MainFrame.cpp:944 +#: src/slic3r/GUI/MainFrame.cpp:1007 #, possible-c-format msgid "%d presets successfully imported." msgstr "" @@ -2527,493 +2862,590 @@ msgstr "" msgid "%s has encountered an error" msgstr "" -#: src/slic3r/GUI/Plater.cpp:137 +#: src/slic3r/GUI/Plater.cpp:146 msgid "Volume" msgstr "" -#: src/slic3r/GUI/Plater.cpp:138 +#: src/slic3r/GUI/Plater.cpp:147 msgid "Facets" msgstr "" -#: src/slic3r/GUI/Plater.cpp:139 +#: src/slic3r/GUI/Plater.cpp:148 msgid "Materials" msgstr "" -#: src/slic3r/GUI/Plater.cpp:142 +#: src/slic3r/GUI/Plater.cpp:151 msgid "Manifold" msgstr "" -#: src/slic3r/GUI/Plater.cpp:192 +#: src/slic3r/GUI/Plater.cpp:201 msgid "Sliced Info" msgstr "" -#: src/slic3r/GUI/Plater.cpp:211 src/slic3r/GUI/Plater.cpp:1049 +#: src/slic3r/GUI/Plater.cpp:220 src/slic3r/GUI/Plater.cpp:1135 msgid "Used Filament (m)" msgstr "" -#: src/slic3r/GUI/Plater.cpp:212 +#: src/slic3r/GUI/Plater.cpp:221 msgid "Used Filament (mm³)" msgstr "" -#: src/slic3r/GUI/Plater.cpp:213 +#: src/slic3r/GUI/Plater.cpp:222 msgid "Used Filament (g)" msgstr "" -#: src/slic3r/GUI/Plater.cpp:214 +#: src/slic3r/GUI/Plater.cpp:223 msgid "Used Material (unit)" msgstr "" -#: src/slic3r/GUI/Plater.cpp:215 src/slic3r/GUI/Plater.cpp:1064 -#: src/libslic3r/PrintConfig.cpp:728 +#: src/slic3r/GUI/Plater.cpp:224 src/slic3r/GUI/Plater.cpp:1150 +#: src/libslic3r/PrintConfig.cpp:742 msgid "Cost" msgstr "" -#: src/slic3r/GUI/Plater.cpp:216 src/slic3r/GUI/Plater.cpp:1036 -#: src/slic3r/GUI/Plater.cpp:1078 +#: src/slic3r/GUI/Plater.cpp:225 src/slic3r/GUI/Plater.cpp:1122 +#: src/slic3r/GUI/Plater.cpp:1164 msgid "Estimated printing time" msgstr "" -#: src/slic3r/GUI/Plater.cpp:217 +#: src/slic3r/GUI/Plater.cpp:226 msgid "Number of tool changes" msgstr "" -#: src/slic3r/GUI/Plater.cpp:291 +#: src/slic3r/GUI/Plater.cpp:317 msgid "Click to edit preset" msgstr "" -#: src/slic3r/GUI/Plater.cpp:431 +#: src/slic3r/GUI/Plater.cpp:469 msgid "Select what kind of support do you need" msgstr "" -#: src/slic3r/GUI/Plater.cpp:433 src/libslic3r/PrintConfig.cpp:1850 -#: src/libslic3r/PrintConfig.cpp:2458 +#: src/slic3r/GUI/Plater.cpp:471 src/libslic3r/PrintConfig.cpp:1865 +#: src/libslic3r/PrintConfig.cpp:2529 msgid "Support on build plate only" msgstr "" -#: src/slic3r/GUI/Plater.cpp:434 src/slic3r/GUI/Plater.cpp:527 +#: src/slic3r/GUI/Plater.cpp:472 src/slic3r/GUI/Plater.cpp:587 msgid "For support enforcers only" msgstr "" -#: src/slic3r/GUI/Plater.cpp:435 +#: src/slic3r/GUI/Plater.cpp:473 msgid "Everywhere" msgstr "" -#: src/slic3r/GUI/Plater.cpp:453 src/slic3r/GUI/Tab.cpp:1062 +#: src/slic3r/GUI/Plater.cpp:505 src/slic3r/GUI/Tab.cpp:1067 msgid "Brim" msgstr "" -#: src/slic3r/GUI/Plater.cpp:455 +#: src/slic3r/GUI/Plater.cpp:507 msgid "" "This flag enables the brim that will be printed around each object on the " "first layer." msgstr "" -#: src/slic3r/GUI/Plater.cpp:463 +#: src/slic3r/GUI/Plater.cpp:515 msgid "Purging volumes" msgstr "" -#: src/slic3r/GUI/Plater.cpp:688 +#: src/slic3r/GUI/Plater.cpp:766 msgid "Print settings" msgstr "" -#: src/slic3r/GUI/Plater.cpp:689 src/slic3r/GUI/Tab.cpp:1506 -#: src/slic3r/GUI/Tab.cpp:1507 +#: src/slic3r/GUI/Plater.cpp:767 src/slic3r/GUI/Tab.cpp:1604 +#: src/slic3r/GUI/Tab.cpp:1605 msgid "Filament" msgstr "" -#: src/slic3r/GUI/Plater.cpp:690 +#: src/slic3r/GUI/Plater.cpp:768 msgid "SLA print settings" msgstr "" -#: src/slic3r/GUI/Plater.cpp:691 src/slic3r/GUI/Preset.cpp:1285 +#: src/slic3r/GUI/Plater.cpp:769 src/slic3r/GUI/Preset.cpp:1310 msgid "SLA material" msgstr "" -#: src/slic3r/GUI/Plater.cpp:692 +#: src/slic3r/GUI/Plater.cpp:770 msgid "Printer" msgstr "" -#: src/slic3r/GUI/Plater.cpp:738 src/slic3r/GUI/Plater.cpp:3908 +#: src/slic3r/GUI/Plater.cpp:820 src/slic3r/GUI/Plater.cpp:4688 msgid "Send to printer" msgstr "" -#: src/slic3r/GUI/Plater.cpp:741 src/slic3r/GUI/Plater.cpp:2476 -#: src/slic3r/GUI/Plater.cpp:3698 +#: src/slic3r/GUI/Plater.cpp:823 src/slic3r/GUI/Plater.cpp:2933 +#: src/slic3r/GUI/Plater.cpp:4421 msgid "Slice now" msgstr "" -#: src/slic3r/GUI/Plater.cpp:881 +#: src/slic3r/GUI/Plater.cpp:963 msgid "Hold Shift to Slice & Export G-code" msgstr "" -#: src/slic3r/GUI/Plater.cpp:982 +#: src/slic3r/GUI/Plater.cpp:1068 #, possible-c-format msgid "%d (%d shells)" msgstr "" -#: src/slic3r/GUI/Plater.cpp:987 +#: src/slic3r/GUI/Plater.cpp:1073 #, possible-c-format msgid "Auto-repaired (%d errors)" msgstr "" -#: src/slic3r/GUI/Plater.cpp:990 +#: src/slic3r/GUI/Plater.cpp:1076 #, possible-c-format msgid "" "%d degenerate facets, %d edges fixed, %d facets removed, %d facets added, %d " "facets reversed, %d backwards edges" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1000 +#: src/slic3r/GUI/Plater.cpp:1086 msgid "Yes" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1023 +#: src/slic3r/GUI/Plater.cpp:1109 msgid "Used Material (ml)" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1026 +#: src/slic3r/GUI/Plater.cpp:1112 msgid "object(s)" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1026 +#: src/slic3r/GUI/Plater.cpp:1112 msgid "supports and pad" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1051 src/slic3r/GUI/Plater.cpp:1066 +#: src/slic3r/GUI/Plater.cpp:1137 src/slic3r/GUI/Plater.cpp:1152 msgid "objects" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1051 src/slic3r/GUI/Plater.cpp:1066 +#: src/slic3r/GUI/Plater.cpp:1137 src/slic3r/GUI/Plater.cpp:1152 msgid "wipe tower" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1081 +#: src/slic3r/GUI/Plater.cpp:1167 msgid "normal mode" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1085 +#: src/slic3r/GUI/Plater.cpp:1171 src/slic3r/GUI/Plater.cpp:1180 +msgid "Color " +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:1176 msgid "stealth mode" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1631 +#: src/slic3r/GUI/Plater.cpp:1271 +msgid "Load File" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:1275 +msgid "Load Files" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:1503 +msgid "ERROR: not enough resources to execute a new job." +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:2056 +msgid "New Project" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:2173 msgid "Loading" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1641 +#: src/slic3r/GUI/Plater.cpp:2183 #, possible-c-format msgid "Processing input file %s\n" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1699 +#: src/slic3r/GUI/Plater.cpp:2211 +msgid "" +"You can't to load SLA project if there is at least one multi-part object on " +"the bed" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:2212 src/slic3r/GUI/Tab.cpp:3064 +msgid "Please check your object list before preset changing." +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:2255 msgid "" "This file contains several objects positioned at multiple heights. Instead " "of considering them as multiple objects, should I consider\n" "this file as a single object having multiple parts?\n" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1702 src/slic3r/GUI/Plater.cpp:1810 +#: src/slic3r/GUI/Plater.cpp:2258 src/slic3r/GUI/Plater.cpp:2310 msgid "Multi-part object detected" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1753 +#: src/slic3r/GUI/Plater.cpp:2265 msgid "" "This file cannot be loaded in a simple mode. Do you want to switch to an " "advanced mode?\n" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1754 +#: src/slic3r/GUI/Plater.cpp:2266 msgid "Detected advanced data" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1787 +#: src/slic3r/GUI/Plater.cpp:2287 #, possible-c-format msgid "" "You can't to add the object(s) from %s because of one or some of them " "is(are) multi-part" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1807 +#: src/slic3r/GUI/Plater.cpp:2307 msgid "" "Multiple objects were loaded for a multi-material printer.\n" "Instead of considering them as multiple objects, should I consider\n" "these files to represent a single object having multiple parts?\n" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1823 +#: src/slic3r/GUI/Plater.cpp:2323 msgid "Loaded" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1921 +#: src/slic3r/GUI/Plater.cpp:2418 msgid "" "Your object appears to be too large, so it was automatically scaled down to " "fit your print bed." msgstr "" -#: src/slic3r/GUI/Plater.cpp:1922 +#: src/slic3r/GUI/Plater.cpp:2419 msgid "Object too large?" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1979 +#: src/slic3r/GUI/Plater.cpp:2476 msgid "Export STL file:" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1986 +#: src/slic3r/GUI/Plater.cpp:2483 msgid "Export AMF file:" msgstr "" -#: src/slic3r/GUI/Plater.cpp:1992 +#: src/slic3r/GUI/Plater.cpp:2489 msgid "Save file as:" msgstr "" -#: src/slic3r/GUI/Plater.cpp:2160 -msgid "Arranging canceled" +#: src/slic3r/GUI/Plater.cpp:2592 +msgid "Delete Object" msgstr "" -#: src/slic3r/GUI/Plater.cpp:2163 +#: src/slic3r/GUI/Plater.cpp:2603 +msgid "Reset Project" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:2630 src/slic3r/GUI/Plater.cpp:3517 +msgid "Mirror" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:2643 +msgid "Optimize Rotation" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:2689 msgid "Arranging" msgstr "" -#: src/slic3r/GUI/Plater.cpp:2200 +#: src/slic3r/GUI/Plater.cpp:2712 msgid "Could not arrange model objects! Some geometries may be invalid." msgstr "" -#: src/slic3r/GUI/Plater.cpp:2207 +#: src/slic3r/GUI/Plater.cpp:2718 +msgid "Arranging canceled." +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:2719 msgid "Arranging done." msgstr "" -#: src/slic3r/GUI/Plater.cpp:2248 -msgid "Orientation search canceled" -msgstr "" - -#: src/slic3r/GUI/Plater.cpp:2253 +#: src/slic3r/GUI/Plater.cpp:2735 msgid "Searching for optimal orientation" msgstr "" -#: src/slic3r/GUI/Plater.cpp:2315 +#: src/slic3r/GUI/Plater.cpp:2768 +msgid "Orientation search canceled." +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:2769 msgid "Orientation found." msgstr "" -#: src/slic3r/GUI/Plater.cpp:2335 +#: src/slic3r/GUI/Plater.cpp:2785 msgid "" "The selected object can't be split because it contains more than one volume/" "material." msgstr "" -#: src/slic3r/GUI/Plater.cpp:2461 +#: src/slic3r/GUI/Plater.cpp:2796 +msgid "Split to Objects" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:2918 msgid "Invalid data" msgstr "" -#: src/slic3r/GUI/Plater.cpp:2470 +#: src/slic3r/GUI/Plater.cpp:2927 msgid "Ready to slice" msgstr "" -#: src/slic3r/GUI/Plater.cpp:2508 src/slic3r/GUI/PrintHostDialogs.cpp:232 +#: src/slic3r/GUI/Plater.cpp:2965 src/slic3r/GUI/PrintHostDialogs.cpp:232 msgid "Cancelling" msgstr "" -#: src/slic3r/GUI/Plater.cpp:2525 +#: src/slic3r/GUI/Plater.cpp:2982 msgid "Another export job is currently running." msgstr "" -#: src/slic3r/GUI/Plater.cpp:2786 -msgid "Export failed" -msgstr "" - -#: src/slic3r/GUI/Plater.cpp:2791 src/slic3r/GUI/PrintHostDialogs.cpp:233 -msgid "Cancelled" -msgstr "" - -#: src/slic3r/GUI/Plater.cpp:2877 src/slic3r/GUI/Plater.cpp:2889 -#: src/slic3r/GUI/Plater.cpp:3000 -msgid "Increase copies" -msgstr "" - -#: src/slic3r/GUI/Plater.cpp:2994 src/slic3r/GUI/Plater.cpp:3013 -msgid "Remove the selected object" -msgstr "" - -#: src/slic3r/GUI/Plater.cpp:3000 -msgid "Place one more copy of the selected object" -msgstr "" - -#: src/slic3r/GUI/Plater.cpp:3002 -msgid "Decrease copies" -msgstr "" - -#: src/slic3r/GUI/Plater.cpp:3002 -msgid "Remove one copy of the selected object" -msgstr "" - -#: src/slic3r/GUI/Plater.cpp:3004 -msgid "Set number of copies" -msgstr "" - -#: src/slic3r/GUI/Plater.cpp:3004 -msgid "Change the number of copies of the selected object" -msgstr "" - -#: src/slic3r/GUI/Plater.cpp:3020 +#: src/slic3r/GUI/Plater.cpp:3036 src/slic3r/GUI/Plater.cpp:3493 msgid "Reload from Disk" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3020 +#: src/slic3r/GUI/Plater.cpp:3072 +msgid "Fix Throught NetFabb" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:3254 +msgid "Export failed" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:3259 src/slic3r/GUI/PrintHostDialogs.cpp:233 +msgid "Cancelled" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:3347 src/slic3r/GUI/Plater.cpp:3359 +#: src/slic3r/GUI/Plater.cpp:3473 +msgid "Increase copies" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:3467 src/slic3r/GUI/Plater.cpp:3486 +msgid "Remove the selected object" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:3473 +msgid "Place one more copy of the selected object" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:3475 +msgid "Decrease copies" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:3475 +msgid "Remove one copy of the selected object" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:3477 +msgid "Set number of copies" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:3477 +msgid "Change the number of copies of the selected object" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:3493 msgid "Reload the selected file from Disk" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3023 +#: src/slic3r/GUI/Plater.cpp:3496 msgid "Export the selected object as STL file" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3035 +#: src/slic3r/GUI/Plater.cpp:3510 msgid "Along X axis" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3035 +#: src/slic3r/GUI/Plater.cpp:3510 msgid "Mirror the selected object along the X axis" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3037 +#: src/slic3r/GUI/Plater.cpp:3512 msgid "Along Y axis" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3037 +#: src/slic3r/GUI/Plater.cpp:3512 msgid "Mirror the selected object along the Y axis" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3039 +#: src/slic3r/GUI/Plater.cpp:3514 msgid "Along Z axis" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3039 +#: src/slic3r/GUI/Plater.cpp:3514 msgid "Mirror the selected object along the Z axis" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3042 -msgid "Mirror" -msgstr "" - -#: src/slic3r/GUI/Plater.cpp:3042 +#: src/slic3r/GUI/Plater.cpp:3517 msgid "Mirror the selected object" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3054 +#: src/slic3r/GUI/Plater.cpp:3529 msgid "To objects" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3054 src/slic3r/GUI/Plater.cpp:3070 +#: src/slic3r/GUI/Plater.cpp:3529 src/slic3r/GUI/Plater.cpp:3549 msgid "Split the selected object into individual objects" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3056 +#: src/slic3r/GUI/Plater.cpp:3531 msgid "To parts" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3056 src/slic3r/GUI/Plater.cpp:3084 +#: src/slic3r/GUI/Plater.cpp:3531 src/slic3r/GUI/Plater.cpp:3563 msgid "Split the selected object into individual sub-parts" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3059 src/slic3r/GUI/Plater.cpp:3070 -#: src/slic3r/GUI/Plater.cpp:3084 src/libslic3r/PrintConfig.cpp:3118 +#: src/slic3r/GUI/Plater.cpp:3534 src/slic3r/GUI/Plater.cpp:3549 +#: src/slic3r/GUI/Plater.cpp:3563 src/libslic3r/PrintConfig.cpp:3245 msgid "Split" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3059 +#: src/slic3r/GUI/Plater.cpp:3534 msgid "Split the selected object" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3076 +#: src/slic3r/GUI/Plater.cpp:3555 msgid "Optimize orientation" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3076 +#: src/slic3r/GUI/Plater.cpp:3555 msgid "Optimize the rotation of the object for better print results." msgstr "" -#: src/slic3r/GUI/Plater.cpp:3127 +#: src/slic3r/GUI/Plater.cpp:3595 msgid "3D editor view" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3138 src/slic3r/GUI/Tab.cpp:2325 +#: src/slic3r/GUI/Plater.cpp:3603 src/slic3r/GUI/Tab.cpp:2534 msgid "Preview" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3375 +#: src/slic3r/GUI/Plater.cpp:3831 +msgid "" +"%1% printer was active at the time the target Undo / Redo snapshot was " +"taken. Switching to %1% printer requires reloading of %1% presets." +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:3992 +msgid "Load Project" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:4016 +msgid "Import Object" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:4020 +msgid "Import Objects" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:4075 msgid "All objects will be removed, continue ?" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3511 +#: src/slic3r/GUI/Plater.cpp:4083 +msgid "Delete Selected Objects" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:4091 +msgid "Increase Instances" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:4127 +msgid "Decrease Instances" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:4163 +#, possible-c-format +msgid "Set numbers of copies to %d" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:4193 +msgid "Cut by Plane" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:4225 msgid "Save G-code file as:" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3511 +#: src/slic3r/GUI/Plater.cpp:4225 msgid "Save SL1 file as:" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3623 +#: src/slic3r/GUI/Plater.cpp:4337 #, possible-c-format msgid "STL file exported to %s" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3639 +#: src/slic3r/GUI/Plater.cpp:4353 #, possible-c-format msgid "AMF file exported to %s" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3642 +#: src/slic3r/GUI/Plater.cpp:4356 #, possible-c-format msgid "Error exporting AMF file %s" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3668 +#: src/slic3r/GUI/Plater.cpp:4382 #, possible-c-format msgid "3MF file exported to %s" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3673 +#: src/slic3r/GUI/Plater.cpp:4387 #, possible-c-format msgid "Error exporting 3MF file %s" msgstr "" -#: src/slic3r/GUI/Plater.cpp:3908 +#: src/slic3r/GUI/Plater.cpp:4687 +msgid "Export" +msgstr "" + +#: src/slic3r/GUI/Plater.cpp:4688 msgid "Send G-code" msgstr "" -#: src/slic3r/GUI/Preferences.cpp:19 src/slic3r/GUI/Tab.cpp:1849 -#: src/slic3r/GUI/Tab.cpp:2050 +#: src/slic3r/GUI/Plater.cpp:4772 +msgid "Paste From Clipboard" +msgstr "" + +#: src/slic3r/GUI/Preferences.cpp:22 src/slic3r/GUI/Tab.cpp:1955 +#: src/slic3r/GUI/Tab.cpp:2193 msgid "General" msgstr "" -#: src/slic3r/GUI/Preferences.cpp:36 +#: src/slic3r/GUI/Preferences.cpp:44 msgid "Remember output directory" msgstr "" -#: src/slic3r/GUI/Preferences.cpp:38 +#: src/slic3r/GUI/Preferences.cpp:46 msgid "" "If this is enabled, Slic3r will prompt the last output directory instead of " "the one containing the input files." msgstr "" -#: src/slic3r/GUI/Preferences.cpp:44 +#: src/slic3r/GUI/Preferences.cpp:52 msgid "Auto-center parts" msgstr "" -#: src/slic3r/GUI/Preferences.cpp:46 +#: src/slic3r/GUI/Preferences.cpp:54 msgid "" "If this is enabled, Slic3r will auto-center objects around the print bed " "center." msgstr "" -#: src/slic3r/GUI/Preferences.cpp:52 +#: src/slic3r/GUI/Preferences.cpp:60 msgid "Background processing" msgstr "" -#: src/slic3r/GUI/Preferences.cpp:54 +#: src/slic3r/GUI/Preferences.cpp:62 msgid "" "If this is enabled, Slic3r will pre-process objects as soon as they're " "loaded in order to save time when exporting G-code." msgstr "" -#: src/slic3r/GUI/Preferences.cpp:63 +#: src/slic3r/GUI/Preferences.cpp:71 msgid "" "If enabled, PrusaSlicer will check for the new versions of itself online. " "When a new version becomes available a notification is displayed at the next " @@ -3021,7 +3453,7 @@ msgid "" "notification mechanisms, no automatic installation is done." msgstr "" -#: src/slic3r/GUI/Preferences.cpp:71 +#: src/slic3r/GUI/Preferences.cpp:79 msgid "" "If enabled, Slic3r downloads updates of built-in system presets in the " "background. These updates are downloaded into a separate temporary location. " @@ -3029,76 +3461,90 @@ msgid "" "startup." msgstr "" -#: src/slic3r/GUI/Preferences.cpp:76 +#: src/slic3r/GUI/Preferences.cpp:84 msgid "Suppress \" - default - \" presets" msgstr "" -#: src/slic3r/GUI/Preferences.cpp:78 +#: src/slic3r/GUI/Preferences.cpp:86 msgid "" "Suppress \" - default - \" presets in the Print / Filament / Printer " "selections once there are any other valid presets available." msgstr "" -#: src/slic3r/GUI/Preferences.cpp:84 +#: src/slic3r/GUI/Preferences.cpp:92 msgid "Show incompatible print and filament presets" msgstr "" -#: src/slic3r/GUI/Preferences.cpp:86 +#: src/slic3r/GUI/Preferences.cpp:94 msgid "" "When checked, the print and filament presets are shown in the preset editor " "even if they are marked as incompatible with the active printer" msgstr "" -#: src/slic3r/GUI/Preferences.cpp:93 -msgid "Use legacy OpenGL 1.1 rendering" -msgstr "" - -#: src/slic3r/GUI/Preferences.cpp:95 -msgid "" -"If you have rendering issues caused by a buggy OpenGL 2.0 driver, you may " -"try to check this checkbox. This will disable the layer height editing and " -"anti aliasing, so it is likely better to upgrade your graphics driver." -msgstr "" - -#: src/slic3r/GUI/Preferences.cpp:103 +#: src/slic3r/GUI/Preferences.cpp:101 msgid "Use Retina resolution for the 3D scene" msgstr "" -#: src/slic3r/GUI/Preferences.cpp:105 +#: src/slic3r/GUI/Preferences.cpp:103 msgid "" "If enabled, the 3D scene will be rendered in Retina resolution. If you are " "experiencing 3D performance problems, disabling this option may help." msgstr "" -#: src/slic3r/GUI/Preferences.cpp:130 +#: src/slic3r/GUI/Preferences.cpp:110 +msgid "Use perspective camera" +msgstr "" + +#: src/slic3r/GUI/Preferences.cpp:112 +msgid "" +"If enabled, use perspective camera. If not enabled, use orthographic camera." +msgstr "" + +#: src/slic3r/GUI/Preferences.cpp:117 +msgid "Use custom size for toolbar icons" +msgstr "" + +#: src/slic3r/GUI/Preferences.cpp:119 +msgid "If enabled, you can change size of toolbar icons manually." +msgstr "" + +#: src/slic3r/GUI/Preferences.cpp:144 #, possible-c-format msgid "You need to restart %s to make the changes effective." msgstr "" +#: src/slic3r/GUI/Preferences.cpp:192 +msgid "Icon size in a respect to the default size" +msgstr "" + +#: src/slic3r/GUI/Preferences.cpp:207 +msgid "Select toolbar icon size in respect to the default one." +msgstr "" + #: src/slic3r/GUI/Preset.cpp:212 msgid "modified" msgstr "" -#: src/slic3r/GUI/Preset.cpp:938 src/slic3r/GUI/Preset.cpp:978 -#: src/slic3r/GUI/Preset.cpp:1043 src/slic3r/GUI/Preset.cpp:1075 -#: src/slic3r/GUI/PresetBundle.cpp:1478 src/slic3r/GUI/PresetBundle.cpp:1543 +#: src/slic3r/GUI/Preset.cpp:963 src/slic3r/GUI/Preset.cpp:1003 +#: src/slic3r/GUI/Preset.cpp:1068 src/slic3r/GUI/Preset.cpp:1100 +#: src/slic3r/GUI/PresetBundle.cpp:1480 src/slic3r/GUI/PresetBundle.cpp:1545 msgid "System presets" msgstr "" -#: src/slic3r/GUI/Preset.cpp:982 src/slic3r/GUI/Preset.cpp:1079 -#: src/slic3r/GUI/PresetBundle.cpp:1548 +#: src/slic3r/GUI/Preset.cpp:1007 src/slic3r/GUI/Preset.cpp:1104 +#: src/slic3r/GUI/PresetBundle.cpp:1550 msgid "User presets" msgstr "" -#: src/slic3r/GUI/Preset.cpp:1011 src/slic3r/GUI/Tab.cpp:241 +#: src/slic3r/GUI/Preset.cpp:1036 src/slic3r/GUI/Tab.cpp:241 msgid "Add a new printer" msgstr "" -#: src/slic3r/GUI/Preset.cpp:1283 +#: src/slic3r/GUI/Preset.cpp:1308 msgid "filament" msgstr "" -#: src/slic3r/GUI/Preset.cpp:1284 +#: src/slic3r/GUI/Preset.cpp:1309 msgid "SLA print" msgstr "" @@ -3293,10 +3739,10 @@ msgid "Time" msgstr "" #: src/slic3r/GUI/RammingChart.cpp:76 src/slic3r/GUI/WipeTowerDialog.cpp:82 -#: src/libslic3r/PrintConfig.cpp:613 src/libslic3r/PrintConfig.cpp:657 -#: src/libslic3r/PrintConfig.cpp:672 src/libslic3r/PrintConfig.cpp:2278 -#: src/libslic3r/PrintConfig.cpp:2287 src/libslic3r/PrintConfig.cpp:2347 -#: src/libslic3r/PrintConfig.cpp:2354 +#: src/libslic3r/PrintConfig.cpp:627 src/libslic3r/PrintConfig.cpp:671 +#: src/libslic3r/PrintConfig.cpp:686 src/libslic3r/PrintConfig.cpp:2349 +#: src/libslic3r/PrintConfig.cpp:2358 src/libslic3r/PrintConfig.cpp:2418 +#: src/libslic3r/PrintConfig.cpp:2425 msgid "s" msgstr "" @@ -3304,20 +3750,20 @@ msgstr "" msgid "Volumetric speed" msgstr "" -#: src/slic3r/GUI/RammingChart.cpp:81 src/libslic3r/PrintConfig.cpp:570 -#: src/libslic3r/PrintConfig.cpp:1220 +#: src/slic3r/GUI/RammingChart.cpp:81 src/libslic3r/PrintConfig.cpp:584 +#: src/libslic3r/PrintConfig.cpp:1234 msgid "mm³/s" msgstr "" -#: src/slic3r/GUI/SysInfoDialog.cpp:44 +#: src/slic3r/GUI/SysInfoDialog.cpp:78 msgid "System Information" msgstr "" -#: src/slic3r/GUI/SysInfoDialog.cpp:120 +#: src/slic3r/GUI/SysInfoDialog.cpp:154 msgid "Copy to Clipboard" msgstr "" -#: src/slic3r/GUI/Tab.cpp:52 src/libslic3r/PrintConfig.cpp:230 +#: src/slic3r/GUI/Tab.cpp:52 src/libslic3r/PrintConfig.cpp:239 msgid "Compatible printers" msgstr "" @@ -3325,7 +3771,7 @@ msgstr "" msgid "Select the printers this profile is compatible with." msgstr "" -#: src/slic3r/GUI/Tab.cpp:58 src/libslic3r/PrintConfig.cpp:245 +#: src/slic3r/GUI/Tab.cpp:58 src/libslic3r/PrintConfig.cpp:254 msgid "Compatible print profiles" msgstr "" @@ -3349,204 +3795,206 @@ msgid "" "or click this button." msgstr "" -#: src/slic3r/GUI/Tab.cpp:920 -msgid "It's a default preset." -msgstr "" - #: src/slic3r/GUI/Tab.cpp:921 -msgid "It's a system preset." -msgstr "" - -#: src/slic3r/GUI/Tab.cpp:922 -#, possible-c-format -msgid "Current preset is inherited from %s" +msgid "This is a default preset." msgstr "" #: src/slic3r/GUI/Tab.cpp:923 -msgid "default preset" +msgid "This is a system preset." msgstr "" -#: src/slic3r/GUI/Tab.cpp:927 -msgid "It can't be deleted or modified." +#: src/slic3r/GUI/Tab.cpp:925 +msgid "Current preset is inherited from the default preset." msgstr "" #: src/slic3r/GUI/Tab.cpp:928 +#, possible-c-format +msgid "" +"Current preset is inherited from:\n" +"\t%s" +msgstr "" + +#: src/slic3r/GUI/Tab.cpp:932 +msgid "It can't be deleted or modified." +msgstr "" + +#: src/slic3r/GUI/Tab.cpp:933 msgid "" "Any modifications should be saved as a new preset inherited from this one." msgstr "" -#: src/slic3r/GUI/Tab.cpp:929 +#: src/slic3r/GUI/Tab.cpp:934 msgid "To do that please specify a new name for the preset." msgstr "" -#: src/slic3r/GUI/Tab.cpp:933 +#: src/slic3r/GUI/Tab.cpp:938 msgid "Additional information:" msgstr "" -#: src/slic3r/GUI/Tab.cpp:939 +#: src/slic3r/GUI/Tab.cpp:944 msgid "printer model" msgstr "" -#: src/slic3r/GUI/Tab.cpp:947 +#: src/slic3r/GUI/Tab.cpp:952 msgid "default print profile" msgstr "" -#: src/slic3r/GUI/Tab.cpp:950 +#: src/slic3r/GUI/Tab.cpp:955 msgid "default filament profile" msgstr "" -#: src/slic3r/GUI/Tab.cpp:964 +#: src/slic3r/GUI/Tab.cpp:969 msgid "default SLA material profile" msgstr "" -#: src/slic3r/GUI/Tab.cpp:968 +#: src/slic3r/GUI/Tab.cpp:973 msgid "default SLA print profile" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1003 src/slic3r/GUI/Tab.cpp:3419 +#: src/slic3r/GUI/Tab.cpp:1008 src/slic3r/GUI/Tab.cpp:3649 msgid "Layers and perimeters" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1004 src/slic3r/GUI/Tab.cpp:1253 -#: src/libslic3r/PrintConfig.cpp:56 +#: src/slic3r/GUI/Tab.cpp:1009 src/slic3r/GUI/Tab.cpp:1257 +#: src/libslic3r/PrintConfig.cpp:66 msgid "Layer height" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1008 +#: src/slic3r/GUI/Tab.cpp:1013 msgid "Vertical shells" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1019 +#: src/slic3r/GUI/Tab.cpp:1024 msgid "Horizontal shells" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1020 src/libslic3r/PrintConfig.cpp:1745 +#: src/slic3r/GUI/Tab.cpp:1025 src/libslic3r/PrintConfig.cpp:1759 msgid "Solid layers" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1025 +#: src/slic3r/GUI/Tab.cpp:1030 msgid "Quality (slower slicing)" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1043 +#: src/slic3r/GUI/Tab.cpp:1048 msgid "Reducing printing time" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1055 +#: src/slic3r/GUI/Tab.cpp:1060 msgid "Skirt and brim" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1072 +#: src/slic3r/GUI/Tab.cpp:1077 msgid "Raft" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1076 +#: src/slic3r/GUI/Tab.cpp:1081 msgid "Options for support material and raft" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1091 +#: src/slic3r/GUI/Tab.cpp:1096 msgid "Speed for print moves" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1103 +#: src/slic3r/GUI/Tab.cpp:1108 msgid "Speed for non-print moves" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1106 +#: src/slic3r/GUI/Tab.cpp:1111 msgid "Modifiers" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1109 +#: src/slic3r/GUI/Tab.cpp:1114 msgid "Acceleration control (advanced)" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1116 +#: src/slic3r/GUI/Tab.cpp:1121 msgid "Autospeed (advanced)" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1124 +#: src/slic3r/GUI/Tab.cpp:1129 msgid "Multiple Extruders" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1132 +#: src/slic3r/GUI/Tab.cpp:1137 msgid "Ooze prevention" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1149 +#: src/slic3r/GUI/Tab.cpp:1154 msgid "Extrusion width" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1159 +#: src/slic3r/GUI/Tab.cpp:1164 msgid "Overlap" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1162 +#: src/slic3r/GUI/Tab.cpp:1167 msgid "Flow" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1171 +#: src/slic3r/GUI/Tab.cpp:1176 msgid "Other" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1174 src/slic3r/GUI/Tab.cpp:3496 +#: src/slic3r/GUI/Tab.cpp:1179 src/slic3r/GUI/Tab.cpp:3703 msgid "Output options" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1175 +#: src/slic3r/GUI/Tab.cpp:1180 msgid "Sequential printing" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1177 +#: src/slic3r/GUI/Tab.cpp:1182 msgid "Extruder clearance (mm)" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1186 src/slic3r/GUI/Tab.cpp:3497 +#: src/slic3r/GUI/Tab.cpp:1191 src/slic3r/GUI/Tab.cpp:3704 msgid "Output file" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1193 src/libslic3r/PrintConfig.cpp:1418 +#: src/slic3r/GUI/Tab.cpp:1198 src/libslic3r/PrintConfig.cpp:1432 msgid "Post-processing scripts" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1199 src/slic3r/GUI/Tab.cpp:1200 -#: src/slic3r/GUI/Tab.cpp:1612 src/slic3r/GUI/Tab.cpp:1613 -#: src/slic3r/GUI/Tab.cpp:2022 src/slic3r/GUI/Tab.cpp:2023 -#: src/slic3r/GUI/Tab.cpp:2116 src/slic3r/GUI/Tab.cpp:2117 -#: src/slic3r/GUI/Tab.cpp:3385 src/slic3r/GUI/Tab.cpp:3386 +#: src/slic3r/GUI/Tab.cpp:1204 src/slic3r/GUI/Tab.cpp:1205 +#: src/slic3r/GUI/Tab.cpp:1716 src/slic3r/GUI/Tab.cpp:1717 +#: src/slic3r/GUI/Tab.cpp:2165 src/slic3r/GUI/Tab.cpp:2166 +#: src/slic3r/GUI/Tab.cpp:2273 src/slic3r/GUI/Tab.cpp:2274 +#: src/slic3r/GUI/Tab.cpp:3586 src/slic3r/GUI/Tab.cpp:3587 msgid "Notes" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1206 src/slic3r/GUI/Tab.cpp:1620 -#: src/slic3r/GUI/Tab.cpp:2029 src/slic3r/GUI/Tab.cpp:2123 -#: src/slic3r/GUI/Tab.cpp:3393 src/slic3r/GUI/Tab.cpp:3502 +#: src/slic3r/GUI/Tab.cpp:1211 src/slic3r/GUI/Tab.cpp:1724 +#: src/slic3r/GUI/Tab.cpp:2172 src/slic3r/GUI/Tab.cpp:2280 +#: src/slic3r/GUI/Tab.cpp:3594 src/slic3r/GUI/Tab.cpp:3709 msgid "Dependencies" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1207 src/slic3r/GUI/Tab.cpp:1621 -#: src/slic3r/GUI/Tab.cpp:2030 src/slic3r/GUI/Tab.cpp:2124 -#: src/slic3r/GUI/Tab.cpp:3394 src/slic3r/GUI/Tab.cpp:3503 +#: src/slic3r/GUI/Tab.cpp:1212 src/slic3r/GUI/Tab.cpp:1725 +#: src/slic3r/GUI/Tab.cpp:2173 src/slic3r/GUI/Tab.cpp:2281 +#: src/slic3r/GUI/Tab.cpp:3595 src/slic3r/GUI/Tab.cpp:3710 msgid "Profile dependencies" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1253 +#: src/slic3r/GUI/Tab.cpp:1256 msgid "" -"Layer height can't be equal to zero.\n" +"Zero layer height is not valid.\n" "\n" -"Shall I set its value to minimum (0.01)?" +"The layer height will be reset to 0.01." msgstr "" -#: src/slic3r/GUI/Tab.cpp:1266 +#: src/slic3r/GUI/Tab.cpp:1268 msgid "" -"First layer height can't be equal to zero.\n" +"Zero first layer height is not valid.\n" "\n" -"Shall I set its value to minimum (0.01)?" +"The first layer height will be reset to 0.01." msgstr "" -#: src/slic3r/GUI/Tab.cpp:1268 src/libslic3r/PrintConfig.cpp:852 +#: src/slic3r/GUI/Tab.cpp:1269 src/libslic3r/PrintConfig.cpp:866 msgid "First layer height" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1284 +#: src/slic3r/GUI/Tab.cpp:1283 #, possible-c-format msgid "" "The Spiral Vase mode requires:\n" @@ -3559,11 +4007,11 @@ msgid "" "Shall I adjust those settings in order to enable Spiral Vase?" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1291 +#: src/slic3r/GUI/Tab.cpp:1290 msgid "Spiral Vase" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1312 +#: src/slic3r/GUI/Tab.cpp:1311 msgid "" "The Wipe Tower currently supports the non-soluble supports only\n" "if they are printed with the current extruder without triggering a tool " @@ -3574,11 +4022,11 @@ msgid "" "Shall I adjust those settings in order to enable the Wipe Tower?" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1316 src/slic3r/GUI/Tab.cpp:1333 +#: src/slic3r/GUI/Tab.cpp:1315 src/slic3r/GUI/Tab.cpp:1332 msgid "Wipe Tower" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1330 +#: src/slic3r/GUI/Tab.cpp:1329 msgid "" "For the Wipe Tower to work with the soluble supports, the support layers\n" "need to be synchronized with the object layers.\n" @@ -3586,7 +4034,7 @@ msgid "" "Shall I synchronize support layers in order to enable the Wipe Tower?" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1348 +#: src/slic3r/GUI/Tab.cpp:1347 msgid "" "Supports work better, if the following feature is enabled:\n" "- Detect bridging perimeters\n" @@ -3594,103 +4042,116 @@ msgid "" "Shall I adjust those settings for supports?" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1351 +#: src/slic3r/GUI/Tab.cpp:1350 msgid "Support Generator" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1393 +#: src/slic3r/GUI/Tab.cpp:1392 msgid "" "The %1% infill pattern is not supposed to work at 100%% density.\n" "\n" "Shall I switch to rectilinear fill pattern?" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1514 src/libslic3r/PrintConfig.cpp:2015 +#: src/slic3r/GUI/Tab.cpp:1502 src/slic3r/GUI/Tab.cpp:1557 +msgid "Filament Overrides" +msgstr "" + +#: src/slic3r/GUI/Tab.cpp:1503 src/slic3r/GUI/Tab.cpp:1562 +#: src/slic3r/GUI/Tab.cpp:2514 +msgid "Retraction" +msgstr "" + +#: src/slic3r/GUI/Tab.cpp:1612 src/libslic3r/PrintConfig.cpp:2030 msgid "Temperature" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1520 +#: src/slic3r/GUI/Tab.cpp:1618 msgid "Bed" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1525 +#: src/slic3r/GUI/Tab.cpp:1623 msgid "Cooling" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1526 src/libslic3r/PrintConfig.cpp:1321 -#: src/libslic3r/PrintConfig.cpp:2134 +#: src/slic3r/GUI/Tab.cpp:1624 src/libslic3r/PrintConfig.cpp:1335 +#: src/libslic3r/PrintConfig.cpp:2150 msgid "Enable" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1537 +#: src/slic3r/GUI/Tab.cpp:1635 msgid "Fan settings" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1538 +#: src/slic3r/GUI/Tab.cpp:1636 msgid "Fan speed" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1546 +#: src/slic3r/GUI/Tab.cpp:1644 msgid "Cooling thresholds" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1552 +#: src/slic3r/GUI/Tab.cpp:1650 msgid "Filament properties" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1556 +#: src/slic3r/GUI/Tab.cpp:1654 msgid "Print speed override" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1566 +#: src/slic3r/GUI/Tab.cpp:1664 +msgid "Wipe tower parameters" +msgstr "" + +#: src/slic3r/GUI/Tab.cpp:1667 msgid "Toolchange parameters with single extruder MM printers" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1581 +#: src/slic3r/GUI/Tab.cpp:1681 msgid "Ramming settings" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1599 src/slic3r/GUI/Tab.cpp:1985 +#: src/slic3r/GUI/Tab.cpp:1703 src/slic3r/GUI/Tab.cpp:2128 msgid "Custom G-code" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1600 src/slic3r/GUI/Tab.cpp:1986 -#: src/libslic3r/PrintConfig.cpp:1771 src/libslic3r/PrintConfig.cpp:1786 +#: src/slic3r/GUI/Tab.cpp:1704 src/slic3r/GUI/Tab.cpp:2129 +#: src/libslic3r/PrintConfig.cpp:1785 src/libslic3r/PrintConfig.cpp:1800 msgid "Start G-code" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1606 src/slic3r/GUI/Tab.cpp:1992 -#: src/libslic3r/PrintConfig.cpp:360 src/libslic3r/PrintConfig.cpp:370 +#: src/slic3r/GUI/Tab.cpp:1710 src/slic3r/GUI/Tab.cpp:2135 +#: src/libslic3r/PrintConfig.cpp:369 src/libslic3r/PrintConfig.cpp:379 msgid "End G-code" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1737 src/slic3r/GUI/Tab.cpp:1925 +#: src/slic3r/GUI/Tab.cpp:1843 src/slic3r/GUI/Tab.cpp:2068 msgid "Test" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1747 +#: src/slic3r/GUI/Tab.cpp:1853 msgid "Could not get a valid Printer Host reference" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1753 src/slic3r/GUI/Tab.cpp:1938 +#: src/slic3r/GUI/Tab.cpp:1859 src/slic3r/GUI/Tab.cpp:2081 msgid "Success!" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1768 +#: src/slic3r/GUI/Tab.cpp:1874 msgid "" "HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" "signed certificate." msgstr "" -#: src/slic3r/GUI/Tab.cpp:1781 +#: src/slic3r/GUI/Tab.cpp:1887 msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1782 +#: src/slic3r/GUI/Tab.cpp:1888 msgid "Open CA certificate file" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1810 +#: src/slic3r/GUI/Tab.cpp:1916 #, possible-c-format msgid "" "HTTPS CA File:\n" @@ -3700,278 +4161,283 @@ msgid "" "Store / Keychain." msgstr "" -#: src/slic3r/GUI/Tab.cpp:1850 src/slic3r/GUI/Tab.cpp:2051 +#: src/slic3r/GUI/Tab.cpp:1956 src/slic3r/GUI/Tab.cpp:2194 msgid "Size and coordinates" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1855 src/slic3r/GUI/Tab.cpp:2056 -#: src/slic3r/GUI/Tab.cpp:3040 +#: src/slic3r/GUI/Tab.cpp:1961 src/slic3r/GUI/Tab.cpp:2199 +#: src/slic3r/GUI/Tab.cpp:3256 msgid "Set" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1877 +#: src/slic3r/GUI/Tab.cpp:1993 msgid "Capabilities" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1882 +#: src/slic3r/GUI/Tab.cpp:1998 msgid "Number of extruders of the printer." msgstr "" -#: src/slic3r/GUI/Tab.cpp:1910 +#: src/slic3r/GUI/Tab.cpp:2023 +msgid "" +"Single Extruder Multi Material is selected, \n" +"and all extruders must have the same diameter.\n" +"Do you want to change the diameter for all extruders to first extruder " +"nozzle diameter value?" +msgstr "" + +#: src/slic3r/GUI/Tab.cpp:2026 src/slic3r/GUI/Tab.cpp:2484 +#: src/libslic3r/PrintConfig.cpp:1310 +msgid "Nozzle diameter" +msgstr "" + +#: src/slic3r/GUI/Tab.cpp:2053 msgid "USB/Serial connection" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1911 src/libslic3r/PrintConfig.cpp:1626 +#: src/slic3r/GUI/Tab.cpp:2054 src/libslic3r/PrintConfig.cpp:1640 msgid "Serial port" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1916 +#: src/slic3r/GUI/Tab.cpp:2059 msgid "Rescan serial ports" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1938 +#: src/slic3r/GUI/Tab.cpp:2081 msgid "Connection to printer works correctly." msgstr "" -#: src/slic3r/GUI/Tab.cpp:1941 +#: src/slic3r/GUI/Tab.cpp:2084 msgid "Connection failed." msgstr "" -#: src/slic3r/GUI/Tab.cpp:1954 src/slic3r/GUI/Tab.cpp:2111 +#: src/slic3r/GUI/Tab.cpp:2097 src/slic3r/GUI/Tab.cpp:2268 msgid "Print Host upload" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1998 src/libslic3r/PrintConfig.cpp:129 +#: src/slic3r/GUI/Tab.cpp:2141 src/libslic3r/PrintConfig.cpp:138 msgid "Before layer change G-code" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2004 src/libslic3r/PrintConfig.cpp:1042 +#: src/slic3r/GUI/Tab.cpp:2147 src/libslic3r/PrintConfig.cpp:1056 msgid "After layer change G-code" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2010 src/libslic3r/PrintConfig.cpp:2041 +#: src/slic3r/GUI/Tab.cpp:2153 src/libslic3r/PrintConfig.cpp:2056 msgid "Tool change G-code" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2016 +#: src/slic3r/GUI/Tab.cpp:2159 msgid "Between objects G-code (for sequential printing)" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2078 +#: src/slic3r/GUI/Tab.cpp:2231 msgid "Display" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2089 +#: src/slic3r/GUI/Tab.cpp:2246 msgid "Tilt" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2090 +#: src/slic3r/GUI/Tab.cpp:2247 msgid "Tilt time" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2096 src/slic3r/GUI/Tab.cpp:3367 +#: src/slic3r/GUI/Tab.cpp:2253 src/slic3r/GUI/Tab.cpp:3568 msgid "Corrections" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2173 src/slic3r/GUI/Tab.cpp:2246 -#: src/libslic3r/PrintConfig.cpp:1092 src/libslic3r/PrintConfig.cpp:1110 -#: src/libslic3r/PrintConfig.cpp:1128 src/libslic3r/PrintConfig.cpp:1145 -#: src/libslic3r/PrintConfig.cpp:1156 src/libslic3r/PrintConfig.cpp:1167 -#: src/libslic3r/PrintConfig.cpp:1178 +#: src/slic3r/GUI/Tab.cpp:2333 src/slic3r/GUI/Tab.cpp:2418 +#: src/libslic3r/PrintConfig.cpp:1106 src/libslic3r/PrintConfig.cpp:1124 +#: src/libslic3r/PrintConfig.cpp:1142 src/libslic3r/PrintConfig.cpp:1159 +#: src/libslic3r/PrintConfig.cpp:1170 src/libslic3r/PrintConfig.cpp:1181 +#: src/libslic3r/PrintConfig.cpp:1192 msgid "Machine limits" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2187 +#: src/slic3r/GUI/Tab.cpp:2347 msgid "Values in this column are for Normal mode" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2188 +#: src/slic3r/GUI/Tab.cpp:2348 msgid "Normal" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2193 +#: src/slic3r/GUI/Tab.cpp:2353 msgid "Values in this column are for Stealth mode" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2194 +#: src/slic3r/GUI/Tab.cpp:2354 msgid "Stealth" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2202 +#: src/slic3r/GUI/Tab.cpp:2362 msgid "Maximum feedrates" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2207 +#: src/slic3r/GUI/Tab.cpp:2367 msgid "Maximum accelerations" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2214 +#: src/slic3r/GUI/Tab.cpp:2374 msgid "Jerk limits" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2219 +#: src/slic3r/GUI/Tab.cpp:2379 msgid "Minimum feedrates" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2268 src/slic3r/GUI/Tab.cpp:2276 +#: src/slic3r/GUI/Tab.cpp:2443 src/slic3r/GUI/Tab.cpp:2451 msgid "Single extruder MM setup" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2277 +#: src/slic3r/GUI/Tab.cpp:2452 msgid "Single extruder multimaterial parameters" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2290 src/libslic3r/GCode/PreviewData.cpp:475 +#: src/slic3r/GUI/Tab.cpp:2465 src/libslic3r/GCode/PreviewData.cpp:477 #, possible-c-format msgid "Extruder %d" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2297 +#: src/slic3r/GUI/Tab.cpp:2483 +msgid "Do you want to change the diameter for all extruders?" +msgstr "" + +#: src/slic3r/GUI/Tab.cpp:2506 msgid "Layer height limits" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2302 +#: src/slic3r/GUI/Tab.cpp:2511 msgid "Position (for multi-extruder printers)" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2305 -msgid "Retraction" -msgstr "" - -#: src/slic3r/GUI/Tab.cpp:2308 +#: src/slic3r/GUI/Tab.cpp:2517 msgid "Only lift Z" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2321 +#: src/slic3r/GUI/Tab.cpp:2530 msgid "" "Retraction when tool is disabled (advanced settings for multi-extruder " "setups)" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2480 +#: src/slic3r/GUI/Tab.cpp:2693 msgid "" "The Wipe option is not available when using the Firmware Retraction mode.\n" "\n" "Shall I disable it in order to enable Firmware Retraction?" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2482 +#: src/slic3r/GUI/Tab.cpp:2695 msgid "Firmware Retraction" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2808 +#: src/slic3r/GUI/Tab.cpp:3024 #, possible-c-format msgid "Default preset (%s)" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2809 +#: src/slic3r/GUI/Tab.cpp:3025 #, possible-c-format msgid "Preset (%s)" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2826 +#: src/slic3r/GUI/Tab.cpp:3042 msgid "has the following unsaved changes:" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2829 +#: src/slic3r/GUI/Tab.cpp:3045 msgid "is not compatible with printer" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2830 +#: src/slic3r/GUI/Tab.cpp:3046 msgid "is not compatible with print profile" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2832 +#: src/slic3r/GUI/Tab.cpp:3048 msgid "and it has the following unsaved changes:" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2836 +#: src/slic3r/GUI/Tab.cpp:3052 msgid "Unsaved Changes" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2848 -msgid "Please check your object list before preset changing." -msgstr "" - -#: src/slic3r/GUI/Tab.cpp:2927 +#: src/slic3r/GUI/Tab.cpp:3143 msgid "%1% - Copy" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2950 +#: src/slic3r/GUI/Tab.cpp:3166 msgid "The supplied name is empty. It can't be saved." msgstr "" -#: src/slic3r/GUI/Tab.cpp:2955 +#: src/slic3r/GUI/Tab.cpp:3171 msgid "Cannot overwrite a system profile." msgstr "" -#: src/slic3r/GUI/Tab.cpp:2959 +#: src/slic3r/GUI/Tab.cpp:3175 msgid "Cannot overwrite an external profile." msgstr "" -#: src/slic3r/GUI/Tab.cpp:2985 +#: src/slic3r/GUI/Tab.cpp:3201 msgid "remove" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2985 +#: src/slic3r/GUI/Tab.cpp:3201 msgid "delete" msgstr "" #. TRN remove/delete -#: src/slic3r/GUI/Tab.cpp:2987 +#: src/slic3r/GUI/Tab.cpp:3203 msgid "Are you sure you want to %1% the selected preset?" msgstr "" -#: src/slic3r/GUI/Tab.cpp:2988 -msgid "Remove" -msgstr "" - #. TRN Remove/Delete -#: src/slic3r/GUI/Tab.cpp:2990 +#: src/slic3r/GUI/Tab.cpp:3206 msgid "%1% Preset" msgstr "" -#: src/slic3r/GUI/Tab.cpp:3116 +#: src/slic3r/GUI/Tab.cpp:3332 msgid "LOCKED LOCK" msgstr "" #. TRN Description for "LOCKED LOCK" -#: src/slic3r/GUI/Tab.cpp:3118 +#: src/slic3r/GUI/Tab.cpp:3334 msgid "" -"indicates that the settings are the same as the system values for the " -"current option group" +"indicates that the settings are the same as the system (or default) values " +"for the current option group" msgstr "" -#: src/slic3r/GUI/Tab.cpp:3120 +#: src/slic3r/GUI/Tab.cpp:3336 msgid "UNLOCKED LOCK" msgstr "" #. TRN Description for "UNLOCKED LOCK" -#: src/slic3r/GUI/Tab.cpp:3122 +#: src/slic3r/GUI/Tab.cpp:3338 msgid "" "indicates that some settings were changed and are not equal to the system " -"values for the current option group.\n" +"(or default) values for the current option group.\n" "Click the UNLOCKED LOCK icon to reset all settings for current option group " -"to the system values." +"to the system (or default) values." msgstr "" -#: src/slic3r/GUI/Tab.cpp:3127 +#: src/slic3r/GUI/Tab.cpp:3343 msgid "WHITE BULLET" msgstr "" #. TRN Description for "WHITE BULLET" -#: src/slic3r/GUI/Tab.cpp:3129 +#: src/slic3r/GUI/Tab.cpp:3345 msgid "" -"for the left button: \tindicates a non-system preset,\n" +"for the left button: \tindicates a non-system (or non-default) preset,\n" "for the right button: \tindicates that the settings hasn't been modified." msgstr "" -#: src/slic3r/GUI/Tab.cpp:3103 +#: src/slic3r/GUI/Tab.cpp:3348 msgid "BACK ARROW" msgstr "" #. TRN Description for "BACK ARROW" -#: src/slic3r/GUI/Tab.cpp:3134 +#: src/slic3r/GUI/Tab.cpp:3350 msgid "" "indicates that the settings were changed and are not equal to the last saved " "preset for the current option group.\n" @@ -3979,30 +4445,31 @@ msgid "" "to the last saved preset." msgstr "" -#: src/slic3r/GUI/Tab.cpp:3159 +#: src/slic3r/GUI/Tab.cpp:3360 msgid "" -"LOCKED LOCK icon indicates that the settings are the same as the system " -"values for the current option group" +"LOCKED LOCK icon indicates that the settings are the same as the system (or " +"default) values for the current option group" msgstr "" -#: src/slic3r/GUI/Tab.cpp:3161 +#: src/slic3r/GUI/Tab.cpp:3362 msgid "" "UNLOCKED LOCK icon indicates that some settings were changed and are not " -"equal to the system values for the current option group.\n" -"Click to reset all settings for current option group to the system values." +"equal to the system (or default) values for the current option group.\n" +"Click to reset all settings for current option group to the system (or " +"default) values." msgstr "" -#: src/slic3r/GUI/Tab.cpp:3164 -msgid "WHITE BULLET icon indicates a non system preset." +#: src/slic3r/GUI/Tab.cpp:3365 +msgid "WHITE BULLET icon indicates a non system (or non default) preset." msgstr "" -#: src/slic3r/GUI/Tab.cpp:3167 +#: src/slic3r/GUI/Tab.cpp:3368 msgid "" "WHITE BULLET icon indicates that the settings are the same as in the last " "saved preset for the current option group." msgstr "" -#: src/slic3r/GUI/Tab.cpp:3169 +#: src/slic3r/GUI/Tab.cpp:3370 msgid "" "BACK ARROW icon indicates that the settings were changed and are not equal " "to the last saved preset for the current option group.\n" @@ -4010,25 +4477,26 @@ msgid "" "preset." msgstr "" -#: src/slic3r/GUI/Tab.cpp:3175 +#: src/slic3r/GUI/Tab.cpp:3376 msgid "" -"LOCKED LOCK icon indicates that the value is the same as the system value." +"LOCKED LOCK icon indicates that the value is the same as the system (or " +"default) value." msgstr "" -#: src/slic3r/GUI/Tab.cpp:3176 +#: src/slic3r/GUI/Tab.cpp:3377 msgid "" "UNLOCKED LOCK icon indicates that the value was changed and is not equal to " -"the system value.\n" -"Click to reset current value to the system value." +"the system (or default) value.\n" +"Click to reset current value to the system (or default) value." msgstr "" -#: src/slic3r/GUI/Tab.cpp:3182 +#: src/slic3r/GUI/Tab.cpp:3383 msgid "" "WHITE BULLET icon indicates that the value is the same as in the last saved " "preset." msgstr "" -#: src/slic3r/GUI/Tab.cpp:3183 +#: src/slic3r/GUI/Tab.cpp:3384 msgid "" "BACK ARROW icon indicates that the value was changed and is not equal to the " "last saved preset.\n" @@ -4036,80 +4504,81 @@ msgid "" msgstr "" #. TRN Preset -#: src/slic3r/GUI/Tab.cpp:3296 +#: src/slic3r/GUI/Tab.cpp:3497 #, possible-c-format msgid "Save %s as:" msgstr "" -#: src/slic3r/GUI/Tab.cpp:3340 +#: src/slic3r/GUI/Tab.cpp:3541 msgid "the following suffix is not allowed:" msgstr "" -#: src/slic3r/GUI/Tab.cpp:3344 +#: src/slic3r/GUI/Tab.cpp:3545 msgid "The supplied name is not available." msgstr "" -#: src/slic3r/GUI/Tab.cpp:3357 +#: src/slic3r/GUI/Tab.cpp:3558 msgid "Material" msgstr "" -#: src/slic3r/GUI/Tab.cpp:3359 src/slic3r/GUI/Tab.cpp:3450 +#: src/slic3r/GUI/Tab.cpp:3560 src/slic3r/GUI/Tab.cpp:3651 +#: src/slic3r/GUI/wxExtensions.cpp:454 msgid "Layers" msgstr "" -#: src/slic3r/GUI/Tab.cpp:3363 +#: src/slic3r/GUI/Tab.cpp:3564 msgid "Exposure" msgstr "" -#: src/slic3r/GUI/Tab.cpp:3458 +#: src/slic3r/GUI/Tab.cpp:3659 msgid "Support head" msgstr "" -#: src/slic3r/GUI/Tab.cpp:3463 +#: src/slic3r/GUI/Tab.cpp:3664 msgid "Support pillar" msgstr "" -#: src/slic3r/GUI/Tab.cpp:3473 +#: src/slic3r/GUI/Tab.cpp:3675 msgid "Connection of the support sticks and junctions" msgstr "" -#: src/slic3r/GUI/Tab.cpp:3478 +#: src/slic3r/GUI/Tab.cpp:3680 msgid "Automatic generation" msgstr "" -#: src/slic3r/GUI/Tab.cpp:3540 +#: src/slic3r/GUI/Tab.cpp:3747 msgid "Head penetration should not be greater than the head width." msgstr "" -#: src/slic3r/GUI/Tab.cpp:3541 +#: src/slic3r/GUI/Tab.cpp:3751 msgid "Invalid Head penetration" msgstr "" -#: src/slic3r/GUI/Tab.cpp:3553 +#: src/slic3r/GUI/Tab.cpp:3767 msgid "Pinhead diameter should be smaller than the pillar diameter." msgstr "" -#: src/slic3r/GUI/Tab.cpp:3554 +#: src/slic3r/GUI/Tab.cpp:3771 msgid "Invalid pinhead diameter" msgstr "" -#: src/slic3r/GUI/Tab.hpp:318 src/slic3r/GUI/Tab.hpp:411 +#: src/slic3r/GUI/Tab.hpp:324 src/slic3r/GUI/Tab.hpp:422 msgid "Print Settings" msgstr "" -#: src/slic3r/GUI/Tab.hpp:337 +#: src/slic3r/GUI/Tab.hpp:348 msgid "Filament Settings" msgstr "" -#: src/slic3r/GUI/Tab.hpp:372 +#: src/slic3r/GUI/Tab.hpp:383 msgid "Printer Settings" msgstr "" -#: src/slic3r/GUI/Tab.hpp:396 +#: src/slic3r/GUI/Tab.hpp:407 msgid "Material Settings" msgstr "" -#: src/slic3r/GUI/Tab.hpp:423 +#: src/slic3r/GUI/Tab.hpp:434 msgid "Save preset" msgstr "" @@ -4122,39 +4591,39 @@ msgstr "" msgid "New version of %s is available" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:46 +#: src/slic3r/GUI/UpdateDialogs.cpp:45 msgid "Current version:" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:48 +#: src/slic3r/GUI/UpdateDialogs.cpp:47 msgid "New version:" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:56 +#: src/slic3r/GUI/UpdateDialogs.cpp:55 msgid "Changelog && Download" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:63 src/slic3r/GUI/UpdateDialogs.cpp:126 +#: src/slic3r/GUI/UpdateDialogs.cpp:62 src/slic3r/GUI/UpdateDialogs.cpp:125 msgid "Open changelog page" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:68 +#: src/slic3r/GUI/UpdateDialogs.cpp:67 msgid "Open download page" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:74 +#: src/slic3r/GUI/UpdateDialogs.cpp:73 msgid "Don't notify about new releases any more" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:92 src/slic3r/GUI/UpdateDialogs.cpp:206 +#: src/slic3r/GUI/UpdateDialogs.cpp:91 src/slic3r/GUI/UpdateDialogs.cpp:205 msgid "Configuration update" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:92 +#: src/slic3r/GUI/UpdateDialogs.cpp:91 msgid "Configuration update is available" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:95 +#: src/slic3r/GUI/UpdateDialogs.cpp:94 msgid "" "Would you like to install it?\n" "\n" @@ -4164,21 +4633,21 @@ msgid "" "Updated configuration bundles:" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:116 +#: src/slic3r/GUI/UpdateDialogs.cpp:115 msgid "Comment:" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:150 +#: src/slic3r/GUI/UpdateDialogs.cpp:149 #, possible-c-format msgid "%s incompatibility" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:151 +#: src/slic3r/GUI/UpdateDialogs.cpp:150 #, possible-c-format msgid "%s configuration is incompatible" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:156 +#: src/slic3r/GUI/UpdateDialogs.cpp:155 #, possible-c-format msgid "" "This version of %s is not compatible with currently installed configuration " @@ -4191,25 +4660,25 @@ msgid "" "existing configuration before installing files compatible with this %s.\n" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:165 +#: src/slic3r/GUI/UpdateDialogs.cpp:164 #, possible-c-format msgid "This %s version: %s" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:170 +#: src/slic3r/GUI/UpdateDialogs.cpp:169 msgid "Incompatible bundles:" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:186 +#: src/slic3r/GUI/UpdateDialogs.cpp:185 #, possible-c-format msgid "Exit %s" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:189 +#: src/slic3r/GUI/UpdateDialogs.cpp:188 msgid "Re-configure" msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:210 +#: src/slic3r/GUI/UpdateDialogs.cpp:209 #, possible-c-format msgid "" "%s now uses an updated configuration structure.\n" @@ -4225,7 +4694,7 @@ msgid "" "choose whether to enable automatic preset updates." msgstr "" -#: src/slic3r/GUI/UpdateDialogs.cpp:226 +#: src/slic3r/GUI/UpdateDialogs.cpp:225 msgid "For more information please visit our wiki page:" msgstr "" @@ -4318,21 +4787,37 @@ msgstr "" msgid "Show advanced settings" msgstr "" -#: src/slic3r/GUI/wxExtensions.cpp:444 +#: src/slic3r/GUI/wxExtensions.cpp:443 msgid "Instances" msgstr "" -#: src/slic3r/GUI/wxExtensions.cpp:451 src/slic3r/GUI/wxExtensions.cpp:518 +#: src/slic3r/GUI/wxExtensions.cpp:447 src/slic3r/GUI/wxExtensions.cpp:592 #, possible-c-format msgid "Instance %d" msgstr "" -#: src/slic3r/GUI/wxExtensions.cpp:2508 +#: src/slic3r/GUI/wxExtensions.cpp:486 +msgid "Range" +msgstr "" + +#: src/slic3r/GUI/wxExtensions.cpp:2570 +msgid "One layer mode" +msgstr "" + +#: src/slic3r/GUI/wxExtensions.cpp:2571 +msgid "Add/Del color change" +msgstr "" + +#: src/slic3r/GUI/wxExtensions.cpp:2572 +msgid "Discard all color changes" +msgstr "" + +#: src/slic3r/GUI/wxExtensions.cpp:2832 #, possible-c-format msgid "Switch to the %s mode" msgstr "" -#: src/slic3r/GUI/wxExtensions.cpp:2509 +#: src/slic3r/GUI/wxExtensions.cpp:2833 #, possible-c-format msgid "Current mode is %s" msgstr "" @@ -4382,17 +4867,17 @@ msgstr "" msgid "Could not connect to Prusa SLA" msgstr "" -#: src/slic3r/Utils/PresetUpdater.cpp:584 +#: src/slic3r/Utils/PresetUpdater.cpp:614 #, possible-c-format msgid "requires min. %s and max. %s" msgstr "" -#: src/slic3r/Utils/PresetUpdater.cpp:589 +#: src/slic3r/Utils/PresetUpdater.cpp:619 #, possible-c-format msgid "requires min. %s" msgstr "" -#: src/slic3r/Utils/PresetUpdater.cpp:591 +#: src/slic3r/Utils/PresetUpdater.cpp:621 #, possible-c-format msgid "requires max. %s" msgstr "" @@ -4478,215 +4963,219 @@ msgstr "" msgid "Model repair failed: \n" msgstr "" -#: src/libslic3r/Zipper.cpp:35 +#: src/libslic3r/Zipper.cpp:32 msgid "undefined error" msgstr "" -#: src/libslic3r/Zipper.cpp:37 +#: src/libslic3r/Zipper.cpp:34 msgid "too many files" msgstr "" -#: src/libslic3r/Zipper.cpp:39 +#: src/libslic3r/Zipper.cpp:36 msgid "file too large" msgstr "" -#: src/libslic3r/Zipper.cpp:41 +#: src/libslic3r/Zipper.cpp:38 msgid "unsupported method" msgstr "" -#: src/libslic3r/Zipper.cpp:43 +#: src/libslic3r/Zipper.cpp:40 msgid "unsupported encryption" msgstr "" -#: src/libslic3r/Zipper.cpp:45 +#: src/libslic3r/Zipper.cpp:42 msgid "unsupported feature" msgstr "" -#: src/libslic3r/Zipper.cpp:47 +#: src/libslic3r/Zipper.cpp:44 msgid "failed finding central directory" msgstr "" -#: src/libslic3r/Zipper.cpp:49 +#: src/libslic3r/Zipper.cpp:46 msgid "not a ZIP archive" msgstr "" -#: src/libslic3r/Zipper.cpp:51 +#: src/libslic3r/Zipper.cpp:48 msgid "invalid header or archive is corrupted" msgstr "" -#: src/libslic3r/Zipper.cpp:53 +#: src/libslic3r/Zipper.cpp:50 msgid "unsupported multidisk archive" msgstr "" -#: src/libslic3r/Zipper.cpp:55 +#: src/libslic3r/Zipper.cpp:52 msgid "decompression failed or archive is corrupted" msgstr "" -#: src/libslic3r/Zipper.cpp:57 +#: src/libslic3r/Zipper.cpp:54 msgid "compression failed" msgstr "" -#: src/libslic3r/Zipper.cpp:59 +#: src/libslic3r/Zipper.cpp:56 msgid "unexpected decompressed size" msgstr "" -#: src/libslic3r/Zipper.cpp:61 +#: src/libslic3r/Zipper.cpp:58 msgid "CRC-32 check failed" msgstr "" -#: src/libslic3r/Zipper.cpp:63 +#: src/libslic3r/Zipper.cpp:60 msgid "unsupported central directory size" msgstr "" -#: src/libslic3r/Zipper.cpp:65 +#: src/libslic3r/Zipper.cpp:62 msgid "allocation failed" msgstr "" -#: src/libslic3r/Zipper.cpp:67 +#: src/libslic3r/Zipper.cpp:64 msgid "file open failed" msgstr "" -#: src/libslic3r/Zipper.cpp:69 +#: src/libslic3r/Zipper.cpp:66 msgid "file create failed" msgstr "" -#: src/libslic3r/Zipper.cpp:71 +#: src/libslic3r/Zipper.cpp:68 msgid "file write failed" msgstr "" -#: src/libslic3r/Zipper.cpp:73 +#: src/libslic3r/Zipper.cpp:70 msgid "file read failed" msgstr "" -#: src/libslic3r/Zipper.cpp:75 +#: src/libslic3r/Zipper.cpp:72 msgid "file close failed" msgstr "" -#: src/libslic3r/Zipper.cpp:77 +#: src/libslic3r/Zipper.cpp:74 msgid "file seek failed" msgstr "" -#: src/libslic3r/Zipper.cpp:79 +#: src/libslic3r/Zipper.cpp:76 msgid "file stat failed" msgstr "" -#: src/libslic3r/Zipper.cpp:81 +#: src/libslic3r/Zipper.cpp:78 msgid "invalid parameter" msgstr "" -#: src/libslic3r/Zipper.cpp:83 +#: src/libslic3r/Zipper.cpp:80 msgid "invalid filename" msgstr "" -#: src/libslic3r/Zipper.cpp:85 +#: src/libslic3r/Zipper.cpp:82 msgid "buffer too small" msgstr "" -#: src/libslic3r/Zipper.cpp:87 +#: src/libslic3r/Zipper.cpp:84 msgid "internal error" msgstr "" -#: src/libslic3r/Zipper.cpp:89 +#: src/libslic3r/Zipper.cpp:86 msgid "file not found" msgstr "" -#: src/libslic3r/Zipper.cpp:91 +#: src/libslic3r/Zipper.cpp:88 msgid "archive is too large" msgstr "" -#: src/libslic3r/Zipper.cpp:93 +#: src/libslic3r/Zipper.cpp:90 msgid "validation failed" msgstr "" -#: src/libslic3r/Zipper.cpp:95 +#: src/libslic3r/Zipper.cpp:92 msgid "write calledback failed" msgstr "" -#: src/libslic3r/Zipper.cpp:105 +#: src/libslic3r/Zipper.cpp:102 msgid "Error with zip archive" msgstr "" -#: src/libslic3r/Print.cpp:1135 +#: src/libslic3r/Print.cpp:1093 msgid "All objects are outside of the print volume." msgstr "" -#: src/libslic3r/Print.cpp:1162 +#: src/libslic3r/Print.cpp:1120 msgid "Some objects are too close; your extruder will collide with them." msgstr "" -#: src/libslic3r/Print.cpp:1177 +#: src/libslic3r/Print.cpp:1135 msgid "" "Some objects are too tall and cannot be printed without extruder collisions." msgstr "" -#: src/libslic3r/Print.cpp:1187 +#: src/libslic3r/Print.cpp:1145 msgid "The Spiral Vase option can only be used when printing a single object." msgstr "" -#: src/libslic3r/Print.cpp:1189 +#: src/libslic3r/Print.cpp:1147 msgid "" "The Spiral Vase option can only be used when printing single material " "objects." msgstr "" -#: src/libslic3r/Print.cpp:1195 +#: src/libslic3r/Print.cpp:1155 msgid "" -"All extruders must have the same diameter for single extruder multimaterial " -"printer." +"The wipe tower is only supported if all extruders have the same nozzle " +"diameter and use filaments of the same diameter." msgstr "" -#: src/libslic3r/Print.cpp:1200 +#: src/libslic3r/Print.cpp:1159 msgid "" "The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter " "and Repetier G-code flavors." msgstr "" -#: src/libslic3r/Print.cpp:1202 +#: src/libslic3r/Print.cpp:1161 msgid "" "The Wipe Tower is currently only supported with the relative extruder " "addressing (use_relative_e_distances=1)." msgstr "" -#: src/libslic3r/Print.cpp:1223 +#: src/libslic3r/Print.cpp:1165 +msgid "All extruders must have the same diameter for the Wipe Tower." +msgstr "" + +#: src/libslic3r/Print.cpp:1186 msgid "" "The Wipe Tower is only supported for multiple objects if they have equal " "layer heights" msgstr "" -#: src/libslic3r/Print.cpp:1225 +#: src/libslic3r/Print.cpp:1188 msgid "" "The Wipe Tower is only supported for multiple objects if they are printed " "over an equal number of raft layers" msgstr "" -#: src/libslic3r/Print.cpp:1227 +#: src/libslic3r/Print.cpp:1190 msgid "" "The Wipe Tower is only supported for multiple objects if they are printed " "with the same support_material_contact_distance" msgstr "" -#: src/libslic3r/Print.cpp:1229 +#: src/libslic3r/Print.cpp:1192 msgid "" "The Wipe Tower is only supported for multiple objects if they are sliced " "equally." msgstr "" -#: src/libslic3r/Print.cpp:1258 +#: src/libslic3r/Print.cpp:1220 msgid "" "The Wipe tower is only supported if all objects have the same layer height " "profile" msgstr "" -#: src/libslic3r/Print.cpp:1268 +#: src/libslic3r/Print.cpp:1230 msgid "The supplied settings will cause an empty print." msgstr "" -#: src/libslic3r/Print.cpp:1285 +#: src/libslic3r/Print.cpp:1247 msgid "" "One or more object were assigned an extruder that the printer does not have." msgstr "" -#: src/libslic3r/Print.cpp:1294 +#: src/libslic3r/Print.cpp:1256 msgid "" "Printing with multiple extruders of differing nozzle diameters. If support " "is to be printed with the current extruder (support_material_extruder == 0 " @@ -4694,13 +5183,13 @@ msgid "" "same diameter." msgstr "" -#: src/libslic3r/Print.cpp:1302 +#: src/libslic3r/Print.cpp:1264 msgid "" "For the Wipe Tower to work with the soluble supports, the support layers " "need to be synchronized with the object layers." msgstr "" -#: src/libslic3r/Print.cpp:1306 +#: src/libslic3r/Print.cpp:1268 msgid "" "The Wipe Tower currently supports the non-soluble supports only if they are " "printed with the current extruder without triggering a tool change. (both " @@ -4708,83 +5197,90 @@ msgid "" "set to 0)." msgstr "" -#: src/libslic3r/Print.cpp:1328 +#: src/libslic3r/Print.cpp:1290 msgid "First layer height can't be greater than nozzle diameter" msgstr "" -#: src/libslic3r/Print.cpp:1332 +#: src/libslic3r/Print.cpp:1294 msgid "Layer height can't be greater than nozzle diameter" msgstr "" -#: src/libslic3r/Print.cpp:1476 +#: src/libslic3r/Print.cpp:1438 msgid "Infilling layers" msgstr "" -#: src/libslic3r/Print.cpp:1484 +#: src/libslic3r/Print.cpp:1446 msgid "Generating skirt" msgstr "" -#: src/libslic3r/Print.cpp:1492 +#: src/libslic3r/Print.cpp:1454 msgid "Generating brim" msgstr "" -#: src/libslic3r/Print.cpp:1520 +#: src/libslic3r/Print.cpp:1482 msgid "Exporting G-code" msgstr "" -#: src/libslic3r/Print.cpp:1524 +#: src/libslic3r/Print.cpp:1486 msgid "Generating G-code" msgstr "" -#: src/libslic3r/SLAPrint.cpp:57 +#: src/libslic3r/SLAPrint.cpp:58 msgid "Slicing model" msgstr "" -#: src/libslic3r/SLAPrint.cpp:58 src/libslic3r/SLAPrint.cpp:819 +#: src/libslic3r/SLAPrint.cpp:59 src/libslic3r/SLAPrint.cpp:871 msgid "Generating support points" msgstr "" -#: src/libslic3r/SLAPrint.cpp:59 +#: src/libslic3r/SLAPrint.cpp:60 msgid "Generating support tree" msgstr "" -#: src/libslic3r/SLAPrint.cpp:60 +#: src/libslic3r/SLAPrint.cpp:61 msgid "Generating pad" msgstr "" -#: src/libslic3r/SLAPrint.cpp:61 +#: src/libslic3r/SLAPrint.cpp:62 msgid "Slicing supports" msgstr "" -#: src/libslic3r/SLAPrint.cpp:78 +#: src/libslic3r/SLAPrint.cpp:79 msgid "Merging slices and calculating statistics" msgstr "" -#: src/libslic3r/SLAPrint.cpp:79 +#: src/libslic3r/SLAPrint.cpp:80 msgid "Rasterizing layers" msgstr "" -#: src/libslic3r/SLAPrint.cpp:622 +#: src/libslic3r/SLAPrint.cpp:650 msgid "" "Cannot proceed without support points! Add support points or disable support " "generation." msgstr "" -#: src/libslic3r/SLAPrint.cpp:634 +#: src/libslic3r/SLAPrint.cpp:664 msgid "Elevation is too low for object." msgstr "" -#. TRN To be shown at the status bar on SLA slicing error. -#: src/libslic3r/SLAPrint.cpp:719 -msgid "Slicing had to be stopped due to an internal error." +#: src/libslic3r/SLAPrint.cpp:670 +msgid "" +"The endings of the support pillars will be deployed on the gap between the " +"object and the pad. 'Support base safety distance' has to be greater than " +"the 'Pad object gap' parameter to avoid this." msgstr "" -#: src/libslic3r/SLAPrint.cpp:867 src/libslic3r/SLAPrint.cpp:877 -#: src/libslic3r/SLAPrint.cpp:925 +#: src/libslic3r/SLAPrint.cpp:759 +msgid "" +"Slicing had to be stopped due to an internal error: Inconsistent slice index." +msgstr "" + +#: src/libslic3r/SLAPrint.cpp:954 src/libslic3r/SLAPrint.cpp:964 +#: src/libslic3r/SLAPrint.cpp:1005 msgid "Visualizing supports" msgstr "" -#: src/libslic3r/SLAPrint.cpp:1463 +#: src/libslic3r/SLAPrint.cpp:1537 msgid "Slicing done" msgstr "" @@ -4800,101 +5296,109 @@ msgstr "" msgid "Bed shape" msgstr "" -#: src/libslic3r/PrintConfig.cpp:58 +#: src/libslic3r/PrintConfig.cpp:56 +msgid "Bed custom texture" +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:61 +msgid "Bed custom model" +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:68 msgid "" "This setting controls the height (and thus the total number) of the slices/" "layers. Thinner layers give better accuracy but take more time to print." msgstr "" -#: src/libslic3r/PrintConfig.cpp:65 +#: src/libslic3r/PrintConfig.cpp:75 msgid "Max print height" msgstr "" -#: src/libslic3r/PrintConfig.cpp:66 +#: src/libslic3r/PrintConfig.cpp:76 msgid "" "Set this to the maximum height that can be reached by your extruder while " "printing." msgstr "" -#: src/libslic3r/PrintConfig.cpp:72 +#: src/libslic3r/PrintConfig.cpp:82 msgid "Slice gap closing radius" msgstr "" -#: src/libslic3r/PrintConfig.cpp:74 +#: src/libslic3r/PrintConfig.cpp:84 msgid "" "Cracks smaller than 2x gap closing radius are being filled during the " "triangle mesh slicing. The gap closing operation may reduce the final print " "resolution, therefore it is advisable to keep the value reasonably low." msgstr "" -#: src/libslic3r/PrintConfig.cpp:82 +#: src/libslic3r/PrintConfig.cpp:92 msgid "Hostname, IP or URL" msgstr "" -#: src/libslic3r/PrintConfig.cpp:83 +#: src/libslic3r/PrintConfig.cpp:93 msgid "" "Slic3r can upload G-code files to a printer host. This field should contain " "the hostname, IP address or URL of the printer host instance." msgstr "" -#: src/libslic3r/PrintConfig.cpp:89 +#: src/libslic3r/PrintConfig.cpp:99 msgid "API Key / Password" msgstr "" -#: src/libslic3r/PrintConfig.cpp:90 +#: src/libslic3r/PrintConfig.cpp:100 msgid "" "Slic3r can upload G-code files to a printer host. This field should contain " "the API Key or the password required for authentication." msgstr "" -#: src/libslic3r/PrintConfig.cpp:96 +#: src/libslic3r/PrintConfig.cpp:106 msgid "HTTPS CA File" msgstr "" -#: src/libslic3r/PrintConfig.cpp:97 +#: src/libslic3r/PrintConfig.cpp:107 msgid "" "Custom CA certificate file can be specified for HTTPS OctoPrint connections, " "in crt/pem format. If left blank, the default OS CA certificate repository " "is used." msgstr "" -#: src/libslic3r/PrintConfig.cpp:112 +#: src/libslic3r/PrintConfig.cpp:121 msgid "Avoid crossing perimeters" msgstr "" -#: src/libslic3r/PrintConfig.cpp:113 +#: src/libslic3r/PrintConfig.cpp:122 msgid "" "Optimize travel moves in order to minimize the crossing of perimeters. This " "is mostly useful with Bowden extruders which suffer from oozing. This " "feature slows down both the print and the G-code generation." msgstr "" -#: src/libslic3r/PrintConfig.cpp:120 src/libslic3r/PrintConfig.cpp:2012 +#: src/libslic3r/PrintConfig.cpp:129 src/libslic3r/PrintConfig.cpp:2027 msgid "Other layers" msgstr "" -#: src/libslic3r/PrintConfig.cpp:121 +#: src/libslic3r/PrintConfig.cpp:130 msgid "" "Bed temperature for layers after the first one. Set this to zero to disable " "bed temperature control commands in the output." msgstr "" -#: src/libslic3r/PrintConfig.cpp:123 +#: src/libslic3r/PrintConfig.cpp:132 msgid "Bed temperature" msgstr "" -#: src/libslic3r/PrintConfig.cpp:130 +#: src/libslic3r/PrintConfig.cpp:139 msgid "" "This custom code is inserted at every layer change, right before the Z move. " "Note that you can use placeholder variables for all Slic3r settings as well " "as [layer_num] and [layer_z]." msgstr "" -#: src/libslic3r/PrintConfig.cpp:140 +#: src/libslic3r/PrintConfig.cpp:149 msgid "Between objects G-code" msgstr "" -#: src/libslic3r/PrintConfig.cpp:141 +#: src/libslic3r/PrintConfig.cpp:150 msgid "" "This code is inserted between objects when using sequential printing. By " "default extruder and bed temperature are reset using non-wait command; " @@ -4904,70 +5408,70 @@ msgid "" "S[first_layer_temperature]\" command wherever you want." msgstr "" -#: src/libslic3r/PrintConfig.cpp:152 +#: src/libslic3r/PrintConfig.cpp:161 msgid "Number of solid layers to generate on bottom surfaces." msgstr "" -#: src/libslic3r/PrintConfig.cpp:153 +#: src/libslic3r/PrintConfig.cpp:162 msgid "Bottom solid layers" msgstr "" -#: src/libslic3r/PrintConfig.cpp:158 +#: src/libslic3r/PrintConfig.cpp:167 msgid "Bridge" msgstr "" -#: src/libslic3r/PrintConfig.cpp:159 +#: src/libslic3r/PrintConfig.cpp:168 msgid "" "This is the acceleration your printer will use for bridges. Set zero to " "disable acceleration control for bridges." msgstr "" -#: src/libslic3r/PrintConfig.cpp:161 src/libslic3r/PrintConfig.cpp:304 -#: src/libslic3r/PrintConfig.cpp:826 src/libslic3r/PrintConfig.cpp:947 -#: src/libslic3r/PrintConfig.cpp:1116 src/libslic3r/PrintConfig.cpp:1169 -#: src/libslic3r/PrintConfig.cpp:1180 src/libslic3r/PrintConfig.cpp:1369 +#: src/libslic3r/PrintConfig.cpp:170 src/libslic3r/PrintConfig.cpp:313 +#: src/libslic3r/PrintConfig.cpp:840 src/libslic3r/PrintConfig.cpp:961 +#: src/libslic3r/PrintConfig.cpp:1130 src/libslic3r/PrintConfig.cpp:1183 +#: src/libslic3r/PrintConfig.cpp:1194 src/libslic3r/PrintConfig.cpp:1383 msgid "mm/s²" msgstr "" -#: src/libslic3r/PrintConfig.cpp:167 +#: src/libslic3r/PrintConfig.cpp:176 msgid "Bridging angle" msgstr "" -#: src/libslic3r/PrintConfig.cpp:169 +#: src/libslic3r/PrintConfig.cpp:178 msgid "" "Bridging angle override. If left to zero, the bridging angle will be " "calculated automatically. Otherwise the provided angle will be used for all " "bridges. Use 180° for zero angle." msgstr "" -#: src/libslic3r/PrintConfig.cpp:172 src/libslic3r/PrintConfig.cpp:744 -#: src/libslic3r/PrintConfig.cpp:1605 src/libslic3r/PrintConfig.cpp:1615 -#: src/libslic3r/PrintConfig.cpp:1843 src/libslic3r/PrintConfig.cpp:1997 -#: src/libslic3r/PrintConfig.cpp:2181 src/libslic3r/PrintConfig.cpp:2498 -#: src/libslic3r/PrintConfig.cpp:2607 +#: src/libslic3r/PrintConfig.cpp:181 src/libslic3r/PrintConfig.cpp:758 +#: src/libslic3r/PrintConfig.cpp:1619 src/libslic3r/PrintConfig.cpp:1629 +#: src/libslic3r/PrintConfig.cpp:1858 src/libslic3r/PrintConfig.cpp:2012 +#: src/libslic3r/PrintConfig.cpp:2197 src/libslic3r/PrintConfig.cpp:2582 +#: src/libslic3r/PrintConfig.cpp:2693 msgid "°" msgstr "" -#: src/libslic3r/PrintConfig.cpp:178 +#: src/libslic3r/PrintConfig.cpp:187 msgid "Bridges fan speed" msgstr "" -#: src/libslic3r/PrintConfig.cpp:179 +#: src/libslic3r/PrintConfig.cpp:188 msgid "This fan speed is enforced during all bridges and overhangs." msgstr "" -#: src/libslic3r/PrintConfig.cpp:180 src/libslic3r/PrintConfig.cpp:756 -#: src/libslic3r/PrintConfig.cpp:1189 src/libslic3r/PrintConfig.cpp:1252 -#: src/libslic3r/PrintConfig.cpp:1497 src/libslic3r/PrintConfig.cpp:2295 -#: src/libslic3r/PrintConfig.cpp:2537 +#: src/libslic3r/PrintConfig.cpp:189 src/libslic3r/PrintConfig.cpp:770 +#: src/libslic3r/PrintConfig.cpp:1203 src/libslic3r/PrintConfig.cpp:1266 +#: src/libslic3r/PrintConfig.cpp:1511 src/libslic3r/PrintConfig.cpp:2366 +#: src/libslic3r/PrintConfig.cpp:2623 msgid "%" msgstr "" -#: src/libslic3r/PrintConfig.cpp:187 +#: src/libslic3r/PrintConfig.cpp:196 msgid "Bridge flow ratio" msgstr "" -#: src/libslic3r/PrintConfig.cpp:189 +#: src/libslic3r/PrintConfig.cpp:198 msgid "" "This factor affects the amount of plastic for bridging. You can decrease it " "slightly to pull the extrudates and prevent sagging, although default " @@ -4975,83 +5479,83 @@ msgid "" "before tweaking this." msgstr "" -#: src/libslic3r/PrintConfig.cpp:199 +#: src/libslic3r/PrintConfig.cpp:208 msgid "Bridges" msgstr "" -#: src/libslic3r/PrintConfig.cpp:201 +#: src/libslic3r/PrintConfig.cpp:210 msgid "Speed for printing bridges." msgstr "" -#: src/libslic3r/PrintConfig.cpp:202 src/libslic3r/PrintConfig.cpp:578 -#: src/libslic3r/PrintConfig.cpp:586 src/libslic3r/PrintConfig.cpp:595 -#: src/libslic3r/PrintConfig.cpp:603 src/libslic3r/PrintConfig.cpp:630 -#: src/libslic3r/PrintConfig.cpp:649 src/libslic3r/PrintConfig.cpp:885 -#: src/libslic3r/PrintConfig.cpp:1012 src/libslic3r/PrintConfig.cpp:1098 -#: src/libslic3r/PrintConfig.cpp:1134 src/libslic3r/PrintConfig.cpp:1147 -#: src/libslic3r/PrintConfig.cpp:1158 src/libslic3r/PrintConfig.cpp:1211 -#: src/libslic3r/PrintConfig.cpp:1270 src/libslic3r/PrintConfig.cpp:1398 -#: src/libslic3r/PrintConfig.cpp:1572 src/libslic3r/PrintConfig.cpp:1581 -#: src/libslic3r/PrintConfig.cpp:1976 src/libslic3r/PrintConfig.cpp:2088 +#: src/libslic3r/PrintConfig.cpp:211 src/libslic3r/PrintConfig.cpp:592 +#: src/libslic3r/PrintConfig.cpp:600 src/libslic3r/PrintConfig.cpp:609 +#: src/libslic3r/PrintConfig.cpp:617 src/libslic3r/PrintConfig.cpp:644 +#: src/libslic3r/PrintConfig.cpp:663 src/libslic3r/PrintConfig.cpp:899 +#: src/libslic3r/PrintConfig.cpp:1026 src/libslic3r/PrintConfig.cpp:1112 +#: src/libslic3r/PrintConfig.cpp:1148 src/libslic3r/PrintConfig.cpp:1161 +#: src/libslic3r/PrintConfig.cpp:1172 src/libslic3r/PrintConfig.cpp:1225 +#: src/libslic3r/PrintConfig.cpp:1284 src/libslic3r/PrintConfig.cpp:1412 +#: src/libslic3r/PrintConfig.cpp:1586 src/libslic3r/PrintConfig.cpp:1595 +#: src/libslic3r/PrintConfig.cpp:1991 src/libslic3r/PrintConfig.cpp:2104 msgid "mm/s" msgstr "" -#: src/libslic3r/PrintConfig.cpp:209 +#: src/libslic3r/PrintConfig.cpp:218 msgid "Brim width" msgstr "" -#: src/libslic3r/PrintConfig.cpp:210 +#: src/libslic3r/PrintConfig.cpp:219 msgid "" "Horizontal width of the brim that will be printed around each object on the " "first layer." msgstr "" -#: src/libslic3r/PrintConfig.cpp:217 +#: src/libslic3r/PrintConfig.cpp:226 msgid "Clip multi-part objects" msgstr "" -#: src/libslic3r/PrintConfig.cpp:218 +#: src/libslic3r/PrintConfig.cpp:227 msgid "" "When printing multi-material objects, this settings will make Slic3r to clip " "the overlapping object parts one by the other (2nd part will be clipped by " "the 1st, 3rd part will be clipped by the 1st and 2nd etc)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:225 +#: src/libslic3r/PrintConfig.cpp:234 msgid "Colorprint height" msgstr "" -#: src/libslic3r/PrintConfig.cpp:226 +#: src/libslic3r/PrintConfig.cpp:235 msgid "Heights at which a filament change is to occur." msgstr "" -#: src/libslic3r/PrintConfig.cpp:236 +#: src/libslic3r/PrintConfig.cpp:245 msgid "Compatible printers condition" msgstr "" -#: src/libslic3r/PrintConfig.cpp:237 +#: src/libslic3r/PrintConfig.cpp:246 msgid "" "A boolean expression using the configuration values of an active printer " "profile. If this expression evaluates to true, this profile is considered " "compatible with the active printer profile." msgstr "" -#: src/libslic3r/PrintConfig.cpp:251 +#: src/libslic3r/PrintConfig.cpp:260 msgid "Compatible print profiles condition" msgstr "" -#: src/libslic3r/PrintConfig.cpp:252 +#: src/libslic3r/PrintConfig.cpp:261 msgid "" "A boolean expression using the configuration values of an active print " "profile. If this expression evaluates to true, this profile is considered " "compatible with the active print profile." msgstr "" -#: src/libslic3r/PrintConfig.cpp:269 +#: src/libslic3r/PrintConfig.cpp:278 msgid "Complete individual objects" msgstr "" -#: src/libslic3r/PrintConfig.cpp:270 +#: src/libslic3r/PrintConfig.cpp:279 msgid "" "When printing multiple objects or copies, this feature will complete each " "object before moving onto next one (and starting it from its bottom layer). " @@ -5059,177 +5563,178 @@ msgid "" "warn and prevent you from extruder collisions, but beware." msgstr "" -#: src/libslic3r/PrintConfig.cpp:278 +#: src/libslic3r/PrintConfig.cpp:287 msgid "Enable auto cooling" msgstr "" -#: src/libslic3r/PrintConfig.cpp:279 +#: src/libslic3r/PrintConfig.cpp:288 msgid "" "This flag enables the automatic cooling logic that adjusts print speed and " "fan speed according to layer printing time." msgstr "" -#: src/libslic3r/PrintConfig.cpp:284 +#: src/libslic3r/PrintConfig.cpp:293 msgid "Cooling tube position" msgstr "" -#: src/libslic3r/PrintConfig.cpp:285 +#: src/libslic3r/PrintConfig.cpp:294 msgid "Distance of the center-point of the cooling tube from the extruder tip." msgstr "" -#: src/libslic3r/PrintConfig.cpp:292 +#: src/libslic3r/PrintConfig.cpp:301 msgid "Cooling tube length" msgstr "" -#: src/libslic3r/PrintConfig.cpp:293 +#: src/libslic3r/PrintConfig.cpp:302 msgid "Length of the cooling tube to limit space for cooling moves inside it." msgstr "" -#: src/libslic3r/PrintConfig.cpp:301 +#: src/libslic3r/PrintConfig.cpp:310 msgid "" "This is the acceleration your printer will be reset to after the role-" "specific acceleration values are used (perimeter/infill). Set zero to " "prevent resetting acceleration at all." msgstr "" -#: src/libslic3r/PrintConfig.cpp:310 +#: src/libslic3r/PrintConfig.cpp:319 msgid "Default filament profile" msgstr "" -#: src/libslic3r/PrintConfig.cpp:311 +#: src/libslic3r/PrintConfig.cpp:320 msgid "" "Default filament profile associated with the current printer profile. On " "selection of the current printer profile, this filament profile will be " "activated." msgstr "" -#: src/libslic3r/PrintConfig.cpp:317 +#: src/libslic3r/PrintConfig.cpp:326 msgid "Default print profile" msgstr "" -#: src/libslic3r/PrintConfig.cpp:318 src/libslic3r/PrintConfig.cpp:2376 -#: src/libslic3r/PrintConfig.cpp:2387 +#: src/libslic3r/PrintConfig.cpp:327 src/libslic3r/PrintConfig.cpp:2447 +#: src/libslic3r/PrintConfig.cpp:2458 msgid "" "Default print profile associated with the current printer profile. On " "selection of the current printer profile, this print profile will be " "activated." msgstr "" -#: src/libslic3r/PrintConfig.cpp:324 +#: src/libslic3r/PrintConfig.cpp:333 msgid "Disable fan for the first" msgstr "" -#: src/libslic3r/PrintConfig.cpp:325 +#: src/libslic3r/PrintConfig.cpp:334 msgid "" "You can set this to a positive value to disable fan at all during the first " "layers, so that it does not make adhesion worse." msgstr "" -#: src/libslic3r/PrintConfig.cpp:327 src/libslic3r/PrintConfig.cpp:957 -#: src/libslic3r/PrintConfig.cpp:1470 src/libslic3r/PrintConfig.cpp:1655 -#: src/libslic3r/PrintConfig.cpp:1716 src/libslic3r/PrintConfig.cpp:1879 -#: src/libslic3r/PrintConfig.cpp:1924 +#: src/libslic3r/PrintConfig.cpp:336 src/libslic3r/PrintConfig.cpp:971 +#: src/libslic3r/PrintConfig.cpp:1484 src/libslic3r/PrintConfig.cpp:1669 +#: src/libslic3r/PrintConfig.cpp:1730 src/libslic3r/PrintConfig.cpp:1894 +#: src/libslic3r/PrintConfig.cpp:1939 msgid "layers" msgstr "" -#: src/libslic3r/PrintConfig.cpp:334 +#: src/libslic3r/PrintConfig.cpp:343 msgid "Don't support bridges" msgstr "" -#: src/libslic3r/PrintConfig.cpp:336 +#: src/libslic3r/PrintConfig.cpp:345 msgid "" "Experimental option for preventing support material from being generated " "under bridged areas." msgstr "" -#: src/libslic3r/PrintConfig.cpp:342 +#: src/libslic3r/PrintConfig.cpp:351 msgid "Distance between copies" msgstr "" -#: src/libslic3r/PrintConfig.cpp:343 +#: src/libslic3r/PrintConfig.cpp:352 msgid "Distance used for the auto-arrange feature of the plater." msgstr "" -#: src/libslic3r/PrintConfig.cpp:350 +#: src/libslic3r/PrintConfig.cpp:359 msgid "Elephant foot compensation" msgstr "" -#: src/libslic3r/PrintConfig.cpp:352 +#: src/libslic3r/PrintConfig.cpp:361 msgid "" "The first layer will be shrunk in the XY plane by the configured value to " "compensate for the 1st layer squish aka an Elephant Foot effect." msgstr "" -#: src/libslic3r/PrintConfig.cpp:361 +#: src/libslic3r/PrintConfig.cpp:370 msgid "" "This end procedure is inserted at the end of the output file. Note that you " "can use placeholder variables for all Slic3r settings." msgstr "" -#: src/libslic3r/PrintConfig.cpp:371 +#: src/libslic3r/PrintConfig.cpp:380 msgid "" "This end procedure is inserted at the end of the output file, before the " -"printer end gcode. Note that you can use placeholder variables for all " +"printer end gcode (and before any toolchange from this filament in case of " +"multimaterial printers). Note that you can use placeholder variables for all " "Slic3r settings. If you have multiple extruders, the gcode is processed in " "extruder order." msgstr "" -#: src/libslic3r/PrintConfig.cpp:381 +#: src/libslic3r/PrintConfig.cpp:391 msgid "Ensure vertical shell thickness" msgstr "" -#: src/libslic3r/PrintConfig.cpp:383 +#: src/libslic3r/PrintConfig.cpp:393 msgid "" "Add solid infill near sloping surfaces to guarantee the vertical shell " "thickness (top+bottom solid layers)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:389 +#: src/libslic3r/PrintConfig.cpp:399 msgid "Top fill pattern" msgstr "" -#: src/libslic3r/PrintConfig.cpp:391 +#: src/libslic3r/PrintConfig.cpp:401 msgid "" "Fill pattern for top infill. This only affects the top visible layer, and " "not its adjacent solid shells." msgstr "" -#: src/libslic3r/PrintConfig.cpp:399 src/libslic3r/PrintConfig.cpp:807 -#: src/libslic3r/PrintConfig.cpp:1957 +#: src/libslic3r/PrintConfig.cpp:409 src/libslic3r/PrintConfig.cpp:821 +#: src/libslic3r/PrintConfig.cpp:1972 msgid "Rectilinear" msgstr "" -#: src/libslic3r/PrintConfig.cpp:400 src/libslic3r/PrintConfig.cpp:813 +#: src/libslic3r/PrintConfig.cpp:410 src/libslic3r/PrintConfig.cpp:827 msgid "Concentric" msgstr "" -#: src/libslic3r/PrintConfig.cpp:401 src/libslic3r/PrintConfig.cpp:817 +#: src/libslic3r/PrintConfig.cpp:411 src/libslic3r/PrintConfig.cpp:831 msgid "Hilbert Curve" msgstr "" -#: src/libslic3r/PrintConfig.cpp:402 src/libslic3r/PrintConfig.cpp:818 +#: src/libslic3r/PrintConfig.cpp:412 src/libslic3r/PrintConfig.cpp:832 msgid "Archimedean Chords" msgstr "" -#: src/libslic3r/PrintConfig.cpp:403 src/libslic3r/PrintConfig.cpp:819 +#: src/libslic3r/PrintConfig.cpp:413 src/libslic3r/PrintConfig.cpp:833 msgid "Octagram Spiral" msgstr "" -#: src/libslic3r/PrintConfig.cpp:410 +#: src/libslic3r/PrintConfig.cpp:419 msgid "Bottom fill pattern" msgstr "" -#: src/libslic3r/PrintConfig.cpp:411 +#: src/libslic3r/PrintConfig.cpp:421 msgid "" "Fill pattern for bottom infill. This only affects the bottom external " "visible layer, and not its adjacent solid shells." msgstr "" -#: src/libslic3r/PrintConfig.cpp:416 src/libslic3r/PrintConfig.cpp:426 +#: src/libslic3r/PrintConfig.cpp:430 src/libslic3r/PrintConfig.cpp:440 msgid "External perimeters" msgstr "" -#: src/libslic3r/PrintConfig.cpp:418 +#: src/libslic3r/PrintConfig.cpp:432 msgid "" "Set this to a non-zero value to set a manual extrusion width for external " "perimeters. If left zero, default extrusion width will be used if set, " @@ -5237,43 +5742,43 @@ msgid "" "(for example 200%), it will be computed over layer height." msgstr "" -#: src/libslic3r/PrintConfig.cpp:421 src/libslic3r/PrintConfig.cpp:529 -#: src/libslic3r/PrintConfig.cpp:846 src/libslic3r/PrintConfig.cpp:858 -#: src/libslic3r/PrintConfig.cpp:978 src/libslic3r/PrintConfig.cpp:1003 -#: src/libslic3r/PrintConfig.cpp:1389 src/libslic3r/PrintConfig.cpp:1727 -#: src/libslic3r/PrintConfig.cpp:1832 src/libslic3r/PrintConfig.cpp:1900 -#: src/libslic3r/PrintConfig.cpp:2058 +#: src/libslic3r/PrintConfig.cpp:435 src/libslic3r/PrintConfig.cpp:543 +#: src/libslic3r/PrintConfig.cpp:860 src/libslic3r/PrintConfig.cpp:872 +#: src/libslic3r/PrintConfig.cpp:992 src/libslic3r/PrintConfig.cpp:1017 +#: src/libslic3r/PrintConfig.cpp:1403 src/libslic3r/PrintConfig.cpp:1741 +#: src/libslic3r/PrintConfig.cpp:1847 src/libslic3r/PrintConfig.cpp:1915 +#: src/libslic3r/PrintConfig.cpp:2074 msgid "mm or %" msgstr "" -#: src/libslic3r/PrintConfig.cpp:428 +#: src/libslic3r/PrintConfig.cpp:442 msgid "" "This separate setting will affect the speed of external perimeters (the " "visible ones). If expressed as percentage (for example: 80%) it will be " "calculated on the perimeters speed setting above. Set to zero for auto." msgstr "" -#: src/libslic3r/PrintConfig.cpp:431 src/libslic3r/PrintConfig.cpp:867 -#: src/libslic3r/PrintConfig.cpp:1686 src/libslic3r/PrintConfig.cpp:1737 -#: src/libslic3r/PrintConfig.cpp:1943 src/libslic3r/PrintConfig.cpp:2070 +#: src/libslic3r/PrintConfig.cpp:445 src/libslic3r/PrintConfig.cpp:881 +#: src/libslic3r/PrintConfig.cpp:1700 src/libslic3r/PrintConfig.cpp:1751 +#: src/libslic3r/PrintConfig.cpp:1958 src/libslic3r/PrintConfig.cpp:2086 msgid "mm/s or %" msgstr "" -#: src/libslic3r/PrintConfig.cpp:438 +#: src/libslic3r/PrintConfig.cpp:452 msgid "External perimeters first" msgstr "" -#: src/libslic3r/PrintConfig.cpp:440 +#: src/libslic3r/PrintConfig.cpp:454 msgid "" "Print contour perimeters from the outermost one to the innermost one instead " "of the default inverse order." msgstr "" -#: src/libslic3r/PrintConfig.cpp:446 +#: src/libslic3r/PrintConfig.cpp:460 msgid "Extra perimeters if needed" msgstr "" -#: src/libslic3r/PrintConfig.cpp:448 +#: src/libslic3r/PrintConfig.cpp:462 #, possible-c-format msgid "" "Add more perimeters when needed for avoiding gaps in sloping walls. Slic3r " @@ -5281,14 +5786,14 @@ msgid "" "is supported." msgstr "" -#: src/libslic3r/PrintConfig.cpp:458 +#: src/libslic3r/PrintConfig.cpp:472 msgid "" "The extruder to use (unless more specific extruder settings are specified). " "This value overrides perimeter and infill extruders, but not the support " "extruders." msgstr "" -#: src/libslic3r/PrintConfig.cpp:470 +#: src/libslic3r/PrintConfig.cpp:484 msgid "" "Set this to the vertical distance between your nozzle tip and (usually) the " "X carriage rods. In other words, this is the height of the clearance " @@ -5296,30 +5801,30 @@ msgid "" "extruder can peek before colliding with other printed objects." msgstr "" -#: src/libslic3r/PrintConfig.cpp:480 +#: src/libslic3r/PrintConfig.cpp:494 msgid "Radius" msgstr "" -#: src/libslic3r/PrintConfig.cpp:481 +#: src/libslic3r/PrintConfig.cpp:495 msgid "" "Set this to the clearance radius around your extruder. If the extruder is " "not centered, choose the largest value for safety. This setting is used to " "check for collisions and to display the graphical preview in the plater." msgstr "" -#: src/libslic3r/PrintConfig.cpp:491 +#: src/libslic3r/PrintConfig.cpp:505 msgid "Extruder Color" msgstr "" -#: src/libslic3r/PrintConfig.cpp:492 src/libslic3r/PrintConfig.cpp:552 +#: src/libslic3r/PrintConfig.cpp:506 src/libslic3r/PrintConfig.cpp:566 msgid "This is only used in the Slic3r interface as a visual help." msgstr "" -#: src/libslic3r/PrintConfig.cpp:498 +#: src/libslic3r/PrintConfig.cpp:512 msgid "Extruder offset" msgstr "" -#: src/libslic3r/PrintConfig.cpp:499 +#: src/libslic3r/PrintConfig.cpp:513 msgid "" "If your firmware doesn't handle the extruder displacement you need the G-" "code to take it into account. This option lets you specify the displacement " @@ -5327,21 +5832,21 @@ msgid "" "coordinates (they will be subtracted from the XY coordinate)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:508 +#: src/libslic3r/PrintConfig.cpp:522 msgid "Extrusion axis" msgstr "" -#: src/libslic3r/PrintConfig.cpp:509 +#: src/libslic3r/PrintConfig.cpp:523 msgid "" "Use this option to set the axis letter associated to your printer's extruder " "(usually E but some printers use A)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:514 +#: src/libslic3r/PrintConfig.cpp:528 msgid "Extrusion multiplier" msgstr "" -#: src/libslic3r/PrintConfig.cpp:515 +#: src/libslic3r/PrintConfig.cpp:529 msgid "" "This factor changes the amount of flow proportionally. You may need to tweak " "this setting to get nice surface finish and correct single wall widths. " @@ -5349,11 +5854,11 @@ msgid "" "more, check filament diameter and your firmware E steps." msgstr "" -#: src/libslic3r/PrintConfig.cpp:523 +#: src/libslic3r/PrintConfig.cpp:537 msgid "Default extrusion width" msgstr "" -#: src/libslic3r/PrintConfig.cpp:525 +#: src/libslic3r/PrintConfig.cpp:539 msgid "" "Set this to a non-zero value to allow a manual extrusion width. If left to " "zero, Slic3r derives extrusion widths from the nozzle diameter (see the " @@ -5362,123 +5867,123 @@ msgid "" "height." msgstr "" -#: src/libslic3r/PrintConfig.cpp:534 +#: src/libslic3r/PrintConfig.cpp:548 msgid "Keep fan always on" msgstr "" -#: src/libslic3r/PrintConfig.cpp:535 +#: src/libslic3r/PrintConfig.cpp:549 msgid "" "If this is enabled, fan will never be disabled and will be kept running at " "least at its minimum speed. Useful for PLA, harmful for ABS." msgstr "" -#: src/libslic3r/PrintConfig.cpp:540 +#: src/libslic3r/PrintConfig.cpp:554 msgid "Enable fan if layer print time is below" msgstr "" -#: src/libslic3r/PrintConfig.cpp:541 +#: src/libslic3r/PrintConfig.cpp:555 msgid "" "If layer print time is estimated below this number of seconds, fan will be " "enabled and its speed will be calculated by interpolating the minimum and " "maximum speeds." msgstr "" -#: src/libslic3r/PrintConfig.cpp:543 src/libslic3r/PrintConfig.cpp:1673 +#: src/libslic3r/PrintConfig.cpp:557 src/libslic3r/PrintConfig.cpp:1687 msgid "approximate seconds" msgstr "" -#: src/libslic3r/PrintConfig.cpp:551 +#: src/libslic3r/PrintConfig.cpp:565 msgid "Color" msgstr "" -#: src/libslic3r/PrintConfig.cpp:557 +#: src/libslic3r/PrintConfig.cpp:571 msgid "Filament notes" msgstr "" -#: src/libslic3r/PrintConfig.cpp:558 +#: src/libslic3r/PrintConfig.cpp:572 msgid "You can put your notes regarding the filament here." msgstr "" -#: src/libslic3r/PrintConfig.cpp:566 src/libslic3r/PrintConfig.cpp:1217 +#: src/libslic3r/PrintConfig.cpp:580 src/libslic3r/PrintConfig.cpp:1231 msgid "Max volumetric speed" msgstr "" -#: src/libslic3r/PrintConfig.cpp:567 +#: src/libslic3r/PrintConfig.cpp:581 msgid "" "Maximum volumetric speed allowed for this filament. Limits the maximum " "volumetric speed of a print to the minimum of print and filament volumetric " "speed. Set to zero for no limit." msgstr "" -#: src/libslic3r/PrintConfig.cpp:576 +#: src/libslic3r/PrintConfig.cpp:590 msgid "Loading speed" msgstr "" -#: src/libslic3r/PrintConfig.cpp:577 +#: src/libslic3r/PrintConfig.cpp:591 msgid "Speed used for loading the filament on the wipe tower." msgstr "" -#: src/libslic3r/PrintConfig.cpp:584 +#: src/libslic3r/PrintConfig.cpp:598 msgid "Loading speed at the start" msgstr "" -#: src/libslic3r/PrintConfig.cpp:585 +#: src/libslic3r/PrintConfig.cpp:599 msgid "Speed used at the very beginning of loading phase." msgstr "" -#: src/libslic3r/PrintConfig.cpp:592 +#: src/libslic3r/PrintConfig.cpp:606 msgid "Unloading speed" msgstr "" -#: src/libslic3r/PrintConfig.cpp:593 +#: src/libslic3r/PrintConfig.cpp:607 msgid "" "Speed used for unloading the filament on the wipe tower (does not affect " "initial part of unloading just after ramming)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:601 +#: src/libslic3r/PrintConfig.cpp:615 msgid "Unloading speed at the start" msgstr "" -#: src/libslic3r/PrintConfig.cpp:602 +#: src/libslic3r/PrintConfig.cpp:616 msgid "" "Speed used for unloading the tip of the filament immediately after ramming." msgstr "" -#: src/libslic3r/PrintConfig.cpp:609 +#: src/libslic3r/PrintConfig.cpp:623 msgid "Delay after unloading" msgstr "" -#: src/libslic3r/PrintConfig.cpp:610 +#: src/libslic3r/PrintConfig.cpp:624 msgid "" "Time to wait after the filament is unloaded. May help to get reliable " "toolchanges with flexible materials that may need more time to shrink to " "original dimensions." msgstr "" -#: src/libslic3r/PrintConfig.cpp:619 +#: src/libslic3r/PrintConfig.cpp:633 msgid "Number of cooling moves" msgstr "" -#: src/libslic3r/PrintConfig.cpp:620 +#: src/libslic3r/PrintConfig.cpp:634 msgid "" "Filament is cooled by being moved back and forth in the cooling tubes. " "Specify desired number of these moves." msgstr "" -#: src/libslic3r/PrintConfig.cpp:628 +#: src/libslic3r/PrintConfig.cpp:642 msgid "Speed of the first cooling move" msgstr "" -#: src/libslic3r/PrintConfig.cpp:629 +#: src/libslic3r/PrintConfig.cpp:643 msgid "Cooling moves are gradually accelerating beginning at this speed." msgstr "" -#: src/libslic3r/PrintConfig.cpp:636 +#: src/libslic3r/PrintConfig.cpp:650 msgid "Minimal purge on wipe tower" msgstr "" -#: src/libslic3r/PrintConfig.cpp:637 +#: src/libslic3r/PrintConfig.cpp:651 msgid "" "After a tool change, the exact position of the newly loaded filament inside " "the nozzle may not be known, and the filament pressure is likely not yet " @@ -5487,62 +5992,62 @@ msgid "" "to produce successive infill or sacrificial object extrusions reliably." msgstr "" -#: src/libslic3r/PrintConfig.cpp:641 +#: src/libslic3r/PrintConfig.cpp:655 msgid "mm³" msgstr "" -#: src/libslic3r/PrintConfig.cpp:647 +#: src/libslic3r/PrintConfig.cpp:661 msgid "Speed of the last cooling move" msgstr "" -#: src/libslic3r/PrintConfig.cpp:648 +#: src/libslic3r/PrintConfig.cpp:662 msgid "Cooling moves are gradually accelerating towards this speed." msgstr "" -#: src/libslic3r/PrintConfig.cpp:655 +#: src/libslic3r/PrintConfig.cpp:669 msgid "Filament load time" msgstr "" -#: src/libslic3r/PrintConfig.cpp:656 +#: src/libslic3r/PrintConfig.cpp:670 msgid "" "Time for the printer firmware (or the Multi Material Unit 2.0) to load a new " "filament during a tool change (when executing the T code). This time is " "added to the total print time by the G-code time estimator." msgstr "" -#: src/libslic3r/PrintConfig.cpp:663 +#: src/libslic3r/PrintConfig.cpp:677 msgid "Ramming parameters" msgstr "" -#: src/libslic3r/PrintConfig.cpp:664 +#: src/libslic3r/PrintConfig.cpp:678 msgid "" "This string is edited by RammingDialog and contains ramming specific " "parameters." msgstr "" -#: src/libslic3r/PrintConfig.cpp:670 +#: src/libslic3r/PrintConfig.cpp:684 msgid "Filament unload time" msgstr "" -#: src/libslic3r/PrintConfig.cpp:671 +#: src/libslic3r/PrintConfig.cpp:685 msgid "" "Time for the printer firmware (or the Multi Material Unit 2.0) to unload a " "filament during a tool change (when executing the T code). This time is " "added to the total print time by the G-code time estimator." msgstr "" -#: src/libslic3r/PrintConfig.cpp:679 +#: src/libslic3r/PrintConfig.cpp:693 msgid "" "Enter your filament diameter here. Good precision is required, so use a " "caliper and do multiple measurements along the filament, then compute the " "average." msgstr "" -#: src/libslic3r/PrintConfig.cpp:686 +#: src/libslic3r/PrintConfig.cpp:700 msgid "Density" msgstr "" -#: src/libslic3r/PrintConfig.cpp:687 +#: src/libslic3r/PrintConfig.cpp:701 msgid "" "Enter your filament density here. This is only for statistical information. " "A decent way is to weigh a known length of filament and compute the ratio of " @@ -5550,113 +6055,113 @@ msgid "" "displacement." msgstr "" -#: src/libslic3r/PrintConfig.cpp:690 +#: src/libslic3r/PrintConfig.cpp:704 msgid "g/cm³" msgstr "" -#: src/libslic3r/PrintConfig.cpp:695 +#: src/libslic3r/PrintConfig.cpp:709 msgid "Filament type" msgstr "" -#: src/libslic3r/PrintConfig.cpp:696 +#: src/libslic3r/PrintConfig.cpp:710 msgid "The filament material type for use in custom G-codes." msgstr "" -#: src/libslic3r/PrintConfig.cpp:722 +#: src/libslic3r/PrintConfig.cpp:736 msgid "Soluble material" msgstr "" -#: src/libslic3r/PrintConfig.cpp:723 +#: src/libslic3r/PrintConfig.cpp:737 msgid "Soluble material is most likely used for a soluble support." msgstr "" -#: src/libslic3r/PrintConfig.cpp:729 +#: src/libslic3r/PrintConfig.cpp:743 msgid "" "Enter your filament cost per kg here. This is only for statistical " "information." msgstr "" -#: src/libslic3r/PrintConfig.cpp:730 +#: src/libslic3r/PrintConfig.cpp:744 msgid "money/kg" msgstr "" -#: src/libslic3r/PrintConfig.cpp:739 +#: src/libslic3r/PrintConfig.cpp:753 msgid "Fill angle" msgstr "" -#: src/libslic3r/PrintConfig.cpp:741 +#: src/libslic3r/PrintConfig.cpp:755 msgid "" "Default base angle for infill orientation. Cross-hatching will be applied to " "this. Bridges will be infilled using the best direction Slic3r can detect, " "so this setting does not affect them." msgstr "" -#: src/libslic3r/PrintConfig.cpp:753 +#: src/libslic3r/PrintConfig.cpp:767 msgid "Fill density" msgstr "" -#: src/libslic3r/PrintConfig.cpp:755 +#: src/libslic3r/PrintConfig.cpp:769 msgid "Density of internal infill, expressed in the range 0% - 100%." msgstr "" -#: src/libslic3r/PrintConfig.cpp:790 +#: src/libslic3r/PrintConfig.cpp:804 msgid "Fill pattern" msgstr "" -#: src/libslic3r/PrintConfig.cpp:792 +#: src/libslic3r/PrintConfig.cpp:806 msgid "Fill pattern for general low-density infill." msgstr "" -#: src/libslic3r/PrintConfig.cpp:808 +#: src/libslic3r/PrintConfig.cpp:822 msgid "Grid" msgstr "" -#: src/libslic3r/PrintConfig.cpp:809 +#: src/libslic3r/PrintConfig.cpp:823 msgid "Triangles" msgstr "" -#: src/libslic3r/PrintConfig.cpp:810 +#: src/libslic3r/PrintConfig.cpp:824 msgid "Stars" msgstr "" -#: src/libslic3r/PrintConfig.cpp:811 +#: src/libslic3r/PrintConfig.cpp:825 msgid "Cubic" msgstr "" -#: src/libslic3r/PrintConfig.cpp:812 +#: src/libslic3r/PrintConfig.cpp:826 msgid "Line" msgstr "" -#: src/libslic3r/PrintConfig.cpp:814 src/libslic3r/PrintConfig.cpp:1959 +#: src/libslic3r/PrintConfig.cpp:828 src/libslic3r/PrintConfig.cpp:1974 msgid "Honeycomb" msgstr "" -#: src/libslic3r/PrintConfig.cpp:815 +#: src/libslic3r/PrintConfig.cpp:829 msgid "3D Honeycomb" msgstr "" -#: src/libslic3r/PrintConfig.cpp:816 +#: src/libslic3r/PrintConfig.cpp:830 msgid "Gyroid" msgstr "" -#: src/libslic3r/PrintConfig.cpp:823 src/libslic3r/PrintConfig.cpp:832 -#: src/libslic3r/PrintConfig.cpp:840 src/libslic3r/PrintConfig.cpp:873 +#: src/libslic3r/PrintConfig.cpp:837 src/libslic3r/PrintConfig.cpp:846 +#: src/libslic3r/PrintConfig.cpp:854 src/libslic3r/PrintConfig.cpp:887 msgid "First layer" msgstr "" -#: src/libslic3r/PrintConfig.cpp:824 +#: src/libslic3r/PrintConfig.cpp:838 msgid "" "This is the acceleration your printer will use for first layer. Set zero to " "disable acceleration control for first layer." msgstr "" -#: src/libslic3r/PrintConfig.cpp:833 +#: src/libslic3r/PrintConfig.cpp:847 msgid "" "Heated build plate temperature for the first layer. Set this to zero to " "disable bed temperature control commands in the output." msgstr "" -#: src/libslic3r/PrintConfig.cpp:842 +#: src/libslic3r/PrintConfig.cpp:856 msgid "" "Set this to a non-zero value to set a manual extrusion width for first " "layer. You can use this to force fatter extrudates for better adhesion. If " @@ -5664,7 +6169,7 @@ msgid "" "layer height. If set to zero, it will use the default extrusion width." msgstr "" -#: src/libslic3r/PrintConfig.cpp:854 +#: src/libslic3r/PrintConfig.cpp:868 msgid "" "When printing with very low layer heights, you might still want to print a " "thicker bottom layer to improve adhesion and tolerance for non perfect build " @@ -5672,47 +6177,47 @@ msgid "" "example: 150%) over the default layer height." msgstr "" -#: src/libslic3r/PrintConfig.cpp:863 +#: src/libslic3r/PrintConfig.cpp:877 msgid "First layer speed" msgstr "" -#: src/libslic3r/PrintConfig.cpp:864 +#: src/libslic3r/PrintConfig.cpp:878 msgid "" "If expressed as absolute value in mm/s, this speed will be applied to all " "the print moves of the first layer, regardless of their type. If expressed " "as a percentage (for example: 40%) it will scale the default speeds." msgstr "" -#: src/libslic3r/PrintConfig.cpp:874 +#: src/libslic3r/PrintConfig.cpp:888 msgid "" "Extruder temperature for first layer. If you want to control temperature " "manually during print, set this to zero to disable temperature control " "commands in the output file." msgstr "" -#: src/libslic3r/PrintConfig.cpp:883 +#: src/libslic3r/PrintConfig.cpp:897 msgid "" "Speed for filling small gaps using short zigzag moves. Keep this reasonably " "low to avoid too much shaking and resonance issues. Set zero to disable gaps " "filling." msgstr "" -#: src/libslic3r/PrintConfig.cpp:891 +#: src/libslic3r/PrintConfig.cpp:905 msgid "Verbose G-code" msgstr "" -#: src/libslic3r/PrintConfig.cpp:892 +#: src/libslic3r/PrintConfig.cpp:906 msgid "" "Enable this to get a commented G-code file, with each line explained by a " "descriptive text. If you print from SD card, the additional weight of the " "file could make your firmware slow down." msgstr "" -#: src/libslic3r/PrintConfig.cpp:899 +#: src/libslic3r/PrintConfig.cpp:913 msgid "G-code flavor" msgstr "" -#: src/libslic3r/PrintConfig.cpp:900 +#: src/libslic3r/PrintConfig.cpp:914 msgid "" "Some G/M-code commands, including temperature control and others, are not " "universal. Set this option to your printer's firmware to get a compatible " @@ -5720,15 +6225,15 @@ msgid "" "extrusion value at all." msgstr "" -#: src/libslic3r/PrintConfig.cpp:923 +#: src/libslic3r/PrintConfig.cpp:937 msgid "No extrusion" msgstr "" -#: src/libslic3r/PrintConfig.cpp:928 +#: src/libslic3r/PrintConfig.cpp:942 msgid "Label objects" msgstr "" -#: src/libslic3r/PrintConfig.cpp:929 +#: src/libslic3r/PrintConfig.cpp:943 msgid "" "Enable this to add comments into the G-Code labeling print moves with what " "object they belong to, which is useful for the Octoprint CancelObject " @@ -5736,46 +6241,46 @@ msgid "" "setup and Wipe into Object / Wipe into Infill." msgstr "" -#: src/libslic3r/PrintConfig.cpp:936 +#: src/libslic3r/PrintConfig.cpp:950 msgid "High extruder current on filament swap" msgstr "" -#: src/libslic3r/PrintConfig.cpp:937 +#: src/libslic3r/PrintConfig.cpp:951 msgid "" "It may be beneficial to increase the extruder motor current during the " "filament exchange sequence to allow for rapid ramming feed rates and to " "overcome resistance when loading a filament with an ugly shaped tip." msgstr "" -#: src/libslic3r/PrintConfig.cpp:945 +#: src/libslic3r/PrintConfig.cpp:959 msgid "" "This is the acceleration your printer will use for infill. Set zero to " "disable acceleration control for infill." msgstr "" -#: src/libslic3r/PrintConfig.cpp:953 +#: src/libslic3r/PrintConfig.cpp:967 msgid "Combine infill every" msgstr "" -#: src/libslic3r/PrintConfig.cpp:955 +#: src/libslic3r/PrintConfig.cpp:969 msgid "" "This feature allows to combine infill and speed up your print by extruding " "thicker infill layers while preserving thin perimeters, thus accuracy." msgstr "" -#: src/libslic3r/PrintConfig.cpp:958 +#: src/libslic3r/PrintConfig.cpp:972 msgid "Combine infill every n layers" msgstr "" -#: src/libslic3r/PrintConfig.cpp:964 +#: src/libslic3r/PrintConfig.cpp:978 msgid "Infill extruder" msgstr "" -#: src/libslic3r/PrintConfig.cpp:966 +#: src/libslic3r/PrintConfig.cpp:980 msgid "The extruder to use when printing infill." msgstr "" -#: src/libslic3r/PrintConfig.cpp:974 +#: src/libslic3r/PrintConfig.cpp:988 msgid "" "Set this to a non-zero value to set a manual extrusion width for infill. If " "left zero, default extrusion width will be used if set, otherwise 1.125 x " @@ -5784,32 +6289,32 @@ msgid "" "example 90%) it will be computed over layer height." msgstr "" -#: src/libslic3r/PrintConfig.cpp:983 +#: src/libslic3r/PrintConfig.cpp:997 msgid "Infill before perimeters" msgstr "" -#: src/libslic3r/PrintConfig.cpp:984 +#: src/libslic3r/PrintConfig.cpp:998 msgid "" "This option will switch the print order of perimeters and infill, making the " "latter first." msgstr "" -#: src/libslic3r/PrintConfig.cpp:989 +#: src/libslic3r/PrintConfig.cpp:1003 msgid "Only infill where needed" msgstr "" -#: src/libslic3r/PrintConfig.cpp:991 +#: src/libslic3r/PrintConfig.cpp:1005 msgid "" "This option will limit infill to the areas actually needed for supporting " "ceilings (it will act as internal support material). If enabled, slows down " "the G-code generation due to the multiple checks involved." msgstr "" -#: src/libslic3r/PrintConfig.cpp:998 +#: src/libslic3r/PrintConfig.cpp:1012 msgid "Infill/perimeters overlap" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1000 +#: src/libslic3r/PrintConfig.cpp:1014 msgid "" "This setting applies an additional overlap between infill and perimeters for " "better bonding. Theoretically this shouldn't be needed, but backlash might " @@ -5817,30 +6322,30 @@ msgid "" "perimeter extrusion width." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1011 +#: src/libslic3r/PrintConfig.cpp:1025 msgid "Speed for printing the internal fill. Set to zero for auto." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1019 +#: src/libslic3r/PrintConfig.cpp:1033 msgid "Inherits profile" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1020 +#: src/libslic3r/PrintConfig.cpp:1034 msgid "Name of the profile, from which this profile inherits." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1033 +#: src/libslic3r/PrintConfig.cpp:1047 msgid "Interface shells" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1034 +#: src/libslic3r/PrintConfig.cpp:1048 msgid "" "Force the generation of solid shells between adjacent materials/volumes. " "Useful for multi-extruder prints with translucent materials or manual " "soluble support material." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1043 +#: src/libslic3r/PrintConfig.cpp:1057 msgid "" "This custom code is inserted at every layer change, right after the Z move " "and before the extruder moves to the first layer point. Note that you can " @@ -5848,11 +6353,11 @@ msgid "" "[layer_z]." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1054 +#: src/libslic3r/PrintConfig.cpp:1068 msgid "Supports remaining times" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1055 +#: src/libslic3r/PrintConfig.cpp:1069 msgid "" "Emit M73 P[percent printed] R[remaining time in minutes] at 1 minute " "intervals into the G-code to let the firmware show accurate remaining time. " @@ -5860,151 +6365,151 @@ msgid "" "firmware supports M73 Qxx Sxx for the silent mode." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1063 +#: src/libslic3r/PrintConfig.cpp:1077 msgid "Supports stealth mode" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1064 +#: src/libslic3r/PrintConfig.cpp:1078 msgid "The firmware supports stealth mode" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1088 +#: src/libslic3r/PrintConfig.cpp:1102 msgid "Maximum feedrate X" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1089 +#: src/libslic3r/PrintConfig.cpp:1103 msgid "Maximum feedrate Y" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1090 +#: src/libslic3r/PrintConfig.cpp:1104 msgid "Maximum feedrate Z" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1091 +#: src/libslic3r/PrintConfig.cpp:1105 msgid "Maximum feedrate E" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1094 +#: src/libslic3r/PrintConfig.cpp:1108 msgid "Maximum feedrate of the X axis" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1095 +#: src/libslic3r/PrintConfig.cpp:1109 msgid "Maximum feedrate of the Y axis" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1096 +#: src/libslic3r/PrintConfig.cpp:1110 msgid "Maximum feedrate of the Z axis" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1097 +#: src/libslic3r/PrintConfig.cpp:1111 msgid "Maximum feedrate of the E axis" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1106 +#: src/libslic3r/PrintConfig.cpp:1120 msgid "Maximum acceleration X" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1107 +#: src/libslic3r/PrintConfig.cpp:1121 msgid "Maximum acceleration Y" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1108 +#: src/libslic3r/PrintConfig.cpp:1122 msgid "Maximum acceleration Z" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1109 +#: src/libslic3r/PrintConfig.cpp:1123 msgid "Maximum acceleration E" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1112 +#: src/libslic3r/PrintConfig.cpp:1126 msgid "Maximum acceleration of the X axis" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1113 +#: src/libslic3r/PrintConfig.cpp:1127 msgid "Maximum acceleration of the Y axis" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1114 +#: src/libslic3r/PrintConfig.cpp:1128 msgid "Maximum acceleration of the Z axis" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1115 +#: src/libslic3r/PrintConfig.cpp:1129 msgid "Maximum acceleration of the E axis" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1124 +#: src/libslic3r/PrintConfig.cpp:1138 msgid "Maximum jerk X" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1125 +#: src/libslic3r/PrintConfig.cpp:1139 msgid "Maximum jerk Y" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1126 +#: src/libslic3r/PrintConfig.cpp:1140 msgid "Maximum jerk Z" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1127 +#: src/libslic3r/PrintConfig.cpp:1141 msgid "Maximum jerk E" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1130 +#: src/libslic3r/PrintConfig.cpp:1144 msgid "Maximum jerk of the X axis" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1131 +#: src/libslic3r/PrintConfig.cpp:1145 msgid "Maximum jerk of the Y axis" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1132 +#: src/libslic3r/PrintConfig.cpp:1146 msgid "Maximum jerk of the Z axis" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1133 +#: src/libslic3r/PrintConfig.cpp:1147 msgid "Maximum jerk of the E axis" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1144 +#: src/libslic3r/PrintConfig.cpp:1158 msgid "Minimum feedrate when extruding" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1146 +#: src/libslic3r/PrintConfig.cpp:1160 msgid "Minimum feedrate when extruding (M205 S)" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1155 +#: src/libslic3r/PrintConfig.cpp:1169 msgid "Minimum travel feedrate" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1157 +#: src/libslic3r/PrintConfig.cpp:1171 msgid "Minimum travel feedrate (M205 T)" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1166 +#: src/libslic3r/PrintConfig.cpp:1180 msgid "Maximum acceleration when extruding" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1168 +#: src/libslic3r/PrintConfig.cpp:1182 msgid "Maximum acceleration when extruding (M204 S)" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1177 +#: src/libslic3r/PrintConfig.cpp:1191 msgid "Maximum acceleration when retracting" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1179 +#: src/libslic3r/PrintConfig.cpp:1193 msgid "Maximum acceleration when retracting (M204 T)" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1187 src/libslic3r/PrintConfig.cpp:1196 +#: src/libslic3r/PrintConfig.cpp:1201 src/libslic3r/PrintConfig.cpp:1210 msgid "Max" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1188 +#: src/libslic3r/PrintConfig.cpp:1202 msgid "This setting represents the maximum speed of your fan." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1197 +#: src/libslic3r/PrintConfig.cpp:1211 #, possible-c-format msgid "" "This is the highest printable layer height for this extruder, used to cap " @@ -6013,28 +6518,28 @@ msgid "" "adhesion. If set to 0, layer height is limited to 75% of the nozzle diameter." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1207 +#: src/libslic3r/PrintConfig.cpp:1221 msgid "Max print speed" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1208 +#: src/libslic3r/PrintConfig.cpp:1222 msgid "" "When setting other speed settings to 0 Slic3r will autocalculate the optimal " "speed in order to keep constant extruder pressure. This experimental setting " "is used to set the highest print speed you want to allow." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1218 +#: src/libslic3r/PrintConfig.cpp:1232 msgid "" "This experimental setting is used to set the maximum volumetric speed your " "extruder supports." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1227 +#: src/libslic3r/PrintConfig.cpp:1241 msgid "Max volumetric slope positive" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1228 src/libslic3r/PrintConfig.cpp:1239 +#: src/libslic3r/PrintConfig.cpp:1242 src/libslic3r/PrintConfig.cpp:1253 msgid "" "This experimental setting is used to limit the speed of change in extrusion " "rate. A value of 1.8 mm³/s² ensures, that a change from the extrusion rate " @@ -6042,99 +6547,95 @@ msgid "" "s) to 5.4 mm³/s (feedrate 60 mm/s) will take at least 2 seconds." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1232 src/libslic3r/PrintConfig.cpp:1243 +#: src/libslic3r/PrintConfig.cpp:1246 src/libslic3r/PrintConfig.cpp:1257 msgid "mm³/s²" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1238 +#: src/libslic3r/PrintConfig.cpp:1252 msgid "Max volumetric slope negative" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1250 src/libslic3r/PrintConfig.cpp:1259 +#: src/libslic3r/PrintConfig.cpp:1264 src/libslic3r/PrintConfig.cpp:1273 msgid "Min" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1251 +#: src/libslic3r/PrintConfig.cpp:1265 msgid "This setting represents the minimum PWM your fan needs to work." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1260 +#: src/libslic3r/PrintConfig.cpp:1274 msgid "" "This is the lowest printable layer height for this extruder and limits the " "resolution for variable layer height. Typical values are between 0.05 mm and " "0.1 mm." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1268 +#: src/libslic3r/PrintConfig.cpp:1282 msgid "Min print speed" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1269 +#: src/libslic3r/PrintConfig.cpp:1283 msgid "Slic3r will not scale speed down below this speed." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1276 +#: src/libslic3r/PrintConfig.cpp:1290 msgid "Minimal filament extrusion length" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1277 +#: src/libslic3r/PrintConfig.cpp:1291 msgid "" "Generate no less than the number of skirt loops required to consume the " "specified amount of filament on the bottom layer. For multi-extruder " "machines, this minimum applies to each extruder." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1286 +#: src/libslic3r/PrintConfig.cpp:1300 msgid "Configuration notes" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1287 +#: src/libslic3r/PrintConfig.cpp:1301 msgid "" "You can put here your personal notes. This text will be added to the G-code " "header comments." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1296 -msgid "Nozzle diameter" -msgstr "" - -#: src/libslic3r/PrintConfig.cpp:1297 +#: src/libslic3r/PrintConfig.cpp:1311 msgid "" "This is the diameter of your extruder nozzle (for example: 0.5, 0.35 etc.)" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1302 +#: src/libslic3r/PrintConfig.cpp:1316 msgid "Host Type" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1303 +#: src/libslic3r/PrintConfig.cpp:1317 msgid "" "Slic3r can upload G-code files to a printer host. This field must contain " "the kind of the host." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1314 +#: src/libslic3r/PrintConfig.cpp:1328 msgid "Only retract when crossing perimeters" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1315 +#: src/libslic3r/PrintConfig.cpp:1329 msgid "" "Disables retraction when the travel path does not exceed the upper layer's " "perimeters (and thus any ooze will be probably invisible)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1322 +#: src/libslic3r/PrintConfig.cpp:1336 msgid "" "This option will drop the temperature of the inactive extruders to prevent " "oozing. It will enable a tall skirt automatically and move extruders outside " "such skirt when changing temperatures." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1329 +#: src/libslic3r/PrintConfig.cpp:1343 msgid "Output filename format" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1330 +#: src/libslic3r/PrintConfig.cpp:1344 msgid "" "You can use all configuration options as variables inside this template. For " "example: [layer_height], [fill_density] etc. You can also use [timestamp], " @@ -6142,31 +6643,31 @@ msgid "" "[input_filename], [input_filename_base]." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1339 +#: src/libslic3r/PrintConfig.cpp:1353 msgid "Detect bridging perimeters" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1341 +#: src/libslic3r/PrintConfig.cpp:1355 msgid "" "Experimental option to adjust flow for overhangs (bridge flow will be used), " "to apply bridge speed to them and enable fan." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1347 +#: src/libslic3r/PrintConfig.cpp:1361 msgid "Filament parking position" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1348 +#: src/libslic3r/PrintConfig.cpp:1362 msgid "" "Distance of the extruder tip from the position where the filament is parked " "when unloaded. This should match the value in printer firmware." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1356 +#: src/libslic3r/PrintConfig.cpp:1370 msgid "Extra loading distance" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1357 +#: src/libslic3r/PrintConfig.cpp:1371 msgid "" "When set to zero, the distance the filament is moved from parking position " "during load is exactly the same as it was moved back during unload. When " @@ -6174,28 +6675,28 @@ msgid "" "than unloading." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1365 src/libslic3r/PrintConfig.cpp:1383 -#: src/libslic3r/PrintConfig.cpp:1395 src/libslic3r/PrintConfig.cpp:1405 +#: src/libslic3r/PrintConfig.cpp:1379 src/libslic3r/PrintConfig.cpp:1397 +#: src/libslic3r/PrintConfig.cpp:1409 src/libslic3r/PrintConfig.cpp:1419 msgid "Perimeters" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1366 +#: src/libslic3r/PrintConfig.cpp:1380 msgid "" "This is the acceleration your printer will use for perimeters. A high value " "like 9000 usually gives good results if your hardware is up to the job. Set " "zero to disable acceleration control for perimeters." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1374 +#: src/libslic3r/PrintConfig.cpp:1388 msgid "Perimeter extruder" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1376 +#: src/libslic3r/PrintConfig.cpp:1390 msgid "" "The extruder to use when printing perimeters and brim. First extruder is 1." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1385 +#: src/libslic3r/PrintConfig.cpp:1399 msgid "" "Set this to a non-zero value to set a manual extrusion width for perimeters. " "You may want to use thinner extrudates to get more accurate surfaces. If " @@ -6204,12 +6705,12 @@ msgid "" "it will be computed over layer height." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1397 +#: src/libslic3r/PrintConfig.cpp:1411 msgid "" "Speed for perimeters (contours, aka vertical shells). Set to zero for auto." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1407 +#: src/libslic3r/PrintConfig.cpp:1421 msgid "" "This option sets the number of perimeters to generate for each layer. Note " "that Slic3r may increase this number automatically when it detects sloping " @@ -6217,11 +6718,11 @@ msgid "" "Perimeters option is enabled." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1411 +#: src/libslic3r/PrintConfig.cpp:1425 msgid "(minimum)" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1419 +#: src/libslic3r/PrintConfig.cpp:1433 msgid "" "If you want to process the output G-code through custom scripts, just list " "their absolute paths here. Separate multiple scripts with a semicolon. " @@ -6230,55 +6731,55 @@ msgid "" "environment variables." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1431 +#: src/libslic3r/PrintConfig.cpp:1445 msgid "Printer type" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1432 +#: src/libslic3r/PrintConfig.cpp:1446 msgid "Type of the printer." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1437 +#: src/libslic3r/PrintConfig.cpp:1451 msgid "Printer notes" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1438 +#: src/libslic3r/PrintConfig.cpp:1452 msgid "You can put your notes regarding the printer here." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1446 +#: src/libslic3r/PrintConfig.cpp:1460 msgid "Printer vendor" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1447 +#: src/libslic3r/PrintConfig.cpp:1461 msgid "Name of the printer vendor." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1452 +#: src/libslic3r/PrintConfig.cpp:1466 msgid "Printer variant" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1453 +#: src/libslic3r/PrintConfig.cpp:1467 msgid "" "Name of the printer variant. For example, the printer variants may be " "differentiated by a nozzle diameter." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1466 +#: src/libslic3r/PrintConfig.cpp:1480 msgid "Raft layers" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1468 +#: src/libslic3r/PrintConfig.cpp:1482 msgid "" "The object will be raised by this number of layers, and support material " "will be generated under it." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1476 +#: src/libslic3r/PrintConfig.cpp:1490 msgid "Resolution" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1477 +#: src/libslic3r/PrintConfig.cpp:1491 msgid "" "Minimum detail resolution, used to simplify the input file for speeding up " "the slicing job and reducing memory usage. High-resolution models often " @@ -6286,278 +6787,278 @@ msgid "" "simplification and use full resolution from input." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1487 +#: src/libslic3r/PrintConfig.cpp:1501 msgid "Minimum travel after retraction" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1488 +#: src/libslic3r/PrintConfig.cpp:1502 msgid "" "Retraction is not triggered when travel moves are shorter than this length." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1494 +#: src/libslic3r/PrintConfig.cpp:1508 msgid "Retract amount before wipe" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1495 +#: src/libslic3r/PrintConfig.cpp:1509 msgid "" "With bowden extruders, it may be wise to do some amount of quick retract " "before doing the wipe movement." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1502 +#: src/libslic3r/PrintConfig.cpp:1516 msgid "Retract on layer change" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1503 +#: src/libslic3r/PrintConfig.cpp:1517 msgid "This flag enforces a retraction whenever a Z move is done." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1508 src/libslic3r/PrintConfig.cpp:1516 +#: src/libslic3r/PrintConfig.cpp:1522 src/libslic3r/PrintConfig.cpp:1530 msgid "Length" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1509 +#: src/libslic3r/PrintConfig.cpp:1523 msgid "Retraction Length" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1510 +#: src/libslic3r/PrintConfig.cpp:1524 msgid "" "When retraction is triggered, filament is pulled back by the specified " "amount (the length is measured on raw filament, before it enters the " "extruder)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1512 src/libslic3r/PrintConfig.cpp:1521 +#: src/libslic3r/PrintConfig.cpp:1526 src/libslic3r/PrintConfig.cpp:1535 msgid "mm (zero to disable)" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1517 +#: src/libslic3r/PrintConfig.cpp:1531 msgid "Retraction Length (Toolchange)" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1518 +#: src/libslic3r/PrintConfig.cpp:1532 msgid "" "When retraction is triggered before changing tool, filament is pulled back " "by the specified amount (the length is measured on raw filament, before it " "enters the extruder)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1526 +#: src/libslic3r/PrintConfig.cpp:1540 msgid "Lift Z" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1527 +#: src/libslic3r/PrintConfig.cpp:1541 msgid "" "If you set this to a positive value, Z is quickly raised every time a " "retraction is triggered. When using multiple extruders, only the setting for " "the first extruder will be considered." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1534 +#: src/libslic3r/PrintConfig.cpp:1548 msgid "Above Z" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1535 +#: src/libslic3r/PrintConfig.cpp:1549 msgid "Only lift Z above" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1536 +#: src/libslic3r/PrintConfig.cpp:1550 msgid "" "If you set this to a positive value, Z lift will only take place above the " "specified absolute Z. You can tune this setting for skipping lift on the " "first layers." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1543 +#: src/libslic3r/PrintConfig.cpp:1557 msgid "Below Z" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1544 +#: src/libslic3r/PrintConfig.cpp:1558 msgid "Only lift Z below" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1545 +#: src/libslic3r/PrintConfig.cpp:1559 msgid "" "If you set this to a positive value, Z lift will only take place below the " "specified absolute Z. You can tune this setting for limiting lift to the " "first layers." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1553 src/libslic3r/PrintConfig.cpp:1561 +#: src/libslic3r/PrintConfig.cpp:1567 src/libslic3r/PrintConfig.cpp:1575 msgid "Extra length on restart" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1554 +#: src/libslic3r/PrintConfig.cpp:1568 msgid "" "When the retraction is compensated after the travel move, the extruder will " "push this additional amount of filament. This setting is rarely needed." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1562 +#: src/libslic3r/PrintConfig.cpp:1576 msgid "" "When the retraction is compensated after changing tool, the extruder will " "push this additional amount of filament." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1569 src/libslic3r/PrintConfig.cpp:1570 +#: src/libslic3r/PrintConfig.cpp:1583 src/libslic3r/PrintConfig.cpp:1584 msgid "Retraction Speed" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1571 +#: src/libslic3r/PrintConfig.cpp:1585 msgid "The speed for retractions (it only applies to the extruder motor)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1577 src/libslic3r/PrintConfig.cpp:1578 +#: src/libslic3r/PrintConfig.cpp:1591 src/libslic3r/PrintConfig.cpp:1592 msgid "Deretraction Speed" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1579 +#: src/libslic3r/PrintConfig.cpp:1593 msgid "" "The speed for loading of a filament into extruder after retraction (it only " "applies to the extruder motor). If left to zero, the retraction speed is " "used." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1586 +#: src/libslic3r/PrintConfig.cpp:1600 msgid "Seam position" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1588 +#: src/libslic3r/PrintConfig.cpp:1602 msgid "Position of perimeters starting points." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1594 +#: src/libslic3r/PrintConfig.cpp:1608 msgid "Random" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1595 +#: src/libslic3r/PrintConfig.cpp:1609 msgid "Nearest" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1596 +#: src/libslic3r/PrintConfig.cpp:1610 msgid "Aligned" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1604 +#: src/libslic3r/PrintConfig.cpp:1618 msgid "Direction" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1606 +#: src/libslic3r/PrintConfig.cpp:1620 msgid "Preferred direction of the seam" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1607 +#: src/libslic3r/PrintConfig.cpp:1621 msgid "Seam preferred direction" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1614 +#: src/libslic3r/PrintConfig.cpp:1628 msgid "Jitter" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1616 +#: src/libslic3r/PrintConfig.cpp:1630 msgid "Seam preferred direction jitter" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1617 +#: src/libslic3r/PrintConfig.cpp:1631 msgid "Preferred direction of the seam - jitter" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1627 +#: src/libslic3r/PrintConfig.cpp:1641 msgid "USB/serial port for printer connection." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1634 +#: src/libslic3r/PrintConfig.cpp:1648 msgid "Serial port speed" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1635 +#: src/libslic3r/PrintConfig.cpp:1649 msgid "Speed (baud) of USB/serial port for printer connection." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1644 +#: src/libslic3r/PrintConfig.cpp:1658 msgid "Distance from object" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1645 +#: src/libslic3r/PrintConfig.cpp:1659 msgid "" "Distance between skirt and object(s). Set this to zero to attach the skirt " "to the object(s) and get a brim for better adhesion." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1652 +#: src/libslic3r/PrintConfig.cpp:1666 msgid "Skirt height" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1653 +#: src/libslic3r/PrintConfig.cpp:1667 msgid "" "Height of skirt expressed in layers. Set this to a tall value to use skirt " "as a shield against drafts." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1660 +#: src/libslic3r/PrintConfig.cpp:1674 msgid "Loops (minimum)" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1661 +#: src/libslic3r/PrintConfig.cpp:1675 msgid "Skirt Loops" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1662 +#: src/libslic3r/PrintConfig.cpp:1676 msgid "" "Number of loops for the skirt. If the Minimum Extrusion Length option is " "set, the number of loops might be greater than the one configured here. Set " "this to zero to disable skirt completely." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1670 +#: src/libslic3r/PrintConfig.cpp:1684 msgid "Slow down if layer print time is below" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1671 +#: src/libslic3r/PrintConfig.cpp:1685 msgid "" "If layer print time is estimated below this number of seconds, print moves " "speed will be scaled down to extend duration to this value." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1681 +#: src/libslic3r/PrintConfig.cpp:1695 msgid "Small perimeters" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1683 +#: src/libslic3r/PrintConfig.cpp:1697 msgid "" "This separate setting will affect the speed of perimeters having radius <= " "6.5mm (usually holes). If expressed as percentage (for example: 80%) it will " "be calculated on the perimeters speed setting above. Set to zero for auto." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1693 +#: src/libslic3r/PrintConfig.cpp:1707 msgid "Solid infill threshold area" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1695 +#: src/libslic3r/PrintConfig.cpp:1709 msgid "" "Force solid infill for regions having a smaller area than the specified " "threshold." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1696 +#: src/libslic3r/PrintConfig.cpp:1710 msgid "mm²" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1702 +#: src/libslic3r/PrintConfig.cpp:1716 msgid "Solid infill extruder" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1704 +#: src/libslic3r/PrintConfig.cpp:1718 msgid "The extruder to use when printing solid infill." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1710 +#: src/libslic3r/PrintConfig.cpp:1724 msgid "Solid infill every" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1712 +#: src/libslic3r/PrintConfig.cpp:1726 msgid "" "This feature allows to force a solid layer every given number of layers. " "Zero to disable. You can set this to any value (for example 9999); Slic3r " @@ -6565,7 +7066,7 @@ msgid "" "according to nozzle diameter and layer height." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1724 +#: src/libslic3r/PrintConfig.cpp:1738 msgid "" "Set this to a non-zero value to set a manual extrusion width for infill for " "solid surfaces. If left zero, default extrusion width will be used if set, " @@ -6573,22 +7074,22 @@ msgid "" "(for example 90%) it will be computed over layer height." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1734 +#: src/libslic3r/PrintConfig.cpp:1748 msgid "" "Speed for printing solid regions (top/bottom/internal horizontal shells). " "This can be expressed as a percentage (for example: 80%) over the default " "infill speed above. Set to zero for auto." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1746 +#: src/libslic3r/PrintConfig.cpp:1760 msgid "Number of solid layers to generate on top and bottom surfaces." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1752 +#: src/libslic3r/PrintConfig.cpp:1766 msgid "Spiral vase" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1753 +#: src/libslic3r/PrintConfig.cpp:1767 msgid "" "This feature will raise Z gradually while printing a single-walled object in " "order to remove any visible seam. This option requires a single perimeter, " @@ -6597,18 +7098,18 @@ msgid "" "when printing more than an object." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1761 +#: src/libslic3r/PrintConfig.cpp:1775 msgid "Temperature variation" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1762 +#: src/libslic3r/PrintConfig.cpp:1776 msgid "" "Temperature difference to be applied when an extruder is not active. Enables " "a full-height \"sacrificial\" skirt on which the nozzles are periodically " "wiped." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1772 +#: src/libslic3r/PrintConfig.cpp:1786 msgid "" "This start procedure is inserted at the beginning, after bed has reached the " "target temperature and extruder just started heating, and before extruder " @@ -6619,105 +7120,106 @@ msgid "" "\"M109 S[first_layer_temperature]\" command wherever you want." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1787 +#: src/libslic3r/PrintConfig.cpp:1801 msgid "" "This start procedure is inserted at the beginning, after any printer start " -"gcode. This is used to override settings for a specific filament. If Slic3r " -"detects M104, M109, M140 or M190 in your custom codes, such commands will " -"not be prepended automatically so you're free to customize the order of " +"gcode (and after any toolchange to this filament in case of multi-material " +"printers). This is used to override settings for a specific filament. If " +"Slic3r detects M104, M109, M140 or M190 in your custom codes, such commands " +"will not be prepended automatically so you're free to customize the order of " "heating commands and other custom actions. Note that you can use placeholder " "variables for all Slic3r settings, so you can put a \"M109 " "S[first_layer_temperature]\" command wherever you want. If you have multiple " "extruders, the gcode is processed in extruder order." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1802 +#: src/libslic3r/PrintConfig.cpp:1817 msgid "Single Extruder Multi Material" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1803 +#: src/libslic3r/PrintConfig.cpp:1818 msgid "The printer multiplexes filaments into a single hot end." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1808 +#: src/libslic3r/PrintConfig.cpp:1823 msgid "Prime all printing extruders" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1809 +#: src/libslic3r/PrintConfig.cpp:1824 msgid "" "If enabled, all printing extruders will be primed at the front edge of the " "print bed at the start of the print." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1814 +#: src/libslic3r/PrintConfig.cpp:1829 msgid "Generate support material" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1816 +#: src/libslic3r/PrintConfig.cpp:1831 msgid "Enable support material generation." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1820 +#: src/libslic3r/PrintConfig.cpp:1835 msgid "Auto generated supports" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1822 +#: src/libslic3r/PrintConfig.cpp:1837 msgid "" "If checked, supports will be generated automatically based on the overhang " "threshold value. If unchecked, supports will be generated inside the " "\"Support Enforcer\" volumes only." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1828 +#: src/libslic3r/PrintConfig.cpp:1843 msgid "XY separation between an object and its support" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1830 +#: src/libslic3r/PrintConfig.cpp:1845 msgid "" "XY separation between an object and its support. If expressed as percentage " "(for example 50%), it will be calculated over external perimeter width." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1840 +#: src/libslic3r/PrintConfig.cpp:1855 msgid "Pattern angle" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1842 +#: src/libslic3r/PrintConfig.cpp:1857 msgid "" "Use this setting to rotate the support material pattern on the horizontal " "plane." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1852 src/libslic3r/PrintConfig.cpp:2460 +#: src/libslic3r/PrintConfig.cpp:1867 src/libslic3r/PrintConfig.cpp:2531 msgid "" "Only create support if it lies on a build plate. Don't create support on a " "print." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1858 +#: src/libslic3r/PrintConfig.cpp:1873 msgid "Contact Z distance" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1860 +#: src/libslic3r/PrintConfig.cpp:1875 msgid "" "The vertical distance between object and support material interface. Setting " "this to 0 will also prevent Slic3r from using bridge flow and speed for the " "first object layer." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1867 +#: src/libslic3r/PrintConfig.cpp:1882 msgid "0 (soluble)" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1868 +#: src/libslic3r/PrintConfig.cpp:1883 msgid "0.2 (detachable)" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1873 +#: src/libslic3r/PrintConfig.cpp:1888 msgid "Enforce support for the first" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1875 +#: src/libslic3r/PrintConfig.cpp:1890 msgid "" "Generate support material for the specified number of layers counting from " "bottom, regardless of whether normal support material is enabled or not and " @@ -6725,21 +7227,21 @@ msgid "" "of objects having a very thin or poor footprint on the build plate." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1880 +#: src/libslic3r/PrintConfig.cpp:1895 msgid "Enforce support for the first n layers" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1886 +#: src/libslic3r/PrintConfig.cpp:1901 msgid "Support material/raft/skirt extruder" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1888 +#: src/libslic3r/PrintConfig.cpp:1903 msgid "" "The extruder to use when printing support material, raft and skirt (1+, 0 to " "use the current extruder to minimize tool changes)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1897 +#: src/libslic3r/PrintConfig.cpp:1912 msgid "" "Set this to a non-zero value to set a manual extrusion width for support " "material. If left zero, default extrusion width will be used if set, " @@ -6747,89 +7249,89 @@ msgid "" "example 90%) it will be computed over layer height." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1905 +#: src/libslic3r/PrintConfig.cpp:1920 msgid "Interface loops" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1907 +#: src/libslic3r/PrintConfig.cpp:1922 msgid "" "Cover the top contact layer of the supports with loops. Disabled by default." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1912 +#: src/libslic3r/PrintConfig.cpp:1927 msgid "Support material/raft interface extruder" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1914 +#: src/libslic3r/PrintConfig.cpp:1929 msgid "" "The extruder to use when printing support material interface (1+, 0 to use " "the current extruder to minimize tool changes). This affects raft too." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1921 +#: src/libslic3r/PrintConfig.cpp:1936 msgid "Interface layers" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1923 +#: src/libslic3r/PrintConfig.cpp:1938 msgid "" "Number of interface layers to insert between the object(s) and support " "material." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1930 +#: src/libslic3r/PrintConfig.cpp:1945 msgid "Interface pattern spacing" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1932 +#: src/libslic3r/PrintConfig.cpp:1947 msgid "Spacing between interface lines. Set zero to get a solid interface." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1941 +#: src/libslic3r/PrintConfig.cpp:1956 msgid "" "Speed for printing support material interface layers. If expressed as " "percentage (for example 50%) it will be calculated over support material " "speed." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1950 +#: src/libslic3r/PrintConfig.cpp:1965 msgid "Pattern" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1952 +#: src/libslic3r/PrintConfig.cpp:1967 msgid "Pattern used to generate support material." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1958 +#: src/libslic3r/PrintConfig.cpp:1973 msgid "Rectilinear grid" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1964 +#: src/libslic3r/PrintConfig.cpp:1979 msgid "Pattern spacing" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1966 +#: src/libslic3r/PrintConfig.cpp:1981 msgid "Spacing between support material lines." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1975 +#: src/libslic3r/PrintConfig.cpp:1990 msgid "Speed for printing support material." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1982 +#: src/libslic3r/PrintConfig.cpp:1997 msgid "Synchronize with object layers" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1984 +#: src/libslic3r/PrintConfig.cpp:1999 msgid "" "Synchronize support layers with the object print layers. This is useful with " "multi-material printers, where the extruder switch is expensive." msgstr "" -#: src/libslic3r/PrintConfig.cpp:1990 +#: src/libslic3r/PrintConfig.cpp:2005 msgid "Overhang threshold" msgstr "" -#: src/libslic3r/PrintConfig.cpp:1992 +#: src/libslic3r/PrintConfig.cpp:2007 msgid "" "Support material will not be generated for overhangs whose slope angle (90° " "= vertical) is above the given threshold. In other words, this value " @@ -6838,50 +7340,53 @@ msgid "" "detection (recommended)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2004 +#: src/libslic3r/PrintConfig.cpp:2019 msgid "With sheath around the support" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2006 +#: src/libslic3r/PrintConfig.cpp:2021 msgid "" "Add a sheath (a single perimeter line) around the base support. This makes " "the support more reliable, but also more difficult to remove." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2013 +#: src/libslic3r/PrintConfig.cpp:2028 msgid "" "Extruder temperature for layers after the first one. Set this to zero to " "disable temperature control commands in the output." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2021 +#: src/libslic3r/PrintConfig.cpp:2036 msgid "Detect thin walls" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2023 +#: src/libslic3r/PrintConfig.cpp:2038 msgid "" "Detect single-width walls (parts where two extrusions don't fit and we need " "to collapse them into a single trace)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2029 +#: src/libslic3r/PrintConfig.cpp:2044 msgid "Threads" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2030 +#: src/libslic3r/PrintConfig.cpp:2045 msgid "" "Threads are used to parallelize long-running tasks. Optimal threads number " "is slightly above the number of available cores/processors." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2042 +#: src/libslic3r/PrintConfig.cpp:2057 msgid "" -"This custom code is inserted right before every extruder change. Note that " -"you can use placeholder variables for all Slic3r settings as well as " -"[previous_extruder] and [next_extruder]." +"This custom code is inserted at every extruder change. If you don't leave " +"this empty, you are expected to take care of the toolchange yourself - " +"PrusaSlicer will not output any other G-code to change the filament. You can " +"use placeholder variables for all Slic3r settings as well as " +"[previous_extruder] and [next_extruder], so e.g. the standard toolchange " +"command can be scripted as T[next_extruder]." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2054 +#: src/libslic3r/PrintConfig.cpp:2070 msgid "" "Set this to a non-zero value to set a manual extrusion width for infill for " "top surfaces. You may want to use thinner extrudates to fill all narrow " @@ -6890,7 +7395,7 @@ msgid "" "percentage (for example 90%) it will be computed over layer height." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2065 +#: src/libslic3r/PrintConfig.cpp:2081 msgid "" "Speed for printing top solid layers (it only applies to the uppermost " "external layers and not to their internal solid layers). You may want to " @@ -6899,43 +7404,43 @@ msgid "" "for auto." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2080 +#: src/libslic3r/PrintConfig.cpp:2096 msgid "Number of solid layers to generate on top surfaces." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2081 +#: src/libslic3r/PrintConfig.cpp:2097 msgid "Top solid layers" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2087 +#: src/libslic3r/PrintConfig.cpp:2103 msgid "Speed for travel moves (jumps between distant extrusion points)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2095 +#: src/libslic3r/PrintConfig.cpp:2111 msgid "Use firmware retraction" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2096 +#: src/libslic3r/PrintConfig.cpp:2112 msgid "" "This experimental setting uses G10 and G11 commands to have the firmware " "handle the retraction. This is only supported in recent Marlin." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2102 +#: src/libslic3r/PrintConfig.cpp:2118 msgid "Use relative E distances" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2103 +#: src/libslic3r/PrintConfig.cpp:2119 msgid "" "If your firmware requires relative E values, check this, otherwise leave it " "unchecked. Most firmwares use absolute values." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2109 +#: src/libslic3r/PrintConfig.cpp:2125 msgid "Use volumetric E" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2110 +#: src/libslic3r/PrintConfig.cpp:2126 msgid "" "This experimental setting uses outputs the E values in cubic millimeters " "instead of linear millimeters. If your firmware doesn't already know " @@ -6945,127 +7450,127 @@ msgid "" "only supported in recent Marlin." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2120 +#: src/libslic3r/PrintConfig.cpp:2136 msgid "Enable variable layer height feature" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2121 +#: src/libslic3r/PrintConfig.cpp:2137 msgid "" "Some printers or printer setups may have difficulties printing with a " "variable layer height. Enabled by default." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2127 +#: src/libslic3r/PrintConfig.cpp:2143 msgid "Wipe while retracting" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2128 +#: src/libslic3r/PrintConfig.cpp:2144 msgid "" "This flag will move the nozzle while retracting to minimize the possible " "blob on leaky extruders." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2135 +#: src/libslic3r/PrintConfig.cpp:2151 msgid "" "Multi material printers may need to prime or purge extruders on tool " "changes. Extrude the excess material into the wipe tower." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2141 +#: src/libslic3r/PrintConfig.cpp:2157 msgid "Purging volumes - load/unload volumes" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2142 +#: src/libslic3r/PrintConfig.cpp:2158 msgid "" "This vector saves required volumes to change from/to each tool used on the " "wipe tower. These values are used to simplify creation of the full purging " "volumes below." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2148 +#: src/libslic3r/PrintConfig.cpp:2164 msgid "Purging volumes - matrix" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2149 +#: src/libslic3r/PrintConfig.cpp:2165 msgid "" "This matrix describes volumes (in cubic milimetres) required to purge the " "new filament on the wipe tower for any given pair of tools." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2158 +#: src/libslic3r/PrintConfig.cpp:2174 msgid "Position X" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2159 +#: src/libslic3r/PrintConfig.cpp:2175 msgid "X coordinate of the left front corner of a wipe tower" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2165 +#: src/libslic3r/PrintConfig.cpp:2181 msgid "Position Y" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2166 +#: src/libslic3r/PrintConfig.cpp:2182 msgid "Y coordinate of the left front corner of a wipe tower" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2173 +#: src/libslic3r/PrintConfig.cpp:2189 msgid "Width of a wipe tower" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2179 +#: src/libslic3r/PrintConfig.cpp:2195 msgid "Wipe tower rotation angle" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2180 +#: src/libslic3r/PrintConfig.cpp:2196 msgid "Wipe tower rotation angle with respect to x-axis." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2187 +#: src/libslic3r/PrintConfig.cpp:2203 msgid "Wipe into this object's infill" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2188 +#: src/libslic3r/PrintConfig.cpp:2204 msgid "" "Purging after toolchange will done inside this object's infills. This lowers " "the amount of waste but may result in longer print time due to additional " "travel moves." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2195 +#: src/libslic3r/PrintConfig.cpp:2211 msgid "Wipe into this object" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2196 +#: src/libslic3r/PrintConfig.cpp:2212 msgid "" "Object will be used to purge the nozzle after a toolchange to save material " "that would otherwise end up in the wipe tower and decrease print time. " "Colours of the objects will be mixed as a result." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2202 +#: src/libslic3r/PrintConfig.cpp:2218 msgid "Maximal bridging distance" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2203 +#: src/libslic3r/PrintConfig.cpp:2219 msgid "Maximal distance between supports on sparse infill sections." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2209 +#: src/libslic3r/PrintConfig.cpp:2225 msgid "XY Size Compensation" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2211 +#: src/libslic3r/PrintConfig.cpp:2227 msgid "" "The object will be grown/shrunk in the XY plane by the configured value " "(negative = inwards, positive = outwards). This might be useful for fine-" "tuning hole sizes." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2219 +#: src/libslic3r/PrintConfig.cpp:2235 msgid "Z offset" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2220 +#: src/libslic3r/PrintConfig.cpp:2236 msgid "" "This value will be added (or subtracted) from all the Z coordinates in the " "output G-code. It is used to compensate for bad Z endstop position: for " @@ -7073,308 +7578,345 @@ msgid "" "print bed, set this to -0.3 (or fix your endstop)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2237 +#: src/libslic3r/PrintConfig.cpp:2294 msgid "Display width" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2238 +#: src/libslic3r/PrintConfig.cpp:2295 msgid "Width of the display" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2243 +#: src/libslic3r/PrintConfig.cpp:2300 msgid "Display height" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2244 +#: src/libslic3r/PrintConfig.cpp:2301 msgid "Height of the display" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2249 +#: src/libslic3r/PrintConfig.cpp:2306 msgid "Number of pixels in" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2251 +#: src/libslic3r/PrintConfig.cpp:2308 msgid "Number of pixels in X" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2257 +#: src/libslic3r/PrintConfig.cpp:2314 msgid "Number of pixels in Y" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2262 +#: src/libslic3r/PrintConfig.cpp:2319 +msgid "Display horizontal mirroring" +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2320 +msgid "Mirror horizontally" +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2321 +msgid "Enable horizontal mirroring of output images" +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2326 +msgid "Display vertical mirroring" +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2327 +msgid "Mirror vertically" +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2328 +msgid "Enable vertical mirroring of output images" +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2333 msgid "Display orientation" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2263 +#: src/libslic3r/PrintConfig.cpp:2334 msgid "" "Set the actual LCD display orientation inside the SLA printer. Portrait mode " "will flip the meaning of display width and height parameters and the output " "images will be rotated by 90 degrees." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2269 +#: src/libslic3r/PrintConfig.cpp:2340 msgid "Landscape" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2270 +#: src/libslic3r/PrintConfig.cpp:2341 msgid "Portrait" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2275 +#: src/libslic3r/PrintConfig.cpp:2346 msgid "Fast" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2276 +#: src/libslic3r/PrintConfig.cpp:2347 msgid "Fast tilt" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2277 +#: src/libslic3r/PrintConfig.cpp:2348 msgid "Time of the fast tilt" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2284 +#: src/libslic3r/PrintConfig.cpp:2355 msgid "Slow" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2285 +#: src/libslic3r/PrintConfig.cpp:2356 msgid "Slow tilt" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2286 +#: src/libslic3r/PrintConfig.cpp:2357 msgid "Time of the slow tilt" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2293 +#: src/libslic3r/PrintConfig.cpp:2364 msgid "Area fill" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2294 +#: src/libslic3r/PrintConfig.cpp:2365 msgid "" "The percentage of the bed area. \n" "If the print area exceeds the specified value, \n" "then a slow tilt will be used, otherwise - a fast tilt" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2301 src/libslic3r/PrintConfig.cpp:2302 -#: src/libslic3r/PrintConfig.cpp:2303 +#: src/libslic3r/PrintConfig.cpp:2372 src/libslic3r/PrintConfig.cpp:2373 +#: src/libslic3r/PrintConfig.cpp:2374 msgid "Printer scaling correction" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2309 src/libslic3r/PrintConfig.cpp:2310 +#: src/libslic3r/PrintConfig.cpp:2380 src/libslic3r/PrintConfig.cpp:2381 msgid "Printer absolute correction" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2311 +#: src/libslic3r/PrintConfig.cpp:2382 msgid "" "Will inflate or deflate the sliced 2D polygons according to the sign of the " "correction." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2317 src/libslic3r/PrintConfig.cpp:2318 +#: src/libslic3r/PrintConfig.cpp:2388 src/libslic3r/PrintConfig.cpp:2389 msgid "Printer gamma correction" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2319 +#: src/libslic3r/PrintConfig.cpp:2390 msgid "" "This will apply a gamma correction to the rasterized 2D polygons. A gamma " "value of zero means thresholding with the threshold in the middle. This " "behaviour eliminates antialiasing without losing holes in polygons." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2330 src/libslic3r/PrintConfig.cpp:2331 +#: src/libslic3r/PrintConfig.cpp:2401 src/libslic3r/PrintConfig.cpp:2402 msgid "Initial layer height" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2337 +#: src/libslic3r/PrintConfig.cpp:2408 msgid "Faded layers" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2338 +#: src/libslic3r/PrintConfig.cpp:2409 msgid "" "Number of the layers needed for the exposure time fade from initial exposure " "time to the exposure time" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2345 src/libslic3r/PrintConfig.cpp:2346 +#: src/libslic3r/PrintConfig.cpp:2416 src/libslic3r/PrintConfig.cpp:2417 msgid "Exposure time" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2352 src/libslic3r/PrintConfig.cpp:2353 +#: src/libslic3r/PrintConfig.cpp:2423 src/libslic3r/PrintConfig.cpp:2424 msgid "Initial exposure time" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2359 src/libslic3r/PrintConfig.cpp:2360 +#: src/libslic3r/PrintConfig.cpp:2430 src/libslic3r/PrintConfig.cpp:2431 msgid "Correction for expansion" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2366 +#: src/libslic3r/PrintConfig.cpp:2437 msgid "SLA print material notes" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2367 +#: src/libslic3r/PrintConfig.cpp:2438 msgid "You can put your notes regarding the SLA print material here." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2375 src/libslic3r/PrintConfig.cpp:2386 +#: src/libslic3r/PrintConfig.cpp:2446 src/libslic3r/PrintConfig.cpp:2457 msgid "Default SLA material profile" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2397 +#: src/libslic3r/PrintConfig.cpp:2468 msgid "Generate supports" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2399 +#: src/libslic3r/PrintConfig.cpp:2470 msgid "Generate supports for the models" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2404 +#: src/libslic3r/PrintConfig.cpp:2475 msgid "Support head front diameter" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2406 +#: src/libslic3r/PrintConfig.cpp:2477 msgid "Diameter of the pointing side of the head" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2413 +#: src/libslic3r/PrintConfig.cpp:2484 msgid "Support head penetration" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2415 +#: src/libslic3r/PrintConfig.cpp:2486 msgid "How much the pinhead has to penetrate the model surface" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2422 +#: src/libslic3r/PrintConfig.cpp:2493 msgid "Support head width" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2424 +#: src/libslic3r/PrintConfig.cpp:2495 msgid "Width from the back sphere center to the front sphere center" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2432 +#: src/libslic3r/PrintConfig.cpp:2503 msgid "Support pillar diameter" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2434 +#: src/libslic3r/PrintConfig.cpp:2505 msgid "Diameter in mm of the support pillars" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2442 +#: src/libslic3r/PrintConfig.cpp:2513 msgid "Support pillar connection mode" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2443 +#: src/libslic3r/PrintConfig.cpp:2514 msgid "" "Controls the bridge type between two neighboring pillars. Can be zig-zag, " "cross (double zig-zag) or dynamic which will automatically switch between " "the first two depending on the distance of the two pillars." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2451 +#: src/libslic3r/PrintConfig.cpp:2522 msgid "Zig-Zag" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2452 +#: src/libslic3r/PrintConfig.cpp:2523 msgid "Cross" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2453 +#: src/libslic3r/PrintConfig.cpp:2524 msgid "Dynamic" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2465 +#: src/libslic3r/PrintConfig.cpp:2536 msgid "Pillar widening factor" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2467 +#: src/libslic3r/PrintConfig.cpp:2538 msgid "" "Merging bridges or pillars into another pillars can increase the radius. " "Zero means no increase, one means full increase." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2476 +#: src/libslic3r/PrintConfig.cpp:2547 msgid "Support base diameter" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2478 +#: src/libslic3r/PrintConfig.cpp:2549 msgid "Diameter in mm of the pillar base" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2486 +#: src/libslic3r/PrintConfig.cpp:2557 msgid "Support base height" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2488 +#: src/libslic3r/PrintConfig.cpp:2559 msgid "The height of the pillar base cone" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2495 +#: src/libslic3r/PrintConfig.cpp:2566 +msgid "Support base safety distance" +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2569 +msgid "" +"The minimum distance of the pillar base from the model in mm. Makes sense in " +"zero elevation mode where a gap according to this parameter is inserted " +"between the model and the pad." +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2579 msgid "Critical angle" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2497 +#: src/libslic3r/PrintConfig.cpp:2581 msgid "The default angle for connecting support sticks and junctions." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2505 +#: src/libslic3r/PrintConfig.cpp:2589 msgid "Max bridge length" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2507 +#: src/libslic3r/PrintConfig.cpp:2591 msgid "The max length of a bridge" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2514 +#: src/libslic3r/PrintConfig.cpp:2598 msgid "Max pillar linking distance" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2516 +#: src/libslic3r/PrintConfig.cpp:2600 msgid "" "The max distance of two pillars to get linked with each other. A zero value " "will prohibit pillar cascading." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2524 +#: src/libslic3r/PrintConfig.cpp:2608 msgid "Object elevation" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2526 -msgid "How much the supports should lift up the supported object." +#: src/libslic3r/PrintConfig.cpp:2610 +msgid "" +"How much the supports should lift up the supported object. If this value is " +"zero, the bottom of the model geometry will be considered as part of the pad." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2536 +#: src/libslic3r/PrintConfig.cpp:2622 msgid "This is a relative measure of support points density." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2542 +#: src/libslic3r/PrintConfig.cpp:2628 msgid "Minimal distance of the support points" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2544 +#: src/libslic3r/PrintConfig.cpp:2630 msgid "No support points will be placed closer than this threshold." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2550 +#: src/libslic3r/PrintConfig.cpp:2636 msgid "Use pad" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2552 +#: src/libslic3r/PrintConfig.cpp:2638 msgid "Add a pad underneath the supported model" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2557 +#: src/libslic3r/PrintConfig.cpp:2643 msgid "Pad wall thickness" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2559 +#: src/libslic3r/PrintConfig.cpp:2645 msgid "The thickness of the pad and its optional cavity walls." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2567 +#: src/libslic3r/PrintConfig.cpp:2653 msgid "Pad wall height" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2568 +#: src/libslic3r/PrintConfig.cpp:2654 msgid "" "Defines the pad cavity depth. Set to zero to disable the cavity. Be careful " "when enabling this feature, as some resins may produce an extreme suction " @@ -7382,279 +7924,317 @@ msgid "" "difficult." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2581 +#: src/libslic3r/PrintConfig.cpp:2667 msgid "Max merge distance" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2583 +#: src/libslic3r/PrintConfig.cpp:2669 msgid "" "Some objects can get along with a few smaller pads instead of a single big " "one. This parameter defines how far the center of two smaller pads should " "be. If theyare closer, they will get merged into one pad." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2594 +#: src/libslic3r/PrintConfig.cpp:2680 msgid "Pad edge radius" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2603 +#: src/libslic3r/PrintConfig.cpp:2689 msgid "Pad wall slope" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2605 +#: src/libslic3r/PrintConfig.cpp:2691 msgid "" "The slope of the pad wall relative to the bed plane. 90 degrees means " "straight walls." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2967 +#: src/libslic3r/PrintConfig.cpp:2700 +msgid "Pad object gap" +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2702 +msgid "" +"The gap between the object bottom and the generated pad in zero elevation " +"mode." +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2711 +msgid "Pad object connector stride" +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2713 +msgid "" +"Distance between two connector sticks between the object pad and the " +"generated pad." +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2721 +msgid "Pad object connector width" +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2723 +msgid "" +"The width of the connectors sticks which connect the object pad and the " +"generated pad." +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2731 +msgid "Pad object connector penetration" +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:2734 +msgid "How much should the tiny connectors penetrate into the model body." +msgstr "" + +#: src/libslic3r/PrintConfig.cpp:3094 msgid "Export OBJ" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2968 +#: src/libslic3r/PrintConfig.cpp:3095 msgid "Export the model(s) as OBJ." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2979 +#: src/libslic3r/PrintConfig.cpp:3106 msgid "Export SLA" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2980 +#: src/libslic3r/PrintConfig.cpp:3107 msgid "Slice the model and export SLA printing layers as PNG." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2985 +#: src/libslic3r/PrintConfig.cpp:3112 msgid "Export 3MF" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2986 +#: src/libslic3r/PrintConfig.cpp:3113 msgid "Export the model(s) as 3MF." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2990 +#: src/libslic3r/PrintConfig.cpp:3117 msgid "Export AMF" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2991 +#: src/libslic3r/PrintConfig.cpp:3118 msgid "Export the model(s) as AMF." msgstr "" -#: src/libslic3r/PrintConfig.cpp:2995 +#: src/libslic3r/PrintConfig.cpp:3122 msgid "Export STL" msgstr "" -#: src/libslic3r/PrintConfig.cpp:2996 +#: src/libslic3r/PrintConfig.cpp:3123 msgid "Export the model(s) as STL." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3001 +#: src/libslic3r/PrintConfig.cpp:3128 msgid "Slice the model and export toolpaths as G-code." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3006 +#: src/libslic3r/PrintConfig.cpp:3133 msgid "Slice" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3007 +#: src/libslic3r/PrintConfig.cpp:3134 msgid "" "Slice the model as FFF or SLA based on the printer_technology configuration " "value." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3012 +#: src/libslic3r/PrintConfig.cpp:3139 msgid "Help" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3013 +#: src/libslic3r/PrintConfig.cpp:3140 msgid "Show this help." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3018 +#: src/libslic3r/PrintConfig.cpp:3145 msgid "Help (FFF options)" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3019 +#: src/libslic3r/PrintConfig.cpp:3146 msgid "Show the full list of print/G-code configuration options." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3023 +#: src/libslic3r/PrintConfig.cpp:3150 msgid "Help (SLA options)" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3024 +#: src/libslic3r/PrintConfig.cpp:3151 msgid "Show the full list of SLA print configuration options." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3028 +#: src/libslic3r/PrintConfig.cpp:3155 msgid "Output Model Info" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3029 +#: src/libslic3r/PrintConfig.cpp:3156 msgid "Write information about the model to the console." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3033 +#: src/libslic3r/PrintConfig.cpp:3160 msgid "Save config file" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3034 +#: src/libslic3r/PrintConfig.cpp:3161 msgid "Save configuration to the specified file." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3044 +#: src/libslic3r/PrintConfig.cpp:3171 msgid "Align XY" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3045 +#: src/libslic3r/PrintConfig.cpp:3172 msgid "Align the model to the given point." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3050 +#: src/libslic3r/PrintConfig.cpp:3177 msgid "Cut model at the given Z." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3071 +#: src/libslic3r/PrintConfig.cpp:3198 msgid "Center" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3072 +#: src/libslic3r/PrintConfig.cpp:3199 msgid "Center the print around the given center." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3076 +#: src/libslic3r/PrintConfig.cpp:3203 msgid "Don't arrange" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3077 +#: src/libslic3r/PrintConfig.cpp:3204 msgid "" "Do not rearrange the given models before merging and keep their original XY " "coordinates." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3080 +#: src/libslic3r/PrintConfig.cpp:3207 msgid "Duplicate" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3081 +#: src/libslic3r/PrintConfig.cpp:3208 msgid "Multiply copies by this factor." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3085 +#: src/libslic3r/PrintConfig.cpp:3212 msgid "Duplicate by grid" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3086 +#: src/libslic3r/PrintConfig.cpp:3213 msgid "Multiply copies by creating a grid." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3089 +#: src/libslic3r/PrintConfig.cpp:3216 msgid "Merge" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3090 +#: src/libslic3r/PrintConfig.cpp:3217 msgid "" "Arrange the supplied models in a plate and merge them in a single model in " "order to perform actions once." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3095 +#: src/libslic3r/PrintConfig.cpp:3222 msgid "" "Try to repair any non-manifold meshes (this option is implicitly added " "whenever we need to slice the model to perform the requested action)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3099 +#: src/libslic3r/PrintConfig.cpp:3226 msgid "Rotation angle around the Z axis in degrees." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3103 +#: src/libslic3r/PrintConfig.cpp:3230 msgid "Rotate around X" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3104 +#: src/libslic3r/PrintConfig.cpp:3231 msgid "Rotation angle around the X axis in degrees." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3108 +#: src/libslic3r/PrintConfig.cpp:3235 msgid "Rotate around Y" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3109 +#: src/libslic3r/PrintConfig.cpp:3236 msgid "Rotation angle around the Y axis in degrees." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3114 +#: src/libslic3r/PrintConfig.cpp:3241 msgid "Scaling factor or percentage." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3119 +#: src/libslic3r/PrintConfig.cpp:3246 msgid "" "Detect unconnected parts in the given model(s) and split them into separate " "objects." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3122 +#: src/libslic3r/PrintConfig.cpp:3249 msgid "Scale to Fit" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3123 +#: src/libslic3r/PrintConfig.cpp:3250 msgid "Scale to fit the given volume." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3132 +#: src/libslic3r/PrintConfig.cpp:3259 msgid "Ignore non-existent config files" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3133 +#: src/libslic3r/PrintConfig.cpp:3260 msgid "Do not fail if a file supplied to --load does not exist." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3136 +#: src/libslic3r/PrintConfig.cpp:3263 msgid "Load config file" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3137 +#: src/libslic3r/PrintConfig.cpp:3264 msgid "" "Load configuration from the specified file. It can be used more than once to " "load options from multiple files." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3140 +#: src/libslic3r/PrintConfig.cpp:3267 msgid "Output File" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3141 +#: src/libslic3r/PrintConfig.cpp:3268 msgid "" "The file where the output will be written (if not specified, it will be " "based on the input file)." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3151 +#: src/libslic3r/PrintConfig.cpp:3278 msgid "Data directory" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3152 +#: src/libslic3r/PrintConfig.cpp:3279 msgid "" "Load and store settings at the given directory. This is useful for " "maintaining different profiles or including configurations from a network " "storage." msgstr "" -#: src/libslic3r/PrintConfig.cpp:3155 +#: src/libslic3r/PrintConfig.cpp:3282 msgid "Logging level" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3156 +#: src/libslic3r/PrintConfig.cpp:3283 msgid "" "Messages with severity lower or eqal to the loglevel will be printed out. 0:" "trace, 1:debug, 2:info, 3:warning, 4:error, 5:fatal" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3161 +#: src/libslic3r/PrintConfig.cpp:3288 msgid "Render with a software renderer" msgstr "" -#: src/libslic3r/PrintConfig.cpp:3162 +#: src/libslic3r/PrintConfig.cpp:3289 msgid "" "Render with a software renderer. The bundled MESA software renderer is " "loaded instead of the default OpenGL driver." @@ -7696,21 +8276,21 @@ msgstr "" msgid "Volumetric flow rate (mm3/s)" msgstr "" -#: src/libslic3r/GCode/PreviewData.cpp:491 +#: src/libslic3r/GCode/PreviewData.cpp:493 msgid "Default print color" msgstr "" -#: src/libslic3r/GCode/PreviewData.cpp:495 +#: src/libslic3r/GCode/PreviewData.cpp:500 #, possible-c-format msgid "up to %.2f mm" msgstr "" -#: src/libslic3r/GCode/PreviewData.cpp:499 +#: src/libslic3r/GCode/PreviewData.cpp:504 #, possible-c-format msgid "above %.2f mm" msgstr "" -#: src/libslic3r/GCode/PreviewData.cpp:504 +#: src/libslic3r/GCode/PreviewData.cpp:509 #, possible-c-format msgid "%.2f - %.2f mm" msgstr "" diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx index 81b1ca15f..99f7f0ba3 100644 --- a/resources/profiles/PrusaResearch.idx +++ b/resources/profiles/PrusaResearch.idx @@ -1,3 +1,7 @@ +min_slic3r_version = 2.1.0-alpha0 +1.0.0-beta1 Updated color for the ASA filaments to differ from the other filaments. Single extruder printers now have no extruder color assigned, obects and toolpaths will be colored with the color of the active filament. +1.0.0-beta0 Printer model checks in start G-codes, ASA filament profiles, limits on min / max SL1 exposition times +1.0.0-alpha0 Filament specific retract for PET and similar copolymers, and for FLEX min_slic3r_version = 1.42.0-alpha6 0.8.3 FW version and SL1 materials update 0.8.2 FFF and SL1 settings update diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 7a3d7f020..0f4e60ab3 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -8,7 +8,7 @@ technologies = FFF; SLA # Configuration version of this file. Config file will only be installed, if the config_version differs. # This means, the server may force the PrusaSlicer configuration to be downgraded. -config_version = 0.8.3 +config_version = 1.0.0-beta1 # Where to get the updates from? config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/ changelog_url = http://files.prusa3d.com/?latest=slicer-profiles&lng=%1% @@ -821,7 +821,7 @@ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and # MK2 MMU # [print:0.35mm FAST sol full 0.6 nozzle] inherits = *0.35mm*; *0.6nozzle*; *soluble_support* -compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_model=="MK2SMM" and nozzle_diameter[0]==0.6 and num_extruders>1 external_perimeter_extrusion_width = 0.6 external_perimeter_speed = 30 notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder @@ -886,8 +886,8 @@ solid_infill_speed = 70 top_solid_infill_speed = 45 external_perimeter_extrusion_width = 0.7 perimeter_extrusion_width = 0.7 -infill_extrusion_width = 0.72 -solid_infill_extrusion_width = 0.72 +infill_extrusion_width = 0.7 +solid_infill_extrusion_width = 0.7 # XXXXXXXXXXXXXXXXXXXXXX # XXX----- MK2.5 ----XXX @@ -1019,12 +1019,22 @@ max_fan_speed = 50 min_fan_speed = 30 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{elsif nozzle_diameter[0]==0.6}24{else}45{endif} ; Filament gcode" temperature = 240 +filament_retract_length = 1.4 +filament_retract_lift = 0.2 +compatible_printers_condition = printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) [filament:*PET06*] inherits = *PET* -compatible_printers_condition = nozzle_diameter[0]==0.6 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) +compatible_printers_condition = nozzle_diameter[0]==0.6 and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) filament_max_volumetric_speed = 15 +[filament:*PETMMU1*] +inherits = *PET* +filament_retract_length = nil +filament_retract_speed = nil +filament_retract_lift = 0.2 +compatible_printers_condition = printer_model=="MK2SMM" + [filament:*ABS*] inherits = *common* bed_temperature = 110 @@ -1049,7 +1059,7 @@ inherits = *common* bed_temperature = 50 bridge_fan_speed = 100 # For now, all but selected filaments are disabled for the MMU 2.0 -compatible_printers_condition = nozzle_diameter[0]>0.35 and num_extruders==1 && ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material) +compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model!="MK2SMM" and num_extruders==1 && ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material) cooling = 0 disable_fan_first_layers = 1 extrusion_multiplier = 1.2 @@ -1062,8 +1072,10 @@ first_layer_bed_temperature = 50 first_layer_temperature = 240 max_fan_speed = 90 min_fan_speed = 70 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +start_filament_gcode = "M900 K0"; Filament gcode" temperature = 240 +filament_retract_length = 0.4 +filament_retract_lift = 0 [filament:ColorFabb Brass Bronze] inherits = *PLA* @@ -1134,7 +1146,7 @@ temperature = 270 [filament:ColorFabb XT-CF20] inherits = *PET* -compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) +compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) extrusion_multiplier = 1.2 filament_cost = 80.65 filament_density = 1.35 @@ -1144,6 +1156,8 @@ first_layer_bed_temperature = 90 first_layer_temperature = 260 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" temperature = 260 +filament_retract_length = nil +filament_retract_lift = 0.2 [filament:ColorFabb nGen] inherits = *PET* @@ -1173,13 +1187,15 @@ first_layer_temperature = 260 max_fan_speed = 35 min_fan_speed = 20 temperature = 260 +filament_retract_length = nil +filament_retract_lift = 0 +compatible_printers_condition = nozzle_diameter[0]>0.35 and num_extruders==1 && ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material) [filament:E3D Edge] inherits = *PET* filament_cost = 56.9 filament_density = 1.26 filament_type = EDGE -filament_notes = "List of manufacturers tested with standard PET print settings:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladec PETG" [filament:E3D PC-ABS] inherits = *ABS* @@ -1199,17 +1215,31 @@ temperature = 240 [filament:Fillamentum ASA] inherits = *ABS* filament_cost = 38.7 -filament_density = 1.04 +filament_density = 1.07 fan_always_on = 1 first_layer_temperature = 265 temperature = 265 filament_type = ASA -[filament:Fillamentum CPE HG100 HM100] +[filament:Prusament ASA] +inherits = *ABS* +filament_cost = 35.28 +filament_density = 1.07 +fan_always_on = 1 +first_layer_temperature = 260 +first_layer_bed_temperature = 105 +temperature = 260 +bed_temperature = 110 +min_fan_speed = 20 +disable_fan_first_layers = 4 +filament_type = ASA +filament_colour = #FFF2EC +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{elsif nozzle_diameter[0]==0.6}12{else}20{endif} ; Filament gcode" + +[filament:Fillamentum CPE] inherits = *PET* filament_cost = 54.1 filament_density = 1.25 -filament_notes = "CPE HG100 , CPE HM100" filament_type = CPE first_layer_bed_temperature = 90 first_layer_temperature = 275 @@ -1248,6 +1278,15 @@ filament_cost = 25.4 filament_density = 1.24 filament_notes = "List of materials tested with standard PLA print settings:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" +[filament:Generic FLEX] +inherits = *FLEX* +filament_cost = 82 +filament_density = 1.22 +filament_max_volumetric_speed = 1.2 +filament_retract_length = 0 +filament_retract_speed = nil +filament_retract_lift = nil + [filament:Polymaker PC-Max] inherits = *ABS* filament_cost = 77.3 @@ -1297,6 +1336,24 @@ filament_unloading_speed = 20 [filament:Generic ABS MMU2] inherits = *ABS MMU2* +[filament:Prusament ASA MMU2] +inherits = *ABS MMU2* +filament_cost = 35.28 +filament_density = 1.07 +fan_always_on = 1 +first_layer_temperature = 260 +first_layer_bed_temperature = 105 +temperature = 260 +bed_temperature = 110 +min_fan_speed = 20 +disable_fan_first_layers = 4 +filament_cooling_final_speed = 2 +filament_cooling_initial_speed = 3 +filament_cooling_moves = 1 +filament_type = ASA +filament_colour = #FFF2EC +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{elsif nozzle_diameter[0]==0.6}12{else}20{endif} ; Filament gcode" + [filament:Prusa ABS MMU2] inherits = *ABS MMU2* @@ -1323,7 +1380,7 @@ inherits = *PET* filament_cost = 27.82 filament_density = 1.27 filament_notes = "List of manufacturers tested with standard PET print settings:\n\nE3D Edge\nPlasty Mladec PETG" -compatible_printers_condition = nozzle_diameter[0]!=0.6 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) +compatible_printers_condition = nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) [filament:Prusament PETG] inherits = *PET* @@ -1332,7 +1389,7 @@ temperature = 250 filament_cost = 24.99 filament_density = 1.27 filament_type = PETG -compatible_printers_condition = nozzle_diameter[0]!=0.6 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) +compatible_printers_condition = nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) [filament:Prusa PET 0.6 nozzle] inherits = *PET06* @@ -1350,7 +1407,7 @@ filament_type = PETG [filament:*PET MMU2*] inherits = Prusa PET -compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material +compatible_printers_condition = nozzle_diameter[0]!=0.6 and printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material temperature = 230 first_layer_temperature = 230 filament_cooling_final_speed = 1 @@ -1364,6 +1421,13 @@ filament_unload_time = 12 filament_unloading_speed = 20 filament_unloading_speed_start = 120 filament_loading_speed_start = 19 +filament_retract_length = 1.4 +filament_retract_lift = 0.2 + +[filament:*PET MMU2 06*] +inherits = *PET MMU2* +compatible_printers_condition = nozzle_diameter[0]==0.6 and printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material +filament_max_volumetric_speed = 13 [filament:Generic PET MMU2] inherits = *PET MMU2* @@ -1375,6 +1439,16 @@ inherits = *PET MMU2* inherits = *PET MMU2* filament_type = PETG +[filament:Generic PET MMU2 0.6 nozzle] +inherits = *PET MMU2 06* + +[filament:Prusa PET MMU2 0.6 nozzle] +inherits = *PET MMU2 06* + +[filament:Prusament PETG MMU2 0.6 nozzle] +inherits = *PET MMU2 06* +filament_type = PETG + [filament:Prusa PLA] inherits = *PLA* filament_cost = 25.4 @@ -1417,6 +1491,7 @@ inherits = *PLA MMU2* inherits = *FLEX* filament_cost = 82 filament_density = 1.22 +filament_max_volumetric_speed = 1.35 [filament:Taulman Bridge] inherits = *common* @@ -1554,6 +1629,130 @@ min_fan_speed = 100 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" temperature = 220 +## Filaments MMU1 + +[filament:ColorFabb HT MMU1] +inherits = *PETMMU1* +bed_temperature = 110 +bridge_fan_speed = 30 +cooling = 1 +disable_fan_first_layers = 3 +fan_always_on = 0 +fan_below_layer_time = 10 +filament_cost = 58.66 +filament_density = 1.18 +first_layer_bed_temperature = 105 +first_layer_temperature = 270 +max_fan_speed = 20 +min_fan_speed = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" +temperature = 270 + +[filament:ColorFabb XT MMU1] +inherits = *PETMMU1* +filament_type = PET +filament_cost = 62.9 +filament_density = 1.27 +first_layer_bed_temperature = 90 +first_layer_temperature = 260 +temperature = 270 + +[filament:ColorFabb XT-CF20 MMU1] +inherits = *PETMMU1* +compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model=="MK2SMM" +extrusion_multiplier = 1.2 +filament_cost = 80.65 +filament_density = 1.35 +filament_colour = #804040 +filament_max_volumetric_speed = 1 +first_layer_bed_temperature = 90 +first_layer_temperature = 260 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 260 + +[filament:ColorFabb nGen MMU1] +inherits = *PETMMU1* +filament_cost = 21.2 +filament_density = 1.2 +bridge_fan_speed = 40 +fan_always_on = 0 +fan_below_layer_time = 10 +filament_type = NGEN +first_layer_temperature = 240 +max_fan_speed = 35 +min_fan_speed = 20 + +[filament:E3D Edge MMU1] +inherits = *PETMMU1* +filament_cost = 56.9 +filament_density = 1.26 +filament_type = EDGE +filament_notes = "List of manufacturers tested with standard PET print settings:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladec PETG" + +[filament:Fillamentum CPE MMU1] +inherits = *PETMMU1* +filament_cost = 54.1 +filament_density = 1.25 +filament_type = CPE +first_layer_bed_temperature = 90 +first_layer_temperature = 275 +max_fan_speed = 50 +min_fan_speed = 50 +temperature = 275 + +[filament:Generic PET MMU1] +inherits = *PETMMU1* +filament_cost = 27.82 +filament_density = 1.27 +filament_notes = "List of manufacturers tested with standard PET print settings:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladec PETG" + +[filament:Prusa PET MMU1] +inherits = *PETMMU1* +filament_cost = 27.82 +filament_density = 1.27 +filament_notes = "List of manufacturers tested with standard PET print settings:\n\nE3D Edge\nPlasty Mladec PETG" + +[filament:Prusament PETG MMU1] +inherits = *PETMMU1* +first_layer_temperature = 240 +temperature = 250 +filament_cost = 24.99 +filament_density = 1.27 +filament_type = PETG + +[filament:Taulman T-Glase MMU1] +inherits = *PETMMU1* +filament_cost = 40 +filament_density = 1.27 +bridge_fan_speed = 40 +cooling = 0 +fan_always_on = 0 +first_layer_bed_temperature = 90 +first_layer_temperature = 240 +max_fan_speed = 5 +min_fan_speed = 0 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" + +[filament:SemiFlex or Flexfill 98A MMU1] +inherits = *FLEX* +filament_cost = 82 +filament_density = 1.22 +filament_max_volumetric_speed = 1.35 +filament_retract_length = nil +filament_retract_speed = nil +filament_retract_lift = nil +compatible_printers_condition = printer_model=="MK2SMM" + +[filament:Generic FLEX MMU1] +inherits = *FLEX* +filament_cost = 82 +filament_density = 1.22 +filament_max_volumetric_speed = 1.2 +filament_retract_length = 0 +filament_retract_speed = nil +filament_retract_lift = nil +compatible_printers_condition = printer_model=="MK2SMM" + [sla_print:*common*] compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_SL1.*/ layer_height = 0.05 @@ -1658,37 +1857,37 @@ initial_exposure_time = 100 [sla_material:Prusa Orange Tough 0.025] inherits = *common 0.025* exposure_time = 6 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Grey Tough 0.025] inherits = *common 0.025* exposure_time = 7 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Azure Blue Tough 0.025] inherits = *common 0.025* exposure_time = 7 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Maroon Tough 0.025] inherits = *common 0.025* exposure_time = 6 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Beige Tough 0.025] inherits = *common 0.025* exposure_time = 6 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Pink Tough 0.025] inherits = *common 0.025* exposure_time = 7 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa White Tough 0.025] inherits = *common 0.025* exposure_time = 6.5 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Transparent Tough 0.025] inherits = *common 0.025* @@ -1703,7 +1902,7 @@ initial_exposure_time = 35 ## [sla_material:Prusa Transparent Green Tough 0.025] ## inherits = *common 0.025* ## exposure_time = 5 -## initial_exposure_time = 30 +## initial_exposure_time = 35 ########### Materials 0.05 @@ -1822,42 +2021,42 @@ initial_exposure_time = 30 [sla_material:Prusa Beige Tough 0.05] inherits = *common 0.05* exposure_time = 7 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Orange Tough 0.05] inherits = *common 0.05* exposure_time = 7.5 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Grey Tough 0.05] inherits = *common 0.05* exposure_time = 8.5 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Black Tough 0.05] inherits = *common 0.05* exposure_time = 6 -initial_exposure_time = 30 +initial_exposure_time = 35 ## [sla_material:Prusa Beige Super Low Odor 0.05] ## inherits = *common 0.05* ## exposure_time = 7.5 -## initial_exposure_time = 30 +## initial_exposure_time = 35 ## [sla_material:Prusa White Super Low Odor 0.05] ## inherits = *common 0.05* ## exposure_time = 6.5 -## initial_exposure_time = 30 +## initial_exposure_time = 35 ## [sla_material:Prusa Grey Super Low Odor 0.05] ## inherits = *common 0.05* ## exposure_time = 6.5 -## initial_exposure_time = 30 +## initial_exposure_time = 35 ## [sla_material:Prusa Black High Tenacity 0.05] ## inherits = *common 0.05* ## exposure_time = 7 -## initial_exposure_time = 30 +## initial_exposure_time = 35 [sla_material:Prusa Green Casting 0.05] inherits = *common 0.05* @@ -1867,37 +2066,37 @@ initial_exposure_time = 40 ## [sla_material:Prusa Yellow Solid 0.05] ## inherits = *common 0.05* ## exposure_time = 7 -## initial_exposure_time = 30 +## initial_exposure_time = 35 [sla_material:Prusa White Tough 0.05] inherits = *common 0.05* exposure_time = 7.5 -initial_exposure_time = 30 +initial_exposure_time = 35 ## [sla_material:Prusa Transparent Green Tough 0.05] ## inherits = *common 0.05* ## exposure_time = 6 -## initial_exposure_time = 30 +## initial_exposure_time = 35 [sla_material:Prusa Transparent Red Tough 0.05] inherits = *common 0.05* exposure_time = 6 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Maroon Tough 0.05] inherits = *common 0.05* exposure_time = 7.5 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Pink Tough 0.05] inherits = *common 0.05* exposure_time = 8 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Azure Blue Tough 0.05] inherits = *common 0.05* exposure_time = 8 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Transparent Tough 0.05] inherits = *common 0.05* @@ -1907,7 +2106,7 @@ initial_exposure_time = 15 ## [sla_material:Prusa Yellow Flexible 0.05] ## inherits = *common 0.05* ## exposure_time = 9 -## initial_exposure_time = 30 +## initial_exposure_time = 35 ## [sla_material:Prusa Clear Flexible 0.05] ## inherits = *common 0.05* @@ -1917,29 +2116,29 @@ initial_exposure_time = 15 ## [sla_material:Prusa White Flexible 0.05] ## inherits = *common 0.05* ## exposure_time = 9 -## initial_exposure_time = 30 +## initial_exposure_time = 35 ## [sla_material:Prusa Blue Flexible 0.05] ## inherits = *common 0.05* ## exposure_time = 9 -## initial_exposure_time = 30 +## initial_exposure_time = 35 ## [sla_material:Prusa Black Flexible 0.05] ## inherits = *common 0.05* ## exposure_time = 9 -## initial_exposure_time = 30 +## initial_exposure_time = 35 ## [sla_material:Prusa Red Flexible 0.05] ## inherits = *common 0.05* ## exposure_time = 9 -## initial_exposure_time = 30 +## initial_exposure_time = 35 ########### Materials 0.035 [sla_material:Prusa Orange Tough 0.035] inherits = *common 0.035* exposure_time = 6 -initial_exposure_time = 30 +initial_exposure_time = 35 ########### Materials 0.1 @@ -1981,7 +2180,7 @@ initial_exposure_time = 55 [sla_material:Prusa Transparent Tough 0.1] inherits = *common 0.1* exposure_time = 8 -initial_exposure_time = 30 +initial_exposure_time = 35 [sla_material:Prusa Green Casting 0.1] inherits = *common 0.1* @@ -1995,7 +2194,6 @@ before_layer_gcode = ;BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]\n\n between_objects_gcode = deretract_speed = 0 end_gcode = G4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors -extruder_colour = #FFFF00 extruder_offset = 0x0 gcode_flavor = marlin silent_mode = 0 @@ -2039,7 +2237,7 @@ retract_speed = 35 serial_port = serial_speed = 250000 single_extruder_multi_material = 0 -start_gcode = M115 U3.2.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting] ; MK2 firmware only supports the old M204 format\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.2.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting] ; MK2 firmware only supports the old M204 format\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 toolchange_gcode = use_firmware_retraction = 0 use_relative_e_distances = 1 @@ -2076,7 +2274,7 @@ printer_model = MK2SMM inherits = *multimaterial* end_gcode = G1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors\n\n printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN -start_gcode = M115 U3.2.3 ; tell printer latest fw version\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting] ; MK2 firmware only supports the old M204 format\n; Start G-Code sequence START\nT?\nM104 S[first_layer_temperature]\nM140 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nM190 S[first_layer_bed_temperature]\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100\nM92 E140\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.2.3 ; tell printer latest fw version\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting] ; MK2 firmware only supports the old M204 format\n; Start G-Code sequence START\nT?\nM104 S[first_layer_temperature]\nM140 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nM190 S[first_layer_bed_temperature]\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100\nM92 E140\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG92 E0.0 default_print_profile = 0.15mm OPTIMAL [printer:*mm-multi*] @@ -2086,7 +2284,7 @@ end_gcode = {if not has_wipe_tower}\n; Pull the filament into the cooling tubes. extruder_colour = #FFAA55;#E37BA0;#4ECDD3;#FB7259 nozzle_diameter = 0.4,0.4,0.4,0.4 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN -start_gcode = M115 U3.2.3 ; tell printer latest fw version\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting] ; MK2 firmware only supports the old M204 format\n; Start G-Code sequence START\nT[initial_tool]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100 ; set max feedrate\nM92 E140 ; E-steps per filament milimeter\n{if not has_single_extruder_multi_material_priming}\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\n{endif}\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.2.3 ; tell printer latest fw version\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting] ; MK2 firmware only supports the old M204 format\n; Start G-Code sequence START\nT[initial_tool]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100 ; set max feedrate\nM92 E140 ; E-steps per filament milimeter\n{if not has_single_extruder_multi_material_priming}\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\n{endif}\nG92 E0.0 default_print_profile = 0.15mm OPTIMAL # XXXXXXXXXXXXXXXXX @@ -2154,19 +2352,19 @@ min_layer_height = 0.1 inherits = Original Prusa i3 MK2S printer_model = MK2.5 remaining_times = 1 -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5 0.25 nozzle] inherits = Original Prusa i3 MK2S 0.25 nozzle printer_model = MK2.5 remaining_times = 1 -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5 0.6 nozzle] inherits = Original Prusa i3 MK2S 0.6 nozzle printer_model = MK2.5 remaining_times = 1 -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5 MMU2 Single] inherits = Original Prusa i3 MK2.5; *mm2* @@ -2195,7 +2393,7 @@ machine_min_travel_rate = 0 default_print_profile = 0.15mm OPTIMAL MK2.5 default_filament_profile = Prusament PLA printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\n; select extruder\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; load to nozzle\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\n; select extruder\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; load to nozzle\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors [printer:Original Prusa i3 MK2.5 MMU2 Single 0.6 nozzle] @@ -2237,23 +2435,23 @@ single_extruder_multi_material = 1 # to be defined explicitely. nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors\n [printer:Original Prusa i3 MK2.5S] inherits = Original Prusa i3 MK2.5 printer_model = MK2.5S -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5S 0.25 nozzle] inherits = Original Prusa i3 MK2.5 0.25 nozzle printer_model = MK2.5S -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5S 0.6 nozzle] inherits = Original Prusa i3 MK2.5 0.6 nozzle printer_model = MK2.5S -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5S MMU2S Single] inherits = Original Prusa i3 MK2.5; *mm2s* @@ -2282,7 +2480,7 @@ machine_min_travel_rate = 0 default_print_profile = 0.15mm OPTIMAL MK2.5 default_filament_profile = Prusament PLA printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors [printer:Original Prusa i3 MK2.5S MMU2S Single 0.6 nozzle] @@ -2302,7 +2500,7 @@ min_layer_height = 0.05 nozzle_diameter = 0.25 printer_variant = 0.25 default_print_profile = 0.10mm DETAIL 0.25 nozzle -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F1400.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F1400.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n [printer:Original Prusa i3 MK2.5S MMU2S] inherits = Original Prusa i3 MK2.5; *mm2s* @@ -2335,9 +2533,24 @@ single_extruder_multi_material = 1 # to be defined explicitely. nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors\n +[printer:Original Prusa i3 MK2.5S MMU2S 0.6 nozzle] +inherits = Original Prusa i3 MK2.5S MMU2S +nozzle_diameter = 0.6,0.6,0.6,0.6,0.6 +max_layer_height = 0.40 +min_layer_height = 0.15 +printer_variant = 0.6 +default_print_profile = 0.20mm NORMAL 0.6 nozzle + +[printer:Original Prusa i3 MK2.5 MMU2 0.6 nozzle] +inherits = Original Prusa i3 MK2.5 MMU2 +nozzle_diameter = 0.6,0.6,0.6,0.6,0.6 +max_layer_height = 0.40 +min_layer_height = 0.15 +printer_variant = 0.6 +default_print_profile = 0.20mm NORMAL 0.6 nozzle # XXXXXXXXXXXXXXXXX # XXX--- MK3 ---XXX @@ -2367,7 +2580,7 @@ remaining_times = 1 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n retract_lift_below = 209 max_print_height = 210 -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} printer_model = MK3 default_print_profile = 0.15mm QUALITY MK3 @@ -2377,7 +2590,7 @@ nozzle_diameter = 0.25 max_layer_height = 0.15 min_layer_height = 0.05 printer_variant = 0.25 -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E8.0 F700.0 ; intro line\nG1 X100.0 E12.5 F700.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E8.0 F700.0 ; intro line\nG1 X100.0 E12.5 F700.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} default_print_profile = 0.10mm DETAIL 0.25 nozzle MK3 [printer:Original Prusa i3 MK3 0.6 nozzle] @@ -2391,17 +2604,17 @@ default_print_profile = 0.30mm QUALITY 0.6 nozzle MK3 [printer:Original Prusa i3 MK3S] inherits = Original Prusa i3 MK3 printer_model = MK3S -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} [printer:Original Prusa i3 MK3S 0.25 nozzle] inherits = Original Prusa i3 MK3 0.25 nozzle printer_model = MK3S -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E8.0 F700.0 ; intro line\nG1 X100.0 E12.5 F700.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E8.0 F700.0 ; intro line\nG1 X100.0 E12.5 F700.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} [printer:Original Prusa i3 MK3S 0.6 nozzle] inherits = Original Prusa i3 MK3 0.6 nozzle printer_model = MK3S -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif} [printer:*mm2*] inherits = Original Prusa i3 MK3 @@ -2431,7 +2644,7 @@ default_filament_profile = Prusament PLA MMU2 inherits = *mm2* single_extruder_multi_material = 0 default_filament_profile = Prusament PLA -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors [printer:Original Prusa i3 MK3 MMU2 Single 0.6 nozzle] @@ -2450,7 +2663,7 @@ nozzle_diameter = 0.25 max_layer_height = 0.15 min_layer_height = 0.05 printer_variant = 0.25 -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F1000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F1400.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F1000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F1400.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n default_print_profile = 0.10mm DETAIL 0.25 nozzle MK3 [printer:Original Prusa i3 MK3 MMU2] @@ -2461,14 +2674,14 @@ inherits = *mm2* machine_max_acceleration_e = 8000,8000 nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors\n [printer:Original Prusa i3 MK3S MMU2S Single] inherits = *mm2s* single_extruder_multi_material = 0 default_filament_profile = Prusament PLA -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors [printer:Original Prusa i3 MK3S MMU2S Single 0.6 nozzle] @@ -2487,7 +2700,7 @@ nozzle_diameter = 0.25 max_layer_height = 0.15 min_layer_height = 0.05 printer_variant = 0.25 -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F1400.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F1400.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n default_print_profile = 0.10mm DETAIL 0.25 nozzle MK3 [printer:Original Prusa i3 MK3S MMU2S] @@ -2495,18 +2708,26 @@ inherits = *mm2s* machine_max_acceleration_e = 8000,8000 nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F -start_gcode = M115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n +start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.7.2 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0\n end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors\n -# 0.6 nozzle MMU printer profile - only for single mode for now +## 0.6mm nozzle MMU2/S printer profiles -# [printer:Original Prusa i3 MK3S MMU2S 0.6 nozzle] -# inherits = Original Prusa i3 MK3S MMU2S -# nozzle_diameter = 0.6,0.6,0.6,0.6,0.6 -# max_layer_height = 0.40 -# min_layer_height = 0.15 -# printer_variant = 0.6 -# default_print_profile = 0.30mm QUALITY 0.6 nozzle MK3 +[printer:Original Prusa i3 MK3S MMU2S 0.6 nozzle] +inherits = Original Prusa i3 MK3S MMU2S +nozzle_diameter = 0.6,0.6,0.6,0.6,0.6 +max_layer_height = 0.40 +min_layer_height = 0.15 +printer_variant = 0.6 +default_print_profile = 0.30mm QUALITY 0.6 nozzle MK3 + +[printer:Original Prusa i3 MK3 MMU2 0.6 nozzle] +inherits = Original Prusa i3 MK3 MMU2 +nozzle_diameter = 0.6,0.6,0.6,0.6,0.6 +max_layer_height = 0.40 +min_layer_height = 0.15 +printer_variant = 0.6 +default_print_profile = 0.30mm QUALITY 0.6 nozzle MK3 [printer:Original Prusa SL1] printer_technology = SLA @@ -2514,13 +2735,17 @@ printer_model = SL1 printer_variant = default default_sla_material_profile = Prusa Orange Tough 0.05 default_sla_print_profile = 0.05 Normal -bed_shape = 0.98x1.02,119.98x1.02,119.98x67.02,0.98x67.02 +bed_shape = 1.48x1.02,119.48x1.02,119.48x67.02,1.48x67.02 display_height = 68.04 display_orientation = portrait display_pixels_x = 2560 display_pixels_y = 1440 display_width = 120.96 max_print_height = 150 +min_exposure_time = 1 +max_exposure_time = 120 +min_initial_exposure_time = 1 +max_initial_exposure_time = 300 printer_correction = 1,1,1 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\n diff --git a/sandboxes/CMakeLists.txt b/sandboxes/CMakeLists.txt index 0e1f52d6c..5905c438e 100644 --- a/sandboxes/CMakeLists.txt +++ b/sandboxes/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(slabasebed) +add_subdirectory(slasupporttree) diff --git a/sandboxes/slabasebed/slabasebed.cpp b/sandboxes/slabasebed/slabasebed.cpp index 5393f61fd..b8b94d86f 100644 --- a/sandboxes/slabasebed/slabasebed.cpp +++ b/sandboxes/slabasebed/slabasebed.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -15,8 +16,8 @@ const std::string USAGE_STR = { namespace Slic3r { namespace sla { -Contour3D create_base_pool(const Polygons &ground_layer, - const Polygons &holes = {}, +Contour3D create_base_pool(const Polygons &ground_layer, + const ExPolygons &holes = {}, const PoolConfig& cfg = PoolConfig()); Contour3D walls(const Polygon& floor_plate, const Polygon& ceiling, @@ -43,22 +44,22 @@ int main(const int argc, const char *argv[]) { model.ReadSTLFile(argv[1]); model.align_to_origin(); - Polygons ground_slice; + ExPolygons ground_slice; sla::base_plate(model, ground_slice, 0.1f); if(ground_slice.empty()) return EXIT_FAILURE; - Polygon gndfirst; gndfirst = ground_slice.front(); - sla::offset_with_breakstick_holes(gndfirst, 0.5, 10, 0.3); + ground_slice = offset_ex(ground_slice, 0.5); + ExPolygon gndfirst; gndfirst = ground_slice.front(); + sla::breakstick_holes(gndfirst, 0.5, 10, 0.3); sla::Contour3D mesh; - bench.start(); sla::PoolConfig cfg; cfg.min_wall_height_mm = 0; cfg.edge_radius_mm = 0; - mesh = sla::create_base_pool(ground_slice, {}, cfg); + mesh = sla::create_base_pool(to_polygons(ground_slice), {}, cfg); bench.stop(); @@ -75,7 +76,7 @@ int main(const int argc, const char *argv[]) { if(std::abs(a) < 1e-6) std::cout << "degenerate triangle" << std::endl; } -// basepool.write_ascii("out.stl"); + // basepool.write_ascii("out.stl"); std::fstream outstream("out.obj", std::fstream::out); mesh.to_obj(outstream); diff --git a/sandboxes/slasupporttree/CMakeLists.txt b/sandboxes/slasupporttree/CMakeLists.txt new file mode 100644 index 000000000..79adb842b --- /dev/null +++ b/sandboxes/slasupporttree/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(slasupporttree slasupporttree.cpp) +target_link_libraries(slasupporttree libslic3r ${Boost_LIBRARIES} ${TBB_LIBRARIES} ${Boost_LIBRARIES} ${CMAKE_DL_LIBS}) diff --git a/sandboxes/slasupporttree/slasupporttree.cpp b/sandboxes/slasupporttree/slasupporttree.cpp new file mode 100644 index 000000000..dcaddf6d3 --- /dev/null +++ b/sandboxes/slasupporttree/slasupporttree.cpp @@ -0,0 +1,42 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +const std::string USAGE_STR = { + "Usage: slasupporttree stlfilename.stl" +}; + +int main(const int argc, const char *argv[]) { + using namespace Slic3r; + using std::cout; using std::endl; + + if(argc < 2) { + cout << USAGE_STR << endl; + return EXIT_SUCCESS; + } + + DynamicPrintConfig config; + + Model model = Model::read_from_file(argv[1], &config); + + SLAPrint print; + + print.apply(model, config); + print.process(); + + + return EXIT_SUCCESS; +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eff9a0a9e..a829d9591 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,6 @@ project(Slic3r-native) +add_subdirectory(build-utils) add_subdirectory(admesh) add_subdirectory(avrdude) # boost/nowide @@ -48,7 +49,7 @@ if (SLIC3R_GUI) endif () endif () else () - find_package(wxWidgets 3.1 REQUIRED COMPONENTS base core adv html gl) + find_package(wxWidgets 3.1 REQUIRED COMPONENTS html adv gl core base) endif () if(UNIX) @@ -57,6 +58,9 @@ if (SLIC3R_GUI) include(${wxWidgets_USE_FILE}) +# list(REMOVE_ITEM wxWidgets_LIBRARIES oleacc) + message(STATUS "wx libs: ${wxWidgets_LIBRARIES}") + add_subdirectory(slic3r) endif() @@ -66,13 +70,20 @@ endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/PrusaSlicer.rc.in ${CMAKE_CURRENT_BINARY_DIR}/slic3r.rc @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/PrusaSlicer.manifest.in ${CMAKE_CURRENT_BINARY_DIR}/slic3r.manifest @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/osx/Info.plist.in ${CMAKE_CURRENT_BINARY_DIR}/Info.plist @ONLY) -if (MSVC) +if (WIN32) add_library(slic3r SHARED PrusaSlicer.cpp PrusaSlicer.hpp) else () add_executable(slic3r PrusaSlicer.cpp PrusaSlicer.hpp) endif () + add_library(slic3r_lib STATIC PrusaSlicer.cpp PrusaSlicer.hpp) -if (NOT MSVC) + +if (MINGW) + target_link_options(slic3r PUBLIC "-Wl,-allow-multiple-definition") + set_target_properties(slic3r PROPERTIES PREFIX "") +endif (MINGW) + +if (NOT WIN32) # Binary name on unix like systems (OSX, Linux) set_target_properties(slic3r PROPERTIES OUTPUT_NAME "slic3r++") endif () @@ -101,7 +112,7 @@ if (SLIC3R_GUI) # Configure libcurl and its dependencies OpenSSL & zlib find_package(CURL REQUIRED) - if (NOT MSVC) + if (NOT WIN32) # Required by libcurl find_package(ZLIB REQUIRED) endif() @@ -135,7 +146,7 @@ if (SLIC3R_GUI) target_link_libraries(slic3r user32.lib Setupapi.lib OpenGL32.Lib GlU32.Lib) target_link_libraries(slic3r_lib user32.lib Setupapi.lib OpenGL32.Lib GlU32.Lib) elseif (MINGW) - target_link_libraries(slic3r -lopengl32) + target_link_libraries(slic3r opengl32 ws2_32 uxtheme setupapi) target_link_libraries(slic3r_lib -lopengl32) elseif (APPLE) target_link_libraries(slic3r "-framework OpenGL") @@ -148,27 +159,34 @@ endif () # On Windows, a shim application is required to produce a console / non console version of the Slic3r application. # Also the shim may load the Mesa software OpenGL renderer if the default renderer does not support OpenGL 2.0 and higher. -if (MSVC) +if (WIN32) + if (MINGW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode") + endif() + add_executable(slic3r_app_gui WIN32 PrusaSlicer_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/slic3r.rc) # Generate debug symbols even in release mode. - #target_link_options(slic3r_app_gui PUBLIC "$<$:/DEBUG>") + if(MSVC) + target_link_options(slic3r_app_gui PUBLIC "$<$:/DEBUG>") + endif() target_compile_definitions(slic3r_app_gui PRIVATE -DSLIC3R_WRAPPER_NOCONSOLE) - add_dependencies(slic3r_app_gui slic3r) - set_target_properties(slic3r_app_gui PROPERTIES OUTPUT_NAME "slic3r++") + add_dependencies(slic3r_app_gui PrusaSlicer) + set_target_properties(slic3r_app_gui PROPERTIES OUTPUT_NAME "prusa-slicer") target_link_libraries(slic3r_app_gui PRIVATE boost_headeronly) add_executable(slic3r_app_console PrusaSlicer_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/slic3r.rc) # Generate debug symbols even in release mode. - #target_link_options(slic3r_app_console PUBLIC "$<$:/DEBUG>") + if (MSVC) + target_link_options(slic3r_app_console PUBLIC "$<$:/DEBUG>") + endif () target_compile_definitions(slic3r_app_console PRIVATE -DSLIC3R_WRAPPER_CONSOLE) - add_dependencies(slic3r_app_console slic3r) - set_target_properties(slic3r_app_console PROPERTIES OUTPUT_NAME "slic3r++_console") + add_dependencies(slic3r_app_console PrusaSlicer) + set_target_properties(slic3r_app_console PROPERTIES OUTPUT_NAME "prusa-slicer-console") target_link_libraries(slic3r_app_console PRIVATE boost_headeronly) - endif () # Link the resources dir to where Slic3r GUI expects it -if (MSVC) +if (WIN32) if (CMAKE_CONFIGURATION_TYPES) foreach (CONF ${CMAKE_CONFIGURATION_TYPES}) file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${CONF}" WIN_CONF_OUTPUT_DIR) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 84a4298b7..58fa4b8c2 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "unix/fhs.hpp" // Generated by CMake from ../platform/unix/fhs.hpp.in @@ -47,6 +48,7 @@ #ifdef SLIC3R_GUI #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/GUI_App.hpp" + #include "slic3r/GUI/3DScene.hpp" #endif /* SLIC3R_GUI */ using namespace Slic3r; @@ -59,6 +61,26 @@ PrinterTechnology get_printer_technology(const DynamicConfig &config) int CLI::run(int argc, char **argv) { + // Switch boost::filesystem to utf8. + try { + boost::nowide::nowide_filesystem(); + } catch (const std::runtime_error& ex) { + std::string caption = std::string(SLIC3R_APP_NAME) + " Error"; + std::string text = std::string("An error occured while setting up locale.\n") + ( +#if !defined(_WIN32) && !defined(__APPLE__) + // likely some linux system + "You may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n" +#endif + SLIC3R_APP_NAME " will now terminate.\n\n") + ex.what(); + #if defined(_WIN32) && defined(SLIC3R_GUI) + if (m_actions.empty()) + // Empty actions means Slicer is executed in the GUI mode. Show a GUI message. + MessageBoxA(NULL, text.c_str(), caption.c_str(), MB_OK | MB_ICONERROR); + #endif + boost::nowide::cerr << text.c_str() << std::endl; + return 1; + } + if (! this->setup(argc, argv)) return 1; @@ -409,7 +431,7 @@ int CLI::run(int argc, char **argv) outfile_final = sla_print.print_statistics().finalize_output_path(outfile); sla_print.export_raster(outfile_final); } - if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final) != 0) { + if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final)) { boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl; return 1; } @@ -484,7 +506,10 @@ int CLI::run(int argc, char **argv) if (! m_extra_config.empty()) gui->mainframe->load_config(m_extra_config); }); - return wxEntry(argc, argv); + int result = wxEntry(argc, argv); + //FIXME this is a workaround for the PrusaSlicer 2.1 release. + _3DScene::destroy(); + return result; #else /* SLIC3R_GUI */ // No GUI support. Just print out a help. this->print_help(false); @@ -499,6 +524,7 @@ int CLI::run(int argc, char **argv) bool CLI::setup(int argc, char **argv) { { + Slic3r::set_logging_level(1); const char *loglevel = boost::nowide::getenv("SLIC3R_LOGLEVEL"); if (loglevel != nullptr) { if (loglevel[0] >= '0' && loglevel[0] <= '9' && loglevel[1] == 0) @@ -651,7 +677,7 @@ std::string CLI::output_filepath(const Model &model, IO::ExportFormat format) co return proposed_path.string(); } -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__MINGW32__) extern "C" { __declspec(dllexport) int __stdcall slic3r_main(int argc, wchar_t **argv) { diff --git a/src/PrusaSlicer_app_msvc.cpp b/src/PrusaSlicer_app_msvc.cpp index 696acfbec..d544ca7c5 100644 --- a/src/PrusaSlicer_app_msvc.cpp +++ b/src/PrusaSlicer_app_msvc.cpp @@ -205,6 +205,8 @@ extern "C" { Slic3rMainFunc slic3r_main = nullptr; } +extern "C" { + #ifdef SLIC3R_WRAPPER_NOCONSOLE int APIENTRY wWinMain(HINSTANCE /* hInstance */, HINSTANCE /* hPrevInstance */, PWSTR /* lpCmdLine */, int /* nCmdShow */) { @@ -298,3 +300,4 @@ int wmain(int argc, wchar_t **argv) // argc minus the trailing nullptr of the argv return slic3r_main((int)argv_extended.size() - 1, argv_extended.data()); } +} diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index a328baa75..f37c4af07 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -162,23 +162,23 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first) // Read a single facet from an ASCII .STL file // skip solid/endsolid // (in this order, otherwise it won't work when they are paired in the middle of a file) - fscanf(fp, "endsolid%*[^\n]\n"); - fscanf(fp, "solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid") + fscanf(fp, "endsolid %*[^\n]\n"); + fscanf(fp, "solid %*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid") // Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs. - int res_normal = fscanf(fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]); + int res_normal = fscanf(fp, " facet normal %31s %31s %31s ", normal_buf[0], normal_buf[1], normal_buf[2]); assert(res_normal == 3); - int res_outer_loop = fscanf(fp, " outer loop"); + int res_outer_loop = fscanf(fp, " outer loop "); assert(res_outer_loop == 0); - int res_vertex1 = fscanf(fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2)); + int res_vertex1 = fscanf(fp, " vertex %f %f %f ", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2)); assert(res_vertex1 == 3); - int res_vertex2 = fscanf(fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2)); + int res_vertex2 = fscanf(fp, " vertex %f %f %f ", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2)); assert(res_vertex2 == 3); - int res_vertex3 = fscanf(fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2)); + int res_vertex3 = fscanf(fp, " vertex %f %f %f ", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2)); assert(res_vertex3 == 3); - int res_endloop = fscanf(fp, " endloop"); + int res_endloop = fscanf(fp, " endloop %*[^\n]\n"); assert(res_endloop == 0); // There is a leading and trailing white space around endfacet to eat up all leading and trailing white spaces including numerous tabs and new lines. - int res_endfacet = fscanf(fp, " endfacet "); + int res_endfacet = fscanf(fp, " endfacet %*[^\n]\n"); if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) { BOOST_LOG_TRIVIAL(error) << "Something is syntactically very wrong with this ASCII STL! "; return false; diff --git a/src/avrdude/CMakeLists.txt b/src/avrdude/CMakeLists.txt index 0e9b9e6d4..889720021 100644 --- a/src/avrdude/CMakeLists.txt +++ b/src/avrdude/CMakeLists.txt @@ -74,6 +74,10 @@ if (MSVC) windows/unistd.cpp windows/getopt.c ) +elseif (MINGW) + set(AVRDUDE_SOURCES ${AVRDUDE_SOURCES} + windows/utf8.c + ) endif() add_executable(avrdude-conf-gen conf-generate.cpp) @@ -81,13 +85,13 @@ add_executable(avrdude-conf-gen conf-generate.cpp) # Config file embedding add_custom_command( DEPENDS avrdude-conf-gen ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf - OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf.h - COMMAND $ avrdude-slic3r.conf avrdude_slic3r_conf > avrdude-slic3r.conf.h + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/avrdude-slic3r.conf.h + COMMAND $ avrdude-slic3r.conf avrdude_slic3r_conf ${CMAKE_CURRENT_BINARY_DIR}/avrdude-slic3r.conf.h WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) add_custom_target(gen_conf_h - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf.h + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/avrdude-slic3r.conf.h ) add_library(avrdude STATIC ${AVRDUDE_SOURCES}) @@ -96,7 +100,15 @@ add_dependencies(avrdude gen_conf_h) add_executable(avrdude-slic3r main-standalone.cpp) target_link_libraries(avrdude-slic3r avrdude) +encoding_check(avrdude) +encoding_check(avrdude-slic3r) + +# Make avrdude-slic3r.conf.h includable: +target_include_directories(avrdude SYSTEM PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + if (WIN32) target_compile_definitions(avrdude PRIVATE WIN32NATIVE=1) - target_include_directories(avrdude SYSTEM PRIVATE windows) # So that sources find the getopt.h windows drop-in + if(MSVC) + target_include_directories(avrdude SYSTEM PRIVATE windows) # So that sources find the getopt.h windows drop-in + endif(MSVC) endif() diff --git a/src/avrdude/avrdude-slic3r.conf.h b/src/avrdude/avrdude-slic3r.conf.h deleted file mode 100644 index 905b14ee8..000000000 --- a/src/avrdude/avrdude-slic3r.conf.h +++ /dev/null @@ -1,1188 +0,0 @@ -/* WARN: This file is auto-generated from `avrdude-slic3r.conf` */ -const unsigned char avrdude_slic3r_conf[] = { - 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, - 0x20, 0x61, 0x20, 0x62, 0x61, 0x73, 0x69, 0x63, 0x20, 0x6d, 0x69, 0x6e, - 0x69, 0x6d, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, - 0x66, 0x69, 0x6c, 0x65, 0x20, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, - 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, - 0x76, 0x72, 0x64, 0x75, 0x64, 0x65, 0x2d, 0x73, 0x6c, 0x69, 0x63, 0x33, - 0x72, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x0a, 0x23, 0x20, 0x73, - 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x63, 0x61, - 0x6e, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, - 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, 0x20, 0x6d, - 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x4f, - 0x6e, 0x6c, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x74, 0x73, - 0x20, 0x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x20, 0x66, 0x6f, 0x72, 0x20, - 0x50, 0x72, 0x75, 0x73, 0x61, 0x33, 0x44, 0x20, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x63, 0x6f, 0x70, - 0x69, 0x65, 0x64, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x66, 0x72, 0x6f, - 0x6d, 0x20, 0x61, 0x76, 0x72, 0x64, 0x75, 0x64, 0x65, 0x2e, 0x63, 0x6f, - 0x6e, 0x66, 0x0a, 0x23, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x65, 0x65, 0x64, - 0x65, 0x64, 0x2c, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, - 0x61, 0x6e, 0x20, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, - 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, - 0x61, 0x76, 0x72, 0x64, 0x75, 0x64, 0x65, 0x2d, 0x73, 0x6c, 0x69, 0x63, - 0x33, 0x72, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x61, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x2d, 0x43, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2d, - 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x0a, 0x23, 0x0a, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, - 0x6d, 0x65, 0x72, 0x0a, 0x20, 0x20, 0x69, 0x64, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x77, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x3b, 0x0a, - 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x57, - 0x69, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x79, - 0x70, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x77, 0x69, 0x72, 0x69, 0x6e, - 0x67, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, - 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3b, 0x0a, 0x3b, 0x0a, 0x0a, 0x70, - 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x0a, 0x20, 0x20, - 0x69, 0x64, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x61, 0x72, 0x64, - 0x75, 0x69, 0x6e, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, 0x73, - 0x63, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x41, 0x72, 0x64, 0x75, 0x69, 0x6e, - 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x22, 0x3b, - 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x72, - 0x69, 0x61, 0x6c, 0x3b, 0x0a, 0x3b, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, - 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x0a, 0x20, 0x20, 0x69, 0x64, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x61, 0x76, 0x72, 0x31, 0x30, 0x39, - 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x20, 0x20, 0x3d, - 0x20, 0x22, 0x41, 0x74, 0x6d, 0x65, 0x6c, 0x20, 0x41, 0x70, 0x70, 0x4e, - 0x6f, 0x74, 0x65, 0x20, 0x41, 0x56, 0x52, 0x31, 0x30, 0x39, 0x20, 0x42, - 0x6f, 0x6f, 0x74, 0x20, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x22, 0x3b, - 0x0a, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x22, - 0x62, 0x75, 0x74, 0x74, 0x65, 0x72, 0x66, 0x6c, 0x79, 0x22, 0x3b, 0x0a, - 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x72, 0x69, - 0x61, 0x6c, 0x3b, 0x0a, 0x3b, 0x0a, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, - 0x41, 0x54, 0x6d, 0x65, 0x67, 0x61, 0x32, 0x35, 0x36, 0x30, 0x0a, 0x23, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, - 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x6d, 0x32, 0x35, 0x36, 0x30, - 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x41, 0x54, 0x6d, 0x65, 0x67, 0x61, 0x32, 0x35, 0x36, - 0x30, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x30, 0x78, 0x31, 0x65, 0x20, 0x30, 0x78, 0x39, 0x38, - 0x20, 0x30, 0x78, 0x30, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, - 0x61, 0x73, 0x5f, 0x6a, 0x74, 0x61, 0x67, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x79, 0x65, 0x73, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x73, 0x74, 0x6b, 0x35, 0x30, 0x30, 0x5f, 0x64, 0x65, - 0x76, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, - 0x42, 0x32, 0x3b, 0x0a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x61, 0x76, 0x72, - 0x39, 0x31, 0x30, 0x5f, 0x64, 0x65, 0x76, 0x63, 0x6f, 0x64, 0x65, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x34, 0x33, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, 0x5f, 0x65, 0x72, 0x61, 0x73, 0x65, - 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x6c, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x30, 0x78, 0x44, 0x37, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x62, 0x73, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x41, 0x30, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x65, 0x74, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x64, 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x70, 0x67, 0x6d, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, - 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, - 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x22, - 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, - 0x69, 0x70, 0x5f, 0x65, 0x72, 0x61, 0x73, 0x65, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x3b, 0x0a, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x73, 0x74, 0x61, 0x62, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x63, 0x6d, 0x64, 0x65, 0x78, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x6c, 0x6f, 0x6f, 0x70, 0x73, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x62, 0x79, 0x74, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, - 0x6c, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x33, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6c, 0x6c, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x35, - 0x33, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x65, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x73, 0x74, 0x64, 0x65, 0x6c, 0x61, - 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x70, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, - 0x74, 0x61, 0x63, 0x6b, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x30, 0x45, 0x2c, - 0x20, 0x30, 0x78, 0x31, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x46, 0x2c, - 0x20, 0x30, 0x78, 0x31, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x45, 0x2c, - 0x20, 0x30, 0x78, 0x33, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x46, 0x2c, - 0x20, 0x30, 0x78, 0x33, 0x46, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x30, 0x78, 0x34, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x35, - 0x45, 0x2c, 0x20, 0x30, 0x78, 0x34, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x35, - 0x46, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x37, - 0x45, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x37, - 0x46, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, - 0x78, 0x36, 0x36, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x36, 0x2c, 0x20, 0x30, - 0x78, 0x36, 0x37, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x37, 0x2c, 0x20, 0x30, - 0x78, 0x36, 0x41, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x41, 0x2c, 0x20, 0x30, - 0x78, 0x36, 0x42, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x42, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x42, 0x45, 0x2c, - 0x20, 0x30, 0x78, 0x46, 0x44, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, - 0x20, 0x30, 0x78, 0x30, 0x31, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, - 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, - 0x20, 0x30, 0x78, 0x30, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, - 0x76, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x74, 0x61, 0x62, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x6d, 0x6f, - 0x64, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, - 0x61, 0x74, 0x63, 0x68, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x73, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x35, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x76, 0x74, - 0x67, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x77, - 0x65, 0x72, 0x6f, 0x66, 0x66, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x35, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x65, 0x74, 0x64, 0x65, 0x6c, 0x61, - 0x79, 0x6d, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x65, - 0x74, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x75, 0x73, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x68, 0x76, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x74, 0x61, 0x62, - 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, - 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, 0x65, - 0x72, 0x61, 0x73, 0x65, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, 0x69, 0x64, - 0x74, 0x68, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x63, 0x68, 0x69, 0x70, 0x65, 0x72, 0x61, 0x73, 0x65, 0x70, 0x6f, 0x6c, - 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x31, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, - 0x61, 0x6d, 0x66, 0x75, 0x73, 0x65, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, - 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x66, 0x75, 0x73, - 0x65, 0x70, 0x6f, 0x6c, 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x20, 0x3d, 0x20, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, - 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6c, 0x6f, 0x63, 0x6b, 0x70, 0x75, 0x6c, - 0x73, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x30, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, - 0x6c, 0x6f, 0x63, 0x6b, 0x70, 0x6f, 0x6c, 0x6c, 0x74, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x35, 0x3b, 0x0a, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x69, 0x64, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x30, 0x78, 0x33, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70, - 0x6d, 0x63, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x35, 0x37, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x61, 0x6d, 0x70, 0x7a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x33, 0x62, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x66, 0x75, 0x6c, 0x6c, 0x70, - 0x61, 0x67, 0x65, 0x62, 0x69, 0x74, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x20, 0x3d, 0x20, 0x6e, 0x6f, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x6f, 0x63, 0x64, 0x72, 0x65, 0x76, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x34, 0x3b, - 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, - 0x20, 0x22, 0x65, 0x65, 0x70, 0x72, 0x6f, 0x6d, 0x22, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x64, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x6e, 0x6f, 0x3b, 0x20, 0x2f, 0x2a, 0x20, 0x6c, 0x65, 0x61, 0x76, 0x65, - 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x22, 0x6e, 0x6f, 0x22, 0x20, 0x2a, - 0x2f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, - 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x38, 0x3b, 0x20, 0x20, 0x2f, 0x2a, 0x20, 0x66, - 0x6f, 0x72, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x20, - 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x69, 0x6e, 0x67, 0x20, - 0x2a, 0x2f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x34, 0x30, 0x39, 0x36, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, - 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, - 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, - 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, - 0x65, 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x31, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, - 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, - 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, - 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, - 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, - 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, - 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, - 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, - 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, - 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, - 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, - 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, - 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, - 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, - 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x20, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, - 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, - 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6c, 0x6f, 0x20, 0x3d, 0x20, 0x22, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x22, 0x2c, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, - 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, - 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, - 0x20, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x77, 0x72, 0x69, - 0x74, 0x65, 0x70, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, - 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, - 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, - 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x65, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x34, 0x31, 0x3b, 0x0a, - 0x20, 0x20, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x31, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x38, 0x3b, 0x0a, 0x20, 0x20, 0x72, - 0x65, 0x61, 0x64, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x32, - 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, - 0x22, 0x66, 0x6c, 0x61, 0x73, 0x68, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x64, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x79, 0x65, - 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x36, 0x32, 0x31, 0x34, 0x34, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, - 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x6e, 0x75, 0x6d, 0x5f, 0x70, 0x61, 0x67, 0x65, - 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x30, - 0x32, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x34, 0x35, 0x30, 0x30, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, - 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, - 0x3d, 0x20, 0x34, 0x35, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, - 0x5f, 0x70, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, - 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x72, 0x65, 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x32, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, - 0x5f, 0x6c, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x31, 0x35, 0x20, 0x61, - 0x31, 0x34, 0x20, 0x61, 0x31, 0x33, 0x20, 0x61, 0x31, 0x32, 0x20, 0x20, - 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, - 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, - 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, - 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, - 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, - 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, - 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x68, 0x69, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x61, 0x31, 0x35, 0x20, 0x61, 0x31, 0x34, 0x20, 0x61, 0x31, 0x33, 0x20, - 0x61, 0x31, 0x32, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, - 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, - 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, - 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x6f, 0x20, - 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, - 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x70, 0x61, - 0x67, 0x65, 0x5f, 0x6c, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, - 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, - 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, - 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, - 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, - 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, - 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, - 0x6f, 0x61, 0x64, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x68, 0x69, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, - 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, - 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, - 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, - 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, - 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, - 0x20, 0x20, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x70, 0x61, 0x67, - 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, - 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x61, 0x31, 0x35, 0x20, 0x61, 0x31, 0x34, 0x20, 0x61, - 0x31, 0x33, 0x20, 0x61, 0x31, 0x32, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, - 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, - 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x3b, 0x0a, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x61, - 0x64, 0x5f, 0x65, 0x78, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x31, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x61, 0x31, 0x36, 0x22, 0x2c, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x65, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x34, 0x31, 0x3b, 0x0a, - 0x20, 0x20, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x31, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, - 0x20, 0x72, 0x65, 0x61, 0x64, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x3d, - 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, - 0x79, 0x20, 0x22, 0x6c, 0x66, 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, - 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, - 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, - 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, - 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, - 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x68, 0x66, 0x75, - 0x73, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, - 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x69, 0x20, - 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, - 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, - 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, - 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, - 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, - 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, - 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, - 0x79, 0x20, 0x22, 0x65, 0x66, 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, - 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x20, 0x78, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, - 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, - 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, - 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x6c, 0x6f, 0x63, - 0x6b, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x30, - 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, - 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, - 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x31, 0x20, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x2c, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, 0x31, 0x20, - 0x31, 0x20, 0x69, 0x20, 0x69, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, - 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, - 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, - 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, - 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, - 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x20, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, - 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, - 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x78, 0x20, 0x61, 0x31, 0x20, 0x61, 0x30, 0x20, 0x20, - 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, - 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, - 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x20, - 0x20, 0x3b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, - 0x41, 0x54, 0x6d, 0x65, 0x67, 0x61, 0x33, 0x32, 0x75, 0x34, 0x0a, 0x23, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, - 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x6d, 0x33, 0x32, 0x75, 0x34, - 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x41, 0x54, 0x6d, 0x65, 0x67, 0x61, 0x33, 0x32, 0x55, - 0x34, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x30, 0x78, 0x31, 0x65, 0x20, 0x30, 0x78, 0x39, 0x35, - 0x20, 0x30, 0x78, 0x38, 0x37, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, - 0x73, 0x62, 0x70, 0x69, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x32, 0x66, 0x66, 0x34, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x61, 0x73, 0x5f, 0x6a, 0x74, - 0x61, 0x67, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x79, 0x65, 0x73, 0x3b, 0x0a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x73, - 0x74, 0x6b, 0x35, 0x30, 0x30, 0x5f, 0x64, 0x65, 0x76, 0x63, 0x6f, 0x64, - 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x42, 0x32, 0x3b, 0x0a, - 0x23, 0x20, 0x20, 0x20, 0x20, 0x61, 0x76, 0x72, 0x39, 0x31, 0x30, 0x5f, - 0x64, 0x65, 0x76, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x30, 0x78, 0x34, 0x33, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, - 0x69, 0x70, 0x5f, 0x65, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x64, 0x65, 0x6c, - 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x6c, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, - 0x44, 0x37, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x73, 0x32, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x30, 0x78, 0x41, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x72, 0x65, 0x73, 0x65, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x64, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x64, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, - 0x67, 0x6d, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x22, 0x2c, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x3b, - 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, 0x5f, 0x65, - 0x72, 0x61, 0x73, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, - 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x32, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, - 0x61, 0x62, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x31, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6d, 0x64, - 0x65, 0x78, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x32, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x79, 0x6e, - 0x63, 0x68, 0x6c, 0x6f, 0x6f, 0x70, 0x73, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x33, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x79, 0x74, - 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6c, 0x6c, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6c, 0x6c, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x35, 0x33, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x70, 0x72, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x70, 0x6f, 0x73, 0x74, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6c, - 0x6c, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x31, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x70, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x74, 0x61, 0x63, 0x6b, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x30, 0x78, 0x30, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x31, - 0x45, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x31, - 0x46, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x33, - 0x45, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x33, - 0x46, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, - 0x78, 0x34, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x35, 0x45, 0x2c, 0x20, 0x30, - 0x78, 0x34, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x35, 0x46, 0x2c, 0x20, 0x30, - 0x78, 0x36, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x45, 0x2c, 0x20, 0x30, - 0x78, 0x36, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x46, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x36, 0x36, 0x2c, - 0x20, 0x30, 0x78, 0x37, 0x36, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x37, 0x2c, - 0x20, 0x30, 0x78, 0x37, 0x37, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x41, 0x2c, - 0x20, 0x30, 0x78, 0x37, 0x41, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x42, 0x2c, - 0x20, 0x30, 0x78, 0x37, 0x42, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x30, 0x78, 0x42, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x46, - 0x44, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, - 0x31, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, - 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x76, 0x65, 0x6e, 0x74, - 0x65, 0x72, 0x73, 0x74, 0x61, 0x62, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x6d, 0x6f, 0x64, 0x65, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x61, 0x74, 0x63, 0x68, - 0x63, 0x79, 0x63, 0x6c, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x76, 0x74, 0x67, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x6f, 0x66, - 0x66, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x31, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, - 0x65, 0x73, 0x65, 0x74, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x6d, 0x73, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x65, 0x74, 0x64, 0x65, 0x6c, - 0x61, 0x79, 0x75, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x76, 0x6c, - 0x65, 0x61, 0x76, 0x65, 0x73, 0x74, 0x61, 0x62, 0x64, 0x65, 0x6c, 0x61, - 0x79, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x35, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, 0x65, 0x72, 0x61, 0x73, 0x65, - 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, - 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, - 0x65, 0x72, 0x61, 0x73, 0x65, 0x70, 0x6f, 0x6c, 0x6c, 0x74, 0x69, 0x6d, - 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x66, 0x75, - 0x73, 0x65, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, - 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, - 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x66, 0x75, 0x73, 0x65, 0x70, 0x6f, 0x6c, - 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x35, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, - 0x6d, 0x6c, 0x6f, 0x63, 0x6b, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, 0x69, - 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6c, 0x6f, 0x63, 0x6b, - 0x70, 0x6f, 0x6c, 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, - 0x3d, 0x20, 0x35, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x64, - 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x33, 0x31, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70, 0x6d, 0x63, 0x72, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x35, 0x37, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x72, 0x61, 0x6d, 0x70, 0x7a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x30, 0x78, 0x33, 0x62, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x6c, - 0x6c, 0x6f, 0x77, 0x66, 0x75, 0x6c, 0x6c, 0x70, 0x61, 0x67, 0x65, 0x62, - 0x69, 0x74, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x20, 0x3d, 0x20, 0x6e, - 0x6f, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x63, 0x64, 0x72, - 0x65, 0x76, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, 0x3b, 0x0a, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x65, 0x65, - 0x70, 0x72, 0x6f, 0x6d, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6e, 0x6f, 0x3b, 0x20, - 0x2f, 0x2a, 0x20, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x20, 0x74, 0x68, 0x69, - 0x73, 0x20, 0x22, 0x6e, 0x6f, 0x22, 0x20, 0x2a, 0x2f, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x34, 0x3b, 0x20, 0x20, 0x2f, 0x2a, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, - 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x20, 0x70, 0x72, 0x6f, 0x67, - 0x72, 0x61, 0x6d, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x2a, 0x2f, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x31, 0x30, 0x32, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, - 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, - 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, - 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, - 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x5f, - 0x70, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x30, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, - 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x61, 0x31, 0x30, - 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, - 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, - 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, - 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, - 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, - 0x20, 0x20, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, - 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, - 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, - 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x20, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, - 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, 0x3b, - 0x0a, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x70, 0x61, 0x67, 0x65, - 0x5f, 0x6c, 0x6f, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x31, 0x20, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x31, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, - 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, - 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, - 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x70, 0x61, - 0x67, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, - 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, - 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, - 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, - 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x3b, - 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x30, 0x78, 0x34, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x30, 0x3b, 0x0a, - 0x20, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x69, 0x7a, 0x65, 0x20, - 0x3d, 0x20, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x66, 0x6c, 0x61, - 0x73, 0x68, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x70, 0x61, 0x67, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x79, 0x65, 0x73, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x33, 0x32, 0x37, 0x36, 0x38, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, - 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x32, - 0x38, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, - 0x75, 0x6d, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, - 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, - 0x34, 0x35, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, - 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x34, 0x35, 0x30, 0x30, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, - 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x31, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, 0x61, - 0x63, 0x6b, 0x5f, 0x70, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6c, 0x6f, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x20, 0x20, 0x30, 0x20, 0x61, 0x31, 0x34, 0x20, 0x61, 0x31, 0x33, - 0x20, 0x61, 0x31, 0x32, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, - 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, - 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, - 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, - 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x6f, - 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, - 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x5f, - 0x68, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x61, 0x31, - 0x34, 0x20, 0x61, 0x31, 0x33, 0x20, 0x61, 0x31, 0x32, 0x20, 0x20, 0x20, - 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, - 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, - 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, - 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, - 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, - 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, - 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, - 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6c, 0x6f, 0x61, 0x64, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6c, 0x6f, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, - 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, - 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, - 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, - 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x70, 0x61, 0x67, - 0x65, 0x5f, 0x68, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, - 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, - 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, 0x3b, - 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, - 0x69, 0x74, 0x65, 0x70, 0x61, 0x67, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x31, - 0x35, 0x20, 0x61, 0x31, 0x34, 0x20, 0x61, 0x31, 0x33, 0x20, 0x61, 0x31, - 0x32, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, - 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, - 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, - 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, - 0x20, 0x20, 0x20, 0x78, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x6f, - 0x64, 0x65, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x34, 0x31, - 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x31, 0x32, 0x38, 0x3b, 0x0a, - 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, - 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, - 0x72, 0x79, 0x20, 0x22, 0x6c, 0x66, 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, - 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, - 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, - 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, - 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, - 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, - 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x68, 0x66, - 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, - 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x69, - 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, - 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, - 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, - 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, - 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, - 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, - 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, - 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, - 0x72, 0x79, 0x20, 0x22, 0x65, 0x66, 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, - 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, - 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, - 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, - 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, - 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x6c, 0x6f, - 0x63, 0x6b, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, - 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, 0x31, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, - 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, - 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, - 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x31, 0x20, - 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x2c, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, 0x31, - 0x20, 0x31, 0x20, 0x69, 0x20, 0x69, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, - 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, - 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, - 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, - 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, - 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x63, 0x61, 0x6c, 0x69, 0x62, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, - 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x20, - 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x30, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, - 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, - 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, - 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x61, 0x31, 0x20, 0x61, 0x30, 0x20, - 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, - 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, - 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, - 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x0a, - 0, 0 -}; -const size_t avrdude_slic3r_conf_size = 14178; -const size_t avrdude_slic3r_conf_size_yy = 14180; diff --git a/src/avrdude/conf-generate.cpp b/src/avrdude/conf-generate.cpp index 4aa80ae0a..e61f42eb4 100644 --- a/src/avrdude/conf-generate.cpp +++ b/src/avrdude/conf-generate.cpp @@ -6,36 +6,42 @@ int main(int argc, char const *argv[]) { - if (argc != 3) { - std::cerr << "Usage: " << argv[0] << " " << std::endl; + if (argc != 4) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; return -1; } - const char* filename = argv[1]; + const char* filename_in = argv[1]; const char* symbol = argv[2]; + const char* filename_out = argv[3]; size_t size = 0; - std::fstream file(filename); + std::fstream file(filename_in, std::ios::in | std::ios::binary); if (!file.good()) { - std::cerr << "Cannot read file: " << filename << std::endl; + std::cerr << "Cannot read file: " << filename_in << std::endl; } - std::cout << "/* WARN: This file is auto-generated from `" << filename << "` */" << std::endl; - std::cout << "const unsigned char " << symbol << "[] = {"; + std::fstream output(filename_out, std::ios::out | std::ios::trunc); + if (!output.good()) { + std::cerr << "Cannot open output file: " << filename_out << std::endl; + } + + output << "/* WARN: This file is auto-generated from `" << filename_in << "` */" << std::endl; + output << "const unsigned char " << symbol << "[] = {"; char c; - std::cout << std::hex; - std::cout.fill('0'); + output << std::hex; + output.fill('0'); for (file.get(c); !file.eof(); size++, file.get(c)) { - if (size % 12 == 0) { std::cout << "\n "; } - std::cout << "0x" << std::setw(2) << (unsigned)c << ", "; + if (size % 12 == 0) { output << "\n "; } + output << "0x" << std::setw(2) << (unsigned)c << ", "; } - std::cout << "\n 0, 0\n};\n"; + output << "\n 0, 0\n};\n"; - std::cout << std::dec; - std::cout << "const size_t " << symbol << "_size = " << size << ";" << std::endl; - std::cout << "const size_t " << symbol << "_size_yy = " << size + 2 << ";" << std::endl; + output << std::dec; + output << "const size_t " << symbol << "_size = " << size << ";" << std::endl; + output << "const size_t " << symbol << "_size_yy = " << size + 2 << ";" << std::endl; return 0; } diff --git a/src/avrdude/lexer.c b/src/avrdude/lexer.c index f2d8adb4b..46d88170f 100644 --- a/src/avrdude/lexer.c +++ b/src/avrdude/lexer.c @@ -30,7 +30,7 @@ /* C99 systems have . Non-C99 systems may or may not. */ -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(_MSC_VER) /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. diff --git a/src/avrdude/main-standalone.cpp b/src/avrdude/main-standalone.cpp index df6d79e13..f7cd6d1d4 100644 --- a/src/avrdude/main-standalone.cpp +++ b/src/avrdude/main-standalone.cpp @@ -38,6 +38,10 @@ struct ArgvUtf8 : std::vector } }; +#endif + +#ifdef _MSC_VER + int wmain(int argc_w, wchar_t *argv_w[]) { ArgvUtf8 argv_utf8(argc_w, argv_w); diff --git a/src/avrdude/windows/unistd.h b/src/avrdude/windows/unistd.h index 95ba79a34..c88b780bf 100644 --- a/src/avrdude/windows/unistd.h +++ b/src/avrdude/windows/unistd.h @@ -63,10 +63,15 @@ extern "C" { #define STDOUT_FILENO 1 #define STDERR_FILENO 2 +#if defined(_MSC_VER) && defined(__clang__) +#include +struct timezone; +struct timeval; +#else #ifndef __cplusplus /* should be in some equivalent to */ typedef __int8 int8_t; -typedef __int16 int16_t; +typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int8 uint8_t; @@ -74,6 +79,7 @@ typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; #endif +#endif int usleep(unsigned usec); diff --git a/src/build-utils/CMakeLists.txt b/src/build-utils/CMakeLists.txt new file mode 100644 index 000000000..3b3961b56 --- /dev/null +++ b/src/build-utils/CMakeLists.txt @@ -0,0 +1,39 @@ + +add_executable(encoding-check encoding-check.cpp) + +# A global no-op target which depends on all encodings checks, +# and on which in turn all checked targets depend. +# This is done to make encoding checks the first thing to be +# performed before actually compiling any sources of the checked targets +# to make the check fail as early as possible. +add_custom_target(global-encoding-check + ALL + DEPENDS encoding-check +) + +# Function that adds source file encoding check to a target +# using the above encoding-check binary + +function(encoding_check TARGET) + # Obtain target source files + get_target_property(T_SOURCES ${TARGET} SOURCES) + + # Define top-level encoding check target for this ${TARGET} + add_custom_target(encoding-check-${TARGET} + DEPENDS encoding-check ${T_SOURCES} + COMMENT "Checking source files encodings for target ${TARGET}" + ) + + # Add checking of each source file as a subcommand of encoding-check-${TARGET} + foreach(file ${T_SOURCES}) + add_custom_command(TARGET encoding-check-${TARGET} + COMMAND $ ${TARGET} ${file} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + endforeach() + + # This adds dependency on encoding-check-${TARGET} to ${TARET} + # via the global-encoding-check + add_dependencies(global-encoding-check encoding-check-${TARGET}) + add_dependencies(${TARGET} global-encoding-check) +endfunction() diff --git a/src/build-utils/encoding-check.cpp b/src/build-utils/encoding-check.cpp new file mode 100644 index 000000000..89f225572 --- /dev/null +++ b/src/build-utils/encoding-check.cpp @@ -0,0 +1,119 @@ +#include +#include +#include +#include + + +/* + * The utf8_check() function scans the '\0'-terminated string starting + * at s. It returns a pointer to the first byte of the first malformed + * or overlong UTF-8 sequence found, or NULL if the string contains + * only correct UTF-8. It also spots UTF-8 sequences that could cause + * trouble if converted to UTF-16, namely surrogate characters + * (U+D800..U+DFFF) and non-Unicode positions (U+FFFE..U+FFFF). This + * routine is very likely to find a malformed sequence if the input + * uses any other encoding than UTF-8. It therefore can be used as a + * very effective heuristic for distinguishing between UTF-8 and other + * encodings. + * + * I wrote this code mainly as a specification of functionality; there + * are no doubt performance optimizations possible for certain CPUs. + * + * Markus Kuhn -- 2005-03-30 + * License: http://www.cl.cam.ac.uk/~mgk25/short-license.html + */ + +unsigned char *utf8_check(unsigned char *s) +{ + while (*s) { + if (*s < 0x80) { + // 0xxxxxxx + s++; + } else if ((s[0] & 0xe0) == 0xc0) { + // 110xxxxx 10xxxxxx + if ((s[1] & 0xc0) != 0x80 || + (s[0] & 0xfe) == 0xc0) { // overlong? + return s; + } else { + s += 2; + } + } else if ((s[0] & 0xf0) == 0xe0) { + // 1110xxxx 10xxxxxx 10xxxxxx + if ((s[1] & 0xc0) != 0x80 || + (s[2] & 0xc0) != 0x80 || + (s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || // overlong? + (s[0] == 0xed && (s[1] & 0xe0) == 0xa0) || // surrogate? + (s[0] == 0xef && s[1] == 0xbf && + (s[2] & 0xfe) == 0xbe)) { // U+FFFE or U+FFFF? + return s; + } else { + s += 3; + } + } else if ((s[0] & 0xf8) == 0xf0) { + // 11110xxX 10xxxxxx 10xxxxxx 10xxxxxx + if ((s[1] & 0xc0) != 0x80 || + (s[2] & 0xc0) != 0x80 || + (s[3] & 0xc0) != 0x80 || + (s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || // overlong? + (s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) { // > U+10FFFF? + return s; + } else { + s += 4; + } + } else { + return s; + } + } + + return NULL; +} + + +int main(int argc, char const *argv[]) +{ + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + return -1; + } + + const char* target = argv[1]; + const char* filename = argv[2]; + + const auto error_exit = [=](const char* error) { + std::cerr << "\n\tError: " << error << ": " << filename << "\n" + << "\tTarget: " << target << "\n" + << std::endl; + std::exit(-2); + }; + + std::ifstream file(filename, std::ios::binary | std::ios::ate); + const auto size = file.tellg(); + + if (size == 0) { + return 0; + } + + file.seekg(0, std::ios::beg); + std::vector buffer(size); + + if (file.read(buffer.data(), size)) { + buffer.push_back('\0'); + + // Check UTF-8 validity + if (utf8_check(reinterpret_cast(buffer.data())) != nullptr) { + error_exit("Source file does not contain (valid) UTF-8"); + } + + // Check against a BOM mark + if (buffer.size() >= 3 + && buffer[0] == '\xef' + && buffer[1] == '\xbb' + && buffer[2] == '\xbf') { + error_exit("Source file is valid UTF-8 but contains a BOM mark"); + } + } else { + error_exit("Could not read source file"); + } + + return 0; +} diff --git a/src/libigl/igl/SortableRow.h b/src/libigl/igl/SortableRow.h index 5f172987b..182bf8134 100644 --- a/src/libigl/igl/SortableRow.h +++ b/src/libigl/igl/SortableRow.h @@ -1,9 +1,9 @@ // This file is part of libigl, a simple c++ geometry processing library. -// +// // Copyright (C) 2013 Alec Jacobson -// -// This Source Code Form is subject to the terms of the Mozilla Public License -// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can // obtain one at http://mozilla.org/MPL/2.0/. #ifndef IGL_SORTABLE_ROW_H #define IGL_SORTABLE_ROW_H @@ -14,57 +14,53 @@ namespace igl { - // Templates: - // T should be a matrix that implements .size(), and operator(int i) - template - class SortableRow - { - public: - T data; - public: - SortableRow():data(){}; - SortableRow(const T & data):data(data){}; - bool operator<(const SortableRow & that) const - { - // Get reference so that I can use parenthesis - const SortableRow & THIS = *this; +// Templates: +// T should be a matrix that implements .size(), and operator(int i) +template +class SortableRow +{ +public: + T data; +public: + SortableRow():data(){}; + SortableRow(const T & data):data(data){}; + bool operator<(const SortableRow & that) const + { // Lexicographical - int minc = (THIS.data.size() < that.data.size()? - THIS.data.size() : that.data.size()); + int minc = (this->data.size() < that.data.size()? + this->data.size() : that.data.size()); // loop over columns for(int i = 0;idata(i) == that.data(i)) + { + continue; + } + return this->data(i) < that.data(i); } // All characters the same, comes done to length - return THIS.data.size() & THIS = *this; - if(THIS.data.size() != that.data.size()) + return this->data.size()data.size() != that.data.size()) { - return false; - } - for(int i = 0;idata.size();i++) + { + if(this->data(i) != that.data(i)) + { + return false; + } } return true; - }; - bool operator!=(const SortableRow & that) const - { + }; + bool operator!=(const SortableRow & that) const + { return !(*this == that); - }; - }; + }; +}; } #endif diff --git a/src/libigl/igl/ray_box_intersect.cpp b/src/libigl/igl/ray_box_intersect.cpp index 8c6346d86..088273f25 100644 --- a/src/libigl/igl/ray_box_intersect.cpp +++ b/src/libigl/igl/ray_box_intersect.cpp @@ -1,12 +1,12 @@ // This file is part of libigl, a simple c++ geometry processing library. -// +// // Copyright (C) 2016 Alec Jacobson -// -// This Source Code Form is subject to the terms of the Mozilla Public License -// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can // obtain one at http://mozilla.org/MPL/2.0/. #include "ray_box_intersect.h" -#include +#include template < typename Derivedsource, @@ -27,7 +27,7 @@ IGL_INLINE bool igl::ray_box_intersect( const Eigen::Vector3f& rayo, const Eigen::Vector3f& rayd, const Eigen::Vector3f& bmin, - const Eigen::Vector3f& bmax, + const Eigen::Vector3f& bmax, float & tnear, float & tfar )->bool @@ -35,12 +35,12 @@ IGL_INLINE bool igl::ray_box_intersect( Eigen::Vector3f bnear; Eigen::Vector3f bfar; // Checks for intersection testing on each direction coordinate - // Computes + // Computes float t1, t2; tnear = -1e+6f, tfar = 1e+6f; //, tCube; bool intersectFlag = true; for (int i = 0; i < 3; ++i) { - // std::cout << "coordinate " << i << ": bmin " << bmin(i) << ", bmax " << bmax(i) << std::endl; + // std::cout << "coordinate " << i << ": bmin " << bmin(i) << ", bmax " << bmax(i) << std::endl; assert(bmin(i) <= bmax(i)); if (::fabs(rayd(i)) < 1e-6) { // Ray parallel to axis i-th if (rayo(i) < bmin(i) || rayo(i) > bmax(i)) { @@ -59,12 +59,12 @@ IGL_INLINE bool igl::ray_box_intersect( } // std::cout << " bnear " << bnear(i) << ", bfar " << bfar(i) << std::endl; // Finds the distance parameters t1 and t2 of the two ray-box intersections: - // t1 must be the closest to the ray origin rayo. + // t1 must be the closest to the ray origin rayo. t1 = (bnear(i) - rayo(i)) / rayd(i); t2 = (bfar(i) - rayo(i)) / rayd(i); if (t1 > t2) { std::swap(t1,t2); - } + } // The two intersection values are used to saturate tnear and tfar if (t1 > tnear) { tnear = t1; @@ -72,7 +72,7 @@ IGL_INLINE bool igl::ray_box_intersect( if (t2 < tfar) { tfar = t2; } - // std::cout << " t1 " << t1 << ", t2 " << t2 << ", tnear " << tnear << ", tfar " << tfar + // std::cout << " t1 " << t1 << ", t2 " << t2 << ", tnear " << tnear << ", tfar " << tfar // << " tnear > tfar? " << (tnear > tfar) << ", tfar < 0? " << (tfar < 0) << std::endl; if(tnear > tfar) { intersectFlag = false; @@ -101,11 +101,11 @@ IGL_INLINE bool igl::ray_box_intersect( // This should be precomputed and provided as input typedef Matrix RowVector3S; const RowVector3S inv_dir( 1./dir(0),1./dir(1),1./dir(2)); - const std::vector sign = { inv_dir(0)<0, inv_dir(1)<0, inv_dir(2)<0}; + const std::array sign = { inv_dir(0)<0, inv_dir(1)<0, inv_dir(2)<0}; // http://people.csail.mit.edu/amy/papers/box-jgt.pdf // "An Efficient and Robust Ray–Box Intersection Algorithm" Scalar tymin, tymax, tzmin, tzmax; - std::vector bounds = {box.min(),box.max()}; + std::array bounds = {box.min(),box.max()}; tmin = ( bounds[sign[0]](0) - origin(0)) * inv_dir(0); tmax = ( bounds[1-sign[0]](0) - origin(0)) * inv_dir(0); tymin = (bounds[sign[1]](1) - origin(1)) * inv_dir(1); @@ -146,4 +146,4 @@ IGL_INLINE bool igl::ray_box_intersect( #ifdef IGL_STATIC_LIBRARY template bool igl::ray_box_intersect, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::AlignedBox const&, double const&, double const&, double&, double&); -#endif \ No newline at end of file +#endif diff --git a/src/libigl/igl/ray_mesh_intersect.cpp b/src/libigl/igl/ray_mesh_intersect.cpp index 512a35c46..18060fbad 100644 --- a/src/libigl/igl/ray_mesh_intersect.cpp +++ b/src/libigl/igl/ray_mesh_intersect.cpp @@ -29,7 +29,9 @@ IGL_INLINE bool igl::ray_mesh_intersect( // Should be but can't be const Vector3d s_d = s.template cast(); Vector3d dir_d = dir.template cast(); - hits.clear(); + hits.clear(); + hits.reserve(F.rows()); + // loop over all triangles for(int f = 0;f& shapes) //#define DISABLE_BOOST_SERIALIZE //#define DISABLE_BOOST_UNSERIALIZE +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4244) +#pragma warning(disable: 4267) +#endif // All other operators and algorithms are implemented with boost #include +#ifdef _MSC_VER +#pragma warning(pop) +#endif #endif // CLIPPER_BACKEND_HPP diff --git a/src/libnest2d/tests/test.cpp b/src/libnest2d/tests/test.cpp index 29577344d..4a6691415 100644 --- a/src/libnest2d/tests/test.cpp +++ b/src/libnest2d/tests/test.cpp @@ -7,6 +7,10 @@ #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" diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index b4cfac954..34e07302a 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -12,6 +12,11 @@ #include #include + +#if defined(_MSC_VER) && defined(__clang__) +#define BOOST_NO_CXX17_HDR_STRING_VIEW +#endif + #include #include @@ -128,13 +133,24 @@ protected: PConfig m_pconf; // Placement configuration TBin m_bin; double m_bin_area; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4244) +#pragma warning(disable: 4267) +#endif SpatIndex m_rtree; // spatial index for the normal (bigger) objects SpatIndex m_smallsrtree; // spatial index for only the smaller items +#ifdef _MSC_VER +#pragma warning(pop) +#endif + double m_norm; // A coefficient to scale distances MultiPolygon m_merged_pile; // The already merged pile (vector of items) Box m_pilebb; // The bounding box of the merged pile. - ItemGroup m_remaining; // Remaining items (m_items at the beginning) - ItemGroup m_items; // The items to be packed + ItemGroup m_remaining; // Remaining items + ItemGroup m_items; // allready packed items + size_t m_item_count = 0; // Number of all items to be packed template ArithmeticOnly norm(T val) { @@ -152,7 +168,6 @@ protected: const double bin_area = m_bin_area; const SpatIndex& spatindex = m_rtree; const SpatIndex& smalls_spatindex = m_smallsrtree; - const ItemGroup& remaining = m_remaining; // We will treat big items (compared to the print bed) differently auto isBig = [bin_area](double a) { @@ -194,8 +209,8 @@ protected: } compute_case; bool bigitems = isBig(item.area()) || spatindex.empty(); - if(bigitems && !remaining.empty()) compute_case = BIG_ITEM; - else if (bigitems && remaining.empty()) compute_case = LAST_BIG_ITEM; + if(bigitems && !m_remaining.empty()) compute_case = BIG_ITEM; + else if (bigitems && m_remaining.empty()) compute_case = LAST_BIG_ITEM; else compute_case = SMALL_ITEM; switch (compute_case) { @@ -220,7 +235,7 @@ protected: // The smalles distance from the arranged pile center: double dist = norm(*(std::min_element(dists.begin(), dists.end()))); double bindist = norm(pl::distance(ibb.center(), bincenter)); - dist = 0.8 * dist + 0.2*bindist; + dist = 0.8 * dist + 0.2 * bindist; // Prepare a variable for the alignment score. // This will indicate: how well is the candidate item @@ -252,29 +267,24 @@ protected: if(ascore < alignment_score) alignment_score = ascore; } } - + density = std::sqrt(norm(fullbb.width()) * norm(fullbb.height())); - + double R = double(m_remaining.size()) / m_item_count; + // The final mix of the score is the balance between the // distance from the full pile center, the pack density and // the alignment with the neighbors if (result.empty()) - score = 0.5 * dist + 0.5 * density; + score = 0.50 * dist + 0.50 * density; else - score = 0.40 * dist + 0.40 * density + 0.2 * alignment_score; + score = R * 0.60 * dist + + (1.0 - R) * 0.20 * density + + 0.20 * alignment_score; break; } case LAST_BIG_ITEM: { - auto mp = m_merged_pile; - mp.emplace_back(item.transformedShape()); - auto chull = sl::convexHull(mp); - - placers::EdgeCache ec(chull); - - double circ = norm(ec.circumference()); - double bcirc = 2.0 * norm(fullbb.width() + fullbb.height()); - score = 0.5 * circ + 0.5 * bcirc; + score = norm(pl::distance(ibb.center(), m_pilebb.center())); break; } case SMALL_ITEM: { @@ -340,9 +350,11 @@ public: m_pck.configure(m_pconf); } - template inline void operator()(Args&&...args) { - m_rtree.clear(); /*m_preload_idx.clear();*/ - m_pck.execute(std::forward(args)...); + template inline void operator()(It from, It to) { + m_rtree.clear(); + m_item_count += size_t(to - from); + m_pck.execute(from, to); + m_item_count = 0; } inline void preload(std::vector& fixeditems) { @@ -361,6 +373,7 @@ public: } m_pck.configure(m_pconf); + m_item_count += fixeditems.size(); } }; @@ -424,6 +437,18 @@ inline Circle to_lnCircle(const CircleBed& circ) { } // Get the type of bed geometry from a simple vector of points. +void BedShapeHint::reset(BedShapes type) +{ + if (m_type != type) { + if (m_type == bsIrregular) + m_bed.polygon.Slic3r::Polyline::~Polyline(); + else if (type == bsIrregular) + ::new (&m_bed.polygon) Polyline(); + } + + m_type = type; +} + BedShapeHint::BedShapeHint(const Polyline &bed) { auto x = [](const Point& p) { return p(X); }; auto y = [](const Point& p) { return p(Y); }; @@ -492,19 +517,50 @@ BedShapeHint::BedShapeHint(const Polyline &bed) { m_type = BedShapes::bsCircle; m_bed.circ = c; } else { + assert(m_type != BedShapes::bsIrregular); m_type = BedShapes::bsIrregular; - m_bed.polygon = bed; + ::new (&m_bed.polygon) Polyline(bed); } } +BedShapeHint &BedShapeHint::operator=(BedShapeHint &&cpy) +{ + reset(cpy.m_type); + + switch(m_type) { + case bsBox: m_bed.box = std::move(cpy.m_bed.box); break; + case bsCircle: m_bed.circ = std::move(cpy.m_bed.circ); break; + case bsIrregular: m_bed.polygon = std::move(cpy.m_bed.polygon); break; + case bsInfinite: m_bed.infbed = std::move(cpy.m_bed.infbed); break; + case bsUnknown: break; + } + + return *this; +} + +BedShapeHint &BedShapeHint::operator=(const BedShapeHint &cpy) +{ + reset(cpy.m_type); + + switch(m_type) { + case bsBox: m_bed.box = cpy.m_bed.box; break; + case bsCircle: m_bed.circ = cpy.m_bed.circ; break; + case bsIrregular: m_bed.polygon = cpy.m_bed.polygon; break; + case bsInfinite: m_bed.infbed = cpy.m_bed.infbed; break; + case bsUnknown: break; + } + + return *this; +} + template // Arrange for arbitrary bin type void _arrange( - std::vector & shapes, - std::vector & excludes, - const BinT & bin, - coord_t minobjd, - std::function prind, - std::function stopfn) + std::vector & shapes, + std::vector & excludes, + const BinT & bin, + coord_t minobjd, + std::function prind, + std::function stopfn) { // Integer ceiling the min distance from the bed perimeters coord_t md = minobjd - 2 * scaled(0.1 + EPSILON); diff --git a/src/libslic3r/Arrange.hpp b/src/libslic3r/Arrange.hpp index c02393dd9..1cfe1c907 100644 --- a/src/libslic3r/Arrange.hpp +++ b/src/libslic3r/Arrange.hpp @@ -39,18 +39,24 @@ enum BedShapes { class BedShapeHint { BedShapes m_type = BedShapes::bsInfinite; + // The union neither calls constructors nor destructors of its members. + // The only member with non-trivial constructor / destructor is the polygon, + // a placement new / delete needs to be called over it. union BedShape_u { // TODO: use variant from cpp17? CircleBed circ; BoundingBox box; Polyline polygon; InfiniteBed infbed{}; ~BedShape_u() {} - BedShape_u() {}; + BedShape_u() {} } m_bed; + // Reset the type, allocate m_bed properly + void reset(BedShapes type); + public: - BedShapeHint(){}; + BedShapeHint(){} /// Get a bed shape hint for arrange() from a naked Polyline. explicit BedShapeHint(const Polyline &polyl); @@ -73,38 +79,13 @@ public: { if (m_type == BedShapes::bsIrregular) m_bed.polygon.Slic3r::Polyline::~Polyline(); - }; + } BedShapeHint(const BedShapeHint &cpy) { *this = cpy; } BedShapeHint(BedShapeHint &&cpy) { *this = std::move(cpy); } - BedShapeHint &operator=(const BedShapeHint &cpy) - { - m_type = cpy.m_type; - switch(m_type) { - case bsBox: m_bed.box = cpy.m_bed.box; break; - case bsCircle: m_bed.circ = cpy.m_bed.circ; break; - case bsIrregular: m_bed.polygon = cpy.m_bed.polygon; break; - case bsInfinite: m_bed.infbed = cpy.m_bed.infbed; break; - case bsUnknown: break; - } - - return *this; - } - - BedShapeHint& operator=(BedShapeHint &&cpy) - { - m_type = cpy.m_type; - switch(m_type) { - case bsBox: m_bed.box = std::move(cpy.m_bed.box); break; - case bsCircle: m_bed.circ = std::move(cpy.m_bed.circ); break; - case bsIrregular: m_bed.polygon = std::move(cpy.m_bed.polygon); break; - case bsInfinite: m_bed.infbed = std::move(cpy.m_bed.infbed); break; - case bsUnknown: break; - } - - return *this; - } + BedShapeHint &operator=(const BedShapeHint &cpy); + BedShapeHint& operator=(BedShapeHint &&cpy); BedShapes get_type() const { return m_type; } diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 6865be226..e4e0294fd 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -5,6 +5,10 @@ include(PrecompiledHeader) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libslic3r_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/libslic3r_version.h @ONLY) +if (MINGW) + add_compile_options(-Wa,-mbig-obj) +endif () + add_library(libslic3r STATIC pchheader.cpp pchheader.hpp @@ -72,7 +76,7 @@ add_library(libslic3r STATIC GCode/CoolingBuffer.cpp GCode/CoolingBuffer.hpp GCode/PostProcessor.cpp - GCode/PostProcessor.hpp + GCode/PostProcessor.hpp # GCode/PressureEqualizer.cpp # GCode/PressureEqualizer.hpp GCode/PreviewData.cpp @@ -127,6 +131,8 @@ add_library(libslic3r STATIC Point.hpp Polygon.cpp Polygon.hpp + PolygonTrimmer.cpp + PolygonTrimmer.hpp Polyline.cpp Polyline.hpp PolylineCollection.cpp @@ -139,6 +145,7 @@ add_library(libslic3r STATIC PrintConfig.hpp PrintObject.cpp PrintRegion.cpp + Semver.cpp SLAPrint.cpp SLAPrint.hpp SLA/SLAAutoSupports.hpp @@ -186,6 +193,8 @@ add_library(libslic3r STATIC SLA/SLARasterWriter.cpp ) +encoding_check(libslic3r) + if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY) add_precompiled_header(libslic3r pchheader.hpp FORCEINCLUDE) endif () diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index ede5a16e7..081e6fd60 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -396,7 +396,7 @@ public: this->values[i] = rhs_vec->values[i]; modified = true; } - return false; + return modified; } private: diff --git a/src/libslic3r/EdgeGrid.cpp b/src/libslic3r/EdgeGrid.cpp index 62d1444cd..c69c52179 100644 --- a/src/libslic3r/EdgeGrid.cpp +++ b/src/libslic3r/EdgeGrid.cpp @@ -11,6 +11,7 @@ #include "libslic3r.h" #include "ClipperUtils.hpp" #include "EdgeGrid.hpp" +#include "Geometry.hpp" #include "SVG.hpp" #if 0 @@ -275,136 +276,27 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) // 6) Finally fill in m_cell_data by rasterizing the lines once again. for (size_t i = 0; i < m_cells.size(); ++i) m_cells[i].end = m_cells[i].begin; - for (size_t i = 0; i < m_contours.size(); ++i) { - const Slic3r::Points &pts = *m_contours[i]; - for (size_t j = 0; j < pts.size(); ++j) { - // End points of the line segment. - Slic3r::Point p1(pts[j]); - Slic3r::Point p2 = pts[(j + 1 == pts.size()) ? 0 : j + 1]; - p1(0) -= m_bbox.min(0); - p1(1) -= m_bbox.min(1); - p2(0) -= m_bbox.min(0); - p2(1) -= m_bbox.min(1); - // Get the cells of the end points. - coord_t ix = p1(0) / m_resolution; - coord_t iy = p1(1) / m_resolution; - coord_t ixb = p2(0) / m_resolution; - coord_t iyb = p2(1) / m_resolution; - assert(ix >= 0 && size_t(ix) < m_cols); - assert(iy >= 0 && size_t(iy) < m_rows); - assert(ixb >= 0 && size_t(ixb) < m_cols); - assert(iyb >= 0 && size_t(iyb) < m_rows); - // Account for the end points. - m_cell_data[m_cells[iy*m_cols + ix].end++] = std::pair(i, j); - if (ix == ixb && iy == iyb) - // Both ends fall into the same cell. - continue; - // Raster the centeral part of the line. - coord_t dx = std::abs(p2(0) - p1(0)); - coord_t dy = std::abs(p2(1) - p1(1)); - if (p1(0) < p2(0)) { - int64_t ex = int64_t((ix + 1)*m_resolution - p1(0)) * int64_t(dy); - if (p1(1) < p2(1)) { - // x positive, y positive - int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); - do { - assert(ix <= ixb && iy <= iyb); - if (ex < ey) { - ey -= ex; - ex = int64_t(dy) * m_resolution; - ix += 1; + + struct Visitor { + Visitor(std::vector> &cell_data, std::vector &cells, size_t cols) : + cell_data(cell_data), cells(cells), cols(cols), i(0), j(0) {} + + void operator()(coord_t iy, coord_t ix) { cell_data[cells[iy*cols + ix].end++] = std::pair(i, j); } + + std::vector> &cell_data; + std::vector &cells; + size_t cols; + size_t i; + size_t j; + } visitor(m_cell_data, m_cells, m_cols); + + assert(visitor.i == 0); + for (; visitor.i < m_contours.size(); ++ visitor.i) { + const Slic3r::Points &pts = *m_contours[visitor.i]; + for (visitor.j = 0; visitor.j < pts.size(); ++ visitor.j) + this->visit_cells_intersecting_line(pts[visitor.j], pts[(visitor.j + 1 == pts.size()) ? 0 : visitor.j + 1], visitor); } - else if (ex == ey) { - ex = int64_t(dy) * m_resolution; - ey = int64_t(dx) * m_resolution; - ix += 1; - iy += 1; } - else { - assert(ex > ey); - ex -= ey; - ey = int64_t(dx) * m_resolution; - iy += 1; - } - m_cell_data[m_cells[iy*m_cols + ix].end++] = std::pair(i, j); - } while (ix != ixb || iy != iyb); - } - else { - // x positive, y non positive - int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); - do { - assert(ix <= ixb && iy >= iyb); - if (ex <= ey) { - ey -= ex; - ex = int64_t(dy) * m_resolution; - ix += 1; - } - else { - ex -= ey; - ey = int64_t(dx) * m_resolution; - iy -= 1; - } - m_cell_data[m_cells[iy*m_cols + ix].end++] = std::pair(i, j); - } while (ix != ixb || iy != iyb); - } - } - else { - int64_t ex = int64_t(p1(0) - ix*m_resolution) * int64_t(dy); - if (p1(1) < p2(1)) { - // x non positive, y positive - int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); - do { - assert(ix >= ixb && iy <= iyb); - if (ex < ey) { - ey -= ex; - ex = int64_t(dy) * m_resolution; - ix -= 1; - } - else { - assert(ex >= ey); - ex -= ey; - ey = int64_t(dx) * m_resolution; - iy += 1; - } - m_cell_data[m_cells[iy*m_cols + ix].end++] = std::pair(i, j); - } while (ix != ixb || iy != iyb); - } - else { - // x non positive, y non positive - int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); - do { - assert(ix >= ixb && iy >= iyb); - if (ex < ey) { - ey -= ex; - ex = int64_t(dy) * m_resolution; - ix -= 1; - } - else if (ex == ey) { - // The lower edge of a grid cell belongs to the cell. - // Handle the case where the ray may cross the lower left corner of a cell in a general case, - // or a left or lower edge in a degenerate case (horizontal or vertical line). - if (dx > 0) { - ex = int64_t(dy) * m_resolution; - ix -= 1; - } - if (dy > 0) { - ey = int64_t(dx) * m_resolution; - iy -= 1; - } - } - else { - assert(ex > ey); - ex -= ey; - ey = int64_t(dx) * m_resolution; - iy -= 1; - } - m_cell_data[m_cells[iy*m_cols + ix].end++] = std::pair(i, j); - } while (ix != ixb || iy != iyb); - } - } - } - } -} #if 0 // Divide, round to a grid coordinate. @@ -1360,28 +1252,6 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset, bool fill_holes) co return out; } -inline int segments_could_intersect( - const Slic3r::Point &ip1, const Slic3r::Point &ip2, - const Slic3r::Point &jp1, const Slic3r::Point &jp2) -{ - Vec2crd iv = (ip2 - ip1); - Vec2crd vij1 = (jp1 - ip1); - Vec2crd vij2 = (jp2 - ip1); - int64_t tij1 = cross2(iv, vij1); - int64_t tij2 = cross2(iv, vij2); - int sij1 = (tij1 > 0) ? 1 : ((tij1 < 0) ? -1 : 0); // signum - int sij2 = (tij2 > 0) ? 1 : ((tij2 < 0) ? -1 : 0); - return sij1 * sij2; -} - -inline bool segments_intersect( - const Slic3r::Point &ip1, const Slic3r::Point &ip2, - const Slic3r::Point &jp1, const Slic3r::Point &jp2) -{ - return segments_could_intersect(ip1, ip2, jp1, jp2) <= 0 && - segments_could_intersect(jp1, jp2, ip1, ip2) <= 0; -} - std::vector> EdgeGrid::Grid::intersecting_edges() const { std::vector> out; @@ -1405,7 +1275,7 @@ std::vector> if (&ipts == &jpts && (&ip1 == &jp2 || &jp1 == &ip2)) // Segments of the same contour share a common vertex. continue; - if (segments_intersect(ip1, ip2, jp1, jp2)) { + if (Geometry::segments_intersect(ip1, ip2, jp1, jp2)) { // The two segments intersect. Add them to the output. int jfirst = (&jpts < &ipts) || (&jpts == &ipts && jpt < ipt); out.emplace_back(jfirst ? @@ -1440,7 +1310,7 @@ bool EdgeGrid::Grid::has_intersecting_edges() const const Slic3r::Point &jp1 = jpts[jpt]; const Slic3r::Point &jp2 = jpts[(jpt + 1 == jpts.size()) ? 0 : jpt + 1]; if (! (&ipts == &jpts && (&ip1 == &jp2 || &jp1 == &ip2)) && - segments_intersect(ip1, ip2, jp1, jp2)) + Geometry::segments_intersect(ip1, ip2, jp1, jp2)) return true; } } diff --git a/src/libslic3r/EdgeGrid.hpp b/src/libslic3r/EdgeGrid.hpp index 7faafdb3e..cad20e07b 100644 --- a/src/libslic3r/EdgeGrid.hpp +++ b/src/libslic3r/EdgeGrid.hpp @@ -65,6 +65,145 @@ public: std::vector> intersecting_edges() const; bool has_intersecting_edges() const; + template void visit_cells_intersecting_line(Slic3r::Point p1, Slic3r::Point p2, FUNCTION func) const + { + // End points of the line segment. + p1(0) -= m_bbox.min(0); + p1(1) -= m_bbox.min(1); + p2(0) -= m_bbox.min(0); + p2(1) -= m_bbox.min(1); + // Get the cells of the end points. + coord_t ix = p1(0) / m_resolution; + coord_t iy = p1(1) / m_resolution; + coord_t ixb = p2(0) / m_resolution; + coord_t iyb = p2(1) / m_resolution; + assert(ix >= 0 && size_t(ix) < m_cols); + assert(iy >= 0 && size_t(iy) < m_rows); + assert(ixb >= 0 && size_t(ixb) < m_cols); + assert(iyb >= 0 && size_t(iyb) < m_rows); + // Account for the end points. + func(iy, ix); + if (ix == ixb && iy == iyb) + // Both ends fall into the same cell. + return; + // Raster the centeral part of the line. + coord_t dx = std::abs(p2(0) - p1(0)); + coord_t dy = std::abs(p2(1) - p1(1)); + if (p1(0) < p2(0)) { + int64_t ex = int64_t((ix + 1)*m_resolution - p1(0)) * int64_t(dy); + if (p1(1) < p2(1)) { + // x positive, y positive + int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); + do { + assert(ix <= ixb && iy <= iyb); + if (ex < ey) { + ey -= ex; + ex = int64_t(dy) * m_resolution; + ix += 1; + } + else if (ex == ey) { + ex = int64_t(dy) * m_resolution; + ey = int64_t(dx) * m_resolution; + ix += 1; + iy += 1; + } + else { + assert(ex > ey); + ex -= ey; + ey = int64_t(dx) * m_resolution; + iy += 1; + } + func(iy, ix); + } while (ix != ixb || iy != iyb); + } + else { + // x positive, y non positive + int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); + do { + assert(ix <= ixb && iy >= iyb); + if (ex <= ey) { + ey -= ex; + ex = int64_t(dy) * m_resolution; + ix += 1; + } + else { + ex -= ey; + ey = int64_t(dx) * m_resolution; + iy -= 1; + } + func(iy, ix); + } while (ix != ixb || iy != iyb); + } + } + else { + int64_t ex = int64_t(p1(0) - ix*m_resolution) * int64_t(dy); + if (p1(1) < p2(1)) { + // x non positive, y positive + int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); + do { + assert(ix >= ixb && iy <= iyb); + if (ex < ey) { + ey -= ex; + ex = int64_t(dy) * m_resolution; + ix -= 1; + } + else { + assert(ex >= ey); + ex -= ey; + ey = int64_t(dx) * m_resolution; + iy += 1; + } + func(iy, ix); + } while (ix != ixb || iy != iyb); + } + else { + // x non positive, y non positive + int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); + do { + assert(ix >= ixb && iy >= iyb); + if (ex < ey) { + ey -= ex; + ex = int64_t(dy) * m_resolution; + ix -= 1; + } + else if (ex == ey) { + // The lower edge of a grid cell belongs to the cell. + // Handle the case where the ray may cross the lower left corner of a cell in a general case, + // or a left or lower edge in a degenerate case (horizontal or vertical line). + if (dx > 0) { + ex = int64_t(dy) * m_resolution; + ix -= 1; + } + if (dy > 0) { + ey = int64_t(dx) * m_resolution; + iy -= 1; + } + } + else { + assert(ex > ey); + ex -= ey; + ey = int64_t(dx) * m_resolution; + iy -= 1; + } + func(iy, ix); + } while (ix != ixb || iy != iyb); + } + } + } + + std::pair>::const_iterator, std::vector>::const_iterator> cell_data_range(coord_t row, coord_t col) const + { + const EdgeGrid::Grid::Cell &cell = m_cells[row * m_cols + col]; + return std::make_pair(m_cell_data.begin() + cell.begin, m_cell_data.begin() + cell.end); + } + + std::pair segment(const std::pair &contour_and_segment_idx) const + { + const Slic3r::Points &ipts = *m_contours[contour_and_segment_idx.first]; + size_t ipt = contour_and_segment_idx.second; + return std::pair(ipts[ipt], ipts[(ipt + 1 == ipts.size()) ? 0 : ipt + 1]); + } + protected: struct Cell { Cell() : begin(0), end(0) {} diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp index c45ee30c8..a2409c389 100644 --- a/src/libslic3r/Flow.cpp +++ b/src/libslic3r/Flow.cpp @@ -76,10 +76,14 @@ float Flow::spacing() const return this->width + BRIDGE_EXTRA_SPACING; // rectangle with semicircles at the ends float min_flow_spacing = this->width - this->height * (1. - 0.25 * PI); - return this->width - PERIMETER_LINE_OVERLAP_FACTOR * (this->width - min_flow_spacing); + float res = this->width - PERIMETER_LINE_OVERLAP_FACTOR * (this->width - min_flow_spacing); #else - return float(this->bridge ? (this->width + BRIDGE_EXTRA_SPACING) : (this->width - this->height * (1. - 0.25 * PI))); + float res = float(this->bridge ? (this->width + BRIDGE_EXTRA_SPACING) : (this->width - this->height * (1. - 0.25 * PI))); #endif +// assert(res > 0.f); + if (res <= 0.f) + throw std::runtime_error("Flow::spacing() produced negative spacing. Did you set some extrusion width too small?"); + return res; } // This method returns the centerline spacing between an extrusion using this @@ -89,20 +93,26 @@ float Flow::spacing(const Flow &other) const { assert(this->height == other.height); assert(this->bridge == other.bridge); - return float(this->bridge ? + float res = float(this->bridge ? 0.5 * this->width + 0.5 * other.width + BRIDGE_EXTRA_SPACING : 0.5 * this->spacing() + 0.5 * other.spacing()); +// assert(res > 0.f); + if (res <= 0.f) + throw std::runtime_error("Flow::spacing() produced negative spacing. Did you set some extrusion width too small?"); + return res; } // This method returns extrusion volume per head move unit. double Flow::mm3_per_mm() const { - double res = this->bridge ? + float res = this->bridge ? // Area of a circle with dmr of this->width. (this->width * this->width) * 0.25 * PI : // Rectangle with semicircles at the ends. ~ h (w - 0.215 h) this->height * (this->width - this->height * (1. - 0.25 * PI)); - assert(res > 0.); + //assert(res > 0.); + if (res <= 0.) + throw std::runtime_error("Flow::mm3_per_mm() produced negative flow. Did you set some extrusion width too small?"); return res; } diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 0cc0a9d58..5e0878884 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -4,6 +4,8 @@ #include "../GCode.hpp" #include "../Geometry.hpp" +#include "../I18N.hpp" + #include "3mf.hpp" #include @@ -71,6 +73,7 @@ const char* V2_ATTR = "v2"; const char* V3_ATTR = "v3"; const char* OBJECTID_ATTR = "objectid"; const char* TRANSFORM_ATTR = "transform"; +const char* PRINTABLE_ATTR = "printable"; const char* KEY_ATTR = "key"; const char* VALUE_ATTR = "value"; @@ -131,6 +134,12 @@ int get_attribute_value_int(const char** attributes, unsigned int attributes_siz return (text != nullptr) ? ::atoi(text) : 0; } +bool get_attribute_value_bool(const char** attributes, unsigned int attributes_size, const char* attribute_key) +{ + const char* text = get_attribute_value_charptr(attributes, attributes_size, attribute_key); + return (text != nullptr) ? (bool)::atoi(text) : true; +} + Slic3r::Transform3d get_transform_from_string(const std::string& mat_str) { if (mat_str.empty()) @@ -195,6 +204,11 @@ bool is_valid_object_type(const std::string& type) namespace Slic3r { +//! macro used to mark string used at localization, +//! return same string +#define L(s) (s) +#define _(s) Slic3r::I18N::translate(s) + // Base class with error messages management class _3MF_Base { @@ -343,6 +357,7 @@ namespace Slic3r { // Version of the 3mf file unsigned int m_version; + bool m_check_version; XML_Parser m_xml_parser; Model* m_model; @@ -365,7 +380,7 @@ namespace Slic3r { _3MF_Importer(); ~_3MF_Importer(); - bool load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config); + bool load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config, bool check_version); private: void _destroy_xml_parser(); @@ -428,7 +443,7 @@ namespace Slic3r { bool _handle_start_metadata(const char** attributes, unsigned int num_attributes); bool _handle_end_metadata(); - bool _create_object_instance(int object_id, const Transform3d& transform, unsigned int recur_counter); + bool _create_object_instance(int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter); void _apply_transform(ModelInstance& instance, const Transform3d& transform); @@ -458,6 +473,7 @@ namespace Slic3r { _3MF_Importer::_3MF_Importer() : m_version(0) + , m_check_version(false) , m_xml_parser(nullptr) , m_model(nullptr) , m_unit_factor(1.0f) @@ -472,9 +488,10 @@ namespace Slic3r { _destroy_xml_parser(); } - bool _3MF_Importer::load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config) + bool _3MF_Importer::load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config, bool check_version) { m_version = 0; + m_check_version = check_version; m_model = &model; m_unit_factor = 1.0f; m_curr_object.reset(); @@ -536,12 +553,21 @@ namespace Slic3r { if (boost::algorithm::istarts_with(name, MODEL_FOLDER) && boost::algorithm::iends_with(name, MODEL_EXTENSION)) { - // valid model name -> extract model - if (!_extract_model_from_archive(archive, stat)) + try { + // valid model name -> extract model + if (!_extract_model_from_archive(archive, stat)) + { + close_zip_reader(&archive); + add_error("Archive does not contain a valid model"); + return false; + } + } + catch (const std::exception& e) + { + // ensure the zip archive is closed and rethrow the exception close_zip_reader(&archive); - add_error("Archive does not contain a valid model"); - return false; + throw e; } } } @@ -1367,8 +1393,9 @@ namespace Slic3r { int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR); Transform3d transform = get_transform_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); + int printable = get_attribute_value_bool(attributes, num_attributes, PRINTABLE_ATTR); - return _create_object_instance(object_id, transform, 1); + return _create_object_instance(object_id, transform, printable, 1); } bool _3MF_Importer::_handle_end_item() @@ -1391,12 +1418,20 @@ namespace Slic3r { bool _3MF_Importer::_handle_end_metadata() { if (m_curr_metadata_name == SLIC3RPE_3MF_VERSION) + { m_version = (unsigned int)atoi(m_curr_characters.c_str()); + if (m_check_version && (m_version > VERSION_3MF)) + { + std::string msg = _(L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatibile.")); + throw std::runtime_error(msg.c_str()); + } + } + return true; } - bool _3MF_Importer::_create_object_instance(int object_id, const Transform3d& transform, unsigned int recur_counter) + bool _3MF_Importer::_create_object_instance(int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter) { static const unsigned int MAX_RECURSIONS = 10; @@ -1432,6 +1467,7 @@ namespace Slic3r { add_error("Unable to add object instance"); return false; } + instance->printable = printable; m_instances.emplace_back(instance, transform); } @@ -1441,7 +1477,7 @@ namespace Slic3r { // recursively process nested components for (const Component& component : it->second) { - if (!_create_object_instance(component.object_id, transform * component.transform, recur_counter + 1)) + if (!_create_object_instance(component.object_id, transform * component.transform, printable, recur_counter + 1)) return false; } } @@ -1655,10 +1691,12 @@ namespace Slic3r { { unsigned int id; Transform3d transform; + bool printable; - BuildItem(unsigned int id, const Transform3d& transform) + BuildItem(unsigned int id, const Transform3d& transform, const bool printable) : id(id) , transform(transform) + , printable(printable) { } }; @@ -1951,7 +1989,7 @@ namespace Slic3r { Transform3d t = instance->get_matrix(); // instance_id is just a 1 indexed index in build_items. assert(instance_id == build_items.size() + 1); - build_items.emplace_back(instance_id, t); + build_items.emplace_back(instance_id, t, instance->printable); stream << " \n"; @@ -2059,7 +2097,7 @@ namespace Slic3r { stream << " "; } } - stream << "\" />\n"; + stream << "\" printable =\"" << item.printable << "\" />\n"; } stream << " \n"; @@ -2305,13 +2343,13 @@ namespace Slic3r { return true; } - bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model) + bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version) { if ((path == nullptr) || (config == nullptr) || (model == nullptr)) return false; _3MF_Importer importer; - bool res = importer.load_model_from_file(path, *model, *config); + bool res = importer.load_model_from_file(path, *model, *config, check_version); importer.log_errors(); return res; } diff --git a/src/libslic3r/Format/3mf.hpp b/src/libslic3r/Format/3mf.hpp index b5927651e..f387192ab 100644 --- a/src/libslic3r/Format/3mf.hpp +++ b/src/libslic3r/Format/3mf.hpp @@ -24,7 +24,7 @@ namespace Slic3r { class DynamicPrintConfig; // Load the content of a 3mf file into the given model and preset bundle. - extern bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model); + extern bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version); // Save the given model and the config data contained in the given Print into a 3mf file. // The model could be modified during the export process if meshes are not repaired or have no shared vertices diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index f2ce363ef..bb2982420 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -11,6 +11,8 @@ #include "../GCode.hpp" #include "../PrintConfig.hpp" #include "../Utils.hpp" +#include "../I18N.hpp" + #include "AMF.hpp" #include @@ -42,9 +44,14 @@ const char* SLIC3R_CONFIG_TYPE = "slic3rpe_config"; namespace Slic3r { +//! macro used to mark string used at localization, +//! return same string +#define L(s) (s) +#define _(s) Slic3r::I18N::translate(s) + struct AMFParserContext { - AMFParserContext(XML_Parser parser, DynamicPrintConfig *config, Model *model) : + AMFParserContext(XML_Parser parser, DynamicPrintConfig* config, Model* model) : m_version(0), m_parser(parser), m_model(*model), @@ -137,6 +144,7 @@ struct AMFParserContext NODE_TYPE_MIRRORX, // amf/constellation/instance/mirrorx NODE_TYPE_MIRRORY, // amf/constellation/instance/mirrory NODE_TYPE_MIRRORZ, // amf/constellation/instance/mirrorz + NODE_TYPE_PRINTABLE, // amf/constellation/instance/mirrorz NODE_TYPE_METADATA, // anywhere under amf/*/metadata }; @@ -145,7 +153,8 @@ struct AMFParserContext : deltax_set(false), deltay_set(false), deltaz_set(false) , rx_set(false), ry_set(false), rz_set(false) , scalex_set(false), scaley_set(false), scalez_set(false) - , mirrorx_set(false), mirrory_set(false), mirrorz_set(false) {} + , mirrorx_set(false), mirrory_set(false), mirrorz_set(false) + , printable(true) {} // Shift in the X axis. float deltax; bool deltax_set; @@ -178,6 +187,8 @@ struct AMFParserContext bool mirrory_set; float mirrorz; bool mirrorz_set; + // printable property + bool printable; bool anything_set() const { return deltax_set || deltay_set || deltaz_set || rx_set || ry_set || rz_set || @@ -321,6 +332,8 @@ void AMFParserContext::startElement(const char *name, const char **atts) node_type_new = NODE_TYPE_MIRRORY; else if (strcmp(name, "mirrorz") == 0) node_type_new = NODE_TYPE_MIRRORZ; + else if (strcmp(name, "printable") == 0) + node_type_new = NODE_TYPE_PRINTABLE; } else if (m_path[2] == NODE_TYPE_LAYER_CONFIG && strcmp(name, "range") == 0) { assert(m_object); @@ -397,7 +410,8 @@ void AMFParserContext::characters(const XML_Char *s, int len) m_path.back() == NODE_TYPE_SCALE || m_path.back() == NODE_TYPE_MIRRORX || m_path.back() == NODE_TYPE_MIRRORY || - m_path.back() == NODE_TYPE_MIRRORZ) + m_path.back() == NODE_TYPE_MIRRORZ || + m_path.back() == NODE_TYPE_PRINTABLE) m_value[0].append(s, len); break; case 6: @@ -507,6 +521,11 @@ void AMFParserContext::endElement(const char * /* name */) m_instance->mirrorz_set = true; m_value[0].clear(); break; + case NODE_TYPE_PRINTABLE: + assert(m_instance); + m_instance->printable = bool(atoi(m_value[0].c_str())); + m_value[0].clear(); + break; // Object vertices: case NODE_TYPE_VERTEX: @@ -685,6 +704,7 @@ void AMFParserContext::endDocument() mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0)); mi->set_scaling_factor(Vec3d(instance.scalex_set ? (double)instance.scalex : 1.0, instance.scaley_set ? (double)instance.scaley : 1.0, instance.scalez_set ? (double)instance.scalez : 1.0)); mi->set_mirror(Vec3d(instance.mirrorx_set ? (double)instance.mirrorx : 1.0, instance.mirrory_set ? (double)instance.mirrory : 1.0, instance.mirrorz_set ? (double)instance.mirrorz : 1.0)); + mi->printable = instance.printable; } } } @@ -742,7 +762,7 @@ bool load_amf_file(const char *path, DynamicPrintConfig *config, Model *model) return result; } -bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig* config, Model* model, unsigned int& version) +bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig* config, Model* model, bool check_version) { if (stat.m_uncomp_size == 0) { @@ -788,19 +808,21 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi ctx.endDocument(); - version = ctx.m_version; + if (check_version && (ctx.m_version > VERSION_AMF)) + { + std::string msg = _(L("The selected amf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatibile.")); + throw std::runtime_error(msg.c_str()); + } return true; } // Load an AMF archive into a provided model. -bool load_amf_archive(const char *path, DynamicPrintConfig *config, Model *model) +bool load_amf_archive(const char* path, DynamicPrintConfig* config, Model* model, bool check_version) { if ((path == nullptr) || (model == nullptr)) return false; - unsigned int version = 0; - mz_zip_archive archive; mz_zip_zero_struct(&archive); @@ -820,11 +842,20 @@ bool load_amf_archive(const char *path, DynamicPrintConfig *config, Model *model { if (boost::iends_with(stat.m_filename, ".amf")) { - if (!extract_model_from_archive(archive, stat, config, model, version)) + try { + if (!extract_model_from_archive(archive, stat, config, model, check_version)) + { + close_zip_reader(&archive); + printf("Archive does not contain a valid model"); + return false; + } + } + catch (const std::exception& e) + { + // ensure the zip archive is closed and rethrow the exception close_zip_reader(&archive); - printf("Archive does not contain a valid model"); - return false; + throw e; } break; @@ -849,7 +880,7 @@ bool load_amf_archive(const char *path, DynamicPrintConfig *config, Model *model // Load an AMF file into a provided model. // If config is not a null pointer, updates it if the amf file/archive contains config data -bool load_amf(const char *path, DynamicPrintConfig *config, Model *model) +bool load_amf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version) { if (boost::iends_with(path, ".amf.xml")) // backward compatibility with older slic3r output @@ -864,7 +895,7 @@ bool load_amf(const char *path, DynamicPrintConfig *config, Model *model) file.read(const_cast(zip_mask.data()), 2); file.close(); - return (zip_mask == "PK") ? load_amf_archive(path, config, model) : load_amf_file(path, config, model); + return (zip_mask == "PK") ? load_amf_archive(path, config, model, check_version) : load_amf_file(path, config, model); } else return false; @@ -1036,6 +1067,7 @@ bool store_amf(std::string &path, Model *model, const DynamicPrintConfig *config " %lf\n" " %lf\n" " %lf\n" + " %d\n" " \n", object_id, instance->get_offset(X), @@ -1049,7 +1081,8 @@ bool store_amf(std::string &path, Model *model, const DynamicPrintConfig *config instance->get_scaling_factor(Z), instance->get_mirror(X), instance->get_mirror(Y), - instance->get_mirror(Z)); + instance->get_mirror(Z), + instance->printable); //FIXME missing instance->scaling_factor instances.append(buf); diff --git a/src/libslic3r/Format/AMF.hpp b/src/libslic3r/Format/AMF.hpp index d7b08edeb..c8b7a8df2 100644 --- a/src/libslic3r/Format/AMF.hpp +++ b/src/libslic3r/Format/AMF.hpp @@ -7,7 +7,7 @@ class Model; class DynamicPrintConfig; // Load the content of an amf file into the given model and configuration. -extern bool load_amf(const char *path, DynamicPrintConfig *config, Model *model); +extern bool load_amf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version); // Save the given model and the config data into an amf file. // The model could be modified during the export process if meshes are not repaired or have no shared vertices diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index ccd8bb279..ea330f192 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1,4 +1,5 @@ #include "libslic3r.h" +#include "I18N.hpp" #include "GCode.hpp" #include "ExtrusionEntity.hpp" #include "EdgeGrid.hpp" @@ -23,6 +24,8 @@ #include "SVG.hpp" +#include + #include #if 0 @@ -36,6 +39,11 @@ namespace Slic3r { +//! macro used to mark string used at localization, +//! return same string +#define L(s) (s) +#define _(s) Slic3r::I18N::translate(s) + // Only add a newline in case the current G-code does not end with a newline. static inline void check_add_eol(std::string &gcode) { @@ -43,6 +51,11 @@ static inline void check_add_eol(std::string &gcode) gcode += '\n'; } +void AvoidCrossingPerimeters::init_external_mp(const Print &print) +{ + m_external_mp = Slic3r::make_unique(union_ex(this->collect_contours_all_layers(print.objects()))); +} + // Plan a travel move while minimizing the number of perimeter crossings. // point is in unscaled coordinates, in the coordinate system of the current active object // (set by gcodegen.set_origin()). @@ -59,6 +72,72 @@ Polyline AvoidCrossingPerimeters::travel_to(const GCode &gcodegen, const Point & return result; } +// Collect outer contours of all objects over all layers. +// Discard objects only containing thin walls (offset would fail on an empty polygon). +// Used by avoid crossing perimeters feature. +Polygons AvoidCrossingPerimeters::collect_contours_all_layers(const PrintObjectPtrs& objects) +{ + Polygons islands; + for (const PrintObject *object : objects) { + // Reducing all the object slices into the Z projection in a logarithimc fashion. + // First reduce to half the number of layers. + std::vector polygons_per_layer((object->layers().size() + 1) / 2); + tbb::parallel_for(tbb::blocked_range(0, object->layers().size() / 2), + [&object, &polygons_per_layer](const tbb::blocked_range &range) { + for (size_t i = range.begin(); i < range.end(); ++ i) { + const Layer* layer1 = object->layers()[i * 2]; + const Layer* layer2 = object->layers()[i * 2 + 1]; + Polygons polys; + polys.reserve(layer1->slices.expolygons.size() + layer2->slices.expolygons.size()); + for (const ExPolygon &expoly : layer1->slices.expolygons) + //FIXME no holes? + polys.emplace_back(expoly.contour); + for (const ExPolygon &expoly : layer2->slices.expolygons) + //FIXME no holes? + polys.emplace_back(expoly.contour); + polygons_per_layer[i] = union_(polys); + } + }); + if (object->layers().size() & 1) { + const Layer *layer = object->layers().back(); + Polygons polys; + polys.reserve(layer->slices.expolygons.size()); + for (const ExPolygon &expoly : layer->slices.expolygons) + //FIXME no holes? + polys.emplace_back(expoly.contour); + polygons_per_layer.back() = union_(polys); + } + // Now reduce down to a single layer. + size_t cnt = polygons_per_layer.size(); + while (cnt > 1) { + tbb::parallel_for(tbb::blocked_range(0, cnt / 2), + [&polygons_per_layer](const tbb::blocked_range &range) { + for (size_t i = range.begin(); i < range.end(); ++ i) { + Polygons polys; + polys.reserve(polygons_per_layer[i * 2].size() + polygons_per_layer[i * 2 + 1].size()); + polygons_append(polys, polygons_per_layer[i * 2]); + polygons_append(polys, polygons_per_layer[i * 2 + 1]); + polygons_per_layer[i * 2] = union_(polys); + } + }); + for (size_t i = 0; i < cnt / 2; ++ i) + polygons_per_layer[i] = std::move(polygons_per_layer[i * 2]); + if (cnt & 1) + polygons_per_layer[cnt / 2] = std::move(polygons_per_layer[cnt - 1]); + cnt = (cnt + 1) / 2; + } + // And collect copies of the objects. + for (const Point © : object->copies()) { + // All the layers were reduced to the 1st item of polygons_per_layer. + size_t i = islands.size(); + polygons_append(islands, polygons_per_layer.front()); + for (; i < islands.size(); ++ i) + islands[i].translate(copy); + } + } + return islands; +} + std::string OozePrevention::pre_toolchange(GCode &gcodegen) { std::string gcode; @@ -191,9 +270,6 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T std::string tcr_rotated_gcode = post_process_wipe_tower_moves(tcr, wipe_tower_offset, wipe_tower_rotation); - // Disable linear advance for the wipe tower operations. - gcode += (gcodegen.config().gcode_flavor == gcfRepRap ? std::string("M572 D0 S0\n") : std::string("M900 K0\n")); - if (!tcr.priming) { // Move over the wipe tower. // Retract for a tool change, using the toolchange retract value and setting the priming extra length. @@ -362,7 +438,6 @@ std::string WipeTowerIntegration::post_process_wipe_tower_moves(const WipeTower: std::string WipeTowerIntegration::prime(GCode &gcodegen) { - //assert(m_layer_idx == 0); std::string gcode; if (&m_priming != nullptr) { @@ -405,7 +480,8 @@ std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id, assert(m_layer_idx >= 0 && size_t(m_layer_idx) <= m_tool_changes.size()); if (! m_brim_done || gcodegen.writer().need_toolchange(extruder_id) || finish_layer) { if (m_layer_idx < (int)m_tool_changes.size()) { - assert(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size()); + if (! (size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size())) + throw std::runtime_error("Wipe tower generation failed, possibly due to empty first layer."); gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id); } m_brim_done = true; @@ -435,6 +511,7 @@ std::vector GCode::collect_layers_to_print(const PrintObjec // Pair the object layers with the support layers by z. size_t idx_object_layer = 0; size_t idx_support_layer = 0; + const LayerToPrint* last_extrusion_layer = nullptr; while (idx_object_layer < object.layers().size() || idx_support_layer < object.support_layers().size()) { LayerToPrint layer_to_print; layer_to_print.object_layer = (idx_object_layer < object.layers().size()) ? object.layers()[idx_object_layer ++] : nullptr; @@ -448,7 +525,31 @@ std::vector GCode::collect_layers_to_print(const PrintObjec -- idx_object_layer; } } + layers_to_print.emplace_back(layer_to_print); + + // In case there are extrusions on this layer, check there is a layer to lay it on. + if ((layer_to_print.object_layer && layer_to_print.object_layer->has_extrusions()) + || (layer_to_print.support_layer && layer_to_print.support_layer->has_extrusions())) { + double support_contact_z = (last_extrusion_layer && last_extrusion_layer->support_layer) + ? object.config().support_material_contact_distance + : 0.; + double maximal_print_z = (last_extrusion_layer ? last_extrusion_layer->print_z() : 0.) + + layer_to_print.layer()->height + + std::max(0., support_contact_z); + // Negative support_contact_z is not taken into account, it can result in false positives in cases + // where previous layer has object extrusions too (https://github.com/prusa3d/PrusaSlicer/issues/2752) + + + if (layer_to_print.print_z() > maximal_print_z + EPSILON) + throw std::runtime_error(_(L("Empty layers detected, the output would not be printable.")) + "\n\n" + + _(L("Object name: ")) + object.model_object()->name + "\n" + _(L("Print z: ")) + + std::to_string(layers_to_print.back().print_z()) + "\n\n" + _(L("This is " + "usually caused by negligibly small extrusions or by a faulty model. Try to repair " + " the model or change its orientation on the bed."))); + // Remember last layer with extrusions. + last_extrusion_layer = &layers_to_print.back(); + } } return layers_to_print; @@ -561,11 +662,11 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ } if (print->config().remaining_times.value) { - BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for normal mode"; + BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for normal mode" << log_memory_info(); m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f); m_normal_time_estimator.reset(); if (m_silent_time_estimator_enabled) { - BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for silent mode"; + BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for silent mode" << log_memory_info(); m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f); m_silent_time_estimator.reset(); } @@ -573,12 +674,12 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ // starts analyzer calculations if (m_enable_analyzer) { - BOOST_LOG_TRIVIAL(debug) << "Preparing G-code preview data"; + BOOST_LOG_TRIVIAL(debug) << "Preparing G-code preview data" << log_memory_info(); m_analyzer.calc_gcode_preview_data(*preview_data, [print]() { print->throw_if_canceled(); }); m_analyzer.reset(); } - if (rename_file(path_tmp, path) != 0) + if (rename_file(path_tmp, path)) throw std::runtime_error( std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' + "Is " + path_tmp + " locked?" + '\n'); @@ -748,7 +849,7 @@ void GCode::_do_export(Print &print, FILE *file) mm3_per_mm.erase(std::remove_if(mm3_per_mm.begin(), mm3_per_mm.end(), [](double v) { return v < 0.000001; }), mm3_per_mm.end()); if (! mm3_per_mm.empty()) { // In order to honor max_print_speed we need to find a target volumetric - // speed that we can use throughout the print. So we define this target + // speed that we can use throughout the print. So we define this target // volumetric speed as the volumetric speed produced by printing the // smallest cross-section at the maximum speed: any larger cross-section // will need slower feedrates. @@ -836,7 +937,7 @@ void GCode::_do_export(Print &print, FILE *file) _writeln(file, GCodeTimeEstimator::Silent_First_M73_Output_Placeholder_Tag); } - // Prepare the helper object for replacing placeholders in custom G-code and output filename. + // Prepare the helper object for replacing placeholders in custom G-code and output filename. m_placeholder_parser = print.placeholder_parser(); m_placeholder_parser.update_timestamp(); print.update_object_placeholders(m_placeholder_parser.config_writable(), ".gcode"); @@ -931,19 +1032,9 @@ void GCode::_do_export(Print &print, FILE *file) _write(file, this->preamble()); // Initialize a motion planner for object-to-object travel moves. + m_avoid_crossing_perimeters.reset(); if (print.config().avoid_crossing_perimeters.value) { - // Collect outer contours of all objects over all layers. - // Discard objects only containing thin walls (offset would fail on an empty polygon). - Polygons islands; - for (const PrintObject *object : print.objects()) - for (const Layer *layer : object->layers()) - for (const ExPolygon &expoly : layer->slices.expolygons) - for (const Point © : object->copies()) { - islands.emplace_back(expoly.contour); - islands.back().translate(copy); - } - //FIXME Mege the islands in parallel. - m_avoid_crossing_perimeters.init_external_mp(union_ex(islands)); + m_avoid_crossing_perimeters.init_external_mp(print); print.throw_if_canceled(); } @@ -1159,9 +1250,9 @@ void GCode::_do_export(Print &print, FILE *file) print.m_print_statistics.clear(); print.m_print_statistics.estimated_normal_print_time = m_normal_time_estimator.get_time_dhms(); print.m_print_statistics.estimated_silent_print_time = m_silent_time_estimator_enabled ? m_silent_time_estimator.get_time_dhms() : "N/A"; - print.m_print_statistics.estimated_normal_color_print_times = m_normal_time_estimator.get_color_times_dhms(); + print.m_print_statistics.estimated_normal_color_print_times = m_normal_time_estimator.get_color_times_dhms(true); if (m_silent_time_estimator_enabled) - print.m_print_statistics.estimated_silent_color_print_times = m_silent_time_estimator.get_color_times_dhms(); + print.m_print_statistics.estimated_silent_color_print_times = m_silent_time_estimator.get_color_times_dhms(true); std::vector extruders = m_writer.extruders(); if (! extruders.empty()) { @@ -1514,7 +1605,13 @@ void GCode::process_layer( // we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count if (colorprint_change && print./*extruders()*/config().nozzle_diameter.size()==1) + { + // add tag for analyzer + gcode += "; " + GCodeAnalyzer::Color_Change_Tag + "\n"; + // add tag for time estimator + gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n"; gcode += "M600\n"; + } // Extrude skirt at the print_z of the raft layers and normal object layers @@ -1870,7 +1967,8 @@ void GCode::process_layer( ", time estimator memory: " << format_memsize_MB(m_normal_time_estimator.memory_used() + m_silent_time_estimator_enabled ? m_silent_time_estimator.memory_used() : 0) << ", analyzer memory: " << - format_memsize_MB(m_analyzer.memory_used()); + format_memsize_MB(m_analyzer.memory_used()) << + log_memory_info(); } void GCode::apply_print_config(const PrintConfig &print_config) @@ -2789,7 +2887,7 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string EXTRUDER_CONFIG(filament_max_volumetric_speed) / path.mm3_per_mm ); } - double F = speed * 60; // convert mm/sec to mm/min + double F = speed * 60; // convert mm/sec to mm/min // extrude arc or line if (m_enable_extrusion_role_markers) { @@ -3049,7 +3147,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z) // Set the temperature if the wipe tower didn't (not needed for non-single extruder MM) if (m_config.single_extruder_multi_material && !m_config.wipe_tower) { - int temp = (m_layer_index == 0 ? m_config.first_layer_temperature.get_at(extruder_id) : + int temp = (m_layer_index <= 0 ? m_config.first_layer_temperature.get_at(extruder_id) : m_config.temperature.get_at(extruder_id)); gcode += m_writer.set_temperature(temp, false); diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 110280a26..50aca0e6f 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -45,13 +45,17 @@ public: AvoidCrossingPerimeters() : use_external_mp(false), use_external_mp_once(false), disable_once(true) {} ~AvoidCrossingPerimeters() {} - void init_external_mp(const ExPolygons &islands) { m_external_mp = Slic3r::make_unique(islands); } + void reset() { m_external_mp.reset(); m_layer_mp.reset(); } + void init_external_mp(const Print &print); void init_layer_mp(const ExPolygons &islands) { m_layer_mp = Slic3r::make_unique(islands); } Polyline travel_to(const GCode &gcodegen, const Point &point); bool is_init() { return (use_external_mp || use_external_mp_once) ? m_external_mp.get() != nullptr : m_layer_mp.get() != nullptr; } private: + // For initializing the regions to avoid. + static Polygons collect_contours_all_layers(const PrintObjectPtrs& objects); + std::unique_ptr m_external_mp; std::unique_ptr m_layer_mp; }; diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp index 57eee2e21..8fd576081 100644 --- a/src/libslic3r/GCode/Analyzer.cpp +++ b/src/libslic3r/GCode/Analyzer.cpp @@ -25,6 +25,7 @@ const std::string GCodeAnalyzer::Extrusion_Role_Tag = "_ANALYZER_EXTR_ROLE:"; const std::string GCodeAnalyzer::Mm3_Per_Mm_Tag = "_ANALYZER_MM3_PER_MM:"; const std::string GCodeAnalyzer::Width_Tag = "_ANALYZER_WIDTH:"; const std::string GCodeAnalyzer::Height_Tag = "_ANALYZER_HEIGHT:"; +const std::string GCodeAnalyzer::Color_Change_Tag = "_ANALYZER_COLOR_CHANGE"; const double GCodeAnalyzer::Default_mm3_per_mm = 0.0; const float GCodeAnalyzer::Default_Width = 0.0f; @@ -240,11 +241,6 @@ void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLi { switch (::atoi(&cmd[1])) { - case 600: // Set color change - { - _processM600(line); - break; - } case 82: // Set extruder to absolute mode { _processM82(line); @@ -517,12 +513,6 @@ void GCodeAnalyzer::_reset_cached_position() } } -void GCodeAnalyzer::_processM600(const GCodeReader::GCodeLine& line) -{ - m_state.cur_cp_color_id++; - _set_cp_color_id(m_state.cur_cp_color_id); -} - void GCodeAnalyzer::_processT(const std::string& cmd) { if (cmd.length() > 1) @@ -579,6 +569,14 @@ bool GCodeAnalyzer::_process_tags(const GCodeReader::GCodeLine& line) return true; } + // color change tag + pos = comment.find(Color_Change_Tag); + if (pos != comment.npos) + { + _process_color_change_tag(); + return true; + } + return false; } @@ -608,6 +606,12 @@ void GCodeAnalyzer::_process_height_tag(const std::string& comment, size_t pos) _set_height((float)::strtod(comment.substr(pos + Height_Tag.length()).c_str(), nullptr)); } +void GCodeAnalyzer::_process_color_change_tag() +{ + m_state.cur_cp_color_id++; + _set_cp_color_id(m_state.cur_cp_color_id); +} + void GCodeAnalyzer::_set_units(GCodeAnalyzer::EUnits units) { m_state.units = units; @@ -945,12 +949,12 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s polyline = Polyline3(); // add both vertices of the move - polyline.append(Vec3crd(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()))); - polyline.append(Vec3crd(scale_(move.end_position.x()), scale_(move.end_position.y()), scale_(move.end_position.z()))); + polyline.append(Vec3crd((int)scale_(move.start_position.x()), (int)scale_(move.start_position.y()), (int)scale_(move.start_position.z()))); + polyline.append(Vec3crd((int)scale_(move.end_position.x()), (int)scale_(move.end_position.y()), (int)scale_(move.end_position.z()))); } else // append end vertex of the move to current polyline - polyline.append(Vec3crd(scale_(move.end_position.x()), scale_(move.end_position.y()), scale_(move.end_position.z()))); + polyline.append(Vec3crd((int)scale_(move.end_position.x()), (int)scale_(move.end_position.y()), (int)scale_(move.end_position.z()))); // update current values position = move.end_position; @@ -994,7 +998,7 @@ void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_da cancel_callback(); // store position - Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())); + Vec3crd position((int)scale_(move.start_position.x()), (int)scale_(move.start_position.y()), (int)scale_(move.start_position.z())); preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height); } @@ -1021,7 +1025,7 @@ void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_ cancel_callback(); // store position - Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())); + Vec3crd position((int)scale_(move.start_position.x()), (int)scale_(move.start_position.y()), (int)scale_(move.start_position.z())); preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height); } diff --git a/src/libslic3r/GCode/Analyzer.hpp b/src/libslic3r/GCode/Analyzer.hpp index 3ec146c5b..b353dca49 100644 --- a/src/libslic3r/GCode/Analyzer.hpp +++ b/src/libslic3r/GCode/Analyzer.hpp @@ -20,6 +20,7 @@ public: static const std::string Mm3_Per_Mm_Tag; static const std::string Width_Tag; static const std::string Height_Tag; + static const std::string Color_Change_Tag; static const double Default_mm3_per_mm; static const float Default_Width; @@ -178,9 +179,6 @@ private: // Repetier: Go to stored position void _processM402(const GCodeReader::GCodeLine& line); - // Set color change - void _processM600(const GCodeReader::GCodeLine& line); - // Processes T line (Select Tool) void _processT(const std::string& command); void _processT(const GCodeReader::GCodeLine& line); @@ -201,6 +199,9 @@ private: // Processes height tag void _process_height_tag(const std::string& comment, size_t pos); + // Processes color change tag + void _process_color_change_tag(); + void _set_units(EUnits units); EUnits _get_units() const; diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 689dd2662..0f60eb862 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -78,8 +78,13 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool zs.emplace_back(layer->print_z); for (auto layer : object->support_layers()) zs.emplace_back(layer->print_z); - if (! object->layers().empty()) - object_bottom_z = object->layers().front()->print_z - object->layers().front()->height; + + // Find first object layer that is not empty and save its print_z + for (const Layer* layer : object->layers()) + if (layer->has_extrusions()) { + object_bottom_z = layer->print_z - layer->height; + break; + } } this->initialize_layers(zs); } @@ -96,23 +101,6 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool this->collect_extruder_statistics(prime_multi_material); } - -LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) -{ - auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), LayerTools(print_z - EPSILON)); - assert(it_layer_tools != m_layer_tools.end()); - coordf_t dist_min = std::abs(it_layer_tools->print_z - print_z); - for (++ it_layer_tools; it_layer_tools != m_layer_tools.end(); ++it_layer_tools) { - coordf_t d = std::abs(it_layer_tools->print_z - print_z); - if (d >= dist_min) - break; - dist_min = d; - } - -- it_layer_tools; - assert(dist_min < EPSILON); - return *it_layer_tools; -} - void ToolOrdering::initialize_layers(std::vector &zs) { sort_remove_duplicates(zs); @@ -151,7 +139,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object) LayerTools &layer_tools = this->tools_for_layer(layer->print_z); // What extruders are required to print this object layer? for (size_t region_id = 0; region_id < object.region_volumes.size(); ++ region_id) { - const LayerRegion *layerm = (region_id < layer->regions().size()) ? layer->regions()[region_id] : nullptr; + const LayerRegion *layerm = (region_id < layer->regions().size()) ? layer->regions()[region_id] : nullptr; if (layerm == nullptr) continue; const PrintRegion ®ion = *object.print()->regions()[region_id]; @@ -324,16 +312,17 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_ m_layer_tools[j].has_wipe_tower = true; } else { LayerTools <_extra = *m_layer_tools.insert(m_layer_tools.begin() + j, lt_new); + //LayerTools <_prev = m_layer_tools[j]; LayerTools <_next = m_layer_tools[j + 1]; assert(! m_layer_tools[j - 1].extruders.empty() && ! lt_next.extruders.empty()); // FIXME: Following assert tripped when running combine_infill.t. I decided to comment it out for now. // If it is a bug, it's likely not critical, because this code is unchanged for a long time. It might // still be worth looking into it more and decide if it is a bug or an obsolete assert. //assert(lt_prev.extruders.back() == lt_next.extruders.front()); - lt_extra.has_wipe_tower = true; + lt_extra.has_wipe_tower = true; lt_extra.extruders.push_back(lt_next.extruders.front()); - lt_extra.wipe_tower_partitions = lt_next.wipe_tower_partitions; - } + lt_extra.wipe_tower_partitions = lt_next.wipe_tower_partitions; + } } } break; @@ -375,7 +364,7 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material) // Reorder m_all_printing_extruders in the sequence they will be primed, the last one will be m_first_printing_extruder. // Then set m_first_printing_extruder to the 1st extruder primed. m_all_printing_extruders.erase( - std::remove_if(m_all_printing_extruders.begin(), m_all_printing_extruders.end(), + std::remove_if(m_all_printing_extruders.begin(), m_all_printing_extruders.end(), [ this ](const unsigned int eid) { return eid == m_first_printing_extruder; }), m_all_printing_extruders.end()); m_all_printing_extruders.emplace_back(m_first_printing_extruder); @@ -623,6 +612,6 @@ const std::vector* WipingExtrusions::get_extruder_overrides(const Extrusion return &(entity_map_it->second); } - + } // namespace Slic3r diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index 538127810..d4006120d 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -102,45 +102,60 @@ private: class ToolOrdering { public: - ToolOrdering() {} + ToolOrdering() {} - // For the use case when each object is printed separately - // (print.config.complete_objects is true). - ToolOrdering(const PrintObject &object, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false); + // For the use case when each object is printed separately + // (print.config.complete_objects is true). + ToolOrdering(const PrintObject &object, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false); - // For the use case when all objects are printed at once. - // (print.config.complete_objects is false). - ToolOrdering(const Print &print, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false); + // For the use case when all objects are printed at once. + // (print.config.complete_objects is false). + ToolOrdering(const Print &print, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false); - void clear() { m_layer_tools.clear(); } + void clear() { m_layer_tools.clear(); } - // Get the first extruder printing, including the extruder priming areas, returns -1 if there is no layer printed. - unsigned int first_extruder() const { return m_first_printing_extruder; } + // Get the first extruder printing, including the extruder priming areas, returns -1 if there is no layer printed. + unsigned int first_extruder() const { return m_first_printing_extruder; } - // Get the first extruder printing the layer_tools, returns -1 if there is no layer printed. - unsigned int last_extruder() const { return m_last_printing_extruder; } + // Get the first extruder printing the layer_tools, returns -1 if there is no layer printed. + unsigned int last_extruder() const { return m_last_printing_extruder; } - // For a multi-material print, the printing extruders are ordered in the order they shall be primed. - const std::vector& all_extruders() const { return m_all_printing_extruders; } + // For a multi-material print, the printing extruders are ordered in the order they shall be primed. + const std::vector& all_extruders() const { return m_all_printing_extruders; } - // Find LayerTools with the closest print_z. - LayerTools& tools_for_layer(coordf_t print_z); - const LayerTools& tools_for_layer(coordf_t print_z) const - { return *const_cast(&const_cast(this)->tools_for_layer(print_z)); } + template static auto tools_for_layer(Self& self, coordf_t print_z) -> decltype (*self.m_layer_tools.begin()) + { + auto it_layer_tools = std::lower_bound(self.m_layer_tools.begin(), self.m_layer_tools.end(), LayerTools(print_z - EPSILON)); + assert(it_layer_tools != self.m_layer_tools.end()); + coordf_t dist_min = std::abs(it_layer_tools->print_z - print_z); + for (++ it_layer_tools; it_layer_tools != self.m_layer_tools.end(); ++it_layer_tools) { + coordf_t d = std::abs(it_layer_tools->print_z - print_z); + if (d >= dist_min) + break; + dist_min = d; + } + -- it_layer_tools; + assert(dist_min < EPSILON); + return *it_layer_tools; + } - const LayerTools& front() const { return m_layer_tools.front(); } - const LayerTools& back() const { return m_layer_tools.back(); } - std::vector::const_iterator begin() const { return m_layer_tools.begin(); } - std::vector::const_iterator end() const { return m_layer_tools.end(); } - bool empty() const { return m_layer_tools.empty(); } - std::vector& layer_tools() { return m_layer_tools; } - bool has_wipe_tower() const { return ! m_layer_tools.empty() && m_first_printing_extruder != (unsigned int)-1 && m_layer_tools.front().wipe_tower_partitions > 0; } + // Find LayerTools with the closest print_z. + LayerTools& tools_for_layer(coordf_t print_z) { return tools_for_layer(*this, print_z); } + const LayerTools& tools_for_layer(coordf_t print_z) const { return tools_for_layer(*this, print_z); } + + const LayerTools& front() const { return m_layer_tools.front(); } + const LayerTools& back() const { return m_layer_tools.back(); } + std::vector::const_iterator begin() const { return m_layer_tools.begin(); } + std::vector::const_iterator end() const { return m_layer_tools.end(); } + bool empty() const { return m_layer_tools.empty(); } + std::vector& layer_tools() { return m_layer_tools; } + bool has_wipe_tower() const { return ! m_layer_tools.empty() && m_first_printing_extruder != (unsigned int)-1 && m_layer_tools.front().wipe_tower_partitions > 0; } private: - void initialize_layers(std::vector &zs); - void collect_extruders(const PrintObject &object); - void reorder_extruders(unsigned int last_extruder_id); - void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z); + void initialize_layers(std::vector &zs); + void collect_extruders(const PrintObject &object); + void reorder_extruders(unsigned int last_extruder_id); + void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z); void collect_extruder_statistics(bool prime_multi_material); std::vector m_layer_tools; diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index cd90eba04..2ba3b4d51 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -22,6 +22,7 @@ TODO LIST #include #include "Analyzer.hpp" +#include "BoundingBox.hpp" #if defined(__linux) || defined(__GNUC__ ) #include @@ -113,6 +114,11 @@ public: return (*this); } + WipeTowerWriter& disable_linear_advance() { + m_gcode += (m_gcode_flavor == gcfRepRap ? std::string("M572 D0 S0\n") : std::string("M900 K0\n")); + return *this; + } + // Suppress / resume G-code preview in Slic3r. Slic3r will have difficulty to differentiate the various // filament loading and cooling moves from normal extrusion moves. Therefore the writer // is asked to suppres output of some lines, which look like extrusions. @@ -470,6 +476,83 @@ private: +WipeTower::WipeTower(const PrintConfig& config, const std::vector>& wiping_matrix, size_t initial_tool) : + m_semm(config.single_extruder_multi_material.value), + m_wipe_tower_pos(config.wipe_tower_x, config.wipe_tower_y), + m_wipe_tower_width(config.wipe_tower_width), + m_wipe_tower_rotation_angle(config.wipe_tower_rotation_angle), + m_y_shift(0.f), + m_z_pos(0.f), + m_is_first_layer(false), + m_bridging(config.wipe_tower_bridging), + m_gcode_flavor(config.gcode_flavor), + m_current_tool(initial_tool), + wipe_volumes(wiping_matrix) +{ + // If this is a single extruder MM printer, we will use all the SE-specific config values. + // Otherwise, the defaults will be used to turn off the SE stuff. + if (m_semm) { + m_cooling_tube_retraction = config.cooling_tube_retraction; + m_cooling_tube_length = config.cooling_tube_length; + m_parking_pos_retraction = config.parking_pos_retraction; + m_extra_loading_move = config.extra_loading_move; + m_set_extruder_trimpot = config.high_current_on_filament_swap; + } + // Calculate where the priming lines should be - very naive test not detecting parallelograms or custom shapes + const std::vector& bed_points = config.bed_shape.values; + m_bed_shape = (bed_points.size() == 4 ? RectangularBed : CircularBed); + m_bed_width = BoundingBoxf(bed_points).size().x(); +} + + + +void WipeTower::set_extruder(size_t idx, const PrintConfig& config) +{ + //while (m_filpar.size() < idx+1) // makes sure the required element is in the vector + m_filpar.push_back(FilamentParameters()); + + m_filpar[idx].material = config.filament_type.get_at(idx); + m_filpar[idx].temperature = config.temperature.get_at(idx); + m_filpar[idx].first_layer_temperature = config.first_layer_temperature.get_at(idx); + + // If this is a single extruder MM printer, we will use all the SE-specific config values. + // Otherwise, the defaults will be used to turn off the SE stuff. + if (m_semm) { + m_filpar[idx].loading_speed = config.filament_loading_speed.get_at(idx); + m_filpar[idx].loading_speed_start = config.filament_loading_speed_start.get_at(idx); + m_filpar[idx].unloading_speed = config.filament_unloading_speed.get_at(idx); + m_filpar[idx].unloading_speed_start = config.filament_unloading_speed_start.get_at(idx); + m_filpar[idx].delay = config.filament_toolchange_delay.get_at(idx); + m_filpar[idx].cooling_moves = config.filament_cooling_moves.get_at(idx); + m_filpar[idx].cooling_initial_speed = config.filament_cooling_initial_speed.get_at(idx); + m_filpar[idx].cooling_final_speed = config.filament_cooling_final_speed.get_at(idx); + } + + m_filpar[idx].filament_area = float((M_PI/4.f) * pow(config.filament_diameter.get_at(idx), 2)); // all extruders are assumed to have the same filament diameter at this point + float nozzle_diameter = config.nozzle_diameter.get_at(idx); + m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM + + float max_vol_speed = config.filament_max_volumetric_speed.get_at(idx); + if (max_vol_speed!= 0.f) + m_filpar[idx].max_e_speed = (max_vol_speed / filament_area()); + + m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter + + if (m_semm) { + std::istringstream stream{config.filament_ramming_parameters.get_at(idx)}; + float speed = 0.f; + stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator; + m_filpar[idx].ramming_line_width_multiplicator /= 100; + m_filpar[idx].ramming_step_multiplicator /= 100; + while (stream >> speed) + m_filpar[idx].ramming_speed.push_back(speed); + } + + m_used_filament_length.resize(std::max(m_used_filament_length.size(), idx + 1)); // makes sure that the vector is big enough so we don't have to check later +} + + + // Returns gcode to prime the nozzles at the front edge of the print bed. std::vector WipeTower::prime( // print_z of the first layer. @@ -488,9 +571,11 @@ std::vector WipeTower::prime( // therefore the homing position is shifted inside the bed by 0.2 in the firmware to [0.2, -2.0]. // box_coordinates cleaning_box(xy(0.5f, - 1.5f), m_wipe_tower_width, wipe_area); - const float prime_section_width = std::min(240.f / tools.size(), 60.f); - box_coordinates cleaning_box(Vec2f(5.f, 0.01f + m_perimeter_width/2.f), prime_section_width, 100.f); - + float prime_section_width = std::min(0.9f * m_bed_width / tools.size(), 60.f); + box_coordinates cleaning_box(Vec2f(0.02f * m_bed_width, 0.01f + m_perimeter_width/2.f), prime_section_width, 100.f); + // In case of a circular bed, place it so it goes across the diameter and hope it will fit + if (m_bed_shape == CircularBed) + cleaning_box.translate(-m_bed_width/2 + m_bed_width * 0.03f, -m_bed_width * 0.12f); std::vector results; @@ -818,6 +903,8 @@ void WipeTower::toolchange_Unload( } } + writer.disable_linear_advance(); + // now the ramming itself: while (i < m_filpar[m_current_tool].ramming_speed.size()) { @@ -1242,6 +1329,8 @@ void WipeTower::generate(std::vector> & for (auto& used : m_used_filament_length) // reset used filament stats used = 0.f; + m_old_temperature = -1; // reset last temperature written in the gcode + std::vector layer_result; for (auto layer : m_plan) { diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index 0b77664c7..91b828309 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -78,105 +78,11 @@ public: // y -- y coordinates of wipe tower in mm ( left bottom corner ) // width -- width of wipe tower in mm ( default 60 mm - leave as it is ) // wipe_area -- space available for one toolchange in mm - //WipeTower(bool semm, float x, float y, float width, float rotation_angle, float cooling_tube_retraction, - // float cooling_tube_length, float parking_pos_retraction, float extra_loading_move, - // float bridging, bool set_extruder_trimpot, GCodeFlavor flavor, - // const std::vector>& wiping_matrix, unsigned int initial_tool) : - // m_semm(semm), - // m_wipe_tower_pos(x, y), - // m_wipe_tower_width(width), - // m_wipe_tower_rotation_angle(rotation_angle), - // m_y_shift(0.f), - // m_z_pos(0.f), - // m_is_first_layer(false), - // m_gcode_flavor(flavor), - // m_bridging(bridging), - // m_current_tool(initial_tool), - // wipe_volumes(wiping_matrix) - // { - // // If this is a single extruder MM printer, we will use all the SE-specific config values. - // // Otherwise, the defaults will be used to turn off the SE stuff. - // if (m_semm) { - // m_cooling_tube_retraction = cooling_tube_retraction; - // m_cooling_tube_length = cooling_tube_length; - // m_parking_pos_retraction = parking_pos_retraction; - // m_extra_loading_move = extra_loading_move; - // m_set_extruder_trimpot = set_extruder_trimpot; - // } - // } - - WipeTower(PrintConfig &config, const std::vector>& wiping_matrix, unsigned int initial_tool, float first_layer_width) : - m_semm(config.single_extruder_multi_material.value), - m_wipe_tower_pos(float(config.wipe_tower_x.value), float(config.wipe_tower_y.value)), - m_wipe_tower_width(float(config.wipe_tower_width.value)), - m_wipe_tower_rotation_angle(float(config.wipe_tower_rotation_angle.value)), - m_y_shift(0.f), - m_z_pos(0.f), - m_is_first_layer(false), - m_bridging(float(config.wipe_tower_bridging)), - m_gcode_flavor(config.gcode_flavor), - m_current_tool(initial_tool), - wipe_volumes(wiping_matrix), - m_brim_width(first_layer_width), - m_config(&config) - { - // If this is a single extruder MM printer, we will use all the SE-specific config values. - // Otherwise, the defaults will be used to turn off the SE stuff. - if (config.single_extruder_multi_material.value) { - m_cooling_tube_retraction = (float(config.cooling_tube_retraction.value)); - m_cooling_tube_length = (float(config.cooling_tube_length.value)); - m_parking_pos_retraction = (float(config.parking_pos_retraction.value)); - m_extra_loading_move = (float(config.extra_loading_move.value)); - m_set_extruder_trimpot = (config.high_current_on_filament_swap.value); - } - } - + WipeTower(const PrintConfig& config, const std::vector>& wiping_matrix, size_t initial_tool); virtual ~WipeTower() {} // Set the extruder properties. - void set_extruder(size_t idx) - { - //while (m_filpar.size() < idx+1) // makes sure the required element is in the vector - m_filpar.push_back(FilamentParameters()); - - m_filpar[idx].material = m_config->filament_type.get_at(idx); - m_filpar[idx].temperature = (float)m_config->temperature.get_at(idx); - m_filpar[idx].first_layer_temperature = m_config->first_layer_temperature.get_at(idx); - - // If this is a single extruder MM printer, we will use all the SE-specific config values. - // Otherwise, the defaults will be used to turn off the SE stuff. - if (m_semm) { - m_filpar[idx].loading_speed = (float)m_config->filament_loading_speed.get_at(idx); - m_filpar[idx].loading_speed_start = (float)m_config->filament_loading_speed_start.get_at(idx); - m_filpar[idx].unloading_speed = (float)m_config->filament_unloading_speed.get_at(idx); - m_filpar[idx].unloading_speed_start = (float)m_config->filament_unloading_speed_start.get_at(idx); - m_filpar[idx].delay = (float)m_config->filament_toolchange_delay.get_at(idx); - m_filpar[idx].cooling_moves = (float)m_config->filament_cooling_moves.get_at(idx); - m_filpar[idx].cooling_initial_speed = (float)m_config->filament_cooling_initial_speed.get_at(idx); - m_filpar[idx].cooling_final_speed = (float)m_config->filament_cooling_final_speed.get_at(idx); - } - - m_filpar[idx].filament_area = (M_PI/4.f) * pow((float)m_config->filament_diameter.get_at(idx), 2); // all extruders are assumed to have the same filament diameter at this point - m_filpar[idx].nozzle_diameter = (float)m_config->nozzle_diameter.get_at(idx); // to be used in future with (non-single) multiextruder MM - - if ((float)m_config->filament_max_volumetric_speed.get_at(idx) != 0.f) - m_filpar[idx].max_e_speed = ((float)m_config->filament_max_volumetric_speed.get_at(idx) / filament_area()); - - m_perimeter_width = m_filpar[idx].nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter - - if (m_semm) { - std::stringstream stream{ m_config->filament_ramming_parameters.get_at(idx) }; - float speed = 0.f; - stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator; - m_filpar[idx].ramming_line_width_multiplicator /= 100; - m_filpar[idx].ramming_step_multiplicator /= 100; - while (stream >> speed) - m_filpar[idx].ramming_speed.push_back(speed); - } - - m_used_filament_length.resize(std::max(m_used_filament_length.size(), idx + 1)); // makes sure that the vector is big enough so we don't have to check later - } - + void set_extruder(size_t idx, const PrintConfig& config); // Appends into internal structure m_plan containing info about the future wipe tower // to be used before building begins. The entries must be added ordered in z. @@ -285,7 +191,6 @@ private: SHAPE_REVERSED = -1 }; - const bool m_peters_wipe_tower = false; // sparse wipe tower inspired by Peter's post processor - not finished yet const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust const float WT_EPSILON = 1e-3f; @@ -293,7 +198,6 @@ private: return m_filpar[0].filament_area; // all extruders are assumed to have the same filament diameter at this point } - PrintConfig *m_config = NULL; bool m_semm = true; // Are we using a single extruder multimaterial printer? Vec2f m_wipe_tower_pos; // Left front corner of the wipe tower in mm. @@ -318,6 +222,12 @@ private: bool m_adhesion = true; GCodeFlavor m_gcode_flavor; + // Bed properties + enum { + RectangularBed, + CircularBed + } m_bed_shape; + float m_bed_width; // width of the bed bounding box float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill. float m_brim_width = 0.4 * Width_To_Nozzle_Ratio * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill. diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index 33dc9f4b7..00b409344 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -168,10 +168,14 @@ namespace Slic3r { } #endif // ENABLE_MOVE_STATS - const std::string GCodeTimeEstimator::Normal_First_M73_Output_Placeholder_Tag = "; NORMAL_FIRST_M73_OUTPUT_PLACEHOLDER"; - const std::string GCodeTimeEstimator::Silent_First_M73_Output_Placeholder_Tag = "; SILENT_FIRST_M73_OUTPUT_PLACEHOLDER"; - const std::string GCodeTimeEstimator::Normal_Last_M73_Output_Placeholder_Tag = "; NORMAL_LAST_M73_OUTPUT_PLACEHOLDER"; - const std::string GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag = "; SILENT_LAST_M73_OUTPUT_PLACEHOLDER"; + const std::string GCodeTimeEstimator::Normal_First_M73_Output_Placeholder_Tag = "; _TE_NORMAL_FIRST_M73_OUTPUT_PLACEHOLDER"; + const std::string GCodeTimeEstimator::Silent_First_M73_Output_Placeholder_Tag = "; _TE_SILENT_FIRST_M73_OUTPUT_PLACEHOLDER"; + const std::string GCodeTimeEstimator::Normal_Last_M73_Output_Placeholder_Tag = "; _TE_NORMAL_LAST_M73_OUTPUT_PLACEHOLDER"; + const std::string GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag = "; _TE_SILENT_LAST_M73_OUTPUT_PLACEHOLDER"; + + // temporary human readable form to use until not removed from gcode by the new post-process method + const std::string GCodeTimeEstimator::Color_Change_Tag = "PRINT_COLOR_CHANGE"; +// const std::string GCodeTimeEstimator::Color_Change_Tag = "_TE_COLOR_CHANGE"; GCodeTimeEstimator::GCodeTimeEstimator(EMode mode) : m_mode(mode) @@ -390,7 +394,7 @@ namespace Slic3r { fclose(out); in.close(); - if (rename_file(path_tmp, filename) != 0) + if (rename_file(path_tmp, filename)) throw std::runtime_error(std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + filename + '\n' + "Is " + path_tmp + " locked?" + '\n'); @@ -694,22 +698,39 @@ namespace Slic3r { return m_color_times; } - std::vector GCodeTimeEstimator::get_color_times_dhms() const + std::vector GCodeTimeEstimator::get_color_times_dhms(bool include_remaining) const { std::vector ret; + float total_time = 0.0f; for (float t : m_color_times) { - ret.push_back(_get_time_dhms(t)); + std::string time = _get_time_dhms(t); + if (include_remaining) + { + time += " ("; + time += _get_time_dhms(m_time - total_time); + time += ")"; + } + total_time += t; + ret.push_back(time); } return ret; } - std::vector GCodeTimeEstimator::get_color_times_minutes() const + std::vector GCodeTimeEstimator::get_color_times_minutes(bool include_remaining) const { std::vector ret; + float total_time = 0.0f; for (float t : m_color_times) { - ret.push_back(_get_time_minutes(t)); + std::string time = _get_time_minutes(t); + if (include_remaining) + { + time += " ("; + time += _get_time_minutes(m_time - total_time); + time += ")"; + } + total_time += t; } return ret; } @@ -797,6 +818,11 @@ namespace Slic3r { void GCodeTimeEstimator::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line) { PROFILE_FUNC(); + + // processes 'special' comments contained in line + if (_process_tags(line)) + return; + std::string cmd = line.cmd(); if (cmd.length() > 1) { @@ -904,11 +930,6 @@ namespace Slic3r { _processM566(line); break; } - case 600: // Set color change - { - _processM600(line); - break; - } case 702: // MK3 MMU2: Process the final filament unload. { _processM702(line); @@ -1379,18 +1400,6 @@ namespace Slic3r { set_axis_max_jerk(E, line.e() * MMMIN_TO_MMSEC); } - void GCodeTimeEstimator::_processM600(const GCodeReader::GCodeLine& line) - { - PROFILE_FUNC(); - m_needs_color_times = true; - _calculate_time(); - if (m_color_time_cache != 0.0f) - { - m_color_times.push_back(m_color_time_cache); - m_color_time_cache = 0.0f; - } - } - void GCodeTimeEstimator::_processM702(const GCodeReader::GCodeLine& line) { PROFILE_FUNC(); @@ -1422,6 +1431,33 @@ namespace Slic3r { } } + bool GCodeTimeEstimator::_process_tags(const GCodeReader::GCodeLine& line) + { + std::string comment = line.comment(); + + // color change tag + size_t pos = comment.find(Color_Change_Tag); + if (pos != comment.npos) + { + _process_color_change_tag(); + return true; + } + + return false; + } + + void GCodeTimeEstimator::_process_color_change_tag() + { + PROFILE_FUNC(); + m_needs_color_times = true; + _calculate_time(); + if (m_color_time_cache != 0.0f) + { + m_color_times.push_back(m_color_time_cache); + m_color_time_cache = 0.0f; + } + } + void GCodeTimeEstimator::_simulate_st_synchronize() { PROFILE_FUNC(); diff --git a/src/libslic3r/GCodeTimeEstimator.hpp b/src/libslic3r/GCodeTimeEstimator.hpp index 840d58778..dd5d14b57 100644 --- a/src/libslic3r/GCodeTimeEstimator.hpp +++ b/src/libslic3r/GCodeTimeEstimator.hpp @@ -22,6 +22,8 @@ namespace Slic3r { static const std::string Normal_Last_M73_Output_Placeholder_Tag; static const std::string Silent_Last_M73_Output_Placeholder_Tag; + static const std::string Color_Change_Tag; + enum EMode : unsigned char { Normal, @@ -346,14 +348,16 @@ namespace Slic3r { // Returns the estimated time, in minutes (integer) std::string get_time_minutes() const; - // Returns the estimated time, in seconds, for each color + // Returns the estimated time, in seconds, for each color std::vector get_color_times() const; // Returns the estimated time, in format DDd HHh MMm SSs, for each color - std::vector get_color_times_dhms() const; + // If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)" + std::vector get_color_times_dhms(bool include_remaining) const; // Returns the estimated time, in minutes (integer), for each color - std::vector get_color_times_minutes() const; + // If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)" + std::vector get_color_times_minutes(bool include_remaining) const; // Return an estimate of the memory consumed by the time estimator. size_t memory_used() const; @@ -423,15 +427,19 @@ namespace Slic3r { // Set allowable instantaneous speed change void _processM566(const GCodeReader::GCodeLine& line); - // Set color change - void _processM600(const GCodeReader::GCodeLine& line); - // Unload the current filament into the MK3 MMU2 unit at the end of print. void _processM702(const GCodeReader::GCodeLine& line); // Processes T line (Select Tool) void _processT(const GCodeReader::GCodeLine& line); + // Processes the tags + // Returns true if any tag has been processed + bool _process_tags(const GCodeReader::GCodeLine& line); + + // Processes color change tag + void _process_color_change_tag(); + // Simulates firmware st_synchronize() call void _simulate_st_synchronize(); diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index f50b17afe..277be5b32 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -122,6 +122,29 @@ inline bool segment_segment_intersection(const Vec2d &p1, const Vec2d &v1, const return true; } + +inline int segments_could_intersect( + const Slic3r::Point &ip1, const Slic3r::Point &ip2, + const Slic3r::Point &jp1, const Slic3r::Point &jp2) +{ + Vec2i64 iv = (ip2 - ip1).cast(); + Vec2i64 vij1 = (jp1 - ip1).cast(); + Vec2i64 vij2 = (jp2 - ip1).cast(); + int64_t tij1 = cross2(iv, vij1); + int64_t tij2 = cross2(iv, vij2); + int sij1 = (tij1 > 0) ? 1 : ((tij1 < 0) ? -1 : 0); // signum + int sij2 = (tij2 > 0) ? 1 : ((tij2 < 0) ? -1 : 0); + return sij1 * sij2; +} + +inline bool segments_intersect( + const Slic3r::Point &ip1, const Slic3r::Point &ip2, + const Slic3r::Point &jp1, const Slic3r::Point &jp2) +{ + return segments_could_intersect(ip1, ip2, jp1, jp2) <= 0 && + segments_could_intersect(jp1, jp2, ip1, ip2) <= 0; +} + Pointf3s convex_hull(Pointf3s points); Polygon convex_hull(Points points); Polygon convex_hull(const Polygons &polygons); diff --git a/src/libslic3r/MinAreaBoundingBox.cpp b/src/libslic3r/MinAreaBoundingBox.cpp index fafb54a58..15c04517d 100644 --- a/src/libslic3r/MinAreaBoundingBox.cpp +++ b/src/libslic3r/MinAreaBoundingBox.cpp @@ -1,6 +1,11 @@ #include "MinAreaBoundingBox.hpp" #include + +#if defined(_MSC_VER) && defined(__clang__) +#define BOOST_NO_CXX17_HDR_STRING_VIEW +#endif + #include #include diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 3d663fde0..b2f926bdf 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -21,8 +21,6 @@ namespace Slic3r { -unsigned int Model::s_auto_extruder_id = 1; - Model& Model::assign_copy(const Model &rhs) { this->copy_id(rhs); @@ -86,7 +84,7 @@ void Model::update_links_bottom_up_recursive() } } -Model Model::read_from_file(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances) +Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* config, bool add_default_instances, bool check_version) { Model model; @@ -99,11 +97,10 @@ Model Model::read_from_file(const std::string &input_file, DynamicPrintConfig *c result = load_stl(input_file.c_str(), &model); else if (boost::algorithm::iends_with(input_file, ".obj")) result = load_obj(input_file.c_str(), &model); - else if (!boost::algorithm::iends_with(input_file, ".zip.amf") && (boost::algorithm::iends_with(input_file, ".amf") || - boost::algorithm::iends_with(input_file, ".amf.xml"))) - result = load_amf(input_file.c_str(), config, &model); + else if (boost::algorithm::iends_with(input_file, ".amf") || boost::algorithm::iends_with(input_file, ".amf.xml")) + result = load_amf(input_file.c_str(), config, &model, check_version); else if (boost::algorithm::iends_with(input_file, ".3mf")) - result = load_3mf(input_file.c_str(), config, &model); + result = load_3mf(input_file.c_str(), config, &model, false); else if (boost::algorithm::iends_with(input_file, ".prusa")) result = load_prus(input_file.c_str(), &model); else @@ -124,15 +121,15 @@ Model Model::read_from_file(const std::string &input_file, DynamicPrintConfig *c return model; } -Model Model::read_from_archive(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances) +Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig* config, bool add_default_instances, bool check_version) { Model model; bool result = false; if (boost::algorithm::iends_with(input_file, ".3mf")) - result = load_3mf(input_file.c_str(), config, &model); + result = load_3mf(input_file.c_str(), config, &model, check_version); else if (boost::algorithm::iends_with(input_file, ".zip.amf")) - result = load_amf(input_file.c_str(), config, &model); + result = load_amf(input_file.c_str(), config, &model, check_version); else throw std::runtime_error("Unknown file format. Input file must have .3mf or .zip.amf extension."); @@ -486,9 +483,20 @@ bool Model::looks_like_multipart_object() const return false; } +// Generate next extruder ID string, in the range of (1, max_extruders). +static inline std::string auto_extruder_id(unsigned int max_extruders, unsigned int &cntr) +{ + char str_extruder[64]; + sprintf(str_extruder, "%ud", cntr + 1); + if (++ cntr == max_extruders) + cntr = 0; + return str_extruder; +} + void Model::convert_multipart_object(unsigned int max_extruders) { - if (this->objects.empty()) + assert(this->objects.size() >= 2); + if (this->objects.size() < 2) return; ModelObject* object = new ModelObject(this); @@ -496,60 +504,33 @@ void Model::convert_multipart_object(unsigned int max_extruders) object->name = this->objects.front()->name; //FIXME copy the config etc? - reset_auto_extruder_id(); - - //supermerill: note: the new codepath indroduced in fab363493140a93c1786c7898424a73dd1ed2a2e - // doesn't work for my fork for a reason, deactivating it for now. - bool is_single_object = true; // (this->objects.size() == 1); - + unsigned int extruder_counter = 0; for (const ModelObject* o : this->objects) - { - for (const ModelVolume* v : o->volumes) - { - if (is_single_object) - { - // If there is only one object, just copy the volumes - ModelVolume* new_v = object->add_volume(*v); - if (new_v != nullptr) - { - new_v->name = o->name; - new_v->config.set_deserialize("extruder", get_auto_extruder_id_as_string(max_extruders)); - new_v->translate(-o->origin_translation); - } - } - else - { + for (const ModelVolume* v : o->volumes) { // If there are more than one object, put all volumes together // Each object may contain any number of volumes and instances // The volumes transformations are relative to the object containing them... + Geometry::Transformation trafo_volume = v->get_transformation(); + // Revert the centering operation. + trafo_volume.set_offset(trafo_volume.get_offset() - o->origin_translation); int counter = 1; + auto copy_volume = [o, max_extruders, &counter, &extruder_counter](ModelVolume *new_v) { + assert(new_v != nullptr); + new_v->name = o->name + "_" + std::to_string(counter++); + new_v->config.set_deserialize("extruder", auto_extruder_id(max_extruders, extruder_counter)); + return new_v; + }; + if (o->instances.empty()) { + copy_volume(object->add_volume(*v))->set_transformation(trafo_volume); + } else { for (const ModelInstance* i : o->instances) - { - ModelVolume* new_v = object->add_volume(*v); - if (new_v != nullptr) - { - new_v->name = o->name + "_" + std::to_string(counter++); - new_v->config.set_deserialize("extruder", get_auto_extruder_id_as_string(max_extruders)); - new_v->translate(-o->origin_translation); // ...so, transform everything to a common reference system (world) - new_v->set_transformation(i->get_transformation() * v->get_transformation()); + copy_volume(object->add_volume(*v))->set_transformation(i->get_transformation() * trafo_volume); } } - } - } - } - if (is_single_object) - { - // If there is only one object, keep its instances - for (const ModelInstance* i : this->objects.front()->instances) - { - object->add_instance(*i); - } - } - else - // If there are more than one object, create a single instance object->add_instance(); + object->instances[0]->set_offset(object->raw_mesh_bounding_box().center()); this->clear_objects(); this->objects.push_back(object); @@ -574,32 +555,6 @@ void Model::adjust_min_z() } } -unsigned int Model::get_auto_extruder_id(unsigned int max_extruders) -{ - unsigned int id = s_auto_extruder_id; - if (id > max_extruders) { - // The current counter is invalid, likely due to switching the printer profiles - // to a profile with a lower number of extruders. - reset_auto_extruder_id(); - id = s_auto_extruder_id; - } else if (++ s_auto_extruder_id > max_extruders) { - reset_auto_extruder_id(); - } - return id; -} - -std::string Model::get_auto_extruder_id_as_string(unsigned int max_extruders) -{ - char str_extruder[64]; - sprintf(str_extruder, "%ud", get_auto_extruder_id(max_extruders)); - return str_extruder; -} - -void Model::reset_auto_extruder_id() -{ - s_auto_extruder_id = 1; -} - // Propose a filename including path derived from the ModelObject's input path. // If object's name is filled in, use the object name, otherwise use the input name. std::string Model::propose_export_file_name_and_path() const @@ -646,6 +601,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs) this->sla_points_status = rhs.sla_points_status; this->layer_config_ranges = rhs.layer_config_ranges; // #ys_FIXME_experiment this->layer_height_profile = rhs.layer_height_profile; + this->printable = rhs.printable; this->origin_translation = rhs.origin_translation; m_bounding_box = rhs.m_bounding_box; m_bounding_box_valid = rhs.m_bounding_box_valid; @@ -1664,7 +1620,7 @@ size_t ModelVolume::split(unsigned int max_extruders) size_t ivolume = std::find(this->object->volumes.begin(), this->object->volumes.end(), this) - this->object->volumes.begin(); std::string name = this->name; - Model::reset_auto_extruder_id(); + unsigned int extruder_counter = 0; Vec3d offset = this->get_offset(); for (TriangleMesh *mesh : meshptrs) { @@ -1683,7 +1639,7 @@ size_t ModelVolume::split(unsigned int max_extruders) this->object->volumes[ivolume]->center_geometry_after_creation(); this->object->volumes[ivolume]->translate(offset); this->object->volumes[ivolume]->name = name + "_" + std::to_string(idx + 1); - this->object->volumes[ivolume]->config.set_deserialize("extruder", Model::get_auto_extruder_id_as_string(max_extruders)); + this->object->volumes[ivolume]->config.set_deserialize("extruder", auto_extruder_id(max_extruders, extruder_counter)); delete mesh; ++ idx; } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index e644689ef..341ff4a93 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -192,6 +192,8 @@ public: // Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers. // The pairs of are packed into a 1D array. std::vector layer_height_profile; + // Whether or not this object is printable + bool printable; // This vector holds position of selected support points for SLA. The data are // saved in mesh coordinates to allow using them for several instances. @@ -304,11 +306,11 @@ public: private: friend class Model; // This constructor assigns new ID to this ModelObject and its config. - explicit ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()), + explicit ModelObject(Model* model) : m_model(model), printable(true), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) - { assert(this->id().valid()); } - explicit ModelObject(int) : ObjectBase(-1), config(-1), m_model(nullptr), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) - { assert(this->id().invalid()); assert(this->config.id().invalid()); } + { assert(this->id().valid()); } + explicit ModelObject(int) : ObjectBase(-1), config(-1), m_model(nullptr), printable(true), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) + { assert(this->id().invalid()); assert(this->config.id().invalid()); } ~ModelObject(); void assign_new_unique_ids_recursive() override; @@ -370,8 +372,8 @@ private: template void serialize(Archive &ar) { ar(cereal::base_class(this)); Internal::StaticSerializationWrapper config_wrapper(config); - ar(name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_height_profile, sla_support_points, sla_points_status, origin_translation, - m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid); + ar(name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_height_profile, sla_support_points, sla_points_status, printable, origin_translation, + m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid); } }; @@ -595,6 +597,8 @@ private: public: // flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state()) EPrintVolumeState print_volume_state; + // Whether or not this instance is printable + bool printable; ModelObject* get_object() const { return this->object; } @@ -639,8 +643,8 @@ public: const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); } - bool is_printable() const { return print_volume_state == PVS_Inside; } - + bool is_printable() const { return object->printable && printable && (print_volume_state == PVS_Inside); } + // Getting the input polygon for arrange arrangement::ArrangePolygon get_arrange_polygon() const; @@ -667,10 +671,10 @@ private: ModelObject* object; // Constructor, which assigns a new unique ID. - explicit ModelInstance(ModelObject *object) : print_volume_state(PVS_Inside), object(object) { assert(this->id().valid()); } + explicit ModelInstance(ModelObject* object) : print_volume_state(PVS_Inside), printable(true), object(object) { assert(this->id().valid()); } // Constructor, which assigns a new unique ID. explicit ModelInstance(ModelObject *object, const ModelInstance &other) : - m_transformation(other.m_transformation), print_volume_state(PVS_Inside), object(object) { assert(this->id().valid() && this->id() != other.id()); } + m_transformation(other.m_transformation), print_volume_state(PVS_Inside), printable(true), object(object) {assert(this->id().valid() && this->id() != other.id());} explicit ModelInstance(ModelInstance &&rhs) = delete; ModelInstance& operator=(const ModelInstance &rhs) = delete; @@ -681,8 +685,8 @@ private: // Used for deserialization, therefore no IDs are allocated. ModelInstance() : ObjectBase(-1), object(nullptr) { assert(this->id().invalid()); } template void serialize(Archive &ar) { - ar(m_transformation, print_volume_state); - } + ar(m_transformation, print_volume_state, printable); + } }; class ModelWipeTower final : public ObjectBase @@ -721,8 +725,6 @@ private: // all objects may share mutliple materials. class Model final : public ObjectBase { - static unsigned int s_auto_extruder_id; - public: // Materials are owned by a model and referenced by objects through t_model_material_id. // Single material may be shared by multiple models. @@ -745,8 +747,8 @@ public: OBJECTBASE_DERIVED_COPY_MOVE_CLONE(Model) - static Model read_from_file(const std::string &input_file, DynamicPrintConfig *config = nullptr, bool add_default_instances = true); - static Model read_from_archive(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances = true); + static Model read_from_file(const std::string& input_file, DynamicPrintConfig* config = nullptr, bool add_default_instances = true, bool check_version = false); + static Model read_from_archive(const std::string& input_file, DynamicPrintConfig* config, bool add_default_instances = true, bool check_version = false); // Add a new ModelObject to this Model, generate a new ID for this ModelObject. ModelObject* add_object(); @@ -791,14 +793,10 @@ public: void print_info() const { for (const ModelObject *o : this->objects) o->print_info(); } - static unsigned int get_auto_extruder_id(unsigned int max_extruders); - static std::string get_auto_extruder_id_as_string(unsigned int max_extruders); - static void reset_auto_extruder_id(); - // Propose an output file name & path based on the first printable object's name and source input file's path. - std::string propose_export_file_name_and_path() const; + std::string propose_export_file_name_and_path() const; // Propose an output path, replace extension. The new_extension shall contain the initial dot. - std::string propose_export_file_name_and_path(const std::string &new_extension) const; + std::string propose_export_file_name_and_path(const std::string &new_extension) const; private: explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); }; diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index c3ac22e96..530d84907 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -175,6 +175,11 @@ void PlaceholderParser::apply_env_variables() } namespace spirit = boost::spirit; +// Using an encoding, which accepts unsigned chars. +// Don't use boost::spirit::ascii, as it crashes internally due to indexing with negative char values for UTF8 characters into some 7bit character classification tables. +//namespace spirit_encoding = boost::spirit::ascii; +//FIXME iso8859_1 is just a workaround for the problem above. Replace it with UTF8 support! +namespace spirit_encoding = boost::spirit::iso8859_1; namespace qi = boost::spirit::qi; namespace px = boost::phoenix; @@ -931,7 +936,7 @@ namespace client /////////////////////////////////////////////////////////////////////////// // Inspired by the C grammar rules https://www.lysator.liu.se/c/ANSI-C-grammar-y.html template - struct macro_processor : qi::grammar, spirit::ascii::space_type> + struct macro_processor : qi::grammar, spirit_encoding::space_type> { macro_processor() : macro_processor::base_type(start) { @@ -944,12 +949,12 @@ namespace client qi::lexeme_type lexeme; qi::no_skip_type no_skip; qi::real_parser strict_double; - spirit::ascii::char_type char_; + spirit_encoding::char_type char_; utf8_char_skipper_parser utf8char; spirit::bool_type bool_; spirit::int_type int_; spirit::double_type double_; - spirit::ascii::string_type string; + spirit_encoding::string_type string; spirit::eoi_type eoi; spirit::repository::qi::iter_pos_type iter_pos; auto kw = spirit::repository::qi::distinct(qi::copy(alnum | '_')); @@ -1178,20 +1183,20 @@ namespace client } // Generic expression over expr. - typedef qi::rule(const MyContext*), spirit::ascii::space_type> RuleExpression; + typedef qi::rule(const MyContext*), spirit_encoding::space_type> RuleExpression; // The start of the grammar. - qi::rule, spirit::ascii::space_type> start; + qi::rule, spirit_encoding::space_type> start; // A free-form text. - qi::rule text; + qi::rule text; // A free-form text, possibly empty, possibly containing macro expansions. - qi::rule text_block; + qi::rule text_block; // Statements enclosed in curely braces {} - qi::rule macro; + qi::rule macro; // Legacy variable expansion of the original Slic3r, in the form of [scalar_variable] or [vector_variable_index]. - qi::rule legacy_variable_expansion; + qi::rule legacy_variable_expansion; // Parsed identifier name. - qi::rule(), spirit::ascii::space_type> identifier; + qi::rule(), spirit_encoding::space_type> identifier; // Ternary operator (?:) over logical_or_expression. RuleExpression conditional_expression; // Logical or over logical_and_expressions. @@ -1209,16 +1214,16 @@ namespace client // Number literals, functions, braced expressions, variable references, variable indexing references. RuleExpression unary_expression; // Rule to capture a regular expression enclosed in //. - qi::rule(), spirit::ascii::space_type> regular_expression; + qi::rule(), spirit_encoding::space_type> regular_expression; // Evaluate boolean expression into bool. - qi::rule bool_expr_eval; + qi::rule bool_expr_eval; // Reference of a scalar variable, or reference to a field of a vector variable. - qi::rule(const MyContext*), qi::locals, int>, spirit::ascii::space_type> scalar_variable_reference; + qi::rule(const MyContext*), qi::locals, int>, spirit_encoding::space_type> scalar_variable_reference; // Rule to translate an identifier to a ConfigOption, or to fail. - qi::rule(const MyContext*), spirit::ascii::space_type> variable_reference; + qi::rule(const MyContext*), spirit_encoding::space_type> variable_reference; - qi::rule, spirit::ascii::space_type> if_else_output; -// qi::rule, bool, std::string>, spirit::ascii::space_type> switch_output; + qi::rule, spirit_encoding::space_type> if_else_output; +// qi::rule, bool, std::string>, spirit_encoding::space_type> switch_output; qi::symbols keywords; }; @@ -1230,7 +1235,7 @@ static std::string process_macro(const std::string &templ, client::MyContext &co typedef client::macro_processor macro_processor; // Our whitespace skipper. - spirit::ascii::space_type space; + spirit_encoding::space_type space; // Our grammar, statically allocated inside the method, meaning it will be allocated the first time // PlaceholderParser::process() runs. //FIXME this kind of initialization is not thread safe! diff --git a/src/libslic3r/PolygonTrimmer.cpp b/src/libslic3r/PolygonTrimmer.cpp new file mode 100644 index 000000000..3e3c9b498 --- /dev/null +++ b/src/libslic3r/PolygonTrimmer.cpp @@ -0,0 +1,56 @@ +#include "PolygonTrimmer.hpp" +#include "EdgeGrid.hpp" +#include "Geometry.hpp" + +namespace Slic3r { + +TrimmedLoop trim_loop(const Polygon &loop, const EdgeGrid::Grid &grid) +{ + assert(! loop.empty()); + assert(loop.size() >= 2); + + TrimmedLoop out; + + if (loop.size() >= 2) { + size_t cnt = loop.points.size(); + + struct Visitor { + Visitor(const EdgeGrid::Grid &grid, const Slic3r::Point *pt_prev, const Slic3r::Point *pt_this) : grid(grid), pt_prev(pt_prev), pt_this(pt_this) {} + + void operator()(coord_t iy, coord_t ix) { + // Called with a row and colum of the grid cell, which is intersected by a line. + auto cell_data_range = grid.cell_data_range(iy, ix); + for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++ it_contour_and_segment) { + // End points of the line segment and their vector. + auto segment = grid.segment(*it_contour_and_segment); + if (Geometry::segments_intersect(segment.first, segment.second, *pt_prev, *pt_this)) { + // The two segments intersect. Add them to the output. + } + } + } + + const EdgeGrid::Grid &grid; + const Slic3r::Point *pt_this; + const Slic3r::Point *pt_prev; + } visitor(grid, &loop.points.back(), nullptr); + + for (const Point &pt_this : loop.points) { + visitor.pt_this = &pt_this; + grid.visit_cells_intersecting_line(*visitor.pt_prev, pt_this, visitor); + visitor.pt_prev = &pt_this; + } + } + + return out; +} + +std::vector trim_loops(const Polygons &loops, const EdgeGrid::Grid &grid) +{ + std::vector out; + out.reserve(loops.size()); + for (const Polygon &loop : loops) + out.emplace_back(trim_loop(loop, grid)); + return out; +} + +} diff --git a/src/libslic3r/PolygonTrimmer.hpp b/src/libslic3r/PolygonTrimmer.hpp new file mode 100644 index 000000000..eddffbc7f --- /dev/null +++ b/src/libslic3r/PolygonTrimmer.hpp @@ -0,0 +1,32 @@ +#ifndef slic3r_PolygonTrimmer_hpp_ +#define slic3r_PolygonTrimmer_hpp_ + +#include "libslic3r.h" +#include +#include +#include "Line.hpp" +#include "MultiPoint.hpp" +#include "Polyline.hpp" +#include "Polygon.hpp" + +namespace Slic3r { + +namespace EdgeGrid { + class Grid; +} + +struct TrimmedLoop +{ + std::vector points; + // Number of points per segment. Empty if the loop is + std::vector segments; + + bool is_trimmed() const { return ! segments.empty(); } +}; + +TrimmedLoop trim_loop(const Polygon &loop, const EdgeGrid::Grid &grid); +std::vector trim_loops(const Polygons &loops, const EdgeGrid::Grid &grid); + +} // namespace Slic3r + +#endif /* slic3r_PolygonTrimmer_hpp_ */ diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index cb25e714d..2736bfb86 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include //! macro used to mark string used at localization, @@ -270,8 +271,14 @@ std::vector Print::object_extruders() const { std::vector extruders; extruders.reserve(m_regions.size() * 3); - for (const PrintRegion *region : m_regions) - region->collect_object_printing_extruders(extruders); + std::vector region_used(m_regions.size(), false); + for (const PrintObject *object : m_objects) + for (const std::vector> &volumes_per_region : object->region_volumes) + if (! volumes_per_region.empty()) + region_used[&volumes_per_region - &object->region_volumes.front()] = true; + for (size_t idx_region = 0; idx_region < m_regions.size(); ++ idx_region) + if (region_used[idx_region]) + m_regions[idx_region]->collect_object_printing_extruders(extruders); sort_remove_duplicates(extruders); return extruders; } @@ -281,19 +288,26 @@ std::vector Print::support_material_extruders() const { std::vector extruders; bool support_uses_current_extruder = false; + auto num_extruders = (unsigned int)m_config.nozzle_diameter.size(); for (PrintObject *object : m_objects) { if (object->has_support_material()) { + assert(object->config().support_material_extruder >= 0); if (object->config().support_material_extruder == 0) support_uses_current_extruder = true; - else - extruders.push_back(object->config().support_material_extruder - 1); + else { + unsigned int i = (unsigned int)object->config().support_material_extruder - 1; + extruders.emplace_back((i >= num_extruders) ? 0 : i); + } + assert(object->config().support_material_interface_extruder >= 0); if (object->config().support_material_interface_extruder == 0) support_uses_current_extruder = true; - else - extruders.push_back(object->config().support_material_interface_extruder - 1); + else { + unsigned int i = (unsigned int)object->config().support_material_interface_extruder - 1; + extruders.emplace_back((i >= num_extruders) ? 0 : i); } } + } if (support_uses_current_extruder) // Add all object extruders to the support extruders as it is not know which one will be used to print supports. @@ -585,6 +599,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // Apply variables to placeholder parser. The placeholder parser is used by G-code export, // which should be stopped if print_diff is not empty. + size_t num_extruders = m_config.nozzle_diameter.size(); + bool num_extruders_changed = false; if (! full_config_diff.empty() || ! placeholder_parser_overrides.empty()) { update_apply_status(this->invalidate_step(psGCodeExport)); m_placeholder_parser.apply_config(std::move(placeholder_parser_overrides)); @@ -600,6 +616,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // Handle changes to regions config defaults m_default_region_config.apply_only(new_full_config, region_diff, true); m_full_print_config = std::move(new_full_config); + if (num_extruders != m_config.nozzle_diameter.size()) { + num_extruders = m_config.nozzle_diameter.size(); + num_extruders_changed = true; + } } class LayerRanges @@ -776,7 +796,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ print_object_status.emplace(PrintObjectStatus(print_object)); // 3) Synchronize ModelObjects & PrintObjects. - size_t num_extruders = m_config.nozzle_diameter.size(); for (size_t idx_model_object = 0; idx_model_object < model.objects.size(); ++ idx_model_object) { ModelObject &model_object = *m_model.objects[idx_model_object]; auto it_status = model_object_status.find(ModelObjectStatus(model_object.id())); @@ -823,7 +842,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ bool object_config_changed = model_object.config != model_object_new.config; if (object_config_changed) static_cast(model_object.config) = static_cast(model_object_new.config); - if (! object_diff.empty() || object_config_changed) { + if (! object_diff.empty() || object_config_changed || num_extruders_changed) { PrintObjectConfig new_config = PrintObject::object_config_from_model_object(m_default_object_config, model_object, num_extruders); auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); for (auto it = range.first; it != range.second; ++ it) { @@ -1152,16 +1171,27 @@ std::string Print::validate() const // #4043 if (total_copies_count > 1 && ! m_config.complete_objects.value) return L("The Spiral Vase option can only be used when printing a single object."); - if (m_regions.size() > 1) + assert(m_objects.size() == 1); + size_t num_regions = 0; + for (const std::vector> &volumes_per_region : m_objects.front()->region_volumes) + if (! volumes_per_region.empty()) + ++ num_regions; + if (num_regions > 1) return L("The Spiral Vase option can only be used when printing single material objects."); } if (this->has_wipe_tower() && ! m_objects.empty()) { - // make sure all extruders use same diameter filament and have the same nozzle diameter + // Make sure all extruders use same diameter filament and have the same nozzle diameter + // EPSILON comparison is used for nozzles and 10 % tolerance is used for filaments + double first_nozzle_diam = m_config.nozzle_diameter.get_at(extruders().front()); + double first_filament_diam = m_config.filament_diameter.get_at(extruders().front()); for (const auto& extruder_idx : extruders()) { - if (m_config.nozzle_diameter.get_at(extruder_idx) != m_config.nozzle_diameter.get_at(extruders().front()) - || m_config.filament_diameter.get_at(extruder_idx) != m_config.filament_diameter.get_at(extruders().front())) - return L("The wipe tower is only supported if all extruders have the same nozzle diameter and use filaments of the same diameter."); + double nozzle_diam = m_config.nozzle_diameter.get_at(extruder_idx); + double filament_diam = m_config.filament_diameter.get_at(extruder_idx); + if (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam + || std::abs((filament_diam-first_filament_diam)/first_filament_diam) > 0.1) + return L("The wipe tower is only supported if all extruders have the same nozzle diameter " + "and use filaments of the same diameter."); } if (m_config.gcode_flavor != gcfRepRap && m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlin) @@ -1169,15 +1199,11 @@ std::string Print::validate() const if (! m_config.use_relative_e_distances) return L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)."); - for (size_t i=1; i 1) { bool has_custom_layering = false; std::vector> layer_height_profiles; for (const PrintObject *object : m_objects) { - has_custom_layering = ! object->model_object()->layer_config_ranges.empty() || ! object->model_object()->layer_height_profile.empty(); // #ys_FIXME_experiment + has_custom_layering = ! object->model_object()->layer_config_ranges.empty() || ! object->model_object()->layer_height_profile.empty(); if (has_custom_layering) { layer_height_profiles.assign(m_objects.size(), std::vector()); break; @@ -1258,6 +1284,20 @@ std::string Print::validate() const return L("One or more object were assigned an extruder that the printer does not have."); #endif + auto validate_extrusion_width = [min_nozzle_diameter, max_nozzle_diameter](const ConfigBase &config, const char *opt_key, double layer_height, std::string &err_msg) -> bool { + double extrusion_width_min = config.get_abs_value(opt_key, min_nozzle_diameter); + double extrusion_width_max = config.get_abs_value(opt_key, max_nozzle_diameter); + if (extrusion_width_min == 0) { + // Default "auto-generated" extrusion width is always valid. + } else if (extrusion_width_min <= layer_height) { + err_msg = (boost::format(L("%1%=%2% mm is too low to be printable at a layer height %3% mm")) % opt_key % extrusion_width_min % layer_height).str(); + return false; + } else if (extrusion_width_max >= max_nozzle_diameter * 3.) { + err_msg = (boost::format(L("Excessive %1%=%2% mm to be printable with a nozzle diameter %3% mm")) % opt_key % extrusion_width_max % max_nozzle_diameter).str(); + return false; + } + return true; + }; for (PrintObject *object : m_objects) { if (object->config().raft_layers > 0 || object->config().support_material.value) { if ((object->config().support_material_extruder == 0 || object->config().support_material_interface_extruder == 0) && max_nozzle_diameter - min_nozzle_diameter > EPSILON) { @@ -1301,8 +1341,20 @@ std::string Print::validate() const return L("First layer height can't be greater than nozzle diameter"); // validate layer_height - if (object->config().layer_height.value > min_nozzle_diameter) + double layer_height = object->config().layer_height.value; + if (layer_height > min_nozzle_diameter) return L("Layer height can't be greater than nozzle diameter"); + + // Validate extrusion widths. + std::string err_msg; + if (! validate_extrusion_width(object->config(), "extrusion_width", layer_height, err_msg)) + return err_msg; + if ((object->config().support_material || object->config().raft_layers > 0) && ! validate_extrusion_width(object->config(), "support_material_extrusion_width", layer_height, err_msg)) + return err_msg; + for (const char *opt_key : { "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width" }) + for (size_t i = 0; i < object->region_volumes.size(); ++ i) + if (! object->region_volumes[i].empty() && ! validate_extrusion_width(this->get_region(i)->config(), opt_key, layer_height, err_msg)) + return err_msg; } } @@ -1912,7 +1964,7 @@ void Print::_make_wipe_tower() break; lt.has_support = true; // Insert the new support layer. - double height = lt.print_z - m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z; + double height = lt.print_z - (i == 0 ? 0. : m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z); //FIXME the support layer ID is set to -1, as Vojtech hopes it is not being used anyway. it_layer = m_objects.front()->insert_support_layer(it_layer, -1, height, lt.print_z, lt.print_z - 0.5 * height); ++ it_layer; @@ -1922,16 +1974,7 @@ void Print::_make_wipe_tower() this->throw_if_canceled(); // Initialize the wipe tower. - WipeTower wipe_tower(m_config - //m_config.single_extruder_multi_material.value, - //float(m_config.wipe_tower_x.value), float(m_config.wipe_tower_y.value), - //float(m_config.wipe_tower_width.value), - //float(m_config.wipe_tower_rotation_angle.value), float(m_config.cooling_tube_retraction.value), - //float(m_config.cooling_tube_length.value), float(m_config.parking_pos_retraction.value), - //float(m_config.extra_loading_move.value), float(m_config.wipe_tower_bridging), - //m_config.high_current_on_filament_swap.value - , wipe_volumes, - m_wipe_tower_data.tool_ordering.first_extruder(), this->brim_flow().width); + WipeTower wipe_tower(m_config, wipe_volumes, m_wipe_tower_data.tool_ordering.first_extruder()); //wipe_tower.set_retract(); @@ -1939,7 +1982,9 @@ void Print::_make_wipe_tower() // Set the extruder & material properties at the wipe tower object. for (size_t i = 0; i < number_of_extruders; ++i) - wipe_tower.set_extruder(i); + + wipe_tower.set_extruder(i, m_config); + m_wipe_tower_data.priming = Slic3r::make_unique>( wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false)); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 33913b111..9ab2ede1f 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -12,7 +12,7 @@ namespace Slic3r { -//! macro used to mark string used at localization, +//! macro used to mark string used at localization, //! return same string #define L(s) (s) #define _(s) Slic3r::I18N::translate(s) @@ -27,7 +27,7 @@ static void assign_printer_technology_to_unknown(t_optiondef_map &options, Print PrintConfigDef::PrintConfigDef() { this->init_common_params(); - //assign params that are not already allocated to FFF+SLA (default from slic3rPE) + //assign params that are not already allocated to FFF+SLA (default from slic3rPE) assign_printer_technology_to_unknown(this->options, ptFFF | ptSLA); this->init_fff_params(); this->init_extruder_retract_keys(); @@ -52,7 +52,7 @@ void PrintConfigDef::init_common_params() def->label = L("Bed shape"); def->mode = comAdvanced; def->set_default_value(new ConfigOptionPoints{ Vec2d(0, 0), Vec2d(200, 0), Vec2d(200, 200), Vec2d(0, 200) }); - + def = this->add("bed_custom_texture", coString); def->label = L("Bed custom texture"); def->mode = comAdvanced; @@ -87,8 +87,8 @@ void PrintConfigDef::init_common_params() "The gap closing operation may reduce the final print resolution, therefore it is advisable to keep the value reasonably low."); def->sidetext = L("mm"); def->min = 0; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.049)); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.049)); def = this->add("print_host", coString); def->label = L("Hostname, IP or URL"); @@ -103,7 +103,7 @@ void PrintConfigDef::init_common_params() "the API Key or the password required for authentication."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionString("")); - + def = this->add("printhost_cafile", coString); def->label = L("HTTPS CA File"); def->tooltip = L("Custom CA certificate file can be specified for HTTPS OctoPrint connections, in crt/pem format. " @@ -216,7 +216,7 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->max = 2; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(1)); + def->set_default_value(new ConfigOptionFloat(1)); def = this->add("over_bridge_flow_ratio", coFloat); def->label = L("Above the bridges"); @@ -484,6 +484,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Fill pattern for bottom infill. This only affects the bottom visible layer, and not its adjacent solid shells."); def->cli = "bottom-fill-pattern|external-fill-pattern=s"; def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("rectilinear"); def->enum_values.push_back("rectilineargapfill"); def->enum_values.push_back("concentric"); @@ -703,7 +704,7 @@ void PrintConfigDef::init_fff_params() "check filament diameter and your firmware E steps."); def->mode = comSimple; def->set_default_value(new ConfigOptionFloats { 1. }); - + def = this->add("extrusion_width", coFloatOrPercent); def->label = L("Default extrusion width"); def->category = L("Extrusion Width"); @@ -861,7 +862,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("This string is edited by RammingDialog and contains ramming specific parameters."); def->mode = comExpert; def->set_default_value(new ConfigOptionStrings { "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0|" - " 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" }); + " 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" }); def = this->add("filament_unload_time", coFloats); def->label = L("Filament unload time"); @@ -938,7 +939,7 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("money/kg"); def->min = 0; def->set_default_value(new ConfigOptionFloats { 0. }); - + def = this->add("filament_settings_id", coStrings); def->set_default_value(new ConfigOptionStrings { "" }); def->cli = ConfigOptionDef::nocli; @@ -1375,7 +1376,7 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionBool(false)); - def = this->add("silent_mode", coBool); + def = this->add("silent_mode", coBool); def->label = L("Supports stealth mode"); def->category = L("Firmware"); def->tooltip = L("The firmware supports stealth mode"); @@ -1391,79 +1392,79 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0)); - const int machine_limits_opt_width = 70; - { - struct AxisDefault { - std::string name; - std::vector max_feedrate; - std::vector max_acceleration; - std::vector max_jerk; - }; - std::vector axes { - // name, max_feedrate, max_acceleration, max_jerk - { "x", { 500., 200. }, { 9000., 1000. }, { 10. , 10. } }, - { "y", { 500., 200. }, { 9000., 1000. }, { 10. , 10. } }, - { "z", { 12., 12. }, { 500., 200. }, { 0.2, 0.4 } }, - { "e", { 120., 120. }, { 10000., 5000. }, { 2.5, 2.5 } } - }; - for (const AxisDefault &axis : axes) { - std::string axis_upper = boost::to_upper_copy(axis.name); - // Add the machine feedrate limits for XYZE axes. (M203) - def = this->add("machine_max_feedrate_" + axis.name, coFloats); - def->full_label = (boost::format("Maximum feedrate %1%") % axis_upper).str(); - (void)L("Maximum feedrate X"); - (void)L("Maximum feedrate Y"); - (void)L("Maximum feedrate Z"); - (void)L("Maximum feedrate E"); - def->category = L("Machine limits"); - def->tooltip = (boost::format("Maximum feedrate of the %1% axis") % axis_upper).str(); - (void)L("Maximum feedrate of the X axis"); - (void)L("Maximum feedrate of the Y axis"); - (void)L("Maximum feedrate of the Z axis"); - (void)L("Maximum feedrate of the E axis"); - def->sidetext = L("mm/s"); - def->min = 0; - def->width = machine_limits_opt_width; + const int machine_limits_opt_width = 70; + { + struct AxisDefault { + std::string name; + std::vector max_feedrate; + std::vector max_acceleration; + std::vector max_jerk; + }; + std::vector axes { + // name, max_feedrate, max_acceleration, max_jerk + { "x", { 500., 200. }, { 9000., 1000. }, { 10. , 10. } }, + { "y", { 500., 200. }, { 9000., 1000. }, { 10. , 10. } }, + { "z", { 12., 12. }, { 500., 200. }, { 0.2, 0.4 } }, + { "e", { 120., 120. }, { 10000., 5000. }, { 2.5, 2.5 } } + }; + for (const AxisDefault &axis : axes) { + std::string axis_upper = boost::to_upper_copy(axis.name); + // Add the machine feedrate limits for XYZE axes. (M203) + def = this->add("machine_max_feedrate_" + axis.name, coFloats); + def->full_label = (boost::format("Maximum feedrate %1%") % axis_upper).str(); + (void)L("Maximum feedrate X"); + (void)L("Maximum feedrate Y"); + (void)L("Maximum feedrate Z"); + (void)L("Maximum feedrate E"); + def->category = L("Machine limits"); + def->tooltip = (boost::format("Maximum feedrate of the %1% axis") % axis_upper).str(); + (void)L("Maximum feedrate of the X axis"); + (void)L("Maximum feedrate of the Y axis"); + (void)L("Maximum feedrate of the Z axis"); + (void)L("Maximum feedrate of the E axis"); + def->sidetext = L("mm/s"); + def->min = 0; + def->width = machine_limits_opt_width; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloats(axis.max_feedrate)); - // Add the machine acceleration limits for XYZE axes (M201) - def = this->add("machine_max_acceleration_" + axis.name, coFloats); - def->full_label = (boost::format("Maximum acceleration %1%") % axis_upper).str(); - (void)L("Maximum acceleration X"); - (void)L("Maximum acceleration Y"); - (void)L("Maximum acceleration Z"); - (void)L("Maximum acceleration E"); - def->category = L("Machine limits"); - def->tooltip = (boost::format("Maximum acceleration of the %1% axis") % axis_upper).str(); - (void)L("Maximum acceleration of the X axis"); - (void)L("Maximum acceleration of the Y axis"); - (void)L("Maximum acceleration of the Z axis"); - (void)L("Maximum acceleration of the E axis"); - def->sidetext = L("mm/s²"); - def->min = 0; - def->width = machine_limits_opt_width; + def->set_default_value(new ConfigOptionFloats(axis.max_feedrate)); + // Add the machine acceleration limits for XYZE axes (M201) + def = this->add("machine_max_acceleration_" + axis.name, coFloats); + def->full_label = (boost::format("Maximum acceleration %1%") % axis_upper).str(); + (void)L("Maximum acceleration X"); + (void)L("Maximum acceleration Y"); + (void)L("Maximum acceleration Z"); + (void)L("Maximum acceleration E"); + def->category = L("Machine limits"); + def->tooltip = (boost::format("Maximum acceleration of the %1% axis") % axis_upper).str(); + (void)L("Maximum acceleration of the X axis"); + (void)L("Maximum acceleration of the Y axis"); + (void)L("Maximum acceleration of the Z axis"); + (void)L("Maximum acceleration of the E axis"); + def->sidetext = L("mm/s²"); + def->min = 0; + def->width = machine_limits_opt_width; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloats(axis.max_acceleration)); - // Add the machine jerk limits for XYZE axes (M205) - def = this->add("machine_max_jerk_" + axis.name, coFloats); - def->full_label = (boost::format("Maximum jerk %1%") % axis_upper).str(); - (void)L("Maximum jerk X"); - (void)L("Maximum jerk Y"); - (void)L("Maximum jerk Z"); - (void)L("Maximum jerk E"); - def->category = L("Machine limits"); - def->tooltip = (boost::format("Maximum jerk of the %1% axis") % axis_upper).str(); - (void)L("Maximum jerk of the X axis"); - (void)L("Maximum jerk of the Y axis"); - (void)L("Maximum jerk of the Z axis"); - (void)L("Maximum jerk of the E axis"); - def->sidetext = L("mm/s"); - def->min = 0; - def->width = machine_limits_opt_width; + def->set_default_value(new ConfigOptionFloats(axis.max_acceleration)); + // Add the machine jerk limits for XYZE axes (M205) + def = this->add("machine_max_jerk_" + axis.name, coFloats); + def->full_label = (boost::format("Maximum jerk %1%") % axis_upper).str(); + (void)L("Maximum jerk X"); + (void)L("Maximum jerk Y"); + (void)L("Maximum jerk Z"); + (void)L("Maximum jerk E"); + def->category = L("Machine limits"); + def->tooltip = (boost::format("Maximum jerk of the %1% axis") % axis_upper).str(); + (void)L("Maximum jerk of the X axis"); + (void)L("Maximum jerk of the Y axis"); + (void)L("Maximum jerk of the Z axis"); + (void)L("Maximum jerk of the E axis"); + def->sidetext = L("mm/s"); + def->min = 0; + def->width = machine_limits_opt_width; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloats(axis.max_jerk)); - } - } + def->set_default_value(new ConfigOptionFloats(axis.max_jerk)); + } + } // M205 S... [mm/sec] def = this->add("machine_min_extruding_rate", coFloats); @@ -1474,7 +1475,7 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->width = machine_limits_opt_width; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloats{ 0., 0. }); + def->set_default_value(new ConfigOptionFloats{ 0., 0. }); // M205 T... [mm/sec] def = this->add("machine_min_travel_rate", coFloats); @@ -1485,7 +1486,7 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->width = machine_limits_opt_width; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloats{ 0., 0. }); + def->set_default_value(new ConfigOptionFloats{ 0., 0. }); // M204 S... [mm/sec^2] def = this->add("machine_max_acceleration_extruding", coFloats); @@ -1704,7 +1705,7 @@ void PrintConfigDef::init_fff_params() "\n * Keep only bridges: remove the unsupported perimeter, kep only bridges that end in solid area." "\n * Keep bridges and overhangs: remove the unsupported perimeter, keep only bridges that end in solid area, fill the rest with overhang perimeters+bridges." "\n * Fill the voids with bridges: remove the unsupported perimeter, draw bridges over the whole hole. !! can lead to problems with overhangs shape like /\\, consider carefully before using this option!" - "\n!!Computationally intensive!!. "); + "\n!!Computationally intensive!!. "); def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->enum_values.push_back("none"); def->enum_values.push_back("noperi"); @@ -1803,9 +1804,9 @@ void PrintConfigDef::init_fff_params() def->gui_flags = "serialized"; def->multiline = true; def->full_width = true; - def->height = 6; + def->height = 6; def->mode = comExpert; - def->set_default_value(new ConfigOptionStrings()); + def->set_default_value(new ConfigOptionStrings()); def = this->add("printer_model", coString); def->label = L("Printer type"); @@ -1837,7 +1838,7 @@ void PrintConfigDef::init_fff_params() def = this->add("print_settings_id", coString); def->set_default_value(new ConfigOptionString("")); def->cli = ConfigOptionDef::nocli; - + def = this->add("printer_settings_id", coString); def->set_default_value(new ConfigOptionString("")); def->cli = ConfigOptionDef::nocli; @@ -1885,7 +1886,7 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("%"); def->mode = comAdvanced; def->set_default_value(new ConfigOptionPercents { 0. }); - + def = this->add("retract_layer_change", coBools); def->label = L("Retract on layer change"); def->tooltip = L("This flag enforces a retraction whenever a Z move is done."); @@ -1947,7 +1948,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Support material"); def->tooltip = L("Select this option to not use the z-lift on a top surface."); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBools { false }); + def->set_default_value(new ConfigOptionBools { false }); def = this->add("retract_restart_extra", coFloats); def->label = L("Extra length on restart"); @@ -2079,7 +2080,7 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->mode = comSimple; def->set_default_value(new ConfigOptionInt(1)); - + def = this->add("slowdown_below_layer_time", coInts); def->label = L("Slow down if layer print time is below"); def->tooltip = L("If layer print time is estimated below this number of seconds, print moves " @@ -2289,7 +2290,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Single Extruder Multi Material"); def->tooltip = L("The printer multiplexes filaments into a single hot end."); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool(false)); + def->set_default_value(new ConfigOptionBool(false)); def = this->add("single_extruder_multi_material_priming", coBool); def->label = L("Prime all printing extruders"); @@ -2372,8 +2373,8 @@ void PrintConfigDef::init_fff_params() // def->min = 0; def->enum_values.push_back("0"); def->enum_values.push_back("0.2"); - def->enum_labels.push_back(L("0 (soluble)")); - def->enum_labels.push_back(L("0.2 (detachable)")); + def->enum_labels.push_back(L("0 (soluble)")); + def->enum_labels.push_back(L("0.2 (detachable)")); def->mode = comAdvanced; def->aliases = { "support_material_contact_distance" }; def->set_default_value(new ConfigOptionFloatOrPercent(0.2, false)); @@ -2562,7 +2563,7 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->max = max_temp; def->set_default_value(new ConfigOptionInts { 200 }); - + def = this->add("thin_walls", coBool); def->label = L(""); def->full_label = L("Thin walls"); @@ -2604,7 +2605,7 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionInt(threads > 0 ? threads : 2)); def->cli == ConfigOptionDef::nocli; } - + def = this->add("toolchange_gcode", coString); def->label = L("Tool change G-code"); def->tooltip = L("This custom code is inserted at every extruder change. If you don't leave this empty, you are " @@ -2863,45 +2864,45 @@ void PrintConfigDef::init_fff_params() // Declare retract values for filament profile, overriding the printer's extruder profile. for (const char *opt_key : { - // floats - "retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", "retract_restart_extra", "retract_before_travel", - // bools - "retract_layer_change", "wipe", - // percents - "retract_before_wipe"}) { - auto it_opt = options.find(opt_key); - assert(it_opt != options.end()); - def = this->add_nullable(std::string("filament_") + opt_key, it_opt->second.type); - def->label = it_opt->second.label; - def->full_label = it_opt->second.full_label; - def->tooltip = it_opt->second.tooltip; - def->sidetext = it_opt->second.sidetext; - def->mode = it_opt->second.mode; - switch (def->type) { - case coFloats : def->set_default_value(new ConfigOptionFloatsNullable (static_cast(it_opt->second.default_value.get())->values)); break; - case coPercents : def->set_default_value(new ConfigOptionPercentsNullable(static_cast(it_opt->second.default_value.get())->values)); break; - case coBools : def->set_default_value(new ConfigOptionBoolsNullable (static_cast(it_opt->second.default_value.get())->values)); break; - default: assert(false); - } + // floats + "retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", "retract_restart_extra", "retract_before_travel", + // bools + "retract_layer_change", "wipe", + // percents + "retract_before_wipe"}) { + auto it_opt = options.find(opt_key); + assert(it_opt != options.end()); + def = this->add_nullable(std::string("filament_") + opt_key, it_opt->second.type); + def->label = it_opt->second.label; + def->full_label = it_opt->second.full_label; + def->tooltip = it_opt->second.tooltip; + def->sidetext = it_opt->second.sidetext; + def->mode = it_opt->second.mode; + switch (def->type) { + case coFloats : def->set_default_value(new ConfigOptionFloatsNullable (static_cast(it_opt->second.default_value.get())->values)); break; + case coPercents : def->set_default_value(new ConfigOptionPercentsNullable(static_cast(it_opt->second.default_value.get())->values)); break; + case coBools : def->set_default_value(new ConfigOptionBoolsNullable (static_cast(it_opt->second.default_value.get())->values)); break; + default: assert(false); + } } } void PrintConfigDef::init_extruder_retract_keys() { - m_extruder_retract_keys = { - "deretract_speed", - "retract_before_travel", - "retract_before_wipe", - "retract_layer_change", - "retract_length", - "retract_lift", - "retract_lift_above", - "retract_lift_below", - "retract_restart_extra", - "retract_speed", - "wipe" - }; - assert(std::is_sorted(m_extruder_retract_keys.begin(), m_extruder_retract_keys.end())); + m_extruder_retract_keys = { + "deretract_speed", + "retract_before_travel", + "retract_before_wipe", + "retract_layer_change", + "retract_length", + "retract_lift", + "retract_lift_above", + "retract_lift_below", + "retract_restart_extra", + "retract_speed", + "wipe" + }; + assert(std::is_sorted(m_extruder_retract_keys.begin(), m_extruder_retract_keys.end())); } void PrintConfigDef::init_sla_params() @@ -3003,7 +3004,7 @@ void PrintConfigDef::init_sla_params() "to the sign of the correction."); def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0.0)); - + def = this->add("gamma_correction", coFloat); def->label = L("Printer gamma correction"); def->full_label = L("Printer gamma correction"); @@ -3014,7 +3015,7 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(1.0)); - + // SLA Material settings. def = this->add("initial_layer_height", coFloat); @@ -3032,6 +3033,22 @@ void PrintConfigDef::init_sla_params() def->mode = comExpert; def->set_default_value(new ConfigOptionInt(10)); + def = this->add("min_exposure_time", coFloat); + def->label = L("Minimum exposure time"); + def->tooltip = L("Minimum exposure time"); + def->sidetext = L("s"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(0)); + + def = this->add("max_exposure_time", coFloat); + def->label = L("Maximum exposure time"); + def->tooltip = L("Maximum exposure time"); + def->sidetext = L("s"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(100)); + def = this->add("exposure_time", coFloat); def->label = L("Exposure time"); def->tooltip = L("Exposure time"); @@ -3039,6 +3056,22 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->set_default_value(new ConfigOptionFloat(10)); + def = this->add("min_initial_exposure_time", coFloat); + def->label = L("Minimum initial exposure time"); + def->tooltip = L("Minimum initial exposure time"); + def->sidetext = L("s"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(0)); + + def = this->add("max_initial_exposure_time", coFloat); + def->label = L("Maximum initial exposure time"); + def->tooltip = L("Maximum initial exposure time"); + def->sidetext = L("s"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(150)); + def = this->add("initial_exposure_time", coFloat); def->label = L("Initial exposure time"); def->tooltip = L("Initial exposure time"); @@ -3181,7 +3214,7 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(1.0)); - + def = this->add("support_base_safety_distance", coFloat); def->label = L("Support base safety distance"); def->category = L("Supports"); @@ -3296,14 +3329,14 @@ void PrintConfigDef::init_sla_params() def->set_default_value(new ConfigOptionFloat(50.0)); // This is disabled on the UI. I hope it will never be enabled. - def = this->add("pad_edge_radius", coFloat); - def->label = L("Pad edge radius"); - def->category = L("Pad"); -// def->tooltip = L(""); - def->sidetext = L("mm"); - def->min = 0; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(1.0)); +// def = this->add("pad_edge_radius", coFloat); +// def->label = L("Pad edge radius"); +// def->category = L("Pad"); +//// def->tooltip = L(""); +// def->sidetext = L("mm"); +// def->min = 0; +// def->mode = comAdvanced; +// def->set_default_value(new ConfigOptionFloat(1.0)); def = this->add("pad_wall_slope", coFloat); def->label = L("Pad wall slope"); @@ -3315,7 +3348,14 @@ void PrintConfigDef::init_sla_params() def->max = 90; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(45.0)); - + + def = this->add("pad_zero_elevation", coBool); + def->label = L("Pad around object"); + def->category = L("Pad"); + def->tooltip = L("Create pad around object and ignore the support elevation"); + def->mode = comSimple; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("pad_object_gap", coFloat); def->label = L("Pad object gap"); def->category = L("Pad"); @@ -3326,7 +3366,7 @@ void PrintConfigDef::init_sla_params() def->max = 10; def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(1)); - + def = this->add("pad_object_connector_stride", coFloat); def->label = L("Pad object connector stride"); def->category = L("Pad"); @@ -3336,7 +3376,7 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(10)); - + def = this->add("pad_object_connector_width", coFloat); def->label = L("Pad object connector width"); def->category = L("Pad"); @@ -3346,7 +3386,7 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0.5)); - + def = this->add("pad_object_connector_penetration", coFloat); def->label = L("Pad object connector penetration"); def->category = L("Pad"); @@ -3367,7 +3407,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va if (opt_key == "bottom_layer_speed") opt_key = "first_layer_speed"; try { float v = boost::lexical_cast(value); - if (v != 0) + if (v != 0) value = boost::lexical_cast(v*100) + "%"; } catch (boost::bad_lexical_cast &) { value = "0"; @@ -3407,14 +3447,14 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va } else if (opt_key == "octoprint_apikey") { opt_key = "printhost_apikey"; } - + // Ignore the following obsolete configuration keys: static std::set ignore = { "duplicate_x", "duplicate_y", "gcode_arcs", "multiply_x", "multiply_y", - "support_material_tool", "acceleration", "adjust_overhang_flow", + "support_material_tool", "acceleration", "adjust_overhang_flow", "standby_temperature", "scale", "rotate", "duplicate", "duplicate_grid", - "start_perimeters_at_concave_points", "start_perimeters_at_non_overhang", "randomize_start", - "seal_position", "vibration_limit", "bed_size", + "start_perimeters_at_concave_points", "start_perimeters_at_non_overhang", "randomize_start", + "seal_position", "vibration_limit", "bed_size", "print_center", "g0", "threads", "pressure_advance", "wipe_tower_per_color_wipe" #ifndef HAS_PRESSURE_EQUALIZER , "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative" @@ -3425,7 +3465,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va opt_key = ""; return; } - + if (! print_config_def.has(opt_key)) { opt_key = ""; return; @@ -3465,10 +3505,10 @@ void DynamicPrintConfig::normalize() // this->option("support_material_interface_extruder", true)->setInt(extruder); } } - + if (!this->has("solid_infill_extruder") && this->has("infill_extruder")) this->option("solid_infill_extruder", true)->setInt(this->option("infill_extruder")->getInt()); - + if (this->has("spiral_vase") && this->opt("spiral_vase", true)->value) { { // this should be actually done only on the spiral layers instead of all @@ -3541,7 +3581,6 @@ double PrintConfig::min_object_distance(const ConfigBase *config) } } return base_dist; -} //FIXME localize this function. std::string FullPrintConfig::validate() @@ -3565,7 +3604,7 @@ std::string FullPrintConfig::validate() for (double nd : this->nozzle_diameter.values) if (nd < 0.005) return "Invalid value for --nozzle-diameter"; - + // --perimeters if (this->perimeters.value < 0) return "Invalid value for --perimeters"; @@ -3575,8 +3614,8 @@ std::string FullPrintConfig::validate() return "Invalid value for --top-solid-layers"; if (this->bottom_solid_layers < 0) return "Invalid value for --bottom-solid-layers"; - - if (this->use_firmware_retraction.value && + + if (this->use_firmware_retraction.value && this->gcode_flavor.value != gcfSmoothie && this->gcode_flavor.value != gcfRepRap && this->gcode_flavor.value != gcfMarlin && @@ -3588,11 +3627,11 @@ std::string FullPrintConfig::validate() for (unsigned char wipe : this->wipe.values) if (wipe) return "--use-firmware-retraction is not compatible with --wipe"; - + // --gcode-flavor if (! print_config_def.get("gcode_flavor")->has_enum_value(this->gcode_flavor.serialize())) return "Invalid value for --gcode-flavor"; - + // --fill-pattern if (! print_config_def.get("fill_pattern")->has_enum_value(this->fill_pattern.serialize())) return "Invalid value for --fill-pattern"; @@ -3615,7 +3654,7 @@ std::string FullPrintConfig::validate() || ! print_config_def.get("bottom_fill_pattern")->has_enum_value(this->fill_pattern.serialize()) )) return "The selected fill pattern is not supposed to work at 100% density"; - + // --infill-every-layers if (this->infill_every_layers < 1) return "Invalid value for --infill-every-layers"; @@ -3623,7 +3662,7 @@ std::string FullPrintConfig::validate() // --skirt-height if (this->skirt_height < -1) // -1 means as tall as the object return "Invalid value for --skirt-height"; - + // --bridge-flow-ratio if (this->bridge_flow_ratio <= 0) return "Invalid value for --bridge-flow-ratio"; @@ -3667,7 +3706,7 @@ std::string FullPrintConfig::validate() if (this->extra_perimeters) return "Can't make more than one perimeter when spiral vase mode is enabled"; } - + // extrusion widths { double max_nozzle_diameter = 0.; @@ -3724,7 +3763,7 @@ std::string FullPrintConfig::validate() if (out_of_range) return std::string("Value out of range: " + opt_key); } - + // The configuration is valid. return ""; } @@ -3747,13 +3786,13 @@ StaticPrintConfig::StaticCache SLAFullPrint CLIActionsConfigDef::CLIActionsConfigDef() { ConfigOptionDef* def; - + // Actions: def = this->add("export_obj", coBool); def->label = L("Export OBJ"); def->tooltip = L("Export the model(s) as OBJ."); def->set_default_value(new ConfigOptionBool(false)); - + /* def = this->add("export_svg", coBool); def->label = L("Export SVG"); @@ -3761,7 +3800,7 @@ CLIActionsConfigDef::CLIActionsConfigDef() def->set_default_value(new ConfigOptionBool(false); def->set_default_value(new ConfigOptionBool(false)); */ - + def = this->add("export_sla", coBool); def->label = L("Export SLA"); def->tooltip = L("Slice the model and export SLA printing layers as PNG."); @@ -3810,12 +3849,12 @@ CLIActionsConfigDef::CLIActionsConfigDef() def->label = L("Help (SLA options)"); def->tooltip = L("Show the full list of SLA print configuration options."); def->set_default_value(new ConfigOptionBool(false)); - + def = this->add("info", coBool); def->label = L("Output Model Info"); def->tooltip = L("Write information about the model to the console."); def->set_default_value(new ConfigOptionBool(false)); - + def = this->add("save", coString); def->label = L("Save config file"); def->tooltip = L("Save configuration to the specified file."); @@ -3825,38 +3864,38 @@ CLIActionsConfigDef::CLIActionsConfigDef() CLITransformConfigDef::CLITransformConfigDef() { ConfigOptionDef* def; - + // Transform options: def = this->add("align_xy", coPoint); def->label = L("Align XY"); def->tooltip = L("Align the model to the given point."); def->set_default_value(new ConfigOptionPoint(Vec2d(100,100))); - + def = this->add("cut", coFloat); def->label = L("Cut"); def->tooltip = L("Cut model at the given Z."); def->set_default_value(new ConfigOptionFloat(0)); - + /* def = this->add("cut_grid", coFloat); def->label = L("Cut"); def->tooltip = L("Cut model in the XY plane into tiles of the specified max size."); def->set_default_value(new ConfigOptionPoint(); def->set_default_value(new ConfigOptionPoint()); - + def = this->add("cut_x", coFloat); def->label = L("Cut"); def->tooltip = L("Cut model at the given X."); def->set_default_value(new ConfigOptionFloat(0); def->set_default_value(new ConfigOptionFloat(0)); - + def = this->add("cut_y", coFloat); def->label = L("Cut"); def->tooltip = L("Cut model at the given Y."); def->set_default_value(new ConfigOptionFloat(0); def->set_default_value(new ConfigOptionFloat(0)); */ - + def = this->add("center", coPoint); def->label = L("Center"); def->tooltip = L("Center the print around the given center."); @@ -3865,12 +3904,12 @@ CLITransformConfigDef::CLITransformConfigDef() def = this->add("dont_arrange", coBool); def->label = L("Don't arrange"); def->tooltip = L("Do not rearrange the given models before merging and keep their original XY coordinates."); - + def = this->add("duplicate", coInt); def->label = L("Duplicate"); def->tooltip =L("Multiply copies by this factor."); def->min = 1; - + def = this->add("duplicate_grid", coPoint); def->label = L("Duplicate by grid"); def->tooltip = L("Multiply copies by creating a grid."); @@ -3883,22 +3922,22 @@ CLITransformConfigDef::CLITransformConfigDef() def = this->add("repair", coBool); def->label = L("Repair"); def->tooltip = L("Try to repair any non-manifold meshes (this option is implicitly added whenever we need to slice the model to perform the requested action)."); - + def = this->add("rotate", coFloat); def->label = L("Rotate"); def->tooltip = L("Rotation angle around the Z axis in degrees."); def->set_default_value(new ConfigOptionFloat(0)); - + def = this->add("rotate_x", coFloat); def->label = L("Rotate around X"); def->tooltip = L("Rotation angle around the X axis in degrees."); def->set_default_value(new ConfigOptionFloat(0)); - + def = this->add("rotate_y", coFloat); def->label = L("Rotate around Y"); def->tooltip = L("Rotation angle around the Y axis in degrees."); def->set_default_value(new ConfigOptionFloat(0)); - + def = this->add("scale", coFloatOrPercent); def->label = L("Scale"); def->tooltip = L("Scaling factor or percentage."); @@ -3907,7 +3946,7 @@ CLITransformConfigDef::CLITransformConfigDef() def = this->add("split", coBool); def->label = L("Split"); def->tooltip = L("Detect unconnected parts in the given model(s) and split them into separate objects."); - + def = this->add("scale_to_fit", coPoint3); def->label = L("Scale to Fit"); def->tooltip = L("Scale to fit the given volume."); @@ -3917,26 +3956,26 @@ CLITransformConfigDef::CLITransformConfigDef() CLIMiscConfigDef::CLIMiscConfigDef() { ConfigOptionDef* def; - + def = this->add("ignore_nonexistent_config", coBool); def->label = L("Ignore non-existent config files"); def->tooltip = L("Do not fail if a file supplied to --load does not exist."); - + def = this->add("load", coStrings); def->label = L("Load config file"); def->tooltip = L("Load configuration from the specified file. It can be used more than once to load options from multiple files."); - + def = this->add("output", coString); def->label = L("Output File"); def->tooltip = L("The file where the output will be written (if not specified, it will be based on the input file)."); def->cli = "output|o"; -/* +/* def = this->add("autosave", coString); def->label = L("Autosave"); def->tooltip = L("Automatically export current configuration to the specified file."); */ - + def = this->add("datadir", coString); def->label = L("Data directory"); def->tooltip = L("Load and store settings at the given directory. This is useful for maintaining different profiles or including configurations from a network storage."); @@ -3946,7 +3985,7 @@ CLIMiscConfigDef::CLIMiscConfigDef() def->tooltip = L("Messages with severity lower or eqal to the loglevel will be printed out. 0:trace, 1:debug, 2:info, 3:warning, 4:error, 5:fatal"); def->min = 0; -#if defined(_MSC_VER) && defined(SLIC3R_GUI) +#if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(SLIC3R_GUI) def = this->add("sw_renderer", coBool); def->label = L("Render with a software renderer"); def->tooltip = L("Render with a software renderer. The bundled MESA software renderer is loaded instead of the default OpenGL driver."); @@ -3962,15 +4001,15 @@ DynamicPrintAndCLIConfig::PrintAndCLIConfigDef DynamicPrintAndCLIConfig::s_def; void DynamicPrintAndCLIConfig::handle_legacy(t_config_option_key &opt_key, std::string &value) const { - if (cli_actions_config_def .options.find(opt_key) == cli_actions_config_def .options.end() && - cli_transform_config_def.options.find(opt_key) == cli_transform_config_def.options.end() && - cli_misc_config_def .options.find(opt_key) == cli_misc_config_def .options.end()) { - PrintConfigDef::handle_legacy(opt_key, value); - } + if (cli_actions_config_def .options.find(opt_key) == cli_actions_config_def .options.end() && + cli_transform_config_def.options.find(opt_key) == cli_transform_config_def.options.end() && + cli_misc_config_def .options.find(opt_key) == cli_misc_config_def .options.end()) { + PrintConfigDef::handle_legacy(opt_key, value); + } } } #include CEREAL_REGISTER_TYPE(Slic3r::DynamicPrintConfig) -CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::DynamicConfig, Slic3r::DynamicPrintConfig) +CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::DynamicConfig, Slic3r::DynamicPrintConfig) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index f2fef69bc..893b727e1 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -891,7 +891,7 @@ protected: class PrintConfig : public MachineEnvelopeConfig, public GCodeConfig { STATIC_PRINT_CONFIG_CACHE_DERIVED(PrintConfig) - PrintConfig() : MachineEnvelopeConfig(0), GCodeConfig(0) { initialize_cache(); *this = s_cache_PrintConfig.defaults(); } + PrintConfig() : MachineEnvelopeConfig(0), GCodeConfig(0) { initialize_cache(); *this = s_cache_PrintConfig.defaults(); } public: double min_object_distance() const; static double min_object_distance(const ConfigBase *config); @@ -967,7 +967,7 @@ public: ConfigOptionFloat z_offset; protected: - PrintConfig(int) : MachineEnvelopeConfig(1), GCodeConfig(1) {} + PrintConfig(int) : MachineEnvelopeConfig(1), GCodeConfig(1) {} void initialize(StaticCacheBase &cache, const char *base_ptr) { this->MachineEnvelopeConfig::initialize(cache, base_ptr); @@ -1150,7 +1150,7 @@ public: // The height of the pillar base cone in mm. ConfigOptionFloat support_base_height /*= 1.0*/; - + // The minimum distance of the pillar base from the model in mm. ConfigOptionFloat support_base_safety_distance; /*= 1.0*/; @@ -1166,7 +1166,7 @@ public: // The elevation in Z direction upwards. This is the space between the pad // and the model object's bounding box bottom. Units in mm. ConfigOptionFloat support_object_elevation /*= 5.0*/; - + /////// Following options influence automatic support points placement: ConfigOptionInt support_points_density_relative; ConfigOptionFloat support_points_minimal_distance; @@ -1187,11 +1187,11 @@ public: ConfigOptionFloat pad_max_merge_distance /*= 50*/; // The smoothing radius of the pad edges - ConfigOptionFloat pad_edge_radius /*= 1*/; + // ConfigOptionFloat pad_edge_radius /*= 1*/; // The slope of the pad wall... ConfigOptionFloat pad_wall_slope; - + // ///////////////////////////////////////////////////////////////////////// // Zero elevation mode parameters: // - The object pad will be derived from the the model geometry. @@ -1199,16 +1199,19 @@ public: // according to the support_base_safety_distance parameter. // - The two pads will be connected with tiny connector sticks // ///////////////////////////////////////////////////////////////////////// - + + // Disable the elevation (ignore its value) and use the zero elevation mode + ConfigOptionBool pad_zero_elevation; + // This is the gap between the object bottom and the generated pad ConfigOptionFloat pad_object_gap; - + // How far to place the connector sticks on the object pad perimeter ConfigOptionFloat pad_object_connector_stride; - + // The width of the connectors sticks ConfigOptionFloat pad_object_connector_width; - + // How much should the tiny connectors penetrate into the model body ConfigOptionFloat pad_object_connector_penetration; @@ -1239,8 +1242,9 @@ protected: OPT_PTR(pad_wall_thickness); OPT_PTR(pad_wall_height); OPT_PTR(pad_max_merge_distance); - OPT_PTR(pad_edge_radius); + // OPT_PTR(pad_edge_radius); OPT_PTR(pad_wall_slope); + OPT_PTR(pad_zero_elevation); OPT_PTR(pad_object_gap); OPT_PTR(pad_object_connector_stride); OPT_PTR(pad_object_connector_width); @@ -1286,6 +1290,10 @@ public: ConfigOptionFloat fast_tilt_time; ConfigOptionFloat slow_tilt_time; ConfigOptionFloat area_fill; + ConfigOptionFloat min_exposure_time; + ConfigOptionFloat max_exposure_time; + ConfigOptionFloat min_initial_exposure_time; + ConfigOptionFloat max_initial_exposure_time; protected: void initialize(StaticCacheBase &cache, const char *base_ptr) { @@ -1305,6 +1313,10 @@ protected: OPT_PTR(fast_tilt_time); OPT_PTR(slow_tilt_time); OPT_PTR(area_fill); + OPT_PTR(min_exposure_time); + OPT_PTR(max_exposure_time); + OPT_PTR(min_initial_exposure_time); + OPT_PTR(max_initial_exposure_time); } }; @@ -1364,8 +1376,8 @@ extern const CLIMiscConfigDef cli_misc_config_def; class DynamicPrintAndCLIConfig : public DynamicPrintConfig { public: - DynamicPrintAndCLIConfig() {} - DynamicPrintAndCLIConfig(const DynamicPrintAndCLIConfig &other) : DynamicPrintConfig(other) {} + DynamicPrintAndCLIConfig() {} + DynamicPrintAndCLIConfig(const DynamicPrintAndCLIConfig &other) : DynamicPrintConfig(other) {} // Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here. const ConfigDef* def() const override { return &s_def; } @@ -1386,7 +1398,7 @@ private: this->options.insert(cli_transform_config_def.options.begin(), cli_transform_config_def.options.end()); this->options.insert(cli_misc_config_def.options.begin(), cli_misc_config_def.options.end()); for (const auto &kvp : this->options) - this->by_serialization_key_ordinal[kvp.second.serialization_key_ordinal] = &kvp.second; + this->by_serialization_key_ordinal[kvp.second.serialization_key_ordinal] = &kvp.second; } // Do not release the default values, they are handled by print_config_def & cli_actions_config_def / cli_transform_config_def / cli_misc_config_def. ~PrintAndCLIConfigDef() { this->options.clear(); } @@ -1398,36 +1410,36 @@ private: // Serialization through the Cereal library namespace cereal { - // Let cereal know that there are load / save non-member functions declared for DynamicPrintConfig, ignore serialize / load / save from parent class DynamicConfig. - template struct specialize {}; + // Let cereal know that there are load / save non-member functions declared for DynamicPrintConfig, ignore serialize / load / save from parent class DynamicConfig. + template struct specialize {}; - template void load(Archive& archive, Slic3r::DynamicPrintConfig &config) - { - size_t cnt; - archive(cnt); - config.clear(); - for (size_t i = 0; i < cnt; ++ i) { - size_t serialization_key_ordinal; - archive(serialization_key_ordinal); - assert(serialization_key_ordinal > 0); - auto it = Slic3r::print_config_def.by_serialization_key_ordinal.find(serialization_key_ordinal); - assert(it != Slic3r::print_config_def.by_serialization_key_ordinal.end()); - config.set_key_value(it->second->opt_key, it->second->load_option_from_archive(archive)); - } - } + template void load(Archive& archive, Slic3r::DynamicPrintConfig &config) + { + size_t cnt; + archive(cnt); + config.clear(); + for (size_t i = 0; i < cnt; ++ i) { + size_t serialization_key_ordinal; + archive(serialization_key_ordinal); + assert(serialization_key_ordinal > 0); + auto it = Slic3r::print_config_def.by_serialization_key_ordinal.find(serialization_key_ordinal); + assert(it != Slic3r::print_config_def.by_serialization_key_ordinal.end()); + config.set_key_value(it->second->opt_key, it->second->load_option_from_archive(archive)); + } + } - template void save(Archive& archive, const Slic3r::DynamicPrintConfig &config) - { - size_t cnt = config.size(); - archive(cnt); - for (auto it = config.cbegin(); it != config.cend(); ++it) { - const Slic3r::ConfigOptionDef* optdef = Slic3r::print_config_def.get(it->first); - assert(optdef != nullptr); - assert(optdef->serialization_key_ordinal > 0); - archive(optdef->serialization_key_ordinal); - optdef->save_option_to_archive(archive, it->second.get()); - } - } + template void save(Archive& archive, const Slic3r::DynamicPrintConfig &config) + { + size_t cnt = config.size(); + archive(cnt); + for (auto it = config.cbegin(); it != config.cend(); ++it) { + const Slic3r::ConfigOptionDef* optdef = Slic3r::print_config_def.get(it->first); + assert(optdef != nullptr); + assert(optdef->serialization_key_ordinal > 0); + archive(optdef->serialization_key_ordinal); + optdef->save_option_to_archive(archive, it->second.get()); + } + } } #endif diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 725ee5025..ca22ea1c7 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -162,7 +162,7 @@ void PrintObject::make_perimeters() const PrintRegion ®ion = *m_print->regions()[region_id]; if (! region.config().extra_perimeters || region.config().perimeters == 0 || region.config().fill_density == 0 || this->layer_count() < 2) continue; - + BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - start"; tbb::parallel_for( tbb::blocked_range(0, m_layers.size() - 1), @@ -2863,7 +2863,7 @@ void PrintObject::discover_horizontal_shells() if (new_internal_solid.empty()) { // No internal solid needed on this layer. In order to decide whether to continue // searching on the next neighbor (thus enforcing the configured number of solid - // layers, use different strategies according to configured infill density: + // layers, use different strategies according to configured infill density: if (region_config.fill_density.value == 0) { // If user expects the object to be void (for example a hollow sloping vase), // don't continue the search. In this case, we only generate the external solid diff --git a/src/libslic3r/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp index 73b40487b..fc2bdfa7d 100644 --- a/src/libslic3r/PrintRegion.cpp +++ b/src/libslic3r/PrintRegion.cpp @@ -46,7 +46,7 @@ Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool fir } double nozzle_diameter = m_print->config().nozzle_diameter.get_at(extruder-1); - return Flow::new_from_config_width(role, config_width, nozzle_diameter, layer_height, bridge ? (float)m_config.bridge_flow_ratio : 0.0); + return Flow::new_from_config_width(role, config_width, (float)nozzle_diameter, (float)layer_height, bridge ? (float)m_config.bridge_flow_ratio : 0.0f); } coordf_t PrintRegion::nozzle_dmr_avg(const PrintConfig &print_config) const @@ -64,16 +64,27 @@ coordf_t PrintRegion::bridging_height_avg(const PrintConfig &print_config) const void PrintRegion::collect_object_printing_extruders(const PrintConfig &print_config, const PrintRegionConfig ®ion_config, std::vector &object_extruders) { // These checks reflect the same logic used in the GUI for enabling/disabling extruder selection fields. + auto num_extruders = (int)print_config.nozzle_diameter.size(); + auto emplace_extruder = [num_extruders, &object_extruders](int extruder_id) { + int i = std::max(0, extruder_id - 1); + object_extruders.emplace_back((i >= num_extruders) ? 0 : i); + }; if (region_config.perimeters.value > 0 || print_config.brim_width.value > 0) - object_extruders.emplace_back(region_config.perimeter_extruder - 1); + emplace_extruder(region_config.perimeter_extruder); if (region_config.fill_density.value > 0) - object_extruders.emplace_back(region_config.infill_extruder - 1); + emplace_extruder(region_config.infill_extruder); if (region_config.top_solid_layers.value > 0 || region_config.bottom_solid_layers.value > 0) - object_extruders.emplace_back(region_config.solid_infill_extruder - 1); + emplace_extruder(region_config.solid_infill_extruder); } void PrintRegion::collect_object_printing_extruders(std::vector &object_extruders) const { + auto num_extruders = (int)print()->config().nozzle_diameter.size(); + // PrintRegion, if used by some PrintObject, shall have all the extruders set to an existing printer extruder. + // If not, then there must be something wrong with the Print::apply() function. + assert(this->config().perimeter_extruder <= num_extruders); + assert(this->config().infill_extruder <= num_extruders); + assert(this->config().solid_infill_extruder <= num_extruders); collect_object_printing_extruders(print()->config(), this->config(), object_extruders); } diff --git a/src/libslic3r/SLA/SLAAutoSupports.cpp b/src/libslic3r/SLA/SLAAutoSupports.cpp index cbd48796d..5451c7612 100644 --- a/src/libslic3r/SLA/SLAAutoSupports.cpp +++ b/src/libslic3r/SLA/SLAAutoSupports.cpp @@ -1,5 +1,5 @@ -#include "igl/random_points_on_mesh.h" -#include "igl/AABB.h" +//#include "igl/random_points_on_mesh.h" +//#include "igl/AABB.h" #include diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index 48b78fcce..56be5a569 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -85,7 +85,7 @@ using Portion = std::tuple; // Set this to true to enable full parallelism in this module. // Only the well tested parts will be concurrent if this is set to false. -const constexpr bool USE_FULL_CONCURRENCY = false; +const constexpr bool USE_FULL_CONCURRENCY = true; template struct _ccr {}; @@ -713,7 +713,7 @@ struct Pad { } tmesh.translate(0, 0, float(zlevel)); - tmesh.require_shared_vertices(); + if (!tmesh.empty()) tmesh.require_shared_vertices(); } bool empty() const { return tmesh.facets_count() == 0; } @@ -1194,7 +1194,7 @@ class SLASupportTree::Algorithm { // Now a and b vectors are perpendicular to v and to each other. // Together they define the plane where we have to iterate with the // given angles in the 'phis' vector - ccr_par::enumerate(phis.begin(), phis.end(), + ccr_seq::enumerate(phis.begin(), phis.end(), [&hits, &m, sd, r_pin, r_back, s, a, b, c] (double phi, size_t i) { @@ -1297,7 +1297,7 @@ class SLASupportTree::Algorithm { // Hit results std::array hits; - ccr_par::enumerate(phis.begin(), phis.end(), + ccr_seq::enumerate(phis.begin(), phis.end(), [&m, a, b, sd, dir, r, s, ins_check, &hits] (double phi, size_t i) { @@ -2588,7 +2588,7 @@ SLASupportTree::SLASupportTree(double gnd_lvl): m_impl(new Impl()) { const TriangleMesh &SLASupportTree::merged_mesh() const { - return get().merged_mesh(); + return m_impl->merged_mesh(); } void SLASupportTree::merged_mesh_with_pad(TriangleMesh &outmesh) const { @@ -2597,41 +2597,53 @@ void SLASupportTree::merged_mesh_with_pad(TriangleMesh &outmesh) const { } std::vector SLASupportTree::slice( - const std::vector &heights, float cr) const + const std::vector &grid, float cr) const { const TriangleMesh &sup_mesh = m_impl->merged_mesh(); const TriangleMesh &pad_mesh = get_pad(); - std::vector sup_slices; + using Slices = std::vector; + auto slices = reserve_vector(2); + if (!sup_mesh.empty()) { + slices.emplace_back(); + TriangleMeshSlicer sup_slicer(&sup_mesh); sup_slicer.closing_radius = cr; - sup_slicer.slice(heights, &sup_slices, m_impl->ctl().cancelfn); + sup_slicer.slice(grid, &slices.back(), m_impl->ctl().cancelfn); } + if (!pad_mesh.empty()) { + slices.emplace_back(); + auto bb = pad_mesh.bounding_box(); - auto maxzit = std::upper_bound(heights.begin(), heights.end(), bb.max.z()); + auto maxzit = std::upper_bound(grid.begin(), grid.end(), bb.max.z()); - auto padgrid = reserve_vector(heights.end() - maxzit); - std::copy(heights.begin(), maxzit, std::back_inserter(padgrid)); + auto padgrid = reserve_vector(grid.end() - maxzit); + std::copy(grid.begin(), maxzit, std::back_inserter(padgrid)); - std::vector pad_slices; - if (!pad_mesh.empty()) { TriangleMeshSlicer pad_slicer(&pad_mesh); pad_slicer.closing_radius = cr; - pad_slicer.slice(padgrid, &pad_slices, m_impl->ctl().cancelfn); + pad_slicer.slice(padgrid, &slices.back(), m_impl->ctl().cancelfn); } - size_t len = std::min(heights.size(), pad_slices.size()); - len = std::min(len, sup_slices.size()); + size_t len = grid.size(); + for (const Slices &slv : slices) { len = std::min(len, slv.size()); } + // Either the support or the pad or both has to be non empty + if (slices.empty()) return {}; + + Slices &mrg = slices.front(); + + for (auto it = std::next(slices.begin()); it != slices.end(); ++it) { for (size_t i = 0; i < len; ++i) { - std::copy(pad_slices[i].begin(), pad_slices[i].end(), - std::back_inserter(sup_slices[i])); - pad_slices[i] = {}; + Slices &slv = *it; + std::copy(slv[i].begin(), slv[i].end(), std::back_inserter(mrg[i])); + slv[i] = {}; // clear and delete + } } - return sup_slices; + return mrg; } const TriangleMesh &SLASupportTree::add_pad(const ExPolygons& modelbase, diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp index 4016b31f8..a5aede210 100644 --- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp +++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp @@ -148,9 +148,9 @@ std::vector BoxIndex::query(const BoundingBox &qrbb, BoxIndex::QueryType qt) { namespace bgi = boost::geometry::index; - + std::vector ret; ret.reserve(m_impl->m_store.size()); - + switch (qt) { case qtIntersects: m_impl->m_store.query(bgi::intersects(qrbb), std::back_inserter(ret)); @@ -158,7 +158,7 @@ std::vector BoxIndex::query(const BoundingBox &qrbb, case qtWithin: m_impl->m_store.query(bgi::within(qrbb), std::back_inserter(ret)); } - + return ret; } @@ -198,9 +198,9 @@ EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh): m_aabb(new AABBImpl()) { F.resize(stl.stats.number_of_facets, 3); for (unsigned int i = 0; i < stl.stats.number_of_facets; ++i) { const stl_facet &facet = stl.facet_start[i]; - V.block<1, 3>(3 * i + 0, 0) = facet.vertex[0].cast(); - V.block<1, 3>(3 * i + 1, 0) = facet.vertex[1].cast(); - V.block<1, 3>(3 * i + 2, 0) = facet.vertex[2].cast(); + V.block<1, 3>(3 * i + 0, 0) = facet.vertex[0].cast(); + V.block<1, 3>(3 * i + 1, 0) = facet.vertex[1].cast(); + V.block<1, 3>(3 * i + 2, 0) = facet.vertex[2].cast(); F(i, 0) = int(3*i+0); F(i, 1) = int(3*i+1); F(i, 2) = int(3*i+2); @@ -306,6 +306,7 @@ PointSet normals(const PointSet& points, PointSet ret(range.size(), 3); +// for (size_t ridx = 0; ridx < range.size(); ++ridx) tbb::parallel_for(size_t(0), range.size(), [&ret, &range, &mesh, &points, thr, eps](size_t ridx) { diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index bc21d5111..d2e9ebd8a 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -16,6 +16,12 @@ // For geometry algorithms with native Clipper types (no copies and conversions) #include +// #define SLAPRINT_DO_BENCHMARK + +#ifdef SLAPRINT_DO_BENCHMARK +#include +#endif + //#include //#include "tbb/mutex.h" #include "I18N.hpp" @@ -569,6 +575,16 @@ std::string SLAPrint::output_filename(const std::string &filename_base) const } namespace { + +bool is_zero_elevation(const SLAPrintObjectConfig &c) { + bool en_implicit = c.support_object_elevation.getFloat() <= EPSILON && + c.pad_enable.getBool() && c.supports_enable.getBool(); + bool en_explicit = c.pad_zero_elevation.getBool() && + c.supports_enable.getBool(); + + return en_implicit || en_explicit; +} + // Compile the argument for support creation from the static print config. sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) { sla::SupportConfig scfg; @@ -577,7 +593,8 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) { scfg.head_back_radius_mm = 0.5*c.support_pillar_diameter.getFloat(); scfg.head_penetration_mm = c.support_head_penetration.getFloat(); scfg.head_width_mm = c.support_head_width.getFloat(); - scfg.object_elevation_mm = c.support_object_elevation.getFloat(); + scfg.object_elevation_mm = is_zero_elevation(c) ? + 0. : c.support_object_elevation.getFloat(); scfg.bridge_slope = c.support_critical_angle.getFloat() * PI / 180.0 ; scfg.max_bridge_length_mm = c.support_max_bridge_length.getFloat(); scfg.max_pillar_link_distance_mm = c.support_max_pillar_link_distance.getFloat(); @@ -603,8 +620,7 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) { sla::PoolConfig::EmbedObject builtin_pad_cfg(const SLAPrintObjectConfig& c) { sla::PoolConfig::EmbedObject ret; - ret.enabled = c.support_object_elevation.getFloat() <= EPSILON && - c.pad_enable.getBool() && c.supports_enable.getBool(); + ret.enabled = is_zero_elevation(c); if(ret.enabled) { ret.object_gap_mm = c.pad_object_gap.getFloat(); @@ -661,7 +677,9 @@ std::string SLAPrint::validate() const double elv = cfg.object_elevation_mm; if(supports_en && elv > EPSILON && elv < pinhead_width ) - return L("Elevation is too low for object."); + return L( + "Elevation is too low for object. Use the \"Pad around " + "obect\" feature to print the object without elevation."); sla::PoolConfig::EmbedObject builtinpad = builtin_pad_cfg(po->config()); if(supports_en && builtinpad.enabled && @@ -674,6 +692,20 @@ std::string SLAPrint::validate() const } } + double expt_max = m_printer_config.max_exposure_time.getFloat(); + double expt_min = m_printer_config.min_exposure_time.getFloat(); + double expt_cur = m_material_config.exposure_time.getFloat(); + + if (expt_cur < expt_min || expt_cur > expt_max) + return L("Exposition time is out of printer profile bounds."); + + double iexpt_max = m_printer_config.max_initial_exposure_time.getFloat(); + double iexpt_min = m_printer_config.min_initial_exposure_time.getFloat(); + double iexpt_cur = m_material_config.initial_exposure_time.getFloat(); + + if (iexpt_cur < iexpt_min || iexpt_cur > iexpt_max) + return L("Initial exposition time is out of printer profile bounds."); + return ""; } @@ -749,7 +781,7 @@ void SLAPrint::process() for(coord_t h = minZs + ilhs + lhs; h <= maxZs; h += lhs) po.m_slice_index.emplace_back(h, unscale(h) - lh / 2.f, lh); - // Just get the first record that is form the model: + // Just get the first record that is from the model: auto slindex_it = po.closest_slice_record(po.m_slice_index, float(bb3d.min(Z))); @@ -879,7 +911,7 @@ void SLAPrint::process() // If the zero elevation mode is engaged, we have to filter out all the // points that are on the bottom of the object - if (po.config().support_object_elevation.getFloat() <= EPSILON) { + if (is_zero_elevation(po.config())) { double gnd = po.m_supportdata->emesh.ground_level(); auto & pts = po.m_supportdata->support_points; double tolerance = po.config().pad_enable.getBool() @@ -1429,7 +1461,7 @@ void SLAPrint::process() if(canceled()) return; // Sequential version (for testing) - // for(unsigned l = 0; l < lvlcnt; ++l) process_level(l); + // for(unsigned l = 0; l < lvlcnt; ++l) lvlfn(l); // Print all the layers in parallel tbb::parallel_for(0, lvlcnt, lvlfn); @@ -1446,44 +1478,45 @@ void SLAPrint::process() using slaposFn = std::function; using slapsFn = std::function; - std::array pobj_program = + slaposFn pobj_program[] = { - slice_model, - support_points, - support_tree, - base_pool, - slice_supports + slice_model, support_points, support_tree, base_pool, slice_supports }; - std::array print_program = - { - merge_slices_and_eval_stats, - rasterize + // We want to first process all objects... + std::vector level1_obj_steps = { + slaposObjectSlice, slaposSupportPoints, slaposSupportTree, slaposBasePool }; + // and then slice all supports to allow preview to be displayed ASAP + std::vector level2_obj_steps = { + slaposSliceSupports + }; + + slapsFn print_program[] = { merge_slices_and_eval_stats, rasterize }; + SLAPrintStep print_steps[] = { slapsMergeSlicesAndEval, slapsRasterize }; + double st = min_objstatus; - unsigned incr = 0; BOOST_LOG_TRIVIAL(info) << "Start slicing process."; - // TODO: this loop could run in parallel but should not exhaust all the CPU - // power available - // Calculate the support structures first before slicing the supports, - // so that the preview will get displayed ASAP for all objects. - std::vector step_ranges = {slaposObjectSlice, - slaposSliceSupports, - slaposCount}; +#ifdef SLAPRINT_DO_BENCHMARK + Benchmark bench; +#else + struct { + void start() {} void stop() {} double getElapsedSec() { return .0; } + } bench; +#endif - for (size_t idx_range = 0; idx_range + 1 < step_ranges.size(); ++idx_range) { + std::array step_times {}; + + auto apply_steps_on_objects = + [this, &st, ostepd, &pobj_program, &step_times, &bench] + (const std::vector &steps) + { + unsigned incr = 0; for (SLAPrintObject *po : m_objects) { - - BOOST_LOG_TRIVIAL(info) - << "Slicing object " << po->model_object()->name; - - for (int s = int(step_ranges[idx_range]); - s < int(step_ranges[idx_range + 1]); - ++s) { - auto currentstep = static_cast(s); + for (SLAPrintObjectStep step : steps) { // Cancellation checking. Each step will check for // cancellation on its own and return earlier gracefully. @@ -1493,39 +1526,38 @@ void SLAPrint::process() st += incr * ostepd; - if (po->m_stepmask[currentstep] - && po->set_started(currentstep)) { - m_report_status(*this, - st, - OBJ_STEP_LABELS(currentstep)); - pobj_program[currentstep](*po); + if (po->m_stepmask[step] && po->set_started(step)) { + m_report_status(*this, st, OBJ_STEP_LABELS(step)); + bench.start(); + pobj_program[step](*po); + bench.stop(); + step_times[step] += bench.getElapsedSec(); throw_if_canceled(); - po->set_done(currentstep); + po->set_done(step); } - incr = OBJ_STEP_LEVELS[currentstep]; + incr = OBJ_STEP_LEVELS[step]; } } - } - - std::array printsteps = { - slapsMergeSlicesAndEval, slapsRasterize }; + apply_steps_on_objects(level1_obj_steps); + apply_steps_on_objects(level2_obj_steps); + // this would disable the rasterization step - // m_stepmask[slapsRasterize] = false; + // std::fill(m_stepmask.begin(), m_stepmask.end(), false); double pstd = (100 - max_objstatus) / 100.0; st = max_objstatus; - for(size_t s = 0; s < print_program.size(); ++s) { - auto currentstep = printsteps[s]; - + for(SLAPrintStep currentstep : print_steps) { throw_if_canceled(); - if(m_stepmask[currentstep] && set_started(currentstep)) - { + if (m_stepmask[currentstep] && set_started(currentstep)) { m_report_status(*this, st, PRINT_STEP_LABELS(currentstep)); + bench.start(); print_program[currentstep](); + bench.stop(); + step_times[slaposCount + currentstep] += bench.getElapsedSec(); throw_if_canceled(); set_done(currentstep); } @@ -1535,6 +1567,21 @@ void SLAPrint::process() // If everything vent well m_report_status(*this, 100, L("Slicing done")); + +#ifdef SLAPRINT_DO_BENCHMARK + std::string csvbenchstr; + for (size_t i = 0; i < size_t(slaposCount); ++i) + csvbenchstr += OBJ_STEP_LABELS(i) + ";"; + + for (size_t i = 0; i < size_t(slapsCount); ++i) + csvbenchstr += PRINT_STEP_LABELS(i) + ";"; + + csvbenchstr += "\n"; + for (double t : step_times) csvbenchstr += std::to_string(t) + ";"; + + std::cout << "Performance stats: \n" << csvbenchstr << std::endl; +#endif + } bool SLAPrint::invalidate_state_by_config_options(const std::vector &opt_keys, bool &invalidate_all_model_objects) @@ -1553,7 +1600,11 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector steps_rasterize = { + "min_exposure_time", + "max_exposure_time", "exposure_time", + "min_initial_exposure_time", + "max_initial_exposure_time", "initial_exposure_time", "display_width", "display_height", @@ -1647,6 +1698,7 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector= info (3). -extern std::string log_memory_info(); +// The string is non-empty if the loglevel >= info (3) or ignore_loglevel==true. +// Latter is used to get the memory info from SysInfoDialog. +extern std::string log_memory_info(bool ignore_loglevel = false); extern void disable_multi_threading(); // Returns the size of physical memory (RAM) in bytes. extern size_t total_physical_memory(); @@ -60,7 +61,7 @@ extern std::string normalize_utf8_nfc(const char *src); // Safely rename a file even if the target exists. // On Windows, the file explorer (or anti-virus or whatever else) often locks the file // for a short while, so the file may not be movable. Retry while we see recoverable errors. -extern int rename_file(const std::string &from, const std::string &to); +extern std::error_code rename_file(const std::string &from, const std::string &to); // Copy a file, adjust the access attributes, so that the target is writable. extern int copy_file(const std::string &from, const std::string &to); diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index 056212dea..5117f4bbc 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -19,6 +19,7 @@ #include #include "Technologies.hpp" +#include "Semver.hpp" typedef int64_t coord_t; typedef double coordf_t; @@ -91,6 +92,8 @@ inline std::string debug_out_path(const char *name, ...) namespace Slic3r { +extern Semver SEMVER; + template inline T unscale(Q v) { return T(v) * T(SCALING_FACTOR); } diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index f9a044338..e26ed3839 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -13,9 +13,13 @@ #include #include #include + #include #ifdef BSD #include #endif + #ifdef __APPLE__ + #include + #endif #endif #include @@ -29,7 +33,6 @@ #include #include #include -#include #include #include @@ -89,10 +92,10 @@ unsigned get_logging_level() } // Force set_logging_level(<=error) after loading of the DLL. -// Switch boost::filesystem to utf8. +// This is currently only needed if libslic3r is loaded as a shared library into Perl interpreter +// to perform unit and integration tests. static struct RunOnInit { RunOnInit() { - boost::nowide::nowide_filesystem(); set_logging_level(1); } } g_RunOnInit; @@ -170,67 +173,247 @@ const std::string& data_dir() return g_data_dir; } +#ifdef _WIN32 +// The following helpers are borrowed from the LLVM project https://github.com/llvm +namespace WindowsSupport +{ + template + class ScopedHandle { + typedef typename HandleTraits::handle_type handle_type; + handle_type Handle; + ScopedHandle(const ScopedHandle &other) = delete; + void operator=(const ScopedHandle &other) = delete; + public: + ScopedHandle() : Handle(HandleTraits::GetInvalid()) {} + explicit ScopedHandle(handle_type h) : Handle(h) {} + ~ScopedHandle() { if (HandleTraits::IsValid(Handle)) HandleTraits::Close(Handle); } + handle_type take() { + handle_type t = Handle; + Handle = HandleTraits::GetInvalid(); + return t; + } + ScopedHandle &operator=(handle_type h) { + if (HandleTraits::IsValid(Handle)) + HandleTraits::Close(Handle); + Handle = h; + return *this; + } + // True if Handle is valid. + explicit operator bool() const { return HandleTraits::IsValid(Handle) ? true : false; } + operator handle_type() const { return Handle; } + }; + + struct CommonHandleTraits { + typedef HANDLE handle_type; + static handle_type GetInvalid() { return INVALID_HANDLE_VALUE; } + static void Close(handle_type h) { ::CloseHandle(h); } + static bool IsValid(handle_type h) { return h != GetInvalid(); } + }; + + typedef ScopedHandle ScopedFileHandle; + + std::error_code map_windows_error(unsigned windows_error_code) + { + #define MAP_ERR_TO_COND(x, y) case x: return std::make_error_code(std::errc::y) + switch (windows_error_code) { + MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied); + MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists); + MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device); + MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long); + MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_CANNOT_MAKE, permission_denied); + MAP_ERR_TO_COND(ERROR_CANTOPEN, io_error); + MAP_ERR_TO_COND(ERROR_CANTREAD, io_error); + MAP_ERR_TO_COND(ERROR_CANTWRITE, io_error); + MAP_ERR_TO_COND(ERROR_CURRENT_DIRECTORY, permission_denied); + MAP_ERR_TO_COND(ERROR_DEV_NOT_EXIST, no_such_device); + MAP_ERR_TO_COND(ERROR_DEVICE_IN_USE, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_DIR_NOT_EMPTY, directory_not_empty); + MAP_ERR_TO_COND(ERROR_DIRECTORY, invalid_argument); + MAP_ERR_TO_COND(ERROR_DISK_FULL, no_space_on_device); + MAP_ERR_TO_COND(ERROR_FILE_EXISTS, file_exists); + MAP_ERR_TO_COND(ERROR_FILE_NOT_FOUND, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_HANDLE_DISK_FULL, no_space_on_device); + MAP_ERR_TO_COND(ERROR_INVALID_ACCESS, permission_denied); + MAP_ERR_TO_COND(ERROR_INVALID_DRIVE, no_such_device); + MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported); + MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument); + MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument); + MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available); + MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available); + MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument); + MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied); + MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory); + MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again); + MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error); + MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory); + MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error); + MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again); + MAP_ERR_TO_COND(ERROR_SEEK, io_error); + MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied); + MAP_ERR_TO_COND(ERROR_TOO_MANY_OPEN_FILES, too_many_files_open); + MAP_ERR_TO_COND(ERROR_WRITE_FAULT, io_error); + MAP_ERR_TO_COND(ERROR_WRITE_PROTECT, permission_denied); + MAP_ERR_TO_COND(WSAEACCES, permission_denied); + MAP_ERR_TO_COND(WSAEBADF, bad_file_descriptor); + MAP_ERR_TO_COND(WSAEFAULT, bad_address); + MAP_ERR_TO_COND(WSAEINTR, interrupted); + MAP_ERR_TO_COND(WSAEINVAL, invalid_argument); + MAP_ERR_TO_COND(WSAEMFILE, too_many_files_open); + MAP_ERR_TO_COND(WSAENAMETOOLONG, filename_too_long); + default: + return std::error_code(windows_error_code, std::system_category()); + } + #undef MAP_ERR_TO_COND + } + + static std::error_code rename_internal(HANDLE from_handle, const std::wstring &wide_to, bool replace_if_exists) + { + std::vector rename_info_buf(sizeof(FILE_RENAME_INFO) - sizeof(wchar_t) + (wide_to.size() * sizeof(wchar_t))); + FILE_RENAME_INFO &rename_info = *reinterpret_cast(rename_info_buf.data()); + rename_info.ReplaceIfExists = replace_if_exists; + rename_info.RootDirectory = 0; + rename_info.FileNameLength = DWORD(wide_to.size() * sizeof(wchar_t)); + std::copy(wide_to.begin(), wide_to.end(), &rename_info.FileName[0]); + + ::SetLastError(ERROR_SUCCESS); + if (! ::SetFileInformationByHandle(from_handle, FileRenameInfo, &rename_info, (DWORD)rename_info_buf.size())) { + unsigned Error = GetLastError(); + if (Error == ERROR_SUCCESS) + Error = ERROR_CALL_NOT_IMPLEMENTED; // Wine doesn't always set error code. + return map_windows_error(Error); + } + + return std::error_code(); + } + + static std::error_code real_path_from_handle(HANDLE H, std::wstring &buffer) + { + buffer.resize(MAX_PATH + 1); + DWORD CountChars = ::GetFinalPathNameByHandleW(H, (LPWSTR)buffer.data(), (DWORD)buffer.size() - 1, FILE_NAME_NORMALIZED); + if (CountChars > buffer.size()) { + // The buffer wasn't big enough, try again. In this case the return value *does* indicate the size of the null terminator. + buffer.resize((size_t)CountChars); + CountChars = ::GetFinalPathNameByHandleW(H, (LPWSTR)buffer.data(), (DWORD)buffer.size() - 1, FILE_NAME_NORMALIZED); + } + if (CountChars == 0) + return map_windows_error(GetLastError()); + buffer.resize(CountChars); + return std::error_code(); + } + + std::error_code rename(const std::string &from, const std::string &to) + { + // Convert to utf-16. + std::wstring wide_from = boost::nowide::widen(from); + std::wstring wide_to = boost::nowide::widen(to); + + ScopedFileHandle from_handle; + // Retry this a few times to defeat badly behaved file system scanners. + for (unsigned retry = 0; retry != 200; ++ retry) { + if (retry != 0) + ::Sleep(10); + from_handle = ::CreateFileW((LPWSTR)wide_from.data(), GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (from_handle) + break; + } + if (! from_handle) + return map_windows_error(GetLastError()); + + // We normally expect this loop to succeed after a few iterations. If it + // requires more than 200 tries, it's more likely that the failures are due to + // a true error, so stop trying. + for (unsigned retry = 0; retry != 200; ++ retry) { + auto errcode = rename_internal(from_handle, wide_to, true); + + if (errcode == std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category())) { + // Wine doesn't support SetFileInformationByHandle in rename_internal. + // Fall back to MoveFileEx. + if (std::error_code errcode2 = real_path_from_handle(from_handle, wide_from)) + return errcode2; + if (::MoveFileExW((LPCWSTR)wide_from.data(), (LPCWSTR)wide_to.data(), MOVEFILE_REPLACE_EXISTING)) + return std::error_code(); + return map_windows_error(GetLastError()); + } + + if (! errcode || errcode != std::errc::permission_denied) + return errcode; + + // The destination file probably exists and is currently open in another + // process, either because the file was opened without FILE_SHARE_DELETE or + // it is mapped into memory (e.g. using MemoryBuffer). Rename it in order to + // move it out of the way of the source file. Use FILE_FLAG_DELETE_ON_CLOSE + // to arrange for the destination file to be deleted when the other process + // closes it. + ScopedFileHandle to_handle(::CreateFileW((LPCWSTR)wide_to.data(), GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)); + if (! to_handle) { + auto errcode = map_windows_error(GetLastError()); + // Another process might have raced with us and moved the existing file + // out of the way before we had a chance to open it. If that happens, try + // to rename the source file again. + if (errcode == std::errc::no_such_file_or_directory) + continue; + return errcode; + } + + BY_HANDLE_FILE_INFORMATION FI; + if (! ::GetFileInformationByHandle(to_handle, &FI)) + return map_windows_error(GetLastError()); + + // Try to find a unique new name for the destination file. + for (unsigned unique_id = 0; unique_id != 200; ++ unique_id) { + std::wstring tmp_filename = wide_to + L".tmp" + std::to_wstring(unique_id); + std::error_code errcode = rename_internal(to_handle, tmp_filename, false); + if (errcode) { + if (errcode == std::make_error_code(std::errc::file_exists) || errcode == std::make_error_code(std::errc::permission_denied)) { + // Again, another process might have raced with us and moved the file + // before we could move it. Check whether this is the case, as it + // might have caused the permission denied error. If that was the + // case, we don't need to move it ourselves. + ScopedFileHandle to_handle2(::CreateFileW((LPCWSTR)wide_to.data(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); + if (! to_handle2) { + auto errcode = map_windows_error(GetLastError()); + if (errcode == std::errc::no_such_file_or_directory) + break; + return errcode; + } + BY_HANDLE_FILE_INFORMATION FI2; + if (! ::GetFileInformationByHandle(to_handle2, &FI2)) + return map_windows_error(GetLastError()); + if (FI.nFileIndexHigh != FI2.nFileIndexHigh || FI.nFileIndexLow != FI2.nFileIndexLow || FI.dwVolumeSerialNumber != FI2.dwVolumeSerialNumber) + break; + continue; + } + return errcode; + } + break; + } + + // Okay, the old destination file has probably been moved out of the way at + // this point, so try to rename the source file again. Still, another + // process might have raced with us to create and open the destination + // file, so we need to keep doing this until we succeed. + } + + // The most likely root cause. + return std::make_error_code(std::errc::permission_denied); + } +} // namespace WindowsSupport +#endif /* _WIN32 */ // borrowed from LVVM lib/Support/Windows/Path.inc -int rename_file(const std::string &from, const std::string &to) +std::error_code rename_file(const std::string &from, const std::string &to) { - int ec = 0; - #ifdef _WIN32 - - // Convert to utf-16. - std::wstring wide_from = boost::nowide::widen(from); - std::wstring wide_to = boost::nowide::widen(to); - - // Retry while we see recoverable errors. - // System scanners (eg. indexer) might open the source file when it is written - // and closed. - bool TryReplace = true; - - // This loop may take more than 2000 x 1ms to finish. - for (int i = 0; i < 2000; ++ i) { - if (i > 0) - // Sleep 1ms - ::Sleep(1); - if (TryReplace) { - // Try ReplaceFile first, as it is able to associate a new data stream - // with the destination even if the destination file is currently open. - if (::ReplaceFileW(wide_to.data(), wide_from.data(), NULL, 0, NULL, NULL)) - return 0; - DWORD ReplaceError = ::GetLastError(); - ec = -1; // ReplaceError - // If ReplaceFileW returned ERROR_UNABLE_TO_MOVE_REPLACEMENT or - // ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, retry but only use MoveFileExW(). - if (ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT || - ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2) { - TryReplace = false; - continue; - } - // If ReplaceFileW returned ERROR_UNABLE_TO_REMOVE_REPLACED, retry - // using ReplaceFileW(). - if (ReplaceError == ERROR_UNABLE_TO_REMOVE_REPLACED) - continue; - // We get ERROR_FILE_NOT_FOUND if the destination file is missing. - // MoveFileEx can handle this case. - if (ReplaceError != ERROR_ACCESS_DENIED && ReplaceError != ERROR_FILE_NOT_FOUND && ReplaceError != ERROR_SHARING_VIOLATION) - break; - } - if (::MoveFileExW(wide_from.c_str(), wide_to.c_str(), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) - return 0; - DWORD MoveError = ::GetLastError(); - ec = -1; // MoveError - if (MoveError != ERROR_ACCESS_DENIED && MoveError != ERROR_SHARING_VIOLATION) - break; - } - + return WindowsSupport::rename(from, to); #else - boost::nowide::remove(to.c_str()); - ec = boost::nowide::rename(from.c_str(), to.c_str()); - + return std::make_error_code(static_cast(boost::nowide::rename(from.c_str(), to.c_str()))); #endif - - return ec; } int copy_file(const std::string &from, const std::string &to) @@ -431,47 +614,82 @@ std::string format_memsize_MB(size_t n) return out + "MB"; } -#ifdef WIN32 - -#ifndef PROCESS_MEMORY_COUNTERS_EX - // MingW32 doesn't have this struct in psapi.h - typedef struct _PROCESS_MEMORY_COUNTERS_EX { - DWORD cb; - DWORD PageFaultCount; - SIZE_T PeakWorkingSetSize; - SIZE_T WorkingSetSize; - SIZE_T QuotaPeakPagedPoolUsage; - SIZE_T QuotaPagedPoolUsage; - SIZE_T QuotaPeakNonPagedPoolUsage; - SIZE_T QuotaNonPagedPoolUsage; - SIZE_T PagefileUsage; - SIZE_T PeakPagefileUsage; - SIZE_T PrivateUsage; - } PROCESS_MEMORY_COUNTERS_EX, *PPROCESS_MEMORY_COUNTERS_EX; -#endif /* PROCESS_MEMORY_COUNTERS_EX */ - -std::string log_memory_info() +// Returns platform-specific string to be used as log output or parsed in SysInfoDialog. +// The latter parses the string with (semi)colons as separators, it should look about as +// "desc1: value1; desc2: value2" or similar (spaces should not matter). +std::string log_memory_info(bool ignore_loglevel) { std::string out; - if (logSeverity <= boost::log::trivial::info) { + if (ignore_loglevel || logSeverity <= boost::log::trivial::info) { +#ifdef WIN32 + #ifndef PROCESS_MEMORY_COUNTERS_EX + // MingW32 doesn't have this struct in psapi.h + typedef struct _PROCESS_MEMORY_COUNTERS_EX { + DWORD cb; + DWORD PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivateUsage; + } PROCESS_MEMORY_COUNTERS_EX, *PPROCESS_MEMORY_COUNTERS_EX; + #endif /* PROCESS_MEMORY_COUNTERS_EX */ + + HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ::GetCurrentProcessId()); if (hProcess != nullptr) { PROCESS_MEMORY_COUNTERS_EX pmc; if (GetProcessMemoryInfo(hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc))) - out = " WorkingSet: " + format_memsize_MB(pmc.WorkingSetSize) + " PrivateBytes: " + format_memsize_MB(pmc.PrivateUsage) + " Pagefile(peak): " + format_memsize_MB(pmc.PagefileUsage) + "(" + format_memsize_MB(pmc.PeakPagefileUsage) + ")"; + out = " WorkingSet: " + format_memsize_MB(pmc.WorkingSetSize) + "; PrivateBytes: " + format_memsize_MB(pmc.PrivateUsage) + "; Pagefile(peak): " + format_memsize_MB(pmc.PagefileUsage) + "(" + format_memsize_MB(pmc.PeakPagefileUsage) + ")"; + else + out += " Used memory: N/A"; CloseHandle(hProcess); } +#elif defined(__linux__) or defined(__APPLE__) + // Get current memory usage. + #ifdef __APPLE__ + struct mach_task_basic_info info; + mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; + out += " Resident memory: "; + if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount ) == KERN_SUCCESS ) + out += format_memsize_MB((size_t)info.resident_size); + else + out += "N/A"; + #else // i.e. __linux__ + size_t tSize = 0, resident = 0, share = 0; + std::ifstream buffer("/proc/self/statm"); + if (buffer && (buffer >> tSize >> resident >> share)) { + size_t page_size = (size_t)sysconf(_SC_PAGE_SIZE); // in case x86-64 is configured to use 2MB pages + size_t rss = resident * page_size; + out += " Resident memory: " + format_memsize_MB(rss); + out += "; Shared memory: " + format_memsize_MB(share * page_size); + out += "; Private memory: " + format_memsize_MB(rss - share * page_size); + } + else + out += " Used memory: N/A"; + #endif + // Now get peak memory usage. + out += "; Peak memory usage: "; + rusage memory_info; + if (getrusage(RUSAGE_SELF, &memory_info) == 0) + { + size_t peak_mem_usage = (size_t)memory_info.ru_maxrss; + #ifdef __linux__ + peak_mem_usage *= 1024;// getrusage returns the value in kB on linux + #endif + out += format_memsize_MB(peak_mem_usage); + } + else + out += "N/A"; +#endif } return out; } -#else -std::string log_memory_info() -{ - return std::string(); -} -#endif - // Returns the size of physical memory (RAM) in bytes. // http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system size_t total_physical_memory() diff --git a/src/semver/CMakeLists.txt b/src/semver/CMakeLists.txt index e3457bf29..c273121d4 100644 --- a/src/semver/CMakeLists.txt +++ b/src/semver/CMakeLists.txt @@ -5,3 +5,5 @@ add_library(semver STATIC semver.c semver.h ) + +encoding_check(semver) diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index e3a910d6d..e51415d53 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -87,6 +87,8 @@ set(SLIC3R_GUI_SOURCES GUI/LambdaObjectDialog.hpp GUI/Tab.cpp GUI/Tab.hpp + GUI/ConfigManipulation.cpp + GUI/ConfigManipulation.hpp GUI/Field.cpp GUI/Field.hpp GUI/OptionsGroup.cpp @@ -163,6 +165,8 @@ endif () add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES}) +encoding_check(libslic3r_gui) + target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui ${GLEW_LIBRARIES}) if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY) add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE) diff --git a/src/slic3r/Config/Snapshot.cpp b/src/slic3r/Config/Snapshot.cpp index b208554b5..3757ec25b 100644 --- a/src/slic3r/Config/Snapshot.cpp +++ b/src/slic3r/Config/Snapshot.cpp @@ -366,7 +366,7 @@ const Snapshot& SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot: // Snapshot header. snapshot.time_captured = Slic3r::Utils::get_current_time_utc(); snapshot.id = Slic3r::Utils::format_time_ISO8601Z(snapshot.time_captured); - snapshot.slic3r_version_captured = *Semver::parse(SLIC3R_VERSION); // XXX: have Semver Slic3r version + snapshot.slic3r_version_captured = Slic3r::SEMVER; snapshot.comment = comment; snapshot.reason = reason; // Active presets at the time of the snapshot. diff --git a/src/slic3r/Config/Snapshot.hpp b/src/slic3r/Config/Snapshot.hpp index a916dfe92..9a7391691 100644 --- a/src/slic3r/Config/Snapshot.hpp +++ b/src/slic3r/Config/Snapshot.hpp @@ -8,8 +8,8 @@ #include +#include "libslic3r/Semver.hpp" #include "Version.hpp" -#include "../Utils/Semver.hpp" namespace Slic3r { diff --git a/src/slic3r/Config/Version.cpp b/src/slic3r/Config/Version.cpp index 865884c6f..175abff69 100644 --- a/src/slic3r/Config/Version.cpp +++ b/src/slic3r/Config/Version.cpp @@ -15,7 +15,6 @@ namespace Slic3r { namespace GUI { namespace Config { -static const Semver s_current_slic3r_semver(SLIC3R_VERSION); // Optimized lexicographic compare of two pre-release versions, ignoring the numeric suffix. static int compare_prerelease(const char *p1, const char *p2) @@ -64,7 +63,7 @@ bool Version::is_slic3r_supported(const Semver &slic3r_version) const bool Version::is_current_slic3r_supported() const { - return this->is_slic3r_supported(s_current_slic3r_semver); + return this->is_slic3r_supported(Slic3r::SEMVER); } #if 0 diff --git a/src/slic3r/Config/Version.hpp b/src/slic3r/Config/Version.hpp index 560bc29c2..19c565ffb 100644 --- a/src/slic3r/Config/Version.hpp +++ b/src/slic3r/Config/Version.hpp @@ -7,7 +7,7 @@ #include #include "libslic3r/FileParserError.hpp" -#include "../Utils/Semver.hpp" +#include "libslic3r/Semver.hpp" namespace Slic3r { namespace GUI { diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 97e200b38..5b7473980 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -609,10 +609,12 @@ void Bed3D::render_default(bool bottom) const if (!has_model && !bottom) { // draw background + glsafe(::glDepthMask(GL_FALSE)); glsafe(::glColor4f(0.35f, 0.35f, 0.35f, 0.4f)); glsafe(::glNormal3d(0.0f, 0.0f, 1.0f)); glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_vertices_data())); glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount)); + glsafe(::glDepthMask(GL_TRUE)); } // draw grid diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 3c51ca527..d6856a7a7 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -12,6 +12,7 @@ #include "libslic3r/GCode/Analyzer.hpp" #include "slic3r/GUI/PresetBundle.hpp" #include "libslic3r/Format/STL.hpp" +#include "libslic3r/Utils.hpp" #include #include @@ -24,6 +25,8 @@ #include #include +#include + #include #include @@ -74,15 +77,19 @@ void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh &mesh) } } -void GLIndexedVertexArray::finalize_geometry() const +void GLIndexedVertexArray::finalize_geometry(bool opengl_initialized) { assert(this->vertices_and_normals_interleaved_VBO_id == 0); assert(this->triangle_indices_VBO_id == 0); assert(this->quad_indices_VBO_id == 0); - this->shrink_to_fit(); + if (! opengl_initialized) { + // Shrink the data vectors to conserve memory in case the data cannot be transfered to the OpenGL driver yet. + this->shrink_to_fit(); + return; + } - if (! empty()) { + if (! this->vertices_and_normals_interleaved.empty()) { glsafe(::glGenBuffers(1, &this->vertices_and_normals_interleaved_VBO_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved.size() * 4, this->vertices_and_normals_interleaved.data(), GL_STATIC_DRAW)); @@ -124,13 +131,8 @@ void GLIndexedVertexArray::release_geometry() void GLIndexedVertexArray::render() const { - if (this->vertices_and_normals_interleaved_VBO_id == 0) - { - // sends data to gpu, if not done yet - finalize_geometry(); - if (this->vertices_and_normals_interleaved_VBO_id == 0) - return; - } + assert(this->vertices_and_normals_interleaved_VBO_id != 0); + assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)))); @@ -161,13 +163,8 @@ void GLIndexedVertexArray::render( const std::pair& tverts_range, const std::pair& qverts_range) const { - if (this->vertices_and_normals_interleaved_VBO_id == 0) - { - // sends data to gpu, if not done yet - finalize_geometry(); - if (this->vertices_and_normals_interleaved_VBO_id == 0) - return; - } + assert(this->vertices_and_normals_interleaved_VBO_id != 0); + assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0); // Render using the Vertex Buffer Objects. glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); @@ -218,6 +215,7 @@ GLVolume::GLVolume(float r, float g, float b, float a) , extruder_id(0) , selected(false) , disabled(false) + , printable(true) , is_active(true) , zoom_to_volumes(true) , shader_outside_printer_detection_enabled(false) @@ -275,6 +273,13 @@ void GLVolume::set_render_color() set_render_color(color, 4); } + if (!printable) + { + render_color[0] /= 4; + render_color[1] /= 4; + render_color[2] /= 4; + } + if (force_transparent) render_color[3] = color[3]; } @@ -415,30 +420,32 @@ bool GLVolume::is_sla_support() const { return this->composite_id.volume_id == - bool GLVolume::is_sla_pad() const { return this->composite_id.volume_id == -int(slaposBasePool); } std::vector GLVolumeCollection::load_object( - const ModelObject* model_object, + const ModelObject *model_object, int obj_idx, - const std::vector& instance_idxs, - const std::string& color_by) + const std::vector &instance_idxs, + const std::string &color_by, + bool opengl_initialized) { std::vector volumes_idx; for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx) for (int instance_idx : instance_idxs) - volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by)); + volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by, opengl_initialized)); return volumes_idx; } int GLVolumeCollection::load_object_volume( - const ModelObject* model_object, - int obj_idx, - int volume_idx, - int instance_idx, - const std::string& color_by) + const ModelObject *model_object, + int obj_idx, + int volume_idx, + int instance_idx, + const std::string &color_by, + bool opengl_initialized) { - const ModelVolume* model_volume = model_object->volumes[volume_idx]; - const int extruder_id = model_volume->extruder_id(); - const ModelInstance* instance = model_object->instances[instance_idx]; - const TriangleMesh& mesh = model_volume->mesh(); - float color[4]; + const ModelVolume *model_volume = model_object->volumes[volume_idx]; + const int extruder_id = model_volume->extruder_id(); + const ModelInstance *instance = model_object->instances[instance_idx]; + const TriangleMesh &mesh = model_volume->mesh(); + float color[4]; memcpy(color, GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3); /* if (model_volume->is_support_blocker()) { color[0] = 1.0f; @@ -455,6 +462,7 @@ int GLVolumeCollection::load_object_volume( GLVolume& v = *this->volumes.back(); v.set_color_from_model_volume(model_volume); v.indexed_vertex_array.load_mesh(mesh); + v.indexed_vertex_array.finalize_geometry(opengl_initialized); v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx); if (model_volume->is_model_part()) { @@ -475,13 +483,14 @@ int GLVolumeCollection::load_object_volume( // This function produces volumes for multiple instances in a single shot, // as some object specific mesh conversions may be expensive. void GLVolumeCollection::load_object_auxiliary( - const SLAPrintObject* print_object, + const SLAPrintObject *print_object, int obj_idx, // pairs of const std::vector>& instances, SLAPrintObjectStep milestone, // Timestamp of the last change of the milestone - size_t timestamp) + size_t timestamp, + bool opengl_initialized) { assert(print_object->is_step_done(milestone)); Transform3d mesh_trafo_inv = print_object->trafo().inverse(); @@ -495,6 +504,7 @@ void GLVolumeCollection::load_object_auxiliary( this->volumes.emplace_back(new GLVolume((milestone == slaposBasePool) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR)); GLVolume& v = *this->volumes.back(); v.indexed_vertex_array.load_mesh(mesh); + v.indexed_vertex_array.finalize_geometry(opengl_initialized); v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first); v.geometry_id = std::pair(timestamp, model_instance.id().id); // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance. @@ -511,7 +521,7 @@ void GLVolumeCollection::load_object_auxiliary( } int GLVolumeCollection::load_wipe_tower_preview( - int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width) + int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized) { if (depth < 0.01f) return int(this->volumes.size() - 1); @@ -564,6 +574,7 @@ int GLVolumeCollection::load_wipe_tower_preview( this->volumes.emplace_back(new GLVolume(color)); GLVolume& v = *this->volumes.back(); v.indexed_vertex_array.load_mesh(mesh); + v.indexed_vertex_array.finalize_geometry(opengl_initialized); v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0)); v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle)); v.composite_id = GLVolume::CompositeID(obj_idx, 0, 0); @@ -574,6 +585,23 @@ int GLVolumeCollection::load_wipe_tower_preview( return int(this->volumes.size() - 1); } +GLVolume* GLVolumeCollection::new_toolpath_volume(const float *rgba, size_t reserve_vbo_floats) +{ + GLVolume *out = new_nontoolpath_volume(rgba, reserve_vbo_floats); + out->is_extrusion_path = true; + return out; +} + +GLVolume* GLVolumeCollection::new_nontoolpath_volume(const float *rgba, size_t reserve_vbo_floats) +{ + GLVolume *out = new GLVolume(rgba); + out->is_extrusion_path = false; + // Reserving number of vertices (3x position + 3x color) + out->indexed_vertex_array.reserve(reserve_vbo_floats / 6); + this->volumes.emplace_back(out); + return out; +} + GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function filter_func) { GLVolumeWithIdAndZList list; @@ -823,6 +851,230 @@ std::vector GLVolumeCollection::get_current_print_zs(bool active_only) c return print_zs; } +size_t GLVolumeCollection::cpu_memory_used() const +{ + size_t memsize = sizeof(*this) + this->volumes.capacity() * sizeof(GLVolume); + for (const GLVolume *volume : this->volumes) + memsize += volume->cpu_memory_used(); + return memsize; +} + +size_t GLVolumeCollection::gpu_memory_used() const +{ + size_t memsize = 0; + for (const GLVolume *volume : this->volumes) + memsize += volume->gpu_memory_used(); + return memsize; +} + +std::string GLVolumeCollection::log_memory_info() const +{ + return " (GLVolumeCollection RAM: " + format_memsize_MB(this->cpu_memory_used()) + " GPU: " + format_memsize_MB(this->gpu_memory_used()) + " Both: " + format_memsize_MB(this->gpu_memory_used()) + ")"; +} + +bool can_export_to_obj(const GLVolume& volume) +{ + if (!volume.is_active || !volume.is_extrusion_path) + return false; + + if (volume.indexed_vertex_array.triangle_indices.empty() && (std::min(volume.indexed_vertex_array.triangle_indices_size, volume.tverts_range.second - volume.tverts_range.first) == 0)) + return false; + + if (volume.indexed_vertex_array.quad_indices.empty() && (std::min(volume.indexed_vertex_array.quad_indices_size, volume.qverts_range.second - volume.qverts_range.first) == 0)) + return false; + + return true; +} + +bool GLVolumeCollection::has_toolpaths_to_export() const +{ + for (const GLVolume* volume : this->volumes) + { + if (can_export_to_obj(*volume)) + return true; + } + + return false; +} + +void GLVolumeCollection::export_toolpaths_to_obj(const char* filename) const +{ + if (filename == nullptr) + return; + + if (!has_toolpaths_to_export()) + return; + + // collect color information to generate materials + std::set> colors; + for (const GLVolume* volume : this->volumes) + { + if (!can_export_to_obj(*volume)) + continue; + + std::array color; + ::memcpy((void*)color.data(), (const void*)volume->color, 4 * sizeof(float)); + colors.insert(color); + } + + // save materials file + boost::filesystem::path mat_filename(filename); + mat_filename.replace_extension("mtl"); + FILE* fp = boost::nowide::fopen(mat_filename.string().c_str(), "w"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "GLVolumeCollection::export_toolpaths_to_obj: Couldn't open " << mat_filename.string().c_str() << " for writing"; + return; + } + + fprintf(fp, "# G-Code Toolpaths Materials\n"); + fprintf(fp, "# Generated by %s based on Slic3r\n", SLIC3R_BUILD_ID); + + unsigned int colors_count = 1; + for (const std::array& color : colors) + { + fprintf(fp, "\nnewmtl material_%d\n", colors_count++); + fprintf(fp, "Ka 1 1 1\n"); + fprintf(fp, "Kd %f %f %f\n", color[0], color[1], color[2]); + fprintf(fp, "Ks 0 0 0\n"); + } + + fclose(fp); + + // save geometry file + fp = boost::nowide::fopen(filename, "w"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "GLVolumeCollection::export_toolpaths_to_obj: Couldn't open " << filename << " for writing"; + return; + } + + fprintf(fp, "# G-Code Toolpaths\n"); + fprintf(fp, "# Generated by %s based on Slic3r\n", SLIC3R_BUILD_ID); + fprintf(fp, "\nmtllib ./%s\n", mat_filename.filename().string().c_str()); + + unsigned int vertices_count = 0; + unsigned int volumes_count = 0; + + for (const GLVolume* volume : this->volumes) + { + if (!can_export_to_obj(*volume)) + continue; + + std::vector vertices_and_normals_interleaved; + std::vector triangle_indices; + std::vector quad_indices; + + if (!volume->indexed_vertex_array.vertices_and_normals_interleaved.empty()) + // data are in CPU memory + vertices_and_normals_interleaved = volume->indexed_vertex_array.vertices_and_normals_interleaved; + else if ((volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id != 0) && (volume->indexed_vertex_array.vertices_and_normals_interleaved_size != 0)) + { + // data are in GPU memory + vertices_and_normals_interleaved = std::vector(volume->indexed_vertex_array.vertices_and_normals_interleaved_size, 0.0f); + + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id)); + glsafe(::glGetBufferSubData(GL_ARRAY_BUFFER, 0, vertices_and_normals_interleaved.size() * sizeof(float), vertices_and_normals_interleaved.data())); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + } + else + continue; + + if (!volume->indexed_vertex_array.triangle_indices.empty()) + { + // data are in CPU memory + size_t size = std::min(volume->indexed_vertex_array.triangle_indices.size(), volume->tverts_range.second - volume->tverts_range.first); + if (size != 0) + { + std::vector::const_iterator it_begin = volume->indexed_vertex_array.triangle_indices.begin() + volume->tverts_range.first; + std::vector::const_iterator it_end = volume->indexed_vertex_array.triangle_indices.begin() + volume->tverts_range.first + size; + std::copy(it_begin, it_end, std::back_inserter(triangle_indices)); + } + } + else if ((volume->indexed_vertex_array.triangle_indices_VBO_id != 0) && (volume->indexed_vertex_array.triangle_indices_size != 0)) + { + // data are in GPU memory + size_t size = std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first); + if (size != 0) + { + triangle_indices = std::vector(size, 0); + + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.triangle_indices_VBO_id)); + glsafe(::glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, volume->tverts_range.first * sizeof(int), size * sizeof(int), triangle_indices.data())); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + } + } + + if (!volume->indexed_vertex_array.quad_indices.empty()) + { + // data are in CPU memory + size_t size = std::min(volume->indexed_vertex_array.quad_indices.size(), volume->qverts_range.second - volume->qverts_range.first); + if (size != 0) + { + std::vector::const_iterator it_begin = volume->indexed_vertex_array.quad_indices.begin() + volume->qverts_range.first; + std::vector::const_iterator it_end = volume->indexed_vertex_array.quad_indices.begin() + volume->qverts_range.first + size; + std::copy(it_begin, it_end, std::back_inserter(quad_indices)); + } + } + else if ((volume->indexed_vertex_array.quad_indices_VBO_id != 0) && (volume->indexed_vertex_array.quad_indices_size != 0)) + { + // data are in GPU memory + size_t size = std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first); + if (size != 0) + { + quad_indices = std::vector(size, 0); + + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.quad_indices_VBO_id)); + glsafe(::glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, volume->qverts_range.first * sizeof(int), size * sizeof(int), quad_indices.data())); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + } + } + + if (triangle_indices.empty() && quad_indices.empty()) + continue; + + fprintf(fp, "\n# vertices volume %d\n", volumes_count); + for (unsigned int i = 0; i < vertices_and_normals_interleaved.size(); i += 6) + { + fprintf(fp, "v %f %f %f\n", vertices_and_normals_interleaved[i + 3], vertices_and_normals_interleaved[i + 4], vertices_and_normals_interleaved[i + 5]); + } + + fprintf(fp, "\n# normals volume %d\n", volumes_count); + for (unsigned int i = 0; i < vertices_and_normals_interleaved.size(); i += 6) + { + fprintf(fp, "vn %f %f %f\n", vertices_and_normals_interleaved[i + 0], vertices_and_normals_interleaved[i + 1], vertices_and_normals_interleaved[i + 2]); + } + + std::array color; + ::memcpy((void*)color.data(), (const void*)volume->color, 4 * sizeof(float)); + colors.insert(color); + fprintf(fp, "\n# material volume %d\n", volumes_count); + fprintf(fp, "usemtl material_%lld\n", 1 + std::distance(colors.begin(), colors.find(color))); + + fprintf(fp, "\n# triangular facets volume %d\n", volumes_count); + for (unsigned int i = 0; i < triangle_indices.size(); i += 3) + { + int id_v1 = vertices_count + 1 + triangle_indices[i + 0]; + int id_v2 = vertices_count + 1 + triangle_indices[i + 1]; + int id_v3 = vertices_count + 1 + triangle_indices[i + 2]; + fprintf(fp, "f %d//%d %d//%d %d//%d\n", id_v1, id_v1, id_v2, id_v2, id_v3, id_v3); + } + + fprintf(fp, "\n# quadrangular facets volume %d\n", volumes_count); + for (unsigned int i = 0; i < quad_indices.size(); i += 4) + { + int id_v1 = vertices_count + 1 + quad_indices[i + 0]; + int id_v2 = vertices_count + 1 + quad_indices[i + 1]; + int id_v3 = vertices_count + 1 + quad_indices[i + 2]; + int id_v4 = vertices_count + 1 + quad_indices[i + 3]; + fprintf(fp, "f %d//%d %d//%d %d//%d %d//%d\n", id_v1, id_v1, id_v2, id_v2, id_v3, id_v3, id_v4, id_v4); + } + + ++volumes_count; + vertices_count += vertices_and_normals_interleaved.size() / 6; + } + + fclose(fp); +} + // caller is responsible for supplying NO lines with zero length static void thick_lines_to_indexed_vertex_array( const Lines &lines, @@ -1594,6 +1846,7 @@ bool GLArrow::on_init() triangles.emplace_back(7, 13, 6); m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles)); + m_volume.indexed_vertex_array.finalize_geometry(true); return true; } @@ -1707,6 +1960,7 @@ bool GLCurvedArrow::on_init() triangles.emplace_back(vertices_per_level, 2 * vertices_per_level + 1, vertices_per_level + 1); m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles)); + m_volume.indexed_vertex_array.finalize_geometry(true); return true; } @@ -1733,6 +1987,7 @@ bool GLBed::on_init_from_file(const std::string& filename) m_filename = filename; m_volume.indexed_vertex_array.load_mesh(model.mesh()); + m_volume.indexed_vertex_array.finalize_geometry(true); float color[4] = { 0.235f, 0.235f, 0.235f, 1.0f }; set_color(color, 4); @@ -1765,6 +2020,11 @@ bool _3DScene::init(wxGLCanvas* canvas) return s_canvas_mgr.init(canvas); } +void _3DScene::destroy() +{ + s_canvas_mgr.destroy(); +} + GUI::GLCanvas3D* _3DScene::get_canvas(wxGLCanvas* canvas) { return s_canvas_mgr.get_canvas(canvas); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index bd818cf35..502321163 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -65,7 +65,7 @@ public: vertices_and_normals_interleaved_VBO_id(0), triangle_indices_VBO_id(0), quad_indices_VBO_id(0) - {} + { assert(! rhs.has_VBOs()); } GLIndexedVertexArray(GLIndexedVertexArray &&rhs) : vertices_and_normals_interleaved(std::move(rhs.vertices_and_normals_interleaved)), triangle_indices(std::move(rhs.triangle_indices)), @@ -73,7 +73,7 @@ public: vertices_and_normals_interleaved_VBO_id(0), triangle_indices_VBO_id(0), quad_indices_VBO_id(0) - {} + { assert(! rhs.has_VBOs()); } ~GLIndexedVertexArray() { release_geometry(); } @@ -81,14 +81,17 @@ public: { assert(vertices_and_normals_interleaved_VBO_id == 0); assert(triangle_indices_VBO_id == 0); - assert(triangle_indices_VBO_id == 0); - this->vertices_and_normals_interleaved = rhs.vertices_and_normals_interleaved; - this->triangle_indices = rhs.triangle_indices; - this->quad_indices = rhs.quad_indices; - this->m_bounding_box = rhs.m_bounding_box; - vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size; - triangle_indices_size = rhs.triangle_indices_size; - quad_indices_size = rhs.quad_indices_size; + assert(quad_indices_VBO_id == 0); + assert(rhs.vertices_and_normals_interleaved_VBO_id == 0); + assert(rhs.triangle_indices_VBO_id == 0); + assert(rhs.quad_indices_VBO_id == 0); + this->vertices_and_normals_interleaved = rhs.vertices_and_normals_interleaved; + this->triangle_indices = rhs.triangle_indices; + this->quad_indices = rhs.quad_indices; + this->m_bounding_box = rhs.m_bounding_box; + this->vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size; + this->triangle_indices_size = rhs.triangle_indices_size; + this->quad_indices_size = rhs.quad_indices_size; return *this; } @@ -96,21 +99,24 @@ public: { assert(vertices_and_normals_interleaved_VBO_id == 0); assert(triangle_indices_VBO_id == 0); - assert(triangle_indices_VBO_id == 0); - this->vertices_and_normals_interleaved = std::move(rhs.vertices_and_normals_interleaved); - this->triangle_indices = std::move(rhs.triangle_indices); - this->quad_indices = std::move(rhs.quad_indices); - this->m_bounding_box = std::move(rhs.m_bounding_box); - vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size; - triangle_indices_size = rhs.triangle_indices_size; - quad_indices_size = rhs.quad_indices_size; + assert(quad_indices_VBO_id == 0); + assert(rhs.vertices_and_normals_interleaved_VBO_id == 0); + assert(rhs.triangle_indices_VBO_id == 0); + assert(rhs.quad_indices_VBO_id == 0); + this->vertices_and_normals_interleaved = std::move(rhs.vertices_and_normals_interleaved); + this->triangle_indices = std::move(rhs.triangle_indices); + this->quad_indices = std::move(rhs.quad_indices); + this->m_bounding_box = std::move(rhs.m_bounding_box); + this->vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size; + this->triangle_indices_size = rhs.triangle_indices_size; + this->quad_indices_size = rhs.quad_indices_size; return *this; } // Vertices and their normals, interleaved to be used by void glInterleavedArrays(GL_N3F_V3F, 0, x) - mutable std::vector vertices_and_normals_interleaved; - mutable std::vector triangle_indices; - mutable std::vector quad_indices; + std::vector vertices_and_normals_interleaved; + std::vector triangle_indices; + std::vector quad_indices; // When the geometry data is loaded into the graphics card as Vertex Buffer Objects, // the above mentioned std::vectors are cleared and the following variables keep their original length. @@ -120,9 +126,9 @@ public: // IDs of the Vertex Array Objects, into which the geometry has been loaded. // Zero if the VBOs are not sent to GPU yet. - mutable unsigned int vertices_and_normals_interleaved_VBO_id{ 0 }; - mutable unsigned int triangle_indices_VBO_id{ 0 }; - mutable unsigned int quad_indices_VBO_id{ 0 }; + unsigned int vertices_and_normals_interleaved_VBO_id{ 0 }; + unsigned int triangle_indices_VBO_id{ 0 }; + unsigned int quad_indices_VBO_id{ 0 }; void load_mesh_full_shading(const TriangleMesh &mesh); void load_mesh(const TriangleMesh& mesh) { this->load_mesh_full_shading(mesh); } @@ -142,12 +148,12 @@ public: if (this->vertices_and_normals_interleaved.size() + 6 > this->vertices_and_normals_interleaved.capacity()) this->vertices_and_normals_interleaved.reserve(next_highest_power_of_2(this->vertices_and_normals_interleaved.size() + 6)); - this->vertices_and_normals_interleaved.push_back(nx); - this->vertices_and_normals_interleaved.push_back(ny); - this->vertices_and_normals_interleaved.push_back(nz); - this->vertices_and_normals_interleaved.push_back(x); - this->vertices_and_normals_interleaved.push_back(y); - this->vertices_and_normals_interleaved.push_back(z); + this->vertices_and_normals_interleaved.emplace_back(nx); + this->vertices_and_normals_interleaved.emplace_back(ny); + this->vertices_and_normals_interleaved.emplace_back(nz); + this->vertices_and_normals_interleaved.emplace_back(x); + this->vertices_and_normals_interleaved.emplace_back(y); + this->vertices_and_normals_interleaved.emplace_back(z); this->vertices_and_normals_interleaved_size = this->vertices_and_normals_interleaved.size(); m_bounding_box.merge(Vec3f(x, y, z).cast()); @@ -168,9 +174,9 @@ public: if (this->triangle_indices.size() + 3 > this->vertices_and_normals_interleaved.capacity()) this->triangle_indices.reserve(next_highest_power_of_2(this->triangle_indices.size() + 3)); - this->triangle_indices.push_back(idx1); - this->triangle_indices.push_back(idx2); - this->triangle_indices.push_back(idx3); + this->triangle_indices.emplace_back(idx1); + this->triangle_indices.emplace_back(idx2); + this->triangle_indices.emplace_back(idx3); this->triangle_indices_size = this->triangle_indices.size(); }; @@ -181,17 +187,17 @@ public: if (this->quad_indices.size() + 4 > this->vertices_and_normals_interleaved.capacity()) this->quad_indices.reserve(next_highest_power_of_2(this->quad_indices.size() + 4)); - this->quad_indices.push_back(idx1); - this->quad_indices.push_back(idx2); - this->quad_indices.push_back(idx3); - this->quad_indices.push_back(idx4); + this->quad_indices.emplace_back(idx1); + this->quad_indices.emplace_back(idx2); + this->quad_indices.emplace_back(idx3); + this->quad_indices.emplace_back(idx4); this->quad_indices_size = this->quad_indices.size(); }; // Finalize the initialization of the geometry & indices, // upload the geometry and indices to OpenGL VBO objects // and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs. - void finalize_geometry() const; + void finalize_geometry(bool opengl_initialized); // Release the geometry data, release OpenGL VBOs. void release_geometry(); @@ -212,7 +218,7 @@ public: } // Shrink the internal storage to tighly fit the data stored. - void shrink_to_fit() const { + void shrink_to_fit() { this->vertices_and_normals_interleaved.shrink_to_fit(); this->triangle_indices.shrink_to_fit(); this->quad_indices.shrink_to_fit(); @@ -220,6 +226,22 @@ public: const BoundingBoxf3& bounding_box() const { return m_bounding_box; } + // Return an estimate of the memory consumed by this class. + size_t cpu_memory_used() const { return sizeof(*this) + vertices_and_normals_interleaved.capacity() * sizeof(float) + triangle_indices.capacity() * sizeof(int) + quad_indices.capacity() * sizeof(int); } + // Return an estimate of the memory held by GPU vertex buffers. + size_t gpu_memory_used() const + { + size_t memsize = 0; + if (this->vertices_and_normals_interleaved_VBO_id != 0) + memsize += this->vertices_and_normals_interleaved_size * 4; + if (this->triangle_indices_VBO_id != 0) + memsize += this->triangle_indices_size * 4; + if (this->quad_indices_VBO_id != 0) + memsize += this->quad_indices_size * 4; + return memsize; + } + size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); } + private: BoundingBoxf3 m_bounding_box; }; @@ -251,7 +273,7 @@ private: Geometry::Transformation m_volume_transformation; // Shift in z required by sla supports+pad - double m_sla_shift_z; + double m_sla_shift_z; // Bounding box of this volume, in unscaled coordinates. mutable BoundingBoxf3 m_transformed_bounding_box; // Whether or not is needed to recalculate the transformed bounding box. @@ -295,6 +317,8 @@ public: bool selected; // Is this object disabled from selection? bool disabled; + // Is this object printable? + bool printable; // Whether or not this volume is active for rendering bool is_active; // Whether or not to use this volume when applying zoom_to_volumes() @@ -416,18 +440,27 @@ public: bool empty() const { return this->indexed_vertex_array.empty(); } - void set_range(coordf_t low, coordf_t high); + void set_range(double low, double high); void render() const; void render(int color_id, int detection_id, int worldmatrix_id) const; - void finalize_geometry() { this->indexed_vertex_array.finalize_geometry(); } + void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); } void release_geometry() { this->indexed_vertex_array.release_geometry(); } void set_bounding_boxes_as_dirty() { m_transformed_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true; } bool is_sla_support() const; bool is_sla_pad() const; + + // Return an estimate of the memory consumed by this class. + size_t cpu_memory_used() const { + //FIXME what to do wih m_convex_hull? + return sizeof(*this) - sizeof(this->indexed_vertex_array) + this->indexed_vertex_array.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + this->offsets.capacity() * sizeof(size_t); + } + // Return an estimate of the memory held by GPU vertex buffers. + size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); } + size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); } }; typedef std::vector GLVolumePtrs; @@ -462,30 +495,36 @@ public: ~GLVolumeCollection() { clear(); }; std::vector load_object( - const ModelObject* model_object, + const ModelObject *model_object, int obj_idx, - const std::vector& instance_idxs, - const std::string& color_by); + const std::vector &instance_idxs, + const std::string &color_by, + bool opengl_initialized); int load_object_volume( - const ModelObject* model_object, - int obj_idx, - int volume_idx, - int instance_idx, - const std::string& color_by); + const ModelObject *model_object, + int obj_idx, + int volume_idx, + int instance_idx, + const std::string &color_by, + bool opengl_initialized); // Load SLA auxiliary GLVolumes (for support trees or pad). void load_object_auxiliary( - const SLAPrintObject* print_object, + const SLAPrintObject *print_object, int obj_idx, // pairs of const std::vector>& instances, SLAPrintObjectStep milestone, // Timestamp of the last change of the milestone - size_t timestamp); + size_t timestamp, + bool opengl_initialized); int load_wipe_tower_preview( - int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width); + int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized); + + GLVolume* new_toolpath_volume(const float *rgba, size_t reserve_vbo_floats = 0); + GLVolume* new_nontoolpath_volume(const float *rgba, size_t reserve_vbo_floats = 0); // Render the volumes by OpenGL. void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function filter_func = std::function()) const; @@ -493,7 +532,7 @@ public: // Finalize the initialization of the geometry & indices, // upload the geometry and indices to OpenGL VBO objects // and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs. - void finalize_geometry() { for (auto* v : volumes) v->finalize_geometry(); } + void finalize_geometry(bool opengl_initialized) { for (auto* v : volumes) v->finalize_geometry(opengl_initialized); } // Release the geometry data assigned to the volumes. // If OpenGL VBOs were allocated, an OpenGL context has to be active to release them. void release_geometry() { for (auto *v : volumes) v->release_geometry(); } @@ -521,6 +560,18 @@ public: // Returns a vector containing the sorted list of all the print_zs of the volumes contained in this collection std::vector get_current_print_zs(bool active_only) const; + // Return an estimate of the memory consumed by this class. + size_t cpu_memory_used() const; + // Return an estimate of the memory held by GPU vertex buffers. + size_t gpu_memory_used() const; + size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); } + // Return CPU, GPU and total memory log line. + std::string log_memory_info() const; + + bool has_toolpaths_to_export() const; + // Export the geometry of the GLVolumes toolpaths of this collection into the file with the given path, in obj format + void export_toolpaths_to_obj(const char* filename) const; + private: GLVolumeCollection(const GLVolumeCollection &other); GLVolumeCollection& operator=(const GLVolumeCollection &); @@ -538,6 +589,7 @@ public: GLModel(); virtual ~GLModel(); + // init() / init_from_file() shall be called with the OpenGL context active! bool init() { return on_init(); } bool init_from_file(const std::string& filename) { return on_init_from_file(filename); } @@ -567,7 +619,7 @@ protected: class GLArrow : public GLModel { protected: - virtual bool on_init(); + bool on_init() override; }; class GLCurvedArrow : public GLModel @@ -578,13 +630,13 @@ public: explicit GLCurvedArrow(unsigned int resolution); protected: - virtual bool on_init(); + bool on_init() override; }; class GLBed : public GLModel { protected: - virtual bool on_init_from_file(const std::string& filename); + bool on_init_from_file(const std::string& filename) override; }; class _3DScene @@ -599,6 +651,7 @@ public: static void remove_all_canvases(); static bool init(wxGLCanvas* canvas); + static void destroy(); static GUI::GLCanvas3D* get_canvas(wxGLCanvas* canvas); diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index 83ee28168..5b627835a 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -76,9 +76,9 @@ void CopyrightsDialog::fill_entries() { m_entries = { { "wxWidgets" , "2019 wxWidgets" , "https://www.wxwidgets.org/" }, - { "OpenGL" , "1997-2019 The Khronos™ Group Inc" , "https://www.opengl.org/" }, + { "OpenGL" , "1997-2019 The Khronosâ„¢ Group Inc" , "https://www.opengl.org/" }, { "GNU gettext" , "1998, 2019 Free Software Foundation, Inc." , "https://www.gnu.org/software/gettext/" }, - { "PoEdit" , "2019 Václav Slavík" , "https://poedit.net/" }, + { "PoEdit" , "2019 Václav Slavík" , "https://poedit.net/" }, { "ImGUI" , "2014-2019 Omar Cornut" , "https://github.com/ocornut/imgui" }, { "Eigen" , "" , "http://eigen.tuxfamily.org" }, { "ADMesh" , "1995, 1996 Anthony D. Martin; " @@ -106,8 +106,13 @@ void CopyrightsDialog::fill_entries() "2001-2016 Expat maintainers" , "http://www.libexpat.org/" }, { "AVRDUDE" , "2018 Free Software Foundation, Inc." , "http://savannah.nongnu.org/projects/avrdude" }, { "Shinyprofiler" , "2007-2010 Aidin Abedi" , "http://code.google.com/p/shinyprofiler/" }, + { "Real-Time DXT1/DXT5 C compression library" + , "Based on original by fabian \"ryg\" giesen v1.04. " + "Custom version, modified by Yann Collet" , "https://github.com/Cyan4973/RygsDXTc" }, { "Icons for STL and GCODE files." - , "Akira Yasuda" , "http://3dp0.com/icons-for-stl-and-gcode/" } + , "Akira Yasuda" , "http://3dp0.com/icons-for-stl-and-gcode/" }, + { "AppImage packaging for Linux using AppImageKit" + , "2004-2019 Simon Peter and contributors" , "https://appimage.org/" } }; } diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index dfdc79677..96213447c 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -15,9 +15,13 @@ #include #include #include +#include #include #include +#include +#include "I18N.hpp" + namespace Slic3r { static const std::string VENDOR_PREFIX = "vendor:"; @@ -58,7 +62,7 @@ void AppConfig::set_defaults() if (!get("use_legacy_opengl").empty()) erase("", "use_legacy_opengl"); -#if __APPLE__ +#ifdef __APPLE__ if (get("use_retina_opengl").empty()) set("use_retina_opengl", "1"); #endif @@ -90,7 +94,15 @@ void AppConfig::load() namespace pt = boost::property_tree; pt::ptree tree; boost::nowide::ifstream ifs(AppConfig::config_path()); - pt::read_ini(ifs, tree); + try { + pt::read_ini(ifs, tree); + } catch (pt::ptree_error& ex) { + // Error while parsing config file. We'll customize the error message and rethrow to be displayed. + throw std::runtime_error( + _utf8(L("Error parsing PrusaSlicer config file, it is probably corrupted. " + "Try to manualy delete the file to recover from the error. Your user profiles will not be affected.")) + + "\n\n" + AppConfig::config_path() + "\n\n" + ex.what()); + } // 2) Parse the property_tree, extract the sections and key / value pairs. for (const auto §ion : tree) { diff --git a/src/slic3r/GUI/AppConfig.hpp b/src/slic3r/GUI/AppConfig.hpp index 230a92294..8ad17b9db 100644 --- a/src/slic3r/GUI/AppConfig.hpp +++ b/src/slic3r/GUI/AppConfig.hpp @@ -6,7 +6,7 @@ #include #include "libslic3r/Config.hpp" -#include "slic3r/Utils/Semver.hpp" +#include "libslic3r/Semver.hpp" namespace Slic3r { diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index d5b14d59c..9697b1a94 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -153,7 +153,12 @@ void BackgroundSlicingProcess::thread_proc() } catch (CanceledException & /* ex */) { // Canceled, this is all right. assert(m_print->canceled()); - } catch (std::exception &ex) { + } catch (const std::bad_alloc& ex) { + wxString errmsg = wxString::Format(_(L("%s has encountered an error. It was likely caused by running out of memory. " + "If you are sure you have enough RAM on your system, this may also be a bug and we would " + "be glad if you reported it.")), SLIC3R_APP_NAME); + error = errmsg.ToStdString() + "\n\n" + std::string(ex.what()); + } catch (std::exception &ex) { error = ex.what(); } catch (...) { error = "Unknown C++ exception."; diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index 1177c9180..a9be260bd 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -212,7 +212,7 @@ wxPanel* BedShapePanel::init_texture_panel() wxStaticText* lbl = dynamic_cast(e.GetEventObject()); if (lbl != nullptr) { - wxString tooltip_text = (m_custom_texture == NONE) ? _(L("")) : _(m_custom_texture); + wxString tooltip_text = (m_custom_texture == NONE) ? "" : _(m_custom_texture); wxToolTip* tooltip = lbl->GetToolTip(); if ((tooltip == nullptr) || (tooltip->GetTip() != tooltip_text)) lbl->SetToolTip(tooltip_text); @@ -280,7 +280,7 @@ wxPanel* BedShapePanel::init_model_panel() wxStaticText* lbl = dynamic_cast(e.GetEventObject()); if (lbl != nullptr) { - wxString tooltip_text = (m_custom_model == NONE) ? _(L("")) : _(m_custom_model); + wxString tooltip_text = (m_custom_model == NONE) ? "" : _(m_custom_model); wxToolTip* tooltip = lbl->GetToolTip(); if ((tooltip == nullptr) || (tooltip->GetTip() != tooltip_text)) lbl->SetToolTip(tooltip_text); diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 242d00a07..8e3a6d1f1 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -22,10 +22,10 @@ namespace Slic3r { namespace GUI { const double Camera::DefaultDistance = 1000.0; -double Camera::FrustrumMinZSize = 50.0; +double Camera::FrustrumMinZRange = 50.0; +double Camera::FrustrumMinNearZ = 100.0; double Camera::FrustrumZMargin = 10.0; -double Camera::FovMinDeg = 0.5; -double Camera::FovMaxDeg = 75.0; +double Camera::MaxFovDeg = 60.0; Camera::Camera() : phi(45.0f) @@ -186,7 +186,8 @@ void Camera::apply_view_matrix() const void Camera::apply_projection(const BoundingBoxf3& box) const { - m_distance = DefaultDistance; + set_distance(DefaultDistance); + double w = 0.0; double h = 0.0; @@ -194,15 +195,14 @@ void Camera::apply_projection(const BoundingBoxf3& box) const { m_frustrum_zs = calc_tight_frustrum_zs_around(box); - w = (double)m_viewport[2]; - h = (double)m_viewport[3]; + w = 0.5 * (double)m_viewport[2]; + h = 0.5 * (double)m_viewport[3]; - double two_zoom = 2.0 * m_zoom; - if (two_zoom != 0.0) + if (m_zoom != 0.0) { - double inv_two_zoom = 1.0 / two_zoom; - w *= inv_two_zoom; - h *= inv_two_zoom; + double inv_zoom = 1.0 / m_zoom; + w *= inv_zoom; + h *= inv_zoom; } switch (m_type) @@ -226,21 +226,16 @@ void Camera::apply_projection(const BoundingBoxf3& box) const if (m_type == Perspective) { - double fov_rad = 2.0 * std::atan(h / m_frustrum_zs.first); - double fov_deg = Geometry::rad2deg(fov_rad); + double fov_deg = Geometry::rad2deg(2.0 * std::atan(h / m_frustrum_zs.first)); // adjust camera distance to keep fov in a limited range - if (fov_deg > FovMaxDeg + 0.001) + if (fov_deg > MaxFovDeg) { - double new_near_z = h / ::tan(0.5 * Geometry::deg2rad(FovMaxDeg)); - m_distance += (new_near_z - m_frustrum_zs.first); - apply_view_matrix(); - } - else if (fov_deg < FovMinDeg - 0.001) - { - double new_near_z = h / ::tan(0.5 * Geometry::deg2rad(FovMinDeg)); - m_distance += (new_near_z - m_frustrum_zs.first); - apply_view_matrix(); + double delta_z = h / ::tan(0.5 * Geometry::deg2rad(MaxFovDeg)) - m_frustrum_zs.first; + if (delta_z > 0.001) + set_distance(m_distance + delta_z); + else + break; } else break; @@ -328,42 +323,50 @@ void Camera::debug_render() const std::pair Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const { - std::pair ret = std::make_pair(DBL_MAX, -DBL_MAX); + std::pair ret; - Vec3d bb_min = box.min; - Vec3d bb_max = box.max; - - // box vertices in world space - std::vector vertices; - vertices.reserve(8); - vertices.push_back(bb_min); - vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2)); - vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2)); - vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2)); - vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2)); - vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2)); - vertices.push_back(bb_max); - vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2)); - - // set the Z range in eye coordinates (negative Zs are in front of the camera) - for (const Vec3d& v : vertices) + while (true) { - double z = -(m_view_matrix * v)(2); - ret.first = std::min(ret.first, z); - ret.second = std::max(ret.second, z); - } + ret = std::make_pair(DBL_MAX, -DBL_MAX); - // apply margin - ret.first -= FrustrumZMargin; - ret.second += FrustrumZMargin; + // box vertices in world space + std::vector vertices; + vertices.reserve(8); + vertices.push_back(box.min); + vertices.emplace_back(box.max(0), box.min(1), box.min(2)); + vertices.emplace_back(box.max(0), box.max(1), box.min(2)); + vertices.emplace_back(box.min(0), box.max(1), box.min(2)); + vertices.emplace_back(box.min(0), box.min(1), box.max(2)); + vertices.emplace_back(box.max(0), box.min(1), box.max(2)); + vertices.push_back(box.max); + vertices.emplace_back(box.min(0), box.max(1), box.max(2)); - // ensure min size - if (ret.second - ret.first < FrustrumMinZSize) - { - double mid_z = 0.5 * (ret.first + ret.second); - double half_size = 0.5 * FrustrumMinZSize; - ret.first = mid_z - half_size; - ret.second = mid_z + half_size; + // set the Z range in eye coordinates (negative Zs are in front of the camera) + for (const Vec3d& v : vertices) + { + double z = -(m_view_matrix * v)(2); + ret.first = std::min(ret.first, z); + ret.second = std::max(ret.second, z); + } + + // apply margin + ret.first -= FrustrumZMargin; + ret.second += FrustrumZMargin; + + // ensure min size + if (ret.second - ret.first < FrustrumMinZRange) + { + double mid_z = 0.5 * (ret.first + ret.second); + double half_size = 0.5 * FrustrumMinZRange; + ret.first = mid_z - half_size; + ret.second = mid_z + half_size; + } + + if (ret.first >= FrustrumMinNearZ) + break; + + // ensure min Near Z + set_distance(m_distance + FrustrumMinNearZ - ret.first); } return ret; @@ -385,21 +388,19 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca Vec3d up = get_dir_up(); Vec3d forward = get_dir_forward(); - Vec3d bb_min = box.min; - Vec3d bb_max = box.max; Vec3d bb_center = box.center(); // box vertices in world space std::vector vertices; vertices.reserve(8); - vertices.push_back(bb_min); - vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2)); - vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2)); - vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2)); - vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2)); - vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2)); - vertices.push_back(bb_max); - vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2)); + vertices.push_back(box.min); + vertices.emplace_back(box.max(0), box.min(1), box.min(2)); + vertices.emplace_back(box.max(0), box.max(1), box.min(2)); + vertices.emplace_back(box.min(0), box.max(1), box.min(2)); + vertices.emplace_back(box.min(0), box.min(1), box.max(2)); + vertices.emplace_back(box.max(0), box.min(1), box.max(2)); + vertices.push_back(box.max); + vertices.emplace_back(box.min(0), box.max(1), box.max(2)); double max_x = 0.0; double max_y = 0.0; @@ -430,6 +431,12 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca return std::min((double)canvas_w / (2.0 * max_x), (double)canvas_h / (2.0 * max_y)); } +void Camera::set_distance(double distance) const +{ + m_distance = distance; + apply_view_matrix(); +} + } // GUI } // Slic3r diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 79e87c726..839d0d6cf 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -10,10 +10,10 @@ namespace GUI { struct Camera { static const double DefaultDistance; - static double FrustrumMinZSize; + static double FrustrumMinZRange; + static double FrustrumMinNearZ; static double FrustrumZMargin; - static double FovMinDeg; - static double FovMaxDeg; + static double MaxFovDeg; enum EType : unsigned char { @@ -101,6 +101,7 @@ private: // the camera MUST be outside of the bounding box in eye coordinate of the given box std::pair calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const; double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const; + void set_distance(double distance) const; }; } // GUI diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp new file mode 100644 index 000000000..236460dd2 --- /dev/null +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -0,0 +1,373 @@ +// #include "libslic3r/GCodeSender.hpp" +#include "ConfigManipulation.hpp" +#include "I18N.hpp" +#include "GUI_App.hpp" +#include "PresetBundle.hpp" + +#include + +namespace Slic3r { +namespace GUI { + +void ConfigManipulation::apply(DynamicPrintConfig* config, DynamicPrintConfig* new_config) +{ + bool modified = false; + for (auto opt_key : config->diff(*new_config)) { + config->set_key_value(opt_key, new_config->option(opt_key)->clone()); + modified = true; + } + + if (modified && load_config != nullptr) + load_config(); +} + +void ConfigManipulation::toggle_field(const std::string& opt_key, const bool toggle, int opt_index/* = -1*/) +{ + if (local_config) { + if (local_config->option(opt_key) == nullptr) + return; + } + Field* field = get_field(opt_key, opt_index); + if (field==nullptr) return; + field->toggle(toggle); +} + +void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config) +{ + // #ys_FIXME_to_delete + //! Temporary workaround for the correct updates of the TextCtrl (like "layer_height"): + // KillFocus() for the wxSpinCtrl use CallAfter function. So, + // to except the duplicate call of the update() after dialog->ShowModal(), + // let check if this process is already started. + if (is_msg_dlg_already_exist) + return; + + // layer_height shouldn't be equal to zero + if (config->opt_float("layer_height") < EPSILON) + { + const wxString msg_text = _(L("Zero layer height is not valid.\n\nThe layer height will be reset to 0.01.")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK); + DynamicPrintConfig new_conf = *config; + is_msg_dlg_already_exist = true; + dialog->ShowModal(); + new_conf.set_key_value("layer_height", new ConfigOptionFloat(0.01)); + apply(config, &new_conf); + is_msg_dlg_already_exist = false; + } + + if (fabs(config->option("first_layer_height")->value - 0) < EPSILON) + { + const wxString msg_text = _(L("Zero first layer height is not valid.\n\nThe first layer height will be reset to 0.01.")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("First layer height")), wxICON_WARNING | wxOK); + DynamicPrintConfig new_conf = *config; + is_msg_dlg_already_exist = true; + dialog->ShowModal(); + new_conf.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(0.01, false)); + apply(config, &new_conf); + is_msg_dlg_already_exist = false; + } + + double fill_density = config->option("fill_density")->value; + + if (config->opt_bool("spiral_vase") && + !(config->opt_int("perimeters") == 1 && config->opt_int("top_solid_layers") == 0 && + fill_density == 0)) { + wxString msg_text = _(L("The Spiral Vase mode requires:\n" + "- one perimeter\n" + "- no top solid layers\n" + "- 0% fill density\n" + "- no support material\n" + "- no ensure_vertical_shell_thickness")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable Spiral Vase?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Spiral Vase")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); + DynamicPrintConfig new_conf = *config; + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { + new_conf.set_key_value("perimeters", new ConfigOptionInt(1)); + new_conf.set_key_value("top_solid_layers", new ConfigOptionInt(0)); + new_conf.set_key_value("fill_density", new ConfigOptionPercent(0)); + new_conf.set_key_value("support_material", new ConfigOptionBool(false)); + new_conf.set_key_value("support_material_enforce_layers", new ConfigOptionInt(0)); + new_conf.set_key_value("ensure_vertical_shell_thickness", new ConfigOptionBool(false)); + fill_density = 0; + } + else { + new_conf.set_key_value("spiral_vase", new ConfigOptionBool(false)); + } + apply(config, &new_conf); + if (cb_value_change) + cb_value_change("fill_density", fill_density); + } + + if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && + config->opt_float("support_material_contact_distance") > 0. && + (config->opt_int("support_material_extruder") != 0 || config->opt_int("support_material_interface_extruder") != 0)) { + wxString msg_text = _(L("The Wipe Tower currently supports the non-soluble supports only\n" + "if they are printed with the current extruder without triggering a tool change.\n" + "(both support_material_extruder and support_material_interface_extruder need to be set to 0).")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable the Wipe Tower?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Wipe Tower")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); + DynamicPrintConfig new_conf = *config; + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { + new_conf.set_key_value("support_material_extruder", new ConfigOptionInt(0)); + new_conf.set_key_value("support_material_interface_extruder", new ConfigOptionInt(0)); + } + else + new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); + apply(config, &new_conf); + } + + if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && + config->opt_float("support_material_contact_distance") == 0 && + !config->opt_bool("support_material_synchronize_layers")) { + wxString msg_text = _(L("For the Wipe Tower to work with the soluble supports, the support layers\n" + "need to be synchronized with the object layers.")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I synchronize support layers in order to enable the Wipe Tower?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Wipe Tower")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); + DynamicPrintConfig new_conf = *config; + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { + new_conf.set_key_value("support_material_synchronize_layers", new ConfigOptionBool(true)); + } + else + new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); + apply(config, &new_conf); + } + + if (config->opt_bool("support_material")) { + // Ask only once. + if (!support_material_overhangs_queried) { + support_material_overhangs_queried = true; + if (!config->opt_bool("overhangs")/* != 1*/) { + wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n" + "- Detect bridging perimeters")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I adjust those settings for supports?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Support Generator")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO | wxCANCEL : wxOK)); + DynamicPrintConfig new_conf = *config; + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { + // Enable "detect bridging perimeters". + new_conf.set_key_value("overhangs", new ConfigOptionBool(true)); + } + else if (answer == wxID_NO) { + // Do nothing, leave supports on and "detect bridging perimeters" off. + } + else if (answer == wxID_CANCEL) { + // Disable supports. + new_conf.set_key_value("support_material", new ConfigOptionBool(false)); + support_material_overhangs_queried = false; + } + apply(config, &new_conf); + } + } + } + else { + support_material_overhangs_queried = false; + } + + if (config->option("fill_density")->value == 100) { + auto fill_pattern = config->option>("fill_pattern")->value; + std::string str_fill_pattern = ""; + t_config_enum_values map_names = config->option>("fill_pattern")->get_enum_values(); + for (auto it : map_names) { + if (fill_pattern == it.second) { + str_fill_pattern = it.first; + break; + } + } + if (!str_fill_pattern.empty()) { + const std::vector& external_fill_pattern = config->def()->get("top_fill_pattern")->enum_values; + bool correct_100p_fill = false; + for (const std::string& fill : external_fill_pattern) + { + if (str_fill_pattern == fill) + correct_100p_fill = true; + } + // get fill_pattern name from enum_labels for using this one at dialog_msg + str_fill_pattern = _utf8(config->def()->get("fill_pattern")->enum_labels[fill_pattern]); + if (!correct_100p_fill) { + wxString msg_text = GUI::from_u8((boost::format(_utf8(L("The %1% infill pattern is not supposed to work at 100%% density."))) % str_fill_pattern).str()); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I switch to rectilinear fill pattern?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Infill")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK) ); + DynamicPrintConfig new_conf = *config; + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { + new_conf.set_key_value("fill_pattern", new ConfigOptionEnum(ipRectilinear)); + fill_density = 100; + } + else + fill_density = wxGetApp().preset_bundle->prints.get_selected_preset().config.option("fill_density")->value; + new_conf.set_key_value("fill_density", new ConfigOptionPercent(fill_density)); + apply(config, &new_conf); + if (cb_value_change) + cb_value_change("fill_density", fill_density); + } + } + } +} + +void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) +{ + bool have_perimeters = config->opt_int("perimeters") > 0; + for (auto el : { "extra_perimeters", "ensure_vertical_shell_thickness", "thin_walls", "overhangs", + "seam_position", "external_perimeters_first", "external_perimeter_extrusion_width", + "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed" }) + toggle_field(el, have_perimeters); + + bool have_infill = config->option("fill_density")->value > 0; + // infill_extruder uses the same logic as in Print::extruders() + for (auto el : { "fill_pattern", "infill_every_layers", "infill_only_where_needed", + "solid_infill_every_layers", "solid_infill_below_area", "infill_extruder" }) + toggle_field(el, have_infill); + + bool have_solid_infill = config->opt_int("top_solid_layers") > 0 || config->opt_int("bottom_solid_layers") > 0; + // solid_infill_extruder uses the same logic as in Print::extruders() + for (auto el : { "top_fill_pattern", "bottom_fill_pattern", "infill_first", "solid_infill_extruder", + "solid_infill_extrusion_width", "solid_infill_speed" }) + toggle_field(el, have_solid_infill); + + for (auto el : { "fill_angle", "bridge_angle", "infill_extrusion_width", + "infill_speed", "bridge_speed" }) + toggle_field(el, have_infill || have_solid_infill); + + toggle_field("gap_fill_speed", have_perimeters && have_infill); + + bool have_top_solid_infill = config->opt_int("top_solid_layers") > 0; + for (auto el : { "top_infill_extrusion_width", "top_solid_infill_speed" }) + toggle_field(el, have_top_solid_infill); + + bool have_default_acceleration = config->opt_float("default_acceleration") > 0; + for (auto el : { "perimeter_acceleration", "infill_acceleration", + "bridge_acceleration", "first_layer_acceleration" }) + toggle_field(el, have_default_acceleration); + + bool have_skirt = config->opt_int("skirts") > 0 || config->opt_float("min_skirt_length") > 0; + for (auto el : { "skirt_distance", "skirt_height" }) + toggle_field(el, have_skirt); + + bool have_brim = config->opt_float("brim_width") > 0; + // perimeter_extruder uses the same logic as in Print::extruders() + toggle_field("perimeter_extruder", have_perimeters || have_brim); + + bool have_raft = config->opt_int("raft_layers") > 0; + bool have_support_material = config->opt_bool("support_material") || have_raft; + bool have_support_material_auto = have_support_material && config->opt_bool("support_material_auto"); + bool have_support_interface = config->opt_int("support_material_interface_layers") > 0; + bool have_support_soluble = have_support_material && config->opt_float("support_material_contact_distance") == 0; + for (auto el : { "support_material_pattern", "support_material_with_sheath", + "support_material_spacing", "support_material_angle", "support_material_interface_layers", + "dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance", + "support_material_xy_spacing" }) + toggle_field(el, have_support_material); + toggle_field("support_material_threshold", have_support_material_auto); + + for (auto el : { "support_material_interface_spacing", "support_material_interface_extruder", + "support_material_interface_speed", "support_material_interface_contact_loops" }) + toggle_field(el, have_support_material && have_support_interface); + toggle_field("support_material_synchronize_layers", have_support_soluble); + + toggle_field("perimeter_extrusion_width", have_perimeters || have_skirt || have_brim); + toggle_field("support_material_extruder", have_support_material || have_skirt); + toggle_field("support_material_speed", have_support_material || have_brim || have_skirt); + + bool have_sequential_printing = config->opt_bool("complete_objects"); + for (auto el : { "extruder_clearance_radius", "extruder_clearance_height" }) + toggle_field(el, have_sequential_printing); + + bool have_ooze_prevention = config->opt_bool("ooze_prevention"); + toggle_field("standby_temperature_delta", have_ooze_prevention); + + bool have_wipe_tower = config->opt_bool("wipe_tower"); + for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging" }) + toggle_field(el, have_wipe_tower); +} + +void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/) +{ + double head_penetration = config->opt_float("support_head_penetration"); + double head_width = config->opt_float("support_head_width"); + if (head_penetration > head_width) { + wxString msg_text = _(L("Head penetration should not be greater than the head width.")); + + auto dialog = new wxMessageDialog(nullptr, + msg_text, + _(L("Invalid Head penetration")), + wxICON_WARNING | wxOK); + + DynamicPrintConfig new_conf = *config; + if (dialog->ShowModal() == wxID_OK) { + new_conf.set_key_value("support_head_penetration", new ConfigOptionFloat(head_width)); + apply(config, &new_conf); + } + } + + double pinhead_d = config->opt_float("support_head_front_diameter"); + double pillar_d = config->opt_float("support_pillar_diameter"); + if (pinhead_d > pillar_d) { + wxString msg_text = _(L("Pinhead diameter should be smaller than the pillar diameter.")); + + auto dialog = new wxMessageDialog(nullptr, + msg_text, + _(L("Invalid pinhead diameter")), + wxICON_WARNING | wxOK); + + DynamicPrintConfig new_conf = *config; + if (dialog->ShowModal() == wxID_OK) { + new_conf.set_key_value("support_head_front_diameter", new ConfigOptionFloat(pillar_d / 2.0)); + apply(config, &new_conf); + } + } +} + +void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config) +{ + bool supports_en = config->opt_bool("supports_enable"); + + toggle_field("support_head_front_diameter", supports_en); + toggle_field("support_head_penetration", supports_en); + toggle_field("support_head_width", supports_en); + toggle_field("support_pillar_diameter", supports_en); + toggle_field("support_pillar_connection_mode", supports_en); + toggle_field("support_buildplate_only", supports_en); + toggle_field("support_base_diameter", supports_en); + toggle_field("support_base_height", supports_en); + toggle_field("support_base_safety_distance", supports_en); + toggle_field("support_critical_angle", supports_en); + toggle_field("support_max_bridge_length", supports_en); + toggle_field("support_max_pillar_link_distance", supports_en); + toggle_field("support_points_density_relative", supports_en); + toggle_field("support_points_minimal_distance", supports_en); + + bool pad_en = config->opt_bool("pad_enable"); + + toggle_field("pad_wall_thickness", pad_en); + toggle_field("pad_wall_height", pad_en); + toggle_field("pad_max_merge_distance", pad_en); + // toggle_field("pad_edge_radius", supports_en); + toggle_field("pad_wall_slope", pad_en); + toggle_field("pad_zero_elevation", pad_en); + + bool has_suppad = pad_en && supports_en; + bool zero_elev = config->opt_bool("pad_zero_elevation") && has_suppad; + + toggle_field("support_object_elevation", supports_en && !zero_elev); + toggle_field("pad_object_gap", zero_elev); + toggle_field("pad_object_connector_stride", zero_elev); + toggle_field("pad_object_connector_width", zero_elev); + toggle_field("pad_object_connector_penetration", zero_elev); +} + + +} // GUI +} // Slic3r diff --git a/src/slic3r/GUI/ConfigManipulation.hpp b/src/slic3r/GUI/ConfigManipulation.hpp new file mode 100644 index 000000000..1dbadc2bd --- /dev/null +++ b/src/slic3r/GUI/ConfigManipulation.hpp @@ -0,0 +1,62 @@ +#ifndef slic3r_ConfigManipulation_hpp_ +#define slic3r_ConfigManipulation_hpp_ + +/* Class for validation config options + * and update (enable/disable) IU components + * + * Used for config validation for global config (Print Settings Tab) + * and local config (overrides options on sidebar) + * */ + +#include "libslic3r/PrintConfig.hpp" +#include "Field.hpp" +//#include + +namespace Slic3r { +namespace GUI { + +class ConfigManipulation +{ + bool is_msg_dlg_already_exist{ false }; + bool support_material_overhangs_queried{ false }; + + // function to loading of changed configuration + std::function load_config = nullptr; + std::function get_field = nullptr; + // callback to propagation of changed value, if needed + std::function cb_value_change = nullptr; + DynamicPrintConfig* local_config = nullptr; + +public: + ConfigManipulation(std::function load_config, + std::function get_field, + std::function cb_value_change, + DynamicPrintConfig* local_config = nullptr) : + load_config(load_config), + get_field(get_field), + cb_value_change(cb_value_change), + local_config(local_config) {} + ConfigManipulation() {} + + ~ConfigManipulation() { + load_config = nullptr; + get_field = nullptr; + cb_value_change = nullptr; + } + + void apply(DynamicPrintConfig* config, DynamicPrintConfig* new_config); + void toggle_field(const std::string& field_key, const bool toggle, int opt_index = -1); + + // FFF print + void update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config = false); + void toggle_print_fff_options(DynamicPrintConfig* config); + + // SLA print + void update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config = false); + void toggle_print_sla_options(DynamicPrintConfig* config); +}; + +} // GUI +} // Slic3r + +#endif /* slic3r_ConfigManipulation_hpp_ */ diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index fcf15d3c7..eca95b5be 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -25,6 +25,7 @@ #include "PresetBundle.hpp" #include "GUI.hpp" #include "GUI_Utils.hpp" +#include "slic3r/Config/Snapshot.hpp" #include "slic3r/Utils/PresetUpdater.hpp" @@ -33,6 +34,10 @@ namespace GUI { #define MAIN_VENDOR "None" +using Config::Snapshot; +using Config::SnapshotDB; + + // Printer model picker GUI control struct PrinterPickerEvent : public wxEvent @@ -1001,15 +1006,33 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese // Decide whether to create snapshot based on run_reason and the reset profile checkbox bool snapshot = true; + Snapshot::Reason snapshot_reason = Snapshot::SNAPSHOT_UPGRADE; switch (run_reason) { - case ConfigWizard::RR_DATA_EMPTY: snapshot = false; break; - case ConfigWizard::RR_DATA_LEGACY: snapshot = true; break; - case ConfigWizard::RR_DATA_INCOMPAT: snapshot = false; break; // In this case snapshot is done by PresetUpdater with the appropriate reason - case ConfigWizard::RR_USER: snapshot = page_welcome->reset_user_profile(); break; + case ConfigWizard::RR_DATA_EMPTY: + snapshot = false; + break; + case ConfigWizard::RR_DATA_LEGACY: + snapshot = true; + break; + case ConfigWizard::RR_DATA_INCOMPAT: + // In this case snapshot has already been taken by + // PresetUpdater with the appropriate reason + snapshot = false; + break; + case ConfigWizard::RR_USER: + snapshot = page_welcome->reset_user_profile(); + snapshot_reason = Snapshot::SNAPSHOT_USER; + break; } + + if (snapshot) { + SnapshotDB::singleton().take_snapshot(*app_config, snapshot_reason); + } + if (install_bundles.size() > 0) { // Install bundles from resources. - updater->install_bundles_rsrc(std::move(install_bundles), snapshot); + // Don't create snapshot - we've already done that above if applicable. + updater->install_bundles_rsrc(std::move(install_bundles), false); } else { BOOST_LOG_TRIVIAL(info) << "No bundles need to be installed from resources"; } diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 19f0edcbe..8381282c5 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -206,8 +206,8 @@ void Field::get_value_by_opt_type(wxString& str) const wxString msg_text = wxString::Format(_(L("Do you mean %s%% instead of %s %s?\n" "Select YES if you want to change this value to %s%%, \n" "or NO if you are sure that %s %s is a correct value.")), stVal, stVal, sidetext, stVal, stVal, sidetext); - auto dialog = new wxMessageDialog(m_parent, msg_text, _(L("Parameter validation")), wxICON_WARNING | wxYES | wxNO); - if (dialog->ShowModal() == wxID_YES) { + wxMessageDialog dialog(m_parent, msg_text, _(L("Parameter validation")), wxICON_WARNING | wxYES | wxNO); + if (dialog.ShowModal() == wxID_YES) { set_value(wxString::Format("%s%%", stVal), false/*true*/); str += "%%"; } @@ -393,6 +393,12 @@ void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/) else dynamic_cast(window)->SetValue(boost::any_cast(value)); m_disable_change_event = false; + + if (!change_event) { + wxString ret_str = static_cast(window)->GetValue(); + // update m_value to correct work of next value_was_changed() + get_value_by_opt_type(ret_str); + } } void TextCtrl::set_last_meaningful_value() @@ -410,7 +416,7 @@ void TextCtrl::set_na_value() boost::any& TextCtrl::get_value() { wxString ret_str = static_cast(window)->GetValue(); - // modifies ret_string! + // update m_value get_value_by_opt_type(ret_str); return m_value; @@ -553,7 +559,16 @@ void SpinCtrl::BUILD() { break; } - const int min_val = m_opt.min == INT_MIN ? 0: m_opt.min; + const int min_val = m_opt.min == INT_MIN +#ifdef __WXOSX__ + // We will forcibly set the input value for SpinControl, since the value + // inserted from the keyboard is not updated under OSX. + // So, we can't set min control value bigger then 0. + // Otherwise, it couldn't be possible to input from keyboard value + // less then min_val. + || m_opt.min > 0 +#endif + ? 0 : m_opt.min; const int max_val = m_opt.max < 2147483647 ? m_opt.max : 2147483647; auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, @@ -622,11 +637,24 @@ void SpinCtrl::BUILD() { void SpinCtrl::propagate_value() { + if (suppress_propagation) + return; + + suppress_propagation = true; if (tmp_value == UNDEF_VALUE) { on_kill_focus(); } else { +#ifdef __WXOSX__ + // check input value for minimum + if (m_opt.min > 0 && tmp_value < m_opt.min) { + wxSpinCtrl* spin = static_cast(window); + spin->SetValue(m_opt.min); + spin->GetText()->SetInsertionPointEnd(); + } +#endif on_change_field(); } + suppress_propagation = false; } void SpinCtrl::msw_rescale() @@ -946,7 +974,7 @@ boost::any& Choice::get_value() wxString ret_str = field->GetValue(); // options from right panel - std::vector right_panel_options{ "support", "scale_unit" }; + std::vector right_panel_options{ "support", "pad", "scale_unit" }; for (auto rp_option: right_panel_options) if (m_opt_id == rp_option) return m_value = boost::any(ret_str); @@ -1050,11 +1078,12 @@ void ColourPicker::BUILD() // Validate the color wxString clr_str(m_opt.get_default_value()->get_at(m_opt_idx)); wxColour clr(clr_str); - if (! clr.IsOk()) { + if (clr_str.IsEmpty() || !clr.IsOk()) { clr = wxTransparentColour; } auto temp = new wxColourPickerCtrl(m_parent, wxID_ANY, clr, wxDefaultPosition, size); + temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); temp->SetBackgroundStyle(wxBG_STYLE_PAINT); // // recast as a wxWindow to fit the calling convention @@ -1065,17 +1094,60 @@ void ColourPicker::BUILD() temp->SetToolTip(get_tooltip_text(clr_str)); } +void ColourPicker::set_undef_value(wxColourPickerCtrl* field) +{ + field->SetColour(wxTransparentColour); + + wxButton* btn = dynamic_cast(field->GetPickerCtrl()); + wxBitmap bmp = btn->GetBitmap(); + wxMemoryDC dc(bmp); + if (!dc.IsOk()) return; + dc.SetTextForeground(*wxWHITE); + dc.SetFont(wxGetApp().normal_font()); + + const wxRect rect = wxRect(0, 0, bmp.GetWidth(), bmp.GetHeight()); + dc.DrawLabel("undef", rect, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL); + + dc.SelectObject(wxNullBitmap); + btn->SetBitmapLabel(bmp); +} + +void ColourPicker::set_value(const boost::any& value, bool change_event) +{ + m_disable_change_event = !change_event; + const wxString clr_str(boost::any_cast(value)); + auto field = dynamic_cast(window); + + wxColour clr(clr_str); + if (clr_str.IsEmpty() || !clr.IsOk()) + set_undef_value(field); + else + field->SetColour(clr); + + m_disable_change_event = false; +} + boost::any& ColourPicker::get_value() { -// boost::any m_value; - auto colour = static_cast(window)->GetColour(); - auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), colour.Red(), colour.Green(), colour.Blue()); - m_value = clr_str.ToStdString(); - + if (colour == wxTransparentColour) + m_value = std::string(""); + else { + auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), colour.Red(), colour.Green(), colour.Blue()); + m_value = clr_str.ToStdString(); + } return m_value; } +void ColourPicker::msw_rescale() +{ + Field::msw_rescale(); + + wxColourPickerCtrl* field = dynamic_cast(window); + if (field->GetColour() == wxTransparentColour) + set_undef_value(field); +} + void PointCtrl::BUILD() { auto temp = new wxBoxSizer(wxHORIZONTAL); diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 8e8ad3795..ab31fa48a 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -336,6 +336,8 @@ class SpinCtrl : public Field { using Field::Field; private: static const int UNDEF_VALUE = INT_MIN; + + bool suppress_propagation {false}; public: SpinCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id), tmp_value(UNDEF_VALUE) {} SpinCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id), tmp_value(UNDEF_VALUE) {} @@ -409,6 +411,8 @@ public: class ColourPicker : public Field { using Field::Field; + + void set_undef_value(wxColourPickerCtrl* field); public: ColourPicker(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} ColourPicker(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} @@ -422,13 +426,9 @@ public: dynamic_cast(window)->SetColour(value); m_disable_change_event = false; } - void set_value(const boost::any& value, bool change_event = false) { - m_disable_change_event = !change_event; - dynamic_cast(window)->SetColour(boost::any_cast(value)); - m_disable_change_event = false; - } - + void set_value(const boost::any& value, bool change_event = false) override; boost::any& get_value() override; + void msw_rescale() override; void enable() override { dynamic_cast(window)->Enable(); }; void disable() override{ dynamic_cast(window)->Disable(); }; diff --git a/src/slic3r/GUI/FirmwareDialog.cpp b/src/slic3r/GUI/FirmwareDialog.cpp index 7865aecf2..d1f2da040 100644 --- a/src/slic3r/GUI/FirmwareDialog.cpp +++ b/src/slic3r/GUI/FirmwareDialog.cpp @@ -354,7 +354,7 @@ bool FirmwareDialog::priv::check_model_id() // Therefore, regretably, so far the check cannot be used and we just return true here. // TODO: Rewrite Serial using more platform-native code. return true; - + // if (hex_file.model_id.empty()) { // // No data to check against, assume it's ok // return true; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fbb33fa16..081d866d0 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -70,6 +70,11 @@ static const float ERROR_BG_DARK_COLOR[3] = { 0.478f, 0.192f, 0.039f }; static const float ERROR_BG_LIGHT_COLOR[3] = { 0.753f, 0.192f, 0.039f }; //static const float AXES_COLOR[3][3] = { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f } }; +// Number of floats +static const float MAX_VERTEX_BUFFER_SIZE = 131072 * 6; // 3.15MB +// Reserve size in number of floats. +static const float VERTEX_BUFFER_RESERVE_SIZE = 131072 * 2; // 1.05MB + namespace Slic3r { namespace GUI { @@ -1234,10 +1239,9 @@ bool GLCanvas3D::init() return false; } -// // on linux the gl context is not valid until the canvas is not shown on screen -// // we defer the geometry finalization of volumes until the first call to render() -// if (!m_volumes.empty()) -// m_volumes.finalize_geometry(); + // on linux the gl context is not valid until the canvas is not shown on screen + // we defer the geometry finalization of volumes until the first call to render() + m_volumes.finalize_geometry(true); if (m_gizmos.is_enabled() && !m_gizmos.init()) std::cout << "Unable to initialize gizmos: please, check that all the required textures are available" << std::endl; @@ -1320,6 +1324,26 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject _set_warning_texture(WarningTexture::SomethingNotShown, false); } +void GLCanvas3D::update_instance_printable_state_for_object(const size_t obj_idx) +{ + ModelObject* model_object = m_model->objects[obj_idx]; + for (int inst_idx = 0; inst_idx < model_object->instances.size(); inst_idx++) + { + ModelInstance* instance = model_object->instances[inst_idx]; + + for (GLVolume* volume : m_volumes.volumes) + { + if ((volume->object_idx() == obj_idx) && (volume->instance_idx() == inst_idx)) + volume->printable = instance->printable; + } + } +} + +void GLCanvas3D::update_instance_printable_state_for_objects(std::vector& object_idxs) +{ + for (size_t obj_idx : object_idxs) + update_instance_printable_state_for_object(obj_idx); +} void GLCanvas3D::set_config(const DynamicPrintConfig* config) { @@ -1499,14 +1523,8 @@ void GLCanvas3D::render() if (m_canvas == nullptr) return; -#ifndef __WXMAC__ - // on Mac this check causes flickering when changing view - if (!_is_shown_on_screen()) - return; -#endif // __WXMAC__ - // ensures this canvas is current and initialized - if (!_set_current() || !_3DScene::init(m_canvas)) + if (! _is_shown_on_screen() || !_set_current() || !_3DScene::init(m_canvas)) return; #if ENABLE_RENDER_STATISTICS @@ -1529,7 +1547,7 @@ void GLCanvas3D::render() } m_camera.apply_view_matrix(); - m_camera.apply_projection(_max_bounding_box(true)); + m_camera.apply_projection(_max_bounding_box(true, true)); GLfloat position_cam[4] = { 1.0f, 0.0f, 1.0f, 0.0f }; glsafe(::glLightfv(GL_LIGHT1, GL_POSITION, position_cam)); @@ -1691,7 +1709,7 @@ std::vector GLCanvas3D::load_object(const ModelObject& model_object, int ob instance_idxs.push_back(i); } } - return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by); + return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by, m_initialized); } std::vector GLCanvas3D::load_object(const Model& model, int obj_idx) @@ -1879,7 +1897,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); if (it->new_geometry()) { // New volume. - m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by); + m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized); m_volumes.volumes.back()->geometry_id = key.geometry_id; update_object_list = true; } else { @@ -1952,7 +1970,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re for (size_t istep = 0; istep < sla_steps.size(); ++istep) if (!instances[istep].empty()) - m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp); + m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized); } // Shift-up all volumes of the object so that it has the right elevation with respect to the print bed @@ -1992,7 +2010,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re depth = (900.f/w) * (float)(extruders_count - 1); int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( 1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower), - brim_spacing * 4.5f); + brim_spacing * 4.5f, m_initialized); if (volume_idx_wipe_tower_old != -1) map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new; } @@ -2065,6 +2083,52 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re m_dirty = true; } +static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume& vol_old, bool gl_initialized) +{ + // Assign the large pre-allocated buffers to the new GLVolume. + vol_new.indexed_vertex_array = std::move(vol_old.indexed_vertex_array); + // Copy the content back to the old GLVolume. + vol_old.indexed_vertex_array = vol_new.indexed_vertex_array; + // Clear the buffers, but keep them pre-allocated. + vol_new.indexed_vertex_array.clear(); + // Just make sure that clear did not clear the reserved memory. + // Reserving number of vertices (3x position + 3x color) + vol_new.indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6); + // Finalize the old geometry, possibly move data to the graphics card. + vol_old.finalize_geometry(gl_initialized); +} + +static void load_gcode_retractions(const GCodePreviewData::Retraction& retractions, GLCanvas3D::GCodePreviewVolumeIndex::EType extrusion_type, GLVolumeCollection &volumes, GLCanvas3D::GCodePreviewVolumeIndex &volume_index, bool gl_initialized) +{ + volume_index.first_volumes.emplace_back(extrusion_type, 0, (unsigned int)volumes.volumes.size()); + + // nothing to render, return + if (retractions.positions.empty()) + return; + + GLVolume *volume = volumes.new_nontoolpath_volume(retractions.color.rgba, VERTEX_BUFFER_RESERVE_SIZE); + + GCodePreviewData::Retraction::PositionsList copy(retractions.positions); + std::sort(copy.begin(), copy.end(), [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2) { return p1.position(2) < p2.position(2); }); + + for (const GCodePreviewData::Retraction::Position& position : copy) + { + volume->print_zs.push_back(unscale(position.position(2))); + volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); + volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); + + _3DScene::point3_to_verts(position.position, position.width, position.height, *volume); + + // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. + if (volume->indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { + GLVolume &vol = *volume; + volume = volumes.new_nontoolpath_volume(vol.color); + reserve_new_volume_finalize_old_volume(*volume, vol, gl_initialized); + } + } + volume->indexed_vertex_array.finalize_geometry(gl_initialized); +} + void GLCanvas3D::load_gcode_preview(const GCodePreviewData& preview_data, const std::vector& str_tool_colors) { const Print *print = this->fff_print(); @@ -2080,8 +2144,8 @@ void GLCanvas3D::load_gcode_preview(const GCodePreviewData& preview_data, const _load_gcode_extrusion_paths(preview_data, tool_colors); _load_gcode_travel_paths(preview_data, tool_colors); - _load_gcode_retractions(preview_data); - _load_gcode_unretractions(preview_data); + load_gcode_retractions(preview_data.retraction, GCodePreviewVolumeIndex::Retraction, m_volumes, m_gcode_preview_volume_index, m_initialized); + load_gcode_retractions(preview_data.unretraction, GCodePreviewVolumeIndex::Unretraction, m_volumes, m_gcode_preview_volume_index, m_initialized); if (!m_volumes.empty()) { @@ -2110,8 +2174,9 @@ void GLCanvas3D::load_sla_preview() if ((m_canvas != nullptr) && (print != nullptr)) { _set_current(); - // Reload the SLA support structures into GLVolumes. - this->reload_scene(true, true); + // Release OpenGL data before generating new data. + this->reset_volumes(); + _load_sla_shells(); _update_sla_shells_outside_state(); _show_warning_texture_if_needed(WarningTexture::SlaSupportsOutside); } @@ -2125,18 +2190,13 @@ void GLCanvas3D::load_preview(const std::vector& str_tool_colors, c _set_current(); + // Release OpenGL data before generating new data. + this->reset_volumes(); + _load_print_toolpaths(); _load_wipe_tower_toolpaths(str_tool_colors); for (const PrintObject* object : print->objects()) - { - if (object != nullptr) _load_print_object_toolpaths(*object, str_tool_colors, color_print_values); - } - - for (GLVolume* volume : m_volumes.volumes) - { - volume->is_extrusion_path = true; - } _update_toolpath_volumes_outside_state(); _show_warning_texture_if_needed(WarningTexture::ToolpathOutside); @@ -2456,6 +2516,13 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) evt.SetY(evt.GetY() * scale); #endif +#ifdef __WXMSW__ + // For some reason the Idle event is not being generated after the mouse scroll event in case of scrolling with the two fingers on the touch pad, + // if the event is not allowed to be passed further. + // https://github.com/prusa3d/PrusaSlicer/issues/2750 + evt.Skip(); +#endif /* __WXMSW__ */ + // Performs layers editing updates, if enabled if (is_layers_editing_enabled()) { @@ -2906,7 +2973,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) && m_gizmos.get_current_type() != GLGizmosManager::SlaSupports) // disable context menu when the gizmo is open { // forces the selection of the volume - m_selection.add(volume_idx); + /* m_selection.add(volume_idx); // #et_FIXME_if_needed + * To avoid extra "Add-Selection" snapshots, + * call add() with check_for_already_contained=true + * */ + m_selection.add(volume_idx, true, true); m_gizmos.refresh_on_off_state(); post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); m_gizmos.update_data(); @@ -2929,7 +3000,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) else if (evt.Moving()) { m_mouse.position = pos.cast(); - std::string tooltip = L(""); + std::string tooltip = ""; if (tooltip.empty()) tooltip = m_gizmos.get_tooltip(); @@ -3217,7 +3288,7 @@ void GLCanvas3D::do_flatten(const Vec3d& normal, const std::string& snapshot_typ wxGetApp().plater()->take_snapshot(_(snapshot_type)); m_selection.flattening_rotate(normal); - do_rotate(L("")); // avoid taking another snapshot + do_rotate(""); // avoid taking another snapshot } void GLCanvas3D::do_mirror(const std::string& snapshot_type) @@ -3273,7 +3344,7 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type) void GLCanvas3D::set_camera_zoom(double zoom) { const Size& cnv_size = get_canvas_size(); - m_camera.set_zoom(zoom, _max_bounding_box(false), cnv_size.get_width(), cnv_size.get_height()); + m_camera.set_zoom(zoom, _max_bounding_box(false, false), cnv_size.get_width(), cnv_size.get_height()); m_dirty = true; } @@ -3374,6 +3445,16 @@ void GLCanvas3D::msw_rescale() m_warning_texture.msw_rescale(*this); } +bool GLCanvas3D::has_toolpaths_to_export() const +{ + return m_volumes.has_toolpaths_to_export(); +} + +void GLCanvas3D::export_toolpaths_to_obj(const char* filename) const +{ + m_volumes.export_toolpaths_to_obj(filename); +} + bool GLCanvas3D::_is_shown_on_screen() const { return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false; @@ -3568,7 +3649,15 @@ bool GLCanvas3D::_init_main_toolbar() item.sprite_id = 10; item.left.toggable = true; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); }; - item.visibility_callback = [this]()->bool { return m_process->current_printer_technology() == ptFFF; }; + item.visibility_callback = [this]()->bool + { + bool res = m_process->current_printer_technology() == ptFFF; + // turns off if changing printer technology + if (!res && m_main_toolbar.is_item_visible("layersediting") && m_main_toolbar.is_item_pressed("layersediting")) + force_main_toolbar_left_action(get_main_toolbar_item_id("layersediting")); + + return res; + }; item.enabling_callback = []()->bool { return wxGetApp().plater()->can_layers_editing(); }; if (!m_main_toolbar.add_item(item)) return false; @@ -3620,14 +3709,14 @@ bool GLCanvas3D::_init_undoredo_toolbar() std::string curr_additional_tooltip; m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip); - std::string new_additional_tooltip = L(""); + std::string new_additional_tooltip = ""; if (can_undo) wxGetApp().plater()->undo_redo_topmost_string_getter(true, new_additional_tooltip); if (new_additional_tooltip != curr_additional_tooltip) { m_undoredo_toolbar.set_additional_tooltip(id, new_additional_tooltip); - set_tooltip(L("")); + set_tooltip(""); } return can_undo; }; @@ -3649,14 +3738,14 @@ bool GLCanvas3D::_init_undoredo_toolbar() std::string curr_additional_tooltip; m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip); - std::string new_additional_tooltip = L(""); + std::string new_additional_tooltip = ""; if (can_redo) wxGetApp().plater()->undo_redo_topmost_string_getter(false, new_additional_tooltip); if (new_additional_tooltip != curr_additional_tooltip) { m_undoredo_toolbar.set_additional_tooltip(id, new_additional_tooltip); - set_tooltip(L("")); + set_tooltip(""); } return can_redo; }; @@ -3669,13 +3758,9 @@ bool GLCanvas3D::_init_undoredo_toolbar() bool GLCanvas3D::_set_current() { - if (_is_shown_on_screen() && (m_context != nullptr)) { - return m_canvas->SetCurrent(*m_context); + return m_context != nullptr && m_canvas->SetCurrent(*m_context); } - return false; -} - void GLCanvas3D::_resize(unsigned int w, unsigned int h) { if ((m_canvas == nullptr) && (m_context == nullptr)) @@ -3699,9 +3784,20 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) m_dirty = false; } -BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_bed_model) const +BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_bed_model) const { BoundingBoxf3 bb = volumes_bounding_box(); + + // The following is a workaround for gizmos not being taken in account when calculating the tight camera frustrum + // A better solution would ask the gizmo manager for the bounding box of the current active gizmo, if any + if (include_gizmos && m_gizmos.is_running()) + { + BoundingBoxf3 sel_bb = m_selection.get_bounding_box(); + Vec3d sel_bb_center = sel_bb.center(); + Vec3d extend_by = sel_bb.max_size() * Vec3d::Ones(); + bb.merge(BoundingBoxf3(sel_bb_center - extend_by, sel_bb_center + extend_by)); + } + bb.merge(m_bed.get_bounding_box(include_bed_model)); return bb; } @@ -3737,6 +3833,7 @@ void GLCanvas3D::_picking_pass() const // Better to use software ray - casting on a bounding - box hierarchy. if (m_multisample_allowed) + // This flag is often ignored by NVIDIA drivers if rendering into a screen buffer. glsafe(::glDisable(GL_MULTISAMPLE)); glsafe(::glDisable(GL_BLEND)); @@ -3766,6 +3863,8 @@ void GLCanvas3D::_picking_pass() const if (inside) { glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color)); + if (picking_checksum_alpha_channel(color[0], color[1], color[2]) == color[3]) + // Only non-interpolated colors are valid, those have their lowest three bits zeroed. volume_id = color[0] + (color[1] << 8) + (color[2] << 16); } if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) @@ -3789,6 +3888,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const if (m_picking_enabled) { if (m_multisample_allowed) + // This flag is often ignored by NVIDIA drivers if rendering into a screen buffer. glsafe(::glDisable(GL_MULTISAMPLE)); glsafe(::glDisable(GL_BLEND)); @@ -3814,6 +3914,8 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const struct Pixel { std::array data; + // Only non-interpolated colors are valid, those have their lowest three bits zeroed. + bool valid() const { return picking_checksum_alpha_channel(data[0], data[1], data[2]) == data[3]; } int id() const { return data[0] + (data[1] << 8) + (data[2] << 16); } }; @@ -3824,17 +3926,15 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const tbb::parallel_for(tbb::blocked_range(0, frame.size(), (size_t)width), [this, &frame, &idxs, &mutex](const tbb::blocked_range& range) { for (size_t i = range.begin(); i < range.end(); ++i) - { + if (frame[i].valid()) { int volume_id = frame[i].id(); - if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) - { + if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) { mutex.lock(); idxs.insert(volume_id); mutex.unlock(); } } - } - ); + }); #else std::vector frame(4 * px_count); glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data())); @@ -4013,42 +4113,27 @@ void GLCanvas3D::_render_volumes_for_picking() const // do not cull backfaces to show broken geometry, if any glsafe(::glDisable(GL_CULL_FACE)); - glsafe(::glEnable(GL_BLEND)); - glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); const Transform3d& view_matrix = m_camera.get_view_matrix(); - GLVolumeWithIdAndZList to_render = volumes_to_render(m_volumes.volumes, GLVolumeCollection::Opaque, view_matrix); + for (size_t type = 0; type < 2; ++ type) { + GLVolumeWithIdAndZList to_render = volumes_to_render(m_volumes.volumes, (type == 0) ? GLVolumeCollection::Opaque : GLVolumeCollection::Transparent, view_matrix); for (const GLVolumeWithIdAndZ& volume : to_render) - { + if (!volume.first->disabled && ((volume.first->composite_id.volume_id >= 0) || m_render_sla_auxiliaries)) { // Object picking mode. Render the object with a color encoding the object index. - unsigned int r = (volume.second.first & 0x000000FF) >> 0; - unsigned int g = (volume.second.first & 0x0000FF00) >> 8; - unsigned int b = (volume.second.first & 0x00FF0000) >> 16; - glsafe(::glColor3f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255)); - - if (!volume.first->disabled && ((volume.first->composite_id.volume_id >= 0) || m_render_sla_auxiliaries)) + unsigned int id = volume.second.first; + unsigned int r = (id & (0x000000FF << 0)) << 0; + unsigned int g = (id & (0x000000FF << 8)) >> 8; + unsigned int b = (id & (0x000000FF << 16)) >> 16; + unsigned int a = picking_checksum_alpha_channel(r, g, b); + glsafe(::glColor4f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255, (GLfloat)a * INV_255)); volume.first->render(); } - - to_render = volumes_to_render(m_volumes.volumes, GLVolumeCollection::Transparent, view_matrix); - for (const GLVolumeWithIdAndZ& volume : to_render) - { - // Object picking mode. Render the object with a color encoding the object index. - unsigned int r = (volume.second.first & 0x000000FF) >> 0; - unsigned int g = (volume.second.first & 0x0000FF00) >> 8; - unsigned int b = (volume.second.first & 0x00FF0000) >> 16; - glsafe(::glColor3f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255)); - - if (!volume.first->disabled && ((volume.first->composite_id.volume_id >= 0) || m_render_sla_auxiliaries)) - volume.first->render(); } glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - glsafe(::glDisable(GL_BLEND)); glsafe(::glEnable(GL_CULL_FACE)); } @@ -4500,18 +4585,24 @@ void GLCanvas3D::_load_print_toolpaths() if (print_zs.size() > skirt_height) print_zs.erase(print_zs.begin() + skirt_height, print_zs.end()); - m_volumes.volumes.emplace_back(new GLVolume(color)); - GLVolume& volume = *m_volumes.volumes.back(); - for (size_t i = 0; i < skirt_height; ++i) { - volume.print_zs.push_back(print_zs[i]); - volume.offsets.push_back(volume.indexed_vertex_array.quad_indices.size()); - volume.offsets.push_back(volume.indexed_vertex_array.triangle_indices.size()); - if (i == 0) - _3DScene::extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), volume); - _3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), volume); + GLVolume *volume = m_volumes.new_toolpath_volume(color, VERTEX_BUFFER_RESERVE_SIZE); + for (size_t i = 0; i < skirt_height; ++i) { + volume->print_zs.push_back(print_zs[i]); + volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); + volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); + if (i == 0) + _3DScene::extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), *volume); + _3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), *volume); + // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. + if (volume->indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { + GLVolume &vol = *volume; + volume = m_volumes.new_toolpath_volume(vol.color); + reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized); } } + volume->indexed_vertex_array.finalize_geometry(m_initialized); +} void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const std::vector& str_tool_colors, const std::vector& color_print_values) { @@ -4527,12 +4618,6 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c const std::vector* tool_colors; const std::vector* color_print_values; - // Number of vertices (each vertex is 6x4=24 bytes long) - static const size_t alloc_size_max() { return 131072; } // 3.15MB - // static const size_t alloc_size_max () { return 65536; } // 1.57MB - // static const size_t alloc_size_max () { return 32768; } // 786kB - static const size_t alloc_size_reserve() { return alloc_size_max() * 2; } - static const float* color_perimeters() { static float color[4] = { 1.0f, 1.0f, 0.0f, 1.f }; return color; } // yellow static const float* color_infill() { static float color[4] = { 1.0f, 0.5f, 0.5f, 1.f }; return color; } // redish static const float* color_support() { static float color[4] = { 0.5f, 1.0f, 0.5f, 1.f }; return color; } // greenish @@ -4576,16 +4661,20 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c std::sort(ctxt.layers.begin(), ctxt.layers.end(), [](const Layer *l1, const Layer *l2) { return l1->print_z < l2->print_z; }); // Maximum size of an allocation block: 32MB / sizeof(float) - BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - start"; + BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - start" << m_volumes.log_memory_info() << log_memory_info(); //FIXME Improve the heuristics for a grain size. size_t grain_size = std::max(ctxt.layers.size() / 16, size_t(1)); tbb::spin_mutex new_volume_mutex; auto new_volume = [this, &new_volume_mutex](const float *color) -> GLVolume* { - auto *volume = new GLVolume(color); - new_volume_mutex.lock(); + // Allocate the volume before locking. + GLVolume *volume = new GLVolume(color); + volume->is_extrusion_path = true; + tbb::spin_mutex::scoped_lock lock; + // Lock by ROII, so if the emplace_back() fails, the lock will be released. + lock.acquire(new_volume_mutex); m_volumes.volumes.emplace_back(volume); - new_volume_mutex.unlock(); + lock.release(); return volume; }; const size_t volumes_cnt_initial = m_volumes.volumes.size(); @@ -4623,7 +4712,8 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c else vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) }; for (GLVolume *vol : vols) - vol->indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); + // Reserving number of vertices (3x position + 3x color) + vol->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6); for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { const Layer *layer = ctxt.layers[idx_layer]; for (GLVolume *vol : vols) @@ -4670,31 +4760,28 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. for (size_t i = 0; i < vols.size(); ++i) { GLVolume &vol = *vols[i]; - if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) { - // Store the vertex arrays and restart their containers, + if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { vols[i] = new_volume(vol.color); - GLVolume &vol_new = *vols[i]; - // Assign the large pre-allocated buffers to the new GLVolume. - vol_new.indexed_vertex_array = std::move(vol.indexed_vertex_array); - // Copy the content back to the old GLVolume. - vol.indexed_vertex_array = vol_new.indexed_vertex_array; - // Clear the buffers, but keep them pre-allocated. - vol_new.indexed_vertex_array.clear(); - // Just make sure that clear did not clear the reserved memory. - vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); + reserve_new_volume_finalize_old_volume(*vols[i], vol, false); } } } + for (GLVolume *vol : vols) + // Ideally one would call vol->indexed_vertex_array.finalize() here to move the buffers to the OpenGL driver, + // but this code runs in parallel and the OpenGL driver is not thread safe. + vol->indexed_vertex_array.shrink_to_fit(); }); - BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results"; + BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info(); // Remove empty volumes from the newly added volumes. m_volumes.volumes.erase( std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), [](const GLVolume *volume) { return volume->empty(); }), m_volumes.volumes.end()); + for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) + m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized); - BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end"; + BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info(); } void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector& str_tool_colors) @@ -4715,10 +4802,6 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector& str_ Vec2f wipe_tower_pos; float wipe_tower_angle; - // Number of vertices (each vertex is 6x4=24 bytes long) - static const size_t alloc_size_max() { return 131072; } // 3.15MB - static const size_t alloc_size_reserve() { return alloc_size_max() * 2; } - static const float* color_support() { static float color[4] = { 0.5f, 1.0f, 0.5f, 1.f }; return color; } // greenish // For cloring by a tool, return a parsed color. @@ -4751,7 +4834,7 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector& str_ ctxt.wipe_tower_angle = ctxt.print->config().wipe_tower_rotation_angle.value/180.f * PI; ctxt.wipe_tower_pos = Vec2f(ctxt.print->config().wipe_tower_x.value, ctxt.print->config().wipe_tower_y.value); - BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start"; + BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start" << m_volumes.log_memory_info() << log_memory_info(); //FIXME Improve the heuristics for a grain size. size_t n_items = print->wipe_tower_data().tool_changes.size() + (ctxt.priming.empty() ? 0 : 1); @@ -4759,9 +4842,11 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector& str_ tbb::spin_mutex new_volume_mutex; auto new_volume = [this, &new_volume_mutex](const float *color) -> GLVolume* { auto *volume = new GLVolume(color); - new_volume_mutex.lock(); + volume->is_extrusion_path = true; + tbb::spin_mutex::scoped_lock lock; + lock.acquire(new_volume_mutex); m_volumes.volumes.emplace_back(volume); - new_volume_mutex.unlock(); + lock.release(); return volume; }; const size_t volumes_cnt_initial = m_volumes.volumes.size(); @@ -4778,7 +4863,8 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector& str_ else vols = { new_volume(ctxt.color_support()) }; for (GLVolume *volume : vols) - volume->indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); + // Reserving number of vertices (3x position + 3x color) + volume->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6); for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { const std::vector &layer = ctxt.tool_change(idx_layer); for (size_t i = 0; i < vols.size(); ++i) { @@ -4835,30 +4921,25 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector& str_ } for (size_t i = 0; i < vols.size(); ++i) { GLVolume &vol = *vols[i]; - if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) { - // Store the vertex arrays and restart their containers, + if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { vols[i] = new_volume(vol.color); - GLVolume &vol_new = *vols[i]; - // Assign the large pre-allocated buffers to the new GLVolume. - vol_new.indexed_vertex_array = std::move(vol.indexed_vertex_array); - // Copy the content back to the old GLVolume. - vol.indexed_vertex_array = vol_new.indexed_vertex_array; - // Clear the buffers, but keep them pre-allocated. - vol_new.indexed_vertex_array.clear(); - // Just make sure that clear did not clear the reserved memory. - vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); + reserve_new_volume_finalize_old_volume(*vols[i], vol, false); } } + for (GLVolume *vol : vols) + vol->indexed_vertex_array.shrink_to_fit(); }); - BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results"; + BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info(); // Remove empty volumes from the newly added volumes. m_volumes.volumes.erase( std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), [](const GLVolume *volume) { return volume->empty(); }), m_volumes.volumes.end()); + for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) + m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized); - BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end"; + BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info(); } static inline int hex_digit_to_int(const char c) @@ -4871,6 +4952,8 @@ static inline int hex_digit_to_int(const char c) void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_data, const std::vector& tool_colors) { + BOOST_LOG_TRIVIAL(debug) << "Loading G-code extrusion paths - start" << m_volumes.log_memory_info() << log_memory_info(); + // helper functions to select data in dependence of the extrusion view type struct Helper { @@ -4988,19 +5071,15 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat if (filters.empty()) return; + BOOST_LOG_TRIVIAL(debug) << "Loading G-code extrusion paths - create volumes" << m_volumes.log_memory_info() << log_memory_info(); + // creates a new volume for each filter for (Filter& filter : filters) { m_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Extrusion, (unsigned int)filter.role, (unsigned int)m_volumes.volumes.size()); - GLVolume* volume = new GLVolume(Helper::path_color(preview_data, tool_colors, filter.value).rgba); - if (volume != nullptr) - { - filter.volume = volume; - volume->is_extrusion_path = true; - m_volumes.volumes.emplace_back(volume); - } - else - { + try { + filter.volume = m_volumes.new_toolpath_volume(Helper::path_color(preview_data, tool_colors, filter.value).rgba, VERTEX_BUFFER_RESERVE_SIZE); + } catch (std::bad_alloc& /* err */) { // an error occourred - restore to previous state and return m_gcode_preview_volume_index.first_volumes.pop_back(); if (initial_volumes_count != m_volumes.volumes.size()) @@ -5008,16 +5087,16 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat GLVolumePtrs::iterator begin = m_volumes.volumes.begin() + initial_volumes_count; GLVolumePtrs::iterator end = m_volumes.volumes.end(); for (GLVolumePtrs::iterator it = begin; it < end; ++it) - { - GLVolume* volume = *it; - delete volume; - } + delete *it; m_volumes.volumes.erase(begin, end); + //FIXME rethrow bad_alloc? return; } } } + BOOST_LOG_TRIVIAL(debug) << "Loading G-code extrusion paths - populate volumes" << m_volumes.log_memory_info() << log_memory_info(); + // populates volumes for (const GCodePreviewData::Extrusion::Layer& layer : preview_data.extrusion.layers) { @@ -5027,16 +5106,29 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat FiltersList::iterator filter = std::find(filters.begin(), filters.end(), Filter(path_filter, path.role())); if (filter != filters.end()) { - filter->volume->print_zs.push_back(layer.z); - filter->volume->offsets.push_back(filter->volume->indexed_vertex_array.quad_indices.size()); - filter->volume->offsets.push_back(filter->volume->indexed_vertex_array.triangle_indices.size()); + GLVolume &vol = *filter->volume; + vol.print_zs.push_back(layer.z); + vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size()); + vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size()); - _3DScene::extrusionentity_to_verts(path, layer.z, *filter->volume); + _3DScene::extrusionentity_to_verts(path, layer.z, vol); + + // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. + if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { + filter->volume = m_volumes.new_toolpath_volume(vol.color); + reserve_new_volume_finalize_old_volume(*filter->volume, vol, m_initialized); } } } } + // Finalize volumes and sends geometry to gpu + for (Filter &filter : filters) + filter.volume->indexed_vertex_array.finalize_geometry(m_initialized); + + BOOST_LOG_TRIVIAL(debug) << "Loading G-code extrusion paths - end" << m_volumes.log_memory_info() << log_memory_info(); +} + void GLCanvas3D::_load_gcode_travel_paths(const GCodePreviewData& preview_data, const std::vector& tool_colors) { size_t initial_volumes_count = m_volumes.volumes.size(); @@ -5071,10 +5163,7 @@ void GLCanvas3D::_load_gcode_travel_paths(const GCodePreviewData& preview_data, GLVolumePtrs::iterator begin = m_volumes.volumes.begin() + initial_volumes_count; GLVolumePtrs::iterator end = m_volumes.volumes.end(); for (GLVolumePtrs::iterator it = begin; it < end; ++it) - { - GLVolume* volume = *it; - delete volume; - } + delete *it; m_volumes.volumes.erase(begin, end); } @@ -5120,16 +5209,7 @@ bool GLCanvas3D::_travel_paths_by_type(const GCodePreviewData& preview_data) // creates a new volume for each type for (Type& type : types) - { - GLVolume* volume = new GLVolume(preview_data.travel.type_colors[type.value].rgba); - if (volume == nullptr) - return false; - else - { - type.volume = volume; - m_volumes.volumes.emplace_back(volume); - } - } + type.volume = m_volumes.new_nontoolpath_volume(preview_data.travel.type_colors[type.value].rgba, VERTEX_BUFFER_RESERVE_SIZE); // populates volumes for (const GCodePreviewData::Travel::Polyline& polyline : preview_data.travel.polylines) @@ -5137,13 +5217,23 @@ bool GLCanvas3D::_travel_paths_by_type(const GCodePreviewData& preview_data) TypesList::iterator type = std::find(types.begin(), types.end(), Type(polyline.type)); if (type != types.end()) { - type->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().min(2))); - type->volume->offsets.push_back(type->volume->indexed_vertex_array.quad_indices.size()); - type->volume->offsets.push_back(type->volume->indexed_vertex_array.triangle_indices.size()); + GLVolume &vol = *type->volume; + vol.print_zs.push_back(unscale(polyline.polyline.bounding_box().min(2))); + vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size()); + vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size()); - _3DScene::polyline3_to_verts(polyline.polyline, preview_data.travel.width, preview_data.travel.height, *type->volume); + _3DScene::polyline3_to_verts(polyline.polyline, preview_data.travel.width, preview_data.travel.height, vol); + + // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. + if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { + type->volume = m_volumes.new_nontoolpath_volume(vol.color); + reserve_new_volume_finalize_old_volume(*type->volume, vol, m_initialized); } } + } + + for (Type &type : types) + type.volume->finalize_geometry(m_initialized); return true; } @@ -5186,16 +5276,7 @@ bool GLCanvas3D::_travel_paths_by_feedrate(const GCodePreviewData& preview_data) // creates a new volume for each feedrate for (Feedrate& feedrate : feedrates) - { - GLVolume* volume = new GLVolume(preview_data.get_feedrate_color(feedrate.value).rgba); - if (volume == nullptr) - return false; - else - { - feedrate.volume = volume; - m_volumes.volumes.emplace_back(volume); - } - } + feedrate.volume = m_volumes.new_nontoolpath_volume(preview_data.get_feedrate_color(feedrate.value).rgba, VERTEX_BUFFER_RESERVE_SIZE); // populates volumes for (const GCodePreviewData::Travel::Polyline& polyline : preview_data.travel.polylines) @@ -5203,13 +5284,23 @@ bool GLCanvas3D::_travel_paths_by_feedrate(const GCodePreviewData& preview_data) FeedratesList::iterator feedrate = std::find(feedrates.begin(), feedrates.end(), Feedrate(polyline.feedrate)); if (feedrate != feedrates.end()) { - feedrate->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().min(2))); - feedrate->volume->offsets.push_back(feedrate->volume->indexed_vertex_array.quad_indices.size()); - feedrate->volume->offsets.push_back(feedrate->volume->indexed_vertex_array.triangle_indices.size()); + GLVolume &vol = *feedrate->volume; + vol.print_zs.push_back(unscale(polyline.polyline.bounding_box().min(2))); + vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size()); + vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size()); _3DScene::polyline3_to_verts(polyline.polyline, preview_data.travel.width, preview_data.travel.height, *feedrate->volume); + + // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. + if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { + feedrate->volume = m_volumes.new_nontoolpath_volume(vol.color); + reserve_new_volume_finalize_old_volume(*feedrate->volume, vol, m_initialized); } } + } + + for (Feedrate &feedrate : feedrates) + feedrate.volume->finalize_geometry(m_initialized); return true; } @@ -5254,18 +5345,9 @@ bool GLCanvas3D::_travel_paths_by_tool(const GCodePreviewData& preview_data, con for (Tool& tool : tools) { // tool.value could be invalid (as it was with https://github.com/prusa3d/PrusaSlicer/issues/2179), we better check - if (tool.value >= tool_colors.size()) - continue; - - GLVolume* volume = new GLVolume(tool_colors.data() + tool.value * 4); - if (volume == nullptr) - return false; - else - { - tool.volume = volume; - m_volumes.volumes.emplace_back(volume); + if (tool.value < tool_colors.size()) + tool.volume = m_volumes.new_nontoolpath_volume(tool_colors.data() + tool.value * 4, VERTEX_BUFFER_RESERVE_SIZE); } - } // populates volumes for (const GCodePreviewData::Travel::Polyline& polyline : preview_data.travel.polylines) @@ -5273,70 +5355,26 @@ bool GLCanvas3D::_travel_paths_by_tool(const GCodePreviewData& preview_data, con ToolsList::iterator tool = std::find(tools.begin(), tools.end(), Tool(polyline.extruder_id)); if (tool != tools.end() && tool->volume != nullptr) { - tool->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().min(2))); - tool->volume->offsets.push_back(tool->volume->indexed_vertex_array.quad_indices.size()); - tool->volume->offsets.push_back(tool->volume->indexed_vertex_array.triangle_indices.size()); + GLVolume &vol = *tool->volume; + vol.print_zs.push_back(unscale(polyline.polyline.bounding_box().min(2))); + vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size()); + vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size()); _3DScene::polyline3_to_verts(polyline.polyline, preview_data.travel.width, preview_data.travel.height, *tool->volume); + + // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. + if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { + tool->volume = m_volumes.new_nontoolpath_volume(vol.color); + reserve_new_volume_finalize_old_volume(*tool->volume, vol, m_initialized); +} } } + for (Tool& tool : tools) + tool.volume->finalize_geometry(m_initialized); + return true; -} - -void GLCanvas3D::_load_gcode_retractions(const GCodePreviewData& preview_data) -{ - m_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Retraction, 0, (unsigned int)m_volumes.volumes.size()); - - // nothing to render, return - if (preview_data.retraction.positions.empty()) - return; - - GLVolume* volume = new GLVolume(preview_data.retraction.color.rgba); - if (volume != nullptr) - { - m_volumes.volumes.emplace_back(volume); - - GCodePreviewData::Retraction::PositionsList copy(preview_data.retraction.positions); - std::sort(copy.begin(), copy.end(), [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2){ return p1.position(2) < p2.position(2); }); - - for (const GCodePreviewData::Retraction::Position& position : copy) - { - volume->print_zs.push_back(unscale(position.position(2))); - volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); - volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); - - _3DScene::point3_to_verts(position.position, position.width, position.height, *volume); } - } -} - -void GLCanvas3D::_load_gcode_unretractions(const GCodePreviewData& preview_data) -{ - m_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Unretraction, 0, (unsigned int)m_volumes.volumes.size()); - - // nothing to render, return - if (preview_data.unretraction.positions.empty()) - return; - - GLVolume* volume = new GLVolume(preview_data.unretraction.color.rgba); - if (volume != nullptr) - { - m_volumes.volumes.emplace_back(volume); - - GCodePreviewData::Retraction::PositionsList copy(preview_data.unretraction.positions); - std::sort(copy.begin(), copy.end(), [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2){ return p1.position(2) < p2.position(2); }); - - for (const GCodePreviewData::Retraction::Position& position : copy) - { - volume->print_zs.push_back(unscale(position.position(2))); - volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size()); - volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size()); - - _3DScene::point3_to_verts(position.position, position.width, position.height, *volume); - } - } -} void GLCanvas3D::_load_fff_shells() { @@ -5360,7 +5398,7 @@ void GLCanvas3D::_load_fff_shells() instance_ids[i] = i; } - m_volumes.load_object(model_obj, object_id, instance_ids, "object"); + m_volumes.load_object(model_obj, object_id, instance_ids, "object", m_initialized); ++object_id; } @@ -5382,11 +5420,63 @@ void GLCanvas3D::_load_fff_shells() if (!print->is_step_done(psWipeTower)) depth = (900.f/config.wipe_tower_width) * (float)(extruders_count - 1); m_volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle, - !print->is_step_done(psWipeTower), brim_spacing * 4.5f); + !print->is_step_done(psWipeTower), brim_spacing * 4.5f, m_initialized); } } } +// While it looks like we can call +// this->reload_scene(true, true) +// the two functions are quite different: +// 1) This function only loads objects, for which the step slaposSliceSupports already finished. Therefore objects outside of the print bed never load. +// 2) This function loads object mesh with the relative scaling correction (the "relative_correction" parameter) was applied, +// therefore the mesh may be slightly larger or smaller than the mesh shown in the 3D scene. +void GLCanvas3D::_load_sla_shells() +{ + const SLAPrint* print = this->sla_print(); + if (print->objects().empty()) + // nothing to render, return + return; + + auto add_volume = [this](const SLAPrintObject &object, int volume_id, const SLAPrintObject::Instance& instance, + const TriangleMesh &mesh, const float color[4], bool outside_printer_detection_enabled) { + m_volumes.volumes.emplace_back(new GLVolume(color)); + GLVolume& v = *m_volumes.volumes.back(); + v.indexed_vertex_array.load_mesh(mesh); + v.indexed_vertex_array.finalize_geometry(this->m_initialized); + v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled; + v.composite_id.volume_id = volume_id; + v.set_instance_offset(unscale(instance.shift(0), instance.shift(1), 0)); + v.set_instance_rotation(Vec3d(0.0, 0.0, (double)instance.rotation)); + v.set_instance_mirror(X, object.is_left_handed() ? -1. : 1.); + v.set_convex_hull(mesh.convex_hull_3d()); + }; + + // adds objects' volumes + for (const SLAPrintObject* obj : print->objects()) + if (obj->is_step_done(slaposSliceSupports)) { + unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); + for (const SLAPrintObject::Instance& instance : obj->instances()) { + add_volume(*obj, 0, instance, obj->transformed_mesh(), GLVolume::MODEL_COLOR[0], true); + // Set the extruder_id and volume_id to achieve the same color as in the 3D scene when + // through the update_volumes_colors_by_extruder() call. + m_volumes.volumes.back()->extruder_id = obj->model_object()->volumes.front()->extruder_id(); + if (obj->is_step_done(slaposSupportTree) && obj->has_mesh(slaposSupportTree)) + add_volume(*obj, -int(slaposSupportTree), instance, obj->support_mesh(), GLVolume::SLA_SUPPORT_COLOR, true); + if (obj->is_step_done(slaposBasePool) && obj->has_mesh(slaposBasePool)) + add_volume(*obj, -int(slaposBasePool), instance, obj->pad_mesh(), GLVolume::SLA_PAD_COLOR, false); + } + double shift_z = obj->get_current_elevation(); + for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++ i) { + GLVolume& v = *m_volumes.volumes[i]; + // apply shift z + v.set_sla_shift_z(shift_z); + } + } + + update_volumes_colors_by_extruder(); +} + void GLCanvas3D::_update_gcode_volumes_visibility(const GCodePreviewData& preview_data) { unsigned int size = (unsigned int)m_gcode_preview_volume_index.first_volumes.size(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index c9803f9db..0c971518e 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -131,6 +131,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent); class GLCanvas3D { +public: struct GCodePreviewVolumeIndex { enum EType @@ -158,6 +159,7 @@ class GLCanvas3D void reset() { first_volumes.clear(); } }; +private: class LayersEditing { public: @@ -482,6 +484,8 @@ public: void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1); void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1); + void update_instance_printable_state_for_object(size_t obj_idx); + void update_instance_printable_state_for_objects(std::vector& object_idxs); void set_config(const DynamicPrintConfig* config); void set_process(BackgroundSlicingProcess* process); @@ -642,6 +646,9 @@ public: void get_undoredo_toolbar_additional_tooltip(unsigned int item_id, std::string& text) { return m_undoredo_toolbar.get_additional_tooltip(item_id, text); } void set_undoredo_toolbar_additional_tooltip(unsigned int item_id, const std::string& text) { m_undoredo_toolbar.set_additional_tooltip(item_id, text); } + bool has_toolpaths_to_export() const; + void export_toolpaths_to_obj(const char* filename) const; + private: bool _is_shown_on_screen() const; @@ -652,7 +659,7 @@ private: bool _set_current(); void _resize(unsigned int w, unsigned int h); - BoundingBoxf3 _max_bounding_box(bool include_bed_model) const; + BoundingBoxf3 _max_bounding_box(bool include_gizmos, bool include_bed_model) const; void _zoom_to_box(const BoundingBoxf3& box); @@ -715,12 +722,10 @@ private: bool _travel_paths_by_type(const GCodePreviewData& preview_data); bool _travel_paths_by_feedrate(const GCodePreviewData& preview_data); bool _travel_paths_by_tool(const GCodePreviewData& preview_data, const std::vector& tool_colors); - // generates gcode retractions geometry - void _load_gcode_retractions(const GCodePreviewData& preview_data); - // generates gcode unretractions geometry - void _load_gcode_unretractions(const GCodePreviewData& preview_data); // generates objects and wipe tower geometry void _load_fff_shells(); + // Load SLA objects and support structures for objects, for which the slaposSliceSupports step has been finished. + void _load_sla_shells(); // sets gcode geometry visibility according to user selection void _update_gcode_volumes_visibility(const GCodePreviewData& preview_data); void _update_toolpath_volumes_outside_state(); diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index b2a3161e8..a764fec66 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -197,11 +197,7 @@ GLCanvas3DManager::GLCanvas3DManager() GLCanvas3DManager::~GLCanvas3DManager() { - if (m_context != nullptr) - { - delete m_context; - m_context = nullptr; - } + this->destroy(); } bool GLCanvas3DManager::add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar) @@ -282,6 +278,15 @@ bool GLCanvas3DManager::init(wxGLCanvas* canvas) return false; } +void GLCanvas3DManager::destroy() +{ + if (m_context != nullptr) + { + delete m_context; + m_context = nullptr; + } +} + GLCanvas3D* GLCanvas3DManager::get_canvas(wxGLCanvas* canvas) { CanvasesMap::const_iterator it = do_get_canvas(canvas); @@ -290,7 +295,21 @@ GLCanvas3D* GLCanvas3DManager::get_canvas(wxGLCanvas* canvas) wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent) { - int attribList[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 24, WX_GL_SAMPLE_BUFFERS, GL_TRUE, WX_GL_SAMPLES, 4, 0 }; + int attribList[] = { + WX_GL_RGBA, + WX_GL_DOUBLEBUFFER, + // RGB channels each should be allocated with 8 bit depth. One should almost certainly get these bit depths by default. + WX_GL_MIN_RED, 8, + WX_GL_MIN_GREEN, 8, + WX_GL_MIN_BLUE, 8, + // Requesting an 8 bit alpha channel. Interestingly, the NVIDIA drivers would most likely work with some alpha plane, but glReadPixels would not return + // the alpha channel on NVIDIA if not requested when the GL context is created. + WX_GL_MIN_ALPHA, 8, + WX_GL_DEPTH_SIZE, 24, + WX_GL_SAMPLE_BUFFERS, GL_TRUE, + WX_GL_SAMPLES, 4, + 0 + }; if (s_multisample == MS_Unknown) { @@ -300,7 +319,7 @@ wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent) } if (! can_multisample()) - attribList[4] = 0; + attribList[12] = 0; return new wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS); } diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index c0e0df622..760266a27 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -91,6 +91,7 @@ public: void init_gl(); bool init(wxGLCanvas* canvas); + void destroy(); GLCanvas3D* get_canvas(wxGLCanvas* canvas); diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index f3421f150..4fdf12489 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -27,48 +27,57 @@ namespace GUI { void GLTexture::Compressor::reset() { - // force compression completion, if any - m_abort_compressing = true; - // wait for compression completion, if any - while (m_is_compressing) {} - - m_levels.clear(); -} - -void GLTexture::Compressor::add_level(unsigned int w, unsigned int h, const std::vector& data) -{ - m_levels.emplace_back(w, h, data); + if (m_thread.joinable()) { + m_abort_compressing = true; + m_thread.join(); + m_levels.clear(); + m_num_levels_compressed = 0; + m_abort_compressing = false; + } + assert(m_levels.empty()); + assert(m_abort_compressing == false); + assert(m_num_levels_compressed == 0); } void GLTexture::Compressor::start_compressing() { - m_is_compressing = true; - m_abort_compressing = false; - std::thread t(&GLTexture::Compressor::compress, this); - t.detach(); + // The worker thread should be stopped already. + assert(! m_thread.joinable()); + assert(! m_levels.empty()); + assert(m_abort_compressing == false); + assert(m_num_levels_compressed == 0); + if (! m_levels.empty()) { + std::thread thrd(&GLTexture::Compressor::compress, this); + m_thread = std::move(thrd); + } } bool GLTexture::Compressor::unsent_compressed_data_available() const { - for (const Level& level : m_levels) - { - if (!level.sent_to_gpu && level.compressed) + if (m_levels.empty()) + return false; + // Querying the atomic m_num_levels_compressed value synchronizes processor caches, so that the dat of m_levels modified by the worker thread are accessible to the calling thread. + unsigned int num_compressed = m_num_levels_compressed; + for (unsigned int i = 0; i < num_compressed; ++ i) + if (! m_levels[i].sent_to_gpu && ! m_levels[i].compressed_data.empty()) return true; - } - return false; } void GLTexture::Compressor::send_compressed_data_to_gpu() { // this method should be called inside the main thread of Slicer or a new OpenGL context (sharing resources) would be needed + if (m_levels.empty()) + return; glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); glsafe(::glBindTexture(GL_TEXTURE_2D, m_texture.m_id)); - for (int i = 0; i < (int)m_levels.size(); ++i) + // Querying the atomic m_num_levels_compressed value synchronizes processor caches, so that the dat of m_levels modified by the worker thread are accessible to the calling thread. + int num_compressed = (int)m_num_levels_compressed; + for (int i = 0; i < num_compressed; ++ i) { Level& level = m_levels[i]; - if (!level.sent_to_gpu && level.compressed) + if (! level.sent_to_gpu && ! level.compressed_data.empty()) { glsafe(::glCompressedTexSubImage2D(GL_TEXTURE_2D, (GLint)i, 0, 0, (GLsizei)level.w, (GLsizei)level.h, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)level.compressed_data.size(), (const GLvoid*)level.compressed_data.data())); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i)); @@ -76,27 +85,22 @@ void GLTexture::Compressor::send_compressed_data_to_gpu() level.sent_to_gpu = true; // we are done with the compressed data, we can discard it level.compressed_data.clear(); - level.compressed = false; } } glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); -} -bool GLTexture::Compressor::all_compressed_data_sent_to_gpu() const -{ - for (const Level& level : m_levels) - { - if (!level.sent_to_gpu) - return false; - } - - return true; + if (num_compressed == (unsigned int)m_levels.size()) + // Finalize the worker thread, close it. + this->reset(); } void GLTexture::Compressor::compress() { // reference: https://github.com/Cyan4973/RygsDXTc + assert(m_num_levels_compressed == 0); + assert(m_abort_compressing == false); + for (Level& level : m_levels) { if (m_abort_compressing) @@ -111,11 +115,8 @@ void GLTexture::Compressor::compress() // we are done with the source data, we can discard it level.src_data.clear(); - level.compressed = true; + ++ m_num_levels_compressed; } - - m_is_compressing = false; - m_abort_compressing = false; } GLTexture::Quad_UVs GLTexture::FullTextureUVs = { { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 0.0f, 0.0f } }; diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp index 7fc5b8fcf..c4063b93d 100644 --- a/src/slic3r/GUI/GLTexture.hpp +++ b/src/slic3r/GUI/GLTexture.hpp @@ -1,8 +1,10 @@ #ifndef slic3r_GLTexture_hpp_ #define slic3r_GLTexture_hpp_ +#include #include #include +#include class wxImage; @@ -19,29 +21,34 @@ namespace GUI { unsigned int h; std::vector src_data; std::vector compressed_data; - bool compressed; bool sent_to_gpu; - Level(unsigned int w, unsigned int h, const std::vector& data) : w(w), h(h), src_data(data), compressed(false), sent_to_gpu(false) {} + Level(unsigned int w, unsigned int h, const std::vector& data) : w(w), h(h), src_data(data), sent_to_gpu(false) {} }; GLTexture& m_texture; std::vector m_levels; - bool m_is_compressing; - bool m_abort_compressing; + std::thread m_thread; + // Does the caller want the background thread to stop? + // This atomic also works as a memory barrier for synchronizing the cancel event with the worker thread. + std::atomic m_abort_compressing; + // How many levels were compressed since the start of the background processing thread? + // This atomic also works as a memory barrier for synchronizing results of the worker thread with the calling thread. + std::atomic m_num_levels_compressed; public: - explicit Compressor(GLTexture& texture) : m_texture(texture), m_is_compressing(false), m_abort_compressing(false) {} + explicit Compressor(GLTexture& texture) : m_texture(texture), m_abort_compressing(false), m_num_levels_compressed(0) {} + ~Compressor() { reset(); } void reset(); - void add_level(unsigned int w, unsigned int h, const std::vector& data); + void add_level(unsigned int w, unsigned int h, const std::vector& data) { m_levels.emplace_back(w, h, data); } void start_compressing(); bool unsent_compressed_data_available() const; void send_compressed_data_to_gpu(); - bool all_compressed_data_sent_to_gpu() const; + bool all_compressed_data_sent_to_gpu() const { return m_levels.empty(); } private: void compress(); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index df116d9e6..f9252c85c 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -126,7 +126,16 @@ static void generic_exception_handle() try { throw; - } catch (const std::exception &ex) { + } catch (const std::bad_alloc& ex) { + // bad_alloc in main thread is most likely fatal. Report immediately to the user (wxLogError would be delayed) + // and terminate the app so it is at least certain to happen now. + wxString errmsg = wxString::Format(_(L("%s has encountered an error. It was likely caused by running out of memory. " + "If you are sure you have enough RAM on your system, this may also be a bug and we would " + "be glad if you reported it.\n\nThe application will now terminate.")), SLIC3R_APP_NAME); + wxMessageBox(errmsg + "\n\n" + wxString(ex.what()), _(L("Fatal error")), wxOK | wxICON_ERROR); + BOOST_LOG_TRIVIAL(error) << boost::format("std::bad_alloc exception: %1%") % ex.what(); + std::terminate(); + } catch (const std::exception& ex) { wxLogError("Internal error: %s", ex.what()); BOOST_LOG_TRIVIAL(error) << boost::format("Uncaught exception: %1%") % ex.what(); throw; @@ -173,7 +182,8 @@ bool GUI_App::on_init_inner() wxCHECK_MSG(wxDirExists(resources_dir), false, wxString::Format("Resources path does not exist or is not a directory: %s", resources_dir)); - SetAppName(SLIC3R_APP_KEY); + //SetAppName(SLIC3R_APP_KEY); + SetAppName(SLIC3R_APP_KEY "-beta"); SetAppDisplayName(SLIC3R_APP_NAME); // Enable this to get the default Win32 COMCTRL32 behavior of static boxes. @@ -283,6 +293,20 @@ bool GUI_App::on_init_inner() config_wizard_startup(app_conf_exists); preset_updater->slic3r_update_notify(); preset_updater->sync(preset_bundle); + const GLCanvas3DManager::GLInfo &glinfo = GLCanvas3DManager::get_gl_info(); + if (! glinfo.is_version_greater_or_equal_to(2, 0)) { + // Complain about the OpenGL version. + wxString message = wxString::Format( + _(L("PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n" + "while OpenGL version %s, render %s, vendor %s was detected.")), wxString(glinfo.get_version()), wxString(glinfo.get_renderer()), wxString(glinfo.get_vendor())); + message += "\n"; + message += _(L("You may need to update your graphics card driver.")); +#ifdef _WIN32 + message += "\n"; + message += _(L("As a workaround, you may run PrusaSlicer with a software rendered 3D graphics by running prusa-slicer.exe with the --sw_renderer parameter.")); +#endif + wxMessageBox(message, wxString("PrusaSlicer - ") + _(L("Unsupported OpenGL version")), wxOK | wxICON_ERROR); + } }); } }); @@ -986,6 +1010,7 @@ wxString GUI_App::current_language_code_safe() const language_code = language_code.substr(0, idx_underscore); const std::map mapping { { "cs", "cs_CZ", }, + { "sk", "cs_CZ", }, { "de", "de_DE", }, { "es", "es_ES", }, { "fr", "fr_FR", }, diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 77051a957..7aded241b 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -17,6 +17,10 @@ #include #include "slic3r/Utils/FixModelByWin10.hpp" +#ifdef __WXMSW__ +#include "wx/uiaction.h" +#endif /* __WXMSW__ */ + namespace Slic3r { namespace GUI @@ -119,6 +123,10 @@ ObjectList::ObjectList(wxWindow* parent) : * instead of real last clicked item. * So, let check last selected item in such strange way */ +#ifdef __WXMSW__ + // Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected. + int new_selected_column = -1; +#endif __WXMSW__ if (wxGetKeyState(WXK_SHIFT)) { wxDataViewItemArray sels; @@ -128,13 +136,34 @@ ObjectList::ObjectList(wxWindow* parent) : else m_last_selected_item = event.GetItem(); } - else - m_last_selected_item = event.GetItem(); + else { + wxDataViewItem new_selected_item = event.GetItem(); +#ifdef __WXMSW__ + // Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected. + wxDataViewItem item; + wxDataViewColumn *col; + this->HitTest(get_mouse_position_in_control(), item, col); + new_selected_column = (col == nullptr) ? -1 : (int)col->GetModelColumn(); + if (new_selected_item == m_last_selected_item && m_last_selected_column != -1 && m_last_selected_column != new_selected_column) { + // Mouse clicked on another column of the active row. Simulate keyboard enter to enter the editing mode of the current column. + wxUIActionSimulator sim; + sim.Char(WXK_RETURN); + } +#endif __WXMSW__ + m_last_selected_item = new_selected_item; + } +#ifdef __WXMSW__ + m_last_selected_column = new_selected_column; +#endif __WXMSW__ selection_changed(); #ifndef __WXMSW__ set_tooltip_for_item(get_mouse_position_in_control()); -#endif //__WXMSW__ +#endif //__WXMSW__ + +#ifndef __WXOSX__ + list_manipulation(); +#endif //__WXOSX__ }); #ifdef __WXOSX__ @@ -169,7 +198,7 @@ ObjectList::ObjectList(wxWindow* parent) : #ifdef __WXMSW__ GetMainWindow()->Bind(wxEVT_MOTION, [this](wxMouseEvent& event) { - set_tooltip_for_item(/*event.GetPosition()*/get_mouse_position_in_control()); + set_tooltip_for_item(get_mouse_position_in_control()); event.Skip(); }); #endif //__WXMSW__ @@ -180,13 +209,27 @@ ObjectList::ObjectList(wxWindow* parent) : Bind(wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE, &ObjectList::OnDropPossible, this); Bind(wxEVT_DATAVIEW_ITEM_DROP, &ObjectList::OnDrop, this); - Bind(wxEVT_DATAVIEW_ITEM_EDITING_DONE, &ObjectList::OnEditingDone, this); +#ifdef __WXMSW__ + Bind(wxEVT_DATAVIEW_ITEM_EDITING_STARTED, &ObjectList::OnEditingStarted, this); +#endif /* __WXMSW__ */ + Bind(wxEVT_DATAVIEW_ITEM_EDITING_DONE, &ObjectList::OnEditingDone, this); Bind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &ObjectList::ItemValueChanged, this); Bind(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, [this](wxCommandEvent& e) { last_volume_is_deleted(e.GetInt()); }); - Bind(wxEVT_SIZE, ([this](wxSizeEvent &e) { this->EnsureVisible(this->GetCurrentItem()); e.Skip(); })); + Bind(wxEVT_SIZE, ([this](wxSizeEvent &e) { +#ifdef __WXGTK__ + // On GTK, the EnsureVisible call is postponed to Idle processing (see wxDataViewCtrl::m_ensureVisibleDefered). + // So the postponed EnsureVisible() call is planned for an item, which may not exist at the Idle processing time, if this wxEVT_SIZE + // event is succeeded by a delete of the currently active item. We are trying our luck by postponing the wxEVT_SIZE triggered EnsureVisible(), + // which seems to be working as of now. + this->CallAfter([this](){ this->EnsureVisible(this->GetCurrentItem()); }); +#else + this->EnsureVisible(this->GetCurrentItem()); +#endif + e.Skip(); + })); } ObjectList::~ObjectList() @@ -212,16 +255,20 @@ void ObjectList::create_objects_ctrl() EnableDropTarget(wxDF_UNICODETEXT); #endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE - // column 0(Icon+Text) of the view control: + // column ItemName(Icon+Text) of the view control: // And Icon can be consisting of several bitmaps AppendColumn(new wxDataViewColumn(_(L("Name")), new BitmapTextRenderer(), - 0, 20*wxGetApp().em_unit()/*200*/, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE)); + colName, 20*wxGetApp().em_unit()/*200*/, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE)); - // column 1 of the view control: + // column PrintableProperty (Icon) of the view control: + AppendBitmapColumn(" ", colPrint, wxDATAVIEW_CELL_INERT, int(2 * wxGetApp().em_unit()), + wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); + + // column Extruder of the view control: AppendColumn(create_objects_list_extruder_column(4)); - // column 2 of the view control: - AppendBitmapColumn(" ", 2, wxDATAVIEW_CELL_INERT, int(2.5 * wxGetApp().em_unit())/*25*/, + // column ItemEditing of the view control: + AppendBitmapColumn("Editing", colEditing, wxDATAVIEW_CELL_INERT, int(2.5 * wxGetApp().em_unit())/*25*/, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); } @@ -315,28 +362,34 @@ void ObjectList::set_tooltip_for_item(const wxPoint& pt) * Just this->SetToolTip(tooltip) => has no effect. */ - if (!item) + if (!item || GetSelectedItemsCount() > 1) { GetMainWindow()->SetToolTip(""); // hide tooltip return; } - if (col->GetTitle() == " " && GetSelectedItemsCount()<2) - GetMainWindow()->SetToolTip(_(L("Right button click the icon to change the object settings"))); - else if (col->GetTitle() == _("Name")) - { -#ifdef __WXMSW__ - if (pt.x < 2 * wxGetApp().em_unit() || pt.x > 4 * wxGetApp().em_unit()) { - GetMainWindow()->SetToolTip(""); // hide tooltip - return; - } + wxString tooltip = ""; + + if (col->GetTitle() == _(L("Editing"))) +#ifdef __WXOSX__ + tooltip = _(L("Right button click the icon to change the object settings")); +#else + tooltip = _(L("Click the icon to change the object settings")); #endif //__WXMSW__ + else if (col->GetTitle() == " ") +#ifdef __WXOSX__ + tooltip = _(L("Right button click the icon to change the object printable property")); +#else + tooltip = _(L("Click the icon to change the object printable property")); +#endif //__WXMSW__ + else if (col->GetTitle() == _("Name") && (pt.x >= 2 * wxGetApp().em_unit() && pt.x <= 4 * wxGetApp().em_unit())) + { int obj_idx, vol_idx; get_selected_item_indexes(obj_idx, vol_idx, item); - GetMainWindow()->SetToolTip(get_mesh_errors_list(obj_idx, vol_idx)); + tooltip = get_mesh_errors_list(obj_idx, vol_idx); } - else - GetMainWindow()->SetToolTip(""); // hide tooltip + + GetMainWindow()->SetToolTip(tooltip); } wxPoint ObjectList::get_mouse_position_in_control() @@ -377,7 +430,7 @@ wxDataViewColumn* ObjectList::create_objects_list_extruder_column(int extruders_ choices.Add(wxString::Format("%d", i)); wxDataViewChoiceRenderer *c = new wxDataViewChoiceRenderer(choices, wxDATAVIEW_CELL_EDITABLE, wxALIGN_CENTER_HORIZONTAL); - wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, 1, + wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, colExtruder, 8*wxGetApp().em_unit()/*80*/, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); return column; } @@ -397,7 +450,7 @@ void ObjectList::update_extruder_values_for_items(const int max_extruder) else extruder = wxString::Format("%d", object->config.option("extruder")->value); - m_objects_model->SetValue(extruder, item, 1); + m_objects_model->SetValue(extruder, item, colExtruder); if (object->volumes.size() > 1) { for (auto id = 0; id < object->volumes.size(); id++) { @@ -409,7 +462,7 @@ void ObjectList::update_extruder_values_for_items(const int max_extruder) else extruder = wxString::Format("%d", object->volumes[id]->config.option("extruder")->value); - m_objects_model->SetValue(extruder, item, 1); + m_objects_model->SetValue(extruder, item, colExtruder); } } } @@ -421,7 +474,7 @@ void ObjectList::update_objects_list_extruder_column(int extruders_count) if (printer_technology() == ptSLA) extruders_count = 1; - wxDataViewChoiceRenderer* ch_render = dynamic_cast(GetColumn(1)->GetRenderer()); + wxDataViewChoiceRenderer* ch_render = dynamic_cast(GetColumn(colExtruder)->GetRenderer()); if (ch_render->GetChoices().GetCount() - 1 == extruders_count) return; @@ -430,21 +483,21 @@ void ObjectList::update_objects_list_extruder_column(int extruders_count) if (m_objects && extruders_count > 1) update_extruder_values_for_items(extruders_count); - // delete old 2nd column - DeleteColumn(GetColumn(1)); - // insert new created 3rd column - InsertColumn(1, create_objects_list_extruder_column(extruders_count)); + // delete old extruder column + DeleteColumn(GetColumn(colExtruder)); + // insert new created extruder column + InsertColumn(colExtruder, create_objects_list_extruder_column(extruders_count)); // set show/hide for this column set_extruder_column_hidden(extruders_count <= 1); //a workaround for a wrong last column width updating under OSX - GetColumn(2)->SetWidth(25); + GetColumn(colEditing)->SetWidth(25); m_prevent_update_extruder_in_config = false; } void ObjectList::set_extruder_column_hidden(const bool hide) const { - GetColumn(1)->SetHidden(hide); + GetColumn(colExtruder)->SetHidden(hide); } void ObjectList::update_extruder_in_config(const wxDataViewItem& item) @@ -471,7 +524,7 @@ void ObjectList::update_extruder_in_config(const wxDataViewItem& item) } wxVariant variant; - m_objects_model->GetValue(variant, item, 1); + m_objects_model->GetValue(variant, item, colExtruder); const wxString selection = variant.GetString(); if (!m_config || selection.empty()) @@ -490,7 +543,7 @@ void ObjectList::update_name_in_model(const wxDataViewItem& item) const if (obj_idx < 0) return; const int volume_id = m_objects_model->GetVolumeIdByItem(item); - take_snapshot(wxString::Format(_(L("Rename %s")), volume_id < 0 ? _(L("Object")) : _(L("Sub-object")))); + take_snapshot(volume_id < 0 ? _(L("Rename Object")) : _(L("Rename Sub-object"))); if (m_objects_model->GetItemType(item) & itObject) { (*m_objects)[obj_idx]->name = m_objects_model->GetName(item).ToUTF8().data(); @@ -729,26 +782,31 @@ void ObjectList::OnChar(wxKeyEvent& event) #endif /* __WXOSX__ */ void ObjectList::OnContextMenu(wxDataViewEvent&) +{ + list_manipulation(); +} + +void ObjectList::list_manipulation() { wxDataViewItem item; wxDataViewColumn* col; const wxPoint pt = get_mouse_position_in_control(); HitTest(pt, item, col); - if (!item) #ifdef __WXOSX__ // temporary workaround for OSX - // after Yosemite OS X version, HitTest return undefined item - item = GetSelection(); - if (item) - show_context_menu(); - else - printf("undefined item\n"); - return; -#else - return; + // after Yosemite OS X version, HitTest return undefined item + if (!item) item = GetSelection(); #endif // __WXOSX__ + + if (!item) { + printf("undefined item\n"); + return; + } + const wxString title = col->GetTitle(); if (title == " ") + toggle_printable_state(item); + else if (title == _("Editing")) show_context_menu(); else if (title == _("Name")) { @@ -1013,6 +1071,11 @@ const std::vector& ObjectList::get_options_for_bundle(const wxStrin return empty; } +static bool improper_category(const std::string& category, const int extruders_cnt) +{ + return category.empty() || (extruders_cnt == 1 && (category == "Extruders" || category == "Wipe options" )); +} + void ObjectList::get_options_menu(settings_menu_hierarchy& settings_menu, const bool is_part) { auto options = get_options(is_part); @@ -1024,8 +1087,8 @@ void ObjectList::get_options_menu(settings_menu_hierarchy& settings_menu, const { auto const opt = config.def()->get(option); auto category = opt->category; - if (category.empty() || - (category == "Extruders" && extruders_cnt == 1)) continue; + if (improper_category(category, extruders_cnt)) + continue; const std::string& label = !opt->full_label.empty() ? opt->full_label : opt->label; std::pair option_label(option, label); @@ -1043,8 +1106,10 @@ void ObjectList::get_settings_choice(const wxString& category_name) wxArrayInt selections; wxDataViewItem item = GetSelection(); + const ItemType item_type = m_objects_model->GetItemType(item); + settings_menu_hierarchy settings_menu; - const bool is_part = m_objects_model->GetItemType(item) & (itVolume | itLayer); + const bool is_part = item_type & (itVolume | itLayer); get_options_menu(settings_menu, is_part); std::vector< std::pair > *settings_list = nullptr; @@ -1121,7 +1186,10 @@ void ObjectList::get_settings_choice(const wxString& category_name) } #endif - take_snapshot(wxString::Format(_(L("Add Settings for %s")), is_part ? _(L("Sub-object")) : _(L("Object")))); + const wxString snapshot_text = item_type & itLayer ? _(L("Add Settings for Layers")) : + item_type & itVolume ? _(L("Add Settings for Sub-object")) : + _(L("Add Settings for Object")); + take_snapshot(snapshot_text); std::vector selected_options; selected_options.reserve(selection_cnt); @@ -1153,7 +1221,7 @@ void ObjectList::get_settings_choice(const wxString& category_name) // Add settings item for object/sub-object and show them - if (!(m_objects_model->GetItemType(item) & (itObject | itVolume | itLayer))) + if (!(item_type & (itObject | itVolume | itLayer))) item = m_objects_model->GetTopParent(item); show_settings(add_settings_item(item, m_config)); } @@ -1163,11 +1231,13 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name) std::vector options = get_options_for_bundle(bundle_name); wxDataViewItem item = GetSelection(); + ItemType item_type = m_objects_model->GetItemType(item); + /* Because of we couldn't edited layer_height for ItVolume from settings list, * correct options according to the selected item type : * remove "layer_height" option */ - if ((m_objects_model->GetItemType(item) & itVolume) && bundle_name == _("Layers and Perimeters")) { + if ((item_type & itVolume) && bundle_name == _("Layers and Perimeters")) { const auto layer_height_it = std::find(options.begin(), options.end(), "layer_height"); if (layer_height_it != options.end()) options.erase(layer_height_it); @@ -1179,7 +1249,10 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name) assert(m_config); auto opt_keys = m_config->keys(); - take_snapshot(wxString::Format(_(L("Add Settings Bundle for %s")), m_objects_model->GetItemType(item) & (itVolume|itLayer) ? _(L("Sub-object")) : _(L("Object")))); + const wxString snapshot_text = item_type & itLayer ? _(L("Add Settings Bundle for Layers")) : + item_type & itVolume ? _(L("Add Settings Bundle for Sub-object")) : + _(L("Add Settings Bundle for Object")); + take_snapshot(snapshot_text); const DynamicPrintConfig& from_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; for (auto& opt_key : options) @@ -1196,7 +1269,7 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name) } // Add settings item for object/sub-object and show them - if (!(m_objects_model->GetItemType(item) & (itObject | itVolume | itLayer))) + if (!(item_type & (itObject | itVolume | itLayer))) item = m_objects_model->GetTopParent(item); show_settings(add_settings_item(item, m_config)); } @@ -1211,26 +1284,6 @@ void ObjectList::show_settings(const wxDataViewItem settings_item) // update object selection on Plater if (!m_prevent_canvas_selection_update) update_selections_on_canvas(); -/* auto item = GetSelection(); - if (item) { - if (m_objects_model->GetItemType(item) == itInstance) - item = m_objects_model->GetTopParent(item); - const auto settings_item = m_objects_model->IsSettingsItem(item) ? item : m_objects_model->GetSettingsItem(item); - select_item(settings_item ? settings_item : - m_objects_model->AddSettingsChild(item)); - - // update object selection on Plater - if (!m_prevent_canvas_selection_update) - update_selections_on_canvas(); - } - else { - //# ys_FIXME ??? use case ??? - auto panel = wxGetApp().sidebar().scrolled_panel(); - panel->Freeze(); - wxGetApp().obj_settings()->UpdateAndShow(true); - panel->Thaw(); - } - */ } wxMenu* ObjectList::append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type) { @@ -1380,6 +1433,13 @@ wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu, wxWind [this](wxCommandEvent&) { split_instances(); }, "", menu, [](){return wxGetApp().plater()->can_set_instance_to_object(); }, parent); } +wxMenuItem* ObjectList::append_menu_item_printable(wxMenu* menu, wxWindow* parent) +{ + return append_menu_check_item(menu, wxID_ANY, _(L("Printable")), "", [this](wxCommandEvent&) { + wxGetApp().plater()->canvas3D()->get_selection().toggle_instance_printable_state(); + }, menu); +} + void ObjectList::append_menu_items_osx(wxMenu* menu) { append_menu_item(menu, wxID_ANY, _(L("Rename")), "", @@ -1547,7 +1607,7 @@ void ObjectList::create_freq_settings_popupmenu(wxMenu *menu) const int extruders_cnt = extruders_count(); for (auto& it : bundle) { - if (it.first.empty() || it.first == "Extruders" && extruders_cnt == 1) + if (improper_category(it.first, extruders_cnt)) continue; append_menu_item(menu, wxID_ANY, _(it.first), "", @@ -1560,7 +1620,7 @@ void ObjectList::create_freq_settings_popupmenu(wxMenu *menu) m_freq_settings_fff : m_freq_settings_sla; for (auto& it : bundle_quick) { - if (it.first.empty() || it.first == "Extruders" && extruders_cnt == 1) + if (improper_category(it.first, extruders_cnt)) continue; append_menu_item(menu, wxID_ANY, wxString::Format(_(L("Quick Add Settings (%s)")), _(it.first)), "", @@ -1599,6 +1659,9 @@ void ObjectList::load_subobject(ModelVolumeType type) changed_object(obj_idx); + if (type == ModelVolumeType::MODEL_PART) + // update printable state on canvas + wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object((size_t)obj_idx); wxDataViewItem sel_item; for (const auto& volume : volumes_info ) @@ -1722,6 +1785,9 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode new_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); changed_object(obj_idx); + if (type == ModelVolumeType::MODEL_PART) + // update printable state on canvas + wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object((size_t)obj_idx); const auto object_item = m_objects_model->GetTopParent(GetSelection()); select_item(m_objects_model->AddVolumeChild(object_item, name, type, @@ -1765,7 +1831,19 @@ void ObjectList::del_subobject_item(wxDataViewItem& item) if (type & itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0) m_objects_model->DeleteWarningIcon(m_objects_model->GetParent(item)); + // If last two Instances of object is selected, show the message about impossible action + bool show_msg = false; + if (type & itInstance) { + wxDataViewItemArray instances; + m_objects_model->GetChildren(m_objects_model->GetParent(item), instances); + if (instances.Count() == 2 && IsSelected(instances[0]) && IsSelected(instances[1])) + show_msg = true; + } + m_objects_model->Delete(item); + + if (show_msg) + Slic3r::GUI::show_error(nullptr, _(L("Last instance of an object cannot be deleted."))); } void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item) @@ -1848,7 +1926,7 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con if (vol->is_model_part()) ++solid_cnt; if (volume->is_model_part() && solid_cnt == 1) { - Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last solid part from object."))); + Slic3r::GUI::show_error(nullptr, _(L("From Object List You can't delete the last solid part from object."))); return false; } @@ -1867,7 +1945,7 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con } else if (type == itInstance) { if (object->instances.size() == 1) { - Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last intance from object."))); + Slic3r::GUI::show_error(nullptr, _(L("Last instance of an object cannot be deleted."))); return false; } @@ -1894,13 +1972,15 @@ void ObjectList::split() DynamicPrintConfig& config = printer_config(); const ConfigOption *nozzle_dmtrs_opt = config.option("nozzle_diameter", false); const auto nozzle_dmrs_cnt = (nozzle_dmtrs_opt == nullptr) ? size_t(1) : dynamic_cast(nozzle_dmtrs_opt)->values.size(); - if (volume->split(nozzle_dmrs_cnt) == 1) { + if (!volume->is_splittable()) { wxMessageBox(_(L("The selected object couldn't be split because it contains only one part."))); return; } take_snapshot(_(L("Split to Parts"))); + volume->split(nozzle_dmrs_cnt); + wxBusyCursor wait; auto model_object = (*m_objects)[obj_idx]; @@ -2182,7 +2262,7 @@ SettingsBundle ObjectList::get_item_settings_bundle(const DynamicPrintConfig* co for (auto& opt_key : opt_keys) { auto category = config->def()->get(opt_key)->category; - if (category.empty() || (category == "Extruders" && extruders_cnt == 1)) + if (improper_category(category, extruders_cnt)) continue; std::vector< std::string > new_category; @@ -2253,7 +2333,17 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed) // add instances to the object, if it has those if (model_object->instances.size()>1) - increase_object_instances(obj_idx, model_object->instances.size()); + { + std::vector print_idicator(model_object->instances.size()); + for (int i = 0; i < model_object->instances.size(); ++i) + print_idicator[i] = model_object->instances[i]->printable; + + const wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx); + m_objects_model->AddInstanceChild(object_item, print_idicator); + Expand(m_objects_model->GetInstanceRootItem(object_item)); + } + else + m_objects_model->SetPrintableState(model_object->instances[0]->printable ? piPrintable : piUnprintable, obj_idx); // add settings to the object, if it has those add_settings_item(item, &model_object->config); @@ -2335,7 +2425,7 @@ void ObjectList::delete_from_model_and_list(const std::vector& it (*m_objects)[item->obj_idx]->config.has("extruder")) { const wxString extruder = wxString::Format("%d", (*m_objects)[item->obj_idx]->config.option("extruder")->value); - m_objects_model->SetValue(extruder, m_objects_model->GetItemById(item->obj_idx), 1); + m_objects_model->SetValue(extruder, m_objects_model->GetItemById(item->obj_idx), colExtruder); } wxGetApp().plater()->canvas3D()->ensure_on_bed(item->obj_idx); } @@ -2405,33 +2495,47 @@ void ObjectList::remove() if (GetSelectedItemsCount() == 0) return; - wxDataViewItemArray sels; - GetSelections(sels); - - wxDataViewItem parent = wxDataViewItem(0); - - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Delete Selected"))); - - for (auto& item : sels) + auto delete_item = [this](wxDataViewItem item) { - if (m_objects_model->GetParent(item) == wxDataViewItem(0)) + wxDataViewItem parent = m_objects_model->GetParent(item); + if (m_objects_model->GetItemType(item) & itObject) delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1); else { if (m_objects_model->GetItemType(item) & itLayer) { - parent = m_objects_model->GetParent(item); wxDataViewItemArray children; if (m_objects_model->GetChildren(parent, children) == 1) parent = m_objects_model->GetTopParent(item); } - else if (sels.size() == 1) - select_item(m_objects_model->GetParent(item)); del_subobject_item(item); } + + return parent; + }; + + wxDataViewItemArray sels; + GetSelections(sels); + + wxDataViewItem parent = wxDataViewItem(0); + + if (sels.Count() == 1) + parent = delete_item(GetSelection()); + else + { + Plater::TakeSnapshot snapshot = Plater::TakeSnapshot(wxGetApp().plater(), _(L("Delete Selected"))); + + for (auto& item : sels) + { + if (m_objects_model->InvalidItem(item)) // item can be deleted for this moment (like last 2 Instances or Volumes) + continue; + parent = delete_item(item); + } } - if (parent) + if (parent && !m_objects_model->InvalidItem(parent)) { select_item(parent); + update_selections_on_canvas(); + } } void ObjectList::del_layer_range(const t_layer_height_range& range) @@ -2452,13 +2556,13 @@ void ObjectList::del_layer_range(const t_layer_height_range& range) select_item(selectable_item); } -double get_min_layer_height(const int extruder_idx) +static double get_min_layer_height(const int extruder_idx) { const DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config; return config.opt_float("min_layer_height", extruder_idx <= 0 ? 0 : extruder_idx-1); } -double get_max_layer_height(const int extruder_idx) +static double get_max_layer_height(const int extruder_idx) { const DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config; return config.opt_float("max_layer_height", extruder_idx <= 0 ? 0 : extruder_idx-1); @@ -2595,6 +2699,9 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_lay ranges[new_range] = config; wxDataViewItem root_item = m_objects_model->GetLayerRootItem(m_objects_model->GetItemById(obj_idx)); + // To avoid update selection after deleting of a selected item (under GTK) + // set m_prevent_list_events to true + m_prevent_list_events = true; m_objects_model->DeleteChildren(root_item); if (root_item.IsOk()) @@ -2685,8 +2792,12 @@ void ObjectList::update_selections() } else if (m_selection_mode & smLayerRoot) sels.Add(m_objects_model->GetLayerRootItem(obj_item)); - else if (m_selection_mode & smLayer) - sels.Add(m_objects_model->GetItemByLayerId(obj_idx, m_selected_layers_range_idx)); + else if (m_selection_mode & smLayer) { + if (m_selected_layers_range_idx >= 0) + sels.Add(m_objects_model->GetItemByLayerId(obj_idx, m_selected_layers_range_idx)); + else + sels.Add(obj_item); + } } else { for (const auto& object : objects_content) { @@ -2824,7 +2935,7 @@ void ObjectList::update_selections_on_canvas() else { mode = Selection::Instance; - single_selection = false; + single_selection &= (obj_idx != selection.get_object_idx()); std::vector idxs = selection.get_volume_idxs_from_object(obj_idx); volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end()); } @@ -2845,6 +2956,9 @@ void ObjectList::update_selections_on_canvas() wxDataViewItemArray sels; GetSelections(sels); + // clear selection before adding new elements + selection.clear(); //OR remove_all()? + for (auto item : sels) { add_to_selection(item, selection, instance_idx, mode); @@ -3160,33 +3274,6 @@ void ObjectList::last_volume_is_deleted(const int obj_idx) volume->config.set_key_value("extruder", new ConfigOptionInt(0)); } -/* #lm_FIXME_delete_after_testing -void ObjectList::update_settings_items() -{ - m_prevent_canvas_selection_update = true; - wxDataViewItemArray sel; - GetSelections(sel); // stash selection - - wxDataViewItemArray items; - m_objects_model->GetChildren(wxDataViewItem(0), items); - - for (auto& item : items) { - const wxDataViewItem& settings_item = m_objects_model->GetSettingsItem(item); - select_item(settings_item ? settings_item : m_objects_model->AddSettingsChild(item)); - - // If settings item was deleted from the list, - // it's need to be deleted from selection array, if it was there - if (settings_item != m_objects_model->GetSettingsItem(item) && - sel.Index(settings_item) != wxNOT_FOUND) { - sel.Remove(settings_item); - } - } - - // restore selection: - SetSelections(sel); - m_prevent_canvas_selection_update = false; -} -*/ void ObjectList::update_and_show_object_settings_item() { const wxDataViewItem item = GetSelection(); @@ -3321,7 +3408,8 @@ void ObjectList::instances_to_separated_object(const int obj_idx, const std::set } // Add new object to the object_list - add_object_to_list(m_objects->size() - 1); + const size_t new_obj_indx = static_cast(m_objects->size() - 1); + add_object_to_list(new_obj_indx); for (std::set::const_reverse_iterator it = inst_idxs.rbegin(); it != inst_idxs.rend(); ++it) { @@ -3329,12 +3417,17 @@ void ObjectList::instances_to_separated_object(const int obj_idx, const std::set del_subobject_from_object(obj_idx, *it, itInstance); delete_instance_from_list(obj_idx, *it); } + + // update printable state for new volumes on canvas3D + wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object(new_obj_indx); } void ObjectList::instances_to_separated_objects(const int obj_idx) { const int inst_cnt = (*m_objects)[obj_idx]->instances.size(); + std::vector object_idxs; + for (int i = inst_cnt-1; i > 0 ; i--) { // create new object from initial @@ -3348,12 +3441,17 @@ void ObjectList::instances_to_separated_objects(const int obj_idx) } // Add new object to the object_list - add_object_to_list(m_objects->size() - 1); + const size_t new_obj_indx = static_cast(m_objects->size() - 1); + add_object_to_list(new_obj_indx); + object_idxs.push_back(new_obj_indx); // delete current instance from the initial object del_subobject_from_object(obj_idx, i, itInstance); delete_instance_from_list(obj_idx, i); } + + // update printable state for new volumes on canvas3D + wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_objects(object_idxs); } void ObjectList::split_instances() @@ -3408,7 +3506,7 @@ void ObjectList::rename_item() // The icon can't be edited so get its old value and reuse it. wxVariant valueOld; - m_objects_model->GetValue(valueOld, item, 0); + m_objects_model->GetValue(valueOld, item, colName); DataViewBitmapText bmpText; bmpText << valueOld; @@ -3418,7 +3516,7 @@ void ObjectList::rename_item() wxVariant value; value << bmpText; - m_objects_model->SetValue(value, item, 0); + m_objects_model->SetValue(value, item, colName); m_objects_model->ItemChanged(item); update_name_in_model(item); @@ -3459,9 +3557,10 @@ void ObjectList::msw_rescale() // update min size !!! A width of control shouldn't be a wxDefaultCoord SetMinSize(wxSize(1, 15 * em)); - GetColumn(0)->SetWidth(19 * em); - GetColumn(1)->SetWidth( 8 * em); - GetColumn(2)->SetWidth( 2 * em); + GetColumn(colName)->SetWidth(19 * em); + GetColumn(colPrint)->SetWidth( 2 * em); + GetColumn(colExtruder)->SetWidth( 8 * em); + GetColumn(colEditing)->SetWidth( 2 * em); // rescale all icons, used by ObjectList msw_rescale_icons(); @@ -3482,24 +3581,39 @@ void ObjectList::msw_rescale() void ObjectList::ItemValueChanged(wxDataViewEvent &event) { - if (event.GetColumn() == 0) + if (event.GetColumn() == colName) update_name_in_model(event.GetItem()); - else if (event.GetColumn() == 1) + else if (event.GetColumn() == colExtruder) update_extruder_in_config(event.GetItem()); } +#ifdef __WXMSW__ +// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected. +// Here the last active column is forgotten, so when leaving the editing mode, the next mouse click will not enter the editing mode of the newly selected column. +void ObjectList::OnEditingStarted(wxDataViewEvent &event) +{ + m_last_selected_column = -1; +} +#endif __WXMSW__ + void ObjectList::OnEditingDone(wxDataViewEvent &event) { - if (event.GetColumn() != 0) + if (event.GetColumn() != colName) return; - const auto renderer = dynamic_cast(GetColumn(0)->GetRenderer()); + const auto renderer = dynamic_cast(GetColumn(colName)->GetRenderer()); if (renderer->WasCanceled()) wxTheApp->CallAfter([this]{ show_error(this, _(L("The supplied name is not valid;")) + "\n" + _(L("the following characters are not allowed:")) + " <>:/\\|?*\""); }); + +#ifdef __WXMSW__ + // Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected. + // Here the last active column is forgotten, so when leaving the editing mode, the next mouse click will not enter the editing mode of the newly selected column. + m_last_selected_column = -1; +#endif __WXMSW__ } void ObjectList::show_multi_selection_menu() @@ -3575,7 +3689,7 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const /* We can change extruder for Object/Volume only. * So, if Instance is selected, get its Object item and change it */ - m_objects_model->SetValue(extruder_str, type & itInstance ? m_objects_model->GetTopParent(item) : item, 1); + m_objects_model->SetValue(extruder_str, type & itInstance ? m_objects_model->GetTopParent(item) : item, colExtruder); const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) : m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); @@ -3598,18 +3712,69 @@ void ObjectList::update_after_undo_redo() m_objects_model->DeleteAll(); size_t obj_idx = 0; + std::vector obj_idxs; + obj_idxs.reserve(m_objects->size()); while (obj_idx < m_objects->size()) { add_object_to_list(obj_idx, false); + obj_idxs.push_back(obj_idx); ++obj_idx; } -#ifndef __WXOSX__ -// selection_changed(); -#endif /* __WXOSX__ */ - update_selections(); m_prevent_canvas_selection_update = false; + + // update printable states on canvas + wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_objects(obj_idxs); + // update scene + wxGetApp().plater()->update(); +} + +void ObjectList::update_printable_state(int obj_idx, int instance_idx) +{ + ModelObject* object = (*m_objects)[obj_idx]; + + const PrintIndicator printable = object->instances[instance_idx]->printable ? piPrintable : piUnprintable; + if (object->instances.size() == 1) + instance_idx = -1; + + m_objects_model->SetPrintableState(printable, obj_idx, instance_idx); +} + +void ObjectList::toggle_printable_state(wxDataViewItem item) +{ + const ItemType type = m_objects_model->GetItemType(item); + if (!(type&(itObject|itInstance/*|itVolume*/))) + return; + + if (type & itObject) + { + const int obj_idx = m_objects_model->GetObjectIdByItem(item); + ModelObject* object = (*m_objects)[obj_idx]; + + // get object's printable and change it + const bool printable = !m_objects_model->IsPrintable(item); + + const wxString snapshot_text = wxString::Format("%s %s", + printable ? _(L("Set Printable")) : _(L("Set Unprintable")), + object->name); + take_snapshot(snapshot_text); + + // set printable value for all instances in object + for (auto inst : object->instances) + inst->printable = printable; + + // update printable state on canvas + wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object((size_t)obj_idx); + + // update printable state in ObjectList + m_objects_model->SetObjectPrintableState(printable ? piPrintable : piUnprintable , item); + } + else + wxGetApp().plater()->canvas3D()->get_selection().toggle_instance_printable_state(); + + // update scene + wxGetApp().plater()->update(); } ModelObject* ObjectList::object(const int obj_idx) const @@ -3621,4 +3786,4 @@ ModelObject* ObjectList::object(const int obj_idx) const } } //namespace GUI -} //namespace Slic3r \ No newline at end of file +} //namespace Slic3r diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 39558d1c5..0164d20c1 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -157,6 +157,10 @@ private: int m_selected_row = 0; wxDataViewItem m_last_selected_item {nullptr}; +#ifdef __WXMSW__ + // Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected. + int m_last_selected_column = -1; +#endif /* __MSW__ */ #if 0 SettingsBundle m_freq_settings_fff; @@ -225,6 +229,7 @@ public: wxMenuItem* append_menu_item_settings(wxMenu* menu); wxMenuItem* append_menu_item_change_type(wxMenu* menu); wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent); + wxMenuItem* append_menu_item_printable(wxMenu* menu, wxWindow* parent); void append_menu_items_osx(wxMenu* menu); wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu); void append_menu_item_export_stl(wxMenu* menu) const ; @@ -348,12 +353,16 @@ public: void msw_rescale(); void update_after_undo_redo(); + //update printable state for item from objects model + void update_printable_state(int obj_idx, int instance_idx); + void toggle_printable_state(wxDataViewItem item); private: #ifdef __WXOSX__ // void OnChar(wxKeyEvent& event); #endif /* __WXOSX__ */ void OnContextMenu(wxDataViewEvent &event); + void list_manipulation(); void OnBeginDrag(wxDataViewEvent &event); void OnDropPossible(wxDataViewEvent &event); @@ -361,6 +370,10 @@ private: bool can_drop(const wxDataViewItem& item) const ; void ItemValueChanged(wxDataViewEvent &event); +#ifdef __WXMSW__ + // Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected. + void OnEditingStarted(wxDataViewEvent &event); +#endif /* __WXMSW__ */ void OnEditingDone(wxDataViewEvent &event); void show_multi_selection_menu(); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index a4aa3c6d8..29013389e 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -153,8 +153,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : auto manifold_warning_icon = [this](wxWindow* parent) { m_fix_throught_netfab_bitmap = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap); - auto sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(m_fix_throught_netfab_bitmap); +// auto sizer = new wxBoxSizer(wxHORIZONTAL); +// sizer->Add(m_fix_throught_netfab_bitmap); if (is_windows10()) m_fix_throught_netfab_bitmap->Bind(wxEVT_CONTEXT_MENU, [this](wxCommandEvent &e) @@ -167,17 +167,19 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : update_warning_icon_state(wxGetApp().obj_list()->get_mesh_errors_list()); }); - return sizer; +// return sizer; + return m_fix_throught_netfab_bitmap; }; - line.append_widget(manifold_warning_icon); + // line.append_widget(manifold_warning_icon); + line.near_label_widget = manifold_warning_icon; def.label = ""; def.gui_type = "legend"; def.tooltip = L("Object name"); #ifdef __APPLE__ - def.width = 19; + def.width = 20; #else - def.width = 21; + def.width = 22; #endif def.set_default_value(new ConfigOptionString{ " " }); line.append_option(Option(def, "object_name")); @@ -210,6 +212,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : wxSize btn_size(em_unit(parent) * mirror_btn_width, em_unit(parent) * mirror_btn_width); auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off", wxEmptyString, btn_size, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW); btn->SetToolTip(wxString::Format(_(L("Toggle %c axis mirroring")), (int)label)); + btn->SetBitmapDisabled_(m_mirror_bitmap_hidden); m_mirror_buttons[axis_idx].first = btn; m_mirror_buttons[axis_idx].second = mbShown; @@ -286,6 +289,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn, wxBU_EXACTFIT); btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Reset scale"))); change_scale_value(0, 100.); change_scale_value(1, 100.); change_scale_value(2, 100.); @@ -323,7 +327,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); selection.synchronize_unselected_volumes(); // Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. - canvas->do_rotate(L("Set Rotation")); + canvas->do_rotate(L("Reset Rotation")); UpdateAndShow(true); }); @@ -350,6 +354,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : const Geometry::Transformation& instance_trafo = volume->get_instance_transformation(); Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(volume)); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Drop to bed"))); change_position_value(0, diff.x()); change_position_value(1, diff.y()); change_position_value(2, diff.z()); @@ -389,10 +394,19 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : // call back for a rescale of button "Set uniform scale" m_og->rescale_near_label_widget = [this](wxWindow* win) { + // rescale lock icon auto *ctrl = dynamic_cast(win); - if (ctrl == nullptr) + if (ctrl != nullptr) { + ctrl->msw_rescale(); return; - ctrl->msw_rescale(); + } + + if (win == m_fix_throught_netfab_bitmap) + return; + + // rescale "place" of the empty icon (to correct layout of the "Size" and "Scale") + if (dynamic_cast(win) != nullptr) + win->SetMinSize(create_scaled_bitmap(m_parent, "one_layer_lock_on.png").GetSize()); }; } @@ -646,13 +660,13 @@ void ObjectManipulation::update_mirror_buttons_visibility() wxGetApp().CallAfter([this, new_states]{ for (int i=0; i<3; ++i) { if (new_states[i] != m_mirror_buttons[i].second) { - const wxBitmap* bmp; + const ScalableBitmap* bmp; switch (new_states[i]) { - case mbHidden : bmp = &m_mirror_bitmap_hidden.bmp(); m_mirror_buttons[i].first->Enable(false); break; - case mbShown : bmp = &m_mirror_bitmap_off.bmp(); m_mirror_buttons[i].first->Enable(true); break; - case mbActive : bmp = &m_mirror_bitmap_on.bmp(); m_mirror_buttons[i].first->Enable(true); break; + case mbHidden : bmp = &m_mirror_bitmap_hidden; m_mirror_buttons[i].first->Enable(false); break; + case mbShown : bmp = &m_mirror_bitmap_off; m_mirror_buttons[i].first->Enable(true); break; + case mbActive : bmp = &m_mirror_bitmap_on; m_mirror_buttons[i].first->Enable(true); break; } - m_mirror_buttons[i].first->SetBitmap(*bmp); + m_mirror_buttons[i].first->SetBitmap_(*bmp); m_mirror_buttons[i].second = new_states[i]; } } @@ -682,6 +696,7 @@ void ObjectManipulation::emulate_kill_focus() void ObjectManipulation::update_warning_icon_state(const wxString& tooltip) { m_fix_throught_netfab_bitmap->SetBitmap(tooltip.IsEmpty() ? wxNullBitmap : m_manifold_warning_bmp.bmp()); + m_fix_throught_netfab_bitmap->SetMinSize(tooltip.IsEmpty() ? wxSize(0,0) : m_manifold_warning_bmp.bmp().GetSize()); m_fix_throught_netfab_bitmap->SetToolTip(tooltip); } @@ -916,7 +931,10 @@ void ObjectManipulation::msw_rescale() { msw_rescale_word_local_combo(m_word_local_combo); m_manifold_warning_bmp.msw_rescale(); - m_fix_throught_netfab_bitmap->SetBitmap(m_manifold_warning_bmp.bmp()); + + const wxString& tooltip = m_fix_throught_netfab_bitmap->GetToolTipText(); + m_fix_throught_netfab_bitmap->SetBitmap(tooltip.IsEmpty() ? wxNullBitmap : m_manifold_warning_bmp.bmp()); + m_fix_throught_netfab_bitmap->SetMinSize(tooltip.IsEmpty() ? wxSize(0, 0) : m_manifold_warning_bmp.bmp().GetSize()); m_mirror_bitmap_on.msw_rescale(); m_mirror_bitmap_off.msw_rescale(); @@ -925,6 +943,9 @@ void ObjectManipulation::msw_rescale() m_reset_rotation_button->msw_rescale(); m_drop_to_bed_button->msw_rescale(); + for (int id = 0; id < 3; ++id) + m_mirror_buttons[id].first->msw_rescale(); + get_og()->msw_rescale(); } diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 19a0e785c..c90e1e4ed 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -9,6 +9,7 @@ #include #include "I18N.hpp" +#include "ConfigManipulation.hpp" #include @@ -117,7 +118,8 @@ bool ObjectSettings::update_settings_list() optgroup->label_width = 15; optgroup->sidetext_width = 5.5; - optgroup->m_on_change = [](const t_config_option_key& opt_id, const boost::any& value) { + optgroup->m_on_change = [this, config](const t_config_option_key& opt_id, const boost::any& value) { + this->update_config_values(config); wxGetApp().obj_list()->changed_object(); }; // call back for rescaling of the extracolumn control @@ -152,8 +154,10 @@ bool ObjectSettings::update_settings_list() m_og_settings.push_back(optgroup); } - if (!categories.empty()) + if (!categories.empty()) { objects_model->UpdateSettingsDigest(item, categories); + update_config_values(config); + } } else { @@ -164,6 +168,64 @@ bool ObjectSettings::update_settings_list() return true; } +void ObjectSettings::update_config_values(DynamicPrintConfig* config) +{ + const auto objects_model = wxGetApp().obj_list()->GetModel(); + const auto item = wxGetApp().obj_list()->GetSelection(); + const auto printer_technology = wxGetApp().plater()->printer_technology(); + const bool is_object_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itObject; + + if (!item || !objects_model->IsSettingsItem(item) || !config) + return; + + // update config values according to configuration hierarchy + DynamicPrintConfig main_config = printer_technology == ptFFF ? + wxGetApp().preset_bundle->prints.get_edited_preset().config : + wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; + + auto load_config = [this, config, &main_config]() + { + // load checked values from main_config to config + config->apply_only(main_config, config->keys(), true); + // Initialize UI components with the config values. + for (auto og : m_og_settings) + og->reload_config(); + // next config check + update_config_values(config); + }; + + auto get_field = [this](const t_config_option_key & opt_key, int opt_index) + { + Field* field = nullptr; + for (auto og : m_og_settings) { + field = og->get_fieldc(opt_key, opt_index); + if (field != nullptr) + return field; + } + return field; + }; + + ConfigManipulation config_manipulation(load_config, get_field, nullptr, config); + + if (!is_object_settings) + { + const int obj_idx = objects_model->GetObjectIdByItem(item); + assert(obj_idx >= 0); + DynamicPrintConfig* obj_config = &wxGetApp().model().objects[obj_idx]->config; + + main_config.apply(*obj_config, true); + printer_technology == ptFFF ? config_manipulation.update_print_fff_config(&main_config) : + config_manipulation.update_print_sla_config(&main_config) ; + } + + main_config.apply(*config, true); + printer_technology == ptFFF ? config_manipulation.update_print_fff_config(&main_config) : + config_manipulation.update_print_sla_config(&main_config) ; + + printer_technology == ptFFF ? config_manipulation.toggle_print_fff_options(&main_config) : + config_manipulation.toggle_print_sla_options(&main_config) ; +} + void ObjectSettings::UpdateAndShow(const bool show) { OG_Settings::UpdateAndShow(show ? update_settings_list() : false); diff --git a/src/slic3r/GUI/GUI_ObjectSettings.hpp b/src/slic3r/GUI/GUI_ObjectSettings.hpp index 2a0c19c5c..61d90600b 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.hpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.hpp @@ -5,6 +5,7 @@ #include #include #include "wxExtensions.hpp" +#include "libslic3r/PrintConfig.hpp" class wxBoxSizer; @@ -28,6 +29,7 @@ public: virtual wxSizer* get_sizer(); ConfigOptionsGroup* get_og() { return m_og.get(); } + wxWindow* parent() const {return m_parent; } }; @@ -46,6 +48,7 @@ public: ~ObjectSettings() {} bool update_settings_list(); + void update_config_values(DynamicPrintConfig*config); void UpdateAndShow(const bool show) override; void msw_rescale(); }; diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 36354ab24..64218d08f 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -176,6 +176,7 @@ Preview::Preview( , m_checkbox_retractions(nullptr) , m_checkbox_unretractions(nullptr) , m_checkbox_shells(nullptr) + , m_checkbox_legend(nullptr) , m_config(config) , m_process(process) , m_gcode_preview_data(gcode_preview_data) @@ -252,6 +253,9 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view m_checkbox_unretractions = new wxCheckBox(this, wxID_ANY, _(L("Unretractions"))); m_checkbox_shells = new wxCheckBox(this, wxID_ANY, _(L("Shells"))); + m_checkbox_legend = new wxCheckBox(this, wxID_ANY, _(L("Legend"))); + m_checkbox_legend->SetValue(true); + wxBoxSizer* top_sizer = new wxBoxSizer(wxHORIZONTAL); top_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0); top_sizer->Add(m_double_slider_sizer, 0, wxEXPAND, 0); @@ -270,6 +274,8 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view bottom_sizer->Add(m_checkbox_unretractions, 0, wxEXPAND | wxALL, 5); bottom_sizer->AddSpacer(10); bottom_sizer->Add(m_checkbox_shells, 0, wxEXPAND | wxALL, 5); + bottom_sizer->AddSpacer(20); + bottom_sizer->Add(m_checkbox_legend, 0, wxEXPAND | wxALL, 5); wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->Add(top_sizer, 1, wxALL | wxEXPAND, 0); @@ -442,6 +448,7 @@ void Preview::bind_event_handlers() m_checkbox_retractions->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_retractions, this); m_checkbox_unretractions->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_unretractions, this); m_checkbox_shells->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_shells, this); + m_checkbox_legend->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_legend, this); } void Preview::unbind_event_handlers() @@ -453,6 +460,7 @@ void Preview::unbind_event_handlers() m_checkbox_retractions->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_retractions, this); m_checkbox_unretractions->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_unretractions, this); m_checkbox_shells->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_shells, this); + m_checkbox_legend->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_legend, this); } void Preview::show_hide_ui_elements(const std::string& what) @@ -464,6 +472,7 @@ void Preview::show_hide_ui_elements(const std::string& what) m_checkbox_retractions->Enable(enable); m_checkbox_unretractions->Enable(enable); m_checkbox_shells->Enable(enable); + m_checkbox_legend->Enable(enable); enable = (what != "none"); m_label_view_type->Enable(enable); @@ -476,6 +485,7 @@ void Preview::show_hide_ui_elements(const std::string& what) m_checkbox_retractions->Show(visible); m_checkbox_unretractions->Show(visible); m_checkbox_shells->Show(visible); + m_checkbox_legend->Show(visible); m_label_view_type->Show(visible); m_choice_view_type->Show(visible); } @@ -542,6 +552,12 @@ void Preview::on_checkbox_shells(wxCommandEvent& evt) refresh_print(); } +void Preview::on_checkbox_legend(wxCommandEvent& evt) +{ + m_canvas->enable_legend_texture(m_checkbox_legend->IsChecked()); + m_canvas_widget->Refresh(); +} + void Preview::update_view_type() { const DynamicPrintConfig& config = wxGetApp().preset_bundle->project_config; @@ -702,6 +718,11 @@ void Preview::update_double_slider_from_canvas(wxKeyEvent& event) m_slider->SetHigherValue(new_pos); if (event.ShiftDown() || m_slider->is_one_layer()) m_slider->SetLowerValue(m_slider->GetHigherValue()); } + else if (key == 'L') { + m_checkbox_legend->SetValue(!m_checkbox_legend->GetValue()); + auto evt = wxCommandEvent(); + on_checkbox_legend(evt); + } else if (key == 'S') m_slider->ChangeOneLayerLock(); else diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index e86d0e430..401b17a4b 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -80,6 +80,7 @@ class Preview : public wxPanel wxCheckBox* m_checkbox_retractions; wxCheckBox* m_checkbox_unretractions; wxCheckBox* m_checkbox_shells; + wxCheckBox* m_checkbox_legend; DynamicPrintConfig* m_config; BackgroundSlicingProcess* m_process; @@ -129,6 +130,8 @@ public: void update_view_type(); + bool is_loaded() const { return m_loaded; } + private: bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model); @@ -147,6 +150,7 @@ private: void on_checkbox_retractions(wxCommandEvent& evt); void on_checkbox_unretractions(wxCommandEvent& evt); void on_checkbox_shells(wxCommandEvent& evt); + void on_checkbox_legend(wxCommandEvent& evt); // Create/Update/Reset double slider on 3dPreview void create_double_slider(); diff --git a/src/slic3r/GUI/GUI_Utils.cpp b/src/slic3r/GUI/GUI_Utils.cpp index 74e70c554..d5753f2cc 100644 --- a/src/slic3r/GUI/GUI_Utils.cpp +++ b/src/slic3r/GUI/GUI_Utils.cpp @@ -62,7 +62,7 @@ template typename F::FN winapi_get_function(const wchar_t *dll, const c static HINSTANCE dll_handle = LoadLibraryExW(dll, nullptr, 0); if (dll_handle == nullptr) { return nullptr; } - return (F::FN)GetProcAddress(dll_handle, fn_name); + return (typename F::FN)GetProcAddress(dll_handle, fn_name); } #endif diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index a17bbf6d3..c47714e46 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -64,6 +64,12 @@ public: m_prev_scale_factor = m_scale_factor; m_normal_font = get_default_font_for_dpi(dpi); + /* Because of default window font is a primary display font, + * We should set correct font for window before getting em_unit value. + */ +#ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList + this->SetFont(m_normal_font); +#endif // initialize default width_unit according to the width of the one symbol ("m") of the currently active font of this window. m_em_unit = std::max(10, this->GetTextExtent("m").x - 1); @@ -72,6 +78,8 @@ public: this->Bind(EVT_DPI_CHANGED, [this](const DpiChangedEvent &evt) { m_scale_factor = (float)evt.dpi / (float)DPI_DEFAULT; + m_new_font_point_size = get_default_font_for_dpi(evt.dpi).GetPointSize(); + if (!m_can_rescale) return; @@ -124,6 +132,8 @@ private: float m_prev_scale_factor; bool m_can_rescale{ true }; + int m_new_font_point_size; + // void recalc_font() // { // wxClientDC dc(this); @@ -135,14 +145,22 @@ private: // check if new scale is differ from previous bool is_new_scale_factor() const { return fabs(m_scale_factor - m_prev_scale_factor) > 0.001; } + // function for a font scaling of the window + void scale_win_font(wxWindow *window, const int font_point_size) + { + wxFont new_font(window->GetFont()); + new_font.SetPointSize(font_point_size); + window->SetFont(new_font); + } + // recursive function for scaling fonts for all controls in Window - void scale_controls_fonts(wxWindow *window, const float scale_f) + void scale_controls_fonts(wxWindow *window, const int font_point_size) { auto children = window->GetChildren(); for (auto child : children) { - scale_controls_fonts(child, scale_f); - child->SetFont(child->GetFont().Scaled(scale_f)); + scale_controls_fonts(child, font_point_size); + scale_win_font(child, font_point_size); } window->Layout(); @@ -151,18 +169,18 @@ private: void rescale(const wxRect &suggested_rect) { this->Freeze(); - const float relative_scale_factor = m_scale_factor / m_prev_scale_factor; // rescale fonts of all controls - scale_controls_fonts(this, relative_scale_factor); - this->SetFont(this->GetFont().Scaled(relative_scale_factor)); + scale_controls_fonts(this, m_new_font_point_size); + // rescale current window font + scale_win_font(this, m_new_font_point_size); - // rescale normal_font value - m_normal_font = m_normal_font.Scaled(relative_scale_factor); + // set normal application font as a current window font + m_normal_font = this->GetFont(); - // An analog of em_unit value from GUI_App. - m_em_unit = std::max(10, 10 * m_scale_factor); + // update em_unit value for new window font + m_em_unit = std::max(10, this->GetTextExtent("m").x - 1); // rescale missed controls sizes and images on_dpi_changed(suggested_rect); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index a65074646..cb18bdb16 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -29,19 +29,21 @@ GLGizmoBase::Grabber::Grabber() color[0] = 1.0f; color[1] = 1.0f; color[2] = 1.0f; + color[3] = 1.0f; } void GLGizmoBase::Grabber::render(bool hover, float size) const { - float render_color[3]; + float render_color[4]; if (hover) { render_color[0] = 1.0f - color[0]; render_color[1] = 1.0f - color[1]; render_color[2] = 1.0f - color[2]; + render_color[3] = color[3]; } else - ::memcpy((void*)render_color, (const void*)color, 3 * sizeof(float)); + ::memcpy((void*)render_color, (const void*)color, 4 * sizeof(float)); render(size, render_color, true); } @@ -63,7 +65,7 @@ void GLGizmoBase::Grabber::render(float size, const float* render_color, bool us if (use_lighting) glsafe(::glEnable(GL_LIGHTING)); - glsafe(::glColor3fv(render_color)); + glsafe(::glColor4fv(render_color)); glsafe(::glPushMatrix()); glsafe(::glTranslated(center(0), center(1), center(2))); @@ -143,10 +145,11 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, u , m_hover_id(-1) , m_dragging(false) , m_imgui(wxGetApp().imgui()) + , m_first_input_window_render(true) { - ::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 3 * sizeof(float)); - ::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 3 * sizeof(float)); - ::memcpy((void*)m_highlight_color, (const void*)DEFAULT_HIGHLIGHT_COLOR, 3 * sizeof(float)); + ::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 4 * sizeof(float)); + ::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 4 * sizeof(float)); + ::memcpy((void*)m_highlight_color, (const void*)DEFAULT_HIGHLIGHT_COLOR, 4 * sizeof(float)); } void GLGizmoBase::set_hover_id(int id) @@ -161,7 +164,7 @@ void GLGizmoBase::set_hover_id(int id) void GLGizmoBase::set_highlight_color(const float* color) { if (color != nullptr) - ::memcpy((void*)m_highlight_color, (const void*)color, 3 * sizeof(float)); + ::memcpy((void*)m_highlight_color, (const void*)color, 4 * sizeof(float)); } void GLGizmoBase::enable_grabber(unsigned int id) @@ -210,7 +213,7 @@ void GLGizmoBase::update(const UpdateData& data) on_update(data); } -std::array GLGizmoBase::picking_color_component(unsigned int id) const +std::array GLGizmoBase::picking_color_component(unsigned int id) const { static const float INV_255 = 1.0f / 255.0f; @@ -220,9 +223,12 @@ std::array GLGizmoBase::picking_color_component(unsigned int id) const id -= m_group_id; // color components are encoded to match the calculation of volume_id made into GLCanvas3D::_picking_pass() - return std::array { (float)((id >> 0) & 0xff) * INV_255, // red - (float)((id >> 8) & 0xff) * INV_255, // green - (float)((id >> 16) & 0xff) * INV_255 }; // blue + return std::array { + float((id >> 0) & 0xff) * INV_255, // red + float((id >> 8) & 0xff) * INV_255, // green + float((id >> 16) & 0xff) * INV_255, // blue + float(picking_checksum_alpha_channel(id & 0xff, (id >> 8) & 0xff, (id >> 16) & 0xff))* INV_255 // checksum for validating against unwanted alpha blending and multi sampling + }; } void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const @@ -247,10 +253,11 @@ void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const { if (m_grabbers[i].enabled) { - std::array color = picking_color_component(i); + std::array color = picking_color_component(i); m_grabbers[i].color[0] = color[0]; m_grabbers[i].color[1] = color[1]; m_grabbers[i].color[2] = color[2]; + m_grabbers[i].color[3] = color[3]; m_grabbers[i].render_for_picking(mean_size); } } @@ -267,5 +274,32 @@ std::string GLGizmoBase::format(float value, unsigned int decimals) const return Slic3r::string_printf("%.*f", decimals, value); } +void GLGizmoBase::render_input_window(float x, float y, float bottom_limit) +{ + on_render_input_window(x, y, bottom_limit); + if (m_first_input_window_render) + { + // for some reason, the imgui dialogs are not shown on screen in the 1st frame where they are rendered, but show up only with the 2nd rendered frame + // so, we forces another frame rendering the first time the imgui window is shown + m_parent.set_as_dirty(); + m_first_input_window_render = false; + } +} + +// Produce an alpha channel checksum for the red green blue components. The alpha channel may then be used to verify, whether the rgb components +// were not interpolated by alpha blending or multi sampling. +unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue) +{ + // 8 bit hash for the color + unsigned char b = ((((37 * red) + green) & 0x0ff) * 37 + blue) & 0x0ff; + // Increase enthropy by a bit reversal + b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + // Flip every second bit to increase the enthropy even more. + b ^= 0x55; + return b; +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index b84442b94..18053dcd6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -21,11 +21,11 @@ class ModelObject; namespace GUI { -static const float DEFAULT_BASE_COLOR[3] = { 0.625f, 0.625f, 0.625f }; -static const float DEFAULT_DRAG_COLOR[3] = { 1.0f, 1.0f, 1.0f }; -static const float DEFAULT_HIGHLIGHT_COLOR[3] = { 1.0f, 0.38f, 0.0f }; -static const float AXES_COLOR[3][3] = { { 0.75f, 0.0f, 0.0f }, { 0.0f, 0.75f, 0.0f }, { 0.0f, 0.0f, 0.75f } }; -static const float CONSTRAINED_COLOR[3] = { 0.5f, 0.5f, 0.5f }; +static const float DEFAULT_BASE_COLOR[4] = { 0.625f, 0.625f, 0.625f, 1.0f }; +static const float DEFAULT_DRAG_COLOR[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; +static const float DEFAULT_HIGHLIGHT_COLOR[4] = { 1.0f, 0.38f, 0.0f, 1.0f }; +static const float AXES_COLOR[][4] = { { 0.75f, 0.0f, 0.0f, 1.0f }, { 0.0f, 0.75f, 0.0f, 1.0f }, { 0.0f, 0.0f, 0.75f, 1.0f } }; +static const float CONSTRAINED_COLOR[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; @@ -48,7 +48,7 @@ protected: Vec3d center; Vec3d angles; - float color[3]; + float color[4]; bool enabled; bool dragging; @@ -94,11 +94,12 @@ protected: unsigned int m_sprite_id; int m_hover_id; bool m_dragging; - float m_base_color[3]; - float m_drag_color[3]; - float m_highlight_color[3]; + float m_base_color[4]; + float m_drag_color[4]; + float m_highlight_color[4]; mutable std::vector m_grabbers; ImGuiWrapper* m_imgui; + bool m_first_input_window_render; public: GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); @@ -144,7 +145,7 @@ public: void render() const { on_render(); } void render_for_picking() const { on_render_for_picking(); } - void render_input_window(float x, float y, float bottom_limit) { on_render_input_window(x, y, bottom_limit); } + void render_input_window(float x, float y, float bottom_limit); protected: virtual bool on_init() = 0; @@ -166,7 +167,7 @@ protected: // Returns the picking color for the given id, based on the BASE_ID constant // No check is made for clashing with other picking color (i.e. GLVolumes) - std::array picking_color_component(unsigned int id) const; + std::array picking_color_component(unsigned int id) const; void render_grabbers(const BoundingBoxf3& box) const; void render_grabbers(float size) const; void render_grabbers_for_picking(const BoundingBoxf3& box) const; @@ -175,6 +176,10 @@ protected: std::string format(float value, unsigned int decimals) const; }; +// Produce an alpha channel checksum for the red green blue components. The alpha channel may then be used to verify, whether the rgb components +// were not interpolated by alpha blending or multi sampling. +extern unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue); + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 39399fc0d..76a9ed603 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -17,7 +17,7 @@ namespace GUI { const double GLGizmoCut::Offset = 10.0; const double GLGizmoCut::Margin = 20.0; -const std::array GLGizmoCut::GrabberColor = { 1.0, 0.5, 0.0 }; +const std::array GLGizmoCut::GrabberColor = { 1.0, 0.5, 0.0, 1.0 }; GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) @@ -141,6 +141,7 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit) m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); m_imgui->set_next_window_bg_alpha(0.5f); + m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); ImGui::PushItemWidth(m_imgui->scaled(5.0f)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 5bfeda526..6e5738a42 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -11,7 +11,7 @@ class GLGizmoCut : public GLGizmoBase { static const double Offset; static const double Margin; - static const std::array GrabberColor; + static const std::array GrabberColor; mutable double m_cut_z; double m_start_z; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index 5a42cbd31..9fae8893a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -115,7 +115,7 @@ void GLGizmoFlatten::on_render_for_picking() const const_cast(this)->update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { - glsafe(::glColor3fv(picking_color_component(i).data())); + glsafe(::glColor4fv(picking_color_component(i).data())); ::glBegin(GL_POLYGON); for (const Vec3d& vertex : m_planes[i].vertices) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 11bdcd4f8..862ffe41a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -104,15 +104,15 @@ void GLGizmoMove3D::on_render() const // x axis m_grabbers[0].center = Vec3d(box.max(0) + Offset, center(1), center(2)); - ::memcpy((void*)m_grabbers[0].color, (const void*)&AXES_COLOR[0], 3 * sizeof(float)); + ::memcpy((void*)m_grabbers[0].color, (const void*)&AXES_COLOR[0], 4 * sizeof(float)); // y axis m_grabbers[1].center = Vec3d(center(0), box.max(1) + Offset, center(2)); - ::memcpy((void*)m_grabbers[1].color, (const void*)&AXES_COLOR[1], 3 * sizeof(float)); + ::memcpy((void*)m_grabbers[1].color, (const void*)&AXES_COLOR[1], 4 * sizeof(float)); // z axis m_grabbers[2].center = Vec3d(center(0), center(1), box.max(2) + Offset); - ::memcpy((void*)m_grabbers[2].color, (const void*)&AXES_COLOR[2], 3 * sizeof(float)); + ::memcpy((void*)m_grabbers[2].color, (const void*)&AXES_COLOR[2], 4 * sizeof(float)); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); @@ -123,7 +123,7 @@ void GLGizmoMove3D::on_render() const { if (m_grabbers[i].enabled) { - glsafe(::glColor3fv(AXES_COLOR[i])); + glsafe(::glColor4fv(AXES_COLOR[i])); ::glBegin(GL_LINES); ::glVertex3dv(center.data()); ::glVertex3dv(m_grabbers[i].center.data()); @@ -142,7 +142,7 @@ void GLGizmoMove3D::on_render() const else { // draw axis - glsafe(::glColor3fv(AXES_COLOR[m_hover_id])); + glsafe(::glColor4fv(AXES_COLOR[m_hover_id])); ::glBegin(GL_LINES); ::glVertex3dv(center.data()); ::glVertex3dv(m_grabbers[m_hover_id].center.data()); @@ -220,19 +220,20 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); double size = m_dragging ? (double)m_grabbers[axis].get_dragging_half_size(mean_size) : (double)m_grabbers[axis].get_half_size(mean_size); - float color[3]; - ::memcpy((void*)color, (const void*)m_grabbers[axis].color, 3 * sizeof(float)); + float color[4]; + ::memcpy((void*)color, (const void*)m_grabbers[axis].color, 4 * sizeof(float)); if (!picking && (m_hover_id != -1)) { color[0] = 1.0f - color[0]; color[1] = 1.0f - color[1]; color[2] = 1.0f - color[2]; + color[3] = color[3]; } if (!picking) glsafe(::glEnable(GL_LIGHTING)); - glsafe(::glColor3fv(color)); + glsafe(::glColor4fv(color)); glsafe(::glPushMatrix()); glsafe(::glTranslated(m_grabbers[axis].center(0), m_grabbers[axis].center(1), m_grabbers[axis].center(2))); if (axis == X) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index f481bb5d7..9a2c72633 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -155,7 +155,7 @@ void GLGizmoRotate::on_render() const transform_to_local(selection); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); - glsafe(::glColor3fv((m_hover_id != -1) ? m_drag_color : m_highlight_color)); + glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color : m_highlight_color)); render_circle(); @@ -166,7 +166,7 @@ void GLGizmoRotate::on_render() const render_reference_radius(); } - glsafe(::glColor3fv(m_highlight_color)); + glsafe(::glColor4fv(m_highlight_color)); if (m_hover_id != -1) render_angle(); @@ -287,14 +287,14 @@ void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0); m_grabbers[0].angles(2) = m_angle; - glsafe(::glColor3fv((m_hover_id != -1) ? m_drag_color : m_highlight_color)); + glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color : m_highlight_color)); ::glBegin(GL_LINES); ::glVertex3f(0.0f, 0.0f, 0.0f); ::glVertex3dv(m_grabbers[0].center.data()); glsafe(::glEnd()); - ::memcpy((void*)m_grabbers[0].color, (const void*)m_highlight_color, 3 * sizeof(float)); + ::memcpy((void*)m_grabbers[0].color, (const void*)m_highlight_color, 4 * sizeof(float)); render_grabbers(box); } @@ -306,8 +306,8 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size); - float color[3]; - ::memcpy((void*)color, (const void*)m_grabbers[0].color, 3 * sizeof(float)); + float color[4]; + ::memcpy((void*)color, (const void*)m_grabbers[0].color, 4 * sizeof(float)); if (!picking && (m_hover_id != -1)) { color[0] = 1.0f - color[0]; @@ -318,7 +318,7 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick if (!picking) glsafe(::glEnable(GL_LIGHTING)); - glsafe(::glColor3fv(color)); + glsafe(::glColor4fv(color)); glsafe(::glPushMatrix()); glsafe(::glTranslated(m_grabbers[0].center(0), m_grabbers[0].center(1), m_grabbers[0].center(2))); glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 7dc38b801..bf540cb00 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -172,20 +172,20 @@ void GLGizmoScale3D::on_render() const // x axis m_grabbers[0].center = m_transform * Vec3d(m_box.min(0), center(1), center(2)) - offset_x; m_grabbers[1].center = m_transform * Vec3d(m_box.max(0), center(1), center(2)) + offset_x; - ::memcpy((void*)m_grabbers[0].color, (ctrl_down && (m_hover_id == 1)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 3 * sizeof(float)); - ::memcpy((void*)m_grabbers[1].color, (ctrl_down && (m_hover_id == 0)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 3 * sizeof(float)); + ::memcpy((void*)m_grabbers[0].color, (ctrl_down && (m_hover_id == 1)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 4 * sizeof(float)); + ::memcpy((void*)m_grabbers[1].color, (ctrl_down && (m_hover_id == 0)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 4 * sizeof(float)); // y axis m_grabbers[2].center = m_transform * Vec3d(center(0), m_box.min(1), center(2)) - offset_y; m_grabbers[3].center = m_transform * Vec3d(center(0), m_box.max(1), center(2)) + offset_y; - ::memcpy((void*)m_grabbers[2].color, (ctrl_down && (m_hover_id == 3)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 3 * sizeof(float)); - ::memcpy((void*)m_grabbers[3].color, (ctrl_down && (m_hover_id == 2)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 3 * sizeof(float)); + ::memcpy((void*)m_grabbers[2].color, (ctrl_down && (m_hover_id == 3)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 4 * sizeof(float)); + ::memcpy((void*)m_grabbers[3].color, (ctrl_down && (m_hover_id == 2)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 4 * sizeof(float)); // z axis m_grabbers[4].center = m_transform * Vec3d(center(0), center(1), m_box.min(2)) - offset_z; m_grabbers[5].center = m_transform * Vec3d(center(0), center(1), m_box.max(2)) + offset_z; - ::memcpy((void*)m_grabbers[4].color, (ctrl_down && (m_hover_id == 5)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 3 * sizeof(float)); - ::memcpy((void*)m_grabbers[5].color, (ctrl_down && (m_hover_id == 4)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 3 * sizeof(float)); + ::memcpy((void*)m_grabbers[4].color, (ctrl_down && (m_hover_id == 5)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 4 * sizeof(float)); + ::memcpy((void*)m_grabbers[5].color, (ctrl_down && (m_hover_id == 4)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 4 * sizeof(float)); // uniform m_grabbers[6].center = m_transform * Vec3d(m_box.min(0), m_box.min(1), center(2)) - offset_x - offset_y; @@ -194,7 +194,7 @@ void GLGizmoScale3D::on_render() const m_grabbers[9].center = m_transform * Vec3d(m_box.min(0), m_box.max(1), center(2)) - offset_x + offset_y; for (int i = 6; i < 10; ++i) { - ::memcpy((void*)m_grabbers[i].color, (const void*)m_highlight_color, 3 * sizeof(float)); + ::memcpy((void*)m_grabbers[i].color, (const void*)m_highlight_color, 4 * sizeof(float)); } // sets grabbers orientation @@ -214,20 +214,20 @@ void GLGizmoScale3D::on_render() const // draw connections if (m_grabbers[0].enabled && m_grabbers[1].enabled) { - glsafe(::glColor3fv(m_grabbers[0].color)); + glsafe(::glColor4fv(m_grabbers[0].color)); render_grabbers_connection(0, 1); } if (m_grabbers[2].enabled && m_grabbers[3].enabled) { - glsafe(::glColor3fv(m_grabbers[2].color)); + glsafe(::glColor4fv(m_grabbers[2].color)); render_grabbers_connection(2, 3); } if (m_grabbers[4].enabled && m_grabbers[5].enabled) { - glsafe(::glColor3fv(m_grabbers[4].color)); + glsafe(::glColor4fv(m_grabbers[4].color)); render_grabbers_connection(4, 5); } - glsafe(::glColor3fv(m_base_color)); + glsafe(::glColor4fv(m_base_color)); render_grabbers_connection(6, 7); render_grabbers_connection(7, 8); render_grabbers_connection(8, 9); @@ -238,7 +238,7 @@ void GLGizmoScale3D::on_render() const else if ((m_hover_id == 0) || (m_hover_id == 1)) { // draw connection - glsafe(::glColor3fv(m_grabbers[0].color)); + glsafe(::glColor4fv(m_grabbers[0].color)); render_grabbers_connection(0, 1); // draw grabbers m_grabbers[0].render(true, grabber_mean_size); @@ -247,7 +247,7 @@ void GLGizmoScale3D::on_render() const else if ((m_hover_id == 2) || (m_hover_id == 3)) { // draw connection - glsafe(::glColor3fv(m_grabbers[2].color)); + glsafe(::glColor4fv(m_grabbers[2].color)); render_grabbers_connection(2, 3); // draw grabbers m_grabbers[2].render(true, grabber_mean_size); @@ -256,7 +256,7 @@ void GLGizmoScale3D::on_render() const else if ((m_hover_id == 4) || (m_hover_id == 5)) { // draw connection - glsafe(::glColor3fv(m_grabbers[4].color)); + glsafe(::glColor4fv(m_grabbers[4].color)); render_grabbers_connection(4, 5); // draw grabbers m_grabbers[4].render(true, grabber_mean_size); @@ -265,7 +265,7 @@ void GLGizmoScale3D::on_render() const else if (m_hover_id >= 6) { // draw connection - glsafe(::glColor3fv(m_drag_color)); + glsafe(::glColor4fv(m_drag_color)); render_grabbers_connection(6, 7); render_grabbers_connection(7, 8); render_grabbers_connection(8, 9); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index e73baaed7..fe4881466 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -284,7 +284,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) glsafe(::glTranslated(0.0, 0.0, m_z_shift)); glsafe(::glMultMatrixd(instance_matrix.data())); - float render_color[3]; + float render_color[4]; size_t cache_size = m_editing_mode ? m_editing_cache.size() : m_normal_cache.size(); for (size_t i = 0; i < cache_size; ++i) { @@ -296,12 +296,14 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) // First decide about the color of the point. if (picking) { - std::array color = picking_color_component(i); + std::array color = picking_color_component(i); render_color[0] = color[0]; render_color[1] = color[1]; render_color[2] = color[2]; + render_color[3] = color[3]; } else { + render_color[3] = 1.f; if ((m_hover_id == i && m_editing_mode)) { // ignore hover state unless editing mode is active render_color[0] = 0.f; render_color[1] = 1.0f; @@ -318,7 +320,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) for (unsigned char i=0; i<3; ++i) render_color[i] = 0.5f; } } - glsafe(::glColor3fv(render_color)); + glsafe(::glColor4fv(render_color)); float render_color_emissive[4] = { 0.5f * render_color[0], 0.5f * render_color[1], 0.5f * render_color[2], 1.f}; glsafe(::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive)); @@ -420,9 +422,9 @@ void GLGizmoSlaSupports::update_mesh() -// Unprojects the mouse position on the mesh and return the hit point and normal of the facet. -// The function throws if no intersection if found. -std::pair GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos) +// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal +// Return false if no intersection was found, true otherwise. +bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal) { // if the gizmo doesn't have the V, F structures for igl, calculate them first: if (m_its == nullptr) @@ -455,7 +457,7 @@ std::pair GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3), MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3), point1.cast(), (point2-point1).cast(), hits)) - throw std::invalid_argument("unproject_on_mesh(): No intersection found."); + return false; // no intersection found std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; }); @@ -479,14 +481,12 @@ std::pair GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse if (i==hits.size() || (hits.size()-i) % 2 != 0) { // All hits are either clipped, or there is an odd number of unclipped // hits - meaning the nearest must be from inside the mesh. - throw std::invalid_argument("unproject_on_mesh(): No intersection found."); + return false; } // Calculate and return both the point and the facet normal. - return std::make_pair( - result, - a.cross(b) - ); + pos_and_normal = std::make_pair(result, a.cross(b)); + return true; } // Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event. @@ -524,16 +524,15 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // If there is some selection, don't add new point and deselect everything instead. if (m_selection_empty) { - try { - std::pair pos_and_normal = unproject_on_mesh(mouse_position); // don't create anything if this throws - wxGetApp().plater()->take_snapshot(_(L("Add support point"))); + std::pair pos_and_normal; + if (unproject_on_mesh(mouse_position, pos_and_normal)) { // we got an intersection + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Add support point"))); m_editing_cache.emplace_back(sla::SupportPoint(pos_and_normal.first, m_new_point_head_diameter/2.f, false), false, pos_and_normal.second); m_parent.set_as_dirty(); m_wait_for_up_event = true; } - catch (...) { // not clicked on object + else return false; - } } else select_point(NoPoints); @@ -715,14 +714,12 @@ void GLGizmoSlaSupports::delete_selected_points(bool force) std::abort(); } - wxGetApp().plater()->take_snapshot(_(L("Delete support point"))); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Delete support point"))); for (unsigned int idx=0; idxreslice_SLA_supports(*m_model_object); } select_point(NoPoints); @@ -737,10 +734,8 @@ void GLGizmoSlaSupports::on_update(const UpdateData& data) else { if (m_hover_id != -1 && (! m_editing_cache[m_hover_id].support_point.is_new_island || !m_lock_unique_islands)) { std::pair pos_and_normal; - try { - pos_and_normal = unproject_on_mesh(data.mouse_pos.cast()); - } - catch (...) { return; } + if (! unproject_on_mesh(data.mouse_pos.cast(), pos_and_normal)) + return; m_editing_cache[m_hover_id].support_point.pos = pos_and_normal.first; m_editing_cache[m_hover_id].support_point.is_new_island = false; m_editing_cache[m_hover_id].normal = pos_and_normal.second; @@ -920,7 +915,7 @@ RENDER_AGAIN: cache_entry.support_point.head_front_radius = m_old_point_head_diameter / 2.f; float backup = m_new_point_head_diameter; m_new_point_head_diameter = m_old_point_head_diameter; - wxGetApp().plater()->take_snapshot(_(L("Change point head diameter"))); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Change point head diameter"))); m_new_point_head_diameter = backup; for (auto& cache_entry : m_editing_cache) if (cache_entry.selected) @@ -986,7 +981,7 @@ RENDER_AGAIN: if (slider_released) { m_model_object->config.opt("support_points_minimal_distance", true)->value = m_minimal_point_distance_stash; m_model_object->config.opt("support_points_density_relative", true)->value = (int)m_density_stash; - wxGetApp().plater()->take_snapshot(_(L("Support parameter change"))); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Support parameter change"))); m_model_object->config.opt("support_points_minimal_distance", true)->value = minimal_point_distance; m_model_object->config.opt("support_points_density_relative", true)->value = (int)density; wxGetApp().obj_list()->update_and_show_object_settings_item(); @@ -1101,6 +1096,9 @@ std::string GLGizmoSlaSupports::on_get_name() const void GLGizmoSlaSupports::on_set_state() { + if (m_state == Hover) + return; + // m_model_object pointer can be invalid (for instance because of undo/redo action), // we should recover it from the object id m_model_object = nullptr; @@ -1112,6 +1110,7 @@ void GLGizmoSlaSupports::on_set_state() } if (m_state == On && m_old_state != On) { // the gizmo was just turned on + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); if (is_mesh_update_necessary()) update_mesh(); @@ -1128,21 +1127,26 @@ void GLGizmoSlaSupports::on_set_state() m_new_point_head_diameter = static_cast(cfg.option("support_head_front_diameter"))->value; } if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off - wxGetApp().CallAfter([this]() { - // Following is called through CallAfter, because otherwise there was a problem - // on OSX with the wxMessageDialog being shown several times when clicked into. - if (m_model_object) { - if (m_editing_mode && unsaved_changes()) { - wxMessageDialog dlg(GUI::wxGetApp().mainframe, _(L("Do you want to save your manually edited support points?")) + "\n", - _(L("Save changes?")), wxICON_QUESTION | wxYES | wxNO); + bool will_ask = m_model_object && m_editing_mode && unsaved_changes(); + if (will_ask) { + wxGetApp().CallAfter([this]() { + // Following is called through CallAfter, because otherwise there was a problem + // on OSX with the wxMessageDialog being shown several times when clicked into. + wxMessageDialog dlg(GUI::wxGetApp().mainframe, _(L("Do you want to save your manually " + "edited support points?")) + "\n",_(L("Save changes?")), wxICON_QUESTION | wxYES | wxNO); if (dlg.ShowModal() == wxID_YES) editing_mode_apply_changes(); else editing_mode_discard_changes(); - } - } - m_parent.toggle_model_objects_visibility(true); + }); + // refuse to be turned off so the gizmo is active when the CallAfter is executed + m_state = m_old_state; + } + else { + // we are actually shutting down disable_editing_mode(); // so it is not active next time the gizmo opens + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off"))); + m_parent.toggle_model_objects_visibility(true); m_normal_cache.clear(); m_clipping_plane_distance = 0.f; // Release triangle mesh slicer and the AABB spatial search structure. @@ -1150,7 +1154,7 @@ void GLGizmoSlaSupports::on_set_state() m_its = nullptr; m_tms.reset(); m_supports_tms.reset(); - }); + } } m_old_state = m_state; } @@ -1178,7 +1182,7 @@ void GLGizmoSlaSupports::on_stop_dragging() && backup.support_point.pos != m_point_before_drag.support_point.pos) // and it was moved, not just selected { m_editing_cache[m_hover_id] = m_point_before_drag; - wxGetApp().plater()->take_snapshot(_(L("Move support point"))); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Move support point"))); m_editing_cache[m_hover_id] = backup; } } @@ -1277,7 +1281,7 @@ void GLGizmoSlaSupports::editing_mode_apply_changes() disable_editing_mode(); // this leaves the editing mode undo/redo stack and must be done before the snapshot is taken if (unsaved_changes()) { - wxGetApp().plater()->take_snapshot(_(L("Support points edit"))); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Support points edit"))); m_normal_cache.clear(); for (const CacheEntry& ce : m_editing_cache) @@ -1287,7 +1291,7 @@ void GLGizmoSlaSupports::editing_mode_apply_changes() m_model_object->sla_support_points.clear(); m_model_object->sla_support_points = m_normal_cache; - wxGetApp().CallAfter([this]() { wxGetApp().plater()->reslice_SLA_supports(*m_model_object); }); + reslice_SLA_supports(); } } @@ -1304,11 +1308,29 @@ void GLGizmoSlaSupports::reload_cache() } +bool GLGizmoSlaSupports::has_backend_supports() const +{ + // find SlaPrintObject with this ID + for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { + if (po->model_object()->id() == m_model_object->id()) + return po->is_step_done(slaposSupportPoints); + } + return false; +} + +void GLGizmoSlaSupports::reslice_SLA_supports(bool postpone_error_messages) const +{ + wxGetApp().CallAfter([this, postpone_error_messages]() { wxGetApp().plater()->reslice_SLA_supports(*m_model_object, postpone_error_messages); }); +} void GLGizmoSlaSupports::get_data_from_backend() { + if (! has_backend_supports()) + return; + + // find the respective SLAPrintObject, we need a pointer to it for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { - if (po->model_object()->id() == m_model_object->id() && po->is_step_done(slaposSupportPoints)) { + if (po->model_object()->id() == m_model_object->id()) { m_normal_cache.clear(); const std::vector& points = po->get_support_points(); auto mat = po->trafo().inverse().cast(); @@ -1333,8 +1355,8 @@ void GLGizmoSlaSupports::auto_generate() )), _(L("Warning")), wxICON_WARNING | wxYES | wxNO); if (m_model_object->sla_points_status != sla::PointsStatus::UserModified || m_normal_cache.empty() || dlg.ShowModal() == wxID_YES) { - wxGetApp().plater()->take_snapshot(_(L("Autogenerate support points"))); - wxGetApp().CallAfter([this]() { wxGetApp().plater()->reslice_SLA_supports(*m_model_object); }); + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Autogenerate support points"))); + wxGetApp().CallAfter([this]() { reslice_SLA_supports(); }); m_model_object->sla_points_status = sla::PointsStatus::Generating; } } @@ -1446,4 +1468,4 @@ SlaGizmoHelpDialog::SlaGizmoHelpDialog() } // namespace GUI -} // namespace Slic3r \ No newline at end of file +} // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index fb312e664..feb2455cb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -32,7 +32,7 @@ private: int m_active_instance = -1; float m_active_instance_bb_radius; // to cache the bb mutable float m_z_shift = 0.f; - std::pair unproject_on_mesh(const Vec2d& mouse_pos); + bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); const float RenderPointScale = 1.f; @@ -86,6 +86,8 @@ public: bool is_in_editing_mode() const { return m_editing_mode; } bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); } + bool has_backend_supports() const; + void reslice_SLA_supports(bool postpone_error_messages = false) const; private: bool on_init(); @@ -101,6 +103,8 @@ private: void update_cache_entry_normal(unsigned int i) const; bool unsaved_changes() const; + EState m_no_hover_state = Off; + EState m_no_hover_old_state = Off; bool m_lock_unique_islands = false; bool m_editing_mode = false; // Is editing mode active? bool m_old_editing_state = false; // To keep track of whether the user toggled between the modes (needed for imgui refreshes). diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 38af63464..1528a4bcb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -5,6 +5,7 @@ #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_ObjectManipulation.hpp" #include "slic3r/GUI/PresetBundle.hpp" +#include "slic3r/Utils/UndoRedo.hpp" #include #include @@ -280,8 +281,8 @@ bool GLGizmosManager::handle_shortcut(int key) if (m_parent.get_selection().is_empty()) return false; - EType old_current = m_current; bool handled = false; + for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) { if ((it->second == nullptr) || !it->second->is_selectable()) @@ -294,25 +295,34 @@ bool GLGizmosManager::handle_shortcut(int key) if ((it->second->get_state() == GLGizmoBase::On)) { it->second->set_state(GLGizmoBase::Off); - m_current = Undefined; + if (it->second->get_state() == GLGizmoBase::Off) { + m_current = Undefined; + } handled = true; } else if ((it->second->get_state() == GLGizmoBase::Off)) { - it->second->set_state(GLGizmoBase::On); - m_current = it->first; + // Before turning anything on, turn everything else off to see if + // nobody refuses. Only then activate the gizmo. + bool can_open = true; + for (GizmosMap::iterator i = m_gizmos.begin(); i != m_gizmos.end(); ++i) { + if (i->first != it->first) { + if (m_current == i->first && i->second->get_state() != GLGizmoBase::Off ) { + i->second->set_state(GLGizmoBase::Off); + if (i->second->get_state() != GLGizmoBase::Off) + can_open = false; + } + } + } + if (can_open) { + it->second->set_state(GLGizmoBase::On); + m_current = it->first; + } handled = true; } } } - if (handled && (old_current != Undefined) && (old_current != m_current)) - { - GizmosMap::const_iterator it = m_gizmos.find(old_current); - if (it != m_gizmos.end()) - it->second->set_state(GLGizmoBase::Off); - } - return handled; } @@ -455,6 +465,11 @@ ClippingPlane GLGizmosManager::get_sla_clipping_plane() const return ClippingPlane::ClipsNothing(); } +bool GLGizmosManager::wants_reslice_supports_on_undo() const +{ + return (m_current == SlaSupports + && dynamic_cast(m_gizmos.at(SlaSupports))->has_backend_supports()); +} void GLGizmosManager::render_current_gizmo() const { @@ -861,10 +876,13 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) return processed; } -void GLGizmosManager::update_after_undo_redo() +void GLGizmosManager::update_after_undo_redo(const UndoRedo::Snapshot& snapshot) { update_data(); m_serializing = false; + if (m_current == SlaSupports + && snapshot.snapshot_data.flags & UndoRedo::SnapshotData::RECALCULATE_SLA_SUPPORTS) + dynamic_cast(m_gizmos[SlaSupports])->reslice_SLA_supports(true); } void GLGizmosManager::reset() @@ -1065,34 +1083,65 @@ void GLGizmosManager::update_on_off_state(const Vec2d& mouse_pos) float scaled_stride_y = scaled_icons_size + scaled_gap_y; float top_y = 0.5f * (cnv_h - height) + scaled_border; - for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) + auto inside = [scaled_border, scaled_icons_size, &mouse_pos](float top_y) { + return (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size); + }; + + bool could_activate = true; + for (std::pair &type_and_gizmo : m_gizmos) { - if ((it->second == nullptr) || !it->second->is_selectable()) + GLGizmoBase *gizmo = type_and_gizmo.second; + if ((gizmo == nullptr) || !gizmo->is_selectable()) continue; - bool inside = (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size); - if (it->second->is_activable() && inside) - { - if ((it->second->get_state() == GLGizmoBase::On)) - { - it->second->set_state(GLGizmoBase::Hover); - m_current = Undefined; - } - else if ((it->second->get_state() == GLGizmoBase::Hover)) - { - it->second->set_state(GLGizmoBase::On); - m_current = it->first; + if (! (gizmo->is_activable() && inside(top_y))) { + gizmo->set_state(GLGizmoBase::Off); + if (gizmo->get_state() != GLGizmoBase::Off) { + // Gizmo refused to leave it's active state. Don't try to select + could_activate = false; } } - else - it->second->set_state(GLGizmoBase::Off); top_y += scaled_stride_y; } - GizmosMap::iterator it = m_gizmos.find(m_current); - if ((it != m_gizmos.end()) && (it->second != nullptr) && (it->second->get_state() != GLGizmoBase::On)) - it->second->set_state(GLGizmoBase::On); + // We may change m_current soon. If we did it during following loop, gizmos that take undo/redo snapshots + // in their on_set_state function could snapshot a state with the new gizmo already active. + // Therefore, just remember what needs to be done and actually change m_current afterwards. + EType new_current = m_current; + top_y = 0.5f * (cnv_h - height) + scaled_border; + for (std::pair &type_and_gizmo : m_gizmos) + { + GLGizmoBase *gizmo = type_and_gizmo.second; + if ((gizmo == nullptr) || !gizmo->is_selectable()) + continue; + + if (gizmo->is_activable() && inside(top_y)) + { + if ((gizmo->get_state() == GLGizmoBase::On)) + { + gizmo->set_state(GLGizmoBase::Off); + if (gizmo->get_state() == GLGizmoBase::Off) { + gizmo->set_state(GLGizmoBase::Hover); + new_current = Undefined; + } + } + else if ((gizmo->get_state() == GLGizmoBase::Hover) && could_activate) + { + gizmo->set_state(GLGizmoBase::On); + new_current = type_and_gizmo.first; + } + } + + top_y += scaled_stride_y; + } + m_current = new_current; + + if (could_activate) { + GizmosMap::iterator it = m_gizmos.find(m_current); + if ((it != m_gizmos.end()) && (it->second != nullptr) && (it->second->get_state() != GLGizmoBase::On)) + it->second->set_state(GLGizmoBase::On); + } } std::string GLGizmosManager::update_hover_state(const Vec2d& mouse_pos) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index b1c000ceb..c0adeb957 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -9,6 +9,11 @@ #include namespace Slic3r { + +namespace UndoRedo { +struct Snapshot; +} + namespace GUI { class GLCanvas3D; @@ -173,6 +178,7 @@ public: void set_sla_support_data(ModelObject* model_object); bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false, bool alt_down = false, bool control_down = false); ClippingPlane get_sla_clipping_plane() const; + bool wants_reslice_supports_on_undo() const; void render_current_gizmo() const; void render_current_gizmo_for_picking_pass() const; @@ -186,7 +192,7 @@ public: bool on_char(wxKeyEvent& evt); bool on_key(wxKeyEvent& evt); - void update_after_undo_redo(); + void update_after_undo_redo(const UndoRedo::Snapshot& snapshot); private: void reset(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index f58266a5d..8e4d9eebf 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -354,7 +354,7 @@ bool ImGuiWrapper::undo_redo_list(const ImVec2& size, const bool is_undo, bool ( ImGui::Selectable(item_text, i < hovered); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip(item_text); + ImGui::SetTooltip("%s", item_text); hovered = i; is_hovered = true; } diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 89a9d3a61..9f5fae246 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -3,26 +3,27 @@ #include "libslic3r/Utils.hpp" #include "GUI.hpp" #include +#include #include "GUI_App.hpp" #include "wxExtensions.hpp" -namespace Slic3r { +namespace Slic3r { namespace GUI { KBShortcutsDialog::KBShortcutsDialog() - : DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("Keyboard Shortcuts")), + : DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("Keyboard Shortcuts")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); - auto main_sizer = new wxBoxSizer(wxVERTICAL); + auto main_sizer = new wxBoxSizer(wxVERTICAL); // logo m_logo_bmp = ScalableBitmap(this, "Slic3r_32px.png", 32); // fonts const wxFont& font = wxGetApp().normal_font(); - const wxFont& bold_font = wxGetApp().bold_font(); + const wxFont& bold_font = wxGetApp().bold_font(); SetFont(font); wxFont head_font = bold_font; @@ -34,7 +35,9 @@ KBShortcutsDialog::KBShortcutsDialog() fill_shortcuts(); - auto panel = new wxPanel(this); + panel = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, get_size()); + panel->SetScrollbars(1, 20, 1, 2); + auto main_grid_sizer = new wxFlexGridSizer(2, 10, 10); panel->SetSizer(main_grid_sizer); main_sizer->Add(panel, 1, wxEXPAND | wxALL, 0); @@ -78,17 +81,17 @@ KBShortcutsDialog::KBShortcutsDialog() grid_sizer->Add(description, -1, wxALIGN_CENTRE_VERTICAL); } } - + wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK); this->SetEscapeId(wxID_OK); this->Bind(wxEVT_BUTTON, &KBShortcutsDialog::onCloseDialog, this, wxID_OK); main_sizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 15); - + this->Bind(wxEVT_LEFT_DOWN, &KBShortcutsDialog::onCloseDialog, this); - SetSizer(main_sizer); - main_sizer->SetSizeHints(this); + SetSizer(main_sizer); + main_sizer->SetSizeHints(this); } void KBShortcutsDialog::fill_shortcuts() @@ -132,6 +135,7 @@ void KBShortcutsDialog::fill_shortcuts() plater_shortcuts.reserve(20); plater_shortcuts.push_back(Shortcut("A", L("Arrange"))); + plater_shortcuts.push_back(Shortcut("Shift+A", L("Arrange selection"))); plater_shortcuts.push_back(Shortcut(ctrl+"A", L("Select All objects"))); plater_shortcuts.push_back(Shortcut("Del", L("Delete selected"))); plater_shortcuts.push_back(Shortcut(ctrl+"Del", L("Delete All"))); @@ -163,10 +167,10 @@ void KBShortcutsDialog::fill_shortcuts() // Shortcuts gizmo_shortcuts; // gizmo_shortcuts.reserve(2); -// +// // gizmo_shortcuts.push_back(Shortcut("Shift+", L("Press to snap by 5% in Gizmo Scale\n or by 1mm in Gizmo Move"))); // gizmo_shortcuts.push_back(Shortcut(alt, L("Press to scale or rotate selected objects around their own center"))); -// +// // m_full_shortcuts.push_back(std::make_pair(_(L("Gizmo Shortcuts")), std::make_pair(gizmo_shortcuts, 1))); @@ -177,6 +181,7 @@ void KBShortcutsDialog::fill_shortcuts() preview_shortcuts.push_back(Shortcut(L("Arrow Down"), L("Lower Layer"))); preview_shortcuts.push_back(Shortcut("U", L("Upper Layer"))); preview_shortcuts.push_back(Shortcut("D", L("Lower Layer"))); + preview_shortcuts.push_back(Shortcut("L", L("Show/Hide (L)egend"))); m_full_shortcuts.push_back(std::make_pair(_(L("Preview Shortcuts")), std::make_pair(preview_shortcuts, szLeft))); @@ -205,7 +210,9 @@ void KBShortcutsDialog::on_dpi_changed(const wxRect &suggested_rect) msw_buttons_rescale(this, em, { wxID_OK }); - const wxSize& size = wxSize(85 * em, 75 * em); + wxSize size = get_size(); + + panel->SetMinSize(size); SetMinSize(size); Fit(); @@ -218,5 +225,30 @@ void KBShortcutsDialog::onCloseDialog(wxEvent &) this->EndModal(wxID_CLOSE); } +wxSize KBShortcutsDialog::get_size() +{ + wxTopLevelWindow* window = Slic3r::GUI::find_toplevel_parent(this); + const int display_idx = wxDisplay::GetFromWindow(window); + wxRect display; + if (display_idx == wxNOT_FOUND) { + display = wxDisplay(0u).GetClientArea(); + window->Move(display.GetTopLeft()); + } + else { + display = wxDisplay(display_idx).GetClientArea(); + } + + const int em = em_unit(); + wxSize dialog_size = wxSize(90 * em, 85 * em); + + const int margin = 10 * em; + if (dialog_size.x > display.GetWidth()) + dialog_size.x = display.GetWidth() - margin; + if (dialog_size.y > display.GetHeight()) + dialog_size.y = display.GetHeight() - margin; + + return dialog_size; +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/KBShortcutsDialog.hpp b/src/slic3r/GUI/KBShortcutsDialog.hpp index 66fe7c399..7ac28778b 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.hpp +++ b/src/slic3r/GUI/KBShortcutsDialog.hpp @@ -23,10 +23,10 @@ class KBShortcutsDialog : public DPIDialog typedef std::vector< Shortcut > Shortcuts; typedef std::vector< std::pair> > ShortcutsVec; - wxString text_info {wxEmptyString}; + wxScrolledWindow* panel; - ShortcutsVec m_full_shortcuts; - ScalableBitmap m_logo_bmp; + ShortcutsVec m_full_shortcuts; + ScalableBitmap m_logo_bmp; std::vector m_head_bitmaps; public: @@ -39,6 +39,7 @@ protected: private: void onCloseDialog(wxEvent &); + wxSize get_size(); }; } // namespace GUI diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 2d5c93878..38aaf5cf8 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -39,10 +39,12 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S { // Fonts were created by the DPIFrame constructor for the monitor, on which the window opened. wxGetApp().update_fonts(this); +/* #ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList this->SetFont(this->normal_font()); #endif - + // Font is already set in DPIFrame constructor +*/ // Load the icon either from the exe, or from the ico file. #if _WIN32 { @@ -245,6 +247,11 @@ bool MainFrame::can_export_model() const return (m_plater != nullptr) && !m_plater->model().objects.empty(); } +bool MainFrame::can_export_toolpaths() const +{ + return (m_plater != nullptr) && (m_plater->printer_technology() == ptFFF) && m_plater->is_preview_shown() && m_plater->is_preview_loaded() && m_plater->has_toolpaths_to_export(); +} + bool MainFrame::can_export_supports() const { if ((m_plater == nullptr) || (m_plater->printer_technology() != ptSLA) || m_plater->model().objects.empty()) @@ -279,6 +286,18 @@ bool MainFrame::can_export_gcode() const return true; } +bool MainFrame::can_send_gcode() const +{ + if (m_plater == nullptr) + return false; + + if (m_plater->model().objects.empty()) + return false; + + const auto print_host_opt = wxGetApp().preset_bundle->printers.get_edited_preset().config.option("print_host"); + return print_host_opt != nullptr && !print_host_opt->value.empty(); +} + bool MainFrame::can_slice() const { bool bg_proc = wxGetApp().app_config->get("background_processing") == "1"; @@ -411,6 +430,7 @@ void MainFrame::init_menubar() }, wxID_FILE1, wxID_FILE9); std::vector recent_projects = wxGetApp().app_config->get_recent_projects(); + std::reverse(recent_projects.begin(), recent_projects.end()); for (const std::string& project : recent_projects) { m_recent_projects.AddFileToHistory(from_u8(project)); @@ -450,17 +470,25 @@ void MainFrame::init_menubar() [this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(); }, menu_icon("export_gcode"), nullptr, [this](){return can_export_gcode(); }, this); m_changeable_menu_items.push_back(item_export_gcode); + wxMenuItem* item_send_gcode = append_menu_item(export_menu, wxID_ANY, _(L("S&end G-code")) + dots +"\tCtrl+Shift+G", _(L("Send to print current plate as G-code")), + [this](wxCommandEvent&) { if (m_plater) m_plater->send_gcode(); }, menu_icon("export_gcode"), nullptr, + [this](){return can_send_gcode(); }, this); + m_changeable_menu_items.push_back(item_send_gcode); export_menu->AppendSeparator(); append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &STL")) + dots, _(L("Export current plate as STL")), [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, menu_icon("export_plater"), nullptr, [this](){return can_export_model(); }, this); - append_menu_item(export_menu, wxID_ANY, _(L("Export plate as STL including supports")) + dots, _(L("Export current plate as STL including supports")), + append_menu_item(export_menu, wxID_ANY, _(L("Export plate as STL &including supports")) + dots, _(L("Export current plate as STL including supports")), [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(true); }, menu_icon("export_plater"), nullptr, [this](){return can_export_supports(); }, this); append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &AMF")) + dots, _(L("Export current plate as AMF")), [this](wxCommandEvent&) { if (m_plater) m_plater->export_amf(); }, menu_icon("export_plater"), nullptr, [this](){return can_export_model(); }, this); export_menu->AppendSeparator(); + append_menu_item(export_menu, wxID_ANY, _(L("Export &toolpaths as OBJ")) + dots, _(L("Export toolpaths as OBJ")), + [this](wxCommandEvent&) { if (m_plater) m_plater->export_toolpaths_to_obj(); }, menu_icon("export_plater"), nullptr, + [this]() {return can_export_toolpaths(); }, this); + export_menu->AppendSeparator(); append_menu_item(export_menu, wxID_ANY, _(L("Export &Config")) +dots +"\tCtrl+E", _(L("Export current configuration to file")), [this](wxCommandEvent&) { export_config(); }, menu_icon("export_config")); append_menu_item(export_menu, wxID_ANY, _(L("Export Config &Bundle")) + dots, _(L("Export all presets to file")), @@ -692,7 +720,8 @@ void MainFrame::update_menubar() { const bool is_fff = plater()->printer_technology() == ptFFF; - m_changeable_menu_items[miExport] ->SetItemLabel((is_fff ? _(L("Export &G-code")) : _(L("Export")) ) + dots + "\tCtrl+G"); + m_changeable_menu_items[miExport] ->SetItemLabel((is_fff ? _(L("Export &G-code")) : _(L("E&xport")) ) + dots + "\tCtrl+G"); + m_changeable_menu_items[miSend] ->SetItemLabel((is_fff ? _(L("S&end G-code")) : _(L("S&end to print"))) + dots + "\tCtrl+Shift+G"); m_changeable_menu_items[miMaterialTab] ->SetItemLabel((is_fff ? _(L("&Filament Settings Tab")) : _(L("Mate&rial Settings Tab"))) + "\tCtrl+3"); m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(this, menu_icon(is_fff ? "spool": "resin"))); @@ -715,29 +744,26 @@ void MainFrame::quick_slice(const int qs) // select input file if (!(qs & qsReslice)) { - auto dlg = new wxFileDialog(this, _(L("Choose a file to slice (STL/OBJ/AMF/3MF/PRUSA):")), + wxFileDialog dlg(this, _(L("Choose a file to slice (STL/OBJ/AMF/3MF/PRUSA):")), wxGetApp().app_config->get_last_dir(), "", file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_FILE_MUST_EXIST); - if (dlg->ShowModal() != wxID_OK) { - dlg->Destroy(); + if (dlg.ShowModal() != wxID_OK) return; - } - input_file = dlg->GetPath(); - dlg->Destroy(); + input_file = dlg.GetPath(); if (!(qs & qsExportSVG)) m_qs_last_input_file = input_file; } else { if (m_qs_last_input_file.IsEmpty()) { - auto dlg = new wxMessageDialog(this, _(L("No previously sliced file.")), + wxMessageDialog dlg(this, _(L("No previously sliced file.")), _(L("Error")), wxICON_ERROR | wxOK); - dlg->ShowModal(); + dlg.ShowModal(); return; } if (std::ifstream(m_qs_last_input_file.ToUTF8().data())) { - auto dlg = new wxMessageDialog(this, _(L("Previously sliced file ("))+m_qs_last_input_file+_(L(") not found.")), + wxMessageDialog dlg(this, _(L("Previously sliced file ("))+m_qs_last_input_file+_(L(") not found.")), _(L("File Not Found")), wxICON_ERROR | wxOK); - dlg->ShowModal(); + dlg.ShowModal(); return; } input_file = m_qs_last_input_file; @@ -771,31 +797,25 @@ void MainFrame::quick_slice(const int qs) } else if (qs & qsSaveAs) { // The following line may die if the output_filename_format template substitution fails. - auto dlg = new wxFileDialog(this, wxString::Format(_(L("Save %s file as:")) , qs & qsExportSVG ? _(L("SVG")) : _(L("G-code")) ), + wxFileDialog dlg(this, wxString::Format(_(L("Save %s file as:")) , qs & qsExportSVG ? _(L("SVG")) : _(L("G-code")) ), wxGetApp().app_config->get_last_output_dir(get_dir_name(output_file)), get_base_name(input_file), qs & qsExportSVG ? file_wildcards(FT_SVG) : file_wildcards(FT_GCODE), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - if (dlg->ShowModal() != wxID_OK) { - dlg->Destroy(); + if (dlg.ShowModal() != wxID_OK) return; - } - output_file = dlg->GetPath(); - dlg->Destroy(); + output_file = dlg.GetPath(); if (!(qs & qsExportSVG)) m_qs_last_output_file = output_file; wxGetApp().app_config->update_last_output_dir(get_dir_name(output_file)); } else if (qs & qsExportPNG) { - auto dlg = new wxFileDialog(this, _(L("Save zip file as:")), + wxFileDialog dlg(this, _(L("Save zip file as:")), wxGetApp().app_config->get_last_output_dir(get_dir_name(output_file)), get_base_name(output_file), "*.sl1", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - if (dlg->ShowModal() != wxID_OK) { - dlg->Destroy(); + if (dlg.ShowModal() != wxID_OK) return; + output_file = dlg.GetPath(); } - output_file = dlg->GetPath(); - dlg->Destroy(); - } // show processbar dialog m_progress_dialog = new wxProgressDialog(_(L("Slicing")) + dots, @@ -840,29 +860,23 @@ void MainFrame::repair_stl() { wxString input_file; { - auto dlg = new wxFileDialog(this, _(L("Select the STL file to repair:")), + wxFileDialog dlg(this, _(L("Select the STL file to repair:")), wxGetApp().app_config->get_last_dir(), "", file_wildcards(FT_STL), wxFD_OPEN | wxFD_FILE_MUST_EXIST); - if (dlg->ShowModal() != wxID_OK) { - dlg->Destroy(); + if (dlg.ShowModal() != wxID_OK) return; + input_file = dlg.GetPath(); } - input_file = dlg->GetPath(); - dlg->Destroy(); - } wxString output_file = input_file; { - auto dlg = new wxFileDialog( this, L("Save OBJ file (less prone to coordinate errors than STL) as:"), + wxFileDialog dlg( this, L("Save OBJ file (less prone to coordinate errors than STL) as:"), get_dir_name(output_file), get_base_name(output_file, ".obj"), file_wildcards(FT_OBJ), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - if (dlg->ShowModal() != wxID_OK) { - dlg->Destroy(); + if (dlg.ShowModal() != wxID_OK) return; + output_file = dlg.GetPath(); } - output_file = dlg->GetPath(); - dlg->Destroy(); - } auto tmesh = new Slic3r::TriangleMesh(); tmesh->ReadSTLFile(input_file.ToUTF8().data()); @@ -882,14 +896,13 @@ void MainFrame::export_config() return; } // Ask user for the file name for the config file. - auto dlg = new wxFileDialog(this, _(L("Save configuration as:")), + wxFileDialog dlg(this, _(L("Save configuration as:")), !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : wxGetApp().app_config->get_last_dir(), !m_last_config.IsEmpty() ? get_base_name(m_last_config) : "config.ini", file_wildcards(FT_INI), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); wxString file; - if (dlg->ShowModal() == wxID_OK) - file = dlg->GetPath(); - dlg->Destroy(); + if (dlg.ShowModal() == wxID_OK) + file = dlg.GetPath(); if (!file.IsEmpty()) { wxGetApp().app_config->update_config_dir(get_dir_name(file)); m_last_config = file; @@ -902,13 +915,12 @@ void MainFrame::load_config_file() { if (!wxGetApp().check_unsaved_changes()) return; - auto dlg = new wxFileDialog(this, _(L("Select configuration to load:")), + wxFileDialog dlg(this, _(L("Select configuration to load:")), !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : wxGetApp().app_config->get_last_dir(), "config.ini", "INI files (*.ini, *.gcode)|*.ini;*.INI;*.gcode;*.g", wxFD_OPEN | wxFD_FILE_MUST_EXIST); wxString file; - if (dlg->ShowModal() == wxID_OK) - file = dlg->GetPath(); - dlg->Destroy(); + if (dlg.ShowModal() == wxID_OK) + file = dlg.GetPath(); if (! file.IsEmpty() && this->load_config_file(file.ToUTF8().data())) { wxGetApp().app_config->update_config_dir(get_dir_name(file)); m_last_config = file; @@ -939,14 +951,13 @@ void MainFrame::export_configbundle() return; } // Ask user for a file name. - auto dlg = new wxFileDialog(this, _(L("Save presets bundle as:")), + wxFileDialog dlg(this, _(L("Save presets bundle as:")), !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : wxGetApp().app_config->get_last_dir(), SLIC3R_APP_KEY "_config_bundle.ini", file_wildcards(FT_INI), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); wxString file; - if (dlg->ShowModal() == wxID_OK) - file = dlg->GetPath(); - dlg->Destroy(); + if (dlg.ShowModal() == wxID_OK) + file = dlg.GetPath(); if (!file.IsEmpty()) { // Export the config bundle. wxGetApp().app_config->update_config_dir(get_dir_name(file)); @@ -966,16 +977,13 @@ void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool re if (!wxGetApp().check_unsaved_changes()) return; if (file.IsEmpty()) { - auto dlg = new wxFileDialog(this, _(L("Select configuration to load:")), + wxFileDialog dlg(this, _(L("Select configuration to load:")), !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : wxGetApp().app_config->get_last_dir(), "config.ini", file_wildcards(FT_INI), wxFD_OPEN | wxFD_FILE_MUST_EXIST); - if (dlg->ShowModal() != wxID_OK) { - dlg->Destroy(); + if (dlg.ShowModal() != wxID_OK) return; + file = dlg.GetPath(); } - file = dlg->GetPath(); - dlg->Destroy(); - } wxGetApp().app_config->update_config_dir(get_dir_name(file)); diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index a41f33824..aa1e3d500 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -1,4 +1,4 @@ -#ifndef slic3r_MainFrame_hpp_ +#ifndef slic3r_MainFrame_hpp_ #define slic3r_MainFrame_hpp_ #include "libslic3r/PrintConfig.hpp" @@ -65,8 +65,10 @@ class MainFrame : public DPIFrame bool can_start_new_project() const; bool can_save() const; bool can_export_model() const; + bool can_export_toolpaths() const; bool can_export_supports() const; bool can_export_gcode() const; + bool can_send_gcode() const; bool can_slice() const; bool can_change_view() const; bool can_select() const; @@ -79,6 +81,7 @@ class MainFrame : public DPIFrame enum MenuItems { // FFF SLA miExport = 0, // Export G-code Export + miSend, // Send G-code Send to print miMaterialTab, // Filament Settings Material Settings }; diff --git a/src/slic3r/GUI/MsgDialog.hpp b/src/slic3r/GUI/MsgDialog.hpp index ad4bbcc97..5a4929849 100644 --- a/src/slic3r/GUI/MsgDialog.hpp +++ b/src/slic3r/GUI/MsgDialog.hpp @@ -8,8 +8,6 @@ #include #include -#include "slic3r/Utils/Semver.hpp" - class wxBoxSizer; class wxCheckBox; class wxStaticBitmap; diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 43586d821..9733e4eb0 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -1,4 +1,4 @@ -#include "OptionsGroup.hpp" +#include "OptionsGroup.hpp" #include "ConfigExceptions.hpp" #include diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index dbce7c049..a7b971c75 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -290,17 +290,17 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * auto colors = static_cast(cfg->option("extruder_colour")->clone()); wxColour clr(colors->values[extruder_idx]); if (!clr.IsOk()) - clr = wxTransparentColour; + clr = wxColour(0,0,0); // Don't set alfa to transparence auto data = new wxColourData(); data->SetChooseFull(1); data->SetColour(clr); - auto dialog = new wxColourDialog(this, data); - dialog->CenterOnParent(); - if (dialog->ShowModal() == wxID_OK) + wxColourDialog dialog(this, data); + dialog.CenterOnParent(); + if (dialog.ShowModal() == wxID_OK) { - colors->values[extruder_idx] = dialog->GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX); + colors->values[extruder_idx] = dialog.GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX); DynamicPrintConfig cfg_new = *cfg; cfg_new.set_key_value("extruder_colour", colors); @@ -309,7 +309,6 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * wxGetApp().preset_bundle->update_platter_filament_ui(extruder_idx, this); wxGetApp().plater()->on_config_change(cfg_new); } - dialog->Destroy(); }); } @@ -556,14 +555,21 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : Tab* tab = wxGetApp().get_tab(Preset::TYPE_SLA_PRINT); if (!tab) return; - if (opt_key == "pad_enable") { - tab->set_value(opt_key, value); - tab->update(); + DynamicPrintConfig new_conf = *config_sla; + if (opt_key == "pad") { + const wxString& selection = boost::any_cast(value); + + const bool pad_enable = selection == _("None") ? false : true; + new_conf.set_key_value("pad_enable", new ConfigOptionBool(pad_enable)); + + if (selection == _("Below object")) + new_conf.set_key_value("pad_zero_elevation", new ConfigOptionBool(false)); + else if (selection == _("Around object")) + new_conf.set_key_value("pad_zero_elevation", new ConfigOptionBool(true)); } else { assert(opt_key == "support"); - DynamicPrintConfig new_conf = *config_sla; const wxString& selection = boost::any_cast(value); const bool supports_enable = selection == _("None") ? false : true; @@ -573,10 +579,9 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : new_conf.set_key_value("support_buildplate_only", new ConfigOptionBool(false)); else if (selection == _("Support on build plate only")) new_conf.set_key_value("support_buildplate_only", new ConfigOptionBool(true)); - - tab->load_config(new_conf); } + tab->load_config(new_conf); tab->update_dirty(); }; @@ -594,9 +599,19 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : line = Line{ "", "" }; - option = m_og_sla->get_option("pad_enable"); - option.opt.sidetext = " "; + ConfigOptionDef pad_def; + pad_def.label = L("Pad"); + pad_def.type = coStrings; + pad_def.gui_type = "select_open"; + pad_def.tooltip = L("Select what kind of pad do you need"); + pad_def.enum_labels.push_back(L("None")); + pad_def.enum_labels.push_back(L("Below object")); + pad_def.enum_labels.push_back(L("Around object")); + pad_def.set_default_value(new ConfigOptionStrings{ "Below object" }); + option = Option(pad_def, "pad"); + option.opt.full_width = true; line.append_option(option); + line.append_widget(empty_widget); m_og_sla->append_line(line); @@ -709,8 +724,8 @@ void Sidebar::priv::show_preset_comboboxes() Sidebar::Sidebar(Plater *parent) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(40 * wxGetApp().em_unit(), -1)), p(new priv(parent)) { - p->scrolled = new wxScrolledWindow(this, wxID_ANY/*, wxDefaultPosition, wxSize(40 * wxGetApp().em_unit(), -1)*/); - p->scrolled->SetScrollbars(0, 20, 1, 2); + p->scrolled = new wxScrolledWindow(this); + p->scrolled->SetScrollbars(0, 100, 1, 2); // Sizer in the scrolled area @@ -1176,10 +1191,10 @@ void Sidebar::show_sliced_info_sizer(const bool show) if (ps.estimated_silent_print_time != "N/A") { new_label += wxString::Format("\n - %s", _(L("stealth mode"))); info_text += wxString::Format("\n%s", ps.estimated_silent_print_time); - for (int i = (int)ps.estimated_normal_color_print_times.size() - 1; i >= 0; --i) + for (int i = (int)ps.estimated_silent_color_print_times.size() - 1; i >= 0; --i) { new_label += wxString::Format("\n - %s%d", _(L("Color ")), i + 1); - info_text += wxString::Format("\n%s", ps.estimated_normal_color_print_times[i]); + info_text += wxString::Format("\n%s", ps.estimated_silent_color_print_times[i]); } } p->sliced_info->SetTextAndShow(siEstimatedTime, info_text, new_label); @@ -1443,7 +1458,7 @@ struct Plater::priv // Do a full refresh of scene tree, including regenerating // all the GLVolumes. FIXME The update function shall just // reload the modified matrices. - if (!was_canceled()) plater().update(true); + if (!was_canceled()) plater().update((unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH); } public: @@ -1662,7 +1677,7 @@ struct Plater::priv // Apply the arrange result to all selected objects for (ArrangePolygon &ap : m_selected) ap.apply(); - plater().update(false /*dont force_full_scene_refresh*/); + plater().update(); } }; @@ -1745,10 +1760,20 @@ struct Plater::priv priv(Plater *q, MainFrame *main_frame); ~priv(); - void update(bool force_full_scene_refresh = false, bool force_background_processing_update = false); + enum class UpdateParams { + FORCE_FULL_SCREEN_REFRESH = 1, + FORCE_BACKGROUND_PROCESSING_UPDATE = 2, + POSTPONE_VALIDATION_ERROR_MESSAGE = 4, + }; + void update(unsigned int flags = 0); void select_view(const std::string& direction); void select_view_3D(const std::string& name); void select_next_view_3D(); + + bool is_preview_shown() const { return current_panel == preview; } + bool is_preview_loaded() const { return preview->is_loaded(); } + bool is_view3D_shown() const { return current_panel == view3D; } + void reset_all_gizmos(); void update_ui_from_settings(); ProgressStatusBar* statusbar(); @@ -1818,11 +1843,18 @@ struct Plater::priv UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT = 16, }; // returns bit mask of UpdateBackgroundProcessReturnState - unsigned int update_background_process(bool force_validation = false); + unsigned int update_background_process(bool force_validation = false, bool postpone_error_messages = false); // Restart background processing thread based on a bitmask of UpdateBackgroundProcessReturnState. bool restart_background_process(unsigned int state); // returns bit mask of UpdateBackgroundProcessReturnState unsigned int update_restart_background_process(bool force_scene_update, bool force_preview_update); + void show_delayed_error_message() { + if (!this->delayed_error_message.empty()) { + std::string msg = std::move(this->delayed_error_message); + this->delayed_error_message.clear(); + GUI::show_error(this->q, msg); + } + } void export_gcode(fs::path output_path, PrintHostJob upload_job); void reload_from_disk(); void fix_through_netfabb(const int obj_idx, const int vol_idx = -1); @@ -1889,7 +1921,7 @@ private: void update_fff_scene(); void update_sla_scene(); void undo_redo_to(std::vector::const_iterator it_snapshot); - void update_after_undo_redo(bool temp_snapshot_was_taken = false); + void update_after_undo_redo(const UndoRedo::Snapshot& snapshot, bool temp_snapshot_was_taken = false); // path to project file stored with no extension wxString m_project_filename; @@ -2063,7 +2095,7 @@ Plater::priv::~priv() delete config; } -void Plater::priv::update(bool force_full_scene_refresh, bool force_background_processing_update) +void Plater::priv::update(unsigned int flags) { // the following line, when enabled, causes flickering on NVIDIA graphics cards // wxWindowUpdateLocker freeze_guard(q); @@ -2076,11 +2108,11 @@ void Plater::priv::update(bool force_full_scene_refresh, bool force_background_p } unsigned int update_status = 0; - if (this->printer_technology == ptSLA || force_background_processing_update) + if (this->printer_technology == ptSLA || (flags & (unsigned int)UpdateParams::FORCE_BACKGROUND_PROCESSING_UPDATE)) // Update the SLAPrint from the current Model, so that the reload_scene() // pulls the correct data. - update_status = this->update_background_process(false); - this->view3D->reload_scene(false, force_full_scene_refresh); + update_status = this->update_background_process(false, flags & (unsigned int)UpdateParams::POSTPONE_VALIDATION_ERROR_MESSAGE); + this->view3D->reload_scene(false, flags & (unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH); this->preview->reload_print(); if (this->printer_technology == ptSLA) this->restart_background_process(update_status); @@ -2196,7 +2228,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ DynamicPrintConfig config; { DynamicPrintConfig config_loaded; - model = Slic3r::Model::read_from_archive(path.string(), &config_loaded, false); + model = Slic3r::Model::read_from_archive(path.string(), &config_loaded, false, load_config); if (load_config && !config_loaded.empty()) { // Based on the printer technology field found in the loaded config, select the base for the config, PrinterTechnology printer_technology = Preset::printer_technology(config_loaded); @@ -2236,7 +2268,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ } } else { - model = Slic3r::Model::read_from_file(path.string(), nullptr, false); + model = Slic3r::Model::read_from_file(path.string(), nullptr, false, load_config); for (auto obj : model.objects) if (obj->name.empty()) obj->name = fs::path(obj->input_file).filename().string(); @@ -2303,7 +2335,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ } } - if (new_model != nullptr) { + if (new_model != nullptr && new_model->objects.size() > 1) { wxMessageDialog dlg(q, _(L( "Multiple objects were loaded for a multi-material printer.\n" "Instead of considering them as multiple objects, should I consider\n" @@ -2327,6 +2359,9 @@ std::vector Plater::priv::load_files(const std::vector& input_ // automatic selection of added objects if (!obj_idxs.empty() && (view3D != nullptr)) { + // update printable state for new volumes on canvas3D + wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_objects(obj_idxs); + Selection& selection = view3D->get_canvas3d()->get_selection(); selection.clear(); for (size_t idx : obj_idxs) @@ -2440,6 +2475,7 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type) case FT_AMF: case FT_3MF: case FT_GCODE: + case FT_OBJ: wildcard = file_wildcards(file_type); break; default: @@ -2490,18 +2526,23 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type) dlg_title = _(L("Save file as:")); break; } + case FT_OBJ: + { + output_file.replace_extension("obj"); + dlg_title = _(L("Export OBJ file:")); + break; + } default: break; } - wxFileDialog* dlg = new wxFileDialog(q, dlg_title, + wxFileDialog dlg(q, dlg_title, from_path(output_file.parent_path()), from_path(output_file.filename()), wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - if (dlg->ShowModal() != wxID_OK) { + if (dlg.ShowModal() != wxID_OK) return wxEmptyString; - } - wxString out_path = dlg->GetPath(); + wxString out_path = dlg.GetPath(); fs::path path(into_path(out_path)); wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); @@ -2628,7 +2669,6 @@ void Plater::priv::reset() void Plater::priv::mirror(Axis axis) { - this->take_snapshot(_(L("Mirror"))); view3D->mirror_selection(axis); } @@ -2844,7 +2884,7 @@ void Plater::priv::update_print_volume_state() // Update background processing thread from the current config and Model. // Returns a bitmask of UpdateBackgroundProcessReturnState. -unsigned int Plater::priv::update_background_process(bool force_validation) +unsigned int Plater::priv::update_background_process(bool force_validation, bool postpone_error_messages) { // bitmap of enum UpdateBackgroundProcessReturnState unsigned int return_state = 0; @@ -2854,8 +2894,6 @@ unsigned int Plater::priv::update_background_process(bool force_validation) this->background_process_timer.Stop(); // Update the "out of print bed" state of ModelInstances. this->update_print_volume_state(); - // The delayed error message is no more valid. - this->delayed_error_message.clear(); // Apply new config to the possibly running background task. bool was_running = this->background_process.running(); Print::ApplyStatus invalidated = this->background_process.apply(this->q->model(), wxGetApp().preset_bundle->full_config()); @@ -2881,6 +2919,8 @@ unsigned int Plater::priv::update_background_process(bool force_validation) } if ((invalidated != Print::APPLY_STATUS_UNCHANGED || force_validation) && ! this->background_process.empty()) { + // The delayed error message is no more valid. + this->delayed_error_message.clear(); // The state of the Print changed, and it is non-zero. Let's validate it and give the user feedback on errors. std::string err = this->background_process.validate(); if (err.empty()) { @@ -2893,7 +2933,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation) while (p->GetParent()) p = p->GetParent(); auto *top_level_wnd = dynamic_cast(p); - if (top_level_wnd && top_level_wnd->IsActive()) { + if (! postpone_error_messages && top_level_wnd && top_level_wnd->IsActive()) { // The error returned from the Print needs to be translated into the local language. GUI::show_error(this->q, _(err)); } else { @@ -2902,6 +2942,9 @@ unsigned int Plater::priv::update_background_process(bool force_validation) } return_state |= UPDATE_BACKGROUND_PROCESS_INVALID; } + } else if (! this->delayed_error_message.empty()) { + // Reusing the old state. + return_state |= UPDATE_BACKGROUND_PROCESS_INVALID; } if (invalidated != Print::APPLY_STATUS_UNCHANGED && was_running && ! this->background_process.running() && @@ -3491,6 +3534,9 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ sidebar->obj_list()->append_menu_item_instance_to_object(menu, q); menu->AppendSeparator(); + wxMenuItem* menu_item_printable = sidebar->obj_list()->append_menu_item_printable(menu, q); + menu->AppendSeparator(); + append_menu_item(menu, wxID_ANY, _(L("Reload from Disk")), _(L("Reload the selected file from Disk")), [this](wxCommandEvent&) { reload_from_disk(); }); @@ -3498,6 +3544,17 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ [this](wxCommandEvent&) { q->export_stl(false, true); }); menu->AppendSeparator(); + + q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { + const Selection& selection = get_selection(); + int instance_idx = selection.get_instance_idx(); + evt.Enable(instance_idx != -1); + if (instance_idx != -1) + { + evt.Check(model.objects[selection.get_object_idx()]->instances[instance_idx]->printable); + view3D->set_as_dirty(); + } + }, menu_item_printable->GetId()); } sidebar->obj_list()->append_menu_item_fix_through_netfabb(menu); @@ -3782,6 +3839,12 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name) } else if (this->sidebar->obj_list()->is_selected(itLayerRoot)) snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_LAYERROOT_ON_SIDEBAR; + + // If SLA gizmo is active, ask it if it wants to trigger support generation + // on loading this snapshot. + if (view3D->get_canvas3d()->get_gizmos_manager().wants_reslice_supports_on_undo()) + snapshot_data.flags |= UndoRedo::SnapshotData::RECALCULATE_SLA_SUPPORTS; + //FIXME updating the Wipe tower config values at the ModelWipeTower from the Print config. // This is a workaround until we refactor the Wipe Tower position / orientation to live solely inside the Model, not in the Print config. if (this->printer_technology == ptFFF) { @@ -3822,6 +3885,9 @@ void Plater::priv::undo_redo_to(size_t time_to_load) void Plater::priv::undo_redo_to(std::vector::const_iterator it_snapshot) { + // Make sure that no updating function calls take_snapshot until we are done. + SuppressSnapshots snapshot_supressor(q); + bool temp_snapshot_was_taken = this->undo_redo_stack().temp_snapshot_active(); PrinterTechnology new_printer_technology = it_snapshot->snapshot_data.printer_technology; bool printer_technology_changed = this->printer_technology != new_printer_technology; @@ -3864,9 +3930,14 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator bool new_selected_layer_on_sidebar = (new_flags & UndoRedo::SnapshotData::SELECTED_LAYER_ON_SIDEBAR) != 0; bool new_selected_layerroot_on_sidebar = (new_flags & UndoRedo::SnapshotData::SELECTED_LAYERROOT_ON_SIDEBAR) != 0; + if (this->view3D->get_canvas3d()->get_gizmos_manager().wants_reslice_supports_on_undo()) + top_snapshot_data.flags |= UndoRedo::SnapshotData::RECALCULATE_SLA_SUPPORTS; + // Disable layer editing before the Undo / Redo jump. if (!new_variable_layer_editing_active && view3D->is_layers_editing_enabled()) view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting")); + // Make a copy of the snapshot, undo/redo could invalidate the iterator + const UndoRedo::Snapshot snapshot_copy = *it_snapshot; // Do the jump in time. if (it_snapshot->timestamp < this->undo_redo_stack().active_snapshot_time() ? this->undo_redo_stack().undo(model, this->view3D->get_canvas3d()->get_selection(), this->view3D->get_canvas3d()->get_gizmos_manager(), top_snapshot_data, it_snapshot->timestamp) : @@ -3904,18 +3975,18 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator if (new_selected_settings_on_sidebar || new_selected_layer_on_sidebar) this->sidebar->obj_list()->set_selected_layers_range_idx(layer_range_idx); - this->update_after_undo_redo(temp_snapshot_was_taken); + this->update_after_undo_redo(snapshot_copy, temp_snapshot_was_taken); // Enable layer editing after the Undo / Redo jump. if (! view3D->is_layers_editing_enabled() && this->layers_height_allowed() && new_variable_layer_editing_active) view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting")); } } -void Plater::priv::update_after_undo_redo(bool /* temp_snapshot_was_taken */) +void Plater::priv::update_after_undo_redo(const UndoRedo::Snapshot& snapshot, bool /* temp_snapshot_was_taken */) { this->view3D->get_canvas3d()->get_selection().clear(); // Update volumes from the deserializd model, always stop / update the background processing (for both the SLA and FFF technologies). - this->update(false, true); + this->update((unsigned int)UpdateParams::FORCE_BACKGROUND_PROCESSING_UPDATE | (unsigned int)UpdateParams::POSTPONE_VALIDATION_ERROR_MESSAGE); // Release old snapshots if the memory allocated is excessive. This may remove the top most snapshot if jumping to the very first snapshot. //if (temp_snapshot_was_taken) // Release the old snapshots always, as it may have happened, that some of the triangle meshes got deserialized from the snapshot, while some @@ -3923,7 +3994,7 @@ void Plater::priv::update_after_undo_redo(bool /* temp_snapshot_was_taken */) this->undo_redo_stack().release_least_recently_used(); //YS_FIXME update obj_list from the deserialized model (maybe store ObjectIDs into the tree?) (no selections at this point of time) this->view3D->get_canvas3d()->get_selection().set_deserialized(GUI::Selection::EMode(this->undo_redo_stack().selection_deserialized().mode), this->undo_redo_stack().selection_deserialized().volumes_and_instances); - this->view3D->get_canvas3d()->get_gizmos_manager().update_after_undo_redo(); + this->view3D->get_canvas3d()->get_gizmos_manager().update_after_undo_redo(snapshot); wxGetApp().obj_list()->update_after_undo_redo(); @@ -3934,6 +4005,11 @@ void Plater::priv::update_after_undo_redo(bool /* temp_snapshot_was_taken */) view3D->set_as_dirty(); } + // this->update() above was called with POSTPONE_VALIDATION_ERROR_MESSAGE, so that if an error message was generated when updating the back end, it would not open immediately, + // but it would be saved to be show later. Let's do it now. We do not want to display the message box earlier, because on Windows & OSX the message box takes over the message + // queue pump, which in turn executes the rendering function before a full update after the Undo / Redo jump. + this->show_delayed_error_message(); + //FIXME what about the state of the manipulators? //FIXME what about the focus? Cursor in the side panel? @@ -4066,6 +4142,10 @@ void Plater::select_view(const std::string& direction) { p->select_view(directio void Plater::select_view_3D(const std::string& name) { p->select_view_3D(name); } +bool Plater::is_preview_shown() const { return p->is_preview_shown(); } +bool Plater::is_preview_loaded() const { return p->is_preview_loaded(); } +bool Plater::is_view3D_shown() const { return p->is_view3D_shown(); } + void Plater::select_all() { p->select_all(); } void Plater::deselect_all() { p->deselect_all(); } @@ -4389,6 +4469,24 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) } } +bool Plater::has_toolpaths_to_export() const +{ + return p->preview->get_canvas3d()->has_toolpaths_to_export(); +} + +void Plater::export_toolpaths_to_obj() const +{ + if ((printer_technology() != ptFFF) || !is_preview_loaded()) + return; + + wxString path = p->get_export_file(FT_OBJ); + if (path.empty()) + return; + + wxBusyCursor wait; + p->preview->get_canvas3d()->export_toolpaths_to_obj(into_u8(path).c_str()); +} + void Plater::reslice() { // Stop arrange and (or) optimize rotation tasks. @@ -4430,11 +4528,11 @@ void Plater::reslice() p->preview->update_view_type(); } -void Plater::reslice_SLA_supports(const ModelObject &object) +void Plater::reslice_SLA_supports(const ModelObject &object, bool postpone_error_messages) { //FIXME Don't reslice if export of G-code or sending to OctoPrint is running. // bitmask of UpdateBackgroundProcessReturnState - unsigned int state = this->p->update_background_process(true); + unsigned int state = this->p->update_background_process(true, postpone_error_messages); if (state & priv::UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) this->p->view3D->reload_scene(false); @@ -4537,7 +4635,7 @@ void Plater::undo_redo_topmost_string_getter(const bool is_undo, std::string& ou return; } - out_text = L(""); + out_text = ""; } void Plater::on_extruders_change(int num_extruders) @@ -4573,6 +4671,30 @@ void Plater::on_config_change(const DynamicPrintConfig &config) bool update_scheduled = false; bool bed_shape_changed = false; for (auto opt_key : p->config->diff(config)) { + if (opt_key == "filament_colour") + { + update_scheduled = true; // update should be scheduled (for update 3DScene) #2738 + + /* There is a case, when we use filament_color instead of extruder_color (when extruder_color == ""). + * Thus plater config option "filament_colour" should be filled with filament_presets values. + * Otherwise, on 3dScene will be used last edited filament color for all volumes with extruder_color == "". + */ + const std::vector filament_presets = wxGetApp().preset_bundle->filament_presets; + if (filament_presets.size() > 1 && + p->config->option(opt_key)->values.size() != config.option(opt_key)->values.size()) + { + const PresetCollection& filaments = wxGetApp().preset_bundle->filaments; + std::vector filament_colors; + filament_colors.reserve(filament_presets.size()); + + for (const std::string& filament_preset : filament_presets) + filament_colors.push_back(filaments.find_preset(filament_preset, true)->config.opt_string("filament_colour", (unsigned)0)); + + p->config->option(opt_key)->values = filament_colors; + continue; + } + } + p->config->set_key_value(opt_key, config.option(opt_key)->clone()); if (opt_key == "printer_technology") this->set_printer_technology(config.opt_enum(opt_key)); @@ -4634,12 +4756,8 @@ void Plater::on_activate() this->p->preview->get_wxglcanvas()->SetFocus(); #endif - if (! this->p->delayed_error_message.empty()) { - std::string msg = std::move(this->p->delayed_error_message); - this->p->delayed_error_message.clear(); - GUI::show_error(this, msg); + this->p->show_delayed_error_message(); } -} wxString Plater::get_project_filename(const wxString& extension) const { diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index d7f7f3791..c2d7545e9 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -156,6 +156,10 @@ public: void select_view(const std::string& direction); void select_view_3D(const std::string& name); + bool is_preview_shown() const; + bool is_preview_loaded() const; + bool is_view3D_shown() const; + // Called after the Preferences dialog is closed and the program settings are saved. // Update the UI based on the current preferences. void update_ui_from_settings(); @@ -179,8 +183,10 @@ public: void export_stl(bool extended = false, bool selection_only = false); void export_amf(); void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path()); + bool has_toolpaths_to_export() const; + void export_toolpaths_to_obj() const; void reslice(); - void reslice_SLA_supports(const ModelObject &object); + void reslice_SLA_supports(const ModelObject &object, bool postpone_error_messages = false); void changed_object(int obj_idx); void changed_objects(const std::vector& object_idxs); void schedule_background_process(bool schedule = true); diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index f4abeda03..216cda4ed 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -450,7 +450,7 @@ const std::vector& Preset::filament_options() , "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", "start_filament_gcode", "end_filament_gcode", // Retract overrides - "filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel", + "filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel", "filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe", // Profile compatibility "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits" @@ -536,9 +536,10 @@ const std::vector& Preset::sla_print_options() "pad_wall_thickness", "pad_wall_height", "pad_max_merge_distance", - "pad_edge_radius", + // "pad_edge_radius", "pad_wall_slope", "pad_object_gap", + "pad_zero_elevation", "pad_object_connector_stride", "pad_object_connector_width", "pad_object_connector_penetration", @@ -558,7 +559,8 @@ const std::vector& Preset::sla_material_options() if (s_opts.empty()) { s_opts = { "initial_layer_height", - "exposure_time", "initial_exposure_time", + "exposure_time", + "initial_exposure_time", "material_correction", "material_notes", "default_sla_material_profile", @@ -584,6 +586,8 @@ const std::vector& Preset::sla_printer_options() "relative_correction", "absolute_correction", "gamma_correction", + "min_exposure_time", "max_exposure_time", + "min_initial_exposure_time", "max_initial_exposure_time", "print_host", "printhost_apikey", "printhost_cafile", "printer_notes", "inherits" diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index b61bf100c..ebd707c3b 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -8,7 +8,7 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/PrintConfig.hpp" -#include "slic3r/Utils/Semver.hpp" +#include "libslic3r/Semver.hpp" class wxBitmap; class wxBitmapComboBox; diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 93ffdb73d..f637e141f 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -763,8 +763,11 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool } } // Load the configs into this->filaments and make them active. - this->filament_presets.clear(); - for (size_t i = 0; i < configs.size(); ++ i) { + this->filament_presets = std::vector(configs.size()); + // To avoid incorrect selection of the first filament preset (means a value of Preset->m_idx_selected) + // in a case when next added preset take a place of previosly selected preset, + // we should add presets from last to first + for (int i = (int)configs.size()-1; i >= 0; i--) { DynamicPrintConfig &cfg = configs[i]; // Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets. cfg.opt_string("compatible_printers_condition", true) = compatible_printers_condition_values[i + 1]; @@ -789,7 +792,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool new_name, std::move(cfg), i == 0); loaded->save(); } - this->filament_presets.emplace_back(loaded->name); + this->filament_presets[i] = loaded->name; } } // 4) Load the project config values (the per extruder wipe matrix etc). @@ -1484,11 +1487,16 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::Pr * and scale them in respect to em_unit value */ const float scale_f = ui->em_unit() * 0.1f; - const int icon_height = 16 * scale_f + 0.5f; - const int normal_icon_width = 16 * scale_f + 0.5f; + + // To avoid the errors of number rounding for different combination of monitor configuration, + // let use scaled 8px, as a smallest icon unit + const int icon_unit = 8 * scale_f + 0.5f; + const int icon_height = 2 * icon_unit; //16 * scale_f + 0.5f; + const int normal_icon_width = 2 * icon_unit; //16 * scale_f + 0.5f; + const int thin_icon_width = icon_unit; //8 * scale_f + 0.5f; + const int wide_icon_width = 3 * icon_unit; //24 * scale_f + 0.5f; + const int space_icon_width = 2 * scale_f + 0.5f; - const int wide_icon_width = 24 * scale_f + 0.5f; - const int thin_icon_width = 8 * scale_f + 0.5f; for (int i = this->filaments().front().is_visible ? 0 : 1; i < int(this->filaments().size()); ++i) { const Preset &preset = this->filaments.preset(i); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 211863627..937619a46 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -100,6 +100,7 @@ void Selection::set_volumes(GLVolumePtrs* volumes) update_valid(); } +// Init shall be called from the OpenGL render function, so that the OpenGL context is initialized! bool Selection::init() { if (!m_arrow.init()) @@ -402,8 +403,10 @@ void Selection::remove_all() if (is_empty()) return; - - if (!wxGetApp().plater()->can_redo()) + +// Not taking the snapshot with non-empty Redo stack will likely be more confusing than losing the Redo stack. +// Let's wait for user feedback. +// if (!wxGetApp().plater()->can_redo()) wxGetApp().plater()->take_snapshot(_(L("Selection-Remove All"))); m_mode = Instance; @@ -1459,6 +1462,39 @@ std::vector Selection::get_unselected_volume_idxs_from(const std:: return idxs; } +void Selection::toggle_instance_printable_state() +{ + int instance_idx = get_instance_idx(); + if (instance_idx == -1) + return; + + int obj_idx = get_object_idx(); + if ((0 <= obj_idx) && (obj_idx < (int)m_model->objects.size())) + { + ModelObject* model_object = m_model->objects[obj_idx]; + if ((0 <= instance_idx) && (instance_idx < (int)model_object->instances.size())) + { + ModelInstance* instance = model_object->instances[instance_idx]; + const bool printable = !instance->printable; + + wxString snapshot_text = model_object->instances.size() == 1 ? wxString::Format("%s %s", + printable ? _(L("Set Printable")) : _(L("Set Unprintable")), model_object->name) : + printable ? _(L("Set Printable Instance")) : _(L("Set Unprintable Instance")); + wxGetApp().plater()->take_snapshot(snapshot_text); + + instance->printable = printable; + + for (GLVolume* volume : *m_volumes) + { + if ((volume->object_idx() == obj_idx) && (volume->instance_idx() == instance_idx)) + volume->printable = instance->printable; + } + + wxGetApp().obj_list()->update_printable_state(obj_idx, instance_idx); + } + } +} + void Selection::update_valid() { m_valid = (m_volumes != nullptr) && (m_model != nullptr); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 0f71cefc4..c27b4cc29 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -336,6 +336,8 @@ public: // returns the list of idxs of the volumes contained in the given list but not in the selection std::vector get_unselected_volume_idxs_from(const std::vector& volume_idxs) const; + void toggle_instance_printable_state(); + private: void update_valid(); void update_type(); diff --git a/src/slic3r/GUI/SysInfoDialog.cpp b/src/slic3r/GUI/SysInfoDialog.cpp index 76fb56b7c..8190edb8b 100644 --- a/src/slic3r/GUI/SysInfoDialog.cpp +++ b/src/slic3r/GUI/SysInfoDialog.cpp @@ -58,21 +58,19 @@ std::string get_mem_info(bool format_as_html) std::string b_end = format_as_html ? "" : ""; std::string line_end = format_as_html ? "
" : "\n"; - const Slic3r::UndoRedo::Stack &stack = wxGetApp().plater()->undo_redo_stack_main(); - out << b_start << "RAM size reserved for the Undo / Redo stack [MB]: " << b_end << Slic3r::format_memsize_MB(stack.get_memory_limit()) << line_end; - out << b_start << "RAM size occupied by the Undo / Redo stack [MB]: " << b_end << Slic3r::format_memsize_MB(stack.memsize()) << line_end << line_end; - -#ifdef _WIN32 - HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ::GetCurrentProcessId()); - if (hProcess != nullptr) { - PROCESS_MEMORY_COUNTERS_EX pmc; - if (GetProcessMemoryInfo(hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc))) - out << b_start << "WorkingSet [MB]: " << b_end << format_memsize_MB(pmc.WorkingSetSize) << line_end - << b_start << "PrivateBytes [MB]: " << b_end << format_memsize_MB(pmc.PrivateUsage) << line_end - << b_start << "Pagefile(peak) [MB]: " << b_end << format_memsize_MB(pmc.PagefileUsage) << "(" << format_memsize_MB(pmc.PeakPagefileUsage) << ")" << line_end; - CloseHandle(hProcess); + std::string mem_info_str = log_memory_info(true); + std::istringstream mem_info(mem_info_str); + std::string value; + while (std::getline(mem_info, value, ':')) { + out << b_start << (value+": ") << b_end; + std::getline(mem_info, value, ';'); + out << value << line_end; } -#endif + + const Slic3r::UndoRedo::Stack &stack = wxGetApp().plater()->undo_redo_stack_main(); + out << b_start << "RAM size reserved for the Undo / Redo stack: " << b_end << Slic3r::format_memsize_MB(stack.get_memory_limit()) << line_end; + out << b_start << "RAM size occupied by the Undo / Redo stack: " << b_end << Slic3r::format_memsize_MB(stack.memsize()) << line_end << line_end; + return out.str(); } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 5f9c8f75c..b73d6b48d 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -62,6 +62,8 @@ Tab::Tab(wxNotebook* parent, const wxString& title, Preset::Type type) : m_em_unit = wxGetApp().em_unit(); + m_config_manipulation = get_config_manipulation(); + Bind(wxEVT_SIZE, ([this](wxSizeEvent &evt) { for (auto page : m_pages) if (! page.get()->IsShown()) @@ -159,8 +161,8 @@ void Tab::create_preset_tab() m_undo_to_sys_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent) { on_roll_back_value(true); })); m_question_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent) { - auto dlg = new ButtonsDescription(this, m_icon_descriptions); - if (dlg->ShowModal() == wxID_OK) { + ButtonsDescription dlg(this, m_icon_descriptions); + if (dlg.ShowModal() == wxID_OK) { // Colors for ui "decoration" for (Tab *tab : wxGetApp().tabs_list) { tab->m_sys_label_clr = wxGetApp().get_label_clr_sys(); @@ -373,6 +375,8 @@ void Tab::update_labels_colour() // Thaw(); auto cur_item = m_treectrl->GetFirstVisibleItem(); + if (!cur_item || !m_treectrl->IsVisible(cur_item)) + return; while (cur_item) { auto title = m_treectrl->GetItemText(cur_item); for (auto page : m_pages) @@ -468,7 +472,7 @@ void Tab::update_changed_ui() wxTheApp->CallAfter([this]() { if (parent()) //To avoid a crash, parent should be exist for a moment of a tree updating - update_changed_tree_ui(); + update_changed_tree_ui(); }); } @@ -731,6 +735,8 @@ void Tab::update_mode() m_mode_sizer->SetMode(m_mode); update_visibility(); + + update_changed_tree_ui(); } void Tab::update_visibility() @@ -743,8 +749,6 @@ void Tab::update_visibility() Layout(); Thaw(); - - update_changed_tree_ui(); } void Tab::msw_rescale() @@ -836,6 +840,11 @@ static wxString support_combo_value_for_config(const DynamicPrintConfig &config, _("Everywhere")); } +static wxString pad_combo_value_for_config(const DynamicPrintConfig &config) +{ + return config.opt_bool("pad_enable") ? (config.opt_bool("pad_zero_elevation") ? _("Around object") : _("Below object")) : _("None"); +} + void Tab::on_value_change(const std::string& opt_key, const boost::any& value) { if (wxGetApp().plater() == nullptr) { @@ -855,6 +864,9 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) (opt_key == "supports_enable" || opt_key == "support_buildplate_only")) og_freq_chng_params->set_value("support", support_combo_value_for_config(*m_config, is_fff)); + if (! is_fff && (opt_key == "pad_enable" || opt_key == "pad_zero_elevation")) + og_freq_chng_params->set_value("pad", pad_combo_value_for_config(*m_config)); + if (opt_key == "brim_width") { bool val = m_config->opt_float("brim_width") > 0.0 ? true : false; @@ -989,6 +1001,8 @@ void Tab::update_frequently_changed_parameters() if (!og_freq_chng_params) return; og_freq_chng_params->set_value("support", support_combo_value_for_config(*m_config, is_fff)); + if (! is_fff) + og_freq_chng_params->set_value("pad", pad_combo_value_for_config(*m_config)); const std::string updated_value_key = is_fff ? "fill_density" : "pad_enable"; @@ -1261,7 +1275,7 @@ void TabPrint::build() line.append_option(option); optgroup->append_line(line); - optgroup = page->new_optgroup(_(L("Output file"))); + optgroup = page->new_optgroup(_(L("Output file"))); optgroup->append_single_option_line("gcode_comments"); optgroup->append_single_option_line("gcode_label_objects"); option = optgroup->get_option("output_filename_format"); @@ -1312,6 +1326,7 @@ void TabPrint::update() if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) return; // ys_FIXME + /* // #ys_FIXME_to_delete //! Temporary workaround for the correct updates of the TextCtrl (like "layer_height"): // KillFocus() for the wxSpinCtrl use CallAfter function. So, @@ -1319,18 +1334,21 @@ void TabPrint::update() // let check if this process is already started. if (is_msg_dlg_already_exist) return; + */ m_update_cnt++; // Freeze(); + /* #ys_FIXME_delete_after_testing (refactoring) + * // layer_height shouldn't be equal to zero if (m_config->opt_float("layer_height") < EPSILON) { const wxString msg_text = _(L("Zero layer height is not valid.\n\nThe layer height will be reset to 0.01.")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Layer height")), wxICON_WARNING | wxOK); + wxMessageDialog dialog(parent(), msg_text, _(L("Layer height")), wxICON_WARNING | wxOK); DynamicPrintConfig new_conf = *m_config; is_msg_dlg_already_exist = true; - dialog->ShowModal(); + dialog.ShowModal(); new_conf.set_key_value("layer_height", new ConfigOptionFloat(0.01)); load_config(new_conf); is_msg_dlg_already_exist = false; @@ -1339,10 +1357,10 @@ void TabPrint::update() if (fabs(m_config->option("first_layer_height")->value - 0) < EPSILON) { const wxString msg_text = _(L("Zero first layer height is not valid.\n\nThe first layer height will be reset to 0.01.")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("First layer height")), wxICON_WARNING | wxOK); + wxMessageDialog dialog(parent(), msg_text, _(L("First layer height")), wxICON_WARNING | wxOK); DynamicPrintConfig new_conf = *m_config; is_msg_dlg_already_exist = true; - dialog->ShowModal(); + dialog.ShowModal(); new_conf.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(0.01, false)); load_config(new_conf); is_msg_dlg_already_exist = false; @@ -1371,9 +1389,9 @@ void TabPrint::update() "- unchecked 'dense infill'\n" "- unchecked 'extra perimeters'\n" "\nShall I adjust those settings in order to enable Spiral Vase?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Spiral Vase")), wxICON_WARNING | wxYES | wxNO); + wxMessageDialog dialog(parent(), msg_text, _(L("Spiral Vase")), wxICON_WARNING | wxYES | wxNO); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_YES) { + if (dialog.ShowModal() == wxID_YES) { new_conf.set_key_value("perimeters", new ConfigOptionInt(1)); new_conf.set_key_value("top_solid_layers", new ConfigOptionInt(0)); new_conf.set_key_value("fill_density", new ConfigOptionPercent(0)); @@ -1399,9 +1417,9 @@ void TabPrint::update() "if they are printed with the current extruder without triggering a tool change.\n" "(both support_material_extruder and support_material_interface_extruder need to be set to 0).\n" "\nShall I adjust those settings in order to enable the Wipe Tower?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO); + wxMessageDialog dialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_YES) { + if (dialog.ShowModal() == wxID_YES) { new_conf.set_key_value("support_material_extruder", new ConfigOptionInt(0)); new_conf.set_key_value("support_material_interface_extruder", new ConfigOptionInt(0)); } @@ -1416,9 +1434,9 @@ void TabPrint::update() wxString msg_text = _(L("For the Wipe Tower to work with the soluble supports, the support layers\n" "need to be synchronized with the object layers.\n" "\nShall I synchronize support layers in order to enable the Wipe Tower?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO); + wxMessageDialog dialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_YES) { + if (dialog.ShowModal() == wxID_YES) { new_conf.set_key_value("support_material_synchronize_layers", new ConfigOptionBool(true)); } else @@ -1434,9 +1452,9 @@ void TabPrint::update() wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n" "- Detect bridging perimeters\n" "\nShall I adjust those settings for supports?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Support Generator")), wxICON_WARNING | wxYES | wxNO | wxCANCEL); + wxMessageDialog dialog(parent(), msg_text, _(L("Support Generator")), wxICON_WARNING | wxYES | wxNO | wxCANCEL); DynamicPrintConfig new_conf = *m_config; - auto answer = dialog->ShowModal(); + auto answer = dialog.ShowModal(); if (answer == wxID_YES) { // Enable "detect bridging perimeters". new_conf.set_key_value("overhangs", new ConfigOptionBool(true)); @@ -1483,9 +1501,9 @@ void TabPrint::update() if (!correct_100p_fill) { wxString msg_text = GUI::from_u8((boost::format(_utf8(L("The %1% infill pattern is not supposed to work at 100%% density.\n\n" "Shall I switch to rectilinear fill pattern?"))) % str_fill_pattern).str()); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Infill")), wxICON_WARNING | wxYES | wxNO); + wxMessageDialog dialog(parent(), msg_text, _(L("Infill")), wxICON_WARNING | wxYES | wxNO); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_YES) { + if (dialog.ShowModal() == wxID_YES) { new_conf.set_key_value("fill_pattern", new ConfigOptionEnum(ipRectilinear)); fill_density = 100; } @@ -1587,6 +1605,9 @@ void TabPrint::update() bool have_wipe_tower = m_config->opt_bool("wipe_tower"); for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging"}) get_field(el)->toggle(have_wipe_tower); + */ + + m_config_manipulation.update_print_fff_config(m_config, true); m_recommended_thin_wall_thickness_description_line->SetText( from_u8(PresetHints::recommended_thin_wall_thickness(*m_preset_bundle))); @@ -1595,9 +1616,14 @@ void TabPrint::update() // Thaw(); m_update_cnt--; - if (m_update_cnt==0) + if (m_update_cnt==0) { + m_config_manipulation.toggle_print_fff_options(m_config); + + wxGetApp().obj_list()->update_and_show_object_settings_item(); + wxGetApp().mainframe->on_config_changed(m_config); } +} void TabPrint::OnActivate() { @@ -1718,7 +1744,7 @@ void TabFilament::build() optgroup->append_single_option_line("filament_density"); optgroup->append_single_option_line("filament_cost"); - optgroup = page->new_optgroup(_(L("Temperature ")) + wxString("°C", wxConvUTF8)); + optgroup = page->new_optgroup(_(L("Temperature")) + wxString(" °C", wxConvUTF8)); Line line = { _(L("Extruder")), "" }; line.append_option(optgroup->get_option("first_layer_temperature")); line.append_option(optgroup->get_option("temperature")); @@ -1872,6 +1898,17 @@ void TabFilament::reload_config() Tab::reload_config(); } +void TabFilament::update_volumetric_flow_preset_hints() +{ + wxString text; + try { + text = from_u8(PresetHints::maximum_volumetric_flow_description(*m_preset_bundle)); + } catch (std::exception &ex) { + text = _(L("Volumetric flow hints not available\n\n")) + from_u8(ex.what()); + } + m_volumetric_speed_description_line->SetText(text); +} + void TabFilament::update() { if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) @@ -1881,8 +1918,7 @@ void TabFilament::update() wxString text = from_u8(PresetHints::cooling_description(m_presets->get_edited_preset())); m_cooling_description_line->SetText(text); - text = from_u8(PresetHints::maximum_volumetric_flow_description(*m_preset_bundle)); - m_volumetric_speed_description_line->SetText(text); + this->update_volumetric_flow_preset_hints(); Layout(); bool cooling = m_config->opt_bool("cooling", 0); @@ -1904,7 +1940,7 @@ void TabFilament::update() void TabFilament::OnActivate() { - m_volumetric_speed_description_line->SetText(from_u8(PresetHints::maximum_volumetric_flow_description(*m_preset_bundle))); + this->update_volumetric_flow_preset_hints(); Tab::OnActivate(); } @@ -2137,16 +2173,19 @@ void TabPrinter::build_fff() const wxString msg_text = _(L("Single Extruder Multi Material is selected, \n" "and all extruders must have the same diameter.\n" "Do you want to change the diameter for all extruders to first extruder nozzle diameter value?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); + wxMessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); - if (dialog->ShowModal() == wxID_YES) { DynamicPrintConfig new_conf = *m_config; + if (dialog.ShowModal() == wxID_YES) { for (size_t i = 1; i < nozzle_diameters.size(); i++) nozzle_diameters[i] = frst_diam; new_conf.set_key_value("nozzle_diameter", new ConfigOptionFloats(nozzle_diameters)); - load_config(new_conf); } + else + new_conf.set_key_value("single_extruder_multi_material", new ConfigOptionBool(false)); + + load_config(new_conf); break; } } @@ -2380,6 +2419,12 @@ void TabPrinter::build_sla() optgroup->append_single_option_line("absolute_correction"); optgroup->append_single_option_line("gamma_correction"); + optgroup = page->new_optgroup(_(L("Exposure"))); + optgroup->append_single_option_line("min_exposure_time"); + optgroup->append_single_option_line("max_exposure_time"); + optgroup->append_single_option_line("min_initial_exposure_time"); + optgroup->append_single_option_line("max_initial_exposure_time"); + optgroup = page->new_optgroup(_(L("Print Host upload"))); build_printhost(optgroup.get()); @@ -2413,9 +2458,9 @@ void TabPrinter::extruders_count_changed(size_t extruders_count) { bool is_count_changed = false; if (m_extruders_count != extruders_count) { - m_extruders_count = extruders_count; - m_preset_bundle->printers.get_edited_preset().set_num_extruders(extruders_count); - m_preset_bundle->update_multi_material_filament_presets(); + m_extruders_count = extruders_count; + m_preset_bundle->printers.get_edited_preset().set_num_extruders(extruders_count); + m_preset_bundle->update_multi_material_filament_presets(); is_count_changed = true; } else if (m_extruders_count == 1 && @@ -2600,11 +2645,12 @@ void TabPrinter::build_unregular_pages() // if value was changed if (fabs(nozzle_diameters[extruder_idx == 0 ? 1 : 0] - new_nd) > EPSILON) { - const wxString msg_text = _(L("Do you want to change the diameter for all extruders?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); + const wxString msg_text = _(L("This is a single extruder multimaterial printer, diameters of all extruders " + "will be set to the new value. Do you want to proceed?")); + wxMessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_YES) { + if (dialog.ShowModal() == wxID_YES) { for (size_t i = 0; i < nozzle_diameters.size(); i++) { if (i==extruder_idx) continue; @@ -2653,7 +2699,33 @@ void TabPrinter::build_unregular_pages() optgroup->append_single_option_line("retract_restart_extra_toolchange", extruder_idx); optgroup = page->new_optgroup(_(L("Preview"))); - optgroup->append_single_option_line("extruder_colour", extruder_idx); + + auto reset_to_filament_color = [this, extruder_idx](wxWindow* parent) { + add_scaled_button(parent, &m_reset_to_filament_color, "undo", + _(L("Reset to Filament Color")), wxBU_LEFT | wxBU_EXACTFIT); + ScalableButton* btn = m_reset_to_filament_color; + btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(btn); + + btn->Bind(wxEVT_BUTTON, [this, extruder_idx](wxCommandEvent& e) + { + std::vector colors = static_cast(m_config->option("extruder_colour"))->values; + colors[extruder_idx] = ""; + + DynamicPrintConfig new_conf = *m_config; + new_conf.set_key_value("extruder_colour", new ConfigOptionStrings(colors)); + load_config(new_conf); + + update_dirty(); + update(); + }); + + return sizer; + }; + line = optgroup->create_single_option_line("extruder_colour", extruder_idx); + line.append_widget(reset_to_filament_color); + optgroup->append_line(line); #ifdef __WXMSW__ layout_page(page); @@ -2810,13 +2882,13 @@ void TabPrinter::update_fff() get_field("retract_before_wipe", i)->toggle(wipe); if (use_firmware_retraction && wipe) { - auto dialog = new wxMessageDialog(parent(), + wxMessageDialog dialog(parent(), _(L("The Wipe option is not available when using the Firmware Retraction mode.\n" "\nShall I disable it in order to enable Firmware Retraction?")), _(L("Firmware Retraction")), wxICON_WARNING | wxYES | wxNO); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_YES) { + if (dialog.ShowModal() == wxID_YES) { auto wipe = static_cast(m_config->option("wipe")->clone()); for (int w = 0; w < wipe->values.size(); w++) wipe->values[w] = false; @@ -3172,10 +3244,10 @@ bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr message += wxString("\n") + tab + from_u8(new_printer_name) + "\n\n"; message += _(L("and it has the following unsaved changes:")); } - auto confirm = new wxMessageDialog(parent(), + wxMessageDialog confirm(parent(), message + "\n" + changes + "\n\n" + _(L("Discard changes and continue anyway?")), _(L("Unsaved Changes")), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION); - return confirm->ShowModal() == wxID_YES; + return confirm.ShowModal() == wxID_YES; } // If we are switching from the FFF-preset to the SLA, we should to control the printed objects if they have a part(s). @@ -3282,11 +3354,11 @@ void Tab::save_preset(std::string name /*= ""*/) values.push_back(preset.name); } - auto dlg = new SavePresetWindow(parent()); - dlg->build(title(), default_name, values); - if (dlg->ShowModal() != wxID_OK) + SavePresetWindow dlg(parent()); + dlg.build(title(), default_name, values); + if (dlg.ShowModal() != wxID_OK) return; - name = dlg->get_name(); + name = dlg.get_name(); if (name == "") { show_error(this, _(L("The supplied name is empty. It can't be saved."))); return; @@ -3816,6 +3888,7 @@ void TabSLAPrint::build() // optgroup->append_single_option_line("pad_edge_radius"); optgroup->append_single_option_line("pad_wall_slope"); + optgroup->append_single_option_line("pad_zero_elevation"); optgroup->append_single_option_line("pad_object_gap"); optgroup->append_single_option_line("pad_object_connector_stride"); optgroup->append_single_option_line("pad_object_connector_width"); @@ -3865,19 +3938,47 @@ void TabSLAPrint::update() m_update_cnt++; + /* #ys_FIXME_delete_after_testing (refactoring) + * + bool supports_en = m_config->opt_bool("supports_enable"); + + get_field("support_head_front_diameter")->toggle(supports_en); + get_field("support_head_penetration")->toggle(supports_en); + get_field("support_head_width")->toggle(supports_en); + get_field("support_pillar_diameter")->toggle(supports_en); + get_field("support_pillar_connection_mode")->toggle(supports_en); + get_field("support_buildplate_only")->toggle(supports_en); + get_field("support_base_diameter")->toggle(supports_en); + get_field("support_base_height")->toggle(supports_en); + get_field("support_base_safety_distance")->toggle(supports_en); + get_field("support_critical_angle")->toggle(supports_en); + get_field("support_max_bridge_length")->toggle(supports_en); + get_field("support_max_pillar_link_distance")->toggle(supports_en); + get_field("support_points_density_relative")->toggle(supports_en); + get_field("support_points_minimal_distance")->toggle(supports_en); + + bool pad_en = m_config->opt_bool("pad_enable"); + + get_field("pad_wall_thickness")->toggle(pad_en); + get_field("pad_wall_height")->toggle(pad_en); + get_field("pad_max_merge_distance")->toggle(pad_en); + // get_field("pad_edge_radius")->toggle(supports_en); + get_field("pad_wall_slope")->toggle(pad_en); + get_field("pad_zero_elevation")->toggle(pad_en); + double head_penetration = m_config->opt_float("support_head_penetration"); double head_width = m_config->opt_float("support_head_width"); if (head_penetration > head_width) { wxString msg_text = _( L("Head penetration should not be greater than the head width.")); - auto dialog = new wxMessageDialog(parent(), + wxMessageDialog dialog(parent(), msg_text, _(L("Invalid Head penetration")), wxICON_WARNING | wxOK); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_OK) { + if (dialog.ShowModal() == wxID_OK) { new_conf.set_key_value("support_head_penetration", new ConfigOptionFloat(head_width)); } @@ -3891,13 +3992,13 @@ void TabSLAPrint::update() wxString msg_text = _(L( "Pinhead diameter should be smaller than the pillar diameter.")); - auto dialog = new wxMessageDialog(parent(), + wxMessageDialog dialog (parent(), msg_text, _(L("Invalid pinhead diameter")), wxICON_WARNING | wxOK); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_OK) { + if (dialog.ShowModal() == wxID_OK) { new_conf.set_key_value("support_head_front_diameter", new ConfigOptionFloat(pillar_d / 2.0)); } @@ -3905,18 +4006,49 @@ void TabSLAPrint::update() load_config(new_conf); } - // if(m_config->opt_float("support_object_elevation") < EPSILON && - // m_config->opt_bool("pad_enable")) { - // // TODO: disable editding of: - // // pad_object_connector_stride - // // pad_object_connector_width - // // pad_object_connector_penetration - // } + bool has_suppad = pad_en && supports_en; + bool zero_elev = m_config->opt_bool("pad_zero_elevation") && has_suppad; + get_field("support_object_elevation")->toggle(supports_en && !zero_elev); + get_field("pad_object_gap")->toggle(zero_elev); + get_field("pad_object_connector_stride")->toggle(zero_elev); + get_field("pad_object_connector_width")->toggle(zero_elev); + get_field("pad_object_connector_penetration")->toggle(zero_elev); +*/ + + m_config_manipulation.update_print_sla_config(m_config, true); m_update_cnt--; - if (m_update_cnt == 0) wxGetApp().mainframe->on_config_changed(m_config); + if (m_update_cnt == 0) { + m_config_manipulation.toggle_print_sla_options(m_config); + + wxGetApp().obj_list()->update_and_show_object_settings_item(); + + wxGetApp().mainframe->on_config_changed(m_config); } +} + +ConfigManipulation Tab::get_config_manipulation() +{ + auto load_config = [this]() + { + update_dirty(); + // Initialize UI components with the config values. + reload_config(); + update(); + }; + + auto get_field_ = [this](const t_config_option_key& opt_key, int opt_index) { + return get_field(opt_key, opt_index); + }; + + auto cb_value_change = [this](const std::string& opt_key, const boost::any& value) { + return on_value_change(opt_key, value); + }; + + return ConfigManipulation(load_config, get_field_, cb_value_change); +} + } // GUI } // Slic3r diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 6ff76f5c4..f57558c45 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -32,6 +32,7 @@ #include "ButtonsDescription.hpp" #include "Event.hpp" #include "wxExtensions.hpp" +#include "ConfigManipulation.hpp" namespace Slic3r { namespace GUI { @@ -218,7 +219,7 @@ protected: int m_em_unit; // To avoid actions with no-completed Tab bool m_complited { false }; - ConfigOptionMode m_mode = comSimple; + ConfigOptionMode m_mode = comExpert; // to correct first Tab update_visibility() set mode to Expert public: PresetBundle* m_preset_bundle; @@ -313,6 +314,9 @@ protected: void update_frequently_changed_parameters(); void fill_icon_descriptions(); void set_tooltips_text(); + + ConfigManipulation m_config_manipulation; + ConfigManipulation get_config_manipulation(); }; class TabPrint : public Tab @@ -340,6 +344,7 @@ class TabFilament : public Tab void add_filament_overrides_page(); void update_filament_overrides_page(); + void update_volumetric_flow_preset_hints(); std::map m_overrides_options; public: @@ -370,6 +375,7 @@ public: wxButton* m_serial_test_btn = nullptr; ScalableButton* m_print_host_test_btn = nullptr; ScalableButton* m_printhost_browse_btn = nullptr; + ScalableButton* m_reset_to_filament_color = nullptr; size_t m_extruders_count; size_t m_extruders_count_old = 0; diff --git a/src/slic3r/GUI/UpdateDialogs.hpp b/src/slic3r/GUI/UpdateDialogs.hpp index 2a580e251..4b61b84c2 100644 --- a/src/slic3r/GUI/UpdateDialogs.hpp +++ b/src/slic3r/GUI/UpdateDialogs.hpp @@ -5,7 +5,7 @@ #include #include -#include "slic3r/Utils/Semver.hpp" +#include "libslic3r/Semver.hpp" #include "MsgDialog.hpp" class wxBoxSizer; diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 9f36eceb9..a4cccfb86 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -157,6 +157,24 @@ wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, return item; } +wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string, const wxString& description, + std::function cb, wxEvtHandler* event_handler) +{ + if (id == wxID_ANY) + id = wxNewId(); + + wxMenuItem* item = menu->AppendCheckItem(id, string, description); + +#ifdef __WXMSW__ + if (event_handler != nullptr && event_handler != menu) + event_handler->Bind(wxEVT_MENU, cb, id); + else +#endif // __WXMSW__ + menu->Bind(wxEVT_MENU, cb, id); + + return item; +} + const unsigned int wxCheckListBoxComboPopup::DefaultWidth = 200; const unsigned int wxCheckListBoxComboPopup::DefaultHeight = 200; const unsigned int wxCheckListBoxComboPopup::DefaultItemHeight = 18; @@ -432,6 +450,16 @@ wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in, // ObjectDataViewModelNode // ---------------------------------------------------------------------------- +void ObjectDataViewModelNode::init_container() +{ +#ifdef __WXGTK__ + // it's necessary on GTK because of control have to know if this item will be container + // in another case you couldn't to add subitem for this item + // it will be produce "segmentation fault" + m_container = true; +#endif //__WXGTK__ +} + ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) : m_parent(parent), m_type(type), @@ -454,13 +482,8 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent m_name = _(L("Layers")); } -#ifdef __WXGTK__ - // it's necessary on GTK because of control have to know if this item will be container - // in another case you couldn't to add subitem for this item - // it will be produce "segmentation fault" if (type & (itInstanceRoot | itLayerRoot)) - m_container = true; -#endif //__WXGTK__ + init_container(); } ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, @@ -486,16 +509,19 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")"; m_bmp = create_scaled_bitmap(nullptr, "edit_layers_some"); // FIXME: pass window ptr -#ifdef __WXGTK__ - // it's necessary on GTK because of control have to know if this item will be container - // in another case you couldn't to add subitem for this item - // it will be produce "segmentation fault" - m_container = true; -#endif //__WXGTK__ - set_action_icon(); + init_container(); } +#ifndef NDEBUG +bool ObjectDataViewModelNode::valid() +{ + // Verify that the object was not deleted yet. + assert(m_idx >= -1); + return m_idx >= -1; +} +#endif /* NDEBUG */ + void ObjectDataViewModelNode::set_action_icon() { m_action_icon_name = m_type & itObject ? "advanced_plus" : @@ -503,6 +529,13 @@ void ObjectDataViewModelNode::set_action_icon() m_action_icon = create_scaled_bitmap(nullptr, m_action_icon_name); // FIXME: pass window ptr } +void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable) +{ + m_printable = printable; + m_printable_icon = m_printable == piUndef ? m_empty_bmp : + create_scaled_bitmap(nullptr, m_printable == piPrintable ? "eye_open.png" : "eye_closed.png"); +} + Slic3r::GUI::BitmapCache *m_bitmap_cache = nullptr; void ObjectDataViewModelNode::update_settings_digest_bitmaps() { @@ -556,17 +589,20 @@ bool ObjectDataViewModelNode::SetValue(const wxVariant& variant, unsigned col) { switch (col) { - case 0: { + case colPrint: + m_printable_icon << variant; + return true; + case colName: { DataViewBitmapText data; data << variant; m_bmp = data.GetBitmap(); m_name = data.GetText(); return true; } - case 1: { + case colExtruder: { const wxString & val = variant.GetString(); m_extruder = val == "0" ? _(L("default")) : val; return true; } - case 2: + case colEditing: m_action_icon << variant; return true; default: @@ -726,26 +762,60 @@ static bool append_root_node(ObjectDataViewModelNode *parent_node, return false; } -wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num) +wxDataViewItem ObjectDataViewModel::AddRoot(const wxDataViewItem &parent_item, ItemType root_type) { ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID(); if (!parent_node) return wxDataViewItem(0); // get InstanceRoot node - ObjectDataViewModelNode *inst_root_node { nullptr }; + ObjectDataViewModelNode *root_node { nullptr }; + const bool appended = append_root_node(parent_node, &root_node, root_type); + if (!root_node) return wxDataViewItem(0); - const bool appended = append_root_node(parent_node, &inst_root_node, itInstanceRoot); - const wxDataViewItem inst_root_item((void*)inst_root_node); - if (!inst_root_node) return wxDataViewItem(0); + const wxDataViewItem root_item((void*)root_node); if (appended) - ItemAdded(parent_item, inst_root_item);// notify control + ItemAdded(parent_item, root_item);// notify control + return root_item; +} + +wxDataViewItem ObjectDataViewModel::AddInstanceRoot(const wxDataViewItem &parent_item) +{ + return AddRoot(parent_item, itInstanceRoot); +} + +wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num) +{ + const std::vector print_indicator(num, true); + + return wxDataViewItem((void*)AddInstanceChild(parent_item, print_indicator)); +} + +wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem& parent_item, + const std::vector& print_indicator) +{ + const wxDataViewItem inst_root_item = AddInstanceRoot(parent_item); + if (!inst_root_item) return wxDataViewItem(0); + + ObjectDataViewModelNode* inst_root_node = (ObjectDataViewModelNode*)inst_root_item.GetID(); + + const bool just_created = inst_root_node->GetChildren().Count() == 0; // Add instance nodes ObjectDataViewModelNode *instance_node = nullptr; size_t counter = 0; - while (counter < num) { + while (counter < print_indicator.size()) { instance_node = new ObjectDataViewModelNode(inst_root_node, itInstance); + + // if InstanceRoot item is just created and start to adding Instances + if (just_created && counter == 0) { + ObjectDataViewModelNode* obj_node = (ObjectDataViewModelNode*)parent_item.GetID(); + // use object's printable state to first instance + instance_node->set_printable_icon(obj_node->IsPrintable()); + } + else + instance_node->set_printable_icon(print_indicator[counter] ? piPrintable : piUnprintable); + inst_root_node->Append(instance_node); // notify control const wxDataViewItem instance_item((void*)instance_node); @@ -753,25 +823,67 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &paren ++counter; } + // update object_node printable property + UpdateObjectPrintable(parent_item); + return wxDataViewItem((void*)instance_node); } +void ObjectDataViewModel::UpdateObjectPrintable(wxDataViewItem parent_item) +{ + const wxDataViewItem inst_root_item = GetInstanceRootItem(parent_item); + if (!inst_root_item) + return; + + ObjectDataViewModelNode* inst_root_node = (ObjectDataViewModelNode*)inst_root_item.GetID(); + + const size_t child_cnt = inst_root_node->GetChildren().Count(); + PrintIndicator obj_pi = piUnprintable; + for (size_t i=0; i < child_cnt; i++) + if (inst_root_node->GetNthChild(i)->IsPrintable() & piPrintable) { + obj_pi = piPrintable; + break; + } + // and set printable state for object_node to piUndef + ObjectDataViewModelNode* obj_node = (ObjectDataViewModelNode*)parent_item.GetID(); + obj_node->set_printable_icon(obj_pi); + ItemChanged(parent_item); +} + +// update printable property for all instances from object +void ObjectDataViewModel::UpdateInstancesPrintable(wxDataViewItem parent_item) +{ + const wxDataViewItem inst_root_item = GetInstanceRootItem(parent_item); + if (!inst_root_item) + return; + + ObjectDataViewModelNode* obj_node = (ObjectDataViewModelNode*)parent_item.GetID(); + const PrintIndicator obj_pi = obj_node->IsPrintable(); + + ObjectDataViewModelNode* inst_root_node = (ObjectDataViewModelNode*)inst_root_item.GetID(); + const size_t child_cnt = inst_root_node->GetChildren().Count(); + + for (size_t i=0; i < child_cnt; i++) + { + ObjectDataViewModelNode* inst_node = inst_root_node->GetNthChild(i); + // and set printable state for object_node to piUndef + inst_node->set_printable_icon(obj_pi); + ItemChanged(wxDataViewItem((void*)inst_node)); + } +} + +bool ObjectDataViewModel::IsPrintable(const wxDataViewItem& item) const +{ + ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID(); + if (!node) + return false; + + return node->IsPrintable() == piPrintable; +} + wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_item) { - ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID(); - if (!parent_node) return wxDataViewItem(0); - - // get LayerRoot node - ObjectDataViewModelNode *layer_root_node{ nullptr }; - const bool appended = append_root_node(parent_node, &layer_root_node, itLayerRoot); - if (!layer_root_node) return wxDataViewItem(0); - - const wxDataViewItem layer_root_item((void*)layer_root_node); - - if (appended) - ItemAdded(parent_item, layer_root_item);// notify control - - return layer_root_item; + return AddRoot(parent_item, itLayerRoot); } wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item, @@ -869,11 +981,13 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item) ItemDeleted(parent, item); ObjectDataViewModelNode *last_instance_node = node_parent->GetNthChild(0); + PrintIndicator last_instance_printable = last_instance_node->IsPrintable(); node_parent->GetChildren().Remove(last_instance_node); delete last_instance_node; ItemDeleted(parent, wxDataViewItem(last_instance_node)); ObjectDataViewModelNode *obj_node = node_parent->GetParent(); + obj_node->set_printable_icon(last_instance_printable); obj_node->GetChildren().Remove(node_parent); delete node_parent; ret_item = wxDataViewItem(obj_node); @@ -886,6 +1000,9 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item) return ret_item; } + if (node->m_type & itInstance) + UpdateObjectPrintable(wxDataViewItem(node_parent->GetParent())); + // if there was last layer item, delete this one and layers root item if (node_parent->GetChildCount() == 0 && node_parent->m_type == itLayerRoot) { @@ -995,9 +1112,12 @@ wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &par const int inst_cnt = inst_root_node->GetChildCount(); const bool delete_inst_root_item = inst_cnt - num < 2 ? true : false; + PrintIndicator last_inst_printable = piUndef; + int stop = delete_inst_root_item ? 0 : inst_cnt - num; for (int i = inst_cnt - 1; i >= stop;--i) { ObjectDataViewModelNode *last_instance_node = inst_root_node->GetNthChild(i); + if (i==0) last_inst_printable = last_instance_node->IsPrintable(); inst_root_node->GetChildren().Remove(last_instance_node); delete last_instance_node; ItemDeleted(inst_root_item, wxDataViewItem(last_instance_node)); @@ -1006,13 +1126,18 @@ wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &par if (delete_inst_root_item) { ret_item = parent_item; parent_node->GetChildren().Remove(inst_root_node); + parent_node->set_printable_icon(last_inst_printable); ItemDeleted(parent_item, inst_root_item); + ItemChanged(parent_item); #ifndef __WXGTK__ if (parent_node->GetChildCount() == 0) parent_node->m_container = false; #endif //__WXGTK__ } + // update object_node printable property + UpdateObjectPrintable(parent_item); + return ret_item; } @@ -1316,6 +1441,18 @@ int ObjectDataViewModel::GetRowByItem(const wxDataViewItem& item) const return -1; } +bool ObjectDataViewModel::InvalidItem(const wxDataViewItem& item) +{ + if (!item) + return true; + + ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID(); + if (!node || node->invalid()) + return true; + + return false; +} + wxString ObjectDataViewModel::GetName(const wxDataViewItem &item) const { ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); @@ -1338,13 +1475,16 @@ void ObjectDataViewModel::GetValue(wxVariant &variant, const wxDataViewItem &ite ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); switch (col) { - case 0: + case colPrint: + variant << node->m_printable_icon; + break; + case colName: variant << DataViewBitmapText(node->m_name, node->m_bmp); break; - case 1: + case colExtruder: variant = node->m_extruder; break; - case 2: + case colEditing: variant << node->m_action_icon; break; default: @@ -1407,7 +1547,7 @@ bool ObjectDataViewModel::IsEnabled(const wxDataViewItem &item, unsigned int col ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); // disable extruder selection for the non "itObject|itVolume" item - return !(col == 1 && node->m_extruder.IsEmpty()); + return !(col == colExtruder && node->m_extruder.IsEmpty()); } wxDataViewItem ObjectDataViewModel::GetParent(const wxDataViewItem &item) const @@ -1417,6 +1557,7 @@ wxDataViewItem ObjectDataViewModel::GetParent(const wxDataViewItem &item) const return wxDataViewItem(0); ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); + assert(node != nullptr && node->valid()); // objects nodes has no parent too if (node->m_type == itObject) @@ -1571,6 +1712,46 @@ void ObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const Slic3r ItemChanged(item); } +wxDataViewItem ObjectDataViewModel::SetPrintableState( + PrintIndicator printable, + int obj_idx, + int subobj_idx /* = -1*/, + ItemType subobj_type/* = itInstance*/) +{ + wxDataViewItem item = wxDataViewItem(0); + if (subobj_idx < 0) + item = GetItemById(obj_idx); + else + item = subobj_type&itInstance ? GetItemByInstanceId(obj_idx, subobj_idx) : + GetItemByVolumeId(obj_idx, subobj_idx); + + ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID(); + if (!node) + return wxDataViewItem(0); + node->set_printable_icon(printable); + ItemChanged(item); + + if (subobj_idx >= 0) + UpdateObjectPrintable(GetItemById(obj_idx)); + + return item; +} + +wxDataViewItem ObjectDataViewModel::SetObjectPrintableState( + PrintIndicator printable, + wxDataViewItem obj_item) +{ + ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)obj_item.GetID(); + if (!node) + return wxDataViewItem(0); + node->set_printable_icon(printable); + ItemChanged(obj_item); + + UpdateInstancesPrintable(obj_item); + + return obj_item; +} + void ObjectDataViewModel::Rescale() { wxDataViewItemArray all_items; @@ -1755,7 +1936,7 @@ bool BitmapTextRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value // The icon can't be edited so get its old value and reuse it. wxVariant valueOld; - GetView()->GetModel()->GetValue(valueOld, m_item, 0); + GetView()->GetModel()->GetValue(valueOld, m_item, colName); DataViewBitmapText bmpText; bmpText << valueOld; @@ -2743,21 +2924,20 @@ LockButton::LockButton( wxWindow *parent, const wxSize& size /*= wxDefaultSize*/): wxButton(parent, id, wxEmptyString, pos, size, wxBU_EXACTFIT | wxNO_BORDER) { - m_bmp_lock_on = ScalableBitmap(this, "one_layer_lock_on.png"); - m_bmp_lock_off = ScalableBitmap(this, "one_layer_lock_off.png"); - m_bmp_unlock_on = ScalableBitmap(this, "one_layer_unlock_on.png"); - m_bmp_unlock_off = ScalableBitmap(this, "one_layer_unlock_off.png"); + m_bmp_lock_closed = ScalableBitmap(this, "lock_closed"); + m_bmp_lock_closed_f = ScalableBitmap(this, "lock_closed_f"); + m_bmp_lock_open = ScalableBitmap(this, "lock_open"); + m_bmp_lock_open_f = ScalableBitmap(this, "lock_open_f"); #ifdef __WXMSW__ SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); #endif // __WXMSW__ - SetBitmap(m_bmp_unlock_on.bmp()); - SetBitmapDisabled(m_bmp_lock_on.bmp()); + SetBitmap(m_bmp_lock_open.bmp()); + SetBitmapDisabled(m_bmp_lock_open.bmp()); + SetBitmapHover(m_bmp_lock_closed_f.bmp()); //button events - Bind(wxEVT_BUTTON, &LockButton::OnButton, this); - Bind(wxEVT_ENTER_WINDOW, &LockButton::OnEnterBtn, this); - Bind(wxEVT_LEAVE_WINDOW, &LockButton::OnLeaveBtn, this); + Bind(wxEVT_BUTTON, &LockButton::OnButton, this); } void LockButton::OnButton(wxCommandEvent& event) @@ -2766,7 +2946,7 @@ void LockButton::OnButton(wxCommandEvent& event) return; m_is_pushed = !m_is_pushed; - enter_button(true); + update_button_bitmaps(); event.Skip(); } @@ -2774,23 +2954,21 @@ void LockButton::OnButton(wxCommandEvent& event) void LockButton::SetLock(bool lock) { m_is_pushed = lock; - enter_button(true); + update_button_bitmaps(); } void LockButton::msw_rescale() { - m_bmp_lock_on .msw_rescale(); - m_bmp_lock_off .msw_rescale(); - m_bmp_unlock_on .msw_rescale(); - m_bmp_unlock_off.msw_rescale(); + m_bmp_lock_closed.msw_rescale(); + m_bmp_lock_closed_f.msw_rescale(); + m_bmp_lock_open.msw_rescale(); + m_bmp_lock_open_f.msw_rescale(); } -void LockButton::enter_button(const bool enter) +void LockButton::update_button_bitmaps() { - const wxBitmap& icon = m_is_pushed ? - enter ? m_bmp_lock_off.bmp() : m_bmp_lock_on.bmp() : - enter ? m_bmp_unlock_off.bmp() : m_bmp_unlock_on.bmp(); - SetBitmap(icon); + SetBitmap(m_is_pushed ? m_bmp_lock_closed.bmp() : m_bmp_lock_open.bmp()); + SetBitmapHover(m_is_pushed ? m_bmp_lock_closed_f.bmp() : m_bmp_lock_open_f.bmp()); Refresh(); Update(); @@ -2959,6 +3137,13 @@ ScalableButton::ScalableButton( wxWindow * parent, #endif // __WXMSW__ SetBitmap(create_scaled_bitmap(parent, icon_name)); + + if (size != wxDefaultSize) + { + const int em = em_unit(parent); + m_width = size.x/em; + m_height= size.y/em; + } } @@ -2985,11 +3170,24 @@ void ScalableButton::SetBitmap_(const ScalableBitmap& bmp) m_current_icon_name = bmp.name(); } +void ScalableButton::SetBitmapDisabled_(const ScalableBitmap& bmp) +{ + SetBitmapDisabled(bmp.bmp()); + m_disabled_icon_name = bmp.name(); +} + void ScalableButton::msw_rescale() { - const wxBitmap bmp = create_scaled_bitmap(m_parent, m_current_icon_name); + SetBitmap(create_scaled_bitmap(m_parent, m_current_icon_name)); + if (!m_disabled_icon_name.empty()) + SetBitmapDisabled(create_scaled_bitmap(m_parent, m_disabled_icon_name)); - SetBitmap(bmp); + if (m_width > 0 || m_height>0) + { + const int em = em_unit(m_parent); + wxSize size(m_width * em, m_height * em); + SetMinSize(size); + } } diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index d7d5fcac2..14ceab8ff 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -11,13 +11,14 @@ #include #include #include +#include #include #include #include namespace Slic3r { - enum class ModelVolumeType : int; + enum class ModelVolumeType : int; }; typedef double coordf_t; @@ -36,11 +37,14 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const std::function cb, const std::string& icon = "", wxEvtHandler* event_handler = nullptr, std::function const cb_condition = []() { return true; }, wxWindow* parent = nullptr); -wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxString& string, const wxString& description, +wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxString& string, const wxString& description, const std::string& icon = "", std::function const cb_condition = []() { return true; }, wxWindow* parent = nullptr); -wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description, +wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description, + std::function cb, wxEvtHandler* event_handler); + +wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string, const wxString& description, std::function cb, wxEvtHandler* event_handler); class wxDialog; @@ -48,7 +52,7 @@ void edit_tooltip(wxString& tooltip); void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector& btn_ids); int em_unit(wxWindow* win); -wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name, +wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name, const int px_cnt = 16, const bool is_horizontal = false, const bool grayscale = false); class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup @@ -92,23 +96,23 @@ public: class wxDataViewTreeCtrlComboPopup: public wxDataViewTreeCtrl, public wxComboPopup { - static const unsigned int DefaultWidth; - static const unsigned int DefaultHeight; - static const unsigned int DefaultItemHeight; + static const unsigned int DefaultWidth; + static const unsigned int DefaultHeight; + static const unsigned int DefaultItemHeight; - wxString m_text; - int m_cnt_open_items{0}; + wxString m_text; + int m_cnt_open_items{0}; public: - virtual bool Create(wxWindow* parent); - virtual wxWindow* GetControl() { return this; } - virtual void SetStringValue(const wxString& value) { m_text = value; } - virtual wxString GetStringValue() const { return m_text; } + virtual bool Create(wxWindow* parent); + virtual wxWindow* GetControl() { return this; } + virtual void SetStringValue(const wxString& value) { m_text = value; } + virtual wxString GetStringValue() const { return m_text; } // virtual wxSize GetAdjustedSize(int minWidth, int prefHeight, int maxHeight); - virtual void OnKeyEvent(wxKeyEvent& evt); - void OnDataViewTreeCtrlSelection(wxCommandEvent& evt); - void SetItemsCnt(int cnt) { m_cnt_open_items = cnt; } + virtual void OnKeyEvent(wxKeyEvent& evt); + void OnDataViewTreeCtrlSelection(wxCommandEvent& evt); + void SetItemsCnt(int cnt) { m_cnt_open_items = cnt; } }; @@ -121,7 +125,7 @@ class DataViewBitmapText : public wxObject public: DataViewBitmapText( const wxString &text = wxEmptyString, const wxBitmap& bmp = wxNullBitmap) : - m_text(text), + m_text(text), m_bmp(bmp) { } @@ -158,7 +162,7 @@ DECLARE_VARIANT_OBJECT(DataViewBitmapText) // ---------------------------------------------------------------------------- -// ObjectDataViewModelNode: a node inside PrusaObjectDataViewModel +// ObjectDataViewModelNode: a node inside ObjectDataViewModel // ---------------------------------------------------------------------------- enum ItemType { @@ -172,13 +176,28 @@ enum ItemType { itLayer = 64, }; +enum ColumnNumber +{ + colName = 0, // item name + colPrint , // printable property + colExtruder , // extruder selection + colEditing , // item editing +}; + +enum PrintIndicator +{ + piUndef = 0, // no print indicator + piPrintable , // printable + piUnprintable , // unprintable +}; + class ObjectDataViewModelNode; WX_DEFINE_ARRAY_PTR(ObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray); class ObjectDataViewModelNode { - ObjectDataViewModelNode* m_parent; - MyObjectTreeModelNodePtrArray m_children; + ObjectDataViewModelNode* m_parent; + MyObjectTreeModelNodePtrArray m_children; wxBitmap m_empty_bmp; size_t m_volumes_cnt = 0; std::vector< std::string > m_opt_categories; @@ -191,161 +210,166 @@ class ObjectDataViewModelNode bool m_container = false; wxString m_extruder = "default"; wxBitmap m_action_icon; + PrintIndicator m_printable {piUndef}; + wxBitmap m_printable_icon; std::string m_action_icon_name = ""; Slic3r::ModelVolumeType m_volume_type; public: - ObjectDataViewModelNode(const wxString &name, + ObjectDataViewModelNode(const wxString &name, const wxString& extruder): m_parent(NULL), m_name(name), m_type(itObject), m_extruder(extruder) { -#ifdef __WXGTK__ - // it's necessary on GTK because of control have to know if this item will be container - // in another case you couldn't to add subitem for this item - // it will be produce "segmentation fault" - m_container = true; -#endif //__WXGTK__ - set_action_icon(); + init_container(); } - ObjectDataViewModelNode(ObjectDataViewModelNode* parent, - const wxString& sub_obj_name, - const wxBitmap& bmp, - const wxString& extruder, + ObjectDataViewModelNode(ObjectDataViewModelNode* parent, + const wxString& sub_obj_name, + const wxBitmap& bmp, + const wxString& extruder, const int idx = -1 ) : m_parent (parent), - m_name (sub_obj_name), - m_type (itVolume), + m_name (sub_obj_name), + m_type (itVolume), m_idx (idx), m_extruder (extruder) { - m_bmp = bmp; -#ifdef __WXGTK__ - // it's necessary on GTK because of control have to know if this item will be container - // in another case you couldn't to add subitem for this item - // it will be produce "segmentation fault" - m_container = true; -#endif //__WXGTK__ - + m_bmp = bmp; set_action_icon(); + init_container(); } - ObjectDataViewModelNode(ObjectDataViewModelNode* parent, - const t_layer_height_range& layer_range, + ObjectDataViewModelNode(ObjectDataViewModelNode* parent, + const t_layer_height_range& layer_range, const int idx = -1, const wxString& extruder = wxEmptyString ); ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type); - ~ObjectDataViewModelNode() - { - // free all our children nodes - size_t count = m_children.GetCount(); - for (size_t i = 0; i < count; i++) - { - ObjectDataViewModelNode *child = m_children[i]; - delete child; - } - } + ~ObjectDataViewModelNode() + { + // free all our children nodes + size_t count = m_children.GetCount(); + for (size_t i = 0; i < count; i++) + { + ObjectDataViewModelNode *child = m_children[i]; + delete child; + } +#ifndef NDEBUG + // Indicate that the object was deleted. + m_idx = -2; +#endif /* NDEBUG */ + } + void init_container(); bool IsContainer() const { return m_container; } - ObjectDataViewModelNode* GetParent() - { - return m_parent; - } - MyObjectTreeModelNodePtrArray& GetChildren() - { - return m_children; - } - ObjectDataViewModelNode* GetNthChild(unsigned int n) - { - return m_children.Item(n); - } - void Insert(ObjectDataViewModelNode* child, unsigned int n) - { - if (!m_container) - m_container = true; - m_children.Insert(child, n); - } - void Append(ObjectDataViewModelNode* child) - { - if (!m_container) - m_container = true; - m_children.Add(child); - } - void RemoveAllChildren() - { - if (GetChildCount() == 0) - return; - for (int id = int(GetChildCount()) - 1; id >= 0; --id) - { - if (m_children.Item(id)->GetChildCount() > 0) - m_children[id]->RemoveAllChildren(); - auto node = m_children[id]; - m_children.RemoveAt(id); - delete node; - } - } + ObjectDataViewModelNode* GetParent() + { + assert(m_parent == nullptr || m_parent->valid()); + return m_parent; + } + MyObjectTreeModelNodePtrArray& GetChildren() + { + return m_children; + } + ObjectDataViewModelNode* GetNthChild(unsigned int n) + { + return m_children.Item(n); + } + void Insert(ObjectDataViewModelNode* child, unsigned int n) + { + if (!m_container) + m_container = true; + m_children.Insert(child, n); + } + void Append(ObjectDataViewModelNode* child) + { + if (!m_container) + m_container = true; + m_children.Add(child); + } + void RemoveAllChildren() + { + if (GetChildCount() == 0) + return; + for (int id = int(GetChildCount()) - 1; id >= 0; --id) + { + if (m_children.Item(id)->GetChildCount() > 0) + m_children[id]->RemoveAllChildren(); + auto node = m_children[id]; + m_children.RemoveAt(id); + delete node; + } + } - size_t GetChildCount() const - { - return m_children.GetCount(); - } + size_t GetChildCount() const + { + return m_children.GetCount(); + } - bool SetValue(const wxVariant &variant, unsigned int col); + bool SetValue(const wxVariant &variant, unsigned int col); - void SetBitmap(const wxBitmap &icon) { m_bmp = icon; } + void SetBitmap(const wxBitmap &icon) { m_bmp = icon; } const wxBitmap& GetBitmap() const { return m_bmp; } const wxString& GetName() const { return m_name; } ItemType GetType() const { return m_type; } void SetIdx(const int& idx); int GetIdx() const { return m_idx; } t_layer_height_range GetLayerRange() const { return m_layer_range; } + PrintIndicator IsPrintable() const { return m_printable; } - // use this function only for childrens - void AssignAllVal(ObjectDataViewModelNode& from_node) - { - // ! Don't overwrite other values because of equality of this values for all children -- - m_name = from_node.m_name; + // use this function only for childrens + void AssignAllVal(ObjectDataViewModelNode& from_node) + { + // ! Don't overwrite other values because of equality of this values for all children -- + m_name = from_node.m_name; m_bmp = from_node.m_bmp; m_idx = from_node.m_idx; m_extruder = from_node.m_extruder; m_type = from_node.m_type; - } + } - bool SwapChildrens(int frst_id, int scnd_id) { - if (GetChildCount() < 2 || - frst_id < 0 || (size_t)frst_id >= GetChildCount() || - scnd_id < 0 || (size_t)scnd_id >= GetChildCount()) - return false; + bool SwapChildrens(int frst_id, int scnd_id) { + if (GetChildCount() < 2 || + frst_id < 0 || (size_t)frst_id >= GetChildCount() || + scnd_id < 0 || (size_t)scnd_id >= GetChildCount()) + return false; - ObjectDataViewModelNode new_scnd = *GetNthChild(frst_id); - ObjectDataViewModelNode new_frst = *GetNthChild(scnd_id); + ObjectDataViewModelNode new_scnd = *GetNthChild(frst_id); + ObjectDataViewModelNode new_frst = *GetNthChild(scnd_id); new_scnd.m_idx = m_children.Item(scnd_id)->m_idx; new_frst.m_idx = m_children.Item(frst_id)->m_idx; - m_children.Item(frst_id)->AssignAllVal(new_frst); - m_children.Item(scnd_id)->AssignAllVal(new_scnd); - return true; - } + m_children.Item(frst_id)->AssignAllVal(new_frst); + m_children.Item(scnd_id)->AssignAllVal(new_scnd); + return true; + } - // Set action icons for node + // Set action icons for node void set_action_icon(); + // Set printable icon for node + void set_printable_icon(PrintIndicator printable); void update_settings_digest_bitmaps(); - bool update_settings_digest(const std::vector& categories); + bool update_settings_digest(const std::vector& categories); int volume_type() const { return int(m_volume_type); } void msw_rescale(); + +#ifndef NDEBUG + bool valid(); +#endif /* NDEBUG */ + bool invalid() const { return m_idx < -1; } + private: friend class ObjectDataViewModel; }; @@ -359,7 +383,7 @@ wxDECLARE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent); class ObjectDataViewModel :public wxDataViewModel { - std::vector m_objects; + std::vector m_objects; std::vector m_volume_bmps; wxBitmap* m_warning_bmp; @@ -369,7 +393,7 @@ public: ObjectDataViewModel(); ~ObjectDataViewModel(); - wxDataViewItem Add( const wxString &name, + wxDataViewItem Add( const wxString &name, const int extruder, const bool has_errors = false); wxDataViewItem AddVolumeChild( const wxDataViewItem &parent_item, @@ -380,25 +404,26 @@ public: const bool create_frst_child = true); wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num); + wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, const std::vector& print_indicator); wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item); - wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item, + wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item, const t_layer_height_range& layer_range, - const int extruder = 0, + const int extruder = 0, const int index = -1); - wxDataViewItem Delete(const wxDataViewItem &item); - wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num); - void DeleteAll(); + wxDataViewItem Delete(const wxDataViewItem &item); + wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num); + void DeleteAll(); void DeleteChildren(wxDataViewItem& parent); void DeleteVolumeChildren(wxDataViewItem& parent); void DeleteSettings(const wxDataViewItem& parent); - wxDataViewItem GetItemById(int obj_idx); + wxDataViewItem GetItemById(int obj_idx); wxDataViewItem GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type); - wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx); - wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx); + wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx); + wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx); wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx); wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range); int GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range); - int GetIdByItem(const wxDataViewItem& item) const; + int GetIdByItem(const wxDataViewItem& item) const; int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const; int GetObjectIdByItem(const wxDataViewItem& item) const; int GetVolumeIdByItem(const wxDataViewItem& item) const; @@ -407,68 +432,81 @@ public: void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx); int GetRowByItem(const wxDataViewItem& item) const; bool IsEmpty() { return m_objects.empty(); } + bool InvalidItem(const wxDataViewItem& item); - // helper method for wxLog + // helper method for wxLog - wxString GetName(const wxDataViewItem &item) const; + wxString GetName(const wxDataViewItem &item) const; wxBitmap& GetBitmap(const wxDataViewItem &item) const; - // helper methods to change the model + // helper methods to change the model - virtual unsigned int GetColumnCount() const override { return 3;} - virtual wxString GetColumnType(unsigned int col) const override{ return wxT("string"); } + virtual unsigned int GetColumnCount() const override { return 3;} + virtual wxString GetColumnType(unsigned int col) const override{ return wxT("string"); } - virtual void GetValue( wxVariant &variant, - const wxDataViewItem &item, + virtual void GetValue( wxVariant &variant, + const wxDataViewItem &item, unsigned int col) const override; - virtual bool SetValue( const wxVariant &variant, - const wxDataViewItem &item, + virtual bool SetValue( const wxVariant &variant, + const wxDataViewItem &item, unsigned int col) override; - bool SetValue( const wxVariant &variant, - const int item_idx, + bool SetValue( const wxVariant &variant, + const int item_idx, unsigned int col); - // For parent move child from cur_volume_id place to new_volume_id + // For parent move child from cur_volume_id place to new_volume_id // Remaining items will moved up/down accordingly - wxDataViewItem ReorganizeChildren( const int cur_volume_id, + wxDataViewItem ReorganizeChildren( const int cur_volume_id, const int new_volume_id, const wxDataViewItem &parent); - virtual bool IsEnabled(const wxDataViewItem &item, unsigned int col) const override; + virtual bool IsEnabled(const wxDataViewItem &item, unsigned int col) const override; - virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override; + virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override; // get object item wxDataViewItem GetTopParent(const wxDataViewItem &item) const; - virtual bool IsContainer(const wxDataViewItem &item) const override; - virtual unsigned int GetChildren(const wxDataViewItem &parent, - wxDataViewItemArray &array) const override; + virtual bool IsContainer(const wxDataViewItem &item) const override; + virtual unsigned int GetChildren(const wxDataViewItem &parent, + wxDataViewItemArray &array) const override; void GetAllChildren(const wxDataViewItem &parent,wxDataViewItemArray &array) const; - // Is the container just a header or an item with all columns - // In our case it is an item with all columns - virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; } + // Is the container just a header or an item with all columns + // In our case it is an item with all columns + virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; } ItemType GetItemType(const wxDataViewItem &item) const ; - wxDataViewItem GetItemByType( const wxDataViewItem &parent_item, + wxDataViewItem GetItemByType( const wxDataViewItem &parent_item, ItemType type) const; wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const; wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const; wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const; bool IsSettingsItem(const wxDataViewItem &item) const; - void UpdateSettingsDigest( const wxDataViewItem &item, + void UpdateSettingsDigest( const wxDataViewItem &item, const std::vector& categories); + bool IsPrintable(const wxDataViewItem &item) const; + void UpdateObjectPrintable(wxDataViewItem parent_item); + void UpdateInstancesPrintable(wxDataViewItem parent_item); + void SetVolumeBitmaps(const std::vector& volume_bmps) { m_volume_bmps = volume_bmps; } void SetWarningBitmap(wxBitmap* bitmap) { m_warning_bmp = bitmap; } void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type); + wxDataViewItem SetPrintableState( PrintIndicator printable, int obj_idx, + int subobj_idx = -1, + ItemType subobj_type = itInstance); + wxDataViewItem SetObjectPrintableState(PrintIndicator printable, wxDataViewItem obj_item); void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; } // Rescale bitmaps for existing Items void Rescale(); - wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, + wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, const bool is_marked = false); void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false); t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const; + +private: + wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type); + wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item); }; // ---------------------------------------------------------------------------- @@ -510,12 +548,12 @@ public: return false; #else return true; -#endif +#endif } - wxWindow* CreateEditorCtrl(wxWindow* parent, - wxRect labelRect, + wxWindow* CreateEditorCtrl(wxWindow* parent, + wxRect labelRect, const wxVariant& value) override; - bool GetValueFromEditorCtrl( wxWindow* ctrl, + bool GetValueFromEditorCtrl( wxWindow* ctrl, wxVariant& value) override; bool WasCanceled() const { return m_was_unusable_symbol; } @@ -532,88 +570,88 @@ private: class MyCustomRenderer : public wxDataViewCustomRenderer { public: - // This renderer can be either activatable or editable, for demonstration - // purposes. In real programs, you should select whether the user should be - // able to activate or edit the cell and it doesn't make sense to switch - // between the two -- but this is just an example, so it doesn't stop us. - explicit MyCustomRenderer(wxDataViewCellMode mode) - : wxDataViewCustomRenderer("string", mode, wxALIGN_CENTER) - { } + // This renderer can be either activatable or editable, for demonstration + // purposes. In real programs, you should select whether the user should be + // able to activate or edit the cell and it doesn't make sense to switch + // between the two -- but this is just an example, so it doesn't stop us. + explicit MyCustomRenderer(wxDataViewCellMode mode) + : wxDataViewCustomRenderer("string", mode, wxALIGN_CENTER) + { } - virtual bool Render(wxRect rect, wxDC *dc, int state) override/*wxOVERRIDE*/ - { - dc->SetBrush(*wxLIGHT_GREY_BRUSH); - dc->SetPen(*wxTRANSPARENT_PEN); + virtual bool Render(wxRect rect, wxDC *dc, int state) override/*wxOVERRIDE*/ + { + dc->SetBrush(*wxLIGHT_GREY_BRUSH); + dc->SetPen(*wxTRANSPARENT_PEN); - rect.Deflate(2); - dc->DrawRoundedRectangle(rect, 5); + rect.Deflate(2); + dc->DrawRoundedRectangle(rect, 5); - RenderText(m_value, - 0, // no offset - wxRect(dc->GetTextExtent(m_value)).CentreIn(rect), - dc, - state); - return true; - } + RenderText(m_value, + 0, // no offset + wxRect(dc->GetTextExtent(m_value)).CentreIn(rect), + dc, + state); + return true; + } - virtual bool ActivateCell(const wxRect& WXUNUSED(cell), - wxDataViewModel *WXUNUSED(model), - const wxDataViewItem &WXUNUSED(item), - unsigned int WXUNUSED(col), - const wxMouseEvent *mouseEvent) override/*wxOVERRIDE*/ - { - wxString position; - if (mouseEvent) - position = wxString::Format("via mouse at %d, %d", mouseEvent->m_x, mouseEvent->m_y); - else - position = "from keyboard"; + virtual bool ActivateCell(const wxRect& WXUNUSED(cell), + wxDataViewModel *WXUNUSED(model), + const wxDataViewItem &WXUNUSED(item), + unsigned int WXUNUSED(col), + const wxMouseEvent *mouseEvent) override/*wxOVERRIDE*/ + { + wxString position; + if (mouseEvent) + position = wxString::Format("via mouse at %d, %d", mouseEvent->m_x, mouseEvent->m_y); + else + position = "from keyboard"; // wxLogMessage("MyCustomRenderer ActivateCell() %s", position); - return false; - } + return false; + } - virtual wxSize GetSize() const override/*wxOVERRIDE*/ - { - return wxSize(60, 20); - } + virtual wxSize GetSize() const override/*wxOVERRIDE*/ + { + return wxSize(60, 20); + } - virtual bool SetValue(const wxVariant &value) override/*wxOVERRIDE*/ - { - m_value = value.GetString(); - return true; - } + virtual bool SetValue(const wxVariant &value) override/*wxOVERRIDE*/ + { + m_value = value.GetString(); + return true; + } - virtual bool GetValue(wxVariant &WXUNUSED(value)) const override/*wxOVERRIDE*/{ return true; } + virtual bool GetValue(wxVariant &WXUNUSED(value)) const override/*wxOVERRIDE*/{ return true; } - virtual bool HasEditorCtrl() const override/*wxOVERRIDE*/{ return true; } + virtual bool HasEditorCtrl() const override/*wxOVERRIDE*/{ return true; } - virtual wxWindow* - CreateEditorCtrl(wxWindow* parent, - wxRect labelRect, - const wxVariant& value) override/*wxOVERRIDE*/ - { - wxTextCtrl* text = new wxTextCtrl(parent, wxID_ANY, value, - labelRect.GetPosition(), - labelRect.GetSize(), - wxTE_PROCESS_ENTER); - text->SetInsertionPointEnd(); + virtual wxWindow* + CreateEditorCtrl(wxWindow* parent, + wxRect labelRect, + const wxVariant& value) override/*wxOVERRIDE*/ + { + wxTextCtrl* text = new wxTextCtrl(parent, wxID_ANY, value, + labelRect.GetPosition(), + labelRect.GetSize(), + wxTE_PROCESS_ENTER); + text->SetInsertionPointEnd(); - return text; - } + return text; + } - virtual bool - GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) override/*wxOVERRIDE*/ - { - wxTextCtrl* text = wxDynamicCast(ctrl, wxTextCtrl); - if (!text) - return false; + virtual bool + GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) override/*wxOVERRIDE*/ + { + wxTextCtrl* text = wxDynamicCast(ctrl, wxTextCtrl); + if (!text) + return false; - value = text->GetValue(); + value = text->GetValue(); - return true; - } + return true; + } private: - wxString m_value; + wxString m_value; }; @@ -625,7 +663,7 @@ class ScalableBitmap { public: ScalableBitmap() {}; - ScalableBitmap( wxWindow *parent, + ScalableBitmap( wxWindow *parent, const std::string& icon_name = "", const int px_cnt = 16, const bool is_horizontal = false); @@ -671,9 +709,9 @@ public: DoubleSlider( wxWindow *parent, wxWindowID id, - int lowerValue, - int higherValue, - int minValue, + int lowerValue, + int higherValue, + int minValue, int maxValue, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, @@ -716,8 +754,8 @@ public: EnableTickManipulation(false); } - bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; } - bool is_one_layer() const { return m_is_one_layer; } + bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; } + bool is_one_layer() const { return m_is_one_layer; } bool is_lower_at_min() const { return m_lower_value == m_min_value; } bool is_higher_at_max() const { return m_higher_value == m_max_value; } bool is_full_span() const { return this->is_lower_at_min() && this->is_higher_at_max(); } @@ -736,7 +774,7 @@ public: void OnRightUp(wxMouseEvent& event); protected: - + void render(); void draw_focus_rect(); void draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoint pt_end); @@ -843,8 +881,6 @@ public: ~LockButton() {} void OnButton(wxCommandEvent& event); - void OnEnterBtn(wxMouseEvent& event) { enter_button(true); event.Skip(); } - void OnLeaveBtn(wxMouseEvent& event) { enter_button(false); event.Skip(); } bool IsLocked() const { return m_is_pushed; } void SetLock(bool lock); @@ -856,16 +892,16 @@ public: void msw_rescale(); protected: - void enter_button(const bool enter); + void update_button_bitmaps(); private: bool m_is_pushed = false; bool m_disabled = false; - ScalableBitmap m_bmp_lock_on; - ScalableBitmap m_bmp_lock_off; - ScalableBitmap m_bmp_unlock_on; - ScalableBitmap m_bmp_unlock_off; + ScalableBitmap m_bmp_lock_closed; + ScalableBitmap m_bmp_lock_closed_f; + ScalableBitmap m_bmp_lock_open; + ScalableBitmap m_bmp_lock_open_f; }; @@ -896,12 +932,16 @@ public: ~ScalableButton() {} void SetBitmap_(const ScalableBitmap& bmp); + void SetBitmapDisabled_(const ScalableBitmap &bmp); void msw_rescale(); private: wxWindow* m_parent; std::string m_current_icon_name = ""; + std::string m_disabled_icon_name = ""; + int m_width {-1}; // should be multiplied to em_unit + int m_height{-1}; // should be multiplied to em_unit }; diff --git a/src/slic3r/Utils/FixModelByWin10.cpp b/src/slic3r/Utils/FixModelByWin10.cpp index 710f19090..d955d6a7e 100644 --- a/src/slic3r/Utils/FixModelByWin10.cpp +++ b/src/slic3r/Utils/FixModelByWin10.cpp @@ -377,7 +377,7 @@ void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx) // PresetBundle bundle; on_progress(L("Loading repaired model"), 80); DynamicPrintConfig config; - bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), &config, &model); + bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), &config, &model, false); boost::filesystem::remove(path_dst); if (! loaded) throw std::runtime_error(L("Import of the repaired 3mf file failed")); diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 79c4ecfa9..69301547c 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -165,7 +166,7 @@ size_t Http::priv::form_file_read_cb(char *buffer, size_t size, size_t nitems, v try { stream->read(buffer, size * nitems); - } catch (...) { + } catch (const std::exception &) { return CURL_READFUNC_ABORT; } diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index cafa69c55..09ca02071 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -69,7 +70,7 @@ bool OctoPrint::test(wxString &msg) const msg = wxString::Format(_(L("Mismatched type of print host: %s")), text ? *text : "OctoPrint"); } } - catch (...) { + catch (const std::exception &) { res = false; msg = "Could not parse server response"; } diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index bc600fcad..d55063c7b 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -35,6 +35,10 @@ using Slic3r::GUI::Config::Snapshot; using Slic3r::GUI::Config::SnapshotDB; + +// FIXME: Incompat bundle resolution doesn't deal with inherited user presets + + namespace Slic3r { @@ -101,6 +105,17 @@ struct Incompat , vendor(std::move(vendor)) {} + void remove() { + // Remove the bundle file + fs::remove(bundle); + + // Look for an installed index and remove it too if any + const fs::path installed_idx = bundle.replace_extension("idx"); + if (fs::exists(installed_idx)) { + fs::remove(installed_idx); + } + } + friend std::ostream& operator<<(std::ostream& os , const Incompat &self) { os << "Incompat(" << self.bundle.string() << ')'; return os; @@ -113,25 +128,12 @@ struct Updates std::vector updates; }; -static Semver get_slic3r_version() -{ - auto res = Semver::parse(SLIC3R_VERSION); - - if (! res) { - const char *error = "Could not parse Slic3r version string: " SLIC3R_VERSION; - BOOST_LOG_TRIVIAL(error) << error; - throw std::runtime_error(error); - } - - return *res; -} wxDEFINE_EVENT(EVT_SLIC3R_VERSION_ONLINE, wxCommandEvent); struct PresetUpdater::priv { - const Semver ver_slic3r; std::vector index_db; bool enabled_version_check; @@ -159,8 +161,7 @@ struct PresetUpdater::priv }; PresetUpdater::priv::priv() - : ver_slic3r(get_slic3r_version()) - , cache_path(fs::path(Slic3r::data_dir()) / "cache") + : cache_path(fs::path(Slic3r::data_dir()) / "cache") , rsrc_path(fs::path(resources_dir()) / "profiles") , vendor_path(fs::path(Slic3r::data_dir()) / "vendor") , cancel(false) @@ -383,25 +384,6 @@ Updates PresetUpdater::priv::get_config_updates() const continue; } - // Load 'installed' idx, if any. - // 'Installed' indices are kept alongside the bundle in the `vendor` subdir - // for bookkeeping to remember a cancelled update and not offer it again. - if (fs::exists(bundle_path_idx)) { - Index existing_idx; - try { - existing_idx.load(bundle_path_idx); - - const auto existing_recommended = existing_idx.recommended(); - if (existing_recommended != existing_idx.end() && recommended->config_version == existing_recommended->config_version) { - // The user has already seen (and presumably rejected) this update - BOOST_LOG_TRIVIAL(info) << boost::format("Downloaded index for `%1%` is the same as installed one, not offering an update.") % idx.vendor(); - continue; - } - } catch (const std::exception & /* err */) { - BOOST_LOG_TRIVIAL(error) << boost::format("Could nto load installed index %1%") % bundle_path_idx; - } - } - const auto ver_current = idx.find(vp.config_version); const bool ver_current_found = ver_current != idx.end(); @@ -424,6 +406,25 @@ Updates PresetUpdater::priv::get_config_updates() const } else if (recommended->config_version > vp.config_version) { // Config bundle update situation + // Load 'installed' idx, if any. + // 'Installed' indices are kept alongside the bundle in the `vendor` subdir + // for bookkeeping to remember a cancelled update and not offer it again. + if (fs::exists(bundle_path_idx)) { + Index existing_idx; + try { + existing_idx.load(bundle_path_idx); + + const auto existing_recommended = existing_idx.recommended(); + if (existing_recommended != existing_idx.end() && recommended->config_version == existing_recommended->config_version) { + // The user has already seen (and presumably rejected) this update + BOOST_LOG_TRIVIAL(info) << boost::format("Downloaded index for `%1%` is the same as installed one, not offering an update.") % idx.vendor(); + continue; + } + } catch (const std::exception &err) { + BOOST_LOG_TRIVIAL(error) << boost::format("Could not load installed index at `%1%`: %2%") % bundle_path_idx % err.what(); + } + } + // Check if the update is already present in a snapshot const auto recommended_snap = SnapshotDB::singleton().snapshot_with_vendor_preset(vp.name, recommended->config_version); if (recommended_snap != SnapshotDB::singleton().end()) { @@ -485,12 +486,11 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons BOOST_LOG_TRIVIAL(info) << boost::format("Deleting %1% incompatible bundles") % updates.incompats.size(); - for (const auto &incompat : updates.incompats) { + for (auto &incompat : updates.incompats) { BOOST_LOG_TRIVIAL(info) << '\t' << incompat; - fs::remove(incompat.bundle); + incompat.remove(); } - } - else if (updates.updates.size() > 0) { + } else if (updates.updates.size() > 0) { if (snapshot) { BOOST_LOG_TRIVIAL(info) << "Taking a snapshot..."; SnapshotDB::singleton().take_snapshot(*GUI::wxGetApp().app_config, Snapshot::SNAPSHOT_UPGRADE); @@ -584,8 +584,8 @@ void PresetUpdater::slic3r_update_notify() if (ver_online) { // Only display the notification if the version available online is newer AND if we haven't seen it before - if (*ver_online > p->ver_slic3r && (! ver_online_seen || *ver_online_seen < *ver_online)) { - GUI::MsgUpdateSlic3r notification(p->ver_slic3r, *ver_online); + if (*ver_online > Slic3r::SEMVER && (! ver_online_seen || *ver_online_seen < *ver_online)) { + GUI::MsgUpdateSlic3r notification(Slic3r::SEMVER, *ver_online); notification.ShowModal(); if (notification.disable_version_check()) { app_config->set("version_check", "0"); @@ -628,11 +628,17 @@ PresetUpdater::UpdateResult PresetUpdater::config_update() const const auto res = dlg.ShowModal(); if (res == wxID_REPLACE) { BOOST_LOG_TRIVIAL(info) << "User wants to re-configure..."; + + // This effectively removes the incompatible bundles: + // (snapshot is taken beforehand) p->perform_updates(std::move(updates)); + GUI::ConfigWizard wizard(nullptr, GUI::ConfigWizard::RR_DATA_INCOMPAT); + if (! wizard.run(GUI::wxGetApp().preset_bundle, this)) { return R_INCOMPAT_EXIT; } + GUI::wxGetApp().load_current_presets(); return R_INCOMPAT_CONFIGURED; } else { diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index e9e39e695..ab52b2344 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -170,8 +170,6 @@ void PrintHostJobQueue::priv::bg_thread_main() } } catch (const std::exception &e) { emit_error(e.what()); - } catch (...) { - emit_error("Unknown exception"); } // Cleanup leftover files, if any diff --git a/src/slic3r/Utils/Serial.cpp b/src/slic3r/Utils/Serial.cpp index cd2a01cbf..594464692 100644 --- a/src/slic3r/Utils/Serial.cpp +++ b/src/slic3r/Utils/Serial.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -71,13 +72,10 @@ void parse_hardware_id(const std::string &hardware_id, SerialPortInfo &spi) std::regex pattern("USB\\\\.*VID_([[:xdigit:]]+)&PID_([[:xdigit:]]+).*"); std::smatch matches; if (std::regex_match(hardware_id, matches, pattern)) { - try { - vid = std::stoul(matches[1].str(), 0, 16); - pid = std::stoul(matches[2].str(), 0, 16); - spi.id_vendor = vid; - spi.id_product = pid; - } - catch (...) {} + vid = std::stoul(matches[1].str(), 0, 16); + pid = std::stoul(matches[2].str(), 0, 16); + spi.id_vendor = vid; + spi.id_product = pid; } } #endif @@ -353,6 +351,8 @@ void Serial::set_baud_rate(unsigned baud_rate) } } + +/* void Serial::set_DTR(bool on) { auto handle = native_handle(); @@ -495,6 +495,7 @@ std::string Serial::printer_format_line(const std::string &line, unsigned line_n return (boost::format("N%1% %2%*%3%\n") % line_num_str % line % checksum).str(); } +*/ } // namespace Utils diff --git a/src/slic3r/Utils/Serial.hpp b/src/slic3r/Utils/Serial.hpp index 67d64b4ec..8bad75b31 100644 --- a/src/slic3r/Utils/Serial.hpp +++ b/src/slic3r/Utils/Serial.hpp @@ -46,6 +46,17 @@ public: ~Serial(); void set_baud_rate(unsigned baud_rate); + + // The Serial implementation is currently in disarray and therefore commented out. + // The boost implementation seems to have several problems, such as lack of support + // for custom baud rates, few weird implementation bugs and a history of API breakages. + // It's questionable whether it solves more problems than causes. Probably not. + // TODO: Custom implementation not based on asio. + // + // As of now, this class is only kept for the purpose of rebooting AVR109, + // see FirmwareDialog::priv::avr109_reboot() + +/* void set_DTR(bool on); // Resets the line number both internally as well as with the firmware using M110 @@ -68,7 +79,7 @@ public: // Same as above, but with internally-managed line number size_t printer_write_line(const std::string &line); - + // Toggles DTR to reset the printer void printer_reset(); @@ -76,6 +87,7 @@ public: static std::string printer_format_line(const std::string &line, unsigned line_num); private: unsigned m_line_num = 0; +*/ }; diff --git a/src/slic3r/Utils/Time.cpp b/src/slic3r/Utils/Time.cpp index f38c4b407..db1aa31f6 100644 --- a/src/slic3r/Utils/Time.cpp +++ b/src/slic3r/Utils/Time.cpp @@ -21,7 +21,11 @@ time_t parse_time_ISO8601Z(const std::string &sdate) tms.tm_hour = h; // 0-23 tms.tm_min = m; // 0-59 tms.tm_sec = s; // 0-61 (0-60 in C++11) - return mktime(&tms); +#ifdef WIN32 + return _mkgmtime(&tms); +#else /* WIN32 */ + return timegm(&tms); +#endif /* WIN32 */ } std::string format_time_ISO8601Z(time_t time) @@ -47,6 +51,7 @@ std::string format_local_date_time(time_t time) { struct tm tms; #ifdef WIN32 + // Converts a time_t time value to a tm structure, and corrects for the local time zone. localtime_s(&tms, &time); #else localtime_r(&time, &tms); @@ -60,6 +65,7 @@ time_t get_current_time_utc() { #ifdef WIN32 SYSTEMTIME st; + // Retrieves the current system date and time. The system time is expressed in Coordinated Universal Time (UTC). ::GetSystemTime(&st); std::tm tm; tm.tm_sec = st.wSecond; @@ -69,10 +75,10 @@ time_t get_current_time_utc() tm.tm_mon = st.wMonth - 1; tm.tm_year = st.wYear - 1900; tm.tm_isdst = -1; - return mktime(&tm); + return _mkgmtime(&tm); #else - const time_t current_local = time(nullptr); - return mktime(gmtime(¤t_local)); + // time() returns the time as the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). + return time(nullptr); #endif } diff --git a/src/slic3r/Utils/Time.hpp b/src/slic3r/Utils/Time.hpp index 7b670bd3e..6a1aefa18 100644 --- a/src/slic3r/Utils/Time.hpp +++ b/src/slic3r/Utils/Time.hpp @@ -2,7 +2,7 @@ #define slic3r_Utils_Time_hpp_ #include -#include +#include namespace Slic3r { namespace Utils { diff --git a/src/slic3r/Utils/UndoRedo.hpp b/src/slic3r/Utils/UndoRedo.hpp index 558449003..2901eaceb 100644 --- a/src/slic3r/Utils/UndoRedo.hpp +++ b/src/slic3r/Utils/UndoRedo.hpp @@ -45,6 +45,7 @@ struct SnapshotData SELECTED_SETTINGS_ON_SIDEBAR = 2, SELECTED_LAYERROOT_ON_SIDEBAR = 4, SELECTED_LAYER_ON_SIDEBAR = 8, + RECALCULATE_SLA_SUPPORTS = 16 }; }; diff --git a/version.inc b/version.inc index bbbb0e650..e9a3e9448 100644 --- a/version.inc +++ b/version.inc @@ -3,7 +3,7 @@ set(SLIC3R_APP_NAME "Slic3r++") set(SLIC3R_APP_KEY "Slic3r++") -set(SLIC3R_VERSION "2.0.0-1") +set(SLIC3R_VERSION "1.43.0-1") set(SLIC3R_BUILD_ID "slic3r++_${SLIC3R_VERSION}+UNKNOWN") -set(SLIC3R_RC_VERSION "2,0,0,0") -set(SLIC3R_RC_VERSION_DOTS "2.0.0.0") +set(SLIC3R_RC_VERSION "1,43,0,0") +set(SLIC3R_RC_VERSION_DOTS "1.43.0.0") diff --git a/xs/t/03_point.t b/xs/t/03_point.t index cb71f68f5..c950998fb 100644 --- a/xs/t/03_point.t +++ b/xs/t/03_point.t @@ -44,7 +44,7 @@ ok !$point->coincides_with($point2), 'coincides_with'; { my $line = Slic3r::Line->new([50,50], [125,-25]); - is +Slic3r::Point->new(100,0)->distance_to_line($line), 0, 'distance_to_line()'; + cmp_ok(abs(Slic3r::Point->new(100,0)->distance_to_line($line)), '<=', 4e-15, 'distance_to_line()'); } {