diff --git a/CMakeLists.txt b/CMakeLists.txt index 633ab3f19..a41229987 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ -project(PrusaSlicer) cmake_minimum_required(VERSION 3.2) +project(PrusaSlicer) include("version.inc") include(GNUInstallDirs) diff --git a/deps/blosc-mods.patch b/deps/blosc-mods.patch index 9a91b4974..9b1b9cb27 100644 --- a/deps/blosc-mods.patch +++ b/deps/blosc-mods.patch @@ -1,8 +1,9 @@ -From 5669891dfaaa4c814f3ec667ca6bf4e693aea978 Mon Sep 17 00:00:00 2001 +From 7cf6c014a36f1712efbdbe9bc52d2d4922b54673 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 30 Oct 2019 12:54:52 +0100 Subject: [PATCH] Blosc 1.17 fixes and cmake config script +Signed-off-by: tamasmeszaros --- CMakeLists.txt | 105 +++++++++++++++++----------------- blosc/CMakeLists.txt | 118 +++++++++------------------------------ diff --git a/deps/deps-linux.cmake b/deps/deps-linux.cmake index f5571d470..209cc3fd4 100644 --- a/deps/deps-linux.cmake +++ b/deps/deps-linux.cmake @@ -26,8 +26,8 @@ ExternalProject_Add(dep_boost ExternalProject_Add(dep_libopenssl EXCLUDE_FROM_ALL 1 - URL "https://github.com/openssl/openssl/archive/OpenSSL_1_1_0g.tar.gz" - URL_HASH SHA256=8e9516b8635bb9113c51a7b5b27f9027692a56b104e75b709e588c3ffd6a0422 + URL "https://github.com/openssl/openssl/archive/OpenSSL_1_1_0l.tar.gz" + URL_HASH SHA256=e2acf0cf58d9bff2b42f2dc0aee79340c8ffe2c5e45d3ca4533dd5d4f5775b1d BUILD_IN_SOURCE 1 CONFIGURE_COMMAND ./config "--prefix=${DESTDIR}/usr/local" diff --git a/deps/deps-unix-common.cmake b/deps/deps-unix-common.cmake index 74582f601..7491aafe1 100644 --- a/deps/deps-unix-common.cmake +++ b/deps/deps-unix-common.cmake @@ -55,14 +55,14 @@ find_package(Git REQUIRED) ExternalProject_Add(dep_qhull EXCLUDE_FROM_ALL 1 - URL "https://github.com/qhull/qhull/archive/v7.3.2.tar.gz" - URL_HASH SHA256=619c8a954880d545194bc03359404ef36a1abd2dde03678089459757fd790cb0 + #URL "https://github.com/qhull/qhull/archive/v7.3.2.tar.gz" + #URL_HASH SHA256=619c8a954880d545194bc03359404ef36a1abd2dde03678089459757fd790cb0 + GIT_REPOSITORY https://github.com/qhull/qhull.git + GIT_TAG 7afedcc73666e46a9f1d74632412ebecf53b1b30 # v7.3.2 plus the mac build patch CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local ${DEP_CMAKE_OPTS} - UPDATE_COMMAND "" - PATCH_COMMAND patch -p1 < ${CMAKE_CURRENT_SOURCE_DIR}/qhull-mods.patch ) ExternalProject_Add(dep_blosc @@ -80,8 +80,8 @@ ExternalProject_Add(dep_blosc -DBUILD_TESTS=OFF -DBUILD_BENCHMARKS=OFF -DPREFER_EXTERNAL_ZLIB=ON - UPDATE_COMMAND "" - PATCH_COMMAND ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/blosc-mods.patch + PATCH_COMMAND ${GIT_EXECUTABLE} reset --hard && git clean -df && + ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/blosc-mods.patch ) ExternalProject_Add(dep_openexr @@ -96,7 +96,6 @@ ExternalProject_Add(dep_openexr -DPYILMBASE_ENABLE:BOOL=OFF -DOPENEXR_VIEWERS_ENABLE:BOOL=OFF -DOPENEXR_BUILD_UTILS:BOOL=OFF - UPDATE_COMMAND "" ) ExternalProject_Add(dep_openvdb @@ -116,6 +115,6 @@ ExternalProject_Add(dep_openvdb -DOPENVDB_CORE_STATIC=ON -DTBB_STATIC=ON -DOPENVDB_BUILD_VDB_PRINT=ON - UPDATE_COMMAND "" - PATCH_COMMAND ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/openvdb-mods.patch + PATCH_COMMAND PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && + ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/openvdb-mods.patch ) \ No newline at end of file diff --git a/deps/deps-windows.cmake b/deps/deps-windows.cmake index 4aae07d4a..603f24931 100644 --- a/deps/deps-windows.cmake +++ b/deps/deps-windows.cmake @@ -218,15 +218,16 @@ find_package(Git REQUIRED) ExternalProject_Add(dep_qhull EXCLUDE_FROM_ALL 1 - URL "https://github.com/qhull/qhull/archive/v7.3.2.tar.gz" - URL_HASH SHA256=619c8a954880d545194bc03359404ef36a1abd2dde03678089459757fd790cb0 + #URL "https://github.com/qhull/qhull/archive/v7.3.2.tar.gz" + #URL_HASH SHA256=619c8a954880d545194bc03359404ef36a1abd2dde03678089459757fd790cb0 + GIT_REPOSITORY https://github.com/qhull/qhull.git + GIT_TAG 7afedcc73666e46a9f1d74632412ebecf53b1b30 # v7.3.2 plus the mac build patch CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_DEBUG_POSTFIX=d - UPDATE_COMMAND "" BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj INSTALL_COMMAND "" ) @@ -287,8 +288,8 @@ ExternalProject_Add(dep_blosc -DPREFER_EXTERNAL_ZLIB=ON -DBLOSC_IS_SUBPROJECT:BOOL=ON -DBLOSC_INSTALL:BOOL=ON - UPDATE_COMMAND "" - PATCH_COMMAND ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/blosc-mods.patch + PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && + ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/blosc-mods.patch BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj INSTALL_COMMAND "" ) @@ -310,7 +311,6 @@ ExternalProject_Add(dep_openexr -DPYILMBASE_ENABLE:BOOL=OFF -DOPENEXR_VIEWERS_ENABLE:BOOL=OFF -DOPENEXR_BUILD_UTILS:BOOL=OFF - UPDATE_COMMAND "" BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj INSTALL_COMMAND "" ) @@ -323,7 +323,7 @@ ExternalProject_Add(dep_openvdb #URL_HASH SHA256=dc337399dce8e1c9f21f20e97b1ce7e4933cb0a63bb3b8b734d8fcc464aa0c48 GIT_REPOSITORY https://github.com/AcademySoftwareFoundation/openvdb.git GIT_TAG aebaf8d95be5e57fd33949281ec357db4a576c2e #v6.2.1 - DEPENDS dep_blosc dep_openexr #dep_tbb dep_boost + DEPENDS dep_blosc dep_openexr dep_tbb dep_boost CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}" CMAKE_ARGS @@ -339,8 +339,8 @@ ExternalProject_Add(dep_openvdb -DTBB_STATIC=ON -DOPENVDB_BUILD_VDB_PRINT=ON BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj - UPDATE_COMMAND "" - PATCH_COMMAND ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/openvdb-mods.patch + PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && + ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/openvdb-mods.patch INSTALL_COMMAND "" ) diff --git a/deps/openvdb-mods.patch b/deps/openvdb-mods.patch index 60687b8d1..023cb5308 100644 --- a/deps/openvdb-mods.patch +++ b/deps/openvdb-mods.patch @@ -1,8 +1,9 @@ -From e48f4a835fe7cb391f9f90945472bd367fb4c4f1 Mon Sep 17 00:00:00 2001 +From dbe038fce8a15ddc9a5c83ec5156d7bc9e178015 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 16 Oct 2019 17:42:50 +0200 Subject: [PATCH] Build fixes for PrusaSlicer integration +Signed-off-by: tamasmeszaros --- CMakeLists.txt | 3 - cmake/FindBlosc.cmake | 218 --------------- diff --git a/resources/icons/bed/mini.svg b/resources/icons/bed/mini.svg index 1b9476ef8..93c3437bd 100644 --- a/resources/icons/bed/mini.svg +++ b/resources/icons/bed/mini.svg @@ -1,109 +1,70 @@ - - bed_texture_denser - - - - - - - - - - + + MINI_bed_texture + + + + + + + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/localization/pt_br/PrusaSlicer.mo b/resources/localization/pt_br/PrusaSlicer.mo new file mode 100644 index 000000000..a2f3e9789 Binary files /dev/null and b/resources/localization/pt_br/PrusaSlicer.mo differ diff --git a/resources/localization/pt_br/PrusaSlicer_pt_br.po b/resources/localization/pt_br/PrusaSlicer_pt_br.po new file mode 100644 index 000000000..e54f17ec3 --- /dev/null +++ b/resources/localization/pt_br/PrusaSlicer_pt_br.po @@ -0,0 +1,9386 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-09-09 16:39+0200\n" +"PO-Revision-Date: 2019-11-18 16:39-0300\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Poedit 2.2.4\n" +"Last-Translator: \n" +"Language: pt_BR\n" + +#: src/slic3r/GUI/AboutDialog.cpp:39 src/slic3r/GUI/AboutDialog.cpp:291 +msgid "Portions copyright" +msgstr "Direitos autorais das partes" + +#: src/slic3r/GUI/AboutDialog.cpp:127 src/slic3r/GUI/AboutDialog.cpp:256 +msgid "Copyright" +msgstr "Direitos autorais" + +#. TRN "Slic3r _is licensed under the_ License" +#: src/slic3r/GUI/AboutDialog.cpp:129 +msgid "" +"License agreements of all following programs (libraries) are part of " +"application license agreement" +msgstr "" +"Os contratos de licença de todos os seguintes programas (bibliotecas) são " +"parte do contrato de licença de aplicativo" + +#: src/slic3r/GUI/AboutDialog.cpp:199 +#, c-format +msgid "About %s" +msgstr "Sobre %s" + +#: src/slic3r/GUI/AboutDialog.cpp:231 src/slic3r/GUI/MainFrame.cpp:62 +msgid "Version" +msgstr "Versão" + +#. TRN "Slic3r _is licensed under the_ License" +#: src/slic3r/GUI/AboutDialog.cpp:258 +msgid "is licensed under the" +msgstr "está licenciado sobre o(a)" + +#: src/slic3r/GUI/AboutDialog.cpp:259 +msgid "GNU Affero General Public License, version 3" +msgstr "Licensa GNU Affero General Public, versão 3" + +#: src/slic3r/GUI/AboutDialog.cpp:260 +msgid "" +"PrusaSlicer is based on Slic3r by Alessandro Ranellucci and the RepRap " +"community." +msgstr "" +"PrusaSlicer é baseado no Slic3r criado por Alessandro Ranellucci e a " +"comunidade RepRap." + +#: src/slic3r/GUI/AboutDialog.cpp:261 +msgid "" +"Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, " +"Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Vojtech Bubnik and " +"numerous others." +msgstr "" +"Contribuições por Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, " +"Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Vojtech Bubnik e " +"outros." + +#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:92 +msgid "" +"Copying of the temporary G-code to the output G-code failed. Maybe the SD " +"card is write locked?" +msgstr "" +"A cópia do G-código provisório G-código falhou na saída. Talvez o cartão SD " +"está bloqueado para escrita?" + +#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:93 +#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:415 +msgid "Running post-processing scripts" +msgstr "Aplicando scripts de pós-processamento" + +#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:95 +msgid "G-code file exported to %1%" +msgstr "Arquivo G-code exportado para %1%" + +#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:99 +#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:117 +msgid "Slicing complete" +msgstr "Fatiamento completo" + +#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:113 +msgid "Masked SLA file exported to %1%" +msgstr "Arquivo SLA mascarado exportado para %1%" + +#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:155 +#, c-format +msgid "" +"%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." +msgstr "" +"%s encontrou um erro. Provavelmente foi causado por ficar sem memória. Se " +"você tem certeza que você tem RAM suficiente em seu sistema, isso também " +"pode ser um bug e nós estaríamos contentes se você relatou." + +#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:417 +msgid "Copying of the temporary G-code to the output G-code failed" +msgstr "A cópia do G-código provisório G-código falhou na saída" + +#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:426 +msgid "Scheduling upload to `%1%`. See Window -> Print Host Upload Queue" +msgstr "Agendando upload para ` %1%` . Veja a aba -> Print Host Upload Queue" + +#: src/slic3r/GUI/BedShapeDialog.cpp:65 +msgid "Shape" +msgstr "Forma" + +#: src/slic3r/GUI/BedShapeDialog.cpp:72 +msgid "Rectangular" +msgstr "Retangular" + +#: src/slic3r/GUI/BedShapeDialog.cpp:76 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:393 src/slic3r/GUI/Plater.cpp:145 +#: src/slic3r/GUI/Tab.cpp:2524 +msgid "Size" +msgstr "Tamanho" + +#: src/slic3r/GUI/BedShapeDialog.cpp:77 +msgid "Size in X and Y of the rectangular plate." +msgstr "Tamanho no X e Y na mesa retangular." + +#: src/slic3r/GUI/BedShapeDialog.cpp:83 +msgid "Origin" +msgstr "Origem" + +#: src/slic3r/GUI/BedShapeDialog.cpp:84 +msgid "" +"Distance of the 0,0 G-code coordinate from the front left corner of the " +"rectangle." +msgstr "" +"Distância do ponto 0,0 da coordenada do G-code do canto esquerdo do " +"retângulo." + +#: src/slic3r/GUI/BedShapeDialog.cpp:88 +msgid "Circular" +msgstr "Circular" + +#: src/slic3r/GUI/BedShapeDialog.cpp:91 src/slic3r/GUI/ConfigWizard.cpp:123 +#: src/slic3r/GUI/ConfigWizard.cpp:576 src/slic3r/GUI/ConfigWizard.cpp:590 +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:135 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:390 +#: src/slic3r/GUI/WipeTowerDialog.cpp:84 src/slic3r/GUI/wxExtensions.cpp:509 +#: 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:2510 src/libslic3r/PrintConfig.cpp:2519 +#: src/libslic3r/PrintConfig.cpp:2528 src/libslic3r/PrintConfig.cpp:2538 +#: src/libslic3r/PrintConfig.cpp:2582 src/libslic3r/PrintConfig.cpp:2592 +#: src/libslic3r/PrintConfig.cpp:2604 src/libslic3r/PrintConfig.cpp:2624 +#: src/libslic3r/PrintConfig.cpp:2634 src/libslic3r/PrintConfig.cpp:2644 +#: src/libslic3r/PrintConfig.cpp:2662 src/libslic3r/PrintConfig.cpp:2677 +#: src/libslic3r/PrintConfig.cpp:2691 src/libslic3r/PrintConfig.cpp:2704 +#: src/libslic3r/PrintConfig.cpp:2742 src/libslic3r/PrintConfig.cpp:2752 +#: src/libslic3r/PrintConfig.cpp:2761 src/libslic3r/PrintConfig.cpp:2771 +msgid "mm" +msgstr "mm" + +#: src/slic3r/GUI/BedShapeDialog.cpp:92 src/libslic3r/PrintConfig.cpp:692 +msgid "Diameter" +msgstr "Diâmetro" + +#: 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 "" +"Diâmetro da mesa de impressão. Se assume que a origem (0,0) seja localizado " +"no centro." + +#: src/slic3r/GUI/BedShapeDialog.cpp:97 src/slic3r/GUI/GUI_Preview.cpp:247 +#: src/libslic3r/GCode/PreviewData.cpp:159 +msgid "Custom" +msgstr "Customizado" + +#: src/slic3r/GUI/BedShapeDialog.cpp:101 +msgid "Load shape from STL..." +msgstr "Carregar forma do STL..." + +#: src/slic3r/GUI/BedShapeDialog.cpp:154 +msgid "Settings" +msgstr "config." + +#: src/slic3r/GUI/BedShapeDialog.cpp:171 +msgid "Texture" +msgstr "Textura" + +#: src/slic3r/GUI/BedShapeDialog.cpp:181 src/slic3r/GUI/BedShapeDialog.cpp:249 +msgid "Load..." +msgstr "Carregar..." + +#: src/slic3r/GUI/BedShapeDialog.cpp:189 src/slic3r/GUI/BedShapeDialog.cpp:257 +#: src/slic3r/GUI/Tab.cpp:3286 +msgid "Remove" +msgstr "Remover" + +#: src/slic3r/GUI/BedShapeDialog.cpp:239 +msgid "Model" +msgstr "Modelo" + +#: src/slic3r/GUI/BedShapeDialog.cpp:464 +msgid "Choose an STL file to import bed shape from:" +msgstr "Escolha um arquivo STL para importar o formato da mesa:" + +#: src/slic3r/GUI/BedShapeDialog.cpp:471 src/slic3r/GUI/BedShapeDialog.cpp:520 +#: src/slic3r/GUI/BedShapeDialog.cpp:543 +msgid "Invalid file format." +msgstr "Formato de arquivo inválido." + +#: src/slic3r/GUI/BedShapeDialog.cpp:482 +msgid "Error! Invalid model" +msgstr "Erro! Modelo inválido" + +#: src/slic3r/GUI/BedShapeDialog.cpp:490 +msgid "The selected file contains no geometry." +msgstr "O arquivo selecionado não contém geometria." + +#: src/slic3r/GUI/BedShapeDialog.cpp:494 +msgid "" +"The selected file contains several disjoint areas. This is not supported." +msgstr "O arquivo selecionado contém áreas não juntas. Isso não é suportado." + +#: src/slic3r/GUI/BedShapeDialog.cpp:509 +msgid "Choose a file to import bed texture from (PNG/SVG):" +msgstr "Escolher um arquivo para importar a textura da mesa (PNG/SVG):" + +#: src/slic3r/GUI/BedShapeDialog.cpp:532 +msgid "Choose an STL file to import bed model from:" +msgstr "Escolha um arquivo STL para importar o modelo da mesa:" + +#: src/slic3r/GUI/BedShapeDialog.hpp:59 src/slic3r/GUI/ConfigWizard.cpp:535 +msgid "Bed Shape" +msgstr "Formato da mesa" + +#: src/slic3r/GUI/BonjourDialog.cpp:55 +msgid "Network lookup" +msgstr "Pesquisa de rede" + +#: src/slic3r/GUI/BonjourDialog.cpp:72 +msgid "Address" +msgstr "Endereço" + +#: src/slic3r/GUI/BonjourDialog.cpp:73 +msgid "Hostname" +msgstr "Nome do Host" + +#: src/slic3r/GUI/BonjourDialog.cpp:74 +msgid "Service name" +msgstr "Nome de serviços" + +#: src/slic3r/GUI/BonjourDialog.cpp:76 +msgid "OctoPrint version" +msgstr "Versão do OctoPrint" + +#: src/slic3r/GUI/BonjourDialog.cpp:218 +msgid "Searching for devices" +msgstr "Procurando por dispositivos" + +#: src/slic3r/GUI/BonjourDialog.cpp:225 +msgid "Finished" +msgstr "Finalizado" + +#: src/slic3r/GUI/ButtonsDescription.cpp:16 +msgid "Buttons And Text Colors Description" +msgstr "Descrição dos botões e cores de texto" + +#: src/slic3r/GUI/ButtonsDescription.cpp:36 +msgid "Value is the same as the system value" +msgstr "O valor é o mesmo que o valor do sistema" + +#: src/slic3r/GUI/ButtonsDescription.cpp:53 +msgid "" +"Value was changed and is not equal to the system value or the last saved " +"preset" +msgstr "" +"O valor foi mudado e não é igual ao valor do sistema ou da última config. " +"salva" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:18 +msgid "Upgrade" +msgstr "Atualização" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:20 +msgid "Downgrade" +msgstr "Desatualização" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:22 +msgid "Before roll back" +msgstr "Antes de reverter" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:24 +msgid "User" +msgstr "Usuário" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:27 +msgid "Unknown" +msgstr "Desconhecido" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:39 +msgid "Active" +msgstr "Ativar" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:45 +msgid "slic3r version" +msgstr "versão do slic3r" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:46 src/slic3r/GUI/Preset.cpp:1311 +msgid "print" +msgstr "impressão" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:47 +msgid "filaments" +msgstr "filamentos" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:48 src/slic3r/GUI/Preset.cpp:1315 +msgid "printer" +msgstr "impressora" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:52 src/slic3r/GUI/Tab.cpp:961 +msgid "vendor" +msgstr "fornecedor" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:52 +msgid "version" +msgstr "versão" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:53 +msgid "min slic3r version" +msgstr "versão mínima do slic3r" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:55 +msgid "max slic3r version" +msgstr "versão máxima do slic3r" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:58 +msgid "model" +msgstr "modelo" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:58 +msgid "variants" +msgstr "variantes" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:70 +#, c-format +msgid "Incompatible with this %s" +msgstr "Incompatível com isso %s" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:73 +msgid "Activate" +msgstr "Ativar" + +#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:99 +msgid "Configuration Snapshots" +msgstr "config. das versões" + +#: src/slic3r/GUI/ConfigWizard.cpp:123 +msgid "nozzle" +msgstr "bico de impressão" + +#: src/slic3r/GUI/ConfigWizard.cpp:127 +msgid "Alternate nozzles:" +msgstr "Alternar bicos:" + +#: src/slic3r/GUI/ConfigWizard.cpp:193 +msgid "All standard" +msgstr "Todos padrão" + +#: src/slic3r/GUI/ConfigWizard.cpp:194 src/slic3r/GUI/Tab.cpp:3336 +msgid "All" +msgstr "Todos" + +#: src/slic3r/GUI/ConfigWizard.cpp:195 src/slic3r/GUI/Plater.cpp:469 +#: src/slic3r/GUI/Plater.cpp:607 src/libslic3r/GCode/PreviewData.cpp:146 +msgid "None" +msgstr "Nenhum" + +#: src/slic3r/GUI/ConfigWizard.cpp:301 +#, c-format +msgid "Welcome to the %s Configuration Assistant" +msgstr "Bem-vindo ao %s Assistente de config." + +#: src/slic3r/GUI/ConfigWizard.cpp:303 +#, c-format +msgid "Welcome to the %s Configuration Wizard" +msgstr "Bem-vindo ao %s Assistente de config." + +#: src/slic3r/GUI/ConfigWizard.cpp:305 +msgid "Welcome" +msgstr "Bem-vindo(a)" + +#: src/slic3r/GUI/ConfigWizard.cpp:309 src/slic3r/GUI/GUI_App.cpp:793 +#, c-format +msgid "Run %s" +msgstr "Executar %s" + +#: src/slic3r/GUI/ConfigWizard.cpp:311 +#, c-format +msgid "" +"Hello, welcome to %s! This %s helps you with the initial configuration; just " +"a few settings and you will be ready to print." +msgstr "" +"Olá, bem-vindo ao %s! Isso %s te ajuda com a config. inicial; com apenas " +"algumas config. e você estará pronto para imprimir." + +#: src/slic3r/GUI/ConfigWizard.cpp:316 +msgid "" +"Remove user profiles - install from scratch (a snapshot will be taken " +"beforehand)" +msgstr "" +"Remover perfis de usuário - instalar do zero (uma snapshot será salva antes)" + +#: src/slic3r/GUI/ConfigWizard.cpp:347 +#, c-format +msgid "%s Family" +msgstr "%s Família" + +#: src/slic3r/GUI/ConfigWizard.cpp:384 +msgid "Custom Printer Setup" +msgstr "config. da impressora customizada" + +#: src/slic3r/GUI/ConfigWizard.cpp:384 +msgid "Custom Printer" +msgstr "Impressora customizada" + +#: src/slic3r/GUI/ConfigWizard.cpp:386 +msgid "Define a custom printer profile" +msgstr "Definir uma config. para a impressora customizada" + +#: src/slic3r/GUI/ConfigWizard.cpp:388 +msgid "Custom profile name:" +msgstr "Nome customizado da config.:" + +#: src/slic3r/GUI/ConfigWizard.cpp:412 +msgid "Automatic updates" +msgstr "Atualizações automáticas" + +#: src/slic3r/GUI/ConfigWizard.cpp:412 +msgid "Updates" +msgstr "Atualizações" + +#: src/slic3r/GUI/ConfigWizard.cpp:420 src/slic3r/GUI/Preferences.cpp:69 +msgid "Check for application updates" +msgstr "Verificar atualizações nas aplicações" + +#: src/slic3r/GUI/ConfigWizard.cpp:424 +#, c-format +msgid "" +"If enabled, %s checks for new application versions online. When a new " +"version becomes available, a notification is displayed at the next " +"application startup (never during program usage). This is only a " +"notification mechanisms, no automatic installation is done." +msgstr "" +"Se ativada, %s verifica se há novas versões do aplicativo online. Quando uma " +"nova versão se torna disponível, uma notificação é exibida na próxima " +"inicialização do aplicativo (nunca durante o uso do programa). Este é apenas " +"um mecanismos de notificação, nenhuma instalação automática é feita." + +#: src/slic3r/GUI/ConfigWizard.cpp:430 src/slic3r/GUI/Preferences.cpp:77 +msgid "Update built-in Presets automatically" +msgstr "Atualizar predefinições incorporadas automaticamente" + +#: src/slic3r/GUI/ConfigWizard.cpp:434 +#, c-format +msgid "" +"If enabled, %s downloads updates of built-in system presets in the " +"background.These updates are downloaded into a separate temporary location." +"When a new preset version becomes available it is offered at application " +"startup." +msgstr "" +"Se ativada, %s baixa atualizações de predefinições de sistema incorporadas " +"em segundo plano. Essas atualizações são baixadas em um local temporário " +"separado. Quando uma nova versão predefinida se torna disponível, ela é " +"oferecida na inicialização do aplicativo." + +#: src/slic3r/GUI/ConfigWizard.cpp:437 +msgid "" +"Updates are never applied without user's consent and never overwrite user's " +"customized settings." +msgstr "" +"Atualizações nunca são aplicadas sem a permissão do usuário e nunca sobre " +"escrevem as config. do usuário." + +#: src/slic3r/GUI/ConfigWizard.cpp:442 +msgid "" +"Additionally a backup snapshot of the whole configuration is created before " +"an update is applied." +msgstr "" +"Além disso, uma captura de backup de toda a config. é criado antes que uma " +"atualização seja aplicada." + +#: src/slic3r/GUI/ConfigWizard.cpp:449 +msgid "Other Vendors" +msgstr "Outros fornecedores" + +#: src/slic3r/GUI/ConfigWizard.cpp:451 +#, c-format +msgid "Pick another vendor supported by %s:" +msgstr "Escolha outro fornecedor suportado por %s:" + +#: src/slic3r/GUI/ConfigWizard.cpp:497 +msgid "Firmware Type" +msgstr "Tipo de Firmware" + +#: src/slic3r/GUI/ConfigWizard.cpp:497 src/slic3r/GUI/Tab.cpp:2149 +msgid "Firmware" +msgstr "Firmware" + +#: src/slic3r/GUI/ConfigWizard.cpp:501 +msgid "Choose the type of firmware used by your printer." +msgstr "Escolha o tipo de firmware utilizado na sua impressora." + +#: src/slic3r/GUI/ConfigWizard.cpp:535 +msgid "Bed Shape and Size" +msgstr "Forma e tamanho da mesa" + +#: src/slic3r/GUI/ConfigWizard.cpp:538 +msgid "Set the shape of your printer's bed." +msgstr "Insira o formato da mesa de impressão." + +#: src/slic3r/GUI/ConfigWizard.cpp:558 +msgid "Filament and Nozzle Diameters" +msgstr "Diâmetro do bico e do filamento" + +#: src/slic3r/GUI/ConfigWizard.cpp:558 +msgid "Print Diameters" +msgstr "Diâmetros de impressão" + +#: src/slic3r/GUI/ConfigWizard.cpp:572 +msgid "Enter the diameter of your printer's hot end nozzle." +msgstr "Insira o diâmetro do bico de impressão." + +#: src/slic3r/GUI/ConfigWizard.cpp:575 +msgid "Nozzle Diameter:" +msgstr "Diâmetro do bico:" + +#: src/slic3r/GUI/ConfigWizard.cpp:585 +msgid "Enter the diameter of your filament." +msgstr "Coloque o diâmetro do seu filamento." + +#: src/slic3r/GUI/ConfigWizard.cpp:586 +msgid "" +"Good precision is required, so use a caliper and do multiple measurements " +"along the filament, then compute the average." +msgstr "" +"É necessário uma boa precisão, utilize um paquímetro e realize várias " +"medições ao longo do filamento, faça uma média." + +#: src/slic3r/GUI/ConfigWizard.cpp:589 +msgid "Filament Diameter:" +msgstr "Diâmetro do filamento:" + +#: src/slic3r/GUI/ConfigWizard.cpp:623 +msgid "Extruder and Bed Temperatures" +msgstr "Temperaturas da mesa e da extrusora" + +#: src/slic3r/GUI/ConfigWizard.cpp:623 +msgid "Temperatures" +msgstr "Temperaturas" + +#: src/slic3r/GUI/ConfigWizard.cpp:639 +msgid "Enter the temperature needed for extruding your filament." +msgstr "Coloque a temperatura necessária para extrusar seu filamento." + +#: src/slic3r/GUI/ConfigWizard.cpp:640 +msgid "A rule of thumb is 160 to 230 °C for PLA, and 215 to 250 °C for ABS." +msgstr "A regra de ouro é 160 à 230°C para PLA, e 215 à 250°C para ABS." + +#: src/slic3r/GUI/ConfigWizard.cpp:643 +msgid "Extrusion Temperature:" +msgstr "Temperatura de extrusão:" + +#: src/slic3r/GUI/ConfigWizard.cpp:644 src/slic3r/GUI/ConfigWizard.cpp:658 +msgid "°C" +msgstr "°C" + +#: src/slic3r/GUI/ConfigWizard.cpp:653 +msgid "" +"Enter the bed temperature needed for getting your filament to stick to your " +"heated bed." +msgstr "" +"Coloque a temperatura da mesa necessária para fazer com que seu filamento " +"grude na mesa." + +#: src/slic3r/GUI/ConfigWizard.cpp:654 +msgid "" +"A rule of thumb is 60 °C for PLA and 110 °C for ABS. Leave zero if you have " +"no heated bed." +msgstr "" +"A regra de ouro é 60°C para PLA, e 110°C para ABS. Deixe em zero se não há " +"mesa aquecida." + +#: src/slic3r/GUI/ConfigWizard.cpp:657 +msgid "Bed Temperature:" +msgstr "Temperatura da mesa:" + +#: src/slic3r/GUI/ConfigWizard.cpp:1138 +msgid "Select all standard printers" +msgstr "Selecione todas as impressoras padrão" + +#: src/slic3r/GUI/ConfigWizard.cpp:1141 +msgid "< &Back" +msgstr "< &Voltar" + +#: src/slic3r/GUI/ConfigWizard.cpp:1142 +msgid "&Next >" +msgstr "&Próximo >" + +#: src/slic3r/GUI/ConfigWizard.cpp:1143 +msgid "&Finish" +msgstr "&Final" + +#: src/slic3r/GUI/ConfigWizard.cpp:1144 src/slic3r/GUI/FirmwareDialog.cpp:151 +#: src/slic3r/GUI/ProgressStatusBar.cpp:27 +msgid "Cancel" +msgstr "Cancelar" + +#: src/slic3r/GUI/ConfigWizard.cpp:1158 +msgid "Prusa FFF Technology Printers" +msgstr "Impressoras de tecnologia Prusa FFF" + +#: src/slic3r/GUI/ConfigWizard.cpp:1161 +msgid "Prusa MSLA Technology Printers" +msgstr "Impressoras de tecnologia Prusa MSLA" + +#: src/slic3r/GUI/ConfigWizard.cpp:1230 +msgid "Configuration Assistant" +msgstr "Assistente de config." + +#: src/slic3r/GUI/ConfigWizard.cpp:1231 +msgid "Configuration &Assistant" +msgstr "Assistente &de config." + +#: src/slic3r/GUI/ConfigWizard.cpp:1233 +msgid "Configuration Wizard" +msgstr "Assistente de config." + +#: src/slic3r/GUI/ConfigWizard.cpp:1234 +msgid "Configuration &Wizard" +msgstr "Assistente &de config." + +#: src/slic3r/GUI/Field.cpp:125 +msgid "default value" +msgstr "valor padrão" + +#: src/slic3r/GUI/Field.cpp:128 +msgid "parameter name" +msgstr "nome do parâmetro" + +#: src/slic3r/GUI/Field.cpp:139 src/slic3r/GUI/OptionsGroup.cpp:569 +msgid "N/A" +msgstr "N/D" + +#: src/slic3r/GUI/Field.cpp:158 +#, c-format +msgid "%s doesn't support percentage" +msgstr "%s não suporta porcentagem" + +#: src/slic3r/GUI/Field.cpp:174 src/slic3r/GUI/Field.cpp:197 +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:337 +msgid "Invalid numeric input." +msgstr "Entrada numérica não válida." + +#: src/slic3r/GUI/Field.cpp:179 +msgid "Input value is out of range" +msgstr "Valor de entrada está fora do limite" + +#: src/slic3r/GUI/Field.cpp:206 +#, c-format +msgid "" +"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 "" +"Você quer dizer %s%% ao invés de %s %s?\n" +"Selecione SIM se quiser trocar esse valor para %s%%, \n" +"ou NÃO se você tem certeza que %s %s é o valor correto." + +#: src/slic3r/GUI/Field.cpp:209 +msgid "Parameter validation" +msgstr "Validação do parâmetro" + +#: src/slic3r/GUI/FirmwareDialog.cpp:150 +msgid "Flash!" +msgstr "Atualizando!" + +#: src/slic3r/GUI/FirmwareDialog.cpp:152 +msgid "Flashing in progress. Please do not disconnect the printer!" +msgstr "Atualização em progresso. Favor não desconectar sua impressora!" + +#: src/slic3r/GUI/FirmwareDialog.cpp:199 +msgid "Flashing failed" +msgstr "A atualização falhou" + +#: src/slic3r/GUI/FirmwareDialog.cpp:282 +msgid "Flashing succeeded!" +msgstr "Atualizado com sucesso!" + +#: src/slic3r/GUI/FirmwareDialog.cpp:283 +msgid "Flashing failed. Please see the avrdude log below." +msgstr "A atualização falhou. Favor verificar os registros abaixo." + +#: src/slic3r/GUI/FirmwareDialog.cpp:284 +msgid "Flashing cancelled." +msgstr "Atualização cancelada." + +#: src/slic3r/GUI/FirmwareDialog.cpp:332 +#, c-format +msgid "" +"This firmware hex file does not match the printer model.\n" +"The hex file is intended for: %s\n" +"Printer reported: %s\n" +"\n" +"Do you want to continue and flash this hex file anyway?\n" +"Please only continue if you are sure this is the right thing to do." +msgstr "" +"O arquivo hex do firmware não é o mesmo utilizado no modelo da impressora.\n" +"O arquivo hex desejado para: %s\n" +"Impressora relatada: %s\n" +"\n" +"Você gostaria de continuar e atualizar o arquivo hex mesmo assim?\n" +"Favor continuar se tiver certeza que é a coisa certa a se fazer." + +#: src/slic3r/GUI/FirmwareDialog.cpp:419 src/slic3r/GUI/FirmwareDialog.cpp:454 +#, c-format +msgid "" +"Multiple %s devices found. Please only connect one at a time for flashing." +msgstr "" +"Múltiplos %s dispositivos encontrados. Favor conectar um de cada vez para " +"atualização." + +#: src/slic3r/GUI/FirmwareDialog.cpp:436 +#, c-format +msgid "" +"The %s device was not found.\n" +"If the device is connected, please press the Reset button next to the USB " +"connector ..." +msgstr "" +"O %s dispositivo não foi encontrado.\n" +"Se o dispositivo está conectado, favor utilizar o botão de Reset perto do " +"conector USB ..." + +#: src/slic3r/GUI/FirmwareDialog.cpp:548 +#, c-format +msgid "The %s device could not have been found" +msgstr "O %s dispositivo não pode ser encontrado" + +#: src/slic3r/GUI/FirmwareDialog.cpp:645 +#, c-format +msgid "Error accessing port at %s: %s" +msgstr "Erro ao acessa a porta em %s: %s" + +#: src/slic3r/GUI/FirmwareDialog.cpp:647 +#, c-format +msgid "Error: %s" +msgstr "Erro: %s" + +#: src/slic3r/GUI/FirmwareDialog.cpp:777 +msgid "Firmware flasher" +msgstr "Atualizador de Firmware" + +#: src/slic3r/GUI/FirmwareDialog.cpp:802 +msgid "Firmware image:" +msgstr "Imagem do Firmware:" + +#: src/slic3r/GUI/FirmwareDialog.cpp:805 src/slic3r/GUI/Tab.cpp:1870 +#: src/slic3r/GUI/Tab.cpp:1926 +msgid "Browse" +msgstr "Procurar" + +#: src/slic3r/GUI/FirmwareDialog.cpp:807 +msgid "Serial port:" +msgstr "Porte Serial:" + +#: src/slic3r/GUI/FirmwareDialog.cpp:809 +msgid "Autodetected" +msgstr "Auto detectado" + +#: src/slic3r/GUI/FirmwareDialog.cpp:810 +msgid "Rescan" +msgstr "Reescanear" + +#: src/slic3r/GUI/FirmwareDialog.cpp:817 +msgid "Progress:" +msgstr "Progresso:" + +#: src/slic3r/GUI/FirmwareDialog.cpp:820 +msgid "Status:" +msgstr "Status:" + +#: src/slic3r/GUI/FirmwareDialog.cpp:821 +msgid "Ready" +msgstr "Pronto" + +#: src/slic3r/GUI/FirmwareDialog.cpp:841 +msgid "Advanced: Output log" +msgstr "Avançado: log de Saída" + +#: src/slic3r/GUI/FirmwareDialog.cpp:852 +#: src/slic3r/GUI/PrintHostDialogs.cpp:161 +msgid "Close" +msgstr "Fechar" + +#: 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 "" +"Você tem certeza que gostaria de cancelar a atualização de Firmware? \n" +"Isso poderia deixar a sua impressora inutilizável!" + +#: src/slic3r/GUI/FirmwareDialog.cpp:904 +msgid "Confirmation" +msgstr "Confirmação" + +#: src/slic3r/GUI/FirmwareDialog.cpp:907 +msgid "Cancelling..." +msgstr "Cancelando..." + +#: src/slic3r/GUI/GLCanvas3D.cpp:534 +msgid "Layers heights" +msgstr "Altura de camada" + +#: src/slic3r/GUI/GLCanvas3D.cpp:631 +msgid "An object outside the print area was detected" +msgstr "Um objeto foi detectado fora da área de impressão" + +#: src/slic3r/GUI/GLCanvas3D.cpp:632 +msgid "A toolpath outside the print area was detected" +msgstr "Há movimentos fora da área de impressão" + +#: src/slic3r/GUI/GLCanvas3D.cpp:633 +msgid "SLA supports outside the print area were detected" +msgstr "Suportes de SLA foram detectados fora da área de impressão" + +#: src/slic3r/GUI/GLCanvas3D.cpp:634 +msgid "Some objects are not visible when editing supports" +msgstr "Alguns objetos não são visíveis quando editando suportes" + +#: src/slic3r/GUI/GLCanvas3D.cpp:636 +msgid "" +"An object outside the print area was detected\n" +"Resolve the current problem to continue slicing" +msgstr "" +"Um objeto foi encontrado fora da área de impressão\n" +"Resolva o problema atual para continuar o fatiamento" + +#: src/slic3r/GUI/GLCanvas3D.cpp:1733 +msgid "Mirror Object" +msgstr "Espelhar objeto" + +#: src/slic3r/GUI/GLCanvas3D.cpp:2970 +msgid "Move Object" +msgstr "Mover objeto" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3506 +msgid "Undo History" +msgstr "Desfazer histórico" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3506 +msgid "Redo History" +msgstr "Refazer histórico" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3524 +#, c-format +msgid "Undo %1$d Action" +msgid_plural "Undo %1$d Actions" +msgstr[0] "Desfazer ação de %1$d" +msgstr[1] "Desfazer ações de %1$d" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3524 +#, c-format +msgid "Redo %1$d Action" +msgid_plural "Redo %1$d Actions" +msgstr[0] "Refazer ação de %1$d" +msgstr[1] "Refazer ações de %1$d" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3571 +msgid "Add..." +msgstr "Adicionar..." + +#: src/slic3r/GUI/GLCanvas3D.cpp:3579 src/slic3r/GUI/GUI_ObjectList.cpp:1501 +#: src/slic3r/GUI/Plater.cpp:3520 src/slic3r/GUI/Plater.cpp:3539 +#: src/slic3r/GUI/Tab.cpp:3286 +msgid "Delete" +msgstr "Deletar" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3588 src/slic3r/GUI/Plater.cpp:4172 +msgid "Delete all" +msgstr "Deletar todos" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3597 src/slic3r/GUI/KBShortcutsDialog.cpp:137 +#: src/slic3r/GUI/Plater.cpp:2681 +msgid "Arrange" +msgstr "Arranjar" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3597 src/slic3r/GUI/KBShortcutsDialog.cpp:138 +msgid "Arrange selection" +msgstr "Arranjar seleção" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3609 +msgid "Copy" +msgstr "Copiar" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3618 +msgid "Paste" +msgstr "Colar" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3630 src/slic3r/GUI/Plater.cpp:3400 +#: src/slic3r/GUI/Plater.cpp:3412 src/slic3r/GUI/Plater.cpp:3526 +msgid "Add instance" +msgstr "Adicionar instância" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3641 src/slic3r/GUI/Plater.cpp:3528 +msgid "Remove instance" +msgstr "Remover instância" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3654 +msgid "Split to objects" +msgstr "Dividir em objetos" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3664 src/slic3r/GUI/GUI_ObjectList.cpp:1340 +msgid "Split to parts" +msgstr "Dividir em partes" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3677 src/slic3r/GUI/GUI_ObjectList.cpp:2203 +msgid "Height ranges" +msgstr "Limites de altura" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3728 src/slic3r/GUI/MainFrame.cpp:570 +msgid "Undo" +msgstr "Desfazer" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3728 src/slic3r/GUI/GLCanvas3D.cpp:3761 +msgid "Click right mouse button to open History" +msgstr "Clique no botão direito para abrir o Histórico" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3745 +msgid "Next Undo action: %1%" +msgstr "Próxima ação de desfazer: %1%" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3761 src/slic3r/GUI/MainFrame.cpp:573 +msgid "Redo" +msgstr "Refazer" + +#: src/slic3r/GUI/GLCanvas3D.cpp:3777 +msgid "Next Redo action: %1%" +msgstr "Próxima ação de refazer: %1%" + +#: src/slic3r/GUI/GLCanvas3D.cpp:5555 +msgid "Selection-Add from rectangle" +msgstr "Seleção-Adicionar do retângulo" + +#: src/slic3r/GUI/GLCanvas3D.cpp:5574 +msgid "Selection-Remove from rectangle" +msgstr "Seleção-remover do retângulo" + +#: src/slic3r/GUI/GLCanvas3DManager.cpp:273 +#, c-format +msgid "" +"PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n" +"while OpenGL version %s, render %s, vendor %s was detected." +msgstr "" +"PrusaSlicer requer drivers capazes de executar OpenGL 2.0, \n" +"enquanto a versão do OpenGL %s, renderização %s, fornecedor %s foi detectada." + +#: src/slic3r/GUI/GLCanvas3DManager.cpp:276 +msgid "You may need to update your graphics card driver." +msgstr "Você pode ter que atualizar os drivers da sua placa de vídeo." + +#: src/slic3r/GUI/GLCanvas3DManager.cpp:279 +msgid "" +"As a workaround, you may run PrusaSlicer with a software rendered 3D " +"graphics by running prusa-slicer.exe with the --sw_renderer parameter." +msgstr "" +"Como solução alternativa, você pode executar o PrusaSlicer com um software " +"renderizando gráficos 3D por executar Prusa-slicer.exe com o parâmetro--" +"sw_renderer." + +#: src/slic3r/GUI/GLCanvas3DManager.cpp:281 +msgid "Unsupported OpenGL version" +msgstr "Versão do OpenGL não suportada" + +#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:40 +#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:145 src/libslic3r/PrintConfig.cpp:3212 +msgid "Cut" +msgstr "Cortar" + +#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:150 +msgid "Keep upper part" +msgstr "Manter parte superior" + +#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:151 +msgid "Keep lower part" +msgstr "Manter parte inferior" + +#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:152 +msgid "Rotate lower part upwards" +msgstr "Rotacione as partes inferiores para cima" + +#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:155 +msgid "Perform cut" +msgstr "Aplicar o corte" + +#: src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp:45 +msgid "Place on face" +msgstr "Colocar em uma face" + +#: src/slic3r/GUI/Gizmos/GLGizmoMove.cpp:48 +msgid "Move" +msgstr "Mover" + +#: src/slic3r/GUI/Gizmos/GLGizmoMove.cpp:177 +msgid "Position (mm)" +msgstr "Posição (mm)" + +#: src/slic3r/GUI/Gizmos/GLGizmoMove.cpp:177 +msgid "Displacement (mm)" +msgstr "Deslocamento (mm)" + +#: src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp:449 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:477 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:496 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:514 +#: src/libslic3r/PrintConfig.cpp:3261 +msgid "Rotate" +msgstr "Rotacionar" + +#: src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp:482 +msgid "Rotation (deg)" +msgstr "Rotacionar (graus)" + +#: src/slic3r/GUI/Gizmos/GLGizmoScale.cpp:47 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:392 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:497 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:515 +#: src/libslic3r/PrintConfig.cpp:3276 +msgid "Scale" +msgstr "Escala" + +#: src/slic3r/GUI/Gizmos/GLGizmoScale.cpp:292 +msgid "Scale (%)" +msgstr "Escala (%)" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:44 +msgid "Head diameter" +msgstr "Diâmetro da cabeça" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:45 +msgid "Lock supports under new islands" +msgstr "Travar suportes debaixo de novas ilhas" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:46 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1449 +msgid "Remove selected points" +msgstr "Remover pontos selecionados" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:47 +msgid "Remove all points" +msgstr "Remover todos os pontos" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:48 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1452 +msgid "Apply changes" +msgstr "Aplicar mudanças" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:49 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1453 +msgid "Discard changes" +msgstr "Descartar mudanças" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:50 +msgid "Minimal points distance" +msgstr "Distância mínima entre pontos" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:51 +#: src/libslic3r/PrintConfig.cpp:2651 +msgid "Support points density" +msgstr "Densidade dos pontos de suporte" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:52 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1455 +msgid "Auto-generate points" +msgstr "Pontos gerados automaticamente" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:53 +msgid "Manual editing" +msgstr "Edição manual" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:54 +msgid "Clipping of view" +msgstr "Recorte de vista" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:55 +msgid "Reset direction" +msgstr "Restabelecer direção" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:531 +msgid "Add support point" +msgstr "Adicionar ponto de suporte" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:719 +msgid "Delete support point" +msgstr "Deletar ponto de suporte" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:920 +msgid "Change point head diameter" +msgstr "Mudar o diâmetro do ponto da cabeça" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:986 +msgid "Support parameter change" +msgstr "Mudança de parâmetro de suporte" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1094 +msgid "SLA Support Points" +msgstr "Pontos de suporte SLA" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1115 +msgid "SLA gizmo turned on" +msgstr "Gizmo de SLA ligado" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1137 +msgid "Do you want to save your manually edited support points?" +msgstr "Você deseja salvar os pontos manualmente editados?" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1138 +msgid "Save changes?" +msgstr "Salvar mudanças?" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1150 +msgid "SLA gizmo turned off" +msgstr "Gizmo de SLA desligado" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1187 +msgid "Move support point" +msgstr "Mover pontos de suporte" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1286 +msgid "Support points edit" +msgstr "Edição de pontos de suporte" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1355 +msgid "" +"Autogeneration will erase all manually edited points.\n" +"\n" +"Are you sure you want to do it?\n" +msgstr "" +"Gerar automaticamente irá apagar todos os pontos manualmente editados. Tem " +"certeza que quer gerar?\n" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1357 src/slic3r/GUI/GUI.cpp:289 +#: src/slic3r/GUI/WipeTowerDialog.cpp:44 src/slic3r/GUI/WipeTowerDialog.cpp:328 +msgid "Warning" +msgstr "Aviso" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1360 +msgid "Autogenerate support points" +msgstr "Pontos de suporte gerados automaticamente" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1412 +msgid "SLA gizmo keyboard shortcuts" +msgstr "Atalhos no teclado para gizmo SLA" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1423 +msgid "Note: some shortcuts work in (non)editing mode only." +msgstr "Nota: alguns atalhos funcionam somente em modos que não editam." + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1441 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1444 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1445 +msgid "Left click" +msgstr "Clique esquerdo" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1441 +msgid "Add point" +msgstr "Adicionar ponto" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1442 +msgid "Right click" +msgstr "Clique direito" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1442 +msgid "Remove point" +msgstr "Remover ponto" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1443 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1446 +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1447 +msgid "Drag" +msgstr "Arrastar" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1443 +msgid "Move point" +msgstr "Mover ponto" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1444 +msgid "Add point to selection" +msgstr "Adicionar ponto à seleção" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1445 +msgid "Remove point from selection" +msgstr "Remover ponto da seleção" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1446 +msgid "Select by rectangle" +msgstr "Selecionar por retângulo" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1447 +msgid "Deselect by rectangle" +msgstr "Desselecionar por retângulo" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1448 +msgid "Select all points" +msgstr "Selecionar todos os pontos" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1450 +msgid "Mouse wheel" +msgstr "Scroll do mouse" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1450 +msgid "Move clipping plane" +msgstr "Mover plano de recorte" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1451 +msgid "Reset clipping plane" +msgstr "Restabelecer plano de recorte" + +#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1454 +msgid "Switch to editing mode" +msgstr "Alterar para modo de edição" + +#: src/slic3r/GUI/Gizmos/GLGizmosManager.cpp:569 +msgid "Gizmo-Place on Face" +msgstr "Gizmo-Colocar em uma face" + +#: src/slic3r/GUI/Gizmos/GLGizmosManager.cpp:641 +msgid "Gizmo-Move" +msgstr "Gizmo-Mover" + +#: src/slic3r/GUI/Gizmos/GLGizmosManager.cpp:646 +msgid "Gizmo-Scale" +msgstr "Gizmo-Escala" + +#: src/slic3r/GUI/Gizmos/GLGizmosManager.cpp:651 +msgid "Gizmo-Rotate" +msgstr "Gizmo-Rotacionar" + +#: src/slic3r/GUI/GUI.cpp:141 src/slic3r/GUI/Tab.cpp:3145 +msgid "It's impossible to print multi-part object(s) with SLA technology." +msgstr "" +"É impossível imprimir objetos com múltiplas partes com a tecnologia SLA." + +#: src/slic3r/GUI/GUI.cpp:142 +msgid "Please check and fix your object list." +msgstr "Favor verificar e concertar sua lista de objetos." + +#: src/slic3r/GUI/GUI.cpp:143 src/slic3r/GUI/Plater.cpp:2246 +#: src/slic3r/GUI/Tab.cpp:3147 +msgid "Attention!" +msgstr "Atenção!" + +#: src/slic3r/GUI/GUI.cpp:283 +msgid "Notice" +msgstr "Aviso" + +#: src/slic3r/GUI/GUI_App.cpp:132 +#, c-format +msgid "" +"%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" +"\n" +"The application will now terminate." +msgstr "" +"%s encontrou um erro. Provavelmente foi causado por ficar sem memória. Se " +"você tem certeza que você tem RAM suficiente em seu sistema, isso também " +"pode ser um bug e nós estaríamos contentes se você relatou.\n" +"\n" +"O aplicativo será encerrado agora." + +#: src/slic3r/GUI/GUI_App.cpp:135 +msgid "Fatal error" +msgstr "Erro fatal" + +#: src/slic3r/GUI/GUI_App.cpp:442 +msgid "Changing of an application language" +msgstr "Alteração de um idioma do aplicativo" + +#: src/slic3r/GUI/GUI_App.cpp:450 src/slic3r/GUI/GUI_App.cpp:459 +msgid "Recreating" +msgstr "Recriando" + +#: src/slic3r/GUI/GUI_App.cpp:463 +msgid "Loading of current presets" +msgstr "Carregando presets" + +#: src/slic3r/GUI/GUI_App.cpp:471 +msgid "Loading of a mode view" +msgstr "Carregamento de um modelo de vista" + +#: src/slic3r/GUI/GUI_App.cpp:551 +msgid "Choose one file (3MF/AMF):" +msgstr "Escolha um arquivo (3MF/AMF):" + +#: src/slic3r/GUI/GUI_App.cpp:563 +msgid "Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):" +msgstr "Escolha um ou mais arquivos (STL/OBJ/AMF/3MF/PRUSA):" + +#: src/slic3r/GUI/GUI_App.cpp:625 +msgid "Select the language" +msgstr "Selecione a linguagem" + +#: src/slic3r/GUI/GUI_App.cpp:625 +msgid "Language" +msgstr "Linguagem" + +#: src/slic3r/GUI/GUI_App.cpp:796 +msgid "&Configuration Snapshots" +msgstr "&Captura das config." + +#: src/slic3r/GUI/GUI_App.cpp:796 +msgid "Inspect / activate configuration snapshots" +msgstr "Inspecionar / ativar capturas de config." + +#: src/slic3r/GUI/GUI_App.cpp:797 +msgid "Take Configuration &Snapshot" +msgstr "Capturar &config." + +#: src/slic3r/GUI/GUI_App.cpp:797 +msgid "Capture a configuration snapshot" +msgstr "Capturar uma config." + +#: src/slic3r/GUI/GUI_App.cpp:800 +msgid "&Preferences" +msgstr "&Preferências" + +#: src/slic3r/GUI/GUI_App.cpp:806 +msgid "Application preferences" +msgstr "Preferências de aplicação" + +#: src/slic3r/GUI/GUI_App.cpp:809 src/slic3r/GUI/wxExtensions.cpp:3043 +msgid "Simple" +msgstr "Simples" + +#: src/slic3r/GUI/GUI_App.cpp:809 +msgid "Simple View Mode" +msgstr "Modo simples de visualização" + +#: src/slic3r/GUI/GUI_App.cpp:810 src/slic3r/GUI/GUI_ObjectList.cpp:97 +#: src/slic3r/GUI/GUI_ObjectList.cpp:620 src/slic3r/GUI/Tab.cpp:1061 +#: src/slic3r/GUI/Tab.cpp:1076 src/slic3r/GUI/Tab.cpp:1174 +#: src/slic3r/GUI/Tab.cpp:1177 src/slic3r/GUI/Tab.cpp:1685 +#: src/slic3r/GUI/Tab.cpp:2169 src/slic3r/GUI/Tab.cpp:3785 +#: src/slic3r/GUI/wxExtensions.cpp:3044 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 "Avançado" + +#: src/slic3r/GUI/GUI_App.cpp:810 +msgid "Advanced View Mode" +msgstr "Modo avançado de visualização" + +#: src/slic3r/GUI/GUI_App.cpp:811 src/slic3r/GUI/wxExtensions.cpp:3045 +msgid "Expert" +msgstr "Especialista" + +#: src/slic3r/GUI/GUI_App.cpp:811 +msgid "Expert View Mode" +msgstr "Modo especialista de visualização" + +#: src/slic3r/GUI/GUI_App.cpp:816 +msgid "Mode" +msgstr "Modo" + +#: src/slic3r/GUI/GUI_App.cpp:816 +#, c-format +msgid "%s View Mode" +msgstr "%s Modo de visualização" + +#: src/slic3r/GUI/GUI_App.cpp:818 +msgid "Change Application &Language" +msgstr "Mudar &idioma" + +#: src/slic3r/GUI/GUI_App.cpp:820 +msgid "Flash printer &firmware" +msgstr "Atualizar firmware &da impressora" + +#: src/slic3r/GUI/GUI_App.cpp:820 +msgid "Upload a firmware image into an Arduino based printer" +msgstr "Atualizar o firmware para uma impressora baseada em Arduino" + +#: src/slic3r/GUI/GUI_App.cpp:832 +msgid "Taking configuration snapshot" +msgstr "Capturando a config." + +#: src/slic3r/GUI/GUI_App.cpp:832 +msgid "Snapshot name" +msgstr "Nome da captura" + +#: src/slic3r/GUI/GUI_App.cpp:875 +msgid "" +"Switching the language will trigger application restart.\n" +"You will lose content of the plater." +msgstr "" +"Alterar a linguagem fará com que o aplicativo reinicie.\n" +"Você irá perder conteúdo no prato." + +#: src/slic3r/GUI/GUI_App.cpp:877 +msgid "Do you want to proceed?" +msgstr "Você quer prosseguir?" + +#: src/slic3r/GUI/GUI_App.cpp:878 +msgid "Language selection" +msgstr "Seleção de linguagem" + +#: src/slic3r/GUI/GUI_App.cpp:901 +msgid "&Configuration" +msgstr "&Configuração" + +#: src/slic3r/GUI/GUI_App.cpp:923 +msgid "The presets on the following tabs were modified" +msgstr "Os presets seguintes foram modificados" + +#: src/slic3r/GUI/GUI_App.cpp:923 src/slic3r/GUI/Tab.cpp:3133 +msgid "Discard changes and continue anyway?" +msgstr "Descartar mudanças e continuar assim mesmo?" + +#: src/slic3r/GUI/GUI_App.cpp:926 +msgid "Unsaved Presets" +msgstr "config. não salvas" + +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:27 +msgid "Start at height" +msgstr "Começar na altura" + +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:27 +msgid "Stop at height" +msgstr "Parar na altura" + +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:27 src/slic3r/GUI/Tab.cpp:1033 +#: src/libslic3r/PrintConfig.cpp:66 +msgid "Layer height" +msgstr "Altura da camada" + +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:153 +msgid "Remove layer range" +msgstr "Remover limite da camada" + +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:162 +msgid "Add layer range" +msgstr "Adicionar limite da camada" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:34 src/slic3r/GUI/GUI_ObjectList.cpp:88 +#: src/slic3r/GUI/GUI_ObjectList.cpp:611 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 "Camadas e perímetros" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:35 src/slic3r/GUI/GUI_ObjectList.cpp:89 +#: src/slic3r/GUI/GUI_ObjectList.cpp:612 src/slic3r/GUI/Plater.cpp:497 +#: src/slic3r/GUI/Tab.cpp:1065 src/slic3r/GUI/Tab.cpp:1066 +#: 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 "Preenchimento" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:36 src/slic3r/GUI/GUI_ObjectList.cpp:90 +#: src/slic3r/GUI/GUI_ObjectList.cpp:613 src/slic3r/GUI/GUI_Preview.cpp:244 +#: src/slic3r/GUI/Tab.cpp:1094 src/slic3r/GUI/Tab.cpp:1095 +#: 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:156 +msgid "Support material" +msgstr "Material de suporte" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:39 src/slic3r/GUI/GUI_ObjectList.cpp:94 +#: src/slic3r/GUI/GUI_ObjectList.cpp:617 src/libslic3r/PrintConfig.cpp:2202 +#: src/libslic3r/PrintConfig.cpp:2210 +msgid "Wipe options" +msgstr "Opções de limpeza" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:45 +msgid "Pad and Support" +msgstr "Bloco e suporte" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:51 +msgid "Add part" +msgstr "Adicionar parte" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:52 +msgid "Add modifier" +msgstr "Adicionar modificador" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:53 +msgid "Add support enforcer" +msgstr "Adicionar reforço de suporte" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:54 +msgid "Add support blocker" +msgstr "Adicionar bloqueador de suporte" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:91 src/slic3r/GUI/GUI_ObjectList.cpp:614 +#: src/slic3r/GUI/GUI_Preview.cpp:223 src/slic3r/GUI/Tab.cpp:1119 +#: 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 "Velocidade" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:92 src/slic3r/GUI/GUI_ObjectList.cpp:615 +#: src/slic3r/GUI/Tab.cpp:1154 src/slic3r/GUI/Tab.cpp:2043 +#: 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 "Exrtrusoras" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:93 src/slic3r/GUI/GUI_ObjectList.cpp:616 +#: 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 "Espessura da extrusão" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:99 src/slic3r/GUI/GUI_ObjectList.cpp:622 +#: src/slic3r/GUI/Plater.cpp:465 src/slic3r/GUI/Tab.cpp:3737 +#: src/slic3r/GUI/Tab.cpp:3738 src/libslic3r/PrintConfig.cpp:2501 +#: src/libslic3r/PrintConfig.cpp:2508 src/libslic3r/PrintConfig.cpp:2517 +#: src/libslic3r/PrintConfig.cpp:2526 src/libslic3r/PrintConfig.cpp:2536 +#: src/libslic3r/PrintConfig.cpp:2562 src/libslic3r/PrintConfig.cpp:2569 +#: src/libslic3r/PrintConfig.cpp:2580 src/libslic3r/PrintConfig.cpp:2590 +#: src/libslic3r/PrintConfig.cpp:2599 src/libslic3r/PrintConfig.cpp:2612 +#: src/libslic3r/PrintConfig.cpp:2622 src/libslic3r/PrintConfig.cpp:2631 +#: src/libslic3r/PrintConfig.cpp:2641 src/libslic3r/PrintConfig.cpp:2652 +#: src/libslic3r/PrintConfig.cpp:2660 +msgid "Supports" +msgstr "Suportes" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:100 src/slic3r/GUI/GUI_ObjectList.cpp:623 +#: src/slic3r/GUI/Plater.cpp:603 src/slic3r/GUI/Tab.cpp:3769 +#: src/slic3r/GUI/Tab.cpp:3770 src/libslic3r/PrintConfig.cpp:2668 +#: src/libslic3r/PrintConfig.cpp:2675 src/libslic3r/PrintConfig.cpp:2689 +#: src/libslic3r/PrintConfig.cpp:2699 src/libslic3r/PrintConfig.cpp:2721 +#: src/libslic3r/PrintConfig.cpp:2732 src/libslic3r/PrintConfig.cpp:2739 +#: src/libslic3r/PrintConfig.cpp:2750 src/libslic3r/PrintConfig.cpp:2759 +#: src/libslic3r/PrintConfig.cpp:2768 +msgid "Pad" +msgstr "Bloco" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:260 +msgid "Name" +msgstr "Nome" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:271 src/slic3r/GUI/GUI_ObjectList.cpp:373 +msgid "Editing" +msgstr "Edição" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:318 +#, c-format +msgid "Auto-repaired (%d errors):\n" +msgstr "Auto reparando (%d erros):\n" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:325 +msgid "degenerate facets" +msgstr "facetas degeneradas" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:326 +msgid "edges fixed" +msgstr "arestas fixadas" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:327 +msgid "facets removed" +msgstr "facetas removidas" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:328 +msgid "facets added" +msgstr "facetas adicionadas" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:329 +msgid "facets reversed" +msgstr "facetas reversidas" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:330 +msgid "backwards edges" +msgstr "arestas viradas para trás" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:338 +msgid "Right button click the icon to fix STL through Netfabb" +msgstr "" +"Clique com o botão direito no ícone para arrumar STL através do Netfabb" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:375 +msgid "Right button click the icon to change the object settings" +msgstr "Clique com o botão direito no ícone para mudar as config. do objeto" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:377 +msgid "Click the icon to change the object settings" +msgstr "Clique no ícone para mudar as config. do objeto" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:381 +msgid "Right button click the icon to change the object printable property" +msgstr "" +"Clique com o botão direito no ícone para mudar a propriedade de impressão do " +"objeto" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:383 +msgid "Click the icon to change the object printable property" +msgstr "Clique no ícone para mudar a propriedade de impressão do objeto" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:428 src/slic3r/GUI/GUI_ObjectList.cpp:449 +#: src/slic3r/GUI/GUI_ObjectList.cpp:461 src/slic3r/GUI/GUI_ObjectList.cpp:3642 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3652 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3684 src/slic3r/GUI/wxExtensions.cpp:603 +#: src/slic3r/GUI/wxExtensions.cpp:660 src/slic3r/GUI/wxExtensions.cpp:685 +#: src/slic3r/GUI/wxExtensions.cpp:893 +msgid "default" +msgstr "padrão" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:433 src/slic3r/GUI/Tab.cpp:1649 +#: src/libslic3r/PrintConfig.cpp:470 +msgid "Extruder" +msgstr "Extrusora" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:546 +msgid "Rename Object" +msgstr "Renomear objeto" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:546 +msgid "Rename Sub-object" +msgstr "Renomear sub-objeto" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:987 src/slic3r/GUI/GUI_ObjectList.cpp:3464 +msgid "Instances to Separated Objects" +msgstr "Instâncias para separar objetos" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1005 +msgid "Volumes in Object reordered" +msgstr "Volume reorganizados no objeto" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1005 +msgid "Object reordered" +msgstr "Objeto reorganizado" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1060 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1376 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1382 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1623 +#, c-format +msgid "Quick Add Settings (%s)" +msgstr "Adicionar config. rapidamente (%s)" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1137 +msgid "Select showing settings" +msgstr "Selecionar config. mostradas" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1186 +msgid "Add Settings for Layers" +msgstr "Adicionar config. para camadas" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1187 +msgid "Add Settings for Sub-object" +msgstr "Adicionar config. para sub-objetos" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1188 +msgid "Add Settings for Object" +msgstr "Adicionar config. para objetos" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1249 +msgid "Add Settings Bundle for Height range" +msgstr "Adicionar pacote de config. para intervalo de altura" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1250 +msgid "Add Settings Bundle for Sub-object" +msgstr "Adicionar pacote de config. para subobjeto" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1251 +msgid "Add Settings Bundle for Object" +msgstr "Adicionar pacote de config. para objeto" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1290 +msgid "Load" +msgstr "Carregar" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1295 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1320 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1323 +msgid "Box" +msgstr "Caixa" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1295 +msgid "Cylinder" +msgstr "Cilindro" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1295 +msgid "Sphere" +msgstr "Esfera" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1295 +msgid "Slab" +msgstr "Placa" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1347 +msgid "Height range Modifier" +msgstr "Modificador de intervalo de altura" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1355 +msgid "Add settings" +msgstr "Adicionar config." + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1422 +msgid "Change type" +msgstr "Mudar o tipo" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1429 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1577 +msgid "Set as a Separated Object" +msgstr "Configurar como objeto separado" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1435 +msgid "Printable" +msgstr "Imprimível" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1442 +msgid "Rename" +msgstr "Renomear" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1453 +msgid "Fix through the Netfabb" +msgstr "Arrumar através do Netfabb" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1463 src/slic3r/GUI/Plater.cpp:3552 +msgid "Export as STL" +msgstr "Exportar como STL" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1470 +msgid "Change extruder" +msgstr "Mudar extrusora" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1489 src/libslic3r/PrintConfig.cpp:309 +msgid "Default" +msgstr "Padrão" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1495 +msgid "Select new extruder for the object/part" +msgstr "Selecionar nova extrusora para objeto/parte" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1507 +msgid "Scale to print volume" +msgstr "Escalar para volume de impressão" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1507 +msgid "Scale the selected object to fit the print volume" +msgstr "Escale o objeto selecionado para se adequar ao volume de impressão" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1577 +msgid "Set as a Separated Objects" +msgstr "Definir como objetos separados" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1652 +msgid "Load Part" +msgstr "Carregar parte" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1687 +msgid "Error!" +msgstr "Erro!" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1732 +msgid "Add Generic Subobject" +msgstr "Adicionar sub-objeto genérico" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1739 +msgid "Generic" +msgstr "Genérico" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1843 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1945 +msgid "Last instance of an object cannot be deleted." +msgstr "A última instância de um objeto não pode ser excluída." + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1855 +msgid "Delete Settings" +msgstr "Deletar config." + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1879 +msgid "Delete All Instances from Object" +msgstr "Excluir todas as instâncias do objeto" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1895 +msgid "Delete Height Range" +msgstr "Excluir limite de altura" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1926 +msgid "From Object List You can't delete the last solid part from object." +msgstr "" +"Na lista de objetos não é possível excluir a última parte sólida do objeto." + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1930 +msgid "Delete Subobject" +msgstr "Deletar sub-objeto" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1949 +msgid "Delete Instance" +msgstr "Deletar instância" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1973 src/slic3r/GUI/Plater.cpp:2838 +msgid "" +"The selected object couldn't be split because it contains only one part." +msgstr "O seguinte objeto não pode ser dividido pois contém uma parte." + +#: src/slic3r/GUI/GUI_ObjectList.cpp:1977 +msgid "Split to Parts" +msgstr "Dividir em partes" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2025 +msgid "Add Layers" +msgstr "Adicionar camadas" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2150 +msgid "Group manipulation" +msgstr "Manipulação de grupos" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2162 +msgid "Object manipulation" +msgstr "Manipulação de objetos" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2175 +msgid "Object Settings to modify" +msgstr "config. do objeto para modificar" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2179 +msgid "Part Settings to modify" +msgstr "config. da parte para modificar" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2184 +msgid "Layer range Settings to modify" +msgstr "config. de intervalo de camada para modificar" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2190 +msgid "Part manipulation" +msgstr "Manipulação da parte" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2196 +msgid "Instance manipulation" +msgstr "Manipulação da instância" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2203 +msgid "Settings for height range" +msgstr "config. para intervalo de altura" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2388 +msgid "Delete Selected Item" +msgstr "Excluir item selecionado" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2525 +msgid "Delete Selected" +msgstr "Excluir seleção" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2584 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2613 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2631 +msgid "Add Height Range" +msgstr "Adicionar intervalo de altura" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2690 +msgid "Edit Height Range" +msgstr "Editar intervalo de altura" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2974 +msgid "Selection-Remove from list" +msgstr "Seleção-Remover da lista" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:2982 +msgid "Selection-Add from list" +msgstr "Seleção-Adicionar da lista" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3100 +msgid "Object or Instance" +msgstr "Objeto ou instância" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3101 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3234 +msgid "Part" +msgstr "Parte" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3101 +msgid "Layer" +msgstr "Camada" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3103 +msgid "Unsupported selection" +msgstr "Seleção não suportada" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3104 +#, c-format +msgid "You started your selection with %s Item." +msgstr "Você iniciou sua seleção com o item de %s." + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3105 +#, c-format +msgid "In this mode you can select only other %s Items%s" +msgstr "Neste modo, você pode selecionar apenas outros %s itens%s" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3108 +msgid "of a current Object" +msgstr "de um objeto atual" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3113 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3188 src/slic3r/GUI/Plater.cpp:126 +msgid "Info" +msgstr "Informação" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3229 +msgid "You can't change a type of the last solid part of the object." +msgstr "Não é possível alterar um tipo da última parte sólida do objeto." + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3234 +msgid "Modifier" +msgstr "Modificador" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3234 +msgid "Support Enforcer" +msgstr "Reforçador de suporte" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3234 +msgid "Support Blocker" +msgstr "Bloqueador de suporte" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3236 +msgid "Type:" +msgstr "Tipo:" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3236 +msgid "Select type of part" +msgstr "Selecione o tipo de parte" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3241 +msgid "Change Part Type" +msgstr "Mudar o tipo da parte" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3486 +msgid "Enter new name" +msgstr "Insira o novo nome" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3486 +msgid "Renaming" +msgstr "Renomeando" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3502 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3608 src/slic3r/GUI/Tab.cpp:3618 +#: src/slic3r/GUI/Tab.cpp:3622 +msgid "The supplied name is not valid;" +msgstr "O nome inserido não é valido;" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3503 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3609 src/slic3r/GUI/Tab.cpp:3619 +msgid "the following characters are not allowed:" +msgstr "os seguintes caracteres não são permitidos:" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3632 +msgid "Set extruder for selected items" +msgstr "Definir extrusora para itens selecionados" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3633 +msgid "Select extruder number for selected objects and/or parts" +msgstr "Selecione o número da extrusora para objetos e/ou peças selecionados" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3646 +msgid "Select extruder number:" +msgstr "Selecione o número da extrusora:" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3647 +msgid "This extruder will be set for selected items" +msgstr "Esta extrusora será ajustada para artigos selecionados" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3759 src/slic3r/GUI/Selection.cpp:1473 +msgid "Set Printable" +msgstr "Definir como imprimível" + +#: src/slic3r/GUI/GUI_ObjectList.cpp:3759 src/slic3r/GUI/Selection.cpp:1473 +msgid "Set Unprintable" +msgstr "Definir não imprimível" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:62 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:105 +msgid "World coordinates" +msgstr "Coordenadas mundiais" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:63 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:106 +msgid "Local coordinates" +msgstr "Coordenadas locais" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:82 +msgid "Select coordinate space, in which the transformation will be performed." +msgstr "" +"Selecione o espaço de coordenadas, no qual a transformação será executada." + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:125 +msgid "Object Manipulation" +msgstr "Manipulação de objeto" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:178 +msgid "Object name" +msgstr "Nome do objeto" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:214 +#, c-format +msgid "Toggle %c axis mirroring" +msgstr "Ativar espelhamento do eixo %c" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:247 +msgid "Set Mirror" +msgstr "Definir espelhamento" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:287 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:292 +msgid "Reset scale" +msgstr "Restabelecer escala" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:305 +msgid "Reset rotation" +msgstr "Restabelecer rotação" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:330 +msgid "Reset Rotation" +msgstr "Restabelecer Rotação" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:342 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:357 +msgid "Drop to bed" +msgstr "Soltar na mesa" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:390 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:454 +msgid "Position" +msgstr "Posição" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:391 +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:455 +msgid "Rotation" +msgstr "Rotação" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:456 +msgid "Scale factors" +msgstr "Fatores de escala" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:513 +msgid "Translate" +msgstr "Tradução" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:565 +msgid "" +"You cannot use non-uniform scaling mode for multiple objects/parts selection" +msgstr "" +"Não é possível usar o modo de dimensionamento não uniforme para vários " +"objetos/seleção de peças" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:735 +msgid "Set Position" +msgstr "Definir posição" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:766 +msgid "Set Orientation" +msgstr "Definir orientação" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:831 +msgid "Set Scale" +msgstr "Definir escala" + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:915 +msgid "" +"The currently manipulated object is tilted (rotation angles are not " +"multiples of 90°).\n" +"Non-uniform scaling of tilted objects is only possible in the World " +"coordinate system,\n" +"once the rotation is embedded into the object coordinates." +msgstr "" +"O objeto atualmente manipulado é inclinado (os ângulos de rotação não são " +"múltiplos de 90 °).\n" +"O dimensionamento não uniforme de objetos inclinados só é possível no " +"sistema de coordenadas do mundo,\n" +"uma vez que a rotação é incorporada nas coordenadas do objeto." + +#: src/slic3r/GUI/GUI_ObjectManipulation.cpp:918 +msgid "" +"This operation is irreversible.\n" +"Do you want to proceed?" +msgstr "" +"Esta operação é irreversível.\n" +"Você quer prosseguir?" + +#: src/slic3r/GUI/GUI_ObjectSettings.cpp:59 +msgid "Additional Settings" +msgstr "config. Adicionais" + +#: src/slic3r/GUI/GUI_ObjectSettings.cpp:95 +msgid "Remove parameter" +msgstr "Remover parâmetro" + +#: src/slic3r/GUI/GUI_ObjectSettings.cpp:101 +#, c-format +msgid "Delete Option %s" +msgstr "Excluir opção %s" + +#: src/slic3r/GUI/GUI_ObjectSettings.cpp:146 +#, c-format +msgid "Change Option %s" +msgstr "Alterar opção %s" + +#: src/slic3r/GUI/GUI_Preview.cpp:217 +msgid "View" +msgstr "Vista" + +#: src/slic3r/GUI/GUI_Preview.cpp:220 src/slic3r/GUI/GUI_Preview.cpp:569 +#: src/libslic3r/GCode/PreviewData.cpp:378 +msgid "Feature type" +msgstr "Tipo de recurso" + +#: src/slic3r/GUI/GUI_Preview.cpp:221 src/libslic3r/PrintConfig.cpp:483 +msgid "Height" +msgstr "Altura" + +#: src/slic3r/GUI/GUI_Preview.cpp:222 src/libslic3r/PrintConfig.cpp:2188 +msgid "Width" +msgstr "Espessura" + +#: src/slic3r/GUI/GUI_Preview.cpp:224 +msgid "Volumetric flow rate" +msgstr "Taxa de fluxo volumétrico" + +#: src/slic3r/GUI/GUI_Preview.cpp:225 src/slic3r/GUI/GUI_Preview.cpp:333 +#: src/slic3r/GUI/GUI_Preview.cpp:515 src/slic3r/GUI/GUI_Preview.cpp:568 +#: src/slic3r/GUI/GUI_Preview.cpp:774 src/libslic3r/GCode/PreviewData.cpp:388 +msgid "Tool" +msgstr "Ferramenta" + +#: src/slic3r/GUI/GUI_Preview.cpp:226 src/slic3r/GUI/GUI_Preview.cpp:566 +#: src/libslic3r/GCode/PreviewData.cpp:390 +msgid "Color Print" +msgstr "Impressão colorida" + +#: src/slic3r/GUI/GUI_Preview.cpp:229 +msgid "Show" +msgstr "Mostrar" + +#: src/slic3r/GUI/GUI_Preview.cpp:232 src/slic3r/GUI/GUI_Preview.cpp:233 +msgid "Feature types" +msgstr "Tipos de características" + +#: src/slic3r/GUI/GUI_Preview.cpp:235 src/libslic3r/GCode/PreviewData.cpp:147 +msgid "Perimeter" +msgstr "Perímetro" + +#: src/slic3r/GUI/GUI_Preview.cpp:236 src/libslic3r/GCode/PreviewData.cpp:148 +msgid "External perimeter" +msgstr "Perímetro externo" + +#: src/slic3r/GUI/GUI_Preview.cpp:237 src/libslic3r/GCode/PreviewData.cpp:149 +msgid "Overhang perimeter" +msgstr "Perímetro de angulação" + +#: src/slic3r/GUI/GUI_Preview.cpp:238 src/libslic3r/GCode/PreviewData.cpp:150 +msgid "Internal infill" +msgstr "Preenchimento interno" + +#: src/slic3r/GUI/GUI_Preview.cpp:239 src/libslic3r/PrintConfig.cpp:1736 +#: src/libslic3r/PrintConfig.cpp:1746 src/libslic3r/GCode/PreviewData.cpp:151 +msgid "Solid infill" +msgstr "Preenchimento sólido" + +#: src/slic3r/GUI/GUI_Preview.cpp:240 src/libslic3r/PrintConfig.cpp:2068 +#: src/libslic3r/PrintConfig.cpp:2079 src/libslic3r/GCode/PreviewData.cpp:152 +msgid "Top solid infill" +msgstr "Preenchimento do sólido do topo" + +#: src/slic3r/GUI/GUI_Preview.cpp:241 src/libslic3r/GCode/PreviewData.cpp:153 +msgid "Bridge infill" +msgstr "Preenchimento de pontes" + +#: src/slic3r/GUI/GUI_Preview.cpp:242 src/libslic3r/PrintConfig.cpp:895 +#: src/libslic3r/GCode/PreviewData.cpp:154 +msgid "Gap fill" +msgstr "Preenchimento de vão" + +#: src/slic3r/GUI/GUI_Preview.cpp:243 src/slic3r/GUI/Tab.cpp:1085 +#: src/libslic3r/GCode/PreviewData.cpp:155 +msgid "Skirt" +msgstr "Saia" + +#: src/slic3r/GUI/GUI_Preview.cpp:245 src/libslic3r/PrintConfig.cpp:1954 +#: src/libslic3r/GCode/PreviewData.cpp:157 +msgid "Support material interface" +msgstr "Interface do material de suporte" + +#: src/slic3r/GUI/GUI_Preview.cpp:246 src/slic3r/GUI/Tab.cpp:1165 +#: src/libslic3r/GCode/PreviewData.cpp:158 +msgid "Wipe tower" +msgstr "Torre de limpeza" + +#: src/slic3r/GUI/GUI_Preview.cpp:251 src/libslic3r/PrintConfig.cpp:2102 +msgid "Travel" +msgstr "Viagem" + +#: src/slic3r/GUI/GUI_Preview.cpp:252 +msgid "Retractions" +msgstr "Retrações" + +#: src/slic3r/GUI/GUI_Preview.cpp:253 +msgid "Unretractions" +msgstr "Retorno da retração" + +#: src/slic3r/GUI/GUI_Preview.cpp:254 +msgid "Shells" +msgstr "Paredes" + +#: src/slic3r/GUI/GUI_Preview.cpp:255 +msgid "Legend" +msgstr "Legenda" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:14 src/slic3r/GUI/MainFrame.cpp:683 +msgid "Keyboard Shortcuts" +msgstr "Atalhos do teclado" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:107 +msgid "Open project STL/OBJ/AMF/3MF with config, delete bed" +msgstr "Abra o projeto STL/OBJ/AMF/3MF com config., excluir mesa" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:108 +msgid "Import STL/OBJ/AMF/3MF without config, keep bed" +msgstr "Importação STL/OBJ/AMF/3MF sem config., manter a mesa" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:109 +msgid "Load Config from .ini/amf/3mf/gcode" +msgstr "Carregar config. de um .ini/AMF/3mf/Gcode" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:110 src/slic3r/GUI/Plater.cpp:837 +#: src/slic3r/GUI/Plater.cpp:4822 src/libslic3r/PrintConfig.cpp:3163 +msgid "Export G-code" +msgstr "Exportar G-code" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:111 +msgid "Save project (3MF)" +msgstr "Salvar projeto (3MF)" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:112 +msgid "Load Config from .ini/amf/3mf/gcode and merge" +msgstr "Carregar config. de um. ini/AMF/3mf/Gcode e mesclar" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:113 +msgid "(Re)slice" +msgstr "(Re)fatiar" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:116 +msgid "Select Plater Tab" +msgstr "Selecione a guia de prato" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:118 +msgid "Select Print Settings Tab" +msgstr "Selecione a guia config. de impressão" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:119 +msgid "Select Filament Settings Tab" +msgstr "Selecione a guia config. de filamento" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:120 +msgid "Select Printer Settings Tab" +msgstr "Selecione a guia config. da impressora" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:121 +msgid "Switch to 3D" +msgstr "Mude para 3D" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:122 +msgid "Switch to Preview" +msgstr "Mudar para pré-visualização" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:123 src/slic3r/GUI/Preferences.cpp:10 +msgid "Preferences" +msgstr "Preferências" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:124 +#: src/slic3r/GUI/PrintHostDialogs.cpp:136 +msgid "Print host upload queue" +msgstr "Fila de carregamento do host de impressão" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:125 +msgid "Camera view" +msgstr "Vista da câmera" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:126 +msgid "Add Instance of the selected object" +msgstr "Adicionar instância do objeto selecionado" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:127 +msgid "Remove Instance of the selected object" +msgstr "Remover instância do objeto selecionado" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:128 +msgid "Show keyboard shortcuts list" +msgstr "Mostrar lista dos atalhos no teclado" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:129 +msgid "Press to select multiple object or move multiple object with mouse" +msgstr "" +"Aperte para selecionar múltiplos objetos ou mover múltiplos objetos com o " +"mouse" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:131 +msgid "Main Shortcuts" +msgstr "Atalhos principais" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:139 +msgid "Select All objects" +msgstr "Selecionar todos os objetos" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:140 +msgid "Delete selected" +msgstr "Deletar seleção" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:141 +msgid "Delete All" +msgstr "Deletar todos" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:142 +msgid "Copy to clipboard" +msgstr "Copiar para a área de transferência" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:143 +msgid "Paste from clipboard" +msgstr "Colar da área de transferência" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:144 +msgid "Gizmo move" +msgstr "Gizmo-Mover" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:145 +msgid "Gizmo scale" +msgstr "Gizmo-Escala" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:146 +msgid "Gizmo rotate" +msgstr "Gizmo-Rotacionar" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:147 +msgid "Gizmo cut" +msgstr "Gizmo-Cortar" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:148 +msgid "Gizmo Place face on bed" +msgstr "Colocar face do Gizmo na mesa" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:149 +msgid "Gizmo SLA support points" +msgstr "Pontos de suporte do Gizmo SLA" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:150 +#, c-format +msgid "" +"Press to activate selection rectangle\n" +"or to snap by 5% in Gizmo scale\n" +"or to snap by 1mm in Gizmo move" +msgstr "" +"Pressione para ativar o retângulo de seleção\n" +"ou para encaixar em 5% i na escala Gizmo\n" +"ou para encaixar por 1mm em Gizmo mover" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:151 +msgid "" +"Press to scale selection to fit print volume\n" +"in Gizmo scale" +msgstr "" +"Pressione para dimensionar a seleção ao volume de impressão\n" +"na escala Gizmo" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:152 +msgid "" +"Press to activate deselection rectangle\n" +"or to scale or rotate selected objects\n" +"around their own center" +msgstr "" +"Pressione para ativar o retângulo de deseleção\n" +"ou para dimensionar ou girar objetos selecionados\n" +"em torno de seu próprio centro" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:153 +msgid "Press to activate one direction scaling in Gizmo scale" +msgstr "Pressione para ativar um dimensionamento de direção na escala Gizmo" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:154 +msgid "Change camera type (perspective, orthographic)" +msgstr "Alterar tipo de câmera (perspectiva, ortográfica)" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:155 +msgid "Zoom to Bed" +msgstr "Ampliar para a mesa" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:156 +msgid "Zoom to all objects in scene, if none selected" +msgstr "Ampliar para todos os objetos na cena, se nenhum selecionado" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:157 +msgid "Zoom to selected object" +msgstr "Ampliar para o objeto selecionado" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:158 +msgid "Zoom in" +msgstr "Ampliar" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:159 +msgid "Zoom out" +msgstr "Dimiuir" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:160 +msgid "Unselect gizmo / Clear selection" +msgstr "Desmarcar Gizmo/limpar seleção" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:166 +msgid "Plater Shortcuts" +msgstr "Atalhos do prato" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:181 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:193 +msgid "Arrow Up" +msgstr "Seta para cima" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:181 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:183 +msgid "Upper Layer" +msgstr "Camada superior" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:182 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:194 +msgid "Arrow Down" +msgstr "Seta para baixo" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:182 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:184 +msgid "Lower Layer" +msgstr "Camada inferior" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:185 +msgid "Show/Hide (L)egend" +msgstr "Mostrar/ocultar (L) egenda" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:187 +msgid "Preview Shortcuts" +msgstr "Atalhos de visualização" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:193 +msgid "Move current slider thumb Up" +msgstr "Mover a barra de rolagem para cima" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:194 +msgid "Move current slider thumb Down" +msgstr "Mover a barra de rolagem para baixo" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:195 +msgid "Arrow Left" +msgstr "Seta esquerda" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:195 +msgid "Set upper thumb to current slider thumb" +msgstr "Definir o polegar superior para o polegar deslizante atual" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:196 +msgid "Arrow Right" +msgstr "Seta direita" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:196 +msgid "Set lower thumb to current slider thumb" +msgstr "Definir o polegar inferior para o polegar deslizante atual" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:197 +msgid "Add color change marker for current layer" +msgstr "Adicionar mudança de cor para a camada atual" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:198 +msgid "Delete color change marker for current layer" +msgstr "Excluir mudança de cor para a camada atual" + +#: src/slic3r/GUI/KBShortcutsDialog.cpp:200 +msgid "Layers Slider Shortcuts" +msgstr "Atalhos da barra de rolagem de camadas" + +#: src/slic3r/GUI/MainFrame.cpp:64 +msgid "" +" - Remember to check for updates at http://github.com/prusa3d/PrusaSlicer/" +"releases" +msgstr "" +" - Lembre-se de verificar por atualizações em http://github.com/prusa3d/" +"PrusaSlicer/releases" + +#: src/slic3r/GUI/MainFrame.cpp:159 +msgid "based on Slic3r" +msgstr "baseado no Slic3r" + +#: src/slic3r/GUI/MainFrame.cpp:189 +msgid "Plater" +msgstr "Prato" + +#: src/slic3r/GUI/MainFrame.cpp:400 +msgid "&New Project" +msgstr "&Novo projeto" + +#: src/slic3r/GUI/MainFrame.cpp:400 +msgid "Start a new project" +msgstr "Começar um novo projeto" + +#: src/slic3r/GUI/MainFrame.cpp:403 +msgid "&Open Project" +msgstr "&Abrir projeto" + +#: src/slic3r/GUI/MainFrame.cpp:403 +msgid "Open a project file" +msgstr "Abrir novo projeto" + +#: src/slic3r/GUI/MainFrame.cpp:408 +msgid "Recent projects" +msgstr "Projetos recentes" + +#: src/slic3r/GUI/MainFrame.cpp:417 +msgid "The selected project is no more available" +msgstr "O projeto selecionado não está mais disponível" + +#: src/slic3r/GUI/MainFrame.cpp:417 src/slic3r/GUI/MainFrame.cpp:755 +#: src/slic3r/GUI/PrintHostDialogs.cpp:231 +msgid "Error" +msgstr "Erro" + +#: src/slic3r/GUI/MainFrame.cpp:441 +msgid "&Save Project" +msgstr "&Salvar projeto" + +#: src/slic3r/GUI/MainFrame.cpp:441 +msgid "Save current project file" +msgstr "Salvar arquivo" + +#: src/slic3r/GUI/MainFrame.cpp:445 src/slic3r/GUI/MainFrame.cpp:447 +msgid "Save Project &as" +msgstr "Salvar projeto &como" + +#: src/slic3r/GUI/MainFrame.cpp:445 src/slic3r/GUI/MainFrame.cpp:447 +msgid "Save current project file as" +msgstr "Salvar arquivo atual como" + +#: src/slic3r/GUI/MainFrame.cpp:455 +msgid "Import STL/OBJ/AM&F/3MF" +msgstr "Import STL/OBJ/AM&F/3MF" + +#: src/slic3r/GUI/MainFrame.cpp:455 +msgid "Load a model" +msgstr "Carregar um modelo" + +#: src/slic3r/GUI/MainFrame.cpp:459 +msgid "Import &Config" +msgstr "Importar &config." + +#: src/slic3r/GUI/MainFrame.cpp:459 +msgid "Load exported configuration file" +msgstr "Carregar config. de arquivo exportado" + +#: src/slic3r/GUI/MainFrame.cpp:461 +msgid "Import Config from &project" +msgstr "Importar Config do &projeto" + +#: src/slic3r/GUI/MainFrame.cpp:461 +msgid "Load configuration from project file" +msgstr "Carregar config. de arquivo de projeto" + +#: src/slic3r/GUI/MainFrame.cpp:464 +msgid "Import Config &Bundle" +msgstr "Importar coleção &de config." + +#: src/slic3r/GUI/MainFrame.cpp:464 +msgid "Load presets from a bundle" +msgstr "Carregar predefinições de um pacote" + +#: src/slic3r/GUI/MainFrame.cpp:466 +msgid "&Import" +msgstr "&Importar" + +#: src/slic3r/GUI/MainFrame.cpp:469 src/slic3r/GUI/MainFrame.cpp:719 +msgid "Export &G-code" +msgstr "Exportar &G-code" + +#: src/slic3r/GUI/MainFrame.cpp:469 +msgid "Export current plate as G-code" +msgstr "Exporte o prato atual como o G-code" + +#: src/slic3r/GUI/MainFrame.cpp:473 src/slic3r/GUI/MainFrame.cpp:720 +msgid "S&end G-code" +msgstr "E&nviar G-code" + +#: src/slic3r/GUI/MainFrame.cpp:473 +msgid "Send to print current plate as G-code" +msgstr "Enviar para imprimir prato atual como G-code" + +#: src/slic3r/GUI/MainFrame.cpp:478 +msgid "Export plate as &STL" +msgstr "Exportar prato como &STL" + +#: src/slic3r/GUI/MainFrame.cpp:478 +msgid "Export current plate as STL" +msgstr "Exporte o prato atual como STL" + +#: src/slic3r/GUI/MainFrame.cpp:481 +msgid "Export plate as STL &including supports" +msgstr "Exportar prato como STL &incluindo suportes" + +#: src/slic3r/GUI/MainFrame.cpp:481 +msgid "Export current plate as STL including supports" +msgstr "Exporte o prato atual como o STL que inclui suportes" + +#: src/slic3r/GUI/MainFrame.cpp:484 +msgid "Export plate as &AMF" +msgstr "Exportar prato como &AMF" + +#: src/slic3r/GUI/MainFrame.cpp:484 +msgid "Export current plate as AMF" +msgstr "Exporte o prato atual como o AMF" + +#: src/slic3r/GUI/MainFrame.cpp:488 +msgid "Export &toolpaths as OBJ" +msgstr "Exportar &percurso da ferramenta como OBJ" + +#: src/slic3r/GUI/MainFrame.cpp:488 +msgid "Export toolpaths as OBJ" +msgstr "Exportar percursos como OBJ" + +#: src/slic3r/GUI/MainFrame.cpp:492 +msgid "Export &Config" +msgstr "Exportar &config." + +#: src/slic3r/GUI/MainFrame.cpp:492 +msgid "Export current configuration to file" +msgstr "Exporte a config. atual para o arquivo" + +#: src/slic3r/GUI/MainFrame.cpp:494 +msgid "Export Config &Bundle" +msgstr "Exportar coleção &de config." + +#: src/slic3r/GUI/MainFrame.cpp:494 +msgid "Export all presets to file" +msgstr "Exporte todas as predefinições para o arquivo" + +#: src/slic3r/GUI/MainFrame.cpp:496 +msgid "&Export" +msgstr "&Exportar" + +#: src/slic3r/GUI/MainFrame.cpp:502 +msgid "Quick Slice" +msgstr "Fatiamento rápido" + +#: src/slic3r/GUI/MainFrame.cpp:502 +msgid "Slice a file into a G-code" +msgstr "Fatiar um arquivo em um G-code" + +#: src/slic3r/GUI/MainFrame.cpp:508 +msgid "Quick Slice and Save As" +msgstr "Salvamento rápido e salvar como" + +#: src/slic3r/GUI/MainFrame.cpp:508 +msgid "Slice a file into a G-code, save as" +msgstr "Fatiar um arquivo em um G-code, salvar como" + +#: src/slic3r/GUI/MainFrame.cpp:514 +msgid "Repeat Last Quick Slice" +msgstr "Repetir Último Fatiamento Rápido" + +#: src/slic3r/GUI/MainFrame.cpp:514 +msgid "Repeat last quick slice" +msgstr "Repetir último fatiamento rápido" + +#: src/slic3r/GUI/MainFrame.cpp:522 +msgid "(Re)Slice No&w" +msgstr "(Re)Fatiar ago&ra" + +#: src/slic3r/GUI/MainFrame.cpp:522 +msgid "Start new slicing process" +msgstr "Começar novo processo de fatiamento" + +#: src/slic3r/GUI/MainFrame.cpp:526 +msgid "&Repair STL file" +msgstr "&Reparar arquivo STL" + +#: src/slic3r/GUI/MainFrame.cpp:526 +msgid "Automatically repair an STL file" +msgstr "Reparar automaticamente um arquivo STL" + +#: src/slic3r/GUI/MainFrame.cpp:529 +msgid "&Quit" +msgstr "&Sair" + +#: src/slic3r/GUI/MainFrame.cpp:529 +#, c-format +msgid "Quit %s" +msgstr "Sair %s" + +#: src/slic3r/GUI/MainFrame.cpp:554 +msgid "&Select all" +msgstr "&Selecionar todos" + +#: src/slic3r/GUI/MainFrame.cpp:555 +msgid "Selects all objects" +msgstr "Selecionar todos os objetos" + +#: src/slic3r/GUI/MainFrame.cpp:557 +msgid "D&eselect all" +msgstr "D&eselecionar todos" + +#: src/slic3r/GUI/MainFrame.cpp:558 +msgid "Deselects all objects" +msgstr "Deselecionar todos os objetos" + +#: src/slic3r/GUI/MainFrame.cpp:561 +msgid "&Delete selected" +msgstr "&Excluir seleção" + +#: src/slic3r/GUI/MainFrame.cpp:562 +msgid "Deletes the current selection" +msgstr "Excluir a seleção atual" + +#: src/slic3r/GUI/MainFrame.cpp:564 +msgid "Delete &all" +msgstr "Excluir &todos" + +#: src/slic3r/GUI/MainFrame.cpp:565 +msgid "Deletes all objects" +msgstr "Excluir todos os objetos" + +#: src/slic3r/GUI/MainFrame.cpp:569 +msgid "&Undo" +msgstr "&Desfazer" + +#: src/slic3r/GUI/MainFrame.cpp:572 +msgid "&Redo" +msgstr "&Refazer" + +#: src/slic3r/GUI/MainFrame.cpp:577 +msgid "&Copy" +msgstr "&Copiar" + +#: src/slic3r/GUI/MainFrame.cpp:578 +msgid "Copy selection to clipboard" +msgstr "Copiar seleção para a área de transferência" + +#: src/slic3r/GUI/MainFrame.cpp:580 +msgid "&Paste" +msgstr "&Colar" + +#: src/slic3r/GUI/MainFrame.cpp:581 +msgid "Paste clipboard" +msgstr "Colar área de transferência" + +#: src/slic3r/GUI/MainFrame.cpp:590 +msgid "&Plater Tab" +msgstr "&Prato" + +#: src/slic3r/GUI/MainFrame.cpp:590 +msgid "Show the plater" +msgstr "Mostrar o prato" + +#: src/slic3r/GUI/MainFrame.cpp:597 +msgid "P&rint Settings Tab" +msgstr "C&onfig. de impressão" + +#: src/slic3r/GUI/MainFrame.cpp:597 +msgid "Show the print settings" +msgstr "Mostrar as config. de impressão" + +#: src/slic3r/GUI/MainFrame.cpp:599 src/slic3r/GUI/MainFrame.cpp:722 +msgid "&Filament Settings Tab" +msgstr "&config. de filamentos" + +#: src/slic3r/GUI/MainFrame.cpp:599 +msgid "Show the filament settings" +msgstr "Mostrar as config. de filamento" + +#: src/slic3r/GUI/MainFrame.cpp:602 +msgid "Print&er Settings Tab" +msgstr "A&ba de config. da impressora" + +#: src/slic3r/GUI/MainFrame.cpp:602 +msgid "Show the printer settings" +msgstr "Mostrar as config. da impressora" + +#: src/slic3r/GUI/MainFrame.cpp:606 +msgid "3&D" +msgstr "3&D" + +#: src/slic3r/GUI/MainFrame.cpp:606 +msgid "Show the 3D editing view" +msgstr "Mostrar a vista de edição 3D" + +#: src/slic3r/GUI/MainFrame.cpp:609 +msgid "Pre&view" +msgstr "Pre&visualização" + +#: src/slic3r/GUI/MainFrame.cpp:609 +msgid "Show the 3D slices preview" +msgstr "Mostrar a pré-visualização do fatiamento 3D" + +#: src/slic3r/GUI/MainFrame.cpp:628 +msgid "Print &Host Upload Queue" +msgstr "Imprimir &Fila de upload do Host" + +#: src/slic3r/GUI/MainFrame.cpp:628 +msgid "Display the Print Host Upload Queue window" +msgstr "Exibir a janela fila de upload do host de impressão" + +#: src/slic3r/GUI/MainFrame.cpp:637 +msgid "Iso" +msgstr "Isométrico" + +#: src/slic3r/GUI/MainFrame.cpp:637 +msgid "Iso View" +msgstr "Vista isométrica" + +#. TRN To be shown in the main menu View->Top +#. TRN To be shown in Print Settings "Top solid layers" +#: src/slic3r/GUI/MainFrame.cpp:641 src/libslic3r/PrintConfig.cpp:2094 +msgid "Top" +msgstr "Topo" + +#: src/slic3r/GUI/MainFrame.cpp:641 +msgid "Top View" +msgstr "Vista do topo" + +#. TRN To be shown in the main menu View->Bottom +#. TRN To be shown in Print Settings "Bottom solid layers" +#: src/slic3r/GUI/MainFrame.cpp:644 src/libslic3r/PrintConfig.cpp:159 +msgid "Bottom" +msgstr "Base" + +#: src/slic3r/GUI/MainFrame.cpp:644 +msgid "Bottom View" +msgstr "Vista da base" + +#: src/slic3r/GUI/MainFrame.cpp:646 +msgid "Front" +msgstr "Frente" + +#: src/slic3r/GUI/MainFrame.cpp:646 +msgid "Front View" +msgstr "Vista da frente" + +#: src/slic3r/GUI/MainFrame.cpp:648 src/libslic3r/PrintConfig.cpp:1611 +msgid "Rear" +msgstr "Traseira" + +#: src/slic3r/GUI/MainFrame.cpp:648 +msgid "Rear View" +msgstr "Vista traseira" + +#: src/slic3r/GUI/MainFrame.cpp:650 +msgid "Left" +msgstr "Esquerda" + +#: src/slic3r/GUI/MainFrame.cpp:650 +msgid "Left View" +msgstr "Vista esquerda" + +#: src/slic3r/GUI/MainFrame.cpp:652 +msgid "Right" +msgstr "Direita" + +#: src/slic3r/GUI/MainFrame.cpp:652 +msgid "Right View" +msgstr "Vista direita" + +#: src/slic3r/GUI/MainFrame.cpp:659 +msgid "Prusa 3D &Drivers" +msgstr "Drivers 3D &Prusa" + +#: src/slic3r/GUI/MainFrame.cpp:659 +msgid "Open the Prusa3D drivers download page in your browser" +msgstr "Abrir a página para baixar os drivers da Prusa3D no seu navegador" + +#: src/slic3r/GUI/MainFrame.cpp:661 +msgid "Software &Releases" +msgstr "Lançamentos de &software" + +#: src/slic3r/GUI/MainFrame.cpp:661 +msgid "Open the software releases page in your browser" +msgstr "Abrir a página de lançamentos de software no seu navegador" + +#: src/slic3r/GUI/MainFrame.cpp:667 +#, c-format +msgid "%s &Website" +msgstr "%s &Site" + +#: src/slic3r/GUI/MainFrame.cpp:668 +#, c-format +msgid "Open the %s website in your browser" +msgstr "Abra o site do %s no seu navegador" + +#: src/slic3r/GUI/MainFrame.cpp:674 +msgid "System &Info" +msgstr "Informação &do sistema" + +#: src/slic3r/GUI/MainFrame.cpp:674 +msgid "Show system information" +msgstr "Mostrar a informação do sistema" + +#: src/slic3r/GUI/MainFrame.cpp:676 +msgid "Show &Configuration Folder" +msgstr "Mostrar &pasta de config." + +#: src/slic3r/GUI/MainFrame.cpp:676 +msgid "Show user configuration folder (datadir)" +msgstr "Mostrar pasta de config. do usuário (datadir)" + +#: src/slic3r/GUI/MainFrame.cpp:678 +msgid "Report an I&ssue" +msgstr "Reportar um p&roblema" + +#: src/slic3r/GUI/MainFrame.cpp:678 +#, c-format +msgid "Report an issue on %s" +msgstr "Relatar um problema em %s" + +#: src/slic3r/GUI/MainFrame.cpp:680 +#, c-format +msgid "&About %s" +msgstr "&Sobre %s" + +#: src/slic3r/GUI/MainFrame.cpp:680 +msgid "Show about dialog" +msgstr "Mostrar diálogo sobre" + +#: src/slic3r/GUI/MainFrame.cpp:683 +msgid "Show the list of the keyboard shortcuts" +msgstr "Mostrar lista dos atalhos no teclado" + +#: src/slic3r/GUI/MainFrame.cpp:691 +msgid "&File" +msgstr "&Arquivo" + +#: src/slic3r/GUI/MainFrame.cpp:692 +msgid "&Edit" +msgstr "&Editar" + +#: src/slic3r/GUI/MainFrame.cpp:693 +msgid "&Window" +msgstr "&Janela" + +#: src/slic3r/GUI/MainFrame.cpp:694 +msgid "&View" +msgstr "&Vista" + +#: src/slic3r/GUI/MainFrame.cpp:697 +msgid "&Help" +msgstr "&Ajuda" + +#: src/slic3r/GUI/MainFrame.cpp:719 +msgid "E&xport" +msgstr "E&xportar" + +#: src/slic3r/GUI/MainFrame.cpp:720 +msgid "S&end to print" +msgstr "E&nviar para impressora" + +#: src/slic3r/GUI/MainFrame.cpp:722 +msgid "Mate&rial Settings Tab" +msgstr "A&ba de config. de material" + +#: src/slic3r/GUI/MainFrame.cpp:743 +msgid "Choose a file to slice (STL/OBJ/AMF/3MF/PRUSA):" +msgstr "Escolha um arquivo para fatiar (STL/OBJ/AMF/3MF/PRUSA):" + +#: src/slic3r/GUI/MainFrame.cpp:754 +msgid "No previously sliced file." +msgstr "Sem arquivo fatiado anteriormente." + +#: src/slic3r/GUI/MainFrame.cpp:760 +msgid "Previously sliced file (" +msgstr "Arquivo fatiado anteriormente (" + +#: src/slic3r/GUI/MainFrame.cpp:760 +msgid ") not found." +msgstr ") não encontrado." + +#: src/slic3r/GUI/MainFrame.cpp:761 +msgid "File Not Found" +msgstr "Arquivo não encontrado" + +#: src/slic3r/GUI/MainFrame.cpp:796 +#, c-format +msgid "Save %s file as:" +msgstr "Salve o arquivo %s como:" + +#: src/slic3r/GUI/MainFrame.cpp:796 +msgid "SVG" +msgstr "SVG" + +#: src/slic3r/GUI/MainFrame.cpp:796 +msgid "G-code" +msgstr "G-code" + +#: src/slic3r/GUI/MainFrame.cpp:808 +msgid "Save zip file as:" +msgstr "Salvar arquivo compactado(zip) como:" + +#: src/slic3r/GUI/MainFrame.cpp:817 src/slic3r/GUI/Plater.cpp:2981 +#: src/slic3r/GUI/Plater.cpp:4533 src/slic3r/GUI/Tab.cpp:1194 +#: src/slic3r/GUI/Tab.cpp:3786 +msgid "Slicing" +msgstr "Fatiamento" + +#. TRN "Processing input_file_basename" +#: src/slic3r/GUI/MainFrame.cpp:819 +#, c-format +msgid "Processing %s" +msgstr "Processando %s" + +#: src/slic3r/GUI/MainFrame.cpp:842 +msgid " was successfully sliced." +msgstr " foi fatiado com sucesso." + +#: src/slic3r/GUI/MainFrame.cpp:844 +msgid "Slicing Done!" +msgstr "Fatiamento completo!" + +#: src/slic3r/GUI/MainFrame.cpp:859 +msgid "Select the STL file to repair:" +msgstr "Selecione o arquivo STL para corrigir:" + +#: src/slic3r/GUI/MainFrame.cpp:869 +msgid "Save OBJ file (less prone to coordinate errors than STL) as:" +msgstr "" +"Salvar arquivo OBJ (menos propenso a erros de coordenada que STL) como:" + +#: src/slic3r/GUI/MainFrame.cpp:881 +msgid "Your file was repaired." +msgstr "Seu arquivo foi corrigido." + +#: src/slic3r/GUI/MainFrame.cpp:881 src/libslic3r/PrintConfig.cpp:3257 +msgid "Repair" +msgstr "Corrigir" + +#: src/slic3r/GUI/MainFrame.cpp:895 +msgid "Save configuration as:" +msgstr "Salvar config. como:" + +#: src/slic3r/GUI/MainFrame.cpp:914 src/slic3r/GUI/MainFrame.cpp:976 +msgid "Select configuration to load:" +msgstr "Selecionar config. para carregar:" + +#: src/slic3r/GUI/MainFrame.cpp:950 +msgid "Save presets bundle as:" +msgstr "Salvar pacote de predefinições como:" + +#: src/slic3r/GUI/MainFrame.cpp:997 +#, c-format +msgid "%d presets successfully imported." +msgstr "%d predefinições importadas com êxito." + +#: src/slic3r/GUI/MsgDialog.cpp:73 +#, c-format +msgid "%s error" +msgstr "%s erro" + +#: src/slic3r/GUI/MsgDialog.cpp:74 +#, c-format +msgid "%s has encountered an error" +msgstr "%s encontrou um erro" + +#: src/slic3r/GUI/OptionsGroup.cpp:249 +msgctxt "Layers" +msgid "Top" +msgstr "Topo" + +#: src/slic3r/GUI/OptionsGroup.cpp:249 +msgctxt "Layers" +msgid "Bottom" +msgstr "Base" + +#: src/slic3r/GUI/Plater.cpp:146 +msgid "Volume" +msgstr "Volume" + +#: src/slic3r/GUI/Plater.cpp:147 +msgid "Facets" +msgstr "Facetas" + +#: src/slic3r/GUI/Plater.cpp:148 +msgid "Materials" +msgstr "Materiais" + +#: src/slic3r/GUI/Plater.cpp:151 +msgid "Manifold" +msgstr "Múltiplo" + +#: src/slic3r/GUI/Plater.cpp:201 +msgid "Sliced Info" +msgstr "Informações fatiadas" + +#: src/slic3r/GUI/Plater.cpp:220 src/slic3r/GUI/Plater.cpp:1150 +msgid "Used Filament (m)" +msgstr "Filamento utilizado (m)" + +#: src/slic3r/GUI/Plater.cpp:221 +msgid "Used Filament (mm³)" +msgstr "Filamento utilizado (mm³)" + +#: src/slic3r/GUI/Plater.cpp:222 +msgid "Used Filament (g)" +msgstr "Filamento utilizado (g)" + +#: src/slic3r/GUI/Plater.cpp:223 +msgid "Used Material (unit)" +msgstr "Material utilizado (unidade)" + +#: src/slic3r/GUI/Plater.cpp:224 src/slic3r/GUI/Plater.cpp:1165 +#: src/libslic3r/PrintConfig.cpp:742 +msgid "Cost" +msgstr "Custo" + +#: src/slic3r/GUI/Plater.cpp:225 src/slic3r/GUI/Plater.cpp:1137 +#: src/slic3r/GUI/Plater.cpp:1179 +msgid "Estimated printing time" +msgstr "Tempo estimado de impressão" + +#: src/slic3r/GUI/Plater.cpp:226 +msgid "Number of tool changes" +msgstr "Número de mudanças de ferramenta" + +#: src/slic3r/GUI/Plater.cpp:316 +msgid "Click to edit preset" +msgstr "Clique para editar a predefinição" + +#: src/slic3r/GUI/Plater.cpp:468 +msgid "Select what kind of support do you need" +msgstr "Selecione o tipo de suporte que você precisa" + +#: src/slic3r/GUI/Plater.cpp:470 src/libslic3r/PrintConfig.cpp:1865 +#: src/libslic3r/PrintConfig.cpp:2561 +msgid "Support on build plate only" +msgstr "Suportes somente na mesa de impressão" + +#: src/slic3r/GUI/Plater.cpp:471 src/slic3r/GUI/Plater.cpp:592 +msgid "For support enforcers only" +msgstr "Para apenas reforçadores de suporte" + +#: src/slic3r/GUI/Plater.cpp:472 +msgid "Everywhere" +msgstr "Em toda parte" + +#: src/slic3r/GUI/Plater.cpp:504 src/slic3r/GUI/Tab.cpp:1091 +msgid "Brim" +msgstr "Aba" + +#: src/slic3r/GUI/Plater.cpp:506 +msgid "" +"This flag enables the brim that will be printed around each object on the " +"first layer." +msgstr "" +"Este sinalizador permite que a aba que será impressa em torno de cada objeto " +"na primeira camada." + +#: src/slic3r/GUI/Plater.cpp:514 +msgid "Purging volumes" +msgstr "Volumes de purga" + +#: src/slic3r/GUI/Plater.cpp:606 +msgid "Select what kind of pad do you need" +msgstr "Selecione o tipo de bloco que você precisa" + +#: src/slic3r/GUI/Plater.cpp:608 +msgid "Below object" +msgstr "Abaixo do objeto" + +#: src/slic3r/GUI/Plater.cpp:609 +msgid "Around object" +msgstr "Em torno do objeto" + +#: src/slic3r/GUI/Plater.cpp:781 +msgid "Print settings" +msgstr "Config. de impressão" + +#: src/slic3r/GUI/Plater.cpp:782 src/slic3r/GUI/Tab.cpp:1640 +#: src/slic3r/GUI/Tab.cpp:1641 +msgid "Filament" +msgstr "Filamento" + +#: src/slic3r/GUI/Plater.cpp:783 +msgid "SLA print settings" +msgstr "Config. de impressão de SLA" + +#: src/slic3r/GUI/Plater.cpp:784 src/slic3r/GUI/Preset.cpp:1314 +msgid "SLA material" +msgstr "Material de SLA" + +#: src/slic3r/GUI/Plater.cpp:785 +msgid "Printer" +msgstr "Impressora" + +#: src/slic3r/GUI/Plater.cpp:835 src/slic3r/GUI/Plater.cpp:4823 +msgid "Send to printer" +msgstr "Enviar para a impressora" + +#: src/slic3r/GUI/Plater.cpp:838 src/slic3r/GUI/Plater.cpp:2981 +#: src/slic3r/GUI/Plater.cpp:4536 +msgid "Slice now" +msgstr "Fatiar agora" + +#: src/slic3r/GUI/Plater.cpp:978 +msgid "Hold Shift to Slice & Export G-code" +msgstr "Hold Shift to Slice & Export G-code" + +#: src/slic3r/GUI/Plater.cpp:1083 +#, c-format +msgid "%d (%d shells)" +msgstr "%d (%d paredes)" + +#: src/slic3r/GUI/Plater.cpp:1088 +#, c-format +msgid "Auto-repaired (%d errors)" +msgstr "Auto reparando (%d erros):" + +#: src/slic3r/GUI/Plater.cpp:1091 +#, c-format +msgid "" +"%d degenerate facets, %d edges fixed, %d facets removed, %d facets added, %d " +"facets reversed, %d backwards edges" +msgstr "" +"%d degenerate facets, %d edges fixed, %d facets removed, %d facets added, %d " +"facets reversed, %d backwards edges" + +#: src/slic3r/GUI/Plater.cpp:1101 +msgid "Yes" +msgstr "Sim" + +#: src/slic3r/GUI/Plater.cpp:1124 +msgid "Used Material (ml)" +msgstr "Material usado (ml)" + +#: src/slic3r/GUI/Plater.cpp:1127 +msgid "object(s)" +msgstr "objeto(s)" + +#: src/slic3r/GUI/Plater.cpp:1127 +msgid "supports and pad" +msgstr "suportes e bloco" + +#: src/slic3r/GUI/Plater.cpp:1152 src/slic3r/GUI/Plater.cpp:1167 +msgid "objects" +msgstr "objetos" + +#: src/slic3r/GUI/Plater.cpp:1152 src/slic3r/GUI/Plater.cpp:1167 +msgid "wipe tower" +msgstr "torre de limpeza" + +#: src/slic3r/GUI/Plater.cpp:1182 +msgid "normal mode" +msgstr "modo normal" + +#: src/slic3r/GUI/Plater.cpp:1186 src/slic3r/GUI/Plater.cpp:1195 +#: src/libslic3r/PrintConfig.cpp:565 +msgid "Color" +msgstr "Cor" + +#: src/slic3r/GUI/Plater.cpp:1191 +msgid "stealth mode" +msgstr "modo silencioso" + +#: src/slic3r/GUI/Plater.cpp:1286 +msgid "Load File" +msgstr "Carregar arquivo" + +#: src/slic3r/GUI/Plater.cpp:1290 +msgid "Load Files" +msgstr "Carregar arquivos" + +#: src/slic3r/GUI/Plater.cpp:1519 +msgid "ERROR: not enough resources to execute a new job." +msgstr "ERRO: não há recursos suficientes para executar um novo trabalho." + +#: src/slic3r/GUI/Plater.cpp:2089 +msgid "New Project" +msgstr "Novo projeto" + +#: src/slic3r/GUI/Plater.cpp:2206 +msgid "Loading" +msgstr "Carregando" + +#: src/slic3r/GUI/Plater.cpp:2216 +#, c-format +msgid "Processing input file %s\n" +msgstr "Processando o arquivo de entrada %s\n" + +#: src/slic3r/GUI/Plater.cpp:2244 +msgid "" +"You can't load SLA project if there is at least one multi-part object on the " +"bed" +msgstr "" +"Não é possível carregar o projeto de SLA se houver pelo menos um objeto de " +"várias partes na mesa" + +#: src/slic3r/GUI/Plater.cpp:2245 src/slic3r/GUI/Tab.cpp:3146 +msgid "Please check your object list before preset changing." +msgstr "Verifique a lista de objetos antes de alterar a predefinição." + +#: src/slic3r/GUI/Plater.cpp:2288 +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 "" +"Este arquivo contém vários objetos posicionados em várias alturas. Em vez de " +"considerá-los como múltiplos objetos, devo considerar\n" +"Este arquivo como um único objeto com várias partes?\n" + +#: src/slic3r/GUI/Plater.cpp:2291 src/slic3r/GUI/Plater.cpp:2343 +msgid "Multi-part object detected" +msgstr "Objeto de várias partes detectado" + +#: src/slic3r/GUI/Plater.cpp:2298 +msgid "" +"This file cannot be loaded in a simple mode. Do you want to switch to an " +"advanced mode?\n" +msgstr "" +"Este arquivo não pode ser carregado em um modo simples. Deseja mudar para um " +"modo avançado?\n" + +#: src/slic3r/GUI/Plater.cpp:2299 +msgid "Detected advanced data" +msgstr "Dados avançados detectados" + +#: src/slic3r/GUI/Plater.cpp:2320 +#, 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 "" +"Você não pode adicionar o objeto (s) %s por causa de um ou alguns deles é " +"(são) de várias partes" + +#: src/slic3r/GUI/Plater.cpp:2340 +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 "" +"Vários objetos foram carregados para uma impressora de vários materiais.\n" +"Em vez de considerá-los como múltiplos objetos, devo considerar\n" +"esses arquivos para representar um único objeto com várias partes?\n" + +#: src/slic3r/GUI/Plater.cpp:2356 +msgid "Loaded" +msgstr "Carregado" + +#: src/slic3r/GUI/Plater.cpp:2458 +msgid "" +"Your object appears to be too large, so it was automatically scaled down to " +"fit your print bed." +msgstr "" +"Seu objeto parece ser muito grande, por isso foi automaticamente " +"dimensionado para baixo para caber sua mesa de impressão." + +#: src/slic3r/GUI/Plater.cpp:2459 +msgid "Object too large?" +msgstr "Objeto muito grande?" + +#: src/slic3r/GUI/Plater.cpp:2517 +msgid "Export STL file:" +msgstr "Exportar arquivo STL:" + +#: src/slic3r/GUI/Plater.cpp:2524 +msgid "Export AMF file:" +msgstr "Exportar arquivo AMF:" + +#: src/slic3r/GUI/Plater.cpp:2530 +msgid "Save file as:" +msgstr "Salvar arquivo como:" + +#: src/slic3r/GUI/Plater.cpp:2536 +msgid "Export OBJ file:" +msgstr "Exportar arquivo OBJ:" + +#: src/slic3r/GUI/Plater.cpp:2638 +msgid "Delete Object" +msgstr "Excluir objeto" + +#: src/slic3r/GUI/Plater.cpp:2649 +msgid "Reset Project" +msgstr "Redefinir projeto" + +#: src/slic3r/GUI/Plater.cpp:2688 +msgid "Optimize Rotation" +msgstr "Otimize a rotação" + +#: src/slic3r/GUI/Plater.cpp:2734 +msgid "Arranging" +msgstr "Organizar" + +#: src/slic3r/GUI/Plater.cpp:2757 +msgid "Could not arrange model objects! Some geometries may be invalid." +msgstr "" +"Não foi possível organizar objetos de modelo! Algumas geometrias podem ser " +"inválidas." + +#: src/slic3r/GUI/Plater.cpp:2763 +msgid "Arranging canceled." +msgstr "Arranjo cancelado." + +#: src/slic3r/GUI/Plater.cpp:2764 +msgid "Arranging done." +msgstr "Arranjo feito." + +#: src/slic3r/GUI/Plater.cpp:2780 +msgid "Searching for optimal orientation" +msgstr "Procurando orientação ideal" + +#: src/slic3r/GUI/Plater.cpp:2813 +msgid "Orientation search canceled." +msgstr "Pesquisa de orientação cancelada." + +#: src/slic3r/GUI/Plater.cpp:2814 +msgid "Orientation found." +msgstr "Orientação encontrada." + +#: src/slic3r/GUI/Plater.cpp:2830 +msgid "" +"The selected object can't be split because it contains more than one volume/" +"material." +msgstr "" +"O objeto selecionado não pode ser dividido porque contém mais de um volume/" +"material." + +#: src/slic3r/GUI/Plater.cpp:2841 +msgid "Split to Objects" +msgstr "Dividir em objetos" + +#: src/slic3r/GUI/Plater.cpp:2966 +msgid "Invalid data" +msgstr "Dados inválidos" + +#: src/slic3r/GUI/Plater.cpp:2975 +msgid "Ready to slice" +msgstr "Pronto para fatiar" + +#: src/slic3r/GUI/Plater.cpp:3013 src/slic3r/GUI/PrintHostDialogs.cpp:232 +msgid "Cancelling" +msgstr "Cancelar" + +#: src/slic3r/GUI/Plater.cpp:3030 +msgid "Another export job is currently running." +msgstr "Outro trabalho de exportação está em execução no momento." + +#: src/slic3r/GUI/Plater.cpp:3084 src/slic3r/GUI/Plater.cpp:3549 +msgid "Reload from Disk" +msgstr "Recarregar a partir do disco" + +#: src/slic3r/GUI/Plater.cpp:3120 +msgid "Fix Throught NetFabb" +msgstr "Arrumar através do NetFabb" + +#: src/slic3r/GUI/Plater.cpp:3307 +msgid "Export failed" +msgstr "Falha na exportação" + +#: src/slic3r/GUI/Plater.cpp:3312 src/slic3r/GUI/PrintHostDialogs.cpp:233 +msgid "Cancelled" +msgstr "Cancelado" + +#: src/slic3r/GUI/Plater.cpp:3520 src/slic3r/GUI/Plater.cpp:3539 +msgid "Remove the selected object" +msgstr "Remover o objeto selecionado" + +#: src/slic3r/GUI/Plater.cpp:3526 +msgid "Add one more instance of the selected object" +msgstr "Adicionar mais uma instância do objeto selecionado" + +#: src/slic3r/GUI/Plater.cpp:3528 +msgid "Remove one instance of the selected object" +msgstr "Remover uma instância do objeto selecionado" + +#: src/slic3r/GUI/Plater.cpp:3530 +msgid "Set number of instances" +msgstr "Definir o número de instâncias" + +#: src/slic3r/GUI/Plater.cpp:3530 +msgid "Change the number of instances of the selected object" +msgstr "Alterar o número de instâncias do objeto selecionado" + +#: src/slic3r/GUI/Plater.cpp:3549 +msgid "Reload the selected file from Disk" +msgstr "Recarregar o arquivo selecionado a partir do disco" + +#: src/slic3r/GUI/Plater.cpp:3552 +msgid "Export the selected object as STL file" +msgstr "Exportar o objeto selecionado como arquivo STL" + +#: src/slic3r/GUI/Plater.cpp:3577 +msgid "Along X axis" +msgstr "Ao longo do eixo X" + +#: src/slic3r/GUI/Plater.cpp:3577 +msgid "Mirror the selected object along the X axis" +msgstr "Espelhar o objeto selecionado ao longo do eixo X" + +#: src/slic3r/GUI/Plater.cpp:3579 +msgid "Along Y axis" +msgstr "Ao longo do eixo Y" + +#: src/slic3r/GUI/Plater.cpp:3579 +msgid "Mirror the selected object along the Y axis" +msgstr "Espelhar o objeto selecionado ao longo do eixo Y" + +#: src/slic3r/GUI/Plater.cpp:3581 +msgid "Along Z axis" +msgstr "Ao longo do eixo Z" + +#: src/slic3r/GUI/Plater.cpp:3581 +msgid "Mirror the selected object along the Z axis" +msgstr "Espelhar o objeto selecionado ao longo do eixo Z" + +#: src/slic3r/GUI/Plater.cpp:3584 +msgid "Mirror" +msgstr "Espelhar" + +#: src/slic3r/GUI/Plater.cpp:3584 +msgid "Mirror the selected object" +msgstr "Espelhar o objeto selecionado" + +#: src/slic3r/GUI/Plater.cpp:3596 +msgid "To objects" +msgstr "Para objetos" + +#: src/slic3r/GUI/Plater.cpp:3596 src/slic3r/GUI/Plater.cpp:3616 +msgid "Split the selected object into individual objects" +msgstr "Dividir o objeto selecionado em objetos individuais" + +#: src/slic3r/GUI/Plater.cpp:3598 +msgid "To parts" +msgstr "Para peças" + +#: src/slic3r/GUI/Plater.cpp:3598 src/slic3r/GUI/Plater.cpp:3630 +msgid "Split the selected object into individual sub-parts" +msgstr "Dividir o objeto selecionado em subpartes individuais" + +#: src/slic3r/GUI/Plater.cpp:3601 src/slic3r/GUI/Plater.cpp:3616 +#: src/slic3r/GUI/Plater.cpp:3630 src/libslic3r/PrintConfig.cpp:3281 +msgid "Split" +msgstr "Dividir" + +#: src/slic3r/GUI/Plater.cpp:3601 +msgid "Split the selected object" +msgstr "Dividir o objeto selecionado" + +#: src/slic3r/GUI/Plater.cpp:3622 +msgid "Optimize orientation" +msgstr "Otimize a orientação" + +#: src/slic3r/GUI/Plater.cpp:3622 +msgid "Optimize the rotation of the object for better print results." +msgstr "" +"Otimize a rotação do objeto para obter melhores resultados de impressão." + +#: src/slic3r/GUI/Plater.cpp:3662 +msgid "3D editor view" +msgstr "vista do editor 3D" + +#: src/slic3r/GUI/Plater.cpp:3670 src/slic3r/GUI/Tab.cpp:2590 +msgid "Preview" +msgstr "Visualização" + +#: src/slic3r/GUI/Plater.cpp:3907 +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 "" +"a impressora %1% estava ativa no momento em que a captura de desfazer/" +"refazer de destino foi tirado. Mudar para %1% impressora requer recarga de " +"%1% predefinições." + +#: src/slic3r/GUI/Plater.cpp:4081 +msgid "Load Project" +msgstr "Carregar projeto" + +#: src/slic3r/GUI/Plater.cpp:4109 +msgid "Import Object" +msgstr "Importar objeto" + +#: src/slic3r/GUI/Plater.cpp:4113 +msgid "Import Objects" +msgstr "Importar objetos" + +#: src/slic3r/GUI/Plater.cpp:4172 +msgid "All objects will be removed, continue ?" +msgstr "Todos os objetos serão removidos, continuar?" + +#: src/slic3r/GUI/Plater.cpp:4180 +msgid "Delete Selected Objects" +msgstr "Excluir objetos selecionados" + +#: src/slic3r/GUI/Plater.cpp:4188 +msgid "Increase Instances" +msgstr "Aumentar instâncias" + +#: src/slic3r/GUI/Plater.cpp:4224 +msgid "Decrease Instances" +msgstr "Diminuir instâncias" + +#: src/slic3r/GUI/Plater.cpp:4260 +#, c-format +msgid "Set numbers of copies to %d" +msgstr "Definir números de cópias para %d" + +#: src/slic3r/GUI/Plater.cpp:4290 +msgid "Cut by Plane" +msgstr "Cortado por plano" + +#: src/slic3r/GUI/Plater.cpp:4322 +msgid "Save G-code file as:" +msgstr "Salve o arquivo G-code como:" + +#: src/slic3r/GUI/Plater.cpp:4322 +msgid "Save SL1 file as:" +msgstr "Salvar SL1 arquivo como:" + +#: src/slic3r/GUI/Plater.cpp:4434 +#, c-format +msgid "STL file exported to %s" +msgstr "Arquivo STL exportado para %s" + +#: src/slic3r/GUI/Plater.cpp:4450 +#, c-format +msgid "AMF file exported to %s" +msgstr "Arquivo AMF exportado para %s" + +#: src/slic3r/GUI/Plater.cpp:4453 +#, c-format +msgid "Error exporting AMF file %s" +msgstr "Erro ao exportar arquivo AMF %s" + +#: src/slic3r/GUI/Plater.cpp:4479 +#, c-format +msgid "3MF file exported to %s" +msgstr "Arquivo 3MF exportado para %s" + +#: src/slic3r/GUI/Plater.cpp:4484 +#, c-format +msgid "Error exporting 3MF file %s" +msgstr "Erro ao exportar arquivo 3MF %s" + +#: src/slic3r/GUI/Plater.cpp:4822 +msgid "Export" +msgstr "Exportar" + +#: src/slic3r/GUI/Plater.cpp:4823 +msgid "Send G-code" +msgstr "Enviar G-code" + +#: src/slic3r/GUI/Plater.cpp:4907 +msgid "Paste From Clipboard" +msgstr "Colar da área de transferência" + +#: src/slic3r/GUI/Preferences.cpp:22 src/slic3r/GUI/Tab.cpp:2001 +#: src/slic3r/GUI/Tab.cpp:2242 +msgid "General" +msgstr "Geral" + +#: src/slic3r/GUI/Preferences.cpp:44 +msgid "Remember output directory" +msgstr "Lembrar diretório de saída" + +#: 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 "" +"Se isso estiver habilitado, Slic3r solicitará o último diretório de saída em " +"vez de um contendo os arquivos de entrada." + +#: src/slic3r/GUI/Preferences.cpp:52 +msgid "Auto-center parts" +msgstr "Centrar automaticamente as partes" + +#: src/slic3r/GUI/Preferences.cpp:54 +msgid "" +"If this is enabled, Slic3r will auto-center objects around the print bed " +"center." +msgstr "" +"Se isso estiver habilitado, o Slic3r irá centralizar objetos automaticamente " +"ao redor do centro de mesa de impressão." + +#: src/slic3r/GUI/Preferences.cpp:60 +msgid "Background processing" +msgstr "Processamento em segundo plano" + +#: 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 "" +"Se isso estiver ativado, o Slic3r irá pré-processar objetos assim que eles " +"forem carregados para economizar tempo ao exportar o G-code." + +#: 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 " +"application startup (never during program usage). This is only a " +"notification mechanisms, no automatic installation is done." +msgstr "" +"Se habilitado, PrusaSlicer irá verificar as novas versões de si mesmo on-" +"line. Quando uma nova versão se torna disponível, uma notificação é exibida " +"na próxima inicialização do aplicativo (nunca durante o uso do programa). " +"Este é apenas um mecanismos de notificação, nenhuma instalação automática é " +"feita." + +#: 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. " +"When a new preset version becomes available it is offered at application " +"startup." +msgstr "" +"Se ativada, o Slic3r baixa atualizações de predefinições de sistema " +"incorporadas em segundo plano. Essas atualizações são baixadas em um local " +"temporário separado. Quando uma nova versão predefinida se torna disponível, " +"ela é oferecida na inicialização do aplicativo." + +#: src/slic3r/GUI/Preferences.cpp:84 +msgid "Suppress \" - default - \" presets" +msgstr "Suprimir predefinições \"-padrão-\"" + +#: 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 "" +"Suprimir predefinições \"-padrão-\" em impressão/filamento/impressora, uma " +"vez que existam outras predefinições válidas disponíveis." + +#: src/slic3r/GUI/Preferences.cpp:92 +msgid "Show incompatible print and filament presets" +msgstr "Mostrar predefinições de impressão e filamento incompatíveis" + +#: 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 "" +"Quando marcada, as predefinições de impressão e filamento são mostradas no " +"editor de predefinições, mesmo que estejam marcadas como incompatíveis com a " +"impressora ativa" + +#: src/slic3r/GUI/Preferences.cpp:101 +msgid "Use Retina resolution for the 3D scene" +msgstr "Usar a resolução retina para a cena 3D" + +#: 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 "" +"Se ativada, a cena 3D será renderizada na resolução retina. Se você estiver " +"enfrentando problemas de desempenho 3D, desabilitar essa opção pode ajudar." + +#: src/slic3r/GUI/Preferences.cpp:110 +msgid "Use perspective camera" +msgstr "Usar a câmera em perspectiva" + +#: src/slic3r/GUI/Preferences.cpp:112 +msgid "" +"If enabled, use perspective camera. If not enabled, use orthographic camera." +msgstr "" +"Se ativada, use a câmera em perspectiva. Se não estiver ativada, use a " +"câmera ortográfica." + +#: src/slic3r/GUI/Preferences.cpp:117 +msgid "Use custom size for toolbar icons" +msgstr "Usar tamanho personalizado para ícones da barra de ferramentas" + +#: src/slic3r/GUI/Preferences.cpp:119 +msgid "If enabled, you can change size of toolbar icons manually." +msgstr "" +"Se ativado, você pode alterar o tamanho dos ícones da barra de ferramentas " +"manualmente." + +#: src/slic3r/GUI/Preferences.cpp:144 +#, c-format +msgid "You need to restart %s to make the changes effective." +msgstr "Você precisa reiniciar %s para tornar as alterações efetivas." + +#: src/slic3r/GUI/Preferences.cpp:192 +msgid "Icon size in a respect to the default size" +msgstr "Tamanho do ícone em relação ao tamanho padrão" + +#: src/slic3r/GUI/Preferences.cpp:207 +msgid "Select toolbar icon size in respect to the default one." +msgstr "" +"Selecione o tamanho do ícone da barra de ferramentas em relação ao padrão." + +#: src/slic3r/GUI/Preset.cpp:212 +msgid "modified" +msgstr "modificado" + +#: src/slic3r/GUI/Preset.cpp:967 src/slic3r/GUI/Preset.cpp:1007 +#: src/slic3r/GUI/Preset.cpp:1072 src/slic3r/GUI/Preset.cpp:1104 +#: src/slic3r/GUI/PresetBundle.cpp:1484 src/slic3r/GUI/PresetBundle.cpp:1559 +msgid "System presets" +msgstr "Predefinições do sistema" + +#: src/slic3r/GUI/Preset.cpp:1011 src/slic3r/GUI/Preset.cpp:1108 +#: src/slic3r/GUI/PresetBundle.cpp:1564 +msgid "User presets" +msgstr "Predefinições do usuário" + +#: src/slic3r/GUI/Preset.cpp:1040 src/slic3r/GUI/Tab.cpp:243 +msgid "Add a new printer" +msgstr "Adicionar uma nova impressora" + +#: src/slic3r/GUI/Preset.cpp:1312 +msgid "filament" +msgstr "filamento" + +#: src/slic3r/GUI/Preset.cpp:1313 +msgid "SLA print" +msgstr "Impressão de SLA" + +#: src/slic3r/GUI/PresetHints.cpp:28 +msgid "" +"If estimated layer time is below ~%1%s, fan will run at %2%%% and print " +"speed will be reduced so that no less than %3%s are spent on that layer " +"(however, speed will never be reduced below %4%mm/s)." +msgstr "" +"Se o tempo estimado da camada estiver abaixo de ~%1%s, o ventoinha será " +"executado em %2%%% e a velocidade de impressão será reduzida para que não " +"menos de %3%s sejam gastos nessa camada (no entanto, a velocidade nunca será " +"reduzida abaixo de %4% mm/s)." + +#: src/slic3r/GUI/PresetHints.cpp:35 +msgid "" +"\n" +"If estimated layer time is greater, but still below ~%1%s, fan will run at a " +"proportionally decreasing speed between %2%%% and %3%%%." +msgstr "" +"\n" +"Se o tempo estimado da camada for maior, mas ainda abaixo de ~%1%s, o " +"ventoinha será executado em uma velocidade proporcionalmente decrescente " +"entre %2%%% e %3%%%." + +#: src/slic3r/GUI/PresetHints.cpp:39 +msgid "" +"\n" +"During the other layers, fan" +msgstr "" +"\n" +"Durante as outras camadas, o ventoinha" + +#: src/slic3r/GUI/PresetHints.cpp:41 +msgid "Fan" +msgstr "Ventoinha" + +#: src/slic3r/GUI/PresetHints.cpp:47 +msgid "will always run at %1%%%" +msgstr "será sempre executado em %1%%%" + +#: src/slic3r/GUI/PresetHints.cpp:50 +msgid "except for the first %1% layers." +msgstr "exceto para as primeiras camadas %1%." + +#: src/slic3r/GUI/PresetHints.cpp:52 +msgid "except for the first layer." +msgstr "exceto para a primeira camada." + +#: src/slic3r/GUI/PresetHints.cpp:54 +msgid "will be turned off." +msgstr "será desligado." + +#: src/slic3r/GUI/PresetHints.cpp:155 +msgid "external perimeters" +msgstr "perímetros externos" + +#: src/slic3r/GUI/PresetHints.cpp:164 +msgid "perimeters" +msgstr "perímetros" + +#: src/slic3r/GUI/PresetHints.cpp:173 +msgid "infill" +msgstr "preenchimento" + +#: src/slic3r/GUI/PresetHints.cpp:183 +msgid "solid infill" +msgstr "preenchimento sólido" + +#: src/slic3r/GUI/PresetHints.cpp:191 +msgid "top solid infill" +msgstr "preenchimento sólido do topo" + +#: src/slic3r/GUI/PresetHints.cpp:202 +msgid "support" +msgstr "suporte" + +#: src/slic3r/GUI/PresetHints.cpp:212 +msgid "support interface" +msgstr "interface de suporte" + +#: src/slic3r/GUI/PresetHints.cpp:218 +msgid "First layer volumetric" +msgstr "Primeira camada volumétrica" + +#: src/slic3r/GUI/PresetHints.cpp:218 +msgid "Bridging volumetric" +msgstr "Ponteamento volumétrico" + +#: src/slic3r/GUI/PresetHints.cpp:218 +msgid "Volumetric" +msgstr "Volumétrica" + +#: src/slic3r/GUI/PresetHints.cpp:219 +msgid "flow rate is maximized" +msgstr "a taxa de fluxo é maximizada" + +#: src/slic3r/GUI/PresetHints.cpp:222 +msgid "by the print profile maximum" +msgstr "pelo perfil de impressão máximo" + +#: src/slic3r/GUI/PresetHints.cpp:223 +msgid "when printing" +msgstr "ao imprimir" + +#: src/slic3r/GUI/PresetHints.cpp:224 +msgid "with a volumetric rate" +msgstr "com uma taxa volumétrica" + +#: src/slic3r/GUI/PresetHints.cpp:228 +#, c-format +msgid "%3.2f mm³/s at filament speed %3.2f mm/s." +msgstr "%3.2f mm ³/s na velocidade do filamento %3.2f mm/s." + +#: src/slic3r/GUI/PresetHints.cpp:246 +msgid "" +"Recommended object thin wall thickness: Not available due to invalid layer " +"height." +msgstr "" +"Espessura de parede fina do objeto recomendado: não disponível devido à " +"altura da camada inválida." + +#: src/slic3r/GUI/PresetHints.cpp:262 +#, c-format +msgid "Recommended object thin wall thickness for layer height %.2f and" +msgstr "" +"Espessura de parede fina do objeto recomendado para a altura da camada %.2f e" + +#: src/slic3r/GUI/PresetHints.cpp:268 +#, c-format +msgid "%d lines: %.2f mm" +msgstr "%d linhas: %.2f mm" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:33 +msgid "Send G-Code to printer host" +msgstr "Enviar G-code para o host da impressora" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:33 +msgid "Upload to Printer Host with the following filename:" +msgstr "Carregue para o host da impressora com o seguinte nome de arquivo:" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:35 +msgid "Start printing after upload" +msgstr "Iniciar a impressão após o envio" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:42 +msgid "Use forward slashes ( / ) as a directory separator if needed." +msgstr "Use barras (/) como um separador de diretório, se necessário." + +#: src/slic3r/GUI/PrintHostDialogs.cpp:149 +msgid "ID" +msgstr "ID" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:150 +msgid "Progress" +msgstr "Progresso" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:151 +msgid "Status" +msgstr "Status" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:152 +msgid "Host" +msgstr "Servidor" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:153 +msgid "Filename" +msgstr "Nome do arquivo" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:154 +msgid "Error Message" +msgstr "Mensagem de Erro" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:157 +msgid "Cancel selected" +msgstr "Cancelar selecionado" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:159 +msgid "Show error message" +msgstr "Exibir mensagem de erro" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:198 +#: src/slic3r/GUI/PrintHostDialogs.cpp:229 +msgid "Enqueued" +msgstr "Enfileirado" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:230 +msgid "Uploading" +msgstr "Enviando" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:234 +msgid "Completed" +msgstr "Concluído" + +#: src/slic3r/GUI/PrintHostDialogs.cpp:272 +msgid "Error uploading to print host:" +msgstr "Erro ao carregar para o host de impressão:" + +#: src/slic3r/GUI/RammingChart.cpp:23 +msgid "NO RAMMING AT ALL" +msgstr "Não usar Ramming" + +#: src/slic3r/GUI/RammingChart.cpp:76 +msgid "Time" +msgstr "Tempo" + +#: src/slic3r/GUI/RammingChart.cpp:76 src/slic3r/GUI/WipeTowerDialog.cpp:82 +#: 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:2426 src/libslic3r/PrintConfig.cpp:2434 +#: src/libslic3r/PrintConfig.cpp:2441 src/libslic3r/PrintConfig.cpp:2449 +#: src/libslic3r/PrintConfig.cpp:2457 +msgid "s" +msgstr "s" + +#: src/slic3r/GUI/RammingChart.cpp:81 +msgid "Volumetric speed" +msgstr "Velocidade volumétrica" + +#: src/slic3r/GUI/RammingChart.cpp:81 src/libslic3r/PrintConfig.cpp:584 +#: src/libslic3r/PrintConfig.cpp:1234 +msgid "mm³/s" +msgstr "mm ³/s" + +#: src/slic3r/GUI/Selection.cpp:146 +msgid "Selection-Add" +msgstr "Seleção-Adicionar" + +#: src/slic3r/GUI/Selection.cpp:187 +msgid "Selection-Remove" +msgstr "Seleção-remover" + +#: src/slic3r/GUI/Selection.cpp:219 +msgid "Selection-Add Object" +msgstr "Seleção-Adicionar objeto" + +#: src/slic3r/GUI/Selection.cpp:238 +msgid "Selection-Remove Object" +msgstr "Seleção-remover objeto" + +#: src/slic3r/GUI/Selection.cpp:256 +msgid "Selection-Add Instance" +msgstr "Instância de seleção-Adicionar" + +#: src/slic3r/GUI/Selection.cpp:275 +msgid "Selection-Remove Instance" +msgstr "Seleção-remover instância" + +#: src/slic3r/GUI/Selection.cpp:376 +msgid "Selection-Add All" +msgstr "Seleção-adicionar todos" + +#: src/slic3r/GUI/Selection.cpp:402 +msgid "Selection-Remove All" +msgstr "Seleção-remover todos" + +#: src/slic3r/GUI/Selection.cpp:939 +msgid "Scale To Fit" +msgstr "Dimensionar para caber" + +#: src/slic3r/GUI/Selection.cpp:1474 +msgid "Set Printable Instance" +msgstr "Definir instância imprimível" + +#: src/slic3r/GUI/Selection.cpp:1474 +msgid "Set Unprintable Instance" +msgstr "Definir instância não imprimível" + +#: src/slic3r/GUI/SysInfoDialog.cpp:78 +msgid "System Information" +msgstr "Informações do sistema" + +#: src/slic3r/GUI/SysInfoDialog.cpp:154 +msgid "Copy to Clipboard" +msgstr "Copiar para a Área de Transferência" + +#: src/slic3r/GUI/Tab.cpp:52 src/libslic3r/PrintConfig.cpp:239 +msgid "Compatible printers" +msgstr "Impressoras compatíveis" + +#: src/slic3r/GUI/Tab.cpp:53 +msgid "Select the printers this profile is compatible with." +msgstr "Selecione as impressoras com as quais este perfil é compatível." + +#: src/slic3r/GUI/Tab.cpp:58 src/libslic3r/PrintConfig.cpp:254 +msgid "Compatible print profiles" +msgstr "Perfis de impressão compatíveis" + +#: src/slic3r/GUI/Tab.cpp:59 +msgid "Select the print profiles this profile is compatible with." +msgstr "" +"Selecione os perfis de impressão com os quais este perfil é compatível." + +#. TRN "Save current Settings" +#: src/slic3r/GUI/Tab.cpp:135 +#, c-format +msgid "Save current %s" +msgstr "Salvar %s atual" + +#: src/slic3r/GUI/Tab.cpp:136 +msgid "Delete this preset" +msgstr "Exclua esta predefinição" + +#: src/slic3r/GUI/Tab.cpp:141 +msgid "" +"Hover the cursor over buttons to find more information \n" +"or click this button." +msgstr "" +"Passe o cursor sobre os botões para encontrar mais informações \n" +"ou clique neste botão." + +#: src/slic3r/GUI/Tab.cpp:943 +msgid "This is a default preset." +msgstr "Esta é uma predefinição padrão." + +#: src/slic3r/GUI/Tab.cpp:945 +msgid "This is a system preset." +msgstr "Esta é uma predefinição do sistema." + +#: src/slic3r/GUI/Tab.cpp:947 +msgid "Current preset is inherited from the default preset." +msgstr "Predefinição atual é herdada da predefinição padrão." + +#: src/slic3r/GUI/Tab.cpp:950 +#, c-format +msgid "" +"Current preset is inherited from:\n" +"\t%s" +msgstr "" +"Predefinição atual é herdada de:\n" +"\t%s" + +#: src/slic3r/GUI/Tab.cpp:954 +msgid "It can't be deleted or modified." +msgstr "Ele não pode ser excluído ou modificado." + +#: src/slic3r/GUI/Tab.cpp:955 +msgid "" +"Any modifications should be saved as a new preset inherited from this one." +msgstr "" +"Todas as modificações devem ser salvas como uma nova predefinição herdada de " +"uma presente." + +#: src/slic3r/GUI/Tab.cpp:956 +msgid "To do that please specify a new name for the preset." +msgstr "Para fazer isso, especifique um novo nome para a predefinição." + +#: src/slic3r/GUI/Tab.cpp:960 +msgid "Additional information:" +msgstr "Informações adicionais:" + +#: src/slic3r/GUI/Tab.cpp:966 +msgid "printer model" +msgstr "modelo de impressora" + +#: src/slic3r/GUI/Tab.cpp:974 +msgid "default print profile" +msgstr "perfil de impressão padrão" + +#: src/slic3r/GUI/Tab.cpp:977 +msgid "default filament profile" +msgstr "perfil de filamento padrão" + +#: src/slic3r/GUI/Tab.cpp:991 +msgid "default SLA material profile" +msgstr "perfil de material SLA padrão" + +#: src/slic3r/GUI/Tab.cpp:995 +msgid "default SLA print profile" +msgstr "perfil de impressão padrão do SLA" + +#: src/slic3r/GUI/Tab.cpp:1032 src/slic3r/GUI/Tab.cpp:3731 +msgid "Layers and perimeters" +msgstr "Camadas e perímetros" + +#: src/slic3r/GUI/Tab.cpp:1037 +msgid "Vertical shells" +msgstr "Paredes verticais" + +#: src/slic3r/GUI/Tab.cpp:1048 +msgid "Horizontal shells" +msgstr "Paredes horizontais" + +#: src/slic3r/GUI/Tab.cpp:1049 src/libslic3r/PrintConfig.cpp:1759 +msgid "Solid layers" +msgstr "Camadas sólidas" + +#: src/slic3r/GUI/Tab.cpp:1054 +msgid "Quality (slower slicing)" +msgstr "Qualidade (fatiamento mais lento)" + +#: src/slic3r/GUI/Tab.cpp:1072 +msgid "Reducing printing time" +msgstr "Reduzindo o tempo de impressão" + +#: src/slic3r/GUI/Tab.cpp:1084 +msgid "Skirt and brim" +msgstr "Saia e aba" + +#: src/slic3r/GUI/Tab.cpp:1101 +msgid "Raft" +msgstr "Estrado" + +#: src/slic3r/GUI/Tab.cpp:1105 +msgid "Options for support material and raft" +msgstr "Opções para material de suporte e estrado" + +#: src/slic3r/GUI/Tab.cpp:1120 +msgid "Speed for print moves" +msgstr "Velocidade para movimentos de impressão" + +#: src/slic3r/GUI/Tab.cpp:1132 +msgid "Speed for non-print moves" +msgstr "Velocidade para movimentos não impressos" + +#: src/slic3r/GUI/Tab.cpp:1135 +msgid "Modifiers" +msgstr "Modificadores" + +#: src/slic3r/GUI/Tab.cpp:1138 +msgid "Acceleration control (advanced)" +msgstr "Controle de aceleração (avançado)" + +#: src/slic3r/GUI/Tab.cpp:1145 +msgid "Autospeed (advanced)" +msgstr "Velocidade automática (avançado)" + +#: src/slic3r/GUI/Tab.cpp:1153 +msgid "Multiple Extruders" +msgstr "Extrusoras múltiplas" + +#: src/slic3r/GUI/Tab.cpp:1161 +msgid "Ooze prevention" +msgstr "Prevenção de vazão" + +#: src/slic3r/GUI/Tab.cpp:1178 +msgid "Extrusion width" +msgstr "Espessura da extrusão" + +#: src/slic3r/GUI/Tab.cpp:1188 +msgid "Overlap" +msgstr "Cobrir" + +#: src/slic3r/GUI/Tab.cpp:1191 +msgid "Flow" +msgstr "Fluxo" + +#: src/slic3r/GUI/Tab.cpp:1200 +msgid "Other" +msgstr "Outro" + +#: src/slic3r/GUI/Tab.cpp:1203 src/slic3r/GUI/Tab.cpp:3789 +msgid "Output options" +msgstr "Opções de saída" + +#: src/slic3r/GUI/Tab.cpp:1204 +msgid "Sequential printing" +msgstr "Impressão sequencial" + +#: src/slic3r/GUI/Tab.cpp:1206 +msgid "Extruder clearance (mm)" +msgstr "Folga da extrusora (milímetro)" + +#: src/slic3r/GUI/Tab.cpp:1215 src/slic3r/GUI/Tab.cpp:3790 +msgid "Output file" +msgstr "Arquivo de saída" + +#: src/slic3r/GUI/Tab.cpp:1222 src/libslic3r/PrintConfig.cpp:1432 +msgid "Post-processing scripts" +msgstr "Scripts de pós-processamento" + +#: src/slic3r/GUI/Tab.cpp:1228 src/slic3r/GUI/Tab.cpp:1229 +#: src/slic3r/GUI/Tab.cpp:1752 src/slic3r/GUI/Tab.cpp:1753 +#: src/slic3r/GUI/Tab.cpp:2214 src/slic3r/GUI/Tab.cpp:2215 +#: src/slic3r/GUI/Tab.cpp:2328 src/slic3r/GUI/Tab.cpp:2329 +#: src/slic3r/GUI/Tab.cpp:3668 src/slic3r/GUI/Tab.cpp:3669 +msgid "Notes" +msgstr "Notas" + +#: src/slic3r/GUI/Tab.cpp:1235 src/slic3r/GUI/Tab.cpp:1760 +#: src/slic3r/GUI/Tab.cpp:2221 src/slic3r/GUI/Tab.cpp:2335 +#: src/slic3r/GUI/Tab.cpp:3676 src/slic3r/GUI/Tab.cpp:3795 +msgid "Dependencies" +msgstr "Dependências" + +#: src/slic3r/GUI/Tab.cpp:1236 src/slic3r/GUI/Tab.cpp:1761 +#: src/slic3r/GUI/Tab.cpp:2222 src/slic3r/GUI/Tab.cpp:2336 +#: src/slic3r/GUI/Tab.cpp:3677 src/slic3r/GUI/Tab.cpp:3796 +msgid "Profile dependencies" +msgstr "Dependências de perfil" + +#: src/slic3r/GUI/Tab.cpp:1538 src/slic3r/GUI/Tab.cpp:1593 +msgid "Filament Overrides" +msgstr "Sobrescrever config." + +#: src/slic3r/GUI/Tab.cpp:1539 src/slic3r/GUI/Tab.cpp:1598 +#: src/slic3r/GUI/Tab.cpp:2570 +msgid "Retraction" +msgstr "Retração" + +#: src/slic3r/GUI/Tab.cpp:1648 src/libslic3r/PrintConfig.cpp:2030 +msgid "Temperature" +msgstr "Temperatura" + +#: src/slic3r/GUI/Tab.cpp:1654 +msgid "Bed" +msgstr "Mesa" + +#: src/slic3r/GUI/Tab.cpp:1659 +msgid "Cooling" +msgstr "Resfriamento" + +#: src/slic3r/GUI/Tab.cpp:1660 src/libslic3r/PrintConfig.cpp:1335 +#: src/libslic3r/PrintConfig.cpp:2150 +msgid "Enable" +msgstr "Habilitar" + +#: src/slic3r/GUI/Tab.cpp:1671 +msgid "Fan settings" +msgstr "Config. da ventoinha" + +#: src/slic3r/GUI/Tab.cpp:1672 +msgid "Fan speed" +msgstr "Velocidade do ventoinha" + +#: src/slic3r/GUI/Tab.cpp:1680 +msgid "Cooling thresholds" +msgstr "Limiares de resfriamento" + +#: src/slic3r/GUI/Tab.cpp:1686 +msgid "Filament properties" +msgstr "Propriedades de filamento" + +#: src/slic3r/GUI/Tab.cpp:1690 +msgid "Print speed override" +msgstr "Substituição da velocidade de impressão" + +#: src/slic3r/GUI/Tab.cpp:1700 +msgid "Wipe tower parameters" +msgstr "Parâmetros da torre de limpeza" + +#: src/slic3r/GUI/Tab.cpp:1703 +msgid "Toolchange parameters with single extruder MM printers" +msgstr "" +"Parâmetros de mudança de ferramenta com impressoras de multi material com " +"apenas uma extrusora" + +#: src/slic3r/GUI/Tab.cpp:1717 +msgid "Ramming settings" +msgstr "config. de Ramming" + +#: src/slic3r/GUI/Tab.cpp:1739 src/slic3r/GUI/Tab.cpp:2177 +msgid "Custom G-code" +msgstr "G-code customizado" + +#: src/slic3r/GUI/Tab.cpp:1740 src/slic3r/GUI/Tab.cpp:2178 +#: src/libslic3r/PrintConfig.cpp:1785 src/libslic3r/PrintConfig.cpp:1800 +msgid "Start G-code" +msgstr "G-code de início" + +#: src/slic3r/GUI/Tab.cpp:1746 src/slic3r/GUI/Tab.cpp:2184 +#: src/libslic3r/PrintConfig.cpp:369 src/libslic3r/PrintConfig.cpp:379 +msgid "End G-code" +msgstr "G-code de finalização" + +#: src/slic3r/GUI/Tab.cpp:1803 +msgid "Volumetric flow hints not available" +msgstr "Dicas de fluxo volumétrico não disponíveis" + +#: src/slic3r/GUI/Tab.cpp:1889 src/slic3r/GUI/Tab.cpp:2117 +msgid "Test" +msgstr "Teste" + +#: src/slic3r/GUI/Tab.cpp:1899 +msgid "Could not get a valid Printer Host reference" +msgstr "Não foi possível obter uma referência de host de impressora válida" + +#: src/slic3r/GUI/Tab.cpp:1905 src/slic3r/GUI/Tab.cpp:2130 +msgid "Success!" +msgstr "Sucesso!" + +#: src/slic3r/GUI/Tab.cpp:1920 +msgid "" +"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" +"signed certificate." +msgstr "" +"O arquivo HTTPS CA é opcional. Só é necessário se você usar HTTPS com um " +"certificado auto-assinado." + +#: src/slic3r/GUI/Tab.cpp:1933 +msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +msgstr "" +"Arquivos de certificado (*. CRT, *. pem) | *. CRT; *. pem | Todos os " +"arquivos | *. *" + +#: src/slic3r/GUI/Tab.cpp:1934 +msgid "Open CA certificate file" +msgstr "Abra o arquivo de certificado da CA" + +#: src/slic3r/GUI/Tab.cpp:1962 +#, c-format +msgid "" +"HTTPS CA File:\n" +" \tOn this system, %s uses HTTPS certificates from the system Certificate " +"Store or Keychain.\n" +" \tTo use a custom CA file, please import your CA file into Certificate " +"Store / Keychain." +msgstr "" +"Arquivo HTTPS CA:\n" +" \tNeste sistema, %s usa certificados HTTPS do sistema Certificate Store " +"ou keychain.\n" +" \tPara usar um arquivo de CA personalizado, importe seu arquivo de CA " +"para o repositório de certificados/chaveiro." + +#: src/slic3r/GUI/Tab.cpp:2002 src/slic3r/GUI/Tab.cpp:2243 +msgid "Size and coordinates" +msgstr "Tamanho e coordenadas" + +#: src/slic3r/GUI/Tab.cpp:2007 src/slic3r/GUI/Tab.cpp:2248 +#: src/slic3r/GUI/Tab.cpp:3338 +msgid "Set" +msgstr "Definir" + +#: src/slic3r/GUI/Tab.cpp:2039 +msgid "Capabilities" +msgstr "Capacidades" + +#: src/slic3r/GUI/Tab.cpp:2044 +msgid "Number of extruders of the printer." +msgstr "Número de extrusoras da impressora." + +#: src/slic3r/GUI/Tab.cpp:2069 +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 "" +"A extrusora multi material é selecionada, \n" +"e todas as extrusoras devem ter o mesmo diâmetro.\n" +"Você quer mudar o diâmetro para todas as extrusoras ao primeiro valor do " +"diâmetro da ponteira da extrusora?" + +#: src/slic3r/GUI/Tab.cpp:2072 src/slic3r/GUI/Tab.cpp:2540 +#: src/libslic3r/PrintConfig.cpp:1310 +msgid "Nozzle diameter" +msgstr "Diâmetro do bico" + +#: src/slic3r/GUI/Tab.cpp:2102 +msgid "USB/Serial connection" +msgstr "Conexão USB/serial" + +#: src/slic3r/GUI/Tab.cpp:2103 src/libslic3r/PrintConfig.cpp:1640 +msgid "Serial port" +msgstr "Porte Serial" + +#: src/slic3r/GUI/Tab.cpp:2108 +msgid "Rescan serial ports" +msgstr "Portas seriais de Rescan" + +#: src/slic3r/GUI/Tab.cpp:2130 +msgid "Connection to printer works correctly." +msgstr "A ligação à impressora funciona corretamente." + +#: src/slic3r/GUI/Tab.cpp:2133 +msgid "Connection failed." +msgstr "A conexão falhou." + +#: src/slic3r/GUI/Tab.cpp:2146 src/slic3r/GUI/Tab.cpp:2323 +msgid "Print Host upload" +msgstr "Upload do host de impressão" + +#: src/slic3r/GUI/Tab.cpp:2190 src/libslic3r/PrintConfig.cpp:138 +msgid "Before layer change G-code" +msgstr "Antes da mudança de camada G-code" + +#: src/slic3r/GUI/Tab.cpp:2196 src/libslic3r/PrintConfig.cpp:1056 +msgid "After layer change G-code" +msgstr "Após a mudança da camada do G-code" + +#: src/slic3r/GUI/Tab.cpp:2202 src/libslic3r/PrintConfig.cpp:2056 +msgid "Tool change G-code" +msgstr "G-code de troca de ferramenta" + +#: src/slic3r/GUI/Tab.cpp:2208 +msgid "Between objects G-code (for sequential printing)" +msgstr "G-code entre objetos (para impressão sequencial)" + +#: src/slic3r/GUI/Tab.cpp:2280 +msgid "Display" +msgstr "Exibição" + +#: src/slic3r/GUI/Tab.cpp:2295 +msgid "Tilt" +msgstr "Inclinar" + +#: src/slic3r/GUI/Tab.cpp:2296 +msgid "Tilt time" +msgstr "Tempo de inclinação" + +#: src/slic3r/GUI/Tab.cpp:2302 src/slic3r/GUI/Tab.cpp:3650 +msgid "Corrections" +msgstr "Correções" + +#: src/slic3r/GUI/Tab.cpp:2317 src/slic3r/GUI/Tab.cpp:3646 +msgid "Exposure" +msgstr "Exposição" + +#: src/slic3r/GUI/Tab.cpp:2388 src/slic3r/GUI/Tab.cpp:2473 +#: 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 "Limites da máquina" + +#: src/slic3r/GUI/Tab.cpp:2402 +msgid "Values in this column are for Normal mode" +msgstr "Valores nesta coluna são para o modo normal" + +#: src/slic3r/GUI/Tab.cpp:2403 +msgid "Normal" +msgstr "Normal" + +#: src/slic3r/GUI/Tab.cpp:2408 +msgid "Values in this column are for Stealth mode" +msgstr "Valores nesta coluna são para o modo furtivo" + +#: src/slic3r/GUI/Tab.cpp:2409 +msgid "Stealth" +msgstr "Furtivo" + +#: src/slic3r/GUI/Tab.cpp:2417 +msgid "Maximum feedrates" +msgstr "Velocidade máxima de alimentação" + +#: src/slic3r/GUI/Tab.cpp:2422 +msgid "Maximum accelerations" +msgstr "Acelerações máximas" + +#: src/slic3r/GUI/Tab.cpp:2429 +msgid "Jerk limits" +msgstr "Limites de empurrão" + +#: src/slic3r/GUI/Tab.cpp:2434 +msgid "Minimum feedrates" +msgstr "Velocidades alimentação mínimos" + +#: src/slic3r/GUI/Tab.cpp:2498 src/slic3r/GUI/Tab.cpp:2506 +msgid "Single extruder MM setup" +msgstr "config. de extrusora multi material" + +#: src/slic3r/GUI/Tab.cpp:2507 +msgid "Single extruder multimaterial parameters" +msgstr "Parâmetros para extrusora única multimaterial" + +#: src/slic3r/GUI/Tab.cpp:2520 src/libslic3r/GCode/PreviewData.cpp:461 +#, c-format +msgid "Extruder %d" +msgstr "Extrusora %d" + +#: src/slic3r/GUI/Tab.cpp:2538 +msgid "" +"This is a single extruder multimaterial printer, diameters of all extruders " +"will be set to the new value. Do you want to proceed?" +msgstr "" +"Esta é uma única impressora multimaterial extrusora, diâmetros de todas as " +"extrusoras será definido para o novo valor. Você quer prosseguir?" + +#: src/slic3r/GUI/Tab.cpp:2562 +msgid "Layer height limits" +msgstr "Limites de altura da camada" + +#: src/slic3r/GUI/Tab.cpp:2567 +msgid "Position (for multi-extruder printers)" +msgstr "Posição (para impressoras multiextrusoras)" + +#: src/slic3r/GUI/Tab.cpp:2573 +msgid "Only lift Z" +msgstr "Apenas elevar Z" + +#: src/slic3r/GUI/Tab.cpp:2586 +msgid "" +"Retraction when tool is disabled (advanced settings for multi-extruder " +"setups)" +msgstr "" +"Retração quando a ferramenta está desativada (config. avançadas para " +"instalações multiextrusoras)" + +#: src/slic3r/GUI/Tab.cpp:2594 +msgid "Reset to Filament Color" +msgstr "Restabelecer cor do filamento" + +#: src/slic3r/GUI/Tab.cpp:2775 +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 "" +"A opção limpar não está disponível ao usar o modo de retração de firmware.\n" +"\n" +"Devo desativá-lo, a fim de permitir a retração de firmware?" + +#: src/slic3r/GUI/Tab.cpp:2777 +msgid "Firmware Retraction" +msgstr "Retração do firmware" + +#: src/slic3r/GUI/Tab.cpp:3106 +#, c-format +msgid "Default preset (%s)" +msgstr "Predefinição padrão ( %s)" + +#: src/slic3r/GUI/Tab.cpp:3107 +#, c-format +msgid "Preset (%s)" +msgstr "Predefinição ( %s)" + +#: src/slic3r/GUI/Tab.cpp:3124 +msgid "has the following unsaved changes:" +msgstr "tem as seguintes alterações não salvas:" + +#: src/slic3r/GUI/Tab.cpp:3127 +msgid "is not compatible with printer" +msgstr "não é compatível com a impressora" + +#: src/slic3r/GUI/Tab.cpp:3128 +msgid "is not compatible with print profile" +msgstr "não é compatível com o perfil de impressão" + +#: src/slic3r/GUI/Tab.cpp:3130 +msgid "and it has the following unsaved changes:" +msgstr "e tem as seguintes alterações não salvas:" + +#: src/slic3r/GUI/Tab.cpp:3134 +msgid "Unsaved Changes" +msgstr "Alterações não salvas" + +#: src/slic3r/GUI/Tab.cpp:3225 +msgid "%1% - Copy" +msgstr "%1% - cópia" + +#: src/slic3r/GUI/Tab.cpp:3248 +msgid "The supplied name is empty. It can't be saved." +msgstr "O nome fornecido está vazio. Não pode ser salvo." + +#: src/slic3r/GUI/Tab.cpp:3253 +msgid "Cannot overwrite a system profile." +msgstr "Não é possível substituir um perfil de sistema." + +#: src/slic3r/GUI/Tab.cpp:3257 +msgid "Cannot overwrite an external profile." +msgstr "Não é possível substituir um perfil externo." + +#: src/slic3r/GUI/Tab.cpp:3283 +msgid "remove" +msgstr "remover" + +#: src/slic3r/GUI/Tab.cpp:3283 +msgid "delete" +msgstr "excluir" + +#. TRN remove/delete +#: src/slic3r/GUI/Tab.cpp:3285 +msgid "Are you sure you want to %1% the selected preset?" +msgstr "Tem certeza de que deseja %1% da predefinição selecionada?" + +#. TRN Remove/Delete +#: src/slic3r/GUI/Tab.cpp:3288 +msgid "%1% Preset" +msgstr "%1% Predefinição" + +#: src/slic3r/GUI/Tab.cpp:3414 +msgid "LOCKED LOCK" +msgstr "CADEADO FECHADO" + +#. TRN Description for "LOCKED LOCK" +#: src/slic3r/GUI/Tab.cpp:3416 +msgid "" +"indicates that the settings are the same as the system (or default) values " +"for the current option group" +msgstr "" +"indica que as config. são as mesmas que os valores do sistema (ou padrão) " +"para o grupo de opções atual" + +#: src/slic3r/GUI/Tab.cpp:3418 +msgid "UNLOCKED LOCK" +msgstr "CADEADO ABERTO" + +#. TRN Description for "UNLOCKED LOCK" +#: src/slic3r/GUI/Tab.cpp:3420 +msgid "" +"indicates that some settings were changed and are not equal to the system " +"(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 (or default) values." +msgstr "" +"indica que algumas config. foram alteradas e não são iguais aos valores do " +"sistema (ou padrão) para o grupo de opções atual.\n" +"Clique no ícone DESBLOQUEAR para redefinir todas as config. do grupo de " +"opções atual para os valores do sistema (ou padrão)." + +#: src/slic3r/GUI/Tab.cpp:3425 +msgid "WHITE BULLET" +msgstr "PONTO BRANCO" + +#. TRN Description for "WHITE BULLET" +#: src/slic3r/GUI/Tab.cpp:3427 +msgid "" +"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 "" +"para o botão esquerdo: \t indica uma predefinição que não é do sistema (ou " +"não-padrão),\n" +"para o botão direito: \t indica que as config. não foram modificadas." + +#: src/slic3r/GUI/Tab.cpp:3430 +msgid "BACK ARROW" +msgstr "REDEFINIR" + +#. TRN Description for "BACK ARROW" +#: src/slic3r/GUI/Tab.cpp:3432 +msgid "" +"indicates that the settings were changed and are not equal to the last saved " +"preset for the current option group.\n" +"Click the BACK ARROW icon to reset all settings for the current option group " +"to the last saved preset." +msgstr "" +"indica que as config. foram alteradas e não são iguais à última predefinição " +"salva para o grupo de opções atual.\n" +"Clique no ícone REDEFINIR para redefinir todas as config. do grupo de opções " +"atual para a última predefinição salva." + +#: src/slic3r/GUI/Tab.cpp:3442 +msgid "" +"LOCKED LOCK icon indicates that the settings are the same as the system (or " +"default) values for the current option group" +msgstr "" +"O ícone CADEADO FECHADO indica que as config. são as mesmas que os valores " +"do sistema (ou padrão) para o grupo de opções atual" + +#: src/slic3r/GUI/Tab.cpp:3444 +msgid "" +"UNLOCKED LOCK icon indicates that some settings were changed and are not " +"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 "" +"O ícone de CADEADO ABERTO indica que algumas config. foram alteradas e não " +"são iguais aos valores do sistema (ou padrão) para o grupo de opções atual.\n" +"Clique para redefinir todas as config. para o grupo de opções atual para os " +"valores do sistema (ou padrão)." + +#: src/slic3r/GUI/Tab.cpp:3447 +msgid "WHITE BULLET icon indicates a non system (or non default) preset." +msgstr "" +"O ícone PONTO BRANCO indica uma predefinição que não é do sistema (ou não " +"predefinida)." + +#: src/slic3r/GUI/Tab.cpp:3450 +msgid "" +"WHITE BULLET icon indicates that the settings are the same as in the last " +"saved preset for the current option group." +msgstr "" +"O ícone PONTO BRANCO indica que as config. são as mesmas da última " +"predefinição salva para o grupo de opções atual." + +#: src/slic3r/GUI/Tab.cpp:3452 +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" +"Click to reset all settings for the current option group to the last saved " +"preset." +msgstr "" +"O ícone de REDEFINIR indica que as config. foram alteradas e não são iguais " +"à última predefinição salva para o grupo de opções atual.\n" +"Clique para redefinir todas as config. do grupo de opções atual para a " +"última predefinição salva." + +#: src/slic3r/GUI/Tab.cpp:3458 +msgid "" +"LOCKED LOCK icon indicates that the value is the same as the system (or " +"default) value." +msgstr "" +"O ícone CADEADO FECHADO indica que o valor é o mesmo que o valor do sistema " +"(ou padrão)." + +#: src/slic3r/GUI/Tab.cpp:3459 +msgid "" +"UNLOCKED LOCK icon indicates that the value was changed and is not equal to " +"the system (or default) value.\n" +"Click to reset current value to the system (or default) value." +msgstr "" +"O ícone de CADEADO ABERTO indica que o valor foi alterado e não é igual ao " +"valor do sistema (ou padrão).\n" +"Clique para redefinir o valor atual para o valor do sistema (ou padrão)." + +#: src/slic3r/GUI/Tab.cpp:3465 +msgid "" +"WHITE BULLET icon indicates that the value is the same as in the last saved " +"preset." +msgstr "" +"O ícone PONTO BRANCO indica que o valor é o mesmo da última predefinição " +"guardada." + +#: src/slic3r/GUI/Tab.cpp:3466 +msgid "" +"BACK ARROW icon indicates that the value was changed and is not equal to the " +"last saved preset.\n" +"Click to reset current value to the last saved preset." +msgstr "" +"O ícone de REDEFINIR indica que o valor foi alterado e não é igual à última " +"predefinição salva.\n" +"Clique para redefinir o valor atual para a última predefinição salva." + +#. TRN Preset +#: src/slic3r/GUI/Tab.cpp:3579 +#, c-format +msgid "Save %s as:" +msgstr "Salvar %s como:" + +#: src/slic3r/GUI/Tab.cpp:3623 +msgid "the following suffix is not allowed:" +msgstr "o sufixo seguinte não é permitido:" + +#: src/slic3r/GUI/Tab.cpp:3627 +msgid "The supplied name is not available." +msgstr "O nome fornecido não está disponível." + +#: src/slic3r/GUI/Tab.cpp:3640 +msgid "Material" +msgstr "Material" + +#: src/slic3r/GUI/Tab.cpp:3642 src/slic3r/GUI/Tab.cpp:3733 +#: src/slic3r/GUI/wxExtensions.cpp:482 +msgid "Layers" +msgstr "Camadas" + +#: src/slic3r/GUI/Tab.cpp:3741 +msgid "Support head" +msgstr "Cabeça de suporte" + +#: src/slic3r/GUI/Tab.cpp:3746 +msgid "Support pillar" +msgstr "Pilar de suporte" + +#: src/slic3r/GUI/Tab.cpp:3760 +msgid "Connection of the support sticks and junctions" +msgstr "Conexão das varas de suporte e junções" + +#: src/slic3r/GUI/Tab.cpp:3765 +msgid "Automatic generation" +msgstr "Geração Automática" + +#: src/slic3r/GUI/Tab.hpp:328 src/slic3r/GUI/Tab.hpp:428 +msgid "Print Settings" +msgstr "Config. de impressão" + +#: src/slic3r/GUI/Tab.hpp:353 +msgid "Filament Settings" +msgstr "Config. de filamento" + +#: src/slic3r/GUI/Tab.hpp:389 +msgid "Printer Settings" +msgstr "Config. da impressora" + +#: src/slic3r/GUI/Tab.hpp:413 +msgid "Material Settings" +msgstr "Config. de material" + +#: src/slic3r/GUI/Tab.hpp:440 +msgid "Save preset" +msgstr "Salvar predefinição" + +#: src/slic3r/GUI/UpdateDialogs.cpp:38 +msgid "Update available" +msgstr "Atualização disponível" + +#: src/slic3r/GUI/UpdateDialogs.cpp:38 +#, c-format +msgid "New version of %s is available" +msgstr "Nova versão do %s está disponível" + +#: src/slic3r/GUI/UpdateDialogs.cpp:45 +msgid "Current version:" +msgstr "Versão atual:" + +#: src/slic3r/GUI/UpdateDialogs.cpp:47 +msgid "New version:" +msgstr "Nova versão:" + +#: src/slic3r/GUI/UpdateDialogs.cpp:55 +msgid "Changelog && Download" +msgstr "Changelog && Download" + +#: src/slic3r/GUI/UpdateDialogs.cpp:62 src/slic3r/GUI/UpdateDialogs.cpp:127 +msgid "Open changelog page" +msgstr "Abra a página do changelog" + +#: src/slic3r/GUI/UpdateDialogs.cpp:67 +msgid "Open download page" +msgstr "Abrir página de download" + +#: src/slic3r/GUI/UpdateDialogs.cpp:73 +msgid "Don't notify about new releases any more" +msgstr "Não notifique mais sobre novas versões" + +#: src/slic3r/GUI/UpdateDialogs.cpp:91 src/slic3r/GUI/UpdateDialogs.cpp:207 +msgid "Configuration update" +msgstr "Atualização de config." + +#: src/slic3r/GUI/UpdateDialogs.cpp:91 +msgid "Configuration update is available" +msgstr "A atualização de config. está disponível" + +#: src/slic3r/GUI/UpdateDialogs.cpp:94 +msgid "" +"Would you like to install it?\n" +"\n" +"Note that a full configuration snapshot will be created first. It can then " +"be restored at any time should there be a problem with the new version.\n" +"\n" +"Updated configuration bundles:" +msgstr "" +"Gostaria de instalá-lo?\n" +"\n" +"Observe que uma captura da config. completa será criado primeiro. Ele pode " +"então ser restaurado a qualquer momento se houver um problema com a nova " +"versão.\n" +"\n" +"Pacotes de config. atualizados:" + +#: src/slic3r/GUI/UpdateDialogs.cpp:115 +msgid "Comment:" +msgstr "Comentário:" + +#: src/slic3r/GUI/UpdateDialogs.cpp:151 +#, c-format +msgid "%s incompatibility" +msgstr "%s incompatibilidade" + +#: src/slic3r/GUI/UpdateDialogs.cpp:152 +#, c-format +msgid "%s configuration is incompatible" +msgstr "%s config. é incompatível" + +#: src/slic3r/GUI/UpdateDialogs.cpp:157 +#, c-format +msgid "" +"This version of %s is not compatible with currently installed configuration " +"bundles.\n" +"This probably happened as a result of running an older %s after using a " +"newer one.\n" +"\n" +"You may either exit %s and try again with a newer version, or you may re-run " +"the initial configuration. Doing so will create a backup snapshot of the " +"existing configuration before installing files compatible with this %s.\n" +msgstr "" +"Esta versão do %s não é compatível com pacotes de config. atualmente " +"instalados.\n" +"Isso provavelmente aconteceu como resultado da execução de um %s mais antigo " +"depois de usar um mais recente.\n" +"\n" +"Você pode sair %s e tente novamente com uma versão mais recente, ou você " +"pode executar novamente a config. inicial. Isso criará um instantâneo de " +"backup da config. existente antes de instalar os arquivos compatíveis com " +"este %s.\n" + +#: src/slic3r/GUI/UpdateDialogs.cpp:166 +#, c-format +msgid "This %s version: %s" +msgstr "Esta versão %s : %s" + +#: src/slic3r/GUI/UpdateDialogs.cpp:171 +msgid "Incompatible bundles:" +msgstr "Pacotes incompatíveis:" + +#: src/slic3r/GUI/UpdateDialogs.cpp:187 +#, c-format +msgid "Exit %s" +msgstr "Saída %s" + +#: src/slic3r/GUI/UpdateDialogs.cpp:190 +msgid "Re-configure" +msgstr "Re-config.urar" + +#: src/slic3r/GUI/UpdateDialogs.cpp:211 +#, c-format +msgid "" +"%s now uses an updated configuration structure.\n" +"\n" +"So called 'System presets' have been introduced, which hold the built-in " +"default settings for various printers. These System presets cannot be " +"modified, instead, users now may create their own presets inheriting " +"settings from one of the System presets.\n" +"An inheriting preset may either inherit a particular value from its parent " +"or override it with a customized value.\n" +"\n" +"Please proceed with the %s that follows to set up the new presets and to " +"choose whether to enable automatic preset updates." +msgstr "" +"%s agora usa uma estrutura de config. atualizada.\n" +"\n" +"Assim chamado ' Predefinições do sistema ' foram introduzidas, que mantêm as " +"config. padrão internas para várias impressoras. Essas predefinições do " +"sistema não podem ser modificadas, em vez disso, os usuários agora podem " +"criar suas próprias predefinições herdando as config. de uma das " +"predefinições do sistema.\n" +"Uma predefinição herdada pode herdar um valor específico de seu pai ou " +"substituí-lo por um valor personalizado.\n" +"\n" +"Por favor, prossiga com o %s que se segue para config.urar as novas " +"predefinições e para escolher se deseja ativar as atualizações automáticas " +"predefinidas." + +#: src/slic3r/GUI/UpdateDialogs.cpp:227 +msgid "For more information please visit our wiki page:" +msgstr "Para mais informações, visite a nossa página wiki:" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:14 +msgid "Ramming customization" +msgstr "Personalização de Ramming" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:40 +msgid "" +"Ramming denotes the rapid extrusion just before a tool change in a single-" +"extruder MM printer. Its purpose is to properly shape the end of the " +"unloaded filament so it does not prevent insertion of the new filament and " +"can itself be reinserted later. This phase is important and different " +"materials can require different extrusion speeds to get the good shape. For " +"this reason, the extrusion rates during ramming are adjustable.\n" +"\n" +"This is an expert-level setting, incorrect adjustment will likely lead to " +"jams, extruder wheel grinding into filament etc." +msgstr "" +"O Ramming denota a extrusão rápida apenas antes que uma mudança da " +"ferramenta em uma única-extrusora a impressora de multifilamentos Sua " +"finalidade é moldar corretamente a extremidade do filamento descarregado " +"assim que não impede a inserção do filamento novo e pode próprio ser " +"reintroduzido mais tarde. Esta fase é importante e os materiais diferentes " +"podem exigir velocidades diferentes da extrusão para começ a boa forma. Por " +"esta razão, as taxas de extrusão durante a batendo são ajustáveis.\n" +"\n" +"Esta é uma config. de nível especialista, ajuste incorreto provavelmente " +"levará a compotas, roda extrusora moagem em filamento etc." + +#: src/slic3r/GUI/WipeTowerDialog.cpp:82 +msgid "Total ramming time" +msgstr "Tempo total de Ramming" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:84 +msgid "Total rammed volume" +msgstr "Volume total de Ramming" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:88 +msgid "Ramming line width" +msgstr "Largura da linha de Ramming" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:90 +msgid "Ramming line spacing" +msgstr "Espaçamento de linha de Ramming" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:141 +msgid "Wipe tower - Purging volume adjustment" +msgstr "Torre de limpeza - Ajuste de volume de purga" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:225 +msgid "" +"Here you can adjust required purging volume (mm³) for any given pair of " +"tools." +msgstr "" +"Aqui você pode ajustar o volume de purga necessário (mm ³) para qualquer par " +"dado de ferramentas." + +#: src/slic3r/GUI/WipeTowerDialog.cpp:226 +msgid "Extruder changed to" +msgstr "Extrusora alterada para" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:234 +msgid "unloaded" +msgstr "descarregado" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:235 +msgid "loaded" +msgstr "carregado" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:240 +msgid "Tool #" +msgstr "Ferramenta #" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:247 +msgid "" +"Total purging volume is calculated by summing two values below, depending on " +"which tools are loaded/unloaded." +msgstr "" +"O volume de purga total é calculado somando-se dois valores abaixo, " +"dependendo de quais ferramentas são carregadas/descarregadas." + +#: src/slic3r/GUI/WipeTowerDialog.cpp:248 +msgid "Volume to purge (mm³) when the filament is being" +msgstr "Volume a purgar (mm ³) quando o filamento está a ser" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:262 +msgid "From" +msgstr "De" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:327 +msgid "" +"Switching to simple settings will discard changes done in the advanced " +"mode!\n" +"\n" +"Do you want to proceed?" +msgstr "" +"Mudar para config. simples irá descartar as alterações feitas no modo " +"avançado!\n" +"\n" +"Você quer prosseguir?" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:339 +msgid "Show simplified settings" +msgstr "Mostrar config. simplificadas" + +#: src/slic3r/GUI/WipeTowerDialog.cpp:339 +msgid "Show advanced settings" +msgstr "Mostrar opções avançadas" + +#: src/slic3r/GUI/wxExtensions.cpp:471 +msgid "Instances" +msgstr "Instâncias" + +#: src/slic3r/GUI/wxExtensions.cpp:475 src/slic3r/GUI/wxExtensions.cpp:619 +#, c-format +msgid "Instance %d" +msgstr "Instância %d" + +#: src/slic3r/GUI/wxExtensions.cpp:509 +msgid "Range" +msgstr "Intervalo" + +#: src/slic3r/GUI/wxExtensions.cpp:2731 +msgid "One layer mode" +msgstr "Modo de uma camada" + +#: src/slic3r/GUI/wxExtensions.cpp:2732 +msgid "Add/Del color change" +msgstr "Add/Excluir mudança de cor" + +#: src/slic3r/GUI/wxExtensions.cpp:2733 +msgid "Discard all color changes" +msgstr "Descartar todas as alterações de cor" + +#: src/slic3r/GUI/wxExtensions.cpp:2993 +#, c-format +msgid "Switch to the %s mode" +msgstr "Mude para o modo %s" + +#: src/slic3r/GUI/wxExtensions.cpp:2994 +#, c-format +msgid "Current mode is %s" +msgstr "O modo atual é %s" + +#: src/slic3r/Utils/Duet.cpp:51 +msgid "Connection to Duet works correctly." +msgstr "A conexão com o Duet funciona corretamente." + +#: src/slic3r/Utils/Duet.cpp:56 +msgid "Could not connect to Duet" +msgstr "Não foi possível conectar-se ao Duet" + +#: src/slic3r/Utils/Duet.cpp:84 src/slic3r/Utils/Duet.cpp:154 +msgid "Unknown error occured" +msgstr "Ocorreu um erro desconhecido" + +#: src/slic3r/Utils/Duet.cpp:148 +msgid "Wrong password" +msgstr "Senha incorreta" + +#: src/slic3r/Utils/Duet.cpp:151 +msgid "Could not get resources to create a new connection" +msgstr "Não foi possível obter recursos para criar uma nova conexão" + +#: src/slic3r/Utils/OctoPrint.cpp:70 +#, c-format +msgid "Mismatched type of print host: %s" +msgstr "Tipo incompatível de host de impressão: %s" + +#: src/slic3r/Utils/OctoPrint.cpp:85 +msgid "Connection to OctoPrint works correctly." +msgstr "A ligação ao OctoPrint funciona correctamente." + +#: src/slic3r/Utils/OctoPrint.cpp:91 +msgid "Could not connect to OctoPrint" +msgstr "Não foi possível conectar-se ao OctoPrint" + +#: src/slic3r/Utils/OctoPrint.cpp:91 +msgid "Note: OctoPrint version at least 1.1.0 is required." +msgstr "Nota: OctoPrint versão pelo menos 1.1.0 é necessária." + +#: src/slic3r/Utils/OctoPrint.cpp:196 +msgid "Connection to Prusa SL1 works correctly." +msgstr "A conexão com o Prusa SL1 funciona corretamente." + +#: src/slic3r/Utils/OctoPrint.cpp:201 +msgid "Could not connect to Prusa SLA" +msgstr "Não foi possível conectar-se a Prusa SLA" + +#: src/slic3r/Utils/PresetUpdater.cpp:614 +#, c-format +msgid "requires min. %s and max. %s" +msgstr "requer min . %s e máx. %s" + +#: src/slic3r/Utils/PresetUpdater.cpp:619 +#, c-format +msgid "requires min. %s" +msgstr "requer min . %s" + +#: src/slic3r/Utils/PresetUpdater.cpp:621 +#, c-format +msgid "requires max. %s" +msgstr "requer Max. %s" + +#: src/slic3r/Utils/FixModelByWin10.cpp:219 +#: src/slic3r/Utils/FixModelByWin10.cpp:359 +msgid "Exporting source model" +msgstr "Exportando o modelo de origem" + +#: src/slic3r/Utils/FixModelByWin10.cpp:235 +msgid "Failed loading the input model." +msgstr "Falha ao carregar o modelo de entrada." + +#: src/slic3r/Utils/FixModelByWin10.cpp:242 +msgid "Repairing model by the Netfabb service" +msgstr "Modelo de reparação pelo serviço Netfabb" + +#: src/slic3r/Utils/FixModelByWin10.cpp:248 +msgid "Mesh repair failed." +msgstr "Falha na reparação de malha." + +#: src/slic3r/Utils/FixModelByWin10.cpp:251 +#: src/slic3r/Utils/FixModelByWin10.cpp:378 +msgid "Loading repaired model" +msgstr "Carregando o modelo reparado" + +#: src/slic3r/Utils/FixModelByWin10.cpp:263 +#: src/slic3r/Utils/FixModelByWin10.cpp:270 +#: src/slic3r/Utils/FixModelByWin10.cpp:302 +msgid "Saving mesh into the 3MF container failed." +msgstr "Falha ao salvar a malha 3MF no contêiner." + +#: src/slic3r/Utils/FixModelByWin10.cpp:340 +msgid "Model fixing" +msgstr "Fixação do modelo" + +#: src/slic3r/Utils/FixModelByWin10.cpp:341 +msgid "Exporting model..." +msgstr "Exportando o modelo..." + +#: src/slic3r/Utils/FixModelByWin10.cpp:368 +msgid "Export of a temporary 3mf file failed" +msgstr "Falha na exportação de um arquivo 3mf temporário" + +#: src/slic3r/Utils/FixModelByWin10.cpp:383 +msgid "Import of the repaired 3mf file failed" +msgstr "Falha na importação do arquivo 3mf reparado" + +#: src/slic3r/Utils/FixModelByWin10.cpp:385 +msgid "Repaired 3MF file does not contain any object" +msgstr "O arquivo 3MF reparado não contém nenhum objeto" + +#: src/slic3r/Utils/FixModelByWin10.cpp:387 +msgid "Repaired 3MF file contains more than one object" +msgstr "O arquivo 3MF reparado contém mais de um objeto" + +#: src/slic3r/Utils/FixModelByWin10.cpp:389 +msgid "Repaired 3MF file does not contain any volume" +msgstr "O arquivo 3MF reparado não contém nenhum volume" + +#: src/slic3r/Utils/FixModelByWin10.cpp:391 +msgid "Repaired 3MF file contains more than one volume" +msgstr "O arquivo 3MF reparado contém mais de um volume" + +#: src/slic3r/Utils/FixModelByWin10.cpp:400 +msgid "Model repair finished" +msgstr "Reparo do modelo terminado" + +#: src/slic3r/Utils/FixModelByWin10.cpp:406 +msgid "Model repair canceled" +msgstr "Reparo do modelo cancelado" + +#: src/slic3r/Utils/FixModelByWin10.cpp:423 +msgid "Model repaired successfully" +msgstr "Modelo reparado com sucesso" + +#: src/slic3r/Utils/FixModelByWin10.cpp:423 +#: src/slic3r/Utils/FixModelByWin10.cpp:426 +msgid "Model Repair by the Netfabb service" +msgstr "Reparação de modelos pelo serviço Netfabb" + +#: src/slic3r/Utils/FixModelByWin10.cpp:426 +msgid "Model repair failed: \n" +msgstr "Falha no reparo do modelo:\n" + +#: src/libslic3r/Zipper.cpp:32 +msgid "undefined error" +msgstr "erro indefinido" + +#: src/libslic3r/Zipper.cpp:34 +msgid "too many files" +msgstr "muitos arquivos" + +#: src/libslic3r/Zipper.cpp:36 +msgid "file too large" +msgstr "arquivo muito grande" + +#: src/libslic3r/Zipper.cpp:38 +msgid "unsupported method" +msgstr "método não suportado" + +#: src/libslic3r/Zipper.cpp:40 +msgid "unsupported encryption" +msgstr "criptografia sem suporte" + +#: src/libslic3r/Zipper.cpp:42 +msgid "unsupported feature" +msgstr "recurso não suportado" + +#: src/libslic3r/Zipper.cpp:44 +msgid "failed finding central directory" +msgstr "falha ao encontrar o diretório central" + +#: src/libslic3r/Zipper.cpp:46 +msgid "not a ZIP archive" +msgstr "não um arquivo ZIP" + +#: src/libslic3r/Zipper.cpp:48 +msgid "invalid header or archive is corrupted" +msgstr "cabeçalho ou arquivo inválido está corrompido" + +#: src/libslic3r/Zipper.cpp:50 +msgid "unsupported multidisk archive" +msgstr "arquivo Multidisk sem suporte" + +#: src/libslic3r/Zipper.cpp:52 +msgid "decompression failed or archive is corrupted" +msgstr "descompressão falhou ou arquivo está corrompido" + +#: src/libslic3r/Zipper.cpp:54 +msgid "compression failed" +msgstr "falha na compactação" + +#: src/libslic3r/Zipper.cpp:56 +msgid "unexpected decompressed size" +msgstr "tamanho descomprimido inesperado" + +#: src/libslic3r/Zipper.cpp:58 +msgid "CRC-32 check failed" +msgstr "Verificação CRC-32 falhou" + +#: src/libslic3r/Zipper.cpp:60 +msgid "unsupported central directory size" +msgstr "tamanho do diretório central não suportado" + +#: src/libslic3r/Zipper.cpp:62 +msgid "allocation failed" +msgstr "alocação falhou" + +#: src/libslic3r/Zipper.cpp:64 +msgid "file open failed" +msgstr "falha na abertura do arquivo" + +#: src/libslic3r/Zipper.cpp:66 +msgid "file create failed" +msgstr "falha na criação do arquivo" + +#: src/libslic3r/Zipper.cpp:68 +msgid "file write failed" +msgstr "falha na gravação do arquivo" + +#: src/libslic3r/Zipper.cpp:70 +msgid "file read failed" +msgstr "falha na leitura do arquivo" + +#: src/libslic3r/Zipper.cpp:72 +msgid "file close failed" +msgstr "falha ao fechar o arquivo" + +#: src/libslic3r/Zipper.cpp:74 +msgid "file seek failed" +msgstr "falha na busca de arquivo" + +#: src/libslic3r/Zipper.cpp:76 +msgid "file stat failed" +msgstr "falha no status do arquivo" + +#: src/libslic3r/Zipper.cpp:78 +msgid "invalid parameter" +msgstr "parâmetro inválido" + +#: src/libslic3r/Zipper.cpp:80 +msgid "invalid filename" +msgstr "nome de arquivo inválido" + +#: src/libslic3r/Zipper.cpp:82 +msgid "buffer too small" +msgstr "buffer muito pequeno" + +#: src/libslic3r/Zipper.cpp:84 +msgid "internal error" +msgstr "erro interno" + +#: src/libslic3r/Zipper.cpp:86 +msgid "file not found" +msgstr "arquivo não encontrado" + +#: src/libslic3r/Zipper.cpp:88 +msgid "archive is too large" +msgstr "arquivo é muito grande" + +#: src/libslic3r/Zipper.cpp:90 +msgid "validation failed" +msgstr "falha na validação" + +#: src/libslic3r/Zipper.cpp:92 +msgid "write calledback failed" +msgstr "write calledback falhou" + +#: src/libslic3r/Zipper.cpp:102 +msgid "Error with zip archive" +msgstr "Erro com arquivo zip" + +#: src/libslic3r/Print.cpp:1112 +msgid "All objects are outside of the print volume." +msgstr "Todos os objetos estão fora do volume de impressão." + +#: src/libslic3r/Print.cpp:1139 +msgid "Some objects are too close; your extruder will collide with them." +msgstr "Alguns objetos são muito próximos; sua extrusora irá colidir com eles." + +#: src/libslic3r/Print.cpp:1154 +msgid "" +"Some objects are too tall and cannot be printed without extruder collisions." +msgstr "" +"Alguns objetos são muito altos e não podem ser impressos sem colisões de " +"extrusoras." + +#: src/libslic3r/Print.cpp:1164 +msgid "The Spiral Vase option can only be used when printing a single object." +msgstr "A opção vaso espiral só pode ser usada ao imprimir um único objeto." + +#: src/libslic3r/Print.cpp:1171 +msgid "" +"The Spiral Vase option can only be used when printing single material " +"objects." +msgstr "" +"A opção vaso espiral só pode ser usada ao imprimir objetos de material único." + +#: src/libslic3r/Print.cpp:1184 +msgid "" +"The wipe tower is only supported if all extruders have the same nozzle " +"diameter and use filaments of the same diameter." +msgstr "" +"A torre de limpeza só é suportada se todas as extrusoras tiverem o mesmo " +"diâmetro da ponteira e usarem filamentos do mesmo diâmetro." + +#: src/libslic3r/Print.cpp:1189 +msgid "" +"The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter " +"and Repetier G-code flavors." +msgstr "" +"A Wipe Tower é atualmente suportada apenas para os firmwares Marlin, RepRap/" +"Sprinter e Repetier G-code." + +#: src/libslic3r/Print.cpp:1191 +msgid "" +"The Wipe Tower is currently only supported with the relative extruder " +"addressing (use_relative_e_distances=1)." +msgstr "" +"A torre da limpeza é suportada atualmente somente com o endereçamento " +"relativo da extrusora (use_relative_e_distances = 1)." + +#: src/libslic3r/Print.cpp:1193 +msgid "Ooze prevention is currently not supported with the wipe tower enabled." +msgstr "" +"A prevenção de escorrimento não é suportada atualmente com a torre da " +"limpeza permitida." + +#: src/libslic3r/Print.cpp:1214 +msgid "" +"The Wipe Tower is only supported for multiple objects if they have equal " +"layer heights" +msgstr "" +"A torre de limpeza só é suportada para vários objetos se eles tiverem " +"alturas de camada iguais" + +#: src/libslic3r/Print.cpp:1216 +msgid "" +"The Wipe Tower is only supported for multiple objects if they are printed " +"over an equal number of raft layers" +msgstr "" +"A torre de limpeza só é suportada para vários objetos se elas forem " +"impressas em um número igual de camadas de estrado" + +#: src/libslic3r/Print.cpp:1218 +msgid "" +"The Wipe Tower is only supported for multiple objects if they are printed " +"with the same support_material_contact_distance" +msgstr "" +"A torre de limpeza só é suportado para vários objetos se eles são impressos " +"com a mesma distância de contato do suporte" + +#: src/libslic3r/Print.cpp:1220 +msgid "" +"The Wipe Tower is only supported for multiple objects if they are sliced " +"equally." +msgstr "" +"A torre de limpeza só é suportada para vários objetos se eles são fatiados " +"igualmente." + +#: src/libslic3r/Print.cpp:1248 +msgid "" +"The Wipe tower is only supported if all objects have the same layer height " +"profile" +msgstr "" +"A torre de limpeza só é suportada se todos os objetos tiverem o mesmo perfil " +"de altura da camada" + +#: src/libslic3r/Print.cpp:1258 +msgid "The supplied settings will cause an empty print." +msgstr "As config. fornecidas causarão uma impressão vazia." + +#: src/libslic3r/Print.cpp:1275 +msgid "" +"One or more object were assigned an extruder that the printer does not have." +msgstr "" +"Um ou mais objetos foram atribuídos a uma extrusora que a impressora não tem." + +#: src/libslic3r/Print.cpp:1284 +msgid "%1%=%2% mm is too low to be printable at a layer height %3% mm" +msgstr "" +"%1% = %2% mm é muito baixo para ser impresso a uma altura de camada %3% mm" + +#: src/libslic3r/Print.cpp:1287 +msgid "Excessive %1%=%2% mm to be printable with a nozzle diameter %3% mm" +msgstr "" +"Excesso %1%=%2% milímetro a ser imprimível com um diâmetro da ponteira %3% " +"milímetro" + +#: src/libslic3r/Print.cpp:1298 +msgid "" +"Printing with multiple extruders of differing nozzle diameters. If support " +"is to be printed with the current extruder (support_material_extruder == 0 " +"or support_material_interface_extruder == 0), all nozzles have to be of the " +"same diameter." +msgstr "" +"Impressão com múltiplas extrusoras de diferentes diâmetros de bicos. Se a " +"sustentação deve ser imprimida com a extrusora atual " +"(support_material_extruder = = 0 ou support_material_interface_extruder = = " +"0), todos as ponteiras têm que ser do mesmo diâmetro." + +#: src/libslic3r/Print.cpp:1306 +msgid "" +"For the Wipe Tower to work with the soluble supports, the support layers " +"need to be synchronized with the object layers." +msgstr "" +"Para que a torre de limpeza funcione com os suportes solúveis, as camadas de " +"suporte precisam ser sincronizadas com as camadas de objeto." + +#: src/libslic3r/Print.cpp:1310 +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 " +"support_material_extruder and support_material_interface_extruder need to be " +"set to 0)." +msgstr "" +"A torre de limpeza suporta atualmente os suportes não-solúveis somente se " +"são imprimidos com o extrusor atual sem provocar uma mudança da ferramenta. " +"(ambos support_material_extruder e support_material_interface_extruder " +"precisam ser definidos como 0)." + +#: src/libslic3r/Print.cpp:1332 +msgid "First layer height can't be greater than nozzle diameter" +msgstr "" +"A primeira altura da camada não pode ser maior do que o diâmetro da ponteira" + +#: src/libslic3r/Print.cpp:1337 +msgid "Layer height can't be greater than nozzle diameter" +msgstr "A altura da camada não pode ser maior do que o diâmetro da ponteira" + +#: src/libslic3r/Print.cpp:1492 +msgid "Infilling layers" +msgstr "Camadas de preenchimento" + +#: src/libslic3r/Print.cpp:1500 +msgid "Generating skirt" +msgstr "Gerando saia" + +#: src/libslic3r/Print.cpp:1508 +msgid "Generating brim" +msgstr "Gerando a aba" + +#: src/libslic3r/Print.cpp:1536 +msgid "Exporting G-code" +msgstr "Exportando o G-code" + +#: src/libslic3r/Print.cpp:1540 +msgid "Generating G-code" +msgstr "Gerando G-code" + +#: src/libslic3r/SLAPrint.cpp:64 +msgid "Slicing model" +msgstr "Modelo de fatiamento" + +#: src/libslic3r/SLAPrint.cpp:65 src/libslic3r/SLAPrint.cpp:899 +msgid "Generating support points" +msgstr "Gerando pontos de suporte" + +#: src/libslic3r/SLAPrint.cpp:66 +msgid "Generating support tree" +msgstr "Gerando suporte em árvore" + +#: src/libslic3r/SLAPrint.cpp:67 +msgid "Generating pad" +msgstr "Gerando pad" + +#: src/libslic3r/SLAPrint.cpp:68 +msgid "Slicing supports" +msgstr "Fatiando suportes" + +#: src/libslic3r/SLAPrint.cpp:85 +msgid "Merging slices and calculating statistics" +msgstr "Mesclando camadas e calculando estatísticas" + +#: src/libslic3r/SLAPrint.cpp:86 +msgid "Rasterizing layers" +msgstr "Rasterizando camadas" + +#: src/libslic3r/SLAPrint.cpp:661 +msgid "" +"Cannot proceed without support points! Add support points or disable support " +"generation." +msgstr "" +"Não pode prosseguir sem pontos de suporte! Adicione pontos de suporte ou " +"desative a geração de suporte." + +#: src/libslic3r/SLAPrint.cpp:678 +msgid "" +"Elevation is too low for object. Use the \"Pad around object\" feature to " +"print the object without elevation." +msgstr "" +"A elevação é muito baixa para o objeto. Use o recurso \"pad ao redor do " +"objeto\" para imprimir o objeto sem elevação." + +#: src/libslic3r/SLAPrint.cpp:684 +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 "" +"As terminações dos pilares de suporte serão implantadas na lacuna entre o " +"objeto e o pad. ' Distância de segurança de base de suporte ' tem de ser " +"maior do que o parâmetro ' pad objecto Gap ' para evitar este." + +#: src/libslic3r/SLAPrint.cpp:696 +msgid "Exposition time is out of printer profile bounds." +msgstr "O tempo de exposição está fora dos limites do perfil da impressora." + +#: src/libslic3r/SLAPrint.cpp:703 +msgid "Initial exposition time is out of printer profile bounds." +msgstr "" +"O tempo de exposição inicial está fora dos limites do perfil da impressora." + +#: src/libslic3r/SLAPrint.cpp:787 +msgid "" +"Slicing had to be stopped due to an internal error: Inconsistent slice index." +msgstr "" +"O fatiamento teve que ser parado devido a um erro interno: índice de " +"fatiamento inconsistente." + +#: src/libslic3r/SLAPrint.cpp:982 src/libslic3r/SLAPrint.cpp:992 +#: src/libslic3r/SLAPrint.cpp:1033 +msgid "Visualizing supports" +msgstr "Visualizando suportes" + +#: src/libslic3r/SLAPrint.cpp:1566 +msgid "Slicing done" +msgstr "Fatiamento pronto" + +#: src/libslic3r/PrintBase.cpp:71 +msgid "Failed processing of the output_filename_format template." +msgstr "Falha no processamento do modelo output_filename_format." + +#: src/libslic3r/PrintConfig.cpp:43 src/libslic3r/PrintConfig.cpp:44 +msgid "Printer technology" +msgstr "Tecnologia da impressora" + +#: src/libslic3r/PrintConfig.cpp:51 +msgid "Bed shape" +msgstr "Formato da mesa" + +#: src/libslic3r/PrintConfig.cpp:56 +msgid "Bed custom texture" +msgstr "Textura customizada da mesa" + +#: src/libslic3r/PrintConfig.cpp:61 +msgid "Bed custom model" +msgstr "Modelo customizado da mesa" + +#: 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 "" +"Essa config. controla a altura (e, portanto, o número total) das fatias/" +"camadas. Camadas mais finas dão melhor precisão, mas levam mais tempo para " +"imprimir." + +#: src/libslic3r/PrintConfig.cpp:75 +msgid "Max print height" +msgstr "Altura máxima de impressão" + +#: src/libslic3r/PrintConfig.cpp:76 +msgid "" +"Set this to the maximum height that can be reached by your extruder while " +"printing." +msgstr "" +"Defina isto para a altura máxima que pode ser alcançada pela sua extrusora " +"durante a impressão." + +#: src/libslic3r/PrintConfig.cpp:82 +msgid "Slice gap closing radius" +msgstr "Raio de fechamento da abertura da fatia" + +#: 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 "" +"As rachaduras menores do que duas vezes o raio de fechamento estão sendo " +"preenchidas durante o fatiamento da malha triangular. A operação de " +"fechamento de vão pode reduzir a resolução final de impressão, portanto, é " +"aconselhável manter o valor razoavelmente baixo." + +#: src/libslic3r/PrintConfig.cpp:92 +msgid "Hostname, IP or URL" +msgstr "Hostname, IP ou URL" + +#: 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 "" +"Slic3r pode carregar arquivos de G-code para um host de impressora. Este " +"campo deve conter o nome de host, o endereço IP ou a URL da instância de " +"host da impressora." + +#: src/libslic3r/PrintConfig.cpp:99 +msgid "API Key / Password" +msgstr "Chave de API/senha" + +#: 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 "" +"Slic3r pode carregar arquivos de G-code para um host de impressora. Este " +"campo deve conter a chave de API ou a senha exigida para a autenticação." + +#: src/libslic3r/PrintConfig.cpp:106 +msgid "HTTPS CA File" +msgstr "Arquivo de CA HTTPS" + +#: 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 "" +"O arquivo de certificado de CA personalizado pode ser especificado para " +"conexões HTTPS OctoPrint, no formato CRT/PEM. Se deixado em branco, o " +"repositório de certificados do OS CA padrão é usado." + +#: src/libslic3r/PrintConfig.cpp:121 +msgid "Avoid crossing perimeters" +msgstr "Evitar cruzamento de perímetros" + +#: 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 "" +"Otimize os movimentos de viagem para minimizar o cruzamento de perímetros. " +"Isto é principalmente útil com extrusoras Bowden que sofrem de escorrimento. " +"Este recurso retarda a impressão e a geração de G-code." + +#: src/libslic3r/PrintConfig.cpp:129 src/libslic3r/PrintConfig.cpp:2027 +msgid "Other layers" +msgstr "Outras camadas" + +#: 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 "" +"Temperatura da mesa para camadas após o primeiro. Defina isso como zero para " +"desabilitar os comandos de controle de temperatura da mesa na saída." + +#: src/libslic3r/PrintConfig.cpp:132 +msgid "Bed temperature" +msgstr "Temperatura da mesa" + +#: 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 "" +"Esse código personalizado é inserido em cada alteração de camada, logo antes " +"da movimentação Z. Observe que você pode usar variáveis de espaço reservado " +"para todas as config. Slic3r, bem como [layer_num] e [layer_z]." + +#: src/libslic3r/PrintConfig.cpp:149 +msgid "Between objects G-code" +msgstr "G-code entre objetos" + +#: 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; " +"however if M104, M109, M140 or M190 are detected in this custom code, Slic3r " +"will not add temperature commands. 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." +msgstr "" +"Esse código é inserido entre objetos ao usar a impressão sequencial. Por " +"padrão, a extrusora e a temperatura da mesa são redefinidas usando o comando " +"não esperar; no entanto, se M104, M109, M140 ou M190 são detectados neste " +"código personalizado, Slic3r não adicionará comandos de temperatura. Observe " +"que você pode usar variáveis de espaço reservado para todas as config. de " +"Slic3r, para que você possa colocar um comando \"M109 S " +"[temperatura_primeira_camada]\" onde quiser." + +#: src/libslic3r/PrintConfig.cpp:161 +msgid "Number of solid layers to generate on bottom surfaces." +msgstr "Número de camadas sólidas para gerar em superfícies inferiores." + +#: src/libslic3r/PrintConfig.cpp:162 +msgid "Bottom solid layers" +msgstr "Camadas sólidas inferiores" + +#: src/libslic3r/PrintConfig.cpp:167 +msgid "Bridge" +msgstr "Ponte" + +#: 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 "" +"Esta é a aceleração que sua impressora usará para pontes. Defina zero para " +"desabilitar o controle de aceleração para pontes." + +#: 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 "mm/s²" + +#: src/libslic3r/PrintConfig.cpp:176 +msgid "Bridging angle" +msgstr "Ângulo de ponte" + +#: 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 "" +"Sobreposição de ângulo de ponte. Se deixado em zero, o ângulo de ponte será " +"calculado automaticamente. Caso contrário, o ângulo fornecido será usado " +"para todas as pontes. Use 180 ° para o ângulo zero." + +#: 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:2614 +#: src/libslic3r/PrintConfig.cpp:2724 +msgid "°" +msgstr "°" + +#: src/libslic3r/PrintConfig.cpp:187 +msgid "Bridges fan speed" +msgstr "Velocidade da ventoinha nas pontes" + +#: src/libslic3r/PrintConfig.cpp:188 +msgid "This fan speed is enforced during all bridges and overhangs." +msgstr "" +"Esta velocidade da ventoinha é imposta durante todas as pontes e angulações." + +#: 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:2654 +msgid "%" +msgstr "%" + +#: src/libslic3r/PrintConfig.cpp:196 +msgid "Bridge flow ratio" +msgstr "Relação de fluxo da ponte" + +#: 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 " +"settings are usually good and you should experiment with cooling (use a fan) " +"before tweaking this." +msgstr "" +"Esse fator afeta a quantidade de plástico para a ponte. Você pode diminuí-lo " +"um pouco para puxar as extrusões e evitar a flacidez, embora as config. " +"padrão são geralmente boas e você deve experimentar com refrigeração (use " +"uma ventoinha) antes de ajustes isso." + +#: src/libslic3r/PrintConfig.cpp:208 +msgid "Bridges" +msgstr "Pontes" + +#: src/libslic3r/PrintConfig.cpp:210 +msgid "Speed for printing bridges." +msgstr "Velocidade para a impressão de pontes." + +#: 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 "mm/s" + +#: src/libslic3r/PrintConfig.cpp:218 +msgid "Brim width" +msgstr "Largura da aba" + +#: src/libslic3r/PrintConfig.cpp:219 +msgid "" +"Horizontal width of the brim that will be printed around each object on the " +"first layer." +msgstr "" +"Largura horizontal da aba que será impressa em torno de cada objeto na " +"primeira camada." + +#: src/libslic3r/PrintConfig.cpp:226 +msgid "Clip multi-part objects" +msgstr "Clip objetos de várias partes" + +#: 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 "" +"Ao imprimir objetos de vários materiais, essas config. farão com que o " +"Slic3r recorte as partes do objeto sobrepostas uma pela outra (2ª parte será " +"cortada pela 1ª, 3ª parte será cortada pela 1ª e 2ª, etc.)." + +#: src/libslic3r/PrintConfig.cpp:234 +msgid "Colorprint height" +msgstr "Altura da impressão colorida" + +#: src/libslic3r/PrintConfig.cpp:235 +msgid "Heights at which a filament change is to occur." +msgstr "Alturas em que uma mudança do filamento ocorre." + +#: src/libslic3r/PrintConfig.cpp:245 +msgid "Compatible printers condition" +msgstr "Condição de impressoras compatíveis" + +#: 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 "" +"Uma expressão booleana usando os valores de config. de um perfil de " +"impressora ativo. Se essa expressão for avaliada como verdadeira, esse " +"perfil será considerado compatível com o perfil de impressora ativo." + +#: src/libslic3r/PrintConfig.cpp:260 +msgid "Compatible print profiles condition" +msgstr "Condição de perfis de impressão compatíveis" + +#: 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 "" +"Uma expressão booleana usando os valores de config. de um perfil de " +"impressão ativo. Se essa expressão for avaliada como verdadeira, esse perfil " +"será considerado compatível com o perfil de impressão ativo." + +#: src/libslic3r/PrintConfig.cpp:278 +msgid "Complete individual objects" +msgstr "Complete objetos individuais" + +#: 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). " +"This feature is useful to avoid the risk of ruined prints. Slic3r should " +"warn and prevent you from extruder collisions, but beware." +msgstr "" +"Ao imprimir vários objetos ou cópias, esse recurso concluirá cada objeto " +"antes de passar para o próximo (e iniciando-o de sua camada inferior). Este " +"recurso é útil para evitar o risco de impressões arruinadas. Slic3r deve " +"avisar e impedi-lo de colisões de extrusoras, mas cuidado." + +#: src/libslic3r/PrintConfig.cpp:287 +msgid "Enable auto cooling" +msgstr "Ativar o resfriamento automático" + +#: 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 "" +"Esse sinalizador permite a lógica de resfriamento automática que ajusta a " +"velocidade de impressão e a velocidade do ventoinha de acordo com o tempo de " +"impressão da camada." + +#: src/libslic3r/PrintConfig.cpp:293 +msgid "Cooling tube position" +msgstr "Posição do tubo de resfriamento" + +#: src/libslic3r/PrintConfig.cpp:294 +msgid "Distance of the center-point of the cooling tube from the extruder tip." +msgstr "" +"Distância do ponto central do tubo de resfriamento da ponta da extrusora." + +#: src/libslic3r/PrintConfig.cpp:301 +msgid "Cooling tube length" +msgstr "Comprimento do tubo de resfriamento" + +#: src/libslic3r/PrintConfig.cpp:302 +msgid "Length of the cooling tube to limit space for cooling moves inside it." +msgstr "" +"Comprimento do tubo de resfriamento para limitar o espaço para movimentos de " +"resfriamento dentro dele." + +#: 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 "" +"Esta é a aceleração que sua impressora será redefinida para depois que os " +"valores de aceleração específicos da função forem usados (perímetro/" +"preenchimento). Defina zero para evitar redefinir a aceleração em tudo." + +#: src/libslic3r/PrintConfig.cpp:319 +msgid "Default filament profile" +msgstr "Perfil de filamento padrão" + +#: 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 "" +"Perfil de filamento padrão associado ao perfil de impressora atual. Na " +"seleção do perfil da impressora atual, este perfil de filamento será ativado." + +#: src/libslic3r/PrintConfig.cpp:326 +msgid "Default print profile" +msgstr "Perfil de impressão padrão" + +#: src/libslic3r/PrintConfig.cpp:327 src/libslic3r/PrintConfig.cpp:2479 +#: src/libslic3r/PrintConfig.cpp:2490 +msgid "" +"Default print profile associated with the current printer profile. On " +"selection of the current printer profile, this print profile will be " +"activated." +msgstr "" +"Perfil de impressão padrão associado ao perfil de impressora atual. Na " +"seleção do perfil de impressora atual, este perfil de impressão será ativado." + +#: src/libslic3r/PrintConfig.cpp:333 +msgid "Disable fan for the first" +msgstr "Desabilite o ventoinha para a(s) primeira(s)" + +#: 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 "" +"Você pode ajustar isto a um valor positivo para desabilitar a ventoinha " +"durante as primeiras camadas, de modo que melhore a adesão." + +#: 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 "camadas" + +#: src/libslic3r/PrintConfig.cpp:343 +msgid "Don't support bridges" +msgstr "Não suporte pontes" + +#: src/libslic3r/PrintConfig.cpp:345 +msgid "" +"Experimental option for preventing support material from being generated " +"under bridged areas." +msgstr "" +"Opção experimental para impedir que o material de suporte seja gerado em " +"áreas com ponte." + +#: src/libslic3r/PrintConfig.cpp:351 +msgid "Distance between copies" +msgstr "Distância entre cópias" + +#: src/libslic3r/PrintConfig.cpp:352 +msgid "Distance used for the auto-arrange feature of the plater." +msgstr "Distância usada para o recurso de organizar automaticamente o prato." + +#: src/libslic3r/PrintConfig.cpp:359 +msgid "Elephant foot compensation" +msgstr "Compensação do pé do elefante" + +#: 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 "" +"A primeira camada será encolhido no plano XY pelo valor config.urado para " +"compensar a 1ª camada esmagada, também conhecida como pé de elefante." + +#: 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 PrusaSlicer settings." +msgstr "" +"Este procedimento final é inserido no final do arquivo de saída. Observe que " +"você pode usar variáveis de espaço reservado para todas as config. de " +"PrusaSlicer." + +#: src/libslic3r/PrintConfig.cpp:380 +msgid "" +"This end procedure is inserted at the end of the output file, before the " +"printer end gcode (and before any toolchange from this filament in case of " +"multimaterial printers). Note that you can use placeholder variables for all " +"PrusaSlicer settings. If you have multiple extruders, the gcode is processed " +"in extruder order." +msgstr "" +"Este procedimento final é inserido no final do arquivo de saída, antes da " +"extremidade da impressora Gcode (e antes de qualquer troca de ferramenta " +"deste filamento em caso de impressoras multimaterial). Observe que você pode " +"usar variáveis de espaço reservado para todas as config. de PrusaSlicer. Se " +"você tiver várias extrusoras, o Gcode é processado em ordem de extrusora." + +#: src/libslic3r/PrintConfig.cpp:391 +msgid "Ensure vertical shell thickness" +msgstr "Assegure a espessura vertical da parede" + +#: src/libslic3r/PrintConfig.cpp:393 +msgid "" +"Add solid infill near sloping surfaces to guarantee the vertical shell " +"thickness (top+bottom solid layers)." +msgstr "" +"Adicionar preenchimento sólido perto de superfícies inclinadas para garantir " +"a espessura do escudo vertical (camadas sólidas no topo + base )." + +#: src/libslic3r/PrintConfig.cpp:399 +msgid "Top fill pattern" +msgstr "Padrão de preenchimento do topo" + +#: 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 "" +"Padrão de preenchimento para preenchimento do topo. Isto afeta somente a " +"camada visível superior, e não suas paredes adjacentes." + +#: src/libslic3r/PrintConfig.cpp:409 src/libslic3r/PrintConfig.cpp:821 +#: src/libslic3r/PrintConfig.cpp:1972 +msgid "Rectilinear" +msgstr "Rectilíneo" + +#: src/libslic3r/PrintConfig.cpp:410 src/libslic3r/PrintConfig.cpp:827 +msgid "Concentric" +msgstr "Concêntrico" + +#: src/libslic3r/PrintConfig.cpp:411 src/libslic3r/PrintConfig.cpp:831 +msgid "Hilbert Curve" +msgstr "Curva de Hilbert" + +#: src/libslic3r/PrintConfig.cpp:412 src/libslic3r/PrintConfig.cpp:832 +msgid "Archimedean Chords" +msgstr "Cordas Archimedean" + +#: src/libslic3r/PrintConfig.cpp:413 src/libslic3r/PrintConfig.cpp:833 +msgid "Octagram Spiral" +msgstr "Espiral estrelado" + +#: src/libslic3r/PrintConfig.cpp:419 +msgid "Bottom fill pattern" +msgstr "Padrão de preenchimento da base" + +#: 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 "" +"Padrão de preenchimento para preenchimento da base. Isto afeta somente a " +"camada visível externa inferior, e não suas paredes adjacentes." + +#: src/libslic3r/PrintConfig.cpp:430 src/libslic3r/PrintConfig.cpp:440 +msgid "External perimeters" +msgstr "Perímetros externos" + +#: 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, " +"otherwise 1.125 x nozzle diameter will be used. If expressed as percentage " +"(for example 200%), it will be computed over layer height." +msgstr "" +"Defina isso como um valor diferente de zero para definir uma largura de " +"extrusão manual para perímetros externos. Se for deixado zero, a largura de " +"extrusão padrão será usada se definido, caso contrário, 1,125 x diâmetro da " +"ponteira será usado. Se expresso em porcentagem(por exemplo 200%), será " +"calculado sobre a altura da camada." + +#: 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 "mm ou %" + +#: 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 "" +"Esta config. separada afetará a velocidade dos perímetros externos (os " +"visíveis). Se expresso em porcentagem(por exemplo: 80%) Ele será calculado " +"sobre a velocidade de perímetros config. acima. Defina como zero para auto." + +#: 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 "mm/s ou %" + +#: src/libslic3r/PrintConfig.cpp:452 +msgid "External perimeters first" +msgstr "Perímetros externos primeiro" + +#: src/libslic3r/PrintConfig.cpp:454 +msgid "" +"Print contour perimeters from the outermost one to the innermost one instead " +"of the default inverse order." +msgstr "" +"Imprima perímetros de contorno do mais externo para o mais interno em vez da " +"ordem inversa padrão." + +#: src/libslic3r/PrintConfig.cpp:460 +msgid "Extra perimeters if needed" +msgstr "Perímetros extras se necessário" + +#: src/libslic3r/PrintConfig.cpp:462 +#, c-format +msgid "" +"Add more perimeters when needed for avoiding gaps in sloping walls. Slic3r " +"keeps adding perimeters, until more than 70% of the loop immediately above " +"is supported." +msgstr "" +"Adicione mais perímetros quando necessário para evitar lacunas em paredes " +"inclinados. Slic3r continua adicionando perímetros, até que mais de 70% o do " +"loop imediatamente acima é suportado." + +#: 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 "" +"A extrusora a ser usada (a menos que config. de extrusoras mais específicas " +"sejam especificadas). Esse valor substitui as extrusoras de perímetro e " +"preenchimento, mas não as extrusoras de suporte." + +#: 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 " +"cylinder around your extruder, and it represents the maximum depth the " +"extruder can peek before colliding with other printed objects." +msgstr "" +"Defina isto para a distância vertical entre a ponta do bico e (normalmente) " +"as hastes do X. Em outras palavras, esta é a altura do cilindro de folga em " +"torno de sua extrusora, e representa a profundidade máxima que a extrusora " +"pode espreitar antes de colidir com outros objetos impressos." + +#: src/libslic3r/PrintConfig.cpp:494 +msgid "Radius" +msgstr "Raio" + +#: 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 "" +"Defina isso para o raio de folga em torno de sua extrusora. Se a extrusora " +"não estiver centralizada, escolha o maior valor para a segurança. Essa " +"config. é usada para verificar colisões e exibir a visualização gráfica no " +"prato." + +#: src/libslic3r/PrintConfig.cpp:505 +msgid "Extruder Color" +msgstr "Cor da extrusora" + +#: src/libslic3r/PrintConfig.cpp:506 src/libslic3r/PrintConfig.cpp:566 +msgid "This is only used in the Slic3r interface as a visual help." +msgstr "Isso é usado apenas na interface Slic3r como uma ajuda visual." + +#: src/libslic3r/PrintConfig.cpp:512 +msgid "Extruder offset" +msgstr "Compensamento da extrusora" + +#: 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 " +"of each extruder with respect to the first one. It expects positive " +"coordinates (they will be subtracted from the XY coordinate)." +msgstr "" +"Se o seu firmware não manipula o deslocamento da extrusora, você precisa do " +"G-code para levá-lo em conta. Esta opção permite especificar o deslocamento " +"de cada extrusora em relação à primeira. Ele espera coordenadas positivas " +"(eles serão subtraída da coordenada XY)." + +#: src/libslic3r/PrintConfig.cpp:522 +msgid "Extrusion axis" +msgstr "Eixo de extrusão" + +#: 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 "" +"Use esta opção para definir a letra do eixo associada à extrusora da sua " +"impressora (geralmente E, mas algumas impressoras usam A)." + +#: src/libslic3r/PrintConfig.cpp:528 +msgid "Extrusion multiplier" +msgstr "Multiplicador de extrusão" + +#: 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. " +"Usual values are between 0.9 and 1.1. If you think you need to change this " +"more, check filament diameter and your firmware E steps." +msgstr "" +"Esse fator altera a quantidade de fluxo proporcionalmente. Você pode " +"precisar de ajustar esta config. para obter acabamento de superfície " +"agradável e corrigir larguras de parede única. Os valores usuais são entre " +"0,9 e 1,1. Se você acha que precisa mudar isso mais, verifique o diâmetro do " +"filamento e os passos configurados no firmware da extrusora." + +#: src/libslic3r/PrintConfig.cpp:537 +msgid "Default extrusion width" +msgstr "Largura de extrusão padrão" + +#: 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 " +"tooltips for perimeter extrusion width, infill extrusion width etc). If " +"expressed as percentage (for example: 230%), it will be computed over layer " +"height." +msgstr "" +"Defina isso como um valor diferente de zero para permitir uma largura de " +"extrusão manual. Se deixado a zero, Slic3r deriva larguras da extrusão do " +"diâmetro da ponteira (veja as dicas ferramentas para a largura da extrusão " +"do perímetro, a largura de extrusão do preenchimento etc.). Se expresso como " +"porcentagem (por exemplo: 230%), ele será calculado sobre a altura da camada." + +#: src/libslic3r/PrintConfig.cpp:548 +msgid "Keep fan always on" +msgstr "Mantenha a ventoinha sempre ligada" + +#: 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 "" +"Se isso estiver ativado, a ventoinha nunca será desativada e será mantida " +"funcionando pelo menos em sua velocidade mínima. Útil para o PLA, " +"prejudicial para o ABS." + +#: src/libslic3r/PrintConfig.cpp:554 +msgid "Enable fan if layer print time is below" +msgstr "Ative o ventoinha se o tempo de impressão da camada estiver abaixo" + +#: 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 "" +"Se o tempo de impressão da camada for estimado abaixo desse número de " +"segundos, a ventoinha será ativada e sua velocidade será calculada " +"interpolando as velocidades mínima e máxima." + +#: src/libslic3r/PrintConfig.cpp:557 src/libslic3r/PrintConfig.cpp:1687 +msgid "approximate seconds" +msgstr "segundos aproximados" + +#: src/libslic3r/PrintConfig.cpp:571 +msgid "Filament notes" +msgstr "Notas de filamento" + +#: src/libslic3r/PrintConfig.cpp:572 +msgid "You can put your notes regarding the filament here." +msgstr "Você pode colocar suas anotações sobre o filamento aqui." + +#: src/libslic3r/PrintConfig.cpp:580 src/libslic3r/PrintConfig.cpp:1231 +msgid "Max volumetric speed" +msgstr "Máxima velocidade volumétrica" + +#: 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 "" +"Velocidade máxima volumétrica permitida para este filamento. Limita a " +"velocidade volumétrica máxima de uma impressão ao mínimo de velocidade " +"volumétrica de impressão e de filamento. Defina como zero para nenhum limite." + +#: src/libslic3r/PrintConfig.cpp:590 +msgid "Loading speed" +msgstr "Velocidade de carregamento" + +#: src/libslic3r/PrintConfig.cpp:591 +msgid "Speed used for loading the filament on the wipe tower." +msgstr "Velocidade utilizada para carregar o filamento na torre de limpeza." + +#: src/libslic3r/PrintConfig.cpp:598 +msgid "Loading speed at the start" +msgstr "Velocidade de carregamento no início" + +#: src/libslic3r/PrintConfig.cpp:599 +msgid "Speed used at the very beginning of loading phase." +msgstr "Velocidade utilizada no início da fase de carregamento." + +#: src/libslic3r/PrintConfig.cpp:606 +msgid "Unloading speed" +msgstr "Velocidade de descarregamento" + +#: 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 "" +"Velocidade utilizada para descarregar o filamento na torre de limpeza (não " +"afeta a parte inicial do descarregamento logo após o Ramming)." + +#: src/libslic3r/PrintConfig.cpp:615 +msgid "Unloading speed at the start" +msgstr "Velocidade de descarregamento no início" + +#: src/libslic3r/PrintConfig.cpp:616 +msgid "" +"Speed used for unloading the tip of the filament immediately after ramming." +msgstr "" +"Velocidade usada para descarregar a ponta do filamento imediatamente após o " +"Ramming." + +#: src/libslic3r/PrintConfig.cpp:623 +msgid "Delay after unloading" +msgstr "Atraso após o descarregamento" + +#: 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 "" +"Tempo de espera após o filamento ser descarregado. Pode ajudar a obter " +"trocas de ferramenta confiáveis com materiais flexíveis que podem precisar " +"de mais tempo para reduzir as dimensões originais." + +#: src/libslic3r/PrintConfig.cpp:633 +msgid "Number of cooling moves" +msgstr "Número de movimentos de resfriamento" + +#: 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 "" +"O filamento é resfriado por ser movido para frente e para trás nos tubos de " +"resfriamento. Especifique o número desejado desses movimentos." + +#: src/libslic3r/PrintConfig.cpp:642 +msgid "Speed of the first cooling move" +msgstr "Velocidade do primeiro movimento de resfriamento" + +#: src/libslic3r/PrintConfig.cpp:643 +msgid "Cooling moves are gradually accelerating beginning at this speed." +msgstr "" +"Movimentos de resfriamento estão gradualmente acelerando a partir desta " +"velocidade." + +#: src/libslic3r/PrintConfig.cpp:650 +msgid "Minimal purge on wipe tower" +msgstr "Remoção mínima na torre da limpeza" + +#: 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 " +"stable. Before purging the print head into an infill or a sacrificial " +"object, Slic3r will always prime this amount of material into the wipe tower " +"to produce successive infill or sacrificial object extrusions reliably." +msgstr "" +"Após uma mudança da ferramenta, a posição exata do filamento recentemente " +"carregado dentro da ponteira pode não ser conhecida, e a pressão do " +"filamento provavelmente ainda não esteja estável. Antes de purgar a cabeça " +"de impressão em um preenchimento ou um objeto sacrificial, Slic3r sempre " +"Prime esta quantidade de material para a torre de limpeza para produzir " +"sucessivas preenchimento ou sacrificial objeto extrusões de forma confiável." + +#: src/libslic3r/PrintConfig.cpp:655 +msgid "mm³" +msgstr "mm³" + +#: src/libslic3r/PrintConfig.cpp:661 +msgid "Speed of the last cooling move" +msgstr "Velocidade do último movimento de resfriamento" + +#: src/libslic3r/PrintConfig.cpp:662 +msgid "Cooling moves are gradually accelerating towards this speed." +msgstr "" +"Movimentos de resfriamento estão gradualmente acelerando para esta " +"velocidade." + +#: src/libslic3r/PrintConfig.cpp:669 +msgid "Filament load time" +msgstr "Tempo de carga do filamento" + +#: 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 "" +"Tempo para o firmware da impressora (ou a Multi Material Unit 2.0 para " +"carregar um novo filamento durante uma mudança de ferramenta (ao executar o " +"código T). Esse tempo é adicionado ao tempo total de impressão pelo " +"estimador de tempo do G-code." + +#: src/libslic3r/PrintConfig.cpp:677 +msgid "Ramming parameters" +msgstr "Parâmetros de Ramming" + +#: src/libslic3r/PrintConfig.cpp:678 +msgid "" +"This string is edited by RammingDialog and contains ramming specific " +"parameters." +msgstr "" +"Essa cadeia de caracteres é editada por rammingdialog e contém parâmetros " +"específicos de Ramming." + +#: src/libslic3r/PrintConfig.cpp:684 +msgid "Filament unload time" +msgstr "Tempo de descarregamento do filamento" + +#: 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 "" +"Tempo para o firmware da impressora (ou a unidade de material multi 2,0) " +"para descarregar um filamento durante uma mudança de ferramenta (ao executar " +"o código T). Esse tempo é adicionado ao tempo total de impressão pelo " +"estimador de tempo do G-code." + +#: 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 "" +"Insira o diâmetro do filamento aqui. Boa precisão é necessária, então use um " +"paquímetro e fazer várias medições ao longo do filamento, em seguida, " +"calcular a média." + +#: src/libslic3r/PrintConfig.cpp:700 +msgid "Density" +msgstr "Densidade" + +#: 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 " +"the length to volume. Better is to calculate the volume directly through " +"displacement." +msgstr "" +"Insira sua densidade de filamento aqui. Isto é apenas para informação " +"estatística. Uma maneira decente é pesar um comprimento conhecido do " +"filamento e computar a relação do comprimento ao volume. Melhor é calcular o " +"volume diretamente através do deslocamento." + +#: src/libslic3r/PrintConfig.cpp:704 +msgid "g/cm³" +msgstr "g/cm³" + +#: src/libslic3r/PrintConfig.cpp:709 +msgid "Filament type" +msgstr "Tipo de filamento" + +#: src/libslic3r/PrintConfig.cpp:710 +msgid "The filament material type for use in custom G-codes." +msgstr "O tipo de material de filamento para uso em G-code customizados." + +#: src/libslic3r/PrintConfig.cpp:736 +msgid "Soluble material" +msgstr "Material solúvel" + +#: src/libslic3r/PrintConfig.cpp:737 +msgid "Soluble material is most likely used for a soluble support." +msgstr "O material solúvel é mais provável usado para um suporte solúvel." + +#: src/libslic3r/PrintConfig.cpp:743 +msgid "" +"Enter your filament cost per kg here. This is only for statistical " +"information." +msgstr "" +"Insira o seu custo de filamento por kg aqui. Isto é apenas para informação " +"estatística." + +#: src/libslic3r/PrintConfig.cpp:744 +msgid "money/kg" +msgstr "dinheiro/kg" + +#: src/libslic3r/PrintConfig.cpp:753 +msgid "Fill angle" +msgstr "Ângulo de preenchimento" + +#: 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 "" +"Ângulo padrão para a orientação de preenchimento. A hachura cruzada será " +"aplicada a isso. Pontes serão preenchidas usando a melhor direção Slic3r " +"pode detectar, portanto, essa config. não vai afeta-los." + +#: src/libslic3r/PrintConfig.cpp:767 +msgid "Fill density" +msgstr "Densidade de preenchimento" + +#: src/libslic3r/PrintConfig.cpp:769 +msgid "Density of internal infill, expressed in the range 0% - 100%." +msgstr "Densidade de preenchimento interno, expresso na faixa de 0%-100%." + +#: src/libslic3r/PrintConfig.cpp:804 +msgid "Fill pattern" +msgstr "Padrão de preenchimento" + +#: src/libslic3r/PrintConfig.cpp:806 +msgid "Fill pattern for general low-density infill." +msgstr "Padrão de preenchimento para preenchimento de baixa densidade." + +#: src/libslic3r/PrintConfig.cpp:822 +msgid "Grid" +msgstr "Grade" + +#: src/libslic3r/PrintConfig.cpp:823 +msgid "Triangles" +msgstr "Triângulos" + +#: src/libslic3r/PrintConfig.cpp:824 +msgid "Stars" +msgstr "Estrelas" + +#: src/libslic3r/PrintConfig.cpp:825 +msgid "Cubic" +msgstr "Cúbico" + +#: src/libslic3r/PrintConfig.cpp:826 +msgid "Line" +msgstr "Linha" + +#: src/libslic3r/PrintConfig.cpp:828 src/libslic3r/PrintConfig.cpp:1974 +msgid "Honeycomb" +msgstr "Hexágono" + +#: src/libslic3r/PrintConfig.cpp:829 +msgid "3D Honeycomb" +msgstr "Hexágono 3D" + +#: src/libslic3r/PrintConfig.cpp:830 +msgid "Gyroid" +msgstr "Giróide" + +#: src/libslic3r/PrintConfig.cpp:837 src/libslic3r/PrintConfig.cpp:846 +#: src/libslic3r/PrintConfig.cpp:854 src/libslic3r/PrintConfig.cpp:887 +msgid "First layer" +msgstr "Primeira camada" + +#: 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 "" +"Esta é a aceleração que sua impressora usará para a primeira camada. Defina " +"zero para desabilitar o controle de aceleração para a primeira camada." + +#: 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 "" +"Temperatura da mesa aquecida para a primeira camada. Defina isso como zero " +"para desabilitar os comandos de controle de temperatura da mesa na saída." + +#: 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 " +"expressed as percentage (for example 120%) it will be computed over first " +"layer height. If set to zero, it will use the default extrusion width." +msgstr "" +"Defina isso como um valor diferente de zero para definir uma largura de " +"extrusão manual para a primeira camada. Você pode usar este para forçar " +"extrusões maiores para a melhor adesão. Se expresso em porcentagem(por " +"exemplo, 120%) será computado sobre a primeira altura da camada. Se definido " +"como zero, ele usará a largura de extrusão padrão." + +#: src/libslic3r/PrintConfig.cpp:866 +msgid "First layer height" +msgstr "Altura da primeira camada" + +#: 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 " +"plates. This can be expressed as an absolute value or as a percentage (for " +"example: 150%) over the default layer height." +msgstr "" +"Ao imprimir com alturas muito baixas da camada, você pode ainda querer " +"imprimir uma camada inferior mais grossa para melhorar a adesão e a " +"tolerância para mesas não perfeitas. Isso pode ser expresso como um valor " +"absoluto ou como uma porcentagem (por exemplo: 150%) sobre a altura da " +"camada padrão." + +#: src/libslic3r/PrintConfig.cpp:877 +msgid "First layer speed" +msgstr "Velocidade da primeira camada" + +#: 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 "" +"Se expresso como valor absoluto em mm/s, esta velocidade será aplicada a " +"todos os movimentos de impressão da primeira camada, independentemente do " +"seu tipo. Se expresso em porcentagem(por exemplo: 40%) Ele dimensionará as " +"velocidades padrão." + +#: 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 "" +"Temperatura da extrusora para a primeira camada. Se você quiser controlar a " +"temperatura manualmente durante a impressão, defina isso como zero para " +"desabilitar os comandos de controle de temperatura no arquivo de saída." + +#: 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 "" +"Velocidade para encher pequenas lacunas usando movimentos de ziguezague " +"curtos. Mantenha este razoavelmente baixo para evitar demasiada agitação e " +"problemas de ressonância. Defina zero para desabilitar o preenchimento de " +"lacunas." + +#: src/libslic3r/PrintConfig.cpp:905 +msgid "Verbose G-code" +msgstr "Gcode detalhado" + +#: 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 "" +"Habilite isso para obter um arquivo de G-code comentado, com cada linha " +"explicada por um texto descritivo. Se você imprimir a partir do cartão SD, o " +"peso adicional do arquivo pode fazer o seu firmware ficar mais lento." + +#: src/libslic3r/PrintConfig.cpp:913 +msgid "G-code flavor" +msgstr "Tipo de G-code" + +#: 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 " +"output. The \"No extrusion\" flavor prevents PrusaSlicer from exporting any " +"extrusion value at all." +msgstr "" +"Alguns comandos G/M-code, incluindo controle de temperatura e outros, não " +"são universais. Defina esta opção para o firmware da impressora para obter " +"uma saída compatível. O \"sem extrusão\" tipo impede PrusaSlicer de exportar " +"qualquer valor de extrusão em tudo." + +#: src/libslic3r/PrintConfig.cpp:937 +msgid "No extrusion" +msgstr "Sem extrusão" + +#: src/libslic3r/PrintConfig.cpp:942 +msgid "Label objects" +msgstr "Rotular objetos" + +#: 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 " +"plugin. This settings is NOT compatible with Single Extruder Multi Material " +"setup and Wipe into Object / Wipe into Infill." +msgstr "" +"Habilite isso para adicionar comentários aos movimentos de impressão de " +"rotulagem do G-code com o objeto ao qual eles pertencem, o que é útil para o " +"plugin Octoprint CancelObject. Essas config. não são compatíveis com a " +"config. de multi material de extrusora única e limpe em objeto/limpar em " +"preenchimento." + +#: src/libslic3r/PrintConfig.cpp:950 +msgid "High extruder current on filament swap" +msgstr "Corrente elevada da extrusora na troca do filamento" + +#: 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 "" +"Pode ser benéfico aumentar a corrente do motor da extrusora durante a " +"seqüência da troca do filamento para permitir taxas de alimentação de " +"Ramming rápidas e para superar a resistência ao carregar um filamento com " +"uma ponta feia." + +#: 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 "" +"Esta é a aceleração que sua impressora usará para preenchimento. Defina zero " +"para desabilitar o controle de aceleração para preenchimento." + +#: src/libslic3r/PrintConfig.cpp:967 +msgid "Combine infill every" +msgstr "Combine preenchimento a cada" + +#: 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 "" +"Este recurso permite combinar preenchimento e acelerar a sua impressão por " +"extrusão camadas de preenchimento mais espessa, preservando perímetros " +"finos, assim, a precisão." + +#: src/libslic3r/PrintConfig.cpp:972 +msgid "Combine infill every n layers" +msgstr "Combine preenchimento cada n camadas" + +#: src/libslic3r/PrintConfig.cpp:978 +msgid "Infill extruder" +msgstr "Extrusora de preenchimento" + +#: src/libslic3r/PrintConfig.cpp:980 +msgid "The extruder to use when printing infill." +msgstr "" +"A extrusora a ser utilizada quando estiver imprimindo preenchimento sólido." + +#: 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 " +"nozzle diameter will be used. You may want to use fatter extrudates to speed " +"up the infill and make your parts stronger. If expressed as percentage (for " +"example 90%) it will be computed over layer height." +msgstr "" +"Defina isso como um valor diferente de zero para definir uma largura de " +"extrusão manual para preenchimento. Se for deixado zero, a largura de " +"extrusão padrão será usada se definido, caso contrário, 1,125 x diâmetro da " +"ponteira será usado. Você pode querer usar extrusora mais larga para " +"acelerar o preenchimento e tornar suas peças mais fortes. Se expresso em " +"porcentagem(por exemplo, 90%) Ele será calculado sobre a altura da camada." + +#: src/libslic3r/PrintConfig.cpp:997 +msgid "Infill before perimeters" +msgstr "Preenchimento antes dos perímetros" + +#: src/libslic3r/PrintConfig.cpp:998 +msgid "" +"This option will switch the print order of perimeters and infill, making the " +"latter first." +msgstr "" +"Esta opção irá mudar a ordem de impressão de perímetros e preenchimento, " +"tornando o último primeiro." + +#: src/libslic3r/PrintConfig.cpp:1003 +msgid "Only infill where needed" +msgstr "Somente preenchimento onde necessário" + +#: 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 "" +"Esta opção limitará a preenchimento às áreas realmente necessárias para " +"suportar tetos (atuará como o material de sustentação interno). Se " +"habilitada, retarda a geração de G-code devido às várias verificações " +"envolvidas." + +#: src/libslic3r/PrintConfig.cpp:1012 +msgid "Infill/perimeters overlap" +msgstr "Sobreposição de preenchimento/perímetros" + +#: 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 " +"cause gaps. If expressed as percentage (example: 15%) it is calculated over " +"perimeter extrusion width." +msgstr "" +"Esta config. aplica uma sobreposição adicional entre preenchimento e " +"perímetros para melhor colagem. Teoricamente isso não deveria ser " +"necessário, mas a folga pode causar lacunas. Se expresso em " +"porcentagem(exemplo: 15%) é calculado sobre a largura da extrusão do " +"perímetro." + +#: src/libslic3r/PrintConfig.cpp:1025 +msgid "Speed for printing the internal fill. Set to zero for auto." +msgstr "" +"Velocidade para imprimir o preenchimento interno. Defina como zero para auto." + +#: src/libslic3r/PrintConfig.cpp:1033 +msgid "Inherits profile" +msgstr "Herda o perfil" + +#: src/libslic3r/PrintConfig.cpp:1034 +msgid "Name of the profile, from which this profile inherits." +msgstr "Nome do perfil, a partir do qual este perfil herda." + +#: src/libslic3r/PrintConfig.cpp:1047 +msgid "Interface shells" +msgstr "Interface dos perímetros externos." + +#: 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 "" +"Force a geração de perímetros externos sólidas entre materiais/volumes " +"adjacentes. Útil para cópias da multi-extrusora com materiais translúcidos " +"ou material de sustentação solúvel manual." + +#: 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 " +"use placeholder variables for all Slic3r settings as well as [layer_num] and " +"[layer_z]." +msgstr "" +"Este código personalizado é inserido em cada mudança de camada, logo após o " +"movimento Z e antes que a extrusora se mova para o primeiro ponto de camada. " +"Observe que você pode usar variáveis de espaço reservado para todas as " +"config. Slic3r, bem como [layer_num] e [layer_z]." + +#: src/libslic3r/PrintConfig.cpp:1068 +msgid "Supports remaining times" +msgstr "Tempo de impressão restante" + +#: 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. " +"As of now only the Prusa i3 MK3 firmware recognizes M73. Also the i3 MK3 " +"firmware supports M73 Qxx Sxx for the silent mode." +msgstr "" +"Emita M73 P [porcentagem impressa] R [tempo restante em minutos] em " +"intervalos de 1 minuto no G-code para permitir que o firmware mostre o tempo " +"restante exato. A partir de agora apenas o firmware Prusa i3 MK3 reconhece " +"M73. Além disso, o firmware i3 MK3 suporta M73 QXX Sxx para o modo " +"silencioso." + +#: src/libslic3r/PrintConfig.cpp:1077 +msgid "Supports stealth mode" +msgstr "Suporta o modo silencioso" + +#: src/libslic3r/PrintConfig.cpp:1078 +msgid "The firmware supports stealth mode" +msgstr "O firmware suporta o modo silencioso" + +#: src/libslic3r/PrintConfig.cpp:1102 +msgid "Maximum feedrate X" +msgstr "Máxima taxa de alimentação do X" + +#: src/libslic3r/PrintConfig.cpp:1103 +msgid "Maximum feedrate Y" +msgstr "Máxima taxa de alimentação do Y" + +#: src/libslic3r/PrintConfig.cpp:1104 +msgid "Maximum feedrate Z" +msgstr "Máxima taxa de alimentação do Z" + +#: src/libslic3r/PrintConfig.cpp:1105 +msgid "Maximum feedrate E" +msgstr "Máxima taxa de alimentação do E" + +#: src/libslic3r/PrintConfig.cpp:1108 +msgid "Maximum feedrate of the X axis" +msgstr "Máxima taxa de alimentação do eixo X" + +#: src/libslic3r/PrintConfig.cpp:1109 +msgid "Maximum feedrate of the Y axis" +msgstr "Máxima taxa de alimentação do eixo Y" + +#: src/libslic3r/PrintConfig.cpp:1110 +msgid "Maximum feedrate of the Z axis" +msgstr "Máxima taxa de alimentação do eixo Z" + +#: src/libslic3r/PrintConfig.cpp:1111 +msgid "Maximum feedrate of the E axis" +msgstr "Máxima taxa de alimentação do eixo E" + +#: src/libslic3r/PrintConfig.cpp:1120 +msgid "Maximum acceleration X" +msgstr "Aceleração máxima do X" + +#: src/libslic3r/PrintConfig.cpp:1121 +msgid "Maximum acceleration Y" +msgstr "Aceleração máxima do Y" + +#: src/libslic3r/PrintConfig.cpp:1122 +msgid "Maximum acceleration Z" +msgstr "Aceleração máxima do Z" + +#: src/libslic3r/PrintConfig.cpp:1123 +msgid "Maximum acceleration E" +msgstr "Aceleração máxima do E" + +#: src/libslic3r/PrintConfig.cpp:1126 +msgid "Maximum acceleration of the X axis" +msgstr "Aceleração máxima do eixo X" + +#: src/libslic3r/PrintConfig.cpp:1127 +msgid "Maximum acceleration of the Y axis" +msgstr "Aceleração máxima do eixo Y" + +#: src/libslic3r/PrintConfig.cpp:1128 +msgid "Maximum acceleration of the Z axis" +msgstr "Aceleração máxima do eixo Z" + +#: src/libslic3r/PrintConfig.cpp:1129 +msgid "Maximum acceleration of the E axis" +msgstr "Aceleração máxima do eixo E" + +#: src/libslic3r/PrintConfig.cpp:1138 +msgid "Maximum jerk X" +msgstr "Máximo empurrão X" + +#: src/libslic3r/PrintConfig.cpp:1139 +msgid "Maximum jerk Y" +msgstr "Máximo empurrão Y" + +#: src/libslic3r/PrintConfig.cpp:1140 +msgid "Maximum jerk Z" +msgstr "Máximo empurrão Z" + +#: src/libslic3r/PrintConfig.cpp:1141 +msgid "Maximum jerk E" +msgstr "Máximo empurrão E" + +#: src/libslic3r/PrintConfig.cpp:1144 +msgid "Maximum jerk of the X axis" +msgstr "Máximo empurrão do eixo X" + +#: src/libslic3r/PrintConfig.cpp:1145 +msgid "Maximum jerk of the Y axis" +msgstr "Máximo empurrão do eixo Y" + +#: src/libslic3r/PrintConfig.cpp:1146 +msgid "Maximum jerk of the Z axis" +msgstr "Máximo empurrão do eixo Z" + +#: src/libslic3r/PrintConfig.cpp:1147 +msgid "Maximum jerk of the E axis" +msgstr "Máximo empurrão do eixo E" + +#: src/libslic3r/PrintConfig.cpp:1158 +msgid "Minimum feedrate when extruding" +msgstr "Taxa de alimentação mínima ao extrudar" + +#: src/libslic3r/PrintConfig.cpp:1160 +msgid "Minimum feedrate when extruding (M205 S)" +msgstr "Taxa de alimentação mínima ao extrudar (M205 S)" + +#: src/libslic3r/PrintConfig.cpp:1169 +msgid "Minimum travel feedrate" +msgstr "Taxa de alimentação mínima ao viajar" + +#: src/libslic3r/PrintConfig.cpp:1171 +msgid "Minimum travel feedrate (M205 T)" +msgstr "Taxa de alimentação mínima ao viajar (M205 T)" + +#: src/libslic3r/PrintConfig.cpp:1180 +msgid "Maximum acceleration when extruding" +msgstr "Aceleração máxima quando expurgando" + +#: src/libslic3r/PrintConfig.cpp:1182 +msgid "Maximum acceleration when extruding (M204 S)" +msgstr "Aceleração máxima quando extrudando (M204 S)" + +#: src/libslic3r/PrintConfig.cpp:1191 +msgid "Maximum acceleration when retracting" +msgstr "Aceleração máxima durante a retração" + +#: src/libslic3r/PrintConfig.cpp:1193 +msgid "Maximum acceleration when retracting (M204 T)" +msgstr "Aceleração máxima quando retração (M204 T)" + +#: src/libslic3r/PrintConfig.cpp:1201 src/libslic3r/PrintConfig.cpp:1210 +msgid "Max" +msgstr "Máx" + +#: src/libslic3r/PrintConfig.cpp:1202 +msgid "This setting represents the maximum speed of your fan." +msgstr "Esta config. representa a velocidade máxima da sua ventoinha." + +#: src/libslic3r/PrintConfig.cpp:1211 +#, c-format +msgid "" +"This is the highest printable layer height for this extruder, used to cap " +"the variable layer height and support layer height. Maximum recommended " +"layer height is 75% of the extrusion width to achieve reasonable inter-layer " +"adhesion. If set to 0, layer height is limited to 75% of the nozzle diameter." +msgstr "" +"Esta é a altura mais alta imprimível para esta extrusora, usada para tampar " +"a altura variável da camada e suportar a altura da camada. A altura " +"recomendada máxima da camada é 75% o da largura da extrusão para conseguir a " +"adesão razoável entre camadas. Se definido como 0, a altura da camada é " +"limitada a 75% o do diâmetro da ponteira." + +#: src/libslic3r/PrintConfig.cpp:1221 +msgid "Max print speed" +msgstr "Velocidade máxima de impressão" + +#: 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 "" +"Ao definir outras config. de velocidade para 0, o Slic3r irá calcular " +"automaticamente a velocidade ideal, a fim de manter a pressão constante da " +"extrusora. Esta config. experimental é usada para definir a velocidade de " +"impressão mais alta que você deseja permitir." + +#: src/libslic3r/PrintConfig.cpp:1232 +msgid "" +"This experimental setting is used to set the maximum volumetric speed your " +"extruder supports." +msgstr "" +"Esta config. experimental é usada para definir a velocidade máxima " +"volumétrica que sua extrusora suporta." + +#: src/libslic3r/PrintConfig.cpp:1241 +msgid "Max volumetric slope positive" +msgstr "Inclinação volumétrica máx positiva" + +#: 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 " +"of 1.8 mm³/s (0.45mm extrusion width, 0.2mm extrusion height, feedrate 20 mm/" +"s) to 5.4 mm³/s (feedrate 60 mm/s) will take at least 2 seconds." +msgstr "" +"Esta config. experimental é usada para limitar a velocidade de mudança na " +"taxa de extrusão. Um valor de 1,8 mm ³/s ² assegura que uma alteração da " +"taxa de extrusão de 1,8 mm ³/s (largura de extrusão de 0,45 mm, altura de " +"extrusão de 0,2 mm, avanço de 20 mm/s) para 5,4 mm ³/s (avanço 60 mm/s) " +"levará pelo menos 2 segundos." + +#: src/libslic3r/PrintConfig.cpp:1246 src/libslic3r/PrintConfig.cpp:1257 +msgid "mm³/s²" +msgstr "mm ³/s ²" + +#: src/libslic3r/PrintConfig.cpp:1252 +msgid "Max volumetric slope negative" +msgstr "Inclinação volumétrica máx negativa" + +#: src/libslic3r/PrintConfig.cpp:1264 src/libslic3r/PrintConfig.cpp:1273 +msgid "Min" +msgstr "Min" + +#: src/libslic3r/PrintConfig.cpp:1265 +msgid "This setting represents the minimum PWM your fan needs to work." +msgstr "" +"Esta config. representa o PWM mínimo que seu ventoinha precisa para " +"trabalhar." + +#: 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 "" +"Esta é a altura mais baixa imprimível para esta extrusora e limita a " +"definição para a altura variável da camada. Os valores típicos são entre 0, " +"5 mm e 0,1 mm." + +#: src/libslic3r/PrintConfig.cpp:1282 +msgid "Min print speed" +msgstr "Velocidade mínima de impressão" + +#: src/libslic3r/PrintConfig.cpp:1283 +msgid "Slic3r will not scale speed down below this speed." +msgstr "Slic3r não vai escalar a velocidade abaixo desta velocidade." + +#: src/libslic3r/PrintConfig.cpp:1290 +msgid "Minimal filament extrusion length" +msgstr "Comprimento mínimo da extrusão do filamento" + +#: 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 "" +"Gerar não menos do que o número de voltas de saia necessários para consumir " +"a quantidade especificada de filamento na camada inferior. Para máquinas " +"multiextrusoras, este mínimo aplica-se a cada extrusora." + +#: src/libslic3r/PrintConfig.cpp:1300 +msgid "Configuration notes" +msgstr "Notas de config." + +#: 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 "" +"Você pode colocar aqui suas anotações pessoais. Este texto será adicionado " +"aos comentários do cabeçalho do G-code." + +#: src/libslic3r/PrintConfig.cpp:1311 +msgid "" +"This is the diameter of your extruder nozzle (for example: 0.5, 0.35 etc.)" +msgstr "" +"Este é o diâmetro da ponteira da extrusora (por exemplo: 0.5, 0.35 etc.)" + +#: src/libslic3r/PrintConfig.cpp:1316 +msgid "Host Type" +msgstr "Tipo de host" + +#: 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 "" +"Slic3r pode carregar arquivos de G-code para um host de impressora. Este " +"campo deve conter o tipo do host." + +#: src/libslic3r/PrintConfig.cpp:1328 +msgid "Only retract when crossing perimeters" +msgstr "Apenas retrair quando cruzar perímetros" + +#: 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 "" +"Desativa a retração quando o caminho de viagem não excede os perímetros da " +"camada superior (e, portanto, qualquer escorrimento será provavelmente " +"invisível)." + +#: 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 "" +"Esta opção irá descartar a temperatura das extrusoras inativas para evitar a " +"escorrimento. Ele vai permitir uma saia alta automaticamente e mover " +"extrusoras fora de tal saia quando a mudança de temperatura." + +#: src/libslic3r/PrintConfig.cpp:1343 +msgid "Output filename format" +msgstr "Formato de nome de arquivo de saída" + +#: 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], " +"[year], [month], [day], [hour], [minute], [second], [version], " +"[input_filename], [input_filename_base]." +msgstr "" +"Você pode usar todas as opções de config. como variáveis dentro deste " +"modelo. Por exemplo: [camada_altura], [densidade_preenchimento] etc. Você " +"também pode usar [tempo], [ano], [mês], [dia], [hora], [minuto], [segundo], " +"[versão], [nome_entrada], [nome_entrada_base]." + +#: src/libslic3r/PrintConfig.cpp:1353 +msgid "Detect bridging perimeters" +msgstr "Detectar perímetros de ponte" + +#: 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 "" +"Opção experimental para ajustar o fluxo para angulações (o fluxo da ponte " +"será usado), para aplicar a velocidade da ponte a eles e para habilitar a " +"ventoinha." + +#: src/libslic3r/PrintConfig.cpp:1361 +msgid "Filament parking position" +msgstr "Posição de estacionamento do filamento" + +#: 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 "" +"Distância da ponta da extrusora da posição onde o filamento está estacionado " +"quando descarregado. Isso deve corresponder ao valor no firmware da " +"impressora." + +#: src/libslic3r/PrintConfig.cpp:1370 +msgid "Extra loading distance" +msgstr "Distância de carregamento extra" + +#: 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 " +"positive, it is loaded further, if negative, the loading move is shorter " +"than unloading." +msgstr "" +"Quando ajustado a zero, a distância que o filamento é movida da posição do " +"estacionamento durante a carga é exatamente a mesma que foi movida para trás " +"durante o descarregamento. Quando positivo, ele é carregado ainda mais, se " +"negativo, o movimento de carga é menor do que o descarregamento." + +#: src/libslic3r/PrintConfig.cpp:1379 src/libslic3r/PrintConfig.cpp:1397 +#: src/libslic3r/PrintConfig.cpp:1409 src/libslic3r/PrintConfig.cpp:1419 +msgid "Perimeters" +msgstr "Perímetros" + +#: 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 "" +"Esta é a aceleração que sua impressora usará para perímetros. Um alto valor " +"como 9000 geralmente dá bons resultados se o seu hardware suporta. Defina " +"zero para desabilitar o controle de aceleração para perímetros." + +#: src/libslic3r/PrintConfig.cpp:1388 +msgid "Perimeter extruder" +msgstr "Extrusora de perímetro" + +#: src/libslic3r/PrintConfig.cpp:1390 +msgid "" +"The extruder to use when printing perimeters and brim. First extruder is 1." +msgstr "" +"A extrusora para usar ao imprimir perímetros e aba. A primeira extrusora é 1." + +#: 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 " +"left zero, default extrusion width will be used if set, otherwise 1.125 x " +"nozzle diameter will be used. If expressed as percentage (for example 200%) " +"it will be computed over layer height." +msgstr "" +"Defina isso como um valor diferente de zero para definir uma largura de " +"extrusão manual para perímetros. Você pode querer usar extrusões mais finos " +"para obter superfícies mais precisas. Se for deixado zero, a largura de " +"extrusão padrão será usada se definido, caso contrário, 1,125 x diâmetro da " +"ponteira será usado. Se expresso em porcentagem(por exemplo, 200%) Ele será " +"calculado sobre a altura da camada." + +#: src/libslic3r/PrintConfig.cpp:1411 +msgid "" +"Speed for perimeters (contours, aka vertical shells). Set to zero for auto." +msgstr "" +"Velocidade para perímetros (contornos, também chamadas de perímetros " +"externos verticais). Defina como zero para auto." + +#: 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 " +"surfaces which benefit from a higher number of perimeters if the Extra " +"Perimeters option is enabled." +msgstr "" +"Esta opção define o número de perímetros a gerar para cada camada. Observe " +"que o Slic3r pode aumentar esse número automaticamente quando detecta " +"superfícies inclinadas que se beneficiam de um número maior de perímetros se " +"a opção extra perímetros estiver habilitada." + +#: src/libslic3r/PrintConfig.cpp:1425 +msgid "(minimum)" +msgstr "(mínimo)" + +#: 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. " +"Scripts will be passed the absolute path to the G-code file as the first " +"argument, and they can access the Slic3r config settings by reading " +"environment variables." +msgstr "" +"Se você quiser processar o G-code de saída por meio de scripts " +"personalizados, basta listar seus caminhos absolutos aqui. Separe vários " +"scripts com um ponto-e-vírgula. Os scripts serão passados o caminho absoluto " +"para o arquivo de G-code como o primeiro argumento, e eles poderão acessar " +"as config. de config. do Slic3r lendo variáveis de ambiente." + +#: src/libslic3r/PrintConfig.cpp:1445 +msgid "Printer type" +msgstr "Tipo de impressora" + +#: src/libslic3r/PrintConfig.cpp:1446 +msgid "Type of the printer." +msgstr "Tipo da impressora." + +#: src/libslic3r/PrintConfig.cpp:1451 +msgid "Printer notes" +msgstr "Notas da impressora" + +#: src/libslic3r/PrintConfig.cpp:1452 +msgid "You can put your notes regarding the printer here." +msgstr "Você pode colocar suas anotações sobre a impressora aqui." + +#: src/libslic3r/PrintConfig.cpp:1460 +msgid "Printer vendor" +msgstr "Fornecedor da impressora" + +#: src/libslic3r/PrintConfig.cpp:1461 +msgid "Name of the printer vendor." +msgstr "Nome do fornecedor da impressora." + +#: src/libslic3r/PrintConfig.cpp:1466 +msgid "Printer variant" +msgstr "Variante da impressora" + +#: src/libslic3r/PrintConfig.cpp:1467 +msgid "" +"Name of the printer variant. For example, the printer variants may be " +"differentiated by a nozzle diameter." +msgstr "" +"Nome da variante da impressora. Por exemplo, as variantes da impressora " +"podem ser diferenciadas por um diâmetro da ponteira." + +#: src/libslic3r/PrintConfig.cpp:1480 +msgid "Raft layers" +msgstr "Camadas da estrado" + +#: 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 "" +"O objeto será elevado por este número de camadas, e o material de suporte " +"será gerado em baixo dele." + +#: src/libslic3r/PrintConfig.cpp:1490 +msgid "Resolution" +msgstr "Resolução" + +#: 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 " +"carry more detail than printers can render. Set to zero to disable any " +"simplification and use full resolution from input." +msgstr "" +"Resolução de detalhes mínimos, usada para simplificar o arquivo de entrada " +"para acelerar o trabalho de fatiamento e reduzir o uso de memória. Modelos " +"de alta resolução geralmente carregam mais detalhes do que as impressoras " +"podem renderizar. Defina como zero para desabilitar qualquer simplificação e " +"usar a resolução completa da entrada." + +#: src/libslic3r/PrintConfig.cpp:1501 +msgid "Minimum travel after retraction" +msgstr "Retração em viagens acima de" + +#: src/libslic3r/PrintConfig.cpp:1502 +msgid "" +"Retraction is not triggered when travel moves are shorter than this length." +msgstr "" +"A retração não é acionada quando os movimentos de viagem são mais curtos que " +"esse comprimento." + +#: src/libslic3r/PrintConfig.cpp:1508 +msgid "Retract amount before wipe" +msgstr "Quantidade de retração antes da limpeza" + +#: 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 "" +"Com extrusoras Bowden, pode ser sábio fazer alguma quantidade de retração " +"rápida antes de fazer o movimento da limpeza." + +#: src/libslic3r/PrintConfig.cpp:1516 +msgid "Retract on layer change" +msgstr "Retrair na mudança de camada" + +#: src/libslic3r/PrintConfig.cpp:1517 +msgid "This flag enforces a retraction whenever a Z move is done." +msgstr "Este sinalizador impõe uma retração sempre que um movimento Z é feito." + +#: src/libslic3r/PrintConfig.cpp:1522 src/libslic3r/PrintConfig.cpp:1530 +msgid "Length" +msgstr "Comprimento" + +#: src/libslic3r/PrintConfig.cpp:1523 +msgid "Retraction Length" +msgstr "Comprimento de retração" + +#: 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 "" +"Quando a retração é acionada, o filamento é puxado para trás pela quantidade " +"especificada (o comprimento é medido em filamento cru, antes de entrar na " +"extrusora)." + +#: src/libslic3r/PrintConfig.cpp:1526 src/libslic3r/PrintConfig.cpp:1535 +msgid "mm (zero to disable)" +msgstr "mm (zero para desativar)" + +#: src/libslic3r/PrintConfig.cpp:1531 +msgid "Retraction Length (Toolchange)" +msgstr "Comprimento de retração (mudança de ferramenta)" + +#: 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 "" +"Quando a retração é acionada antes de mudar de ferramenta, o filamento é " +"puxado para trás pela quantidade especificada (o comprimento é medido em " +"filamento cru, antes de entrar na extrusora)." + +#: src/libslic3r/PrintConfig.cpp:1540 +msgid "Lift Z" +msgstr "Elevar Z" + +#: 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 "" +"Se você definir isso como um valor positivo, Z é rapidamente elevado sempre " +"que uma retração é acionada. Ao usar várias extrusoras, somente a config. " +"para a primeira extrusora será considerada." + +#: src/libslic3r/PrintConfig.cpp:1548 +msgid "Above Z" +msgstr "Acima de Z" + +#: src/libslic3r/PrintConfig.cpp:1549 +msgid "Only lift Z above" +msgstr "Apenas elevar Z acima" + +#: 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 "" +"Se você definir isso como um valor positivo, o levante do Z só ocorrerá " +"acima do Z absoluto especificado. Você pode ajustar essa config. para pular " +"o elevador nas primeiras camadas." + +#: src/libslic3r/PrintConfig.cpp:1557 +msgid "Below Z" +msgstr "Abaixo de Z" + +#: src/libslic3r/PrintConfig.cpp:1558 +msgid "Only lift Z below" +msgstr "Apenas elevar Z abaixo" + +#: 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 "" +"Se você definir isso como um valor positivo, o levante do Z só ocorrerá " +"abaixo do Z absoluto especificado. Você pode ajustar essa config. para " +"limitar a elevação às primeiras camadas." + +#: src/libslic3r/PrintConfig.cpp:1567 src/libslic3r/PrintConfig.cpp:1575 +msgid "Extra length on restart" +msgstr "Comprimento extra no reinício" + +#: 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 "" +"Quando a retração é compensada após o movimento de viagem, a extrusora vai " +"empurrar esta quantidade adicional de filamento. Essa config. raramente é " +"necessária." + +#: src/libslic3r/PrintConfig.cpp:1576 +msgid "" +"When the retraction is compensated after changing tool, the extruder will " +"push this additional amount of filament." +msgstr "" +"Quando a retração é compensada após a ferramenta de mudança, a extrusora " +"empurrará esta quantidade adicional de filamento." + +#: src/libslic3r/PrintConfig.cpp:1583 src/libslic3r/PrintConfig.cpp:1584 +msgid "Retraction Speed" +msgstr "Velocidade da retração" + +#: src/libslic3r/PrintConfig.cpp:1585 +msgid "The speed for retractions (it only applies to the extruder motor)." +msgstr "A velocidade para retrações (aplica-se somente ao motor da extrusora)." + +#: src/libslic3r/PrintConfig.cpp:1591 src/libslic3r/PrintConfig.cpp:1592 +msgid "Deretraction Speed" +msgstr "Velocidade de retorno de retração" + +#: 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 "" +"A velocidade para o carregamento de um filamento na extrusora após a " +"retração (aplica-se somente ao motor da extrusora). Se deixada como zero, a " +"velocidade de retração é usada." + +#: src/libslic3r/PrintConfig.cpp:1600 +msgid "Seam position" +msgstr "Posição da costura" + +#: src/libslic3r/PrintConfig.cpp:1602 +msgid "Position of perimeters starting points." +msgstr "Posição inicial dos pontos do perímetro." + +#: src/libslic3r/PrintConfig.cpp:1608 +msgid "Random" +msgstr "Aleatório" + +#: src/libslic3r/PrintConfig.cpp:1609 +msgid "Nearest" +msgstr "Próximo" + +#: src/libslic3r/PrintConfig.cpp:1610 +msgid "Aligned" +msgstr "Alinhado(a)" + +#: src/libslic3r/PrintConfig.cpp:1618 +msgid "Direction" +msgstr "Direção" + +#: src/libslic3r/PrintConfig.cpp:1620 +msgid "Preferred direction of the seam" +msgstr "Direção preferida da costura" + +#: src/libslic3r/PrintConfig.cpp:1621 +msgid "Seam preferred direction" +msgstr "Direção de preferência da costura" + +#: src/libslic3r/PrintConfig.cpp:1628 +msgid "Jitter" +msgstr "Jitter" + +#: src/libslic3r/PrintConfig.cpp:1630 +msgid "Seam preferred direction jitter" +msgstr "Direção da costura preferencial para Jitter" + +#: src/libslic3r/PrintConfig.cpp:1631 +msgid "Preferred direction of the seam - jitter" +msgstr "Direção preferida da costura-jitter" + +#: src/libslic3r/PrintConfig.cpp:1641 +msgid "USB/serial port for printer connection." +msgstr "USB/porta serial para conexão da impressora." + +#: src/libslic3r/PrintConfig.cpp:1648 +msgid "Serial port speed" +msgstr "Velocidade da porta serial" + +#: src/libslic3r/PrintConfig.cpp:1649 +msgid "Speed (baud) of USB/serial port for printer connection." +msgstr "Velocidade (baud) do USB/porta serial para conexão da impressora." + +#: src/libslic3r/PrintConfig.cpp:1658 +msgid "Distance from object" +msgstr "Distância do objeto" + +#: 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 "" +"Distância entre a saia e o objeto (s). Defina isso como zero para anexar a " +"saia para o objeto (s) e obter uma aba para uma melhor aderência." + +#: src/libslic3r/PrintConfig.cpp:1666 +msgid "Skirt height" +msgstr "Altura da saia" + +#: 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 "" +"Altura da saia expressa em camadas. Defina isso como um valor alto para usar " +"a saia como um escudo contra rascunhos." + +#: src/libslic3r/PrintConfig.cpp:1674 +msgid "Loops (minimum)" +msgstr "Voltas (mínimo)" + +#: src/libslic3r/PrintConfig.cpp:1675 +msgid "Skirt Loops" +msgstr "Voltas de saia" + +#: 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 "" +"Número de voltas para a saia. Se a opção comprimento mínimo de extrusão " +"estiver definida, o número de voltas pode ser maior do que aquele " +"configurado aqui. Defina isso como zero para desabilitar a saia " +"completamente." + +#: src/libslic3r/PrintConfig.cpp:1684 +msgid "Slow down if layer print time is below" +msgstr "Diminuir a velocidade quando o tempo de impressão for menor que" + +#: 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 "" +"Se o tempo de impressão da camada for estimado abaixo desse número de " +"segundos, a velocidade de impressão será reduzida para estender a duração a " +"esse valor." + +#: src/libslic3r/PrintConfig.cpp:1695 +msgid "Small perimeters" +msgstr "Perímetro pequeno" + +#: 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 "" +"Este ajuste separado afetará a velocidade dos perímetros que têm o raio < = " +"6.5 mm (geralmente furos). Se expresso em porcentagem(por exemplo: 80%) Ele " +"será calculado sobre a velocidade de perímetros configurados acima. Defina " +"como zero para auto." + +#: src/libslic3r/PrintConfig.cpp:1707 +msgid "Solid infill threshold area" +msgstr "Área de limiar de preenchimento sólido" + +#: src/libslic3r/PrintConfig.cpp:1709 +msgid "" +"Force solid infill for regions having a smaller area than the specified " +"threshold." +msgstr "" +"Forçar preenchimento sólido para regiões com uma área menor do que o limite " +"especificado." + +#: src/libslic3r/PrintConfig.cpp:1710 +msgid "mm²" +msgstr "mm²" + +#: src/libslic3r/PrintConfig.cpp:1716 +msgid "Solid infill extruder" +msgstr "Extrusora de preenchimento sólido" + +#: src/libslic3r/PrintConfig.cpp:1718 +msgid "The extruder to use when printing solid infill." +msgstr "" +"A extrusora a ser utilizada quando estiver imprimindo preenchimento sólido." + +#: src/libslic3r/PrintConfig.cpp:1724 +msgid "Solid infill every" +msgstr "Preenchimento sólido a cada" + +#: 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 " +"will automatically choose the maximum possible number of layers to combine " +"according to nozzle diameter and layer height." +msgstr "" +"Este recurso permite forçar uma camada sólida a cada número determinado de " +"camadas. Zero para desabilitar. Você pode definir isso para qualquer valor " +"(por exemplo 9999); Slic3r escolherá automaticamente o número máximo " +"possível de camadas para combinar de acordo com o diâmetro da ponteira e a " +"altura da camada." + +#: 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, " +"otherwise 1.125 x nozzle diameter will be used. If expressed as percentage " +"(for example 90%) it will be computed over layer height." +msgstr "" +"Defina isso como um valor diferente de zero para definir uma largura de " +"extrusão manual para preenchimento de superfícies sólidas. Se for deixado " +"zero, a largura de extrusão padrão será usada se definido, caso contrário, " +"1,125 x diâmetro da ponteira será usado. Se expresso em porcentagem(por " +"exemplo, 90%) Ele será calculado sobre a altura da camada." + +#: 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 "" +"Velocidade para imprimir regiões sólidas (topo/fundo/perímetros externos " +"horizontais internas). Isto pode ser expresso em porcentagem(por exemplo: " +"80%) sobre a velocidade de preenchimento padrão acima. Defina como zero para " +"auto." + +#: src/libslic3r/PrintConfig.cpp:1760 +msgid "Number of solid layers to generate on top and bottom surfaces." +msgstr "" +"Número de camadas sólidas a serem geradas nas interfaces do topo e base." + +#: src/libslic3r/PrintConfig.cpp:1766 +msgid "Spiral vase" +msgstr "Vaso espiral" + +#: 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, " +"no infill, no top solid layers and no support material. You can still set " +"any number of bottom solid layers as well as skirt/brim loops. It won't work " +"when printing more than an object." +msgstr "" +"Este recurso irá elevar Z gradualmente durante a impressão de um objeto de " +"parede única, a fim de remover qualquer costura visível. Esta opção exige um " +"único perímetro, nenhum preenchimento, nenhumas camadas contínuas superiores " +"e nenhum material de sustentação. Você ainda pode definir qualquer número de " +"camadas sólidas de fundo, bem como saia/aba voltas. Ele não funcionará ao " +"imprimir mais de um objeto." + +#: src/libslic3r/PrintConfig.cpp:1775 +msgid "Temperature variation" +msgstr "Variação de temperatura" + +#: 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 "" +"Diferença de temperatura a ser aplicada quando uma extrusora não está ativa. " +"Permite uma saia \"sacrificial\" em que as ponteiras são limpadas " +"periodicamente." + +#: 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 " +"has finished heating. If PrusaSlicer detects M104 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 PrusaSlicer settings, so you can " +"put a \"M109 S[first_layer_temperature]\" command wherever you want." +msgstr "" +"Este procedimento do começo é introduzido no início, depois que a mesa " +"alcançou a temperatura alvo e a extrusora apenas começou o aquecimento, e " +"antes que a extrusora terminasse o aquecimento. Se PrusaSlicer detecta M104 " +"ou M190 em seus códigos personalizados, esses comandos não serão precedidos " +"automaticamente para que você esteja livre para personalizar a ordem dos " +"comandos de aquecimento e outras ações personalizadas. Observe que você pode " +"usar variáveis de espaço reservado para todas as config. de PrusaSlicer, " +"para que você possa colocar um comando \"M109 S " +"[temperatura_primeira_camada]\" onde quiser." + +#: src/libslic3r/PrintConfig.cpp:1801 +msgid "" +"This start procedure is inserted at the beginning, after any printer start " +"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 " +"PrusaSlicer 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 PrusaSlicer 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 "" +"Este procedimento de início é inserido no começo, depois de qualquer " +"impressora iniciar Gcode (e depois de qualquer troca de ferramenta para este " +"filamento em caso de impressoras de vários materiais). Isso é usado para " +"substituir as config. de um filamento específico. Se PrusaSlicer detecta " +"M104, M109, M140 ou M190 em seus códigos personalizados, esses comandos não " +"serão precedidos automaticamente para que você esteja livre para " +"personalizar a ordem dos comandos de aquecimento e outras ações " +"personalizadas. Observe que você pode usar variáveis de espaço reservado " +"para todas as config. de PrusaSlicer, para que você possa colocar um comando " +"\"M109 S [temperatura_primeira_camada]\" onde quiser. Se você tiver várias " +"extrusoras, o Gcode é processado em ordem de extrusora." + +#: src/libslic3r/PrintConfig.cpp:1817 +msgid "Single Extruder Multi Material" +msgstr "Única extrusora multi material" + +#: src/libslic3r/PrintConfig.cpp:1818 +msgid "The printer multiplexes filaments into a single hot end." +msgstr "A impressora multiplexes filamentos em uma única extremidade quente." + +#: src/libslic3r/PrintConfig.cpp:1823 +msgid "Prime all printing extruders" +msgstr "Extrusar todas as extrusoras de impressão" + +#: 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 "" +"Se ativada, todas as extrusoras de impressão extrusarão na aba dianteira da " +"mesa de impressão no início da impressão." + +#: src/libslic3r/PrintConfig.cpp:1829 +msgid "Generate support material" +msgstr "Gerar material de suporte" + +#: src/libslic3r/PrintConfig.cpp:1831 +msgid "Enable support material generation." +msgstr "Habilitar geração de material de suporte." + +#: src/libslic3r/PrintConfig.cpp:1835 +msgid "Auto generated supports" +msgstr "Gerar suportes automaticamente" + +#: 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 "" +"Se marcada, os suportes serão gerados automaticamente com base no valor do " +"limite de angulação. Se desmarcada, as sustentações serão geradas dentro dos " +"volumes do \"reforçador de suporte\" somente." + +#: src/libslic3r/PrintConfig.cpp:1843 +msgid "XY separation between an object and its support" +msgstr "Separação entre o objeto e seu suporte em XY" + +#: 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 "" +"Separação entre o objeto e seu suporte em XY. Se expresso como porcentagem " +"(por exemplo, 50%), será calculado com base na espessura do perímetro " +"externo." + +#: src/libslic3r/PrintConfig.cpp:1855 +msgid "Pattern angle" +msgstr "Ângulo do padrão" + +#: src/libslic3r/PrintConfig.cpp:1857 +msgid "" +"Use this setting to rotate the support material pattern on the horizontal " +"plane." +msgstr "" +"Use essa config. para girar o padrão de material de suporte no plano " +"horizontal." + +#: src/libslic3r/PrintConfig.cpp:1867 src/libslic3r/PrintConfig.cpp:2563 +msgid "" +"Only create support if it lies on a build plate. Don't create support on a " +"print." +msgstr "" +"Apenas criar suporte se ele está em uma mesa. Não crie suporte em uma " +"impressão." + +#: src/libslic3r/PrintConfig.cpp:1873 +msgid "Contact Z distance" +msgstr "Distância de contato Z" + +#: 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 "" +"A distância vertical entre o objeto e a interface de material de suporte. " +"Definir isso como 0 também impedirá Slic3r de usar o fluxo de ponte e a " +"velocidade para a primeira camada de objeto." + +#: src/libslic3r/PrintConfig.cpp:1882 +msgid "0 (soluble)" +msgstr "0 (solúvel)" + +#: src/libslic3r/PrintConfig.cpp:1883 +msgid "0.2 (detachable)" +msgstr "0.2 (destacável)" + +#: src/libslic3r/PrintConfig.cpp:1888 +msgid "Enforce support for the first" +msgstr "Reforçar suportes para a(s) primeira(s)" + +#: 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 " +"regardless of any angle threshold. This is useful for getting more adhesion " +"of objects having a very thin or poor footprint on the build plate." +msgstr "" +"Gere material de suporte para o número especificado de camadas que contam da " +"parte inferior, independentemente de o material de suporte normal estar " +"ativado ou não e independentemente de qualquer limite de ângulo. Isso é útil " +"para obter mais aderência de objetos com uma pegada muito fina ou fraca na " +"placa de construção." + +#: src/libslic3r/PrintConfig.cpp:1895 +msgid "Enforce support for the first n layers" +msgstr "Reforçar suportes na(s) primera(s) n camada(s)" + +#: src/libslic3r/PrintConfig.cpp:1901 +msgid "Support material/raft/skirt extruder" +msgstr "Extrusora de material de suporte/estrado/saia" + +#: 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 "" +"A extrusora a ser usada ao imprimir material de suporte, estrado e saia (1 " +"+, 0 para usar a extrusora atual para minimizar as mudanças na ferramenta)." + +#: 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, " +"otherwise nozzle diameter will be used. If expressed as percentage (for " +"example 90%) it will be computed over layer height." +msgstr "" +"Defina isso como um valor diferente de zero para definir uma largura de " +"extrusão manual para material de suporte. Se deixada em zero, a largura " +"padrão da extrusão será usada, se não o diâmetro da ponteira será usado. Se " +"expresso em porcentagem(por exemplo, 90%) Ele será calculado sobre a altura " +"da camada." + +#: src/libslic3r/PrintConfig.cpp:1920 +msgid "Interface loops" +msgstr "Voltas da interface" + +#: src/libslic3r/PrintConfig.cpp:1922 +msgid "" +"Cover the top contact layer of the supports with loops. Disabled by default." +msgstr "" +"Cubra a camada de contato superior dos suportes com laços. Desativado por " +"padrão." + +#: src/libslic3r/PrintConfig.cpp:1927 +msgid "Support material/raft interface extruder" +msgstr "Extrusora de material de suporte/estrado" + +#: 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 "" +"A extrusora para usar ao imprimir a relação material do apoio (1 +, 0 para " +"usar o extrusor atual para minimizar mudanças da ferramenta). Isso afeta o " +"estrado também." + +#: src/libslic3r/PrintConfig.cpp:1936 +msgid "Interface layers" +msgstr "Camadas de interface" + +#: src/libslic3r/PrintConfig.cpp:1938 +msgid "" +"Number of interface layers to insert between the object(s) and support " +"material." +msgstr "" +"Número de camadas de interface para inserir entre o objeto(s) e material de " +"suporte." + +#: src/libslic3r/PrintConfig.cpp:1945 +msgid "Interface pattern spacing" +msgstr "Espaçamento do padrão da interface" + +#: src/libslic3r/PrintConfig.cpp:1947 +msgid "Spacing between interface lines. Set zero to get a solid interface." +msgstr "" +"Espaçamento entre as linhas de interface. Defina zero para obter uma " +"interface sólida." + +#: 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 "" +"Velocidade para camadas de interface de material de suporte de impressão. Se " +"expresso em porcentagem(por exemplo, 50%) Ele será calculado sobre a " +"velocidade do material de suporte." + +#: src/libslic3r/PrintConfig.cpp:1965 +msgid "Pattern" +msgstr "Padrão" + +#: src/libslic3r/PrintConfig.cpp:1967 +msgid "Pattern used to generate support material." +msgstr "Padrão usado para gerar material de suporte." + +#: src/libslic3r/PrintConfig.cpp:1973 +msgid "Rectilinear grid" +msgstr "Grade rectilínea" + +#: src/libslic3r/PrintConfig.cpp:1979 +msgid "Pattern spacing" +msgstr "Padrão de espaçamento" + +#: src/libslic3r/PrintConfig.cpp:1981 +msgid "Spacing between support material lines." +msgstr "Espaçamento entre linhas de material de suporte." + +#: src/libslic3r/PrintConfig.cpp:1990 +msgid "Speed for printing support material." +msgstr "Velocidade para imprimir material de suporte." + +#: src/libslic3r/PrintConfig.cpp:1997 +msgid "Synchronize with object layers" +msgstr "Sincronizar com camadas de objeto" + +#: 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 "" +"Sincronize camadas de suporte com as camadas de impressão do objeto. Isto é " +"útil com as impressoras do multi-material, onde o interruptor da extrusora é " +"caro." + +#: src/libslic3r/PrintConfig.cpp:2005 +msgid "Overhang threshold" +msgstr "Limite de angulação" + +#: 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 " +"represent the most horizontal slope (measured from the horizontal plane) " +"that you can print without support material. Set to zero for automatic " +"detection (recommended)." +msgstr "" +"O material de suporte não será gerado para angulações cujo ângulo de " +"inclinação (90 ° = vertical) esteja acima do limite determinado. Em outras " +"palavras, esse valor representa a inclinação mais horizontal (medida a " +"partir do plano horizontal) que você pode imprimir sem material de suporte. " +"Defina como zero para detecção automática (recomendado)." + +#: src/libslic3r/PrintConfig.cpp:2019 +msgid "With sheath around the support" +msgstr "Com bainha em torno do apoio" + +#: 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 "" +"Adicione uma bainha (uma única linha de perímetro) em torno do suporte base. " +"Isso torna o suporte mais confiável, mas também mais difícil de remover." + +#: 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 "" +"Temperatura da extrusora para camadas após a primeira. Defina como zero para " +"desabilitar os comandos de controle de temperatura na saída." + +#: src/libslic3r/PrintConfig.cpp:2036 +msgid "Detect thin walls" +msgstr "Detectar paredes finas" + +#: 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 "" +"Detecte paredes de largura única (partes onde duas extrusões não cabem e " +"precisamos recolhê-las em um único traço)." + +#: src/libslic3r/PrintConfig.cpp:2044 +msgid "Threads" +msgstr "Roscas" + +#: 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 "" +"Tópicos são usados para paralelizar tarefas de execução demorada. O número " +"de tópicos ideais está ligeiramente acima do número de núcleos/processadores " +"disponíveis." + +#: src/libslic3r/PrintConfig.cpp:2057 +msgid "" +"This custom code is inserted before every toolchange. Placeholder variables " +"for all PrusaSlicer settings as well as {previous_extruder} and " +"{next_extruder} can be used. When a tool-changing command which changes to " +"the correct extruder is included (such as T{next_extruder}), PrusaSlicer " +"will emit no other such command. It is therefore possible to script custom " +"behaviour both before and after the toolchange." +msgstr "" +"Este código personalizado é inserido antes de cada troca de ferramenta. " +"Variáveis de espaço reservado para todas as config. de PrusaSlicer, bem como " +"{previous_extruder} e {next_extruder} podem ser usadas. Quando um comando de " +"mudança de ferramenta que muda para a extrusora correta está incluído (como " +"T {next_extruder}), PrusaSlicer emitirá nenhum outro comando tal. Portanto, " +"é possível script comportamento personalizado antes e depois da mudança de " +"ferramenta." + +#: 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 " +"regions and get a smoother finish. If left zero, default extrusion width " +"will be used if set, otherwise nozzle diameter will be used. If expressed as " +"percentage (for example 90%) it will be computed over layer height." +msgstr "" +"Defina isso como um valor diferente de zero para definir uma largura de " +"extrusão manual para preenchimento para superfícies superiores. Você pode " +"querer usar extrusões mais finos para preencher todas as regiões estreitas e " +"obter um acabamento mais suave. Se a esquerda zero, a largura padrão da " +"extrusão será usada se ajustado, se não o diâmetro da ponteira será usado. " +"Se expresso em porcentagem(por exemplo, 90%) Ele será calculado sobre a " +"altura da camada." + +#: 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 " +"slow down this to get a nicer surface finish. This can be expressed as a " +"percentage (for example: 80%) over the solid infill speed above. Set to zero " +"for auto." +msgstr "" +"Velocidade para imprimir camadas sólidas superiores (só se aplica às camadas " +"externas superiores e não às suas camadas sólidas internas). Você pode " +"querer diminuir este para ter um revestimento de superfície mais agradável. " +"Isto pode ser expresso em porcentagem(por exemplo: 80%) sobre a velocidade " +"de preenchimento sólido acima. Defina como zero para auto." + +#: src/libslic3r/PrintConfig.cpp:2096 +msgid "Number of solid layers to generate on top surfaces." +msgstr "Número de camadas sólidas para gerar em superfícies superiores." + +#: src/libslic3r/PrintConfig.cpp:2097 +msgid "Top solid layers" +msgstr "Camadas sólidas de topo" + +#: src/libslic3r/PrintConfig.cpp:2103 +msgid "Speed for travel moves (jumps between distant extrusion points)." +msgstr "" +"Velocidade para movimentos de viagem (saltos entre pontos de extrusão " +"distantes)." + +#: src/libslic3r/PrintConfig.cpp:2111 +msgid "Use firmware retraction" +msgstr "Usar retração do firmware" + +#: 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 "" +"Esta config. experimental usa comandos G10 e G11 para que o firmware " +"manipule a retração. Isso só é suportado no recente Marlin." + +#: src/libslic3r/PrintConfig.cpp:2118 +msgid "Use relative E distances" +msgstr "Utilizar distâncias relativas do E" + +#: 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 "" +"Se o firmware necessitar de valores relativos E, verifique isto, caso " +"contrário, deixe-o desmarcado. A maioria dos firmwares usa valores absolutos." + +#: src/libslic3r/PrintConfig.cpp:2125 +msgid "Use volumetric E" +msgstr "Usar E volumétrico" + +#: 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 " +"filament diameter(s), you can put commands like 'M200 D[filament_diameter_0] " +"T0' in your start G-code in order to turn volumetric mode on and use the " +"filament diameter associated to the filament selected in Slic3r. This is " +"only supported in recent Marlin." +msgstr "" +"Essa config. experimental usa saídas os valores E em milímetros cúbicos em " +"vez de milímetros lineares. Se o firmware já não souber o diâmetro (s) do " +"filamento, você pode colocar comandos como ' m 200 D [filament_diameter_0] " +"T0 ' no seu G-code inicial para ativar o modo volumétrico e usar o diâmetro " +"do filamento associado ao filamento selecionado em Slic3r. Isso só é " +"suportado no recente Marlin." + +#: src/libslic3r/PrintConfig.cpp:2136 +msgid "Enable variable layer height feature" +msgstr "Habilitar altura de camada variável" + +#: src/libslic3r/PrintConfig.cpp:2137 +msgid "" +"Some printers or printer setups may have difficulties printing with a " +"variable layer height. Enabled by default." +msgstr "" +"Algumas impressoras ou config. de impressora podem ter dificuldades para " +"imprimir com uma altura de camada variável. Ativado por padrão." + +#: src/libslic3r/PrintConfig.cpp:2143 +msgid "Wipe while retracting" +msgstr "Limpe durante a retração" + +#: src/libslic3r/PrintConfig.cpp:2144 +msgid "" +"This flag will move the nozzle while retracting to minimize the possible " +"blob on leaky extruders." +msgstr "" +"Esta bandeira moverá a ponteira ao retrair para minimizar a bolha possível " +"em extrusoras vazando." + +#: 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 "" +"Várias impressoras de multi-material podem precisar purgar extrusoras em " +"alterações de ferramenta. EXTRUDE o excesso de material para a torre de " +"limpeza." + +#: src/libslic3r/PrintConfig.cpp:2157 +msgid "Purging volumes - load/unload volumes" +msgstr "Volumes de purga-volumes de carga/descarregamento" + +#: 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 "" +"Este vetor salva os volumes necessários para mudar de/para cada ferramenta " +"usada na torre de limpeza. Esses valores são usados para simplificar a " +"criação dos volumes de purga completos abaixo." + +#: src/libslic3r/PrintConfig.cpp:2164 +msgid "Purging volumes - matrix" +msgstr "Volumes de purga-matriz" + +#: 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 "" +"Esta matriz descreve volumes (em milimetros cúbicos) necessários para limpar " +"o novo filamento na torre de limpeza para qualquer dado par de ferramentas." + +#: src/libslic3r/PrintConfig.cpp:2174 +msgid "Position X" +msgstr "Posição X" + +#: src/libslic3r/PrintConfig.cpp:2175 +msgid "X coordinate of the left front corner of a wipe tower" +msgstr "Coordenada X do canto frontal esquerdo de uma torre de limpeza" + +#: src/libslic3r/PrintConfig.cpp:2181 +msgid "Position Y" +msgstr "Posição Y" + +#: src/libslic3r/PrintConfig.cpp:2182 +msgid "Y coordinate of the left front corner of a wipe tower" +msgstr "Coordenada Y do canto dianteiro esquerdo de uma torre de limpeza" + +#: src/libslic3r/PrintConfig.cpp:2189 +msgid "Width of a wipe tower" +msgstr "Largura de uma torre da limpeza" + +#: src/libslic3r/PrintConfig.cpp:2195 +msgid "Wipe tower rotation angle" +msgstr "Ângulo de rotação da torre" + +#: src/libslic3r/PrintConfig.cpp:2196 +msgid "Wipe tower rotation angle with respect to x-axis." +msgstr "Ângulo de rotação da torre de limpeza em relação ao eixo X." + +#: src/libslic3r/PrintConfig.cpp:2203 +msgid "Wipe into this object's infill" +msgstr "Limpe no preenchimento deste objeto" + +#: 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 "" +"Purga após troca de ferramenta será feito dentro de preenchimentos deste " +"objeto. Isso diminui a quantidade de resíduos, mas pode resultar em tempo de " +"impressão mais longo devido a movimentos de viagem adicionais." + +#: src/libslic3r/PrintConfig.cpp:2211 +msgid "Wipe into this object" +msgstr "Limpar neste objeto" + +#: 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 "" +"Objeto será usado para limpar o bico após uma troca de ferramenta para " +"salvar o material que de outra forma acabaria na torre de limpeza e diminuir " +"o tempo de impressão. As cores dos objetos serão misturadas como resultado." + +#: src/libslic3r/PrintConfig.cpp:2218 +msgid "Maximal bridging distance" +msgstr "Distância de ponte máxima" + +#: src/libslic3r/PrintConfig.cpp:2219 +msgid "Maximal distance between supports on sparse infill sections." +msgstr "" +"Distância máxima entre as sustentações em seções preenchimento esparsas." + +#: src/libslic3r/PrintConfig.cpp:2225 +msgid "XY Size Compensation" +msgstr "Compensação de tamanho em XY" + +#: 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 "" +"O objeto será aumentado/encolhido no plano XY pelo valor configurado " +"(negativo = para dentro, positivo = para fora). Isso pode ser útil para " +"ajustar os tamanhos dos furos." + +#: src/libslic3r/PrintConfig.cpp:2235 +msgid "Z offset" +msgstr "Compensamento do Z" + +#: 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 " +"example, if your endstop zero actually leaves the nozzle 0.3mm far from the " +"print bed, set this to -0.3 (or fix your endstop)." +msgstr "" +"Esse valor será adicionado (ou subtraído) de todas as coordenadas Z no G-" +"code de saída. Ele é usado para compensar a posição de final de curso Z " +"ruim: por exemplo, se o seu final de curso zero realmente deixa o bico 0.3 " +"mm longe da mesa de impressão, defina este para-0,3 (ou corrigir o seu final " +"de curso)." + +#: src/libslic3r/PrintConfig.cpp:2294 +msgid "Display width" +msgstr "Largura do display" + +#: src/libslic3r/PrintConfig.cpp:2295 +msgid "Width of the display" +msgstr "Largura do display" + +#: src/libslic3r/PrintConfig.cpp:2300 +msgid "Display height" +msgstr "Altura do display" + +#: src/libslic3r/PrintConfig.cpp:2301 +msgid "Height of the display" +msgstr "Altura do display" + +#: src/libslic3r/PrintConfig.cpp:2306 +msgid "Number of pixels in" +msgstr "Número de pixels em" + +#: src/libslic3r/PrintConfig.cpp:2308 +msgid "Number of pixels in X" +msgstr "Número de pixels em X" + +#: src/libslic3r/PrintConfig.cpp:2314 +msgid "Number of pixels in Y" +msgstr "Número de pixels em Y" + +#: src/libslic3r/PrintConfig.cpp:2319 +msgid "Display horizontal mirroring" +msgstr "Exibir espelhamento horizontal" + +#: src/libslic3r/PrintConfig.cpp:2320 +msgid "Mirror horizontally" +msgstr "Espelhar horizontalmente" + +#: src/libslic3r/PrintConfig.cpp:2321 +msgid "Enable horizontal mirroring of output images" +msgstr "Habilitar espelhamento horizontal de imagens de saída" + +#: src/libslic3r/PrintConfig.cpp:2326 +msgid "Display vertical mirroring" +msgstr "Exibir espelhamento vertical" + +#: src/libslic3r/PrintConfig.cpp:2327 +msgid "Mirror vertically" +msgstr "Espelharvertical" + +#: src/libslic3r/PrintConfig.cpp:2328 +msgid "Enable vertical mirroring of output images" +msgstr "Habilitar espelhamento vertical de imagens de saída" + +#: src/libslic3r/PrintConfig.cpp:2333 +msgid "Display orientation" +msgstr "Orientação do display" + +#: 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 "" +"Defina a orientação real do visor LCD dentro da impressora SLA. O modo " +"retrato inverterá o significado dos parâmetros de largura e altura da tela e " +"as imagens de saída serão giradas por 90 graus." + +#: src/libslic3r/PrintConfig.cpp:2340 +msgid "Landscape" +msgstr "Paisagem" + +#: src/libslic3r/PrintConfig.cpp:2341 +msgid "Portrait" +msgstr "Retrato" + +#: src/libslic3r/PrintConfig.cpp:2346 +msgid "Fast" +msgstr "Rápido" + +#: src/libslic3r/PrintConfig.cpp:2347 +msgid "Fast tilt" +msgstr "Inclinação rápida" + +#: src/libslic3r/PrintConfig.cpp:2348 +msgid "Time of the fast tilt" +msgstr "Tempo da inclinação rápida" + +#: src/libslic3r/PrintConfig.cpp:2355 +msgid "Slow" +msgstr "Lento" + +#: src/libslic3r/PrintConfig.cpp:2356 +msgid "Slow tilt" +msgstr "Inclinação lenta" + +#: src/libslic3r/PrintConfig.cpp:2357 +msgid "Time of the slow tilt" +msgstr "Tempo da inclinação lenta" + +#: src/libslic3r/PrintConfig.cpp:2364 +msgid "Area fill" +msgstr "Preenchimento de área" + +#: 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 "" +"A porcentagem da área de mesa. \n" +"Se a área de impressão exceder o valor especificado, \n" +"em seguida, uma inclinação lenta será usada, caso contrário-uma inclinação " +"rápida" + +#: src/libslic3r/PrintConfig.cpp:2372 src/libslic3r/PrintConfig.cpp:2373 +#: src/libslic3r/PrintConfig.cpp:2374 +msgid "Printer scaling correction" +msgstr "Correção de dimensionamento da impressora" + +#: src/libslic3r/PrintConfig.cpp:2380 src/libslic3r/PrintConfig.cpp:2381 +msgid "Printer absolute correction" +msgstr "Correção absoluta da impressora" + +#: src/libslic3r/PrintConfig.cpp:2382 +msgid "" +"Will inflate or deflate the sliced 2D polygons according to the sign of the " +"correction." +msgstr "" +"Irá inflar ou esvaziar os polígonos 2D cortados de acordo com o sinal da " +"correção." + +#: src/libslic3r/PrintConfig.cpp:2388 src/libslic3r/PrintConfig.cpp:2389 +msgid "Printer gamma correction" +msgstr "Correção de gama de impressora" + +#: 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 "" +"Isso aplicará uma correção de gama para os polígonos 2D rasterizados. Um " +"valor gama de zero significa limiarização com o limiar no meio. Este " +"comportamento elimina suavização sem perder buracos em polígonos." + +#: src/libslic3r/PrintConfig.cpp:2401 src/libslic3r/PrintConfig.cpp:2402 +msgid "Initial layer height" +msgstr "Altura da camada inicial" + +#: src/libslic3r/PrintConfig.cpp:2408 +msgid "Faded layers" +msgstr "Camadas desbotadas" + +#: 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 "" +"Número de camadas necessárias para o tempo de exposição desvanecer-se do " +"tempo de exposição inicial ao tempo de exposição" + +#: src/libslic3r/PrintConfig.cpp:2416 src/libslic3r/PrintConfig.cpp:2417 +msgid "Minimum exposure time" +msgstr "Tempo mínimo de exposição" + +#: src/libslic3r/PrintConfig.cpp:2424 src/libslic3r/PrintConfig.cpp:2425 +msgid "Maximum exposure time" +msgstr "Tempo máximo de exposição" + +#: src/libslic3r/PrintConfig.cpp:2432 src/libslic3r/PrintConfig.cpp:2433 +msgid "Exposure time" +msgstr "Tempo de exposição" + +#: src/libslic3r/PrintConfig.cpp:2439 src/libslic3r/PrintConfig.cpp:2440 +msgid "Minimum initial exposure time" +msgstr "Tempo inicial mínimo de exposição" + +#: src/libslic3r/PrintConfig.cpp:2447 src/libslic3r/PrintConfig.cpp:2448 +msgid "Maximum initial exposure time" +msgstr "Tempo inicial máximo de exposição" + +#: src/libslic3r/PrintConfig.cpp:2455 src/libslic3r/PrintConfig.cpp:2456 +msgid "Initial exposure time" +msgstr "Tempo inicial mínimo de exposição" + +#: src/libslic3r/PrintConfig.cpp:2462 src/libslic3r/PrintConfig.cpp:2463 +msgid "Correction for expansion" +msgstr "Correção para expansão" + +#: src/libslic3r/PrintConfig.cpp:2469 +msgid "SLA print material notes" +msgstr "Notas de material de impressão de SLA" + +#: src/libslic3r/PrintConfig.cpp:2470 +msgid "You can put your notes regarding the SLA print material here." +msgstr "" +"Você pode colocar suas anotações sobre o material de impressão de SLA aqui." + +#: src/libslic3r/PrintConfig.cpp:2478 src/libslic3r/PrintConfig.cpp:2489 +msgid "Default SLA material profile" +msgstr "Perfil de material de SLA padrão" + +#: src/libslic3r/PrintConfig.cpp:2500 +msgid "Generate supports" +msgstr "Gerar suportes" + +#: src/libslic3r/PrintConfig.cpp:2502 +msgid "Generate supports for the models" +msgstr "Gere suportes para os modelos" + +#: src/libslic3r/PrintConfig.cpp:2507 +msgid "Support head front diameter" +msgstr "Diâmetro dianteiro principal da sustentação" + +#: src/libslic3r/PrintConfig.cpp:2509 +msgid "Diameter of the pointing side of the head" +msgstr "Diâmetro do lado apontando da cabeça" + +#: src/libslic3r/PrintConfig.cpp:2516 +msgid "Support head penetration" +msgstr "Suporte de penetração da cabeça" + +#: src/libslic3r/PrintConfig.cpp:2518 +msgid "How much the pinhead has to penetrate the model surface" +msgstr "Quanto a cabeça de alfinete tem de penetrar na superfície do modelo" + +#: src/libslic3r/PrintConfig.cpp:2525 +msgid "Support head width" +msgstr "Largura da cabeça de suporte" + +#: src/libslic3r/PrintConfig.cpp:2527 +msgid "Width from the back sphere center to the front sphere center" +msgstr "Largura do centro da esfera traseira ao centro da esfera dianteira" + +#: src/libslic3r/PrintConfig.cpp:2535 +msgid "Support pillar diameter" +msgstr "Diâmetro do pilar do suporte" + +#: src/libslic3r/PrintConfig.cpp:2537 +msgid "Diameter in mm of the support pillars" +msgstr "Diâmetro em mm dos pilares de suporte" + +#: src/libslic3r/PrintConfig.cpp:2545 +msgid "Support pillar connection mode" +msgstr "Modalidade da conexão da coluna da sustentação" + +#: src/libslic3r/PrintConfig.cpp:2546 +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 "" +"Controla o tipo de ponte entre dois pilares vizinhos. Pode ser zig-zag, Cruz " +"(zig-zag dobro) ou dinâmico que comutará automaticamente entre os primeiros " +"dois dependendo da distância dos dois pilares." + +#: src/libslic3r/PrintConfig.cpp:2554 +msgid "Zig-Zag" +msgstr "Zig-Zag" + +#: src/libslic3r/PrintConfig.cpp:2555 +msgid "Cross" +msgstr "Cruz" + +#: src/libslic3r/PrintConfig.cpp:2556 +msgid "Dynamic" +msgstr "Dinâmico" + +#: src/libslic3r/PrintConfig.cpp:2568 +msgid "Pillar widening factor" +msgstr "Fator de alargamento da coluna" + +#: src/libslic3r/PrintConfig.cpp:2570 +msgid "" +"Merging bridges or pillars into another pillars can increase the radius. " +"Zero means no increase, one means full increase." +msgstr "" +"Mesclar pontes ou pilares em outros pilares pode aumentar o raio. Zero " +"significa que não há aumento, um significa aumento total." + +#: src/libslic3r/PrintConfig.cpp:2579 +msgid "Support base diameter" +msgstr "Diâmetro base do suporte" + +#: src/libslic3r/PrintConfig.cpp:2581 +msgid "Diameter in mm of the pillar base" +msgstr "Diâmetro em mm da base do pilar" + +#: src/libslic3r/PrintConfig.cpp:2589 +msgid "Support base height" +msgstr "Altura base do suporte" + +#: src/libslic3r/PrintConfig.cpp:2591 +msgid "The height of the pillar base cone" +msgstr "A altura do cone da base da coluna" + +#: src/libslic3r/PrintConfig.cpp:2598 +msgid "Support base safety distance" +msgstr "Distância da segurança da base da sustentação" + +#: src/libslic3r/PrintConfig.cpp:2601 +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 "" +"A distância mínima da base do pilar do modelo em mm. faz sentido no modo de " +"elevação zero, onde uma lacuna de acordo com este parâmetro é inserida entre " +"o modelo e o pad." + +#: src/libslic3r/PrintConfig.cpp:2611 +msgid "Critical angle" +msgstr "Ângulo crítico" + +#: src/libslic3r/PrintConfig.cpp:2613 +msgid "The default angle for connecting support sticks and junctions." +msgstr "O ângulo padrão para conectar suportes e junções." + +#: src/libslic3r/PrintConfig.cpp:2621 +msgid "Max bridge length" +msgstr "Comprimento máximo da ponte" + +#: src/libslic3r/PrintConfig.cpp:2623 +msgid "The max length of a bridge" +msgstr "O comprimento máximo de uma ponte" + +#: src/libslic3r/PrintConfig.cpp:2630 +msgid "Max pillar linking distance" +msgstr "Distância máxima de conexão entre pilares" + +#: src/libslic3r/PrintConfig.cpp:2632 +msgid "" +"The max distance of two pillars to get linked with each other. A zero value " +"will prohibit pillar cascading." +msgstr "" +"A distância máxima de dois pilares para ficar ligado uns com os outros. Um " +"valor zero irá proibir o pilar em cascata." + +#: src/libslic3r/PrintConfig.cpp:2640 +msgid "Object elevation" +msgstr "Elevação do objeto" + +#: src/libslic3r/PrintConfig.cpp:2642 +msgid "" +"How much the supports should lift up the supported object. If \"Pad around " +"object\" is enabled, this value is ignored." +msgstr "" +"Quanto os suportes devem levantar o objecto suportado. Se \"pad em torno do " +"objeto\" estiver habilitado, esse valor será ignorado." + +#: src/libslic3r/PrintConfig.cpp:2653 +msgid "This is a relative measure of support points density." +msgstr "Esta é uma medida relativa de densidade de pontos de suporte." + +#: src/libslic3r/PrintConfig.cpp:2659 +msgid "Minimal distance of the support points" +msgstr "Distância mínima dos pontos de suporte" + +#: src/libslic3r/PrintConfig.cpp:2661 +msgid "No support points will be placed closer than this threshold." +msgstr "Nenhum ponto de apoio será colocado mais perto do que este limiar." + +#: src/libslic3r/PrintConfig.cpp:2667 +msgid "Use pad" +msgstr "Use pad" + +#: src/libslic3r/PrintConfig.cpp:2669 +msgid "Add a pad underneath the supported model" +msgstr "Adicionar um pad por baixo do modelo suportado" + +#: src/libslic3r/PrintConfig.cpp:2674 +msgid "Pad wall thickness" +msgstr "Espessura da parede do pad" + +#: src/libslic3r/PrintConfig.cpp:2676 +msgid "The thickness of the pad and its optional cavity walls." +msgstr "A espessura da pad e suas paredes de cavidade opcionais." + +#: src/libslic3r/PrintConfig.cpp:2684 +msgid "Pad wall height" +msgstr "Altura da parede do pad" + +#: src/libslic3r/PrintConfig.cpp:2685 +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 " +"effect inside the cavity, which makes peeling the print off the vat foil " +"difficult." +msgstr "" +"Define a profundidade da cavidade da pad. Defina como zero para desabilitar " +"a cavidade. Tenha cuidado ao ativar este recurso, como algumas resinas podem " +"produzir um efeito de sucção extrema dentro da cavidade, o que torna a " +"descascar a impressão fora da folha de IVA difícil." + +#: src/libslic3r/PrintConfig.cpp:2698 +msgid "Max merge distance" +msgstr "Distância máxima da fusão" + +#: src/libslic3r/PrintConfig.cpp:2700 +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 "" +"Alguns objetos podem se dar bem com algumas pads menores em vez de um único " +"grande. Este parâmetro define até que ponto o centro de duas pads menores " +"deve ser. Se eles estão mais perto, eles vão se fundir em uma pad." + +#: src/libslic3r/PrintConfig.cpp:2720 +msgid "Pad wall slope" +msgstr "Inclinação da parede da pad" + +#: src/libslic3r/PrintConfig.cpp:2722 +msgid "" +"The slope of the pad wall relative to the bed plane. 90 degrees means " +"straight walls." +msgstr "" +"A inclinação da parede da pad em relação ao plano da mesa. 90 graus " +"significa paredes retas." + +#: src/libslic3r/PrintConfig.cpp:2731 +msgid "Pad around object" +msgstr "Pad em torno do objeto" + +#: src/libslic3r/PrintConfig.cpp:2733 +msgid "Create pad around object and ignore the support elevation" +msgstr "Criar pad ao redor do objeto e ignorar a elevação de suporte" + +#: src/libslic3r/PrintConfig.cpp:2738 +msgid "Pad object gap" +msgstr "Vão entre o pad e o objeto" + +#: src/libslic3r/PrintConfig.cpp:2740 +msgid "" +"The gap between the object bottom and the generated pad in zero elevation " +"mode." +msgstr "" +"A lacuna entre a parte inferior do objeto e o pad gerado no modo de elevação " +"zero." + +#: src/libslic3r/PrintConfig.cpp:2749 +msgid "Pad object connector stride" +msgstr "Inserir pad entre o objeto" + +#: src/libslic3r/PrintConfig.cpp:2751 +msgid "" +"Distance between two connector sticks which connect the object and the " +"generated pad." +msgstr "" +"Distância entre duas varas do conector que conectam o objeto e a pad gerada." + +#: src/libslic3r/PrintConfig.cpp:2758 +msgid "Pad object connector width" +msgstr "Largura do conector do objeto pad" + +#: src/libslic3r/PrintConfig.cpp:2760 +msgid "" +"Width of the connector sticks which connect the object and the generated pad." +msgstr "Largura das varas do conector que conectam o objeto e a pad gerada." + +#: src/libslic3r/PrintConfig.cpp:2767 +msgid "Pad object connector penetration" +msgstr "Pad objeto conector de penetração" + +#: src/libslic3r/PrintConfig.cpp:2770 +msgid "How much should the tiny connectors penetrate into the model body." +msgstr "Quanto deve os conectores minúsculos penetrar no corpo do modelo." + +#: src/libslic3r/PrintConfig.cpp:3130 +msgid "Export OBJ" +msgstr "Exportar OBJ" + +#: src/libslic3r/PrintConfig.cpp:3131 +msgid "Export the model(s) as OBJ." +msgstr "Exportar modelo(s) como OBJ." + +#: src/libslic3r/PrintConfig.cpp:3142 +msgid "Export SLA" +msgstr "Exportar SLA" + +#: src/libslic3r/PrintConfig.cpp:3143 +msgid "Slice the model and export SLA printing layers as PNG." +msgstr "Fatiar o modelo e exportar as camadas de impressão SLA como PNG." + +#: src/libslic3r/PrintConfig.cpp:3148 +msgid "Export 3MF" +msgstr "Exportar 3MF" + +#: src/libslic3r/PrintConfig.cpp:3149 +msgid "Export the model(s) as 3MF." +msgstr "Exportar modelo(s) como 3MF." + +#: src/libslic3r/PrintConfig.cpp:3153 +msgid "Export AMF" +msgstr "Exportar AMF" + +#: src/libslic3r/PrintConfig.cpp:3154 +msgid "Export the model(s) as AMF." +msgstr "Exportar modelo(s) como AMF." + +#: src/libslic3r/PrintConfig.cpp:3158 +msgid "Export STL" +msgstr "Exportar STL" + +#: src/libslic3r/PrintConfig.cpp:3159 +msgid "Export the model(s) as STL." +msgstr "Exportar modelo(s) como STL." + +#: src/libslic3r/PrintConfig.cpp:3164 +msgid "Slice the model and export toolpaths as G-code." +msgstr "Fatiar o modelo e exportar o percurso da ferramenta como G-code." + +#: src/libslic3r/PrintConfig.cpp:3169 +msgid "Slice" +msgstr "Fatiar" + +#: src/libslic3r/PrintConfig.cpp:3170 +msgid "" +"Slice the model as FFF or SLA based on the printer_technology configuration " +"value." +msgstr "" +"Divida o modelo como FFF ou SLA com base no valor de config. " +"printer_technology." + +#: src/libslic3r/PrintConfig.cpp:3175 +msgid "Help" +msgstr "Ajuda" + +#: src/libslic3r/PrintConfig.cpp:3176 +msgid "Show this help." +msgstr "Mostrar esta ajuda." + +#: src/libslic3r/PrintConfig.cpp:3181 +msgid "Help (FFF options)" +msgstr "Ajuda (opções FDM)" + +#: src/libslic3r/PrintConfig.cpp:3182 +msgid "Show the full list of print/G-code configuration options." +msgstr "Mostre a lista completa de opções de config. do Print/G-code." + +#: src/libslic3r/PrintConfig.cpp:3186 +msgid "Help (SLA options)" +msgstr "Ajuda (opções SLA)" + +#: src/libslic3r/PrintConfig.cpp:3187 +msgid "Show the full list of SLA print configuration options." +msgstr "Mostrar a lista completa de opções de config. de impressão de SLA." + +#: src/libslic3r/PrintConfig.cpp:3191 +msgid "Output Model Info" +msgstr "Informações do modelo de saída" + +#: src/libslic3r/PrintConfig.cpp:3192 +msgid "Write information about the model to the console." +msgstr "Escreva informações sobre o modelo para o console." + +#: src/libslic3r/PrintConfig.cpp:3196 +msgid "Save config file" +msgstr "Salvar arquivo de config." + +#: src/libslic3r/PrintConfig.cpp:3197 +msgid "Save configuration to the specified file." +msgstr "Salvar config. para o arquivo específico." + +#: src/libslic3r/PrintConfig.cpp:3207 +msgid "Align XY" +msgstr "Alinhar XY" + +#: src/libslic3r/PrintConfig.cpp:3208 +msgid "Align the model to the given point." +msgstr "Alinhar modelo de acordo com o ponto inserido." + +#: src/libslic3r/PrintConfig.cpp:3213 +msgid "Cut model at the given Z." +msgstr "Cortar modelo ao Z fornecido." + +#: src/libslic3r/PrintConfig.cpp:3234 +msgid "Center" +msgstr "Centralizar" + +#: src/libslic3r/PrintConfig.cpp:3235 +msgid "Center the print around the given center." +msgstr "Centralizar a impressão de acordo com o centro informado." + +#: src/libslic3r/PrintConfig.cpp:3239 +msgid "Don't arrange" +msgstr "Não organizar" + +#: src/libslic3r/PrintConfig.cpp:3240 +msgid "" +"Do not rearrange the given models before merging and keep their original XY " +"coordinates." +msgstr "" +"Não reorganize os modelos fornecidos antes de Mesclar e manter suas " +"coordenadas XY originais." + +#: src/libslic3r/PrintConfig.cpp:3243 +msgid "Duplicate" +msgstr "Duplicar" + +#: src/libslic3r/PrintConfig.cpp:3244 +msgid "Multiply copies by this factor." +msgstr "Multiplicar cópias por esse fator." + +#: src/libslic3r/PrintConfig.cpp:3248 +msgid "Duplicate by grid" +msgstr "Duplicar por grade" + +#: src/libslic3r/PrintConfig.cpp:3249 +msgid "Multiply copies by creating a grid." +msgstr "Multiplique cópias criando uma grade." + +#: src/libslic3r/PrintConfig.cpp:3252 +msgid "Merge" +msgstr "Mesclar" + +#: src/libslic3r/PrintConfig.cpp:3253 +msgid "" +"Arrange the supplied models in a plate and merge them in a single model in " +"order to perform actions once." +msgstr "" +"Organize os modelos fornecidos em uma placa e junte-os em um único modelo, a " +"fim de executar ações uma só vez." + +#: src/libslic3r/PrintConfig.cpp:3258 +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 "" +"Tente reparar qualquer malhas não multiplicadas (essa opção é implicitamente " +"adicionada sempre que precisamos cortar o modelo para executar a ação " +"solicitada)." + +#: src/libslic3r/PrintConfig.cpp:3262 +msgid "Rotation angle around the Z axis in degrees." +msgstr "Ângulo de rotação ao redor do eixo Zem graus." + +#: src/libslic3r/PrintConfig.cpp:3266 +msgid "Rotate around X" +msgstr "Rotacionar no X" + +#: src/libslic3r/PrintConfig.cpp:3267 +msgid "Rotation angle around the X axis in degrees." +msgstr "Ângulo de rotação ao redor do eixo X em graus." + +#: src/libslic3r/PrintConfig.cpp:3271 +msgid "Rotate around Y" +msgstr "Rotacionar no Y" + +#: src/libslic3r/PrintConfig.cpp:3272 +msgid "Rotation angle around the Y axis in degrees." +msgstr "Ângulo de rotação ao redor do eixo Y em graus." + +#: src/libslic3r/PrintConfig.cpp:3277 +msgid "Scaling factor or percentage." +msgstr "Escalando fator ou porcentagem." + +#: src/libslic3r/PrintConfig.cpp:3282 +msgid "" +"Detect unconnected parts in the given model(s) and split them into separate " +"objects." +msgstr "" +"Detecte peças não conectadas em um determinado modelo (s) e divida-as em " +"objetos separados." + +#: src/libslic3r/PrintConfig.cpp:3285 +msgid "Scale to Fit" +msgstr "Dimensionar para caber" + +#: src/libslic3r/PrintConfig.cpp:3286 +msgid "Scale to fit the given volume." +msgstr "Escalar para se adequar ao volume informado." + +#: src/libslic3r/PrintConfig.cpp:3295 +msgid "Ignore non-existent config files" +msgstr "Ignorar arquivos de config. não existentes" + +#: src/libslic3r/PrintConfig.cpp:3296 +msgid "Do not fail if a file supplied to --load does not exist." +msgstr "Não falhe se um arquivo fornecido para--carregamento não existe." + +#: src/libslic3r/PrintConfig.cpp:3299 +msgid "Load config file" +msgstr "Carregar arquivo de config." + +#: src/libslic3r/PrintConfig.cpp:3300 +msgid "" +"Load configuration from the specified file. It can be used more than once to " +"load options from multiple files." +msgstr "" +"Carregar a config. do arquivo especificado. Ele pode ser usado mais de uma " +"vez para carregar opções de vários arquivos." + +#: src/libslic3r/PrintConfig.cpp:3303 +msgid "Output File" +msgstr "Arquivo de saída" + +#: src/libslic3r/PrintConfig.cpp:3304 +msgid "" +"The file where the output will be written (if not specified, it will be " +"based on the input file)." +msgstr "" +"O arquivo onde a saída será gravada (se não for especificado, ele será " +"baseado no arquivo de entrada)." + +#: src/libslic3r/PrintConfig.cpp:3314 +msgid "Data directory" +msgstr "Diretório de dados" + +#: src/libslic3r/PrintConfig.cpp:3315 +msgid "" +"Load and store settings at the given directory. This is useful for " +"maintaining different profiles or including configurations from a network " +"storage." +msgstr "" +"Carregar e armazenar as config. no diretório especificado. Isso é útil para " +"manter perfis diferentes ou incluir config. de um armazenamento de rede." + +#: src/libslic3r/PrintConfig.cpp:3318 +msgid "Logging level" +msgstr "Nível de registro" + +#: src/libslic3r/PrintConfig.cpp:3319 +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 "" +"Mensagens com severidade menor ou igual para o LogLevel serão impressos. 0: " +"Trace, 1: debug, 2: info, 3: aviso, 4: erro, 5: fatal" + +#: src/libslic3r/PrintConfig.cpp:3324 +msgid "Render with a software renderer" +msgstr "Renderizar com um software renderizador" + +#: src/libslic3r/PrintConfig.cpp:3325 +msgid "" +"Render with a software renderer. The bundled MESA software renderer is " +"loaded instead of the default OpenGL driver." +msgstr "" +"Renderizar com um software renderizador. O renderizador de software MESA " +"empacotado é carregado em vez do driver OpenGL padrão." + +#: src/libslic3r/PrintObject.cpp:110 +msgid "Processing triangulated mesh" +msgstr "Processando malha triangulada" + +#: src/libslic3r/PrintObject.cpp:141 +msgid "Generating perimeters" +msgstr "Gerando perímetros" + +#: src/libslic3r/PrintObject.cpp:251 +msgid "Preparing infill" +msgstr "Preparando o preenchimento" + +#: src/libslic3r/PrintObject.cpp:391 +msgid "Generating support material" +msgstr "Gerando material de suporte" + +#: src/libslic3r/GCode/PreviewData.cpp:160 +msgid "Mixed" +msgstr "Misto" + +#: src/libslic3r/GCode/PreviewData.cpp:380 +msgid "Height (mm)" +msgstr "Altura (mm)" + +#: src/libslic3r/GCode/PreviewData.cpp:382 +msgid "Width (mm)" +msgstr "Espessura (mm)" + +#: src/libslic3r/GCode/PreviewData.cpp:384 +msgid "Speed (mm/s)" +msgstr "Velocidade (mm/s)" + +#: src/libslic3r/GCode/PreviewData.cpp:386 +msgid "Volumetric flow rate (mm3/s)" +msgstr "Fluxo volumétrico (mm3/s)" + +#: src/libslic3r/GCode/PreviewData.cpp:477 +msgid "Default print color" +msgstr "Cor de impressão padrão" + +#: src/libslic3r/GCode/PreviewData.cpp:484 +#, c-format +msgid "up to %.2f mm" +msgstr "até %.2f mm" + +#: src/libslic3r/GCode/PreviewData.cpp:488 +#, c-format +msgid "above %.2f mm" +msgstr "acima de %.2f mm" + +#: src/libslic3r/GCode/PreviewData.cpp:493 +#, c-format +msgid "%.2f - %.2f mm" +msgstr "%.2f - %.2f mm" diff --git a/resources/udev/90-3dconnexion.rules b/resources/udev/90-3dconnexion.rules new file mode 100644 index 000000000..04d581498 --- /dev/null +++ b/resources/udev/90-3dconnexion.rules @@ -0,0 +1,45 @@ +# See src/slic3r/GUI/Mouse3DController.cpp for the list of devices + +# Logitech vendor devices +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c603", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c605", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c606", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c621", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c623", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c625", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c626", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c627", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c628", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c629", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c62b", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c62e", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c62f", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c631", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c632", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c633", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c635", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c636", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c640", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c652", MODE="0666" + +# 3D Connexion vendor devices +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c603", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c605", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c606", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c621", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c623", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c625", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c626", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c627", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c628", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c629", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c62b", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c62e", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c62f", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c631", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c632", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c633", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c635", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c636", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c640", MODE="0666" +KERNEL=="hidraw*", ATTRS{idVendor}=="256f", ATTRS{idProduct}=="c652", MODE="0666" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1bf278722..530512cbb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,6 +22,8 @@ add_subdirectory(libslic3r) if (SLIC3R_GUI) add_subdirectory(imgui) + add_subdirectory(hidapi) + include_directories(hidapi/include) if(WIN32) message(STATUS "WXWIN environment set to: $ENV{WXWIN}") diff --git a/src/admesh/stl.h b/src/admesh/stl.h index fa0edec2b..9224b0459 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -184,10 +184,21 @@ extern void stl_mirror_xz(stl_file *stl); extern void stl_get_size(stl_file *stl); +// the following function is not used +/* template extern void stl_transform(stl_file *stl, T *trafo3x4) { - for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) { + Eigen::Matrix trafo3x3; + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 3; ++j) + { + trafo3x3(i, j) = (i * 4) + j; + } + } + Eigen::Matrix r = trafo3x3.inverse().transpose(); + for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) { stl_facet &face = stl->facet_start[i_face]; for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) { stl_vertex &v_dst = face.vertex[i_vertex]; @@ -196,21 +207,18 @@ extern void stl_transform(stl_file *stl, T *trafo3x4) v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]); v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]); } - stl_vertex &v_dst = face.normal; - stl_vertex v_src = v_dst; - v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2)); - v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2)); - v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2)); - } + face.normal = (r * face.normal.template cast()).template cast().eval(); + } stl_get_size(stl); } +*/ template inline void stl_transform(stl_file *stl, const Eigen::Transform& t) { - const Eigen::Matrix r = t.matrix().template block<3, 3>(0, 0); - for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) { + const Eigen::Matrix r = t.matrix().template block<3, 3>(0, 0).inverse().transpose(); + for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) { stl_facet &f = stl->facet_start[i]; for (size_t j = 0; j < 3; ++j) f.vertex[j] = (t * f.vertex[j].template cast()).template cast().eval(); @@ -223,12 +231,13 @@ inline void stl_transform(stl_file *stl, const Eigen::Transform inline void stl_transform(stl_file *stl, const Eigen::Matrix& m) { - for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) { + const Eigen::Matrix r = m.inverse().transpose(); + for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) { stl_facet &f = stl->facet_start[i]; for (size_t j = 0; j < 3; ++j) f.vertex[j] = (m * f.vertex[j].template cast()).template cast().eval(); - f.normal = (m * f.normal.template cast()).template cast().eval(); - } + f.normal = (r * f.normal.template cast()).template cast().eval(); + } stl_get_size(stl); } diff --git a/src/hidapi/CMakeLists.txt b/src/hidapi/CMakeLists.txt new file mode 100644 index 000000000..313fafbfd --- /dev/null +++ b/src/hidapi/CMakeLists.txt @@ -0,0 +1,17 @@ + +if (WIN32) + set(HIDAPI_IMPL win/hid.c) +elseif (APPLE) + set(HIDAPI_IMPL mac/hid.c) +else () + # Assume Linux or Unix other than Mac OS + set(HIDAPI_IMPL linux/hid.c) +endif() + +include_directories(include) + +add_library(hidapi STATIC ${HIDAPI_IMPL}) + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + target_link_libraries(hidapi udev) +endif() diff --git a/src/hidapi/include/hidapi.h b/src/hidapi/include/hidapi.h new file mode 100644 index 000000000..1819f8de0 --- /dev/null +++ b/src/hidapi/include/hidapi.h @@ -0,0 +1,395 @@ +/******************************************************* + HIDAPI - Multi-Platform library for + communication with HID devices. + + Alan Ott + Signal 11 Software + + 8/22/2009 + + Copyright 2009, All Rights Reserved. + + At the discretion of the user of this library, + this software may be licensed under the terms of the + GNU General Public License v3, a BSD-Style license, or the + original HIDAPI license as outlined in the LICENSE.txt, + LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt + files located at the root of the source distribution. + These files may also be found in the public source + code repository located at: + http://github.com/signal11/hidapi . +********************************************************/ + +/** @file + * @defgroup API hidapi API + */ + +#ifndef HIDAPI_H__ +#define HIDAPI_H__ + +#include + +#ifdef _WIN32 + #define HID_API_EXPORT __declspec(dllexport) + #define HID_API_CALL +#else + #define HID_API_EXPORT /**< API export macro */ + #define HID_API_CALL /**< API call macro */ +#endif + +#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ + +#ifdef __cplusplus +extern "C" { +#endif + struct hid_device_; + typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ + + /** hidapi info structure */ + struct hid_device_info { + /** Platform-specific device path */ + char *path; + /** Device Vendor ID */ + unsigned short vendor_id; + /** Device Product ID */ + unsigned short product_id; + /** Serial Number */ + wchar_t *serial_number; + /** Device Release Number in binary-coded decimal, + also known as Device Version Number */ + unsigned short release_number; + /** Manufacturer String */ + wchar_t *manufacturer_string; + /** Product string */ + wchar_t *product_string; + /** Usage Page for this Device/Interface + (Windows/Mac only). */ + unsigned short usage_page; + /** Usage for this Device/Interface + (Windows/Mac only).*/ + unsigned short usage; + /** The USB interface which this logical device + represents. + + * Valid on both Linux implementations in all cases. + * Valid on the Windows implementation only if the device + contains more than one interface. + * Valid on the Mac implementation if and only if the device + is a USB HID device. */ + int interface_number; + + /** Pointer to the next device */ + struct hid_device_info *next; + }; + + + /** @brief Initialize the HIDAPI library. + + This function initializes the HIDAPI library. Calling it is not + strictly necessary, as it will be called automatically by + hid_enumerate() and any of the hid_open_*() functions if it is + needed. This function should be called at the beginning of + execution however, if there is a chance of HIDAPI handles + being opened by different threads simultaneously. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_init(void); + + /** @brief Finalize the HIDAPI library. + + This function frees all of the static data associated with + HIDAPI. It should be called at the end of execution to avoid + memory leaks. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_exit(void); + + /** @brief Enumerate the HID Devices. + + This function returns a linked list of all the HID devices + attached to the system which match vendor_id and product_id. + If @p vendor_id is set to 0 then any vendor matches. + If @p product_id is set to 0 then any product matches. + If @p vendor_id and @p product_id are both set to 0, then + all HID devices will be returned. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the types of device + to open. + @param product_id The Product ID (PID) of the types of + device to open. + + @returns + This function returns a pointer to a linked list of type + struct #hid_device_info, containing information about the HID devices + attached to the system, or NULL in the case of failure. Free + this linked list by calling hid_free_enumeration(). + */ + struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); + + /** @brief Free an enumeration Linked List + + This function frees a linked list created by hid_enumerate(). + + @ingroup API + @param devs Pointer to a list of struct_device returned from + hid_enumerate(). + */ + void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); + + /** @brief Open a HID device using a Vendor ID (VID), Product ID + (PID) and optionally a serial number. + + If @p serial_number is NULL, the first device with the + specified VID and PID is opened. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the device to open. + @param product_id The Product ID (PID) of the device to open. + @param serial_number The Serial Number of the device to open + (Optionally NULL). + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number); + + /** @brief Open a HID device by its path name. + + The path name be determined by calling hid_enumerate(), or a + platform-specific path name can be used (eg: /dev/hidraw0 on + Linux). + + @ingroup API + @param path The path name of the device to open + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path); + + /** @brief Write an Output report to a HID device. + + The first byte of @p data[] must contain the Report ID. For + devices which only support a single report, this must be set + to 0x0. The remaining bytes contain the report data. Since + the Report ID is mandatory, calls to hid_write() will always + contain one more byte than the report contains. For example, + if a hid report is 16 bytes long, 17 bytes must be passed to + hid_write(), the Report ID (or 0x0, for devices with a + single report), followed by the report data (16 bytes). In + this example, the length passed in would be 17. + + hid_write() will send the data on the first OUT endpoint, if + one exists. If it does not, it will send the data through + the Control Endpoint (Endpoint 0). + + @ingroup API + @param dev A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length); + + /** @brief Read an Input report from a HID device with timeout. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param dev A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + @param milliseconds timeout in milliseconds or -1 for blocking wait. + + @returns + This function returns the actual number of bytes read and + -1 on error. If no packet was available to be read within + the timeout period, this function returns 0. + */ + int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds); + + /** @brief Read an Input report from a HID device. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param dev A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + + @returns + This function returns the actual number of bytes read and + -1 on error. If no packet was available to be read and + the handle is in non-blocking mode, this function returns 0. + */ + int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length); + + /** @brief Set the device handle to be non-blocking. + + In non-blocking mode calls to hid_read() will return + immediately with a value of 0 if there is no data to be + read. In blocking mode, hid_read() will wait (block) until + there is data to read before returning. + + Nonblocking can be turned on and off at any time. + + @ingroup API + @param dev A device handle returned from hid_open(). + @param nonblock enable or not the nonblocking reads + - 1 to enable nonblocking + - 0 to disable nonblocking. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock); + + /** @brief Send a Feature report to the device. + + Feature reports are sent over the Control endpoint as a + Set_Report transfer. The first byte of @p data[] must + contain the Report ID. For devices which only support a + single report, this must be set to 0x0. The remaining bytes + contain the report data. Since the Report ID is mandatory, + calls to hid_send_feature_report() will always contain one + more byte than the report contains. For example, if a hid + report is 16 bytes long, 17 bytes must be passed to + hid_send_feature_report(): the Report ID (or 0x0, for + devices which do not use numbered reports), followed by the + report data (16 bytes). In this example, the length passed + in would be 17. + + @ingroup API + @param dev A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send, including + the report number. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length); + + /** @brief Get a feature report from a HID device. + + Set the first byte of @p data[] to the Report ID of the + report to be read. Make sure to allow space for this + extra byte in @p data[]. Upon return, the first byte will + still contain the Report ID, and the report data will + start in data[1]. + + @ingroup API + @param dev A device handle returned from hid_open(). + @param data A buffer to put the read data into, including + the Report ID. Set the first byte of @p data[] to the + Report ID of the report to be read, or set it to zero + if your device does not use numbered reports. + @param length The number of bytes to read, including an + extra byte for the report ID. The buffer can be longer + than the actual report. + + @returns + This function returns the number of bytes read plus + one for the report ID (which is still in the first + byte), or -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length); + + /** @brief Close a HID device. + + @ingroup API + @param dev A device handle returned from hid_open(). + */ + void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev); + + /** @brief Get The Manufacturer String from a HID device. + + @ingroup API + @param dev A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen); + + /** @brief Get The Product String from a HID device. + + @ingroup API + @param dev A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen); + + /** @brief Get The Serial Number String from a HID device. + + @ingroup API + @param dev A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen); + + /** @brief Get a string from a HID device, based on its string index. + + @ingroup API + @param dev A device handle returned from hid_open(). + @param string_index The index of the string to get. + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen); + + /** @brief Get a string describing the last error which occurred. + + @ingroup API + @param dev A device handle returned from hid_open(). + + @returns + This function returns a string containing the last error + which occurred or NULL if none has occurred. + */ + HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *dev); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/hidapi/linux/hid.c b/src/hidapi/linux/hid.c new file mode 100644 index 000000000..56dac0fab --- /dev/null +++ b/src/hidapi/linux/hid.c @@ -0,0 +1,797 @@ +/******************************************************* + HIDAPI - Multi-Platform library for + communication with HID devices. + + Alan Ott + Signal 11 Software + + 8/22/2009 + Linux Version - 6/2/2009 + + Copyright 2009, All Rights Reserved. + + At the discretion of the user of this library, + this software may be licensed under the terms of the + GNU General Public License v3, a BSD-Style license, or the + original HIDAPI license as outlined in the LICENSE.txt, + LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt + files located at the root of the source distribution. + These files may also be found in the public source + code repository located at: + http://github.com/signal11/hidapi . +********************************************************/ + +/* C */ +#include +#include +#include +#include +#include + +/* Unix */ +#include +#include +#include +#include +#include +#include +#include + +/* Linux */ +#include +#include +#include +#include + +#include "hidapi.h" + +/* Definitions from linux/hidraw.h. Since these are new, some distros + may not have header files which contain them. */ +#ifndef HIDIOCSFEATURE +#define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len) +#endif +#ifndef HIDIOCGFEATURE +#define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len) +#endif + + +/* USB HID device property names */ +const char *device_string_names[] = { + "manufacturer", + "product", + "serial", +}; + +/* Symbolic names for the properties above */ +enum device_string_id { + DEVICE_STRING_MANUFACTURER, + DEVICE_STRING_PRODUCT, + DEVICE_STRING_SERIAL, + + DEVICE_STRING_COUNT, +}; + +struct hid_device_ { + int device_handle; + int blocking; + int uses_numbered_reports; +}; + + +static __u32 kernel_version = 0; + +static __u32 detect_kernel_version(void) +{ + struct utsname name; + int major, minor, release; + int ret; + + uname(&name); + ret = sscanf(name.release, "%d.%d.%d", &major, &minor, &release); + if (ret == 3) { + return KERNEL_VERSION(major, minor, release); + } + + ret = sscanf(name.release, "%d.%d", &major, &minor); + if (ret == 2) { + return KERNEL_VERSION(major, minor, 0); + } + + printf("Couldn't determine kernel version from version string \"%s\"\n", name.release); + return 0; +} + +static hid_device *new_hid_device(void) +{ + hid_device *dev = calloc(1, sizeof(hid_device)); + dev->device_handle = -1; + dev->blocking = 1; + dev->uses_numbered_reports = 0; + + return dev; +} + + +/* The caller must free the returned string with free(). */ +static wchar_t *utf8_to_wchar_t(const char *utf8) +{ + wchar_t *ret = NULL; + + if (utf8) { + size_t wlen = mbstowcs(NULL, utf8, 0); + if ((size_t) -1 == wlen) { + return wcsdup(L""); + } + ret = calloc(wlen+1, sizeof(wchar_t)); + mbstowcs(ret, utf8, wlen+1); + ret[wlen] = 0x0000; + } + + return ret; +} + +/* Get an attribute value from a udev_device and return it as a whar_t + string. The returned string must be freed with free() when done.*/ +static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name) +{ + return utf8_to_wchar_t(udev_device_get_sysattr_value(dev, udev_name)); +} + +/* uses_numbered_reports() returns 1 if report_descriptor describes a device + which contains numbered reports. */ +static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) { + unsigned int i = 0; + int size_code; + int data_len, key_size; + + while (i < size) { + int key = report_descriptor[i]; + + /* Check for the Report ID key */ + if (key == 0x85/*Report ID*/) { + /* This device has a Report ID, which means it uses + numbered reports. */ + return 1; + } + + //printf("key: %02hhx\n", key); + + if ((key & 0xf0) == 0xf0) { + /* This is a Long Item. The next byte contains the + length of the data section (value) for this key. + See the HID specification, version 1.11, section + 6.2.2.3, titled "Long Items." */ + if (i+1 < size) + data_len = report_descriptor[i+1]; + else + data_len = 0; /* malformed report */ + key_size = 3; + } + else { + /* This is a Short Item. The bottom two bits of the + key contain the size code for the data section + (value) for this key. Refer to the HID + specification, version 1.11, section 6.2.2.2, + titled "Short Items." */ + size_code = key & 0x3; + switch (size_code) { + case 0: + case 1: + case 2: + data_len = size_code; + break; + case 3: + data_len = 4; + break; + default: + /* Can't ever happen since size_code is & 0x3 */ + data_len = 0; + break; + }; + key_size = 1; + } + + /* Skip over this key and it's associated data */ + i += data_len + key_size; + } + + /* Didn't find a Report ID key. Device doesn't use numbered reports. */ + return 0; +} + +/* + * The caller is responsible for free()ing the (newly-allocated) character + * strings pointed to by serial_number_utf8 and product_name_utf8 after use. + */ +static int +parse_uevent_info(const char *uevent, int *bus_type, + unsigned short *vendor_id, unsigned short *product_id, + char **serial_number_utf8, char **product_name_utf8) +{ + char *tmp = strdup(uevent); + char *saveptr = NULL; + char *line; + char *key; + char *value; + + int found_id = 0; + int found_serial = 0; + int found_name = 0; + + line = strtok_r(tmp, "\n", &saveptr); + while (line != NULL) { + /* line: "KEY=value" */ + key = line; + value = strchr(line, '='); + if (!value) { + goto next_line; + } + *value = '\0'; + value++; + + if (strcmp(key, "HID_ID") == 0) { + /** + * type vendor product + * HID_ID=0003:000005AC:00008242 + **/ + int ret = sscanf(value, "%x:%hx:%hx", bus_type, vendor_id, product_id); + if (ret == 3) { + found_id = 1; + } + } else if (strcmp(key, "HID_NAME") == 0) { + /* The caller has to free the product name */ + *product_name_utf8 = strdup(value); + found_name = 1; + } else if (strcmp(key, "HID_UNIQ") == 0) { + /* The caller has to free the serial number */ + *serial_number_utf8 = strdup(value); + found_serial = 1; + } + +next_line: + line = strtok_r(NULL, "\n", &saveptr); + } + + free(tmp); + return (found_id && found_name && found_serial); +} + + +static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t *string, size_t maxlen) +{ + struct udev *udev; + struct udev_device *udev_dev, *parent, *hid_dev; + struct stat s; + int ret = -1; + char *serial_number_utf8 = NULL; + char *product_name_utf8 = NULL; + + /* Create the udev object */ + udev = udev_new(); + if (!udev) { + printf("Can't create udev\n"); + return -1; + } + + /* Get the dev_t (major/minor numbers) from the file handle. */ + ret = fstat(dev->device_handle, &s); + if (-1 == ret) + return ret; + /* Open a udev device from the dev_t. 'c' means character device. */ + udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev); + if (udev_dev) { + hid_dev = udev_device_get_parent_with_subsystem_devtype( + udev_dev, + "hid", + NULL); + if (hid_dev) { + unsigned short dev_vid; + unsigned short dev_pid; + int bus_type; + size_t retm; + + ret = parse_uevent_info( + udev_device_get_sysattr_value(hid_dev, "uevent"), + &bus_type, + &dev_vid, + &dev_pid, + &serial_number_utf8, + &product_name_utf8); + + if (bus_type == BUS_BLUETOOTH) { + switch (key) { + case DEVICE_STRING_MANUFACTURER: + wcsncpy(string, L"", maxlen); + ret = 0; + break; + case DEVICE_STRING_PRODUCT: + retm = mbstowcs(string, product_name_utf8, maxlen); + ret = (retm == (size_t)-1)? -1: 0; + break; + case DEVICE_STRING_SERIAL: + retm = mbstowcs(string, serial_number_utf8, maxlen); + ret = (retm == (size_t)-1)? -1: 0; + break; + case DEVICE_STRING_COUNT: + default: + ret = -1; + break; + } + } + else { + /* This is a USB device. Find its parent USB Device node. */ + parent = udev_device_get_parent_with_subsystem_devtype( + udev_dev, + "usb", + "usb_device"); + if (parent) { + const char *str; + const char *key_str = NULL; + + if (key >= 0 && key < DEVICE_STRING_COUNT) { + key_str = device_string_names[key]; + } else { + ret = -1; + goto end; + } + + str = udev_device_get_sysattr_value(parent, key_str); + if (str) { + /* Convert the string from UTF-8 to wchar_t */ + retm = mbstowcs(string, str, maxlen); + ret = (retm == (size_t)-1)? -1: 0; + goto end; + } + } + } + } + } + +end: + free(serial_number_utf8); + free(product_name_utf8); + + udev_device_unref(udev_dev); + /* parent and hid_dev don't need to be (and can't be) unref'd. + I'm not sure why, but they'll throw double-free() errors. */ + udev_unref(udev); + + return ret; +} + +int HID_API_EXPORT hid_init(void) +{ + const char *locale; + + /* Set the locale if it's not set. */ + locale = setlocale(LC_CTYPE, NULL); + if (!locale) + setlocale(LC_CTYPE, ""); + + kernel_version = detect_kernel_version(); + + return 0; +} + +int HID_API_EXPORT hid_exit(void) +{ + /* Nothing to do for this in the Linux/hidraw implementation. */ + return 0; +} + + +struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) +{ + struct udev *udev; + struct udev_enumerate *enumerate; + struct udev_list_entry *devices, *dev_list_entry; + + struct hid_device_info *root = NULL; /* return object */ + struct hid_device_info *cur_dev = NULL; + struct hid_device_info *prev_dev = NULL; /* previous device */ + + hid_init(); + + /* Create the udev object */ + udev = udev_new(); + if (!udev) { + printf("Can't create udev\n"); + return NULL; + } + + /* Create a list of the devices in the 'hidraw' subsystem. */ + enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(enumerate, "hidraw"); + udev_enumerate_scan_devices(enumerate); + devices = udev_enumerate_get_list_entry(enumerate); + /* For each item, see if it matches the vid/pid, and if so + create a udev_device record for it */ + udev_list_entry_foreach(dev_list_entry, devices) { + const char *sysfs_path; + const char *dev_path; + const char *str; + struct udev_device *raw_dev; /* The device's hidraw udev node. */ + struct udev_device *hid_dev; /* The device's HID udev node. */ + struct udev_device *usb_dev; /* The device's USB udev node. */ + struct udev_device *intf_dev; /* The device's interface (in the USB sense). */ + unsigned short dev_vid; + unsigned short dev_pid; + char *serial_number_utf8 = NULL; + char *product_name_utf8 = NULL; + int bus_type; + int result; + + /* Get the filename of the /sys entry for the device + and create a udev_device object (dev) representing it */ + sysfs_path = udev_list_entry_get_name(dev_list_entry); + raw_dev = udev_device_new_from_syspath(udev, sysfs_path); + dev_path = udev_device_get_devnode(raw_dev); + + hid_dev = udev_device_get_parent_with_subsystem_devtype( + raw_dev, + "hid", + NULL); + + if (!hid_dev) { + /* Unable to find parent hid device. */ + goto next; + } + + result = parse_uevent_info( + udev_device_get_sysattr_value(hid_dev, "uevent"), + &bus_type, + &dev_vid, + &dev_pid, + &serial_number_utf8, + &product_name_utf8); + + if (!result) { + /* parse_uevent_info() failed for at least one field. */ + goto next; + } + + if (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) { + /* We only know how to handle USB and BT devices. */ + goto next; + } + + /* Check the VID/PID against the arguments */ + if ((vendor_id == 0x0 || vendor_id == dev_vid) && + (product_id == 0x0 || product_id == dev_pid)) { + struct hid_device_info *tmp; + + /* VID/PID match. Create the record. */ + tmp = malloc(sizeof(struct hid_device_info)); + if (cur_dev) { + cur_dev->next = tmp; + } + else { + root = tmp; + } + prev_dev = cur_dev; + cur_dev = tmp; + + /* Fill out the record */ + cur_dev->next = NULL; + cur_dev->path = dev_path? strdup(dev_path): NULL; + + /* VID/PID */ + cur_dev->vendor_id = dev_vid; + cur_dev->product_id = dev_pid; + + /* Serial Number */ + cur_dev->serial_number = utf8_to_wchar_t(serial_number_utf8); + + /* Release Number */ + cur_dev->release_number = 0x0; + + /* Interface Number */ + cur_dev->interface_number = -1; + + switch (bus_type) { + case BUS_USB: + /* The device pointed to by raw_dev contains information about + the hidraw device. In order to get information about the + USB device, get the parent device with the + subsystem/devtype pair of "usb"/"usb_device". This will + be several levels up the tree, but the function will find + it. */ + usb_dev = udev_device_get_parent_with_subsystem_devtype( + raw_dev, + "usb", + "usb_device"); + + if (!usb_dev) { + /* Free this device */ + free(cur_dev->serial_number); + free(cur_dev->path); + free(cur_dev); + + /* Take it off the device list. */ + if (prev_dev) { + prev_dev->next = NULL; + cur_dev = prev_dev; + } + else { + cur_dev = root = NULL; + } + + goto next; + } + + /* Manufacturer and Product strings */ + cur_dev->manufacturer_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_MANUFACTURER]); + cur_dev->product_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_PRODUCT]); + + /* Release Number */ + str = udev_device_get_sysattr_value(usb_dev, "bcdDevice"); + cur_dev->release_number = (str)? strtol(str, NULL, 16): 0x0; + + /* Get a handle to the interface's udev node. */ + intf_dev = udev_device_get_parent_with_subsystem_devtype( + raw_dev, + "usb", + "usb_interface"); + if (intf_dev) { + str = udev_device_get_sysattr_value(intf_dev, "bInterfaceNumber"); + cur_dev->interface_number = (str)? strtol(str, NULL, 16): -1; + } + + break; + + case BUS_BLUETOOTH: + /* Manufacturer and Product strings */ + cur_dev->manufacturer_string = wcsdup(L""); + cur_dev->product_string = utf8_to_wchar_t(product_name_utf8); + + break; + + default: + /* Unknown device type - this should never happen, as we + * check for USB and Bluetooth devices above */ + break; + } + } + + next: + free(serial_number_utf8); + free(product_name_utf8); + udev_device_unref(raw_dev); + /* hid_dev, usb_dev and intf_dev don't need to be (and can't be) + unref()d. It will cause a double-free() error. I'm not + sure why. */ + } + /* Free the enumerator and udev objects. */ + udev_enumerate_unref(enumerate); + udev_unref(udev); + + return root; +} + +void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) +{ + struct hid_device_info *d = devs; + while (d) { + struct hid_device_info *next = d->next; + free(d->path); + free(d->serial_number); + free(d->manufacturer_string); + free(d->product_string); + free(d); + d = next; + } +} + +hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) +{ + struct hid_device_info *devs, *cur_dev; + const char *path_to_open = NULL; + hid_device *handle = NULL; + + devs = hid_enumerate(vendor_id, product_id); + cur_dev = devs; + while (cur_dev) { + if (cur_dev->vendor_id == vendor_id && + cur_dev->product_id == product_id) { + if (serial_number) { + if (wcscmp(serial_number, cur_dev->serial_number) == 0) { + path_to_open = cur_dev->path; + break; + } + } + else { + path_to_open = cur_dev->path; + break; + } + } + cur_dev = cur_dev->next; + } + + if (path_to_open) { + /* Open the device */ + handle = hid_open_path(path_to_open); + } + + hid_free_enumeration(devs); + + return handle; +} + +hid_device * HID_API_EXPORT hid_open_path(const char *path) +{ + hid_device *dev = NULL; + + hid_init(); + + dev = new_hid_device(); + + /* OPEN HERE */ + dev->device_handle = open(path, O_RDWR); + + /* If we have a good handle, return it. */ + if (dev->device_handle > 0) { + + /* Get the report descriptor */ + int res, desc_size = 0; + struct hidraw_report_descriptor rpt_desc; + + memset(&rpt_desc, 0x0, sizeof(rpt_desc)); + + /* Get Report Descriptor Size */ + res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size); + if (res < 0) + perror("HIDIOCGRDESCSIZE"); + + + /* Get Report Descriptor */ + rpt_desc.size = desc_size; + res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc); + if (res < 0) { + perror("HIDIOCGRDESC"); + } else { + /* Determine if this device uses numbered reports. */ + dev->uses_numbered_reports = + uses_numbered_reports(rpt_desc.value, + rpt_desc.size); + } + + return dev; + } + else { + /* Unable to open any devices. */ + free(dev); + return NULL; + } +} + + +int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) +{ + int bytes_written; + + bytes_written = write(dev->device_handle, data, length); + + return bytes_written; +} + + +int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) +{ + int bytes_read; + + if (milliseconds >= 0) { + /* Milliseconds is either 0 (non-blocking) or > 0 (contains + a valid timeout). In both cases we want to call poll() + and wait for data to arrive. Don't rely on non-blocking + operation (O_NONBLOCK) since some kernels don't seem to + properly report device disconnection through read() when + in non-blocking mode. */ + int ret; + struct pollfd fds; + + fds.fd = dev->device_handle; + fds.events = POLLIN; + fds.revents = 0; + ret = poll(&fds, 1, milliseconds); + if (ret == -1 || ret == 0) { + /* Error or timeout */ + return ret; + } + else { + /* Check for errors on the file descriptor. This will + indicate a device disconnection. */ + if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) + return -1; + } + } + + bytes_read = read(dev->device_handle, data, length); + if (bytes_read < 0 && (errno == EAGAIN || errno == EINPROGRESS)) + bytes_read = 0; + + if (bytes_read >= 0 && + kernel_version != 0 && + kernel_version < KERNEL_VERSION(2,6,34) && + dev->uses_numbered_reports) { + /* Work around a kernel bug. Chop off the first byte. */ + memmove(data, data+1, bytes_read); + bytes_read--; + } + + return bytes_read; +} + +int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) +{ + return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); +} + +int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) +{ + /* Do all non-blocking in userspace using poll(), since it looks + like there's a bug in the kernel in some versions where + read() will not return -1 on disconnection of the USB device */ + + dev->blocking = !nonblock; + return 0; /* Success */ +} + + +int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) +{ + int res; + + res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data); + if (res < 0) + perror("ioctl (SFEATURE)"); + + return res; +} + +int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) +{ + int res; + + res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data); + if (res < 0) + perror("ioctl (GFEATURE)"); + + + return res; +} + + +void HID_API_EXPORT hid_close(hid_device *dev) +{ + if (!dev) + return; + close(dev->device_handle); + free(dev); +} + + +int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + return get_device_string(dev, DEVICE_STRING_MANUFACTURER, string, maxlen); +} + +int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + return get_device_string(dev, DEVICE_STRING_PRODUCT, string, maxlen); +} + +int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + return get_device_string(dev, DEVICE_STRING_SERIAL, string, maxlen); +} + +int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) +{ + return -1; +} + + +HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) +{ + return NULL; +} diff --git a/src/hidapi/mac/hid.c b/src/hidapi/mac/hid.c new file mode 100644 index 000000000..ca10a9cca --- /dev/null +++ b/src/hidapi/mac/hid.c @@ -0,0 +1,1121 @@ +/******************************************************* + HIDAPI - Multi-Platform library for + communication with HID devices. + + Alan Ott + Signal 11 Software + + 2010-07-03 + + Copyright 2010, All Rights Reserved. + + At the discretion of the user of this library, + this software may be licensed under the terms of the + GNU General Public License v3, a BSD-Style license, or the + original HIDAPI license as outlined in the LICENSE.txt, + LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt + files located at the root of the source distribution. + These files may also be found in the public source + code repository located at: + http://github.com/signal11/hidapi . +********************************************************/ + +/* See Apple Technical Note TN2187 for details on IOHidManager. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hidapi.h" + +/* Barrier implementation because Mac OSX doesn't have pthread_barrier. + It also doesn't have clock_gettime(). So much for POSIX and SUSv2. + This implementation came from Brent Priddy and was posted on + StackOverflow. It is used with his permission. */ +typedef int pthread_barrierattr_t; +typedef struct pthread_barrier { + pthread_mutex_t mutex; + pthread_cond_t cond; + int count; + int trip_count; +} pthread_barrier_t; + +static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count) +{ + if(count == 0) { + errno = EINVAL; + return -1; + } + + if(pthread_mutex_init(&barrier->mutex, 0) < 0) { + return -1; + } + if(pthread_cond_init(&barrier->cond, 0) < 0) { + pthread_mutex_destroy(&barrier->mutex); + return -1; + } + barrier->trip_count = count; + barrier->count = 0; + + return 0; +} + +static int pthread_barrier_destroy(pthread_barrier_t *barrier) +{ + pthread_cond_destroy(&barrier->cond); + pthread_mutex_destroy(&barrier->mutex); + return 0; +} + +static int pthread_barrier_wait(pthread_barrier_t *barrier) +{ + pthread_mutex_lock(&barrier->mutex); + ++(barrier->count); + if(barrier->count >= barrier->trip_count) + { + barrier->count = 0; + pthread_cond_broadcast(&barrier->cond); + pthread_mutex_unlock(&barrier->mutex); + return 1; + } + else + { + pthread_cond_wait(&barrier->cond, &(barrier->mutex)); + pthread_mutex_unlock(&barrier->mutex); + return 0; + } +} + +static int return_data(hid_device *dev, unsigned char *data, size_t length); + +/* Linked List of input reports received from the device. */ +struct input_report { + uint8_t *data; + size_t len; + struct input_report *next; +}; + +struct hid_device_ { + IOHIDDeviceRef device_handle; + int blocking; + int uses_numbered_reports; + int disconnected; + CFStringRef run_loop_mode; + CFRunLoopRef run_loop; + CFRunLoopSourceRef source; + uint8_t *input_report_buf; + CFIndex max_input_report_len; + struct input_report *input_reports; + + pthread_t thread; + pthread_mutex_t mutex; /* Protects input_reports */ + pthread_cond_t condition; + pthread_barrier_t barrier; /* Ensures correct startup sequence */ + pthread_barrier_t shutdown_barrier; /* Ensures correct shutdown sequence */ + int shutdown_thread; +}; + +static hid_device *new_hid_device(void) +{ + hid_device *dev = calloc(1, sizeof(hid_device)); + dev->device_handle = NULL; + dev->blocking = 1; + dev->uses_numbered_reports = 0; + dev->disconnected = 0; + dev->run_loop_mode = NULL; + dev->run_loop = NULL; + dev->source = NULL; + dev->input_report_buf = NULL; + dev->input_reports = NULL; + dev->shutdown_thread = 0; + + /* Thread objects */ + pthread_mutex_init(&dev->mutex, NULL); + pthread_cond_init(&dev->condition, NULL); + pthread_barrier_init(&dev->barrier, NULL, 2); + pthread_barrier_init(&dev->shutdown_barrier, NULL, 2); + + return dev; +} + +static void free_hid_device(hid_device *dev) +{ + if (!dev) + return; + + /* Delete any input reports still left over. */ + struct input_report *rpt = dev->input_reports; + while (rpt) { + struct input_report *next = rpt->next; + free(rpt->data); + free(rpt); + rpt = next; + } + + /* Free the string and the report buffer. The check for NULL + is necessary here as CFRelease() doesn't handle NULL like + free() and others do. */ + if (dev->run_loop_mode) + CFRelease(dev->run_loop_mode); + if (dev->source) + CFRelease(dev->source); + free(dev->input_report_buf); + + /* Clean up the thread objects */ + pthread_barrier_destroy(&dev->shutdown_barrier); + pthread_barrier_destroy(&dev->barrier); + pthread_cond_destroy(&dev->condition); + pthread_mutex_destroy(&dev->mutex); + + /* Free the structure itself. */ + free(dev); +} + +static IOHIDManagerRef hid_mgr = 0x0; + + +#if 0 +static void register_error(hid_device *dev, const char *op) +{ + +} +#endif + + +static int32_t get_int_property(IOHIDDeviceRef device, CFStringRef key) +{ + CFTypeRef ref; + int32_t value; + + ref = IOHIDDeviceGetProperty(device, key); + if (ref) { + if (CFGetTypeID(ref) == CFNumberGetTypeID()) { + CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &value); + return value; + } + } + return 0; +} + +static unsigned short get_vendor_id(IOHIDDeviceRef device) +{ + return get_int_property(device, CFSTR(kIOHIDVendorIDKey)); +} + +static unsigned short get_product_id(IOHIDDeviceRef device) +{ + return get_int_property(device, CFSTR(kIOHIDProductIDKey)); +} + +static int32_t get_max_report_length(IOHIDDeviceRef device) +{ + return get_int_property(device, CFSTR(kIOHIDMaxInputReportSizeKey)); +} + +static int get_string_property(IOHIDDeviceRef device, CFStringRef prop, wchar_t *buf, size_t len) +{ + CFStringRef str; + + if (!len) + return 0; + + str = IOHIDDeviceGetProperty(device, prop); + + buf[0] = 0; + + if (str) { + CFIndex str_len = CFStringGetLength(str); + CFRange range; + CFIndex used_buf_len; + CFIndex chars_copied; + + len --; + + range.location = 0; + range.length = ((size_t)str_len > len)? len: (size_t)str_len; + chars_copied = CFStringGetBytes(str, + range, + kCFStringEncodingUTF32LE, + (char)'?', + FALSE, + (UInt8*)buf, + len * sizeof(wchar_t), + &used_buf_len); + + if (chars_copied == len) + buf[len] = 0; /* len is decremented above */ + else + buf[chars_copied] = 0; + + return 0; + } + else + return -1; + +} + +static int get_serial_number(IOHIDDeviceRef device, wchar_t *buf, size_t len) +{ + return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len); +} + +static int get_manufacturer_string(IOHIDDeviceRef device, wchar_t *buf, size_t len) +{ + return get_string_property(device, CFSTR(kIOHIDManufacturerKey), buf, len); +} + +static int get_product_string(IOHIDDeviceRef device, wchar_t *buf, size_t len) +{ + return get_string_property(device, CFSTR(kIOHIDProductKey), buf, len); +} + + +/* Implementation of wcsdup() for Mac. */ +static wchar_t *dup_wcs(const wchar_t *s) +{ + size_t len = wcslen(s); + wchar_t *ret = malloc((len+1)*sizeof(wchar_t)); + wcscpy(ret, s); + + return ret; +} + +/* hidapi_IOHIDDeviceGetService() + * + * Return the io_service_t corresponding to a given IOHIDDeviceRef, either by: + * - on OS X 10.6 and above, calling IOHIDDeviceGetService() + * - on OS X 10.5, extract it from the IOHIDDevice struct + */ +static io_service_t hidapi_IOHIDDeviceGetService(IOHIDDeviceRef device) +{ + static void *iokit_framework = NULL; + static io_service_t (*dynamic_IOHIDDeviceGetService)(IOHIDDeviceRef device) = NULL; + + /* Use dlopen()/dlsym() to get a pointer to IOHIDDeviceGetService() if it exists. + * If any of these steps fail, dynamic_IOHIDDeviceGetService will be left NULL + * and the fallback method will be used. + */ + if (iokit_framework == NULL) { + iokit_framework = dlopen("/System/Library/IOKit.framework/IOKit", RTLD_LAZY); + + if (iokit_framework != NULL) + dynamic_IOHIDDeviceGetService = dlsym(iokit_framework, "IOHIDDeviceGetService"); + } + + if (dynamic_IOHIDDeviceGetService != NULL) { + /* Running on OS X 10.6 and above: IOHIDDeviceGetService() exists */ + return dynamic_IOHIDDeviceGetService(device); + } + else + { + /* Running on OS X 10.5: IOHIDDeviceGetService() doesn't exist. + * + * Be naughty and pull the service out of the IOHIDDevice. + * IOHIDDevice is an opaque struct not exposed to applications, but its + * layout is stable through all available versions of OS X. + * Tested and working on OS X 10.5.8 i386, x86_64, and ppc. + */ + struct IOHIDDevice_internal { + /* The first field of the IOHIDDevice struct is a + * CFRuntimeBase (which is a private CF struct). + * + * a, b, and c are the 3 fields that make up a CFRuntimeBase. + * See http://opensource.apple.com/source/CF/CF-476.18/CFRuntime.h + * + * The second field of the IOHIDDevice is the io_service_t we're looking for. + */ + uintptr_t a; + uint8_t b[4]; +#if __LP64__ + uint32_t c; +#endif + io_service_t service; + }; + struct IOHIDDevice_internal *tmp = (struct IOHIDDevice_internal *)device; + + return tmp->service; + } +} + +/* Initialize the IOHIDManager. Return 0 for success and -1 for failure. */ +static int init_hid_manager(void) +{ + /* Initialize all the HID Manager Objects */ + hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + if (hid_mgr) { + IOHIDManagerSetDeviceMatching(hid_mgr, NULL); + IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + return 0; + } + + return -1; +} + +/* Initialize the IOHIDManager if necessary. This is the public function, and + it is safe to call this function repeatedly. Return 0 for success and -1 + for failure. */ +int HID_API_EXPORT hid_init(void) +{ + if (!hid_mgr) { + return init_hid_manager(); + } + + /* Already initialized. */ + return 0; +} + +int HID_API_EXPORT hid_exit(void) +{ + if (hid_mgr) { + /* Close the HID manager. */ + IOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone); + CFRelease(hid_mgr); + hid_mgr = NULL; + } + + return 0; +} + +static void process_pending_events(void) { + SInt32 res; + do { + res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, FALSE); + } while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut); +} + +struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) +{ + struct hid_device_info *root = NULL; /* return object */ + struct hid_device_info *cur_dev = NULL; + CFIndex num_devices; + int i; + + /* Set up the HID Manager if it hasn't been done */ + if (hid_init() < 0) + return NULL; + + /* give the IOHIDManager a chance to update itself */ + process_pending_events(); + + /* Get a list of the Devices */ + IOHIDManagerSetDeviceMatching(hid_mgr, NULL); + CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr); + + /* Convert the list into a C array so we can iterate easily. */ + num_devices = CFSetGetCount(device_set); + IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef)); + CFSetGetValues(device_set, (const void **) device_array); + + /* Iterate over each device, making an entry for it. */ + for (i = 0; i < num_devices; i++) { + unsigned short dev_vid; + unsigned short dev_pid; + #define BUF_LEN 256 + wchar_t buf[BUF_LEN]; + + IOHIDDeviceRef dev = device_array[i]; + + if (!dev) { + continue; + } + dev_vid = get_vendor_id(dev); + dev_pid = get_product_id(dev); + + /* Check the VID/PID against the arguments */ + if ((vendor_id == 0x0 || vendor_id == dev_vid) && + (product_id == 0x0 || product_id == dev_pid)) { + struct hid_device_info *tmp; + bool is_usb_hid; /* Is this an actual HID usb device */ + io_object_t iokit_dev; + kern_return_t res; + io_string_t path; + + /* VID/PID match. Create the record. */ + tmp = malloc(sizeof(struct hid_device_info)); + if (cur_dev) { + cur_dev->next = tmp; + } + else { + root = tmp; + } + cur_dev = tmp; + + is_usb_hid = get_int_property(dev, CFSTR(kUSBInterfaceClass)) == kUSBHIDClass; + + /* Get the Usage Page and Usage for this device. */ + cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey)); + cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey)); + + /* Fill out the record */ + cur_dev->next = NULL; + + /* Fill in the path (IOService plane) */ + iokit_dev = hidapi_IOHIDDeviceGetService(dev); + res = IORegistryEntryGetPath(iokit_dev, kIOServicePlane, path); + if (res == KERN_SUCCESS) + cur_dev->path = strdup(path); + else + cur_dev->path = strdup(""); + + /* Serial Number */ + get_serial_number(dev, buf, BUF_LEN); + cur_dev->serial_number = dup_wcs(buf); + + /* Manufacturer and Product strings */ + get_manufacturer_string(dev, buf, BUF_LEN); + cur_dev->manufacturer_string = dup_wcs(buf); + get_product_string(dev, buf, BUF_LEN); + cur_dev->product_string = dup_wcs(buf); + + /* VID/PID */ + cur_dev->vendor_id = dev_vid; + cur_dev->product_id = dev_pid; + + /* Release Number */ + cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey)); + + /* We can only retrieve the interface number for USB HID devices. + * IOKit always seems to return 0 when querying a standard USB device + * for its interface. */ + if (is_usb_hid) { + /* Get the interface number */ + cur_dev->interface_number = get_int_property(dev, CFSTR(kUSBInterfaceNumber)); + } else { + cur_dev->interface_number = -1; + } + } + } + + free(device_array); + CFRelease(device_set); + + return root; +} + +void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) +{ + /* This function is identical to the Linux version. Platform independent. */ + struct hid_device_info *d = devs; + while (d) { + struct hid_device_info *next = d->next; + free(d->path); + free(d->serial_number); + free(d->manufacturer_string); + free(d->product_string); + free(d); + d = next; + } +} + +hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) +{ + /* This function is identical to the Linux version. Platform independent. */ + struct hid_device_info *devs, *cur_dev; + const char *path_to_open = NULL; + hid_device * handle = NULL; + + devs = hid_enumerate(vendor_id, product_id); + cur_dev = devs; + while (cur_dev) { + if (cur_dev->vendor_id == vendor_id && + cur_dev->product_id == product_id) { + if (serial_number) { + if (wcscmp(serial_number, cur_dev->serial_number) == 0) { + path_to_open = cur_dev->path; + break; + } + } + else { + path_to_open = cur_dev->path; + break; + } + } + cur_dev = cur_dev->next; + } + + if (path_to_open) { + /* Open the device */ + handle = hid_open_path(path_to_open); + } + + hid_free_enumeration(devs); + + return handle; +} + +static void hid_device_removal_callback(void *context, IOReturn result, + void *sender) +{ + /* Stop the Run Loop for this device. */ + hid_device *d = context; + + d->disconnected = 1; + CFRunLoopStop(d->run_loop); +} + +/* The Run Loop calls this function for each input report received. + This function puts the data into a linked list to be picked up by + hid_read(). */ +static void hid_report_callback(void *context, IOReturn result, void *sender, + IOHIDReportType report_type, uint32_t report_id, + uint8_t *report, CFIndex report_length) +{ + struct input_report *rpt; + hid_device *dev = context; + + /* Make a new Input Report object */ + rpt = calloc(1, sizeof(struct input_report)); + rpt->data = calloc(1, report_length); + memcpy(rpt->data, report, report_length); + rpt->len = report_length; + rpt->next = NULL; + + /* Lock this section */ + pthread_mutex_lock(&dev->mutex); + + /* Attach the new report object to the end of the list. */ + if (dev->input_reports == NULL) { + /* The list is empty. Put it at the root. */ + dev->input_reports = rpt; + } + else { + /* Find the end of the list and attach. */ + struct input_report *cur = dev->input_reports; + int num_queued = 0; + while (cur->next != NULL) { + cur = cur->next; + num_queued++; + } + cur->next = rpt; + + /* Pop one off if we've reached 30 in the queue. This + way we don't grow forever if the user never reads + anything from the device. */ + if (num_queued > 30) { + return_data(dev, NULL, 0); + } + } + + /* Signal a waiting thread that there is data. */ + pthread_cond_signal(&dev->condition); + + /* Unlock */ + pthread_mutex_unlock(&dev->mutex); + +} + +/* This gets called when the read_thread's run loop gets signaled by + hid_close(), and serves to stop the read_thread's run loop. */ +static void perform_signal_callback(void *context) +{ + hid_device *dev = context; + CFRunLoopStop(dev->run_loop); /*TODO: CFRunLoopGetCurrent()*/ +} + +static void *read_thread(void *param) +{ + hid_device *dev = param; + SInt32 code; + + /* Move the device's run loop to this thread. */ + IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode); + + /* Create the RunLoopSource which is used to signal the + event loop to stop when hid_close() is called. */ + CFRunLoopSourceContext ctx; + memset(&ctx, 0, sizeof(ctx)); + ctx.version = 0; + ctx.info = dev; + ctx.perform = &perform_signal_callback; + dev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0/*order*/, &ctx); + CFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode); + + /* Store off the Run Loop so it can be stopped from hid_close() + and on device disconnection. */ + dev->run_loop = CFRunLoopGetCurrent(); + + /* Notify the main thread that the read thread is up and running. */ + pthread_barrier_wait(&dev->barrier); + + /* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input + reports into the hid_report_callback(). */ + while (!dev->shutdown_thread && !dev->disconnected) { + code = CFRunLoopRunInMode(dev->run_loop_mode, 1000/*sec*/, FALSE); + /* Return if the device has been disconnected */ + if (code == kCFRunLoopRunFinished) { + dev->disconnected = 1; + break; + } + + + /* Break if The Run Loop returns Finished or Stopped. */ + if (code != kCFRunLoopRunTimedOut && + code != kCFRunLoopRunHandledSource) { + /* There was some kind of error. Setting + shutdown seems to make sense, but + there may be something else more appropriate */ + dev->shutdown_thread = 1; + break; + } + } + + /* Now that the read thread is stopping, Wake any threads which are + waiting on data (in hid_read_timeout()). Do this under a mutex to + make sure that a thread which is about to go to sleep waiting on + the condition actually will go to sleep before the condition is + signaled. */ + pthread_mutex_lock(&dev->mutex); + pthread_cond_broadcast(&dev->condition); + pthread_mutex_unlock(&dev->mutex); + + /* Wait here until hid_close() is called and makes it past + the call to CFRunLoopWakeUp(). This thread still needs to + be valid when that function is called on the other thread. */ + pthread_barrier_wait(&dev->shutdown_barrier); + + return NULL; +} + +/* hid_open_path() + * + * path must be a valid path to an IOHIDDevice in the IOService plane + * Example: "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/EHC1@1D,7/AppleUSBEHCI/PLAYSTATION(R)3 Controller@fd120000/IOUSBInterface@0/IOUSBHIDDriver" + */ +hid_device * HID_API_EXPORT hid_open_path(const char *path) +{ + hid_device *dev = NULL; + io_registry_entry_t entry = MACH_PORT_NULL; + + dev = new_hid_device(); + + /* Set up the HID Manager if it hasn't been done */ + if (hid_init() < 0) + return NULL; + + /* Get the IORegistry entry for the given path */ + entry = IORegistryEntryFromPath(kIOMasterPortDefault, path); + if (entry == MACH_PORT_NULL) { + /* Path wasn't valid (maybe device was removed?) */ + goto return_error; + } + + /* Create an IOHIDDevice for the entry */ + dev->device_handle = IOHIDDeviceCreate(kCFAllocatorDefault, entry); + if (dev->device_handle == NULL) { + /* Error creating the HID device */ + goto return_error; + } + + /* Open the IOHIDDevice */ + IOReturn ret = IOHIDDeviceOpen(dev->device_handle, kIOHIDOptionsTypeSeizeDevice); + if (ret == kIOReturnSuccess) { + char str[32]; + + /* Create the buffers for receiving data */ + dev->max_input_report_len = (CFIndex) get_max_report_length(dev->device_handle); + dev->input_report_buf = calloc(dev->max_input_report_len, sizeof(uint8_t)); + + /* Create the Run Loop Mode for this device. + printing the reference seems to work. */ + sprintf(str, "HIDAPI_%p", dev->device_handle); + dev->run_loop_mode = + CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII); + + /* Attach the device to a Run Loop */ + IOHIDDeviceRegisterInputReportCallback( + dev->device_handle, dev->input_report_buf, dev->max_input_report_len, + &hid_report_callback, dev); + IOHIDDeviceRegisterRemovalCallback(dev->device_handle, hid_device_removal_callback, dev); + + /* Start the read thread */ + pthread_create(&dev->thread, NULL, read_thread, dev); + + /* Wait here for the read thread to be initialized. */ + pthread_barrier_wait(&dev->barrier); + + IOObjectRelease(entry); + return dev; + } + else { + goto return_error; + } + +return_error: + if (dev->device_handle != NULL) + CFRelease(dev->device_handle); + + if (entry != MACH_PORT_NULL) + IOObjectRelease(entry); + + free_hid_device(dev); + return NULL; +} + +static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length) +{ + const unsigned char *data_to_send; + size_t length_to_send; + IOReturn res; + + /* Return if the device has been disconnected. */ + if (dev->disconnected) + return -1; + + if (data[0] == 0x0) { + /* Not using numbered Reports. + Don't send the report number. */ + data_to_send = data+1; + length_to_send = length-1; + } + else { + /* Using numbered Reports. + Send the Report Number */ + data_to_send = data; + length_to_send = length; + } + + if (!dev->disconnected) { + res = IOHIDDeviceSetReport(dev->device_handle, + type, + data[0], /* Report ID*/ + data_to_send, length_to_send); + + if (res == kIOReturnSuccess) { + return length; + } + else + return -1; + } + + return -1; +} + +int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) +{ + return set_report(dev, kIOHIDReportTypeOutput, data, length); +} + +/* Helper function, so that this isn't duplicated in hid_read(). */ +static int return_data(hid_device *dev, unsigned char *data, size_t length) +{ + /* Copy the data out of the linked list item (rpt) into the + return buffer (data), and delete the liked list item. */ + struct input_report *rpt = dev->input_reports; + size_t len = (length < rpt->len)? length: rpt->len; + memcpy(data, rpt->data, len); + dev->input_reports = rpt->next; + free(rpt->data); + free(rpt); + return len; +} + +static int cond_wait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + while (!dev->input_reports) { + int res = pthread_cond_wait(cond, mutex); + if (res != 0) + return res; + + /* A res of 0 means we may have been signaled or it may + be a spurious wakeup. Check to see that there's acutally + data in the queue before returning, and if not, go back + to sleep. See the pthread_cond_timedwait() man page for + details. */ + + if (dev->shutdown_thread || dev->disconnected) + return -1; + } + + return 0; +} + +static int cond_timedwait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) +{ + while (!dev->input_reports) { + int res = pthread_cond_timedwait(cond, mutex, abstime); + if (res != 0) + return res; + + /* A res of 0 means we may have been signaled or it may + be a spurious wakeup. Check to see that there's acutally + data in the queue before returning, and if not, go back + to sleep. See the pthread_cond_timedwait() man page for + details. */ + + if (dev->shutdown_thread || dev->disconnected) + return -1; + } + + return 0; + +} + +int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) +{ + int bytes_read = -1; + + /* Lock the access to the report list. */ + pthread_mutex_lock(&dev->mutex); + + /* There's an input report queued up. Return it. */ + if (dev->input_reports) { + /* Return the first one */ + bytes_read = return_data(dev, data, length); + goto ret; + } + + /* Return if the device has been disconnected. */ + if (dev->disconnected) { + bytes_read = -1; + goto ret; + } + + if (dev->shutdown_thread) { + /* This means the device has been closed (or there + has been an error. An error code of -1 should + be returned. */ + bytes_read = -1; + goto ret; + } + + /* There is no data. Go to sleep and wait for data. */ + + if (milliseconds == -1) { + /* Blocking */ + int res; + res = cond_wait(dev, &dev->condition, &dev->mutex); + if (res == 0) + bytes_read = return_data(dev, data, length); + else { + /* There was an error, or a device disconnection. */ + bytes_read = -1; + } + } + else if (milliseconds > 0) { + /* Non-blocking, but called with timeout. */ + int res; + struct timespec ts; + struct timeval tv; + gettimeofday(&tv, NULL); + TIMEVAL_TO_TIMESPEC(&tv, &ts); + ts.tv_sec += milliseconds / 1000; + ts.tv_nsec += (milliseconds % 1000) * 1000000; + if (ts.tv_nsec >= 1000000000L) { + ts.tv_sec++; + ts.tv_nsec -= 1000000000L; + } + + res = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts); + if (res == 0) + bytes_read = return_data(dev, data, length); + else if (res == ETIMEDOUT) + bytes_read = 0; + else + bytes_read = -1; + } + else { + /* Purely non-blocking */ + bytes_read = 0; + } + +ret: + /* Unlock */ + pthread_mutex_unlock(&dev->mutex); + return bytes_read; +} + +int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) +{ + return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); +} + +int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) +{ + /* All Nonblocking operation is handled by the library. */ + dev->blocking = !nonblock; + + return 0; +} + +int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) +{ + return set_report(dev, kIOHIDReportTypeFeature, data, length); +} + +int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) +{ + CFIndex len = length - 1; + IOReturn res; + + /* Return if the device has been unplugged. */ + if (dev->disconnected) + return -1; + + res = IOHIDDeviceGetReport(dev->device_handle, + kIOHIDReportTypeFeature, + data[0], /* Report ID */ + data + 1, &len); + if (res == kIOReturnSuccess) + return len + 1; + else + return -1; +} + + +void HID_API_EXPORT hid_close(hid_device *dev) +{ + if (!dev) + return; + + /* Disconnect the report callback before close. */ + if (!dev->disconnected) { + IOHIDDeviceRegisterInputReportCallback( + dev->device_handle, dev->input_report_buf, dev->max_input_report_len, + NULL, dev); + IOHIDDeviceRegisterRemovalCallback(dev->device_handle, NULL, dev); + IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode); + IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode); + } + + /* Cause read_thread() to stop. */ + dev->shutdown_thread = 1; + + /* Wake up the run thread's event loop so that the thread can exit. */ + CFRunLoopSourceSignal(dev->source); + CFRunLoopWakeUp(dev->run_loop); + + /* Notify the read thread that it can shut down now. */ + pthread_barrier_wait(&dev->shutdown_barrier); + + /* Wait for read_thread() to end. */ + pthread_join(dev->thread, NULL); + + /* Close the OS handle to the device, but only if it's not + been unplugged. If it's been unplugged, then calling + IOHIDDeviceClose() will crash. */ + if (!dev->disconnected) { + IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeSeizeDevice); + } + + /* Clear out the queue of received reports. */ + pthread_mutex_lock(&dev->mutex); + while (dev->input_reports) { + return_data(dev, NULL, 0); + } + pthread_mutex_unlock(&dev->mutex); + CFRelease(dev->device_handle); + + free_hid_device(dev); +} + +int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + return get_manufacturer_string(dev->device_handle, string, maxlen); +} + +int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + return get_product_string(dev->device_handle, string, maxlen); +} + +int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + return get_serial_number(dev->device_handle, string, maxlen); +} + +int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) +{ + /* TODO: */ + + return 0; +} + + +HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) +{ + /* TODO: */ + + return NULL; +} + + + + + + + +#if 0 +static int32_t get_location_id(IOHIDDeviceRef device) +{ + return get_int_property(device, CFSTR(kIOHIDLocationIDKey)); +} + +static int32_t get_usage(IOHIDDeviceRef device) +{ + int32_t res; + res = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey)); + if (!res) + res = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey)); + return res; +} + +static int32_t get_usage_page(IOHIDDeviceRef device) +{ + int32_t res; + res = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey)); + if (!res) + res = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey)); + return res; +} + +static int get_transport(IOHIDDeviceRef device, wchar_t *buf, size_t len) +{ + return get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len); +} + + +int main(void) +{ + IOHIDManagerRef mgr; + int i; + + mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + IOHIDManagerSetDeviceMatching(mgr, NULL); + IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone); + + CFSetRef device_set = IOHIDManagerCopyDevices(mgr); + + CFIndex num_devices = CFSetGetCount(device_set); + IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef)); + CFSetGetValues(device_set, (const void **) device_array); + + for (i = 0; i < num_devices; i++) { + IOHIDDeviceRef dev = device_array[i]; + printf("Device: %p\n", dev); + printf(" %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev)); + + wchar_t serial[256], buf[256]; + char cbuf[256]; + get_serial_number(dev, serial, 256); + + + printf(" Serial: %ls\n", serial); + printf(" Loc: %ld\n", get_location_id(dev)); + get_transport(dev, buf, 256); + printf(" Trans: %ls\n", buf); + make_path(dev, cbuf, 256); + printf(" Path: %s\n", cbuf); + + } + + return 0; +} +#endif diff --git a/src/hidapi/win/hid.c b/src/hidapi/win/hid.c new file mode 100644 index 000000000..4a71e2552 --- /dev/null +++ b/src/hidapi/win/hid.c @@ -0,0 +1,956 @@ +/******************************************************* + HIDAPI - Multi-Platform library for + communication with HID devices. + + Alan Ott + Signal 11 Software + + 8/22/2009 + + Copyright 2009, All Rights Reserved. + + At the discretion of the user of this library, + this software may be licensed under the terms of the + GNU General Public License v3, a BSD-Style license, or the + original HIDAPI license as outlined in the LICENSE.txt, + LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt + files located at the root of the source distribution. + These files may also be found in the public source + code repository located at: + http://github.com/signal11/hidapi . +********************************************************/ + +#include + +#ifndef _NTDEF_ +typedef LONG NTSTATUS; +#endif + +#ifdef __MINGW32__ +#include +#include +#endif + +#ifdef __CYGWIN__ +#include +#define _wcsdup wcsdup +#endif + +/* The maximum number of characters that can be passed into the + HidD_Get*String() functions without it failing.*/ +#define MAX_STRING_WCHARS 0xFFF + +/*#define HIDAPI_USE_DDK*/ + +#ifdef __cplusplus +extern "C" { +#endif + #include + #include + #ifdef HIDAPI_USE_DDK + #include + #endif + + /* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */ + #define HID_OUT_CTL_CODE(id) \ + CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS) + #define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include +#include + + +#include "hidapi.h" + +#undef MIN +#define MIN(x,y) ((x) < (y)? (x): (y)) + +#ifdef _MSC_VER + /* Thanks Microsoft, but I know how to use strncpy(). */ + #pragma warning(disable:4996) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HIDAPI_USE_DDK + /* Since we're not building with the DDK, and the HID header + files aren't part of the SDK, we have to define all this + stuff here. In lookup_functions(), the function pointers + defined below are set. */ + typedef struct _HIDD_ATTRIBUTES{ + ULONG Size; + USHORT VendorID; + USHORT ProductID; + USHORT VersionNumber; + } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; + + typedef USHORT USAGE; + typedef struct _HIDP_CAPS { + USAGE Usage; + USAGE UsagePage; + USHORT InputReportByteLength; + USHORT OutputReportByteLength; + USHORT FeatureReportByteLength; + USHORT Reserved[17]; + USHORT fields_not_used_by_hidapi[10]; + } HIDP_CAPS, *PHIDP_CAPS; + typedef void* PHIDP_PREPARSED_DATA; + #define HIDP_STATUS_SUCCESS 0x110000 + + typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib); + typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len); + typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); + typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); + typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length); + typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length); + typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len); + typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data); + typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data); + typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps); + typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers); + + static HidD_GetAttributes_ HidD_GetAttributes; + static HidD_GetSerialNumberString_ HidD_GetSerialNumberString; + static HidD_GetManufacturerString_ HidD_GetManufacturerString; + static HidD_GetProductString_ HidD_GetProductString; + static HidD_SetFeature_ HidD_SetFeature; + static HidD_GetFeature_ HidD_GetFeature; + static HidD_GetIndexedString_ HidD_GetIndexedString; + static HidD_GetPreparsedData_ HidD_GetPreparsedData; + static HidD_FreePreparsedData_ HidD_FreePreparsedData; + static HidP_GetCaps_ HidP_GetCaps; + static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers; + + static HMODULE lib_handle = NULL; + static BOOLEAN initialized = FALSE; +#endif /* HIDAPI_USE_DDK */ + +struct hid_device_ { + HANDLE device_handle; + BOOL blocking; + USHORT output_report_length; + size_t input_report_length; + void *last_error_str; + DWORD last_error_num; + BOOL read_pending; + char *read_buf; + OVERLAPPED ol; +}; + +static hid_device *new_hid_device() +{ + hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device)); + dev->device_handle = INVALID_HANDLE_VALUE; + dev->blocking = TRUE; + dev->output_report_length = 0; + dev->input_report_length = 0; + dev->last_error_str = NULL; + dev->last_error_num = 0; + dev->read_pending = FALSE; + dev->read_buf = NULL; + memset(&dev->ol, 0, sizeof(dev->ol)); + dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL); + + return dev; +} + +static void free_hid_device(hid_device *dev) +{ + CloseHandle(dev->ol.hEvent); + CloseHandle(dev->device_handle); + LocalFree(dev->last_error_str); + free(dev->read_buf); + free(dev); +} + +static void register_error(hid_device *dev, const char *op) +{ + WCHAR *ptr, *msg; + + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPVOID)&msg, 0/*sz*/, + NULL); + + /* Get rid of the CR and LF that FormatMessage() sticks at the + end of the message. Thanks Microsoft! */ + ptr = msg; + while (*ptr) { + if (*ptr == '\r') { + *ptr = 0x0000; + break; + } + ptr++; + } + + /* Store the message off in the Device entry so that + the hid_error() function can pick it up. */ + LocalFree(dev->last_error_str); + dev->last_error_str = msg; +} + +#ifndef HIDAPI_USE_DDK +static int lookup_functions() +{ + lib_handle = LoadLibraryA("hid.dll"); + if (lib_handle) { +#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1; + RESOLVE(HidD_GetAttributes); + RESOLVE(HidD_GetSerialNumberString); + RESOLVE(HidD_GetManufacturerString); + RESOLVE(HidD_GetProductString); + RESOLVE(HidD_SetFeature); + RESOLVE(HidD_GetFeature); + RESOLVE(HidD_GetIndexedString); + RESOLVE(HidD_GetPreparsedData); + RESOLVE(HidD_FreePreparsedData); + RESOLVE(HidP_GetCaps); + RESOLVE(HidD_SetNumInputBuffers); +#undef RESOLVE + } + else + return -1; + + return 0; +} +#endif + +static HANDLE open_device(const char *path, BOOL open_rw) +{ + HANDLE handle; + DWORD desired_access = (open_rw)? (GENERIC_WRITE | GENERIC_READ): 0; + DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE; + + handle = CreateFileA(path, + desired_access, + share_mode, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/ + 0); + + return handle; +} + +int HID_API_EXPORT hid_init(void) +{ +#ifndef HIDAPI_USE_DDK + if (!initialized) { + if (lookup_functions() < 0) { + hid_exit(); + return -1; + } + initialized = TRUE; + } +#endif + return 0; +} + +int HID_API_EXPORT hid_exit(void) +{ +#ifndef HIDAPI_USE_DDK + if (lib_handle) + FreeLibrary(lib_handle); + lib_handle = NULL; + initialized = FALSE; +#endif + return 0; +} + +struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id) +{ + BOOL res; + struct hid_device_info *root = NULL; /* return object */ + struct hid_device_info *cur_dev = NULL; + + /* Windows objects for interacting with the driver. */ + GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} }; + SP_DEVINFO_DATA devinfo_data; + SP_DEVICE_INTERFACE_DATA device_interface_data; + SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL; + HDEVINFO device_info_set = INVALID_HANDLE_VALUE; + int device_index = 0; + int i; + + if (hid_init() < 0) + return NULL; + + /* Initialize the Windows objects. */ + memset(&devinfo_data, 0x0, sizeof(devinfo_data)); + devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA); + device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + /* Get information for all the devices belonging to the HID class. */ + device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + + /* Iterate over each device in the HID class, looking for the right one. */ + + for (;;) { + HANDLE write_handle = INVALID_HANDLE_VALUE; + DWORD required_size = 0; + HIDD_ATTRIBUTES attrib; + + res = SetupDiEnumDeviceInterfaces(device_info_set, + NULL, + &InterfaceClassGuid, + device_index, + &device_interface_data); + + if (!res) { + /* A return of FALSE from this function means that + there are no more devices. */ + break; + } + + /* Call with 0-sized detail size, and let the function + tell us how long the detail struct needs to be. The + size is put in &required_size. */ + res = SetupDiGetDeviceInterfaceDetailA(device_info_set, + &device_interface_data, + NULL, + 0, + &required_size, + NULL); + + /* Allocate a long enough structure for device_interface_detail_data. */ + device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size); + device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); + + /* Get the detailed data for this device. The detail data gives us + the device path for this device, which is then passed into + CreateFile() to get a handle to the device. */ + res = SetupDiGetDeviceInterfaceDetailA(device_info_set, + &device_interface_data, + device_interface_detail_data, + required_size, + NULL, + NULL); + + if (!res) { + /* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail"); + Continue to the next device. */ + goto cont; + } + + /* Make sure this device is of Setup Class "HIDClass" and has a + driver bound to it. */ + for (i = 0; ; i++) { + char driver_name[256]; + + /* Populate devinfo_data. This function will return failure + when there are no more interfaces left. */ + res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data); + if (!res) + goto cont; + + res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data, + SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL); + if (!res) + goto cont; + + if ((strcmp(driver_name, "HIDClass") == 0) || + (strcmp(driver_name, "Mouse") == 0) || + (strcmp(driver_name, "Keyboard") == 0)) { + /* See if there's a driver bound. */ + res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data, + SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL); + if (res) + break; + } + } + + //wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath); + + /* Open a handle to the device */ + write_handle = open_device(device_interface_detail_data->DevicePath, FALSE); + + /* Check validity of write_handle. */ + if (write_handle == INVALID_HANDLE_VALUE) { + /* Unable to open the device. */ + //register_error(dev, "CreateFile"); + goto cont_close; + } + + + /* Get the Vendor ID and Product ID for this device. */ + attrib.Size = sizeof(HIDD_ATTRIBUTES); + HidD_GetAttributes(write_handle, &attrib); + //wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID); + + /* Check the VID/PID to see if we should add this + device to the enumeration list. */ + if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) && + (product_id == 0x0 || attrib.ProductID == product_id)) { + + #define WSTR_LEN 512 + const char *str; + struct hid_device_info *tmp; + PHIDP_PREPARSED_DATA pp_data = NULL; + HIDP_CAPS caps; + BOOLEAN res; + NTSTATUS nt_res; + wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */ + size_t len; + + /* VID/PID match. Create the record. */ + tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info)); + if (cur_dev) { + cur_dev->next = tmp; + } + else { + root = tmp; + } + cur_dev = tmp; + + /* Get the Usage Page and Usage for this device. */ + res = HidD_GetPreparsedData(write_handle, &pp_data); + if (res) { + nt_res = HidP_GetCaps(pp_data, &caps); + if (nt_res == HIDP_STATUS_SUCCESS) { + cur_dev->usage_page = caps.UsagePage; + cur_dev->usage = caps.Usage; + } + + HidD_FreePreparsedData(pp_data); + } + + /* Fill out the record */ + cur_dev->next = NULL; + str = device_interface_detail_data->DevicePath; + if (str) { + len = strlen(str); + cur_dev->path = (char*) calloc(len+1, sizeof(char)); + strncpy(cur_dev->path, str, len+1); + cur_dev->path[len] = '\0'; + } + else + cur_dev->path = NULL; + + /* Serial Number */ + res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr)); + wstr[WSTR_LEN-1] = 0x0000; + if (res) { + cur_dev->serial_number = _wcsdup(wstr); + } + + /* Manufacturer String */ + res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr)); + wstr[WSTR_LEN-1] = 0x0000; + if (res) { + cur_dev->manufacturer_string = _wcsdup(wstr); + } + + /* Product String */ + res = HidD_GetProductString(write_handle, wstr, sizeof(wstr)); + wstr[WSTR_LEN-1] = 0x0000; + if (res) { + cur_dev->product_string = _wcsdup(wstr); + } + + /* VID/PID */ + cur_dev->vendor_id = attrib.VendorID; + cur_dev->product_id = attrib.ProductID; + + /* Release Number */ + cur_dev->release_number = attrib.VersionNumber; + + /* Interface Number. It can sometimes be parsed out of the path + on Windows if a device has multiple interfaces. See + http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or + search for "Hardware IDs for HID Devices" at MSDN. If it's not + in the path, it's set to -1. */ + cur_dev->interface_number = -1; + if (cur_dev->path) { + char *interface_component = strstr(cur_dev->path, "&mi_"); + if (interface_component) { + char *hex_str = interface_component + 4; + char *endptr = NULL; + cur_dev->interface_number = strtol(hex_str, &endptr, 16); + if (endptr == hex_str) { + /* The parsing failed. Set interface_number to -1. */ + cur_dev->interface_number = -1; + } + } + } + } + +cont_close: + CloseHandle(write_handle); +cont: + /* We no longer need the detail data. It can be freed */ + free(device_interface_detail_data); + + device_index++; + + } + + /* Close the device information handle. */ + SetupDiDestroyDeviceInfoList(device_info_set); + + return root; + +} + +void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs) +{ + /* TODO: Merge this with the Linux version. This function is platform-independent. */ + struct hid_device_info *d = devs; + while (d) { + struct hid_device_info *next = d->next; + free(d->path); + free(d->serial_number); + free(d->manufacturer_string); + free(d->product_string); + free(d); + d = next; + } +} + + +HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) +{ + /* TODO: Merge this functions with the Linux version. This function should be platform independent. */ + struct hid_device_info *devs, *cur_dev; + const char *path_to_open = NULL; + hid_device *handle = NULL; + + devs = hid_enumerate(vendor_id, product_id); + cur_dev = devs; + while (cur_dev) { + if (cur_dev->vendor_id == vendor_id && + cur_dev->product_id == product_id) { + if (serial_number) { + if (wcscmp(serial_number, cur_dev->serial_number) == 0) { + path_to_open = cur_dev->path; + break; + } + } + else { + path_to_open = cur_dev->path; + break; + } + } + cur_dev = cur_dev->next; + } + + if (path_to_open) { + /* Open the device */ + handle = hid_open_path(path_to_open); + } + + hid_free_enumeration(devs); + + return handle; +} + +HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) +{ + hid_device *dev; + HIDP_CAPS caps; + PHIDP_PREPARSED_DATA pp_data = NULL; + BOOLEAN res; + NTSTATUS nt_res; + + if (hid_init() < 0) { + return NULL; + } + + dev = new_hid_device(); + + /* Open a handle to the device */ + dev->device_handle = open_device(path, TRUE); + + /* Check validity of write_handle. */ + if (dev->device_handle == INVALID_HANDLE_VALUE) { + /* System devices, such as keyboards and mice, cannot be opened in + read-write mode, because the system takes exclusive control over + them. This is to prevent keyloggers. However, feature reports + can still be sent and received. Retry opening the device, but + without read/write access. */ + dev->device_handle = open_device(path, FALSE); + + /* Check the validity of the limited device_handle. */ + if (dev->device_handle == INVALID_HANDLE_VALUE) { + /* Unable to open the device, even without read-write mode. */ + register_error(dev, "CreateFile"); + goto err; + } + } + + /* Set the Input Report buffer size to 64 reports. */ + res = HidD_SetNumInputBuffers(dev->device_handle, 64); + if (!res) { + register_error(dev, "HidD_SetNumInputBuffers"); + goto err; + } + + /* Get the Input Report length for the device. */ + res = HidD_GetPreparsedData(dev->device_handle, &pp_data); + if (!res) { + register_error(dev, "HidD_GetPreparsedData"); + goto err; + } + nt_res = HidP_GetCaps(pp_data, &caps); + if (nt_res != HIDP_STATUS_SUCCESS) { + register_error(dev, "HidP_GetCaps"); + goto err_pp_data; + } + dev->output_report_length = caps.OutputReportByteLength; + dev->input_report_length = caps.InputReportByteLength; + HidD_FreePreparsedData(pp_data); + + dev->read_buf = (char*) malloc(dev->input_report_length); + + return dev; + +err_pp_data: + HidD_FreePreparsedData(pp_data); +err: + free_hid_device(dev); + return NULL; +} + +int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length) +{ + DWORD bytes_written; + BOOL res; + + OVERLAPPED ol; + unsigned char *buf; + memset(&ol, 0, sizeof(ol)); + + /* Make sure the right number of bytes are passed to WriteFile. Windows + expects the number of bytes which are in the _longest_ report (plus + one for the report number) bytes even if the data is a report + which is shorter than that. Windows gives us this value in + caps.OutputReportByteLength. If a user passes in fewer bytes than this, + create a temporary buffer which is the proper size. */ + if (length >= dev->output_report_length) { + /* The user passed the right number of bytes. Use the buffer as-is. */ + buf = (unsigned char *) data; + } else { + /* Create a temporary buffer and copy the user's data + into it, padding the rest with zeros. */ + buf = (unsigned char *) malloc(dev->output_report_length); + memcpy(buf, data, length); + memset(buf + length, 0, dev->output_report_length - length); + length = dev->output_report_length; + } + + res = WriteFile(dev->device_handle, buf, length, NULL, &ol); + + if (!res) { + if (GetLastError() != ERROR_IO_PENDING) { + /* WriteFile() failed. Return error. */ + register_error(dev, "WriteFile"); + bytes_written = -1; + goto end_of_function; + } + } + + /* Wait here until the write is done. This makes + hid_write() synchronous. */ + res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/); + if (!res) { + /* The Write operation failed. */ + register_error(dev, "WriteFile"); + bytes_written = -1; + goto end_of_function; + } + +end_of_function: + if (buf != data) + free(buf); + + return bytes_written; +} + + +int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) +{ + DWORD bytes_read = 0; + size_t copy_len = 0; + BOOL res; + + /* Copy the handle for convenience. */ + HANDLE ev = dev->ol.hEvent; + + if (!dev->read_pending) { + /* Start an Overlapped I/O read. */ + dev->read_pending = TRUE; + memset(dev->read_buf, 0, dev->input_report_length); + ResetEvent(ev); + res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol); + + if (!res) { + if (GetLastError() != ERROR_IO_PENDING) { + /* ReadFile() has failed. + Clean up and return error. */ + CancelIo(dev->device_handle); + dev->read_pending = FALSE; + goto end_of_function; + } + } + } + + if (milliseconds >= 0) { + /* See if there is any data yet. */ + res = WaitForSingleObject(ev, milliseconds); + if (res != WAIT_OBJECT_0) { + /* There was no data this time. Return zero bytes available, + but leave the Overlapped I/O running. */ + return 0; + } + } + + /* Either WaitForSingleObject() told us that ReadFile has completed, or + we are in non-blocking mode. Get the number of bytes read. The actual + data has been copied to the data[] array which was passed to ReadFile(). */ + res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/); + + /* Set pending back to false, even if GetOverlappedResult() returned error. */ + dev->read_pending = FALSE; + + if (res && bytes_read > 0) { + if (dev->read_buf[0] == 0x0) { + /* If report numbers aren't being used, but Windows sticks a report + number (0x0) on the beginning of the report anyway. To make this + work like the other platforms, and to make it work more like the + HID spec, we'll skip over this byte. */ + bytes_read--; + copy_len = length > bytes_read ? bytes_read : length; + memcpy(data, dev->read_buf+1, copy_len); + } + else { + /* Copy the whole buffer, report number and all. */ + copy_len = length > bytes_read ? bytes_read : length; + memcpy(data, dev->read_buf, copy_len); + } + } + +end_of_function: + if (!res) { + register_error(dev, "GetOverlappedResult"); + return -1; + } + + return copy_len; +} + +int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length) +{ + return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); +} + +int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock) +{ + dev->blocking = !nonblock; + return 0; /* Success */ +} + +int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) +{ + BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, length); + if (!res) { + register_error(dev, "HidD_SetFeature"); + return -1; + } + + return length; +} + + +int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) +{ + BOOL res; +#if 0 + res = HidD_GetFeature(dev->device_handle, data, length); + if (!res) { + register_error(dev, "HidD_GetFeature"); + return -1; + } + return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */ +#else + DWORD bytes_returned; + + OVERLAPPED ol; + memset(&ol, 0, sizeof(ol)); + + res = DeviceIoControl(dev->device_handle, + IOCTL_HID_GET_FEATURE, + data, length, + data, length, + &bytes_returned, &ol); + + if (!res) { + if (GetLastError() != ERROR_IO_PENDING) { + /* DeviceIoControl() failed. Return error. */ + register_error(dev, "Send Feature Report DeviceIoControl"); + return -1; + } + } + + /* Wait here until the write is done. This makes + hid_get_feature_report() synchronous. */ + res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/); + if (!res) { + /* The operation failed. */ + register_error(dev, "Send Feature Report GetOverLappedResult"); + return -1; + } + + /* bytes_returned does not include the first byte which contains the + report ID. The data buffer actually contains one more byte than + bytes_returned. */ + bytes_returned++; + + return bytes_returned; +#endif +} + +void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev) +{ + if (!dev) + return; + CancelIo(dev->device_handle); + free_hid_device(dev); +} + +int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + BOOL res; + + res = HidD_GetManufacturerString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)); + if (!res) { + register_error(dev, "HidD_GetManufacturerString"); + return -1; + } + + return 0; +} + +int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + BOOL res; + + res = HidD_GetProductString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)); + if (!res) { + register_error(dev, "HidD_GetProductString"); + return -1; + } + + return 0; +} + +int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + BOOL res; + + res = HidD_GetSerialNumberString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)); + if (!res) { + register_error(dev, "HidD_GetSerialNumberString"); + return -1; + } + + return 0; +} + +int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) +{ + BOOL res; + + res = HidD_GetIndexedString(dev->device_handle, string_index, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)); + if (!res) { + register_error(dev, "HidD_GetIndexedString"); + return -1; + } + + return 0; +} + + +HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) +{ + return (wchar_t*)dev->last_error_str; +} + + +/*#define PICPGM*/ +/*#define S11*/ +#define P32 +#ifdef S11 + unsigned short VendorID = 0xa0a0; + unsigned short ProductID = 0x0001; +#endif + +#ifdef P32 + unsigned short VendorID = 0x04d8; + unsigned short ProductID = 0x3f; +#endif + + +#ifdef PICPGM + unsigned short VendorID = 0x04d8; + unsigned short ProductID = 0x0033; +#endif + + +#if 0 +int __cdecl main(int argc, char* argv[]) +{ + int res; + unsigned char buf[65]; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + /* Set up the command buffer. */ + memset(buf,0x00,sizeof(buf)); + buf[0] = 0; + buf[1] = 0x81; + + + /* Open the device. */ + int handle = open(VendorID, ProductID, L"12345"); + if (handle < 0) + printf("unable to open device\n"); + + + /* Toggle LED (cmd 0x80) */ + buf[1] = 0x80; + res = write(handle, buf, 65); + if (res < 0) + printf("Unable to write()\n"); + + /* Request state (cmd 0x81) */ + buf[1] = 0x81; + write(handle, buf, 65); + if (res < 0) + printf("Unable to write() (2)\n"); + + /* Read requested state */ + read(handle, buf, 65); + if (res < 0) + printf("Unable to read()\n"); + + /* Print out the returned buffer. */ + for (int i = 0; i < 4; i++) + printf("buf[%d]: %d\n", i, buf[i]); + + return 0; +} +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 88eba9a51..fa7dd2851 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -2,6 +2,7 @@ #include "../ClipperUtils.hpp" #include "../EdgeGrid.hpp" +#include "../Geometry.hpp" #include "../Surface.hpp" #include "../PrintConfig.hpp" #include "../libslic3r.h" @@ -777,6 +778,8 @@ void mark_boundary_segments_touching_infill( const Vec2d *pt2; } visitor(grid, boundary, boundary_data, distance_colliding * distance_colliding); + BoundingBoxf bboxf(boundary_bbox.min.cast(), boundary_bbox.max.cast()); + bboxf.offset(- SCALED_EPSILON); for (const Polyline &polyline : infill) { // Clip the infill polyline by the Eucledian distance along the polyline. SegmentPoint start_point = clip_start_segment_and_point(polyline.points, clip_distance); @@ -814,10 +817,12 @@ void mark_boundary_segments_touching_infill( Vec2d vperp(-v.y(), v.x()); Vec2d a = pt1 - v - vperp; Vec2d b = pt1 + v - vperp; - grid.visit_cells_intersecting_line(a.cast(), b.cast(), visitor); + if (Geometry::liang_barsky_line_clipping(a, b, bboxf)) + grid.visit_cells_intersecting_line(a.cast(), b.cast(), visitor); a = pt1 - v + vperp; b = pt1 + v + vperp; - grid.visit_cells_intersecting_line(a.cast(), b.cast(), visitor); + if (Geometry::liang_barsky_line_clipping(a, b, bboxf)) + grid.visit_cells_intersecting_line(a.cast(), b.cast(), visitor); #endif } } diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 869449a97..358c77f3f 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -6,9 +6,6 @@ #include "Geometry.hpp" #include "GCode/PrintExtents.hpp" #include "GCode/WipeTower.hpp" -#if ENABLE_THUMBNAIL_GENERATOR -#include "GCode/ThumbnailData.hpp" -#endif // ENABLE_THUMBNAIL_GENERATOR #include "ShortestPath.hpp" #include "Utils.hpp" @@ -35,9 +32,7 @@ #include -#if ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE #include "miniz_extension.hpp" -#endif // ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE #if 0 // Enable debugging and asserts, even in the release build. @@ -695,7 +690,7 @@ std::vector>> GCode::collec } #if ENABLE_THUMBNAIL_GENERATOR -void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, const std::vector* thumbnail_data) +void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb) #else void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_data) #endif // ENABLE_THUMBNAIL_GENERATOR @@ -725,7 +720,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ try { m_placeholder_parser_failed_templates.clear(); #if ENABLE_THUMBNAIL_GENERATOR - this->_do_export(*print, file, thumbnail_data); + this->_do_export(*print, file, thumbnail_cb); #else this->_do_export(*print, file); #endif // ENABLE_THUMBNAIL_GENERATOR @@ -793,9 +788,9 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ } #if ENABLE_THUMBNAIL_GENERATOR -void GCode::_do_export(Print& print, FILE* file, const std::vector* thumbnail_data) +void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb) #else -void GCode::_do_export(Print &print, FILE *file) +void GCode::_do_export(Print& print, FILE* file) #endif // ENABLE_THUMBNAIL_GENERATOR { PROFILE_FUNC(); @@ -812,46 +807,46 @@ void GCode::_do_export(Print &print, FILE *file) // shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor. if (print.config().gcode_flavor.value == gcfMarlin) { m_normal_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values[0]); - m_normal_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values[0]); - m_normal_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values[0]); - m_normal_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values[0]); - m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values[0]); - m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values[0]); - m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values[0]); - m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values[0]); - m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values[0]); - m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values[0]); - m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values[0]); - m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values[0]); - m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values[0]); - m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values[0]); - m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values[0]); - m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values[0]); + m_normal_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values[0]); + m_normal_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values[0]); + m_normal_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values[0]); + m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values[0]); + m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values[0]); + m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values[0]); + m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values[0]); + m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values[0]); + m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values[0]); + m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values[0]); + m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values[0]); + m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values[0]); + m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values[0]); + m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values[0]); + m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values[0]); if (m_silent_time_estimator_enabled) { m_silent_time_estimator.reset(); m_silent_time_estimator.set_dialect(print.config().gcode_flavor); - /* "Stealth mode" values can be just a copy of "normal mode" values + /* "Stealth mode" values can be just a copy of "normal mode" values * (when they aren't input for a printer preset). * Thus, use back value from values, instead of second one, which could be absent */ - m_silent_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values.back()); - m_silent_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values.back()); - m_silent_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values.back()); - m_silent_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values.back()); - m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values.back()); - m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values.back()); - m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values.back()); - m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values.back()); - m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values.back()); - m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values.back()); - m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values.back()); - m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values.back()); - m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values.back()); - m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values.back()); - m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values.back()); - m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values.back()); + m_silent_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values.back()); + m_silent_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values.back()); + m_silent_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values.back()); + m_silent_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values.back()); + m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values.back()); + m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values.back()); + m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values.back()); + m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values.back()); + m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values.back()); + m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values.back()); + m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values.back()); + m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values.back()); + m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values.back()); + m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values.back()); + m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values.back()); + m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values.back()); if (print.config().single_extruder_multi_material) { // As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they // are considered to be active for the single extruder multi-material printers only. @@ -909,7 +904,8 @@ void GCode::_do_export(Print &print, FILE *file) std::sort(zs.begin(), zs.end()); m_layer_count += (unsigned int)(object->copies().size() * (std::unique(zs.begin(), zs.end()) - zs.begin())); } - } else { + } + else { // Print all objects with the same print_z together. std::vector zs; for (auto object : print.objects()) { @@ -927,7 +923,7 @@ void GCode::_do_export(Print &print, FILE *file) m_enable_cooling_markers = true; this->apply_print_config(print.config()); this->set_extruders(print.extruders()); - + // Initialize custom gcode Model* model = print.get_object(0)->model_object()->get_model(); m_custom_g_code_heights = model->custom_gcode_per_height; @@ -937,31 +933,31 @@ void GCode::_do_export(Print &print, FILE *file) // get the minimum cross-section used in the print std::vector mm3_per_mm; for (auto object : print.objects()) { - for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) { + for (size_t region_id = 0; region_id < object->region_volumes.size(); ++region_id) { const PrintRegion* region = print.regions()[region_id]; for (auto layer : object->layers()) { const LayerRegion* layerm = layer->regions()[region_id]; - if (region->config().get_abs_value("perimeter_speed" ) == 0 || - region->config().get_abs_value("small_perimeter_speed" ) == 0 || - region->config().get_abs_value("external_perimeter_speed" ) == 0 || - region->config().get_abs_value("bridge_speed" ) == 0) + if (region->config().get_abs_value("perimeter_speed") == 0 || + region->config().get_abs_value("small_perimeter_speed") == 0 || + region->config().get_abs_value("external_perimeter_speed") == 0 || + region->config().get_abs_value("bridge_speed") == 0) mm3_per_mm.push_back(layerm->perimeters.min_mm3_per_mm()); - if (region->config().get_abs_value("infill_speed" ) == 0 || - region->config().get_abs_value("solid_infill_speed" ) == 0 || - region->config().get_abs_value("top_solid_infill_speed" ) == 0 || - region->config().get_abs_value("bridge_speed" ) == 0) + if (region->config().get_abs_value("infill_speed") == 0 || + region->config().get_abs_value("solid_infill_speed") == 0 || + region->config().get_abs_value("top_solid_infill_speed") == 0 || + region->config().get_abs_value("bridge_speed") == 0) mm3_per_mm.push_back(layerm->fills.min_mm3_per_mm()); } } - if (object->config().get_abs_value("support_material_speed" ) == 0 || - object->config().get_abs_value("support_material_interface_speed" ) == 0) + if (object->config().get_abs_value("support_material_speed") == 0 || + object->config().get_abs_value("support_material_interface_speed") == 0) for (auto layer : object->support_layers()) mm3_per_mm.push_back(layer->support_fills.min_mm3_per_mm()); } print.throw_if_canceled(); // filter out 0-width segments 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()) { + 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 // volumetric speed as the volumetric speed produced by printing the @@ -974,7 +970,7 @@ void GCode::_do_export(Print &print, FILE *file) } } print.throw_if_canceled(); - + m_cooling_buffer = make_unique(*this); if (print.config().spiral_vase.value) m_spiral_vase = make_unique(print.config()); @@ -992,15 +988,15 @@ void GCode::_do_export(Print &print, FILE *file) #if ENABLE_THUMBNAIL_GENERATOR // Write thumbnails using base64 encoding - if (thumbnail_data != nullptr) + if (thumbnail_cb != nullptr) { const size_t max_row_length = 78; - - for (const ThumbnailData& data : *thumbnail_data) + ThumbnailsList thumbnails; + thumbnail_cb(thumbnails, print.full_print_config().option("thumbnails")->values, true, true, true); + for (const ThumbnailData& data : thumbnails) { if (data.is_valid()) { -#if ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE size_t png_size = 0; void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1); if (png_data != nullptr) @@ -1026,39 +1022,6 @@ void GCode::_do_export(Print &print, FILE *file) mz_free(png_data); } -#else - _write_format(file, "\n;\n; thumbnail begin %dx%d\n", data.width, data.height); - - size_t row_size = 4 * data.width; - for (int r = (int)data.height - 1; r >= 0; --r) - { - std::string encoded; - encoded.resize(boost::beast::detail::base64::encoded_size(row_size)); - encoded.resize(boost::beast::detail::base64::encode((void*)&encoded[0], (const void*)(data.pixels.data() + r * row_size), row_size)); - - unsigned int row_count = 0; - while (encoded.size() > max_row_length) - { - if (row_count == 0) - _write_format(file, "; %s\n", encoded.substr(0, max_row_length).c_str()); - else - _write_format(file, ";>%s\n", encoded.substr(0, max_row_length).c_str()); - - encoded = encoded.substr(max_row_length); - ++row_count; - } - - if (encoded.size() > 0) - { - if (row_count == 0) - _write_format(file, "; %s\n", encoded.c_str()); - else - _write_format(file, ";>%s\n", encoded.c_str()); - } - } - - _write(file, "; thumbnail end\n;\n"); -#endif // ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE } print.throw_if_canceled(); } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 261a24d01..7f009b814 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -17,6 +17,9 @@ #include "GCodeTimeEstimator.hpp" #include "EdgeGrid.hpp" #include "GCode/Analyzer.hpp" +#if ENABLE_THUMBNAIL_GENERATOR +#include "GCode/ThumbnailData.hpp" +#endif // ENABLE_THUMBNAIL_GENERATOR #include #include @@ -30,9 +33,6 @@ namespace Slic3r { // Forward declarations. class GCode; class GCodePreviewData; -#if ENABLE_THUMBNAIL_GENERATOR -struct ThumbnailData; -#endif // ENABLE_THUMBNAIL_GENERATOR class AvoidCrossingPerimeters { public: @@ -167,7 +167,7 @@ public: // throws std::runtime_exception on error, // throws CanceledException through print->throw_if_canceled(). #if ENABLE_THUMBNAIL_GENERATOR - void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, const std::vector* thumbnail_data = nullptr); + void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr); #else void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr); #endif // ENABLE_THUMBNAIL_GENERATOR @@ -199,7 +199,7 @@ public: protected: #if ENABLE_THUMBNAIL_GENERATOR - void _do_export(Print& print, FILE* file, const std::vector* thumbnail_data); + void _do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb); #else void _do_export(Print &print, FILE *file); #endif //ENABLE_THUMBNAIL_GENERATOR diff --git a/src/libslic3r/GCode/ThumbnailData.hpp b/src/libslic3r/GCode/ThumbnailData.hpp index 9823ffd31..efe875e15 100644 --- a/src/libslic3r/GCode/ThumbnailData.hpp +++ b/src/libslic3r/GCode/ThumbnailData.hpp @@ -4,6 +4,7 @@ #if ENABLE_THUMBNAIL_GENERATOR #include +#include "libslic3r/Point.hpp" namespace Slic3r { @@ -20,6 +21,9 @@ struct ThumbnailData bool is_valid() const; }; +typedef std::vector ThumbnailsList; +typedef std::function ThumbnailsGeneratorCallback; + } // namespace Slic3r #endif // ENABLE_THUMBNAIL_GENERATOR diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index d996658f2..283d1edb0 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -137,6 +137,79 @@ inline bool segments_intersect( segments_could_intersect(jp1, jp2, ip1, ip2) <= 0; } +// Based on Liang-Barsky function by Daniel White @ http://www.skytopia.com/project/articles/compsci/clipping.html +template +bool liang_barsky_line_clipping( + // Start and end points of the source line, result will be stored there as well. + Eigen::Matrix &x0, + Eigen::Matrix &x1, + // Bounding box to clip with. + const BoundingBoxBase> &bbox) +{ + Eigen::Matrix v = x1 - x0; + double t0 = 0.0; + double t1 = 1.0; + + // Traverse through left, right, bottom, top edges. + for (int edge = 0; edge < 4; ++ edge) + { + double p, q; + switch (edge) { + case 0: p = - v.x(); q = - bbox.min.x() + x0.x(); break; + case 1: p = v.x(); q = bbox.max.x() - x0.x(); break; + case 2: p = - v.y(); q = - bbox.min.y() + x0.y(); break; + default: p = v.y(); q = bbox.max.y() - x0.y(); break; + } + + if (p == 0) { + if (q < 0) + // Line parallel to the bounding box edge is fully outside of the bounding box. + return false; + // else don't clip + } else { + double r = q / p; + if (p < 0) { + if (r > t1) + // Fully clipped. + return false; + if (r > t0) + // Partially clipped. + t0 = r; + } else { + assert(p > 0); + if (r < t0) + // Fully clipped. + return false; + if (r < t1) + // Partially clipped. + t1 = r; + } + } + } + + // Clipped successfully. + x1 = x0 + t1 * v; + x0 += t0 * v; + return true; +} + +// Based on Liang-Barsky function by Daniel White @ http://www.skytopia.com/project/articles/compsci/clipping.html +template +bool liang_barsky_line_clipping( + // Start and end points of the source line. + const Eigen::Matrix &x0src, + const Eigen::Matrix &x1src, + // Bounding box to clip with. + const BoundingBoxBase> &bbox, + // Start and end points of the clipped line. + Eigen::Matrix &x0clip, + Eigen::Matrix &x1clip) +{ + x0clip = x0src; + x1clip = x1src; + return liang_barsky_line_clipping(x0clip, x1clip, bbox); +} + Pointf3s convex_hull(Pointf3s points); Polygon convex_hull(Points points); Polygon convex_hull(const Polygons &polygons); diff --git a/src/libslic3r/Line.cpp b/src/libslic3r/Line.cpp index e5f7b8fa9..05cbfee4e 100644 --- a/src/libslic3r/Line.cpp +++ b/src/libslic3r/Line.cpp @@ -107,6 +107,17 @@ bool Line::intersection(const Line &l2, Point *intersection) const return false; // not intersecting } +bool Line::clip_with_bbox(const BoundingBox &bbox) +{ + Vec2d x0clip, x1clip; + bool result = Geometry::liang_barsky_line_clipping(this->a.cast(), this->b.cast(), BoundingBoxf(bbox.min.cast(), bbox.max.cast()), x0clip, x1clip); + if (result) { + this->a = x0clip.cast(); + this->b = x1clip.cast(); + } + return result; +} + Vec3d Linef3::intersect_plane(double z) const { auto v = (this->b - this->a).cast(); diff --git a/src/libslic3r/Line.hpp b/src/libslic3r/Line.hpp index 559ca946a..06809c02a 100644 --- a/src/libslic3r/Line.hpp +++ b/src/libslic3r/Line.hpp @@ -6,6 +6,7 @@ namespace Slic3r { +class BoundingBox; class Line; class Line3; class Linef3; @@ -43,6 +44,8 @@ public: Vector normal() const { return Vector((this->b(1) - this->a(1)), -(this->b(0) - this->a(0))); } bool intersection(const Line& line, Point* intersection) const; double ccw(const Point& point) const { return point.ccw(*this); } + // Clip a line with a bounding box. Returns false if the line is completely outside of the bounding box. + bool clip_with_bbox(const BoundingBox &bbox); static double distance_to_squared(const Point &point, const Point &a, const Point &b); static double distance_to(const Point &point, const Point &a, const Point &b) { return sqrt(distance_to_squared(point, a, b)); } diff --git a/src/libslic3r/MotionPlanner.cpp b/src/libslic3r/MotionPlanner.cpp index 42bc6c2f1..45a80671c 100644 --- a/src/libslic3r/MotionPlanner.cpp +++ b/src/libslic3r/MotionPlanner.cpp @@ -319,7 +319,7 @@ Polyline MotionPlannerGraph::shortest_path(size_t node_start, size_t node_end) c std::vector map_node_to_queue_id(m_adjacency_list.size(), size_t(-1)); distance[node_start] = 0.; - auto queue = make_mutable_priority_queue( + auto queue = make_mutable_priority_queue( [&map_node_to_queue_id](const node_t node, size_t idx) { map_node_to_queue_id[node] = idx; }, [&distance](const node_t node1, const node_t node2) { return distance[node1] < distance[node2]; }); queue.reserve(m_adjacency_list.size()); diff --git a/src/libslic3r/MutablePriorityQueue.hpp b/src/libslic3r/MutablePriorityQueue.hpp index da469b7ba..b20bf60ea 100644 --- a/src/libslic3r/MutablePriorityQueue.hpp +++ b/src/libslic3r/MutablePriorityQueue.hpp @@ -3,7 +3,7 @@ #include -template +template class MutablePriorityQueue { public: @@ -42,26 +42,30 @@ private: LessPredicate m_less_predicate; }; -template -MutablePriorityQueue make_mutable_priority_queue(IndexSetter &&index_setter, LessPredicate &&less_predicate) +template +MutablePriorityQueue make_mutable_priority_queue(IndexSetter &&index_setter, LessPredicate &&less_predicate) { - return MutablePriorityQueue( + return MutablePriorityQueue( std::forward(index_setter), std::forward(less_predicate)); } -template -inline void MutablePriorityQueue::clear() +template +inline void MutablePriorityQueue::clear() { -#ifndef NDEBUG - for (size_t idx = 0; idx < m_heap.size(); ++ idx) - // Mark as removed from the queue. - m_index_setter(m_heap[idx], std::numeric_limits::max()); +#ifdef NDEBUG + // Only mark as removed from the queue in release mode, if configured so. + if (ResetIndexWhenRemoved) #endif /* NDEBUG */ + { + for (size_t idx = 0; idx < m_heap.size(); ++ idx) + // Mark as removed from the queue. + m_index_setter(m_heap[idx], std::numeric_limits::max()); + } m_heap.clear(); } -template -inline void MutablePriorityQueue::push(const T &item) +template +inline void MutablePriorityQueue::push(const T &item) { size_t idx = m_heap.size(); m_heap.emplace_back(item); @@ -69,8 +73,8 @@ inline void MutablePriorityQueue::push(const T &i update_heap_up(0, idx); } -template -inline void MutablePriorityQueue::push(T &&item) +template +inline void MutablePriorityQueue::push(T &&item) { size_t idx = m_heap.size(); m_heap.emplace_back(std::move(item)); @@ -78,14 +82,18 @@ inline void MutablePriorityQueue::push(T &&item) update_heap_up(0, idx); } -template -inline void MutablePriorityQueue::pop() +template +inline void MutablePriorityQueue::pop() { assert(! m_heap.empty()); -#ifndef NDEBUG - // Mark as removed from the queue. - m_index_setter(m_heap.front(), std::numeric_limits::max()); +#ifdef NDEBUG + // Only mark as removed from the queue in release mode, if configured so. + if (ResetIndexWhenRemoved) #endif /* NDEBUG */ + { + // Mark as removed from the queue. + m_index_setter(m_heap.front(), std::numeric_limits::max()); + } if (m_heap.size() > 1) { m_heap.front() = m_heap.back(); m_heap.pop_back(); @@ -95,14 +103,18 @@ inline void MutablePriorityQueue::pop() m_heap.clear(); } -template -inline void MutablePriorityQueue::remove(size_t idx) +template +inline void MutablePriorityQueue::remove(size_t idx) { assert(idx < m_heap.size()); -#ifndef NDEBUG - // Mark as removed from the queue. - m_index_setter(m_heap[idx], std::numeric_limits::max()); +#ifdef NDEBUG + // Only mark as removed from the queue in release mode, if configured so. + if (ResetIndexWhenRemoved) #endif /* NDEBUG */ + { + // Mark as removed from the queue. + m_index_setter(m_heap[idx], std::numeric_limits::max()); + } if (idx + 1 == m_heap.size()) { m_heap.pop_back(); return; @@ -114,8 +126,8 @@ inline void MutablePriorityQueue::remove(size_t i update_heap_up(0, idx); } -template -inline void MutablePriorityQueue::update_heap_up(size_t top, size_t bottom) +template +inline void MutablePriorityQueue::update_heap_up(size_t top, size_t bottom) { size_t childIdx = bottom; T *child = &m_heap[childIdx]; @@ -138,8 +150,8 @@ inline void MutablePriorityQueue::update_heap_up( } } -template -inline void MutablePriorityQueue::update_heap_down(size_t top, size_t bottom) +template +inline void MutablePriorityQueue::update_heap_down(size_t top, size_t bottom) { size_t parentIdx = top; T *parent = &m_heap[parentIdx]; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 8724e7891..0d2f65076 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1600,7 +1600,7 @@ void Print::process() // write error into the G-code, cannot execute post-processing scripts). // It is up to the caller to show an error message. #if ENABLE_THUMBNAIL_GENERATOR -std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const std::vector* thumbnail_data) +std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb) #else std::string Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data) #endif // ENABLE_THUMBNAIL_GENERATOR @@ -1621,7 +1621,7 @@ std::string Print::export_gcode(const std::string &path_template, GCodePreviewDa // The following line may die for multiple reasons. GCode gcode; #if ENABLE_THUMBNAIL_GENERATOR - gcode.do_export(this, path.c_str(), preview_data, thumbnail_data); + gcode.do_export(this, path.c_str(), preview_data, thumbnail_cb); #else gcode.do_export(this, path.c_str(), preview_data); #endif // ENABLE_THUMBNAIL_GENERATOR diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index b29bac99b..098049f1d 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -11,6 +11,9 @@ #include "Slicing.hpp" #include "GCode/ToolOrdering.hpp" #include "GCode/WipeTower.hpp" +#if ENABLE_THUMBNAIL_GENERATOR +#include "GCode/ThumbnailData.hpp" +#endif // ENABLE_THUMBNAIL_GENERATOR namespace Slic3r { @@ -19,9 +22,6 @@ class PrintObject; class ModelObject; class GCode; class GCodePreviewData; -#if ENABLE_THUMBNAIL_GENERATOR -struct ThumbnailData; -#endif // ENABLE_THUMBNAIL_GENERATOR // Print step IDs for keeping track of the print state. enum PrintStep { @@ -311,7 +311,7 @@ public: // Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file. // If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r). #if ENABLE_THUMBNAIL_GENERATOR - std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, const std::vector* thumbnail_data = nullptr); + std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb = nullptr); #else std::string export_gcode(const std::string &path_template, GCodePreviewData *preview_data); #endif // ENABLE_THUMBNAIL_GENERATOR diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index c4ca46a8c..bf97baaf6 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1522,9 +1522,9 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c layer_height_profile.clear(); if (layer_height_profile.empty()) { - //layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes); - layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); - updated = true; + //layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes); + layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); + updated = true; } return updated; } diff --git a/src/libslic3r/ShortestPath.cpp b/src/libslic3r/ShortestPath.cpp index b38655e68..9362e6043 100644 --- a/src/libslic3r/ShortestPath.cpp +++ b/src/libslic3r/ShortestPath.cpp @@ -191,7 +191,7 @@ std::vector> chain_segments_greedy_constrained_reversals } // Initialize a heap of end points sorted by the lowest distance to the next valid point of a path. - auto queue = make_mutable_priority_queue( + auto queue = make_mutable_priority_queue( [](EndPoint *ep, size_t idx){ ep->heap_idx = idx; }, [](EndPoint *l, EndPoint *r){ return l->distance_out < r->distance_out; }); queue.reserve(end_points.size() * 2 - 1); @@ -389,6 +389,585 @@ std::vector> chain_segments_greedy_constrained_reversals return out; } +template +void update_end_point_in_queue(QueueType &queue, const KDTreeType &kdtree, ChainsType &chains, std::vector &end_points, EndPointType &end_point, size_t first_point_idx, const EndPointType *first_point) +{ + // Updating an end point or a 2nd from an end point. + size_t this_idx = end_point.index(end_points); + // If this segment is not the starting segment, then this end point or the opposite is unconnected. + assert(first_point_idx == this_idx || first_point_idx == (this_idx ^ 1) || end_point.chain_id == 0 || end_point.opposite(end_points).chain_id == 0); + end_point.edge_candidate = nullptr; + if (first_point_idx == this_idx || (end_point.chain_id > 0 && first_point_idx == (this_idx ^ 1))) + { + // One may never flip the 1st edge, don't try it again. + if (! end_point.heap_idx_invalid()) + queue.remove(end_point.heap_idx); + } + else + { + // Update edge_candidate and distance. + size_t chain1a = end_point.chain_id; + size_t chain1b = end_points[this_idx ^ 1].chain_id; + size_t this_chain = chains.equivalent(std::max(chain1a, chain1b)); + // Find the closest point to this end_point, which lies on a different extrusion path (filtered by the filter lambda). + size_t next_idx = find_closest_point(kdtree, end_point.pos, [&end_points, &chains, this_idx, first_point_idx, first_point, this_chain](size_t idx) { + assert(end_points[this_idx].edge_candidate == nullptr); + // Either this end of the edge or the other end of the edge is not yet connected. + assert((end_points[this_idx ].chain_id == 0 && end_points[this_idx ].edge_out == nullptr) || + (end_points[this_idx ^ 1].chain_id == 0 && end_points[this_idx ^ 1].edge_out == nullptr)); + if ((idx ^ this_idx) <= 1 || idx == first_point_idx) + // Points of the same segment shall not be connected. + // Don't connect to the first point, we must not flip the 1st edge. + return false; + size_t chain2a = end_points[idx].chain_id; + size_t chain2b = end_points[idx ^ 1].chain_id; + if (chain2a > 0 && chain2b > 0) + // Only unconnected end point or a point next to an unconnected end point may be connected to. + // Ideally those would be removed from the KD tree, but the update is difficult. + return false; + assert(chain2a == 0 || chain2b == 0); + size_t chain2 = chains.equivalent(std::max(chain2a, chain2b)); + if (this_chain == chain2) + // Don't connect back to the same chain, don't create a loop. + return this_chain == 0; + // Don't connect to a segment requiring flipping if the segment starts or ends with the first point. + if (chain2a > 0) { + // Chain requires flipping. + assert(chain2b == 0); + auto &chain = chains.chain(chain2); + if (chain.begin == first_point || chain.end == first_point) + return false; + } + // Everything is all right, try to connect. + return true; + }); + assert(next_idx < end_points.size()); + assert(chains.equivalent(end_points[next_idx].chain_id) != chains.equivalent(end_points[next_idx ^ 1].chain_id) || end_points[next_idx].chain_id == 0); + end_point.edge_candidate = &end_points[next_idx]; + end_point.distance_out = (end_points[next_idx].pos - end_point.pos).norm(); + if (end_point.chain_id > 0) + end_point.distance_out += chains.chain_flip_penalty(this_chain); + if (end_points[next_idx].chain_id > 0) + // The candidate chain is flipped. + end_point.distance_out += chains.chain_flip_penalty(end_points[next_idx].chain_id); + // Update position of this end point in the queue based on the distance calculated at the line above. + if (end_point.heap_idx_invalid()) + queue.push(&end_point); + else + queue.update(end_point.heap_idx); + } +} + +template +std::vector> chain_segments_greedy_constrained_reversals2_(SegmentEndPointFunc end_point_func, CouldReverseFunc could_reverse_func, size_t num_segments, const PointType *start_near) +{ + std::vector> out; + + if (num_segments == 0) { + // Nothing to do. + } + else if (num_segments == 1) + { + // Just sort the end points so that the first point visited is closest to start_near. + out.emplace_back(0, start_near != nullptr && + (end_point_func(0, true) - *start_near).template cast().squaredNorm() < (end_point_func(0, false) - *start_near).template cast().squaredNorm()); + } + else + { + // End points of segments for the KD tree closest point search. + // A single end point is inserted into the search structure for loops, two end points are entered for open paths. + struct EndPoint { + EndPoint(const Vec2d &pos) : pos(pos) {} + Vec2d pos; + + // Candidate for a new connection link. + EndPoint *edge_candidate = nullptr; + // Distance to the next end point following the link. + // Zero value -> start of the final path. + double distance_out = std::numeric_limits::max(); + + size_t heap_idx = std::numeric_limits::max(); + bool heap_idx_invalid() const { return this->heap_idx == std::numeric_limits::max(); } + + // Identifier of the chain, to which this end point belongs. Zero means unassigned. + size_t chain_id = 0; + // Double linked chain of segment end points in current path. + EndPoint *edge_out = nullptr; + + size_t index(std::vector &endpoints) const { return this - endpoints.data(); } + // Opposite end point of the same segment. + EndPoint& opposite(std::vector &endpoints) { return endpoints[(this - endpoints.data()) ^ 1]; } + const EndPoint& opposite(const std::vector &endpoints) const { return endpoints[(this - endpoints.data()) ^ 1]; } + }; + + std::vector end_points; + end_points.reserve(num_segments * 2); + for (size_t i = 0; i < num_segments; ++ i) { + end_points.emplace_back(end_point_func(i, true ).template cast()); + end_points.emplace_back(end_point_func(i, false).template cast()); + } + + // Construct the closest point KD tree over end points of segments. + auto coordinate_fn = [&end_points](size_t idx, size_t dimension) -> double { return end_points[idx].pos[dimension]; }; + KDTreeIndirect<2, double, decltype(coordinate_fn)> kdtree(coordinate_fn, end_points.size()); + + // Chained segments with their sum of connection lengths. + // The chain supports flipping all the segments, connecting the segments at the opposite ends. + // (this is a very useful path optimization for infill lines). + struct Chain { + size_t num_segments = 0; + double cost = 0.; + double cost_flipped = 0.; + EndPoint *begin = nullptr; + EndPoint *end = nullptr; + size_t equivalent_with = 0; + + // Flipping the chain has a time complexity of O(n). + void flip(std::vector &endpoints) + { + assert(this->num_segments > 1); + assert(this->begin->edge_out == nullptr); + assert(this->end ->edge_out == nullptr); + assert(this->begin->opposite(endpoints).edge_out != nullptr); + assert(this->end ->opposite(endpoints).edge_out != nullptr); + // Start of the current segment processed. + EndPoint *ept = this->begin; + // Previous end point to connect the other side of ept to. + EndPoint *ept_prev = nullptr; + do { + EndPoint *ept_end = &ept->opposite(endpoints); + EndPoint *ept_next = ept_end->edge_out; + assert(ept_next == nullptr || ept_next->edge_out == ept_end); + // Connect to the preceding segment. + ept_end->edge_out = ept_prev; + if (ept_prev != nullptr) + ept_prev->edge_out = ept_end; + ept_prev = ept; + ept = ept_next; + } while (ept != nullptr); + ept_prev->edge_out = nullptr; + // Swap the costs. + std::swap(this->cost, this->cost_flipped); + // Swap the ends. + EndPoint *new_begin = &this->begin->opposite(endpoints); + EndPoint *new_end = &this->end->opposite(endpoints); + std::swap(this->begin->chain_id, new_begin->chain_id); + std::swap(this->end ->chain_id, new_end ->chain_id); + this->begin = new_begin; + this->end = new_end; + assert(this->begin->edge_out == nullptr); + assert(this->end ->edge_out == nullptr); + assert(this->begin->opposite(endpoints).edge_out != nullptr); + assert(this->end ->opposite(endpoints).edge_out != nullptr); + } + + double flip_penalty() const { return this->cost_flipped - this->cost; } + }; + + // Helper to detect loops in already connected paths and to accomodate flipping of chains. + // + // Unique chain IDs are assigned to paths. If paths are connected, end points will not have their chain IDs updated, but the chain IDs + // will remember an "equivalent" chain ID, which is the lowest ID of all the IDs in the path, and the lowest ID is equivalent to itself. + // Chain IDs are indexed starting with 1. + // + // Chains remember their lengths and their lengths when each segment of the chain is flipped. + class Chains { + public: + // Zero'th chain ID is invalid. + Chains(size_t reserve) { + m_chains.reserve(reserve / 2); + // Indexing starts with 1. + m_chains.emplace_back(); + } + + // Generate next equivalence class. + size_t next_id() { + m_chains.emplace_back(); + m_chains.back().equivalent_with = ++ m_last_chain_id; + return m_last_chain_id; + } + + // Get equivalence class for chain ID, update the "equivalent_with" along the equivalence path. + size_t equivalent(size_t chain_id) { + if (chain_id != 0) { + for (size_t last = chain_id;;) { + size_t lower = m_chains[last].equivalent_with; + if (lower == last) { + m_chains[chain_id].equivalent_with = lower; + chain_id = lower; + break; + } + last = lower; + } + } + return chain_id; + } + + // Return a lowest chain ID of the two input chains. + // Produce a new chain ID of both chain IDs are zero. + size_t merge(size_t chain_id1, size_t chain_id2) { + if (chain_id1 == 0) + return (chain_id2 == 0) ? this->next_id() : chain_id2; + if (chain_id2 == 0) + return chain_id1; + assert(m_chains[chain_id1].equivalent_with == chain_id1); + assert(m_chains[chain_id2].equivalent_with == chain_id2); + size_t chain_id = std::min(chain_id1, chain_id2); + m_chains[chain_id1].equivalent_with = chain_id; + m_chains[chain_id2].equivalent_with = chain_id; + return chain_id; + } + + Chain& chain(size_t chain_id) { return m_chains[chain_id]; } + const Chain& chain(size_t chain_id) const { return m_chains[chain_id]; } + + double chain_flip_penalty(size_t chain_id) { + chain_id = this->equivalent(chain_id); + return m_chains[chain_id].flip_penalty(); + } + +#ifndef NDEBUG + bool validate() + { + // Validate that the segments merged chain IDs make up a directed acyclic graph + // with edges oriented towards the lower chain ID, therefore all ending up + // in the lowest chain ID of all of them. + assert(m_last_chain_id >= 0); + assert(m_last_chain_id + 1 == m_chains.size()); + for (size_t i = 0; i < m_chains.size(); ++ i) { + for (size_t last = i;;) { + size_t lower = m_chains[last].equivalent_with; + assert(lower <= last); + if (lower == last) + break; + last = lower; + } + } + return true; + } +#endif /* NDEBUG */ + + private: + std::vector m_chains; + // Unique chain ID assigned to chains of end points of segments. + size_t m_last_chain_id = 0; + } chains(num_segments); + + // Find the first end point closest to start_near. + EndPoint *first_point = nullptr; + size_t first_point_idx = std::numeric_limits::max(); + if (start_near != nullptr) { + size_t idx = find_closest_point(kdtree, start_near->template cast()); + assert(idx < end_points.size()); + first_point = &end_points[idx]; + first_point->distance_out = 0.; + first_point->chain_id = chains.next_id(); + Chain &chain = chains.chain(first_point->chain_id); + chain.begin = first_point; + chain.end = &first_point->opposite(end_points); + first_point_idx = idx; + } + EndPoint *initial_point = first_point; + EndPoint *last_point = nullptr; + + // Assign the closest point and distance to the end points. + for (EndPoint &end_point : end_points) { + assert(end_point.edge_candidate == nullptr); + if (&end_point != first_point) { + size_t this_idx = end_point.index(end_points); + // Find the closest point to this end_point, which lies on a different extrusion path (filtered by the lambda). + // Ignore the starting point as the starting point is considered to be occupied, no end point coud connect to it. + size_t next_idx = find_closest_point(kdtree, end_point.pos, + [this_idx, first_point_idx](size_t idx){ return idx != first_point_idx && (idx ^ this_idx) > 1; }); + assert(next_idx < end_points.size()); + EndPoint &end_point2 = end_points[next_idx]; + end_point.edge_candidate = &end_point2; + end_point.distance_out = (end_point2.pos - end_point.pos).norm(); + } + } + + // Initialize a heap of end points sorted by the lowest distance to the next valid point of a path. + auto queue = make_mutable_priority_queue( + [](EndPoint *ep, size_t idx){ ep->heap_idx = idx; }, + [](EndPoint *l, EndPoint *r){ return l->distance_out < r->distance_out; }); + queue.reserve(end_points.size() * 2); + for (EndPoint &ep : end_points) + if (first_point != &ep) + queue.push(&ep); + +#ifndef NDEBUG + auto validate_graph_and_queue = [&chains, &end_points, &queue, first_point]() -> bool { + assert(chains.validate()); + for (EndPoint &ep : end_points) { + if (ep.heap_idx < queue.size()) { + // End point is on the heap. + assert(*(queue.cbegin() + ep.heap_idx) == &ep); + // One side or the other of the segment is not yet connected. + assert(ep.chain_id == 0 || ep.opposite(end_points).chain_id == 0); + } else { + // End point is NOT on the heap, therefore it must part of the output path. + assert(ep.heap_idx_invalid()); + assert(ep.chain_id != 0); + if (&ep == first_point) { + assert(ep.edge_out == nullptr); + } else { + assert(ep.edge_out != nullptr); + // Detect loops. + for (EndPoint *pt = &ep; pt != nullptr;) { + // Out of queue. It is a final point. + EndPoint *pt_other = &pt->opposite(end_points); + if (pt_other->heap_idx < queue.size()) { + // The other side of this segment is undecided yet. + // assert(pt_other->edge_out == nullptr); + break; + } + pt = pt_other->edge_out; + } + } + } + } + for (EndPoint *ep : queue) + // Points in the queue or the opposites of the same segment are not connected yet. + assert(ep->chain_id == 0 || ep->opposite(end_points).chain_id == 0); + return true; + }; +#endif /* NDEBUG */ + + // Chain the end points: find (num_segments - 1) shortest links not forming bifurcations or loops. + assert(num_segments >= 2); +#ifndef NDEBUG + double distance_taken_last = 0.; +#endif /* NDEBUG */ + // Some links stored onto the priority queue are being invalidated during the calculation and they are not + // updated immediately. If such a situation is detected for an end point pulled from the priority queue, + // the end point is being updated and re-inserted into the priority queue. Therefore the number of iterations + // required is higher than expected (it would be the number of links, num_segments - 1). + // The limit here may not be necessary, but it guards us against an endless loop if something goes wrong. + size_t num_iter = num_segments * 16; + for (size_t num_connections_to_end = num_segments - 1; num_iter > 0; -- num_iter) { + assert(validate_graph_and_queue()); + // Take the first end point, for which the link points to the currently closest valid neighbor. + EndPoint *end_point1 = queue.top(); + assert(end_point1 != first_point); + EndPoint *end_point1_other = &end_point1->opposite(end_points); + // true if end_point1 is not the end of its chain, but the 2nd point. When connecting to the 2nd point, this chain needs + // to be flipped first. + bool chain1_flip = end_point1->chain_id > 0; + // Either this point at the queue is not connected, or it is the 2nd point of a chain. + // If connecting to a 2nd point of a chain, the 1st point shall not yet be connected and this chain will need + // to be flipped. + assert( chain1_flip || (end_point1->chain_id == 0 && end_point1->edge_out == nullptr)); + assert(! chain1_flip || (end_point1_other->chain_id == 0 && end_point1_other->edge_out == nullptr)); + assert(end_point1->edge_candidate != nullptr); +#ifndef NDEBUG + // Each edge added shall be longer than the previous one taken. + //assert(end_point1->distance_out > distance_taken_last - SCALED_EPSILON); + if (end_point1->distance_out < distance_taken_last - SCALED_EPSILON) { +// printf("Warning: taking shorter length than previously is suspicious\n"); + } + distance_taken_last = end_point1->distance_out; +#endif /* NDEBUG */ + // Take the closest end point to the first end point, + EndPoint *end_point2 = end_point1->edge_candidate; + EndPoint *end_point2_other = &end_point2->opposite(end_points); + bool chain2_flip = end_point2->chain_id > 0; + // Is the link from end_point1 to end_point2 still valid? If yes, the link may be taken. Otherwise the link needs to be refreshed. + bool valid = true; + size_t end_point1_chain_id = 0; + size_t end_point2_chain_id = 0; + if (end_point2->chain_id > 0 && end_point2_other->chain_id > 0) { + // The other side is part of the output path. Don't connect to end_point2, update end_point1 and try another one. + valid = false; + } else { + // End points of the opposite ends of the segments. + end_point1_chain_id = chains.equivalent((chain1_flip ? end_point1 : end_point1_other)->chain_id); + end_point2_chain_id = chains.equivalent((chain2_flip ? end_point2 : end_point2_other)->chain_id); + if (end_point1_chain_id == end_point2_chain_id && end_point1_chain_id != 0) + // This edge forms a loop. Update end_point1 and try another one. + valid = false; + else { + // Verify whether end_point1.distance_out still matches the current state of the two end points to be connected and their chains. + // Namely, the other chain may have been flipped in the meantime. + double dist = (end_point2->pos - end_point1->pos).norm(); + if (chain1_flip) + dist += chains.chain_flip_penalty(end_point1_chain_id); + if (chain2_flip) + dist += chains.chain_flip_penalty(end_point2_chain_id); + if (std::abs(dist - end_point1->distance_out) > SCALED_EPSILON) + // The distance changed due to flipping of one of the chains. Refresh this end point in the queue. + valid = false; + } + if (valid && first_point != nullptr) { + // Verify that a chain starting or ending with the first_point does not get flipped. + if (chain1_flip) { + Chain &chain = chains.chain(end_point1_chain_id); + if (chain.begin == first_point || chain.end == first_point) + valid = false; + } + if (valid && chain2_flip) { + Chain &chain = chains.chain(end_point2_chain_id); + if (chain.begin == first_point || chain.end == first_point) + valid = false; + } + } + } + if (valid) { + // Remove the first and second point from the queue. + queue.pop(); + queue.remove(end_point2->heap_idx); + assert(end_point1->edge_candidate == end_point2); + end_point1->edge_candidate = nullptr; + Chain *chain1 = (end_point1_chain_id == 0) ? nullptr : &chains.chain(end_point1_chain_id); + Chain *chain2 = (end_point2_chain_id == 0) ? nullptr : &chains.chain(end_point2_chain_id); + assert(chain1 == nullptr || (chain1_flip ? (chain1->begin == end_point1_other || chain1->end == end_point1_other) : (chain1->begin == end_point1 || chain1->end == end_point1))); + assert(chain2 == nullptr || (chain2_flip ? (chain2->begin == end_point2_other || chain2->end == end_point2_other) : (chain2->begin == end_point2 || chain2->end == end_point2))); + if (chain1_flip) + chain1->flip(end_points); + if (chain2_flip) + chain2->flip(end_points); + assert(chain1 == nullptr || chain1->begin == end_point1 || chain1->end == end_point1); + assert(chain2 == nullptr || chain2->begin == end_point2 || chain2->end == end_point2); + size_t chain_id = chains.merge(end_point1_chain_id, end_point2_chain_id); + Chain &chain = chains.chain(chain_id); + { + Chain chain_dst; + chain_dst.begin = (chain1 == nullptr) ? end_point1_other : (chain1->begin == end_point1) ? chain1->end : chain1->begin; + chain_dst.end = (chain2 == nullptr) ? end_point2_other : (chain2->begin == end_point2) ? chain2->end : chain2->begin; + chain_dst.cost = (chain1 == 0 ? 0. : chain1->cost) + (chain2 == 0 ? 0. : chain2->cost) + (end_point2->pos - end_point1->pos).norm(); + chain_dst.cost_flipped = (chain1 == 0 ? 0. : chain1->cost_flipped) + (chain2 == 0 ? 0. : chain2->cost_flipped) + (end_point2_other->pos - end_point1_other->pos).norm(); + chain_dst.num_segments = (chain1 == 0 ? 1 : chain1->num_segments) + (chain2 == 0 ? 1 : chain2->num_segments); + chain_dst.equivalent_with = chain_id; + chain = chain_dst; + } + if (chain.begin != end_point1_other && ! end_point1_other->heap_idx_invalid()) + queue.remove(end_point1_other->heap_idx); + if (chain.end != end_point2_other && ! end_point2_other->heap_idx_invalid()) + queue.remove(end_point2_other->heap_idx); + end_point1->edge_out = end_point2; + end_point2->edge_out = end_point1; + end_point1->chain_id = chain_id; + end_point2->chain_id = chain_id; + end_point1_other->chain_id = chain_id; + end_point2_other->chain_id = chain_id; + if (chain.begin != first_point) + chain.begin->chain_id = 0; + if (chain.end != first_point) + chain.end->chain_id = 0; + if (-- num_connections_to_end == 0) { + assert(validate_graph_and_queue()); + // Last iteration. There shall be exactly one or two end points waiting to be connected. + assert(queue.size() <= ((first_point == nullptr) ? 4 : 2)); + if (first_point == nullptr) { + // Find the first remaining end point. + do { + first_point = queue.top(); + queue.pop(); + } while (first_point->edge_out != nullptr); + assert(first_point->edge_out == nullptr); + } + // Find the first remaining end point. + do { + last_point = queue.top(); + queue.pop(); + } while (last_point->edge_out != nullptr); + assert(last_point->edge_out == nullptr); +#ifndef NDEBUG + while (! queue.empty()) { + assert(queue.top()->edge_out != nullptr && queue.top()->chain_id > 0); + queue.pop(); + } +#endif /* NDEBUG */ + break; + } else { + //FIXME update the 2nd end points on the queue. + // Update end points of the flipped segments. + update_end_point_in_queue(queue, kdtree, chains, end_points, chain.begin->opposite(end_points), first_point_idx, first_point); + update_end_point_in_queue(queue, kdtree, chains, end_points, chain.end->opposite(end_points), first_point_idx, first_point); + if (chain1_flip) + update_end_point_in_queue(queue, kdtree, chains, end_points, *chain.begin, first_point_idx, first_point); + if (chain2_flip) + update_end_point_in_queue(queue, kdtree, chains, end_points, *chain.end, first_point_idx, first_point); + // End points of chains shall certainly stay in the queue. + assert(chain.begin == first_point || chain.begin->heap_idx < queue.size()); + assert(chain.end == first_point || chain.end ->heap_idx < queue.size()); + assert(&chain.begin->opposite(end_points) != first_point && + (chain.begin == first_point ? chain.begin->opposite(end_points).heap_idx_invalid() : chain.begin->opposite(end_points).heap_idx < queue.size())); + assert(&chain.end ->opposite(end_points) != first_point && + (chain.end == first_point ? chain.end ->opposite(end_points).heap_idx_invalid() : chain.end ->opposite(end_points).heap_idx < queue.size())); + + } + } else { + // This edge forms a loop. Update end_point1 and try another one. + update_end_point_in_queue(queue, kdtree, chains, end_points, *end_point1, first_point_idx, first_point); +#ifndef NDEBUG + // Each edge shall be longer than the last one removed from the queue. + //assert(end_point1->distance_out > distance_taken_last - SCALED_EPSILON); + if (end_point1->distance_out < distance_taken_last - SCALED_EPSILON) { +// printf("Warning: taking shorter length than previously is suspicious\n"); + } +#endif /* NDEBUG */ + //FIXME Remove the other end point from the KD tree. + // As the KD tree update is expensive, do it only after some larger number of points is removed from the queue. + } + assert(validate_graph_and_queue()); + } + assert(queue.empty()); + + // Now interconnect pairs of segments into a chain. + assert(first_point != nullptr); + out.reserve(num_segments); + bool failed = false; + do { + assert(out.size() < num_segments); + size_t first_point_id = first_point - &end_points.front(); + size_t segment_id = first_point_id >> 1; + bool reverse = (first_point_id & 1) != 0; + EndPoint *second_point = &end_points[first_point_id ^ 1]; + if (REVERSE_COULD_FAIL) { + if (reverse && ! could_reverse_func(segment_id)) { + failed = true; + break; + } + } else { + assert(! reverse || could_reverse_func(segment_id)); + } + out.emplace_back(segment_id, reverse); + first_point = second_point->edge_out; + } while (first_point != nullptr); + if (REVERSE_COULD_FAIL) { + if (failed) { + if (start_near == nullptr) { + // We may try the reverse order. + out.clear(); + first_point = last_point; + failed = false; + do { + assert(out.size() < num_segments); + size_t first_point_id = first_point - &end_points.front(); + size_t segment_id = first_point_id >> 1; + bool reverse = (first_point_id & 1) != 0; + EndPoint *second_point = &end_points[first_point_id ^ 1]; + if (reverse && ! could_reverse_func(segment_id)) { + failed = true; + break; + } + out.emplace_back(segment_id, reverse); + first_point = second_point->edge_out; + } while (first_point != nullptr); + } + } + if (failed) + // As a last resort, try a dumb algorithm, which is not sensitive to edge reversal constraints. + out = chain_segments_closest_point(end_points, kdtree, could_reverse_func, (initial_point != nullptr) ? *initial_point : end_points.front()); + } else { + assert(! failed); + } + } + + assert(out.size() == num_segments); + return out; +} + template std::vector> chain_segments_greedy_constrained_reversals(SegmentEndPointFunc end_point_func, CouldReverseFunc could_reverse_func, size_t num_segments, const PointType *start_near) { @@ -402,6 +981,19 @@ std::vector> chain_segments_greedy(SegmentEndPointFunc e return chain_segments_greedy_constrained_reversals_(end_point_func, could_reverse_func, num_segments, start_near); } +template +std::vector> chain_segments_greedy_constrained_reversals2(SegmentEndPointFunc end_point_func, CouldReverseFunc could_reverse_func, size_t num_segments, const PointType *start_near) +{ + return chain_segments_greedy_constrained_reversals2_(end_point_func, could_reverse_func, num_segments, start_near); +} + +template +std::vector> chain_segments_greedy2(SegmentEndPointFunc end_point_func, size_t num_segments, const PointType *start_near) +{ + auto could_reverse_func = [](size_t /* idx */) -> bool { return true; }; + return chain_segments_greedy_constrained_reversals2_(end_point_func, could_reverse_func, num_segments, start_near); +} + std::vector> chain_extrusion_entities(std::vector &entities, const Point *start_near) { auto segment_end_point = [&entities](size_t idx, bool first_point) -> const Point& { return first_point ? entities[idx]->first_point() : entities[idx]->last_point(); }; @@ -472,8 +1064,22 @@ std::vector chain_points(const Points &points, Point *start_near) return out; } +#ifndef NDEBUG +// #define DEBUG_SVG_OUTPUT +#endif /* NDEBUG */ + +#ifdef DEBUG_SVG_OUTPUT +void svg_draw_polyline_chain(const char *name, size_t idx, const Polylines &polylines) +{ + BoundingBox bbox = get_extents(polylines); + SVG svg(debug_out_path("%s-%d.svg", name, idx).c_str(), bbox); + svg.draw(polylines); + for (size_t i = 1; i < polylines.size(); ++i) + svg.draw(Line(polylines[i - 1].last_point(), polylines[i].first_point()), "red"); +} +#endif /* DEBUG_SVG_OUTPUT */ + // Flip the sequences of polylines to lower the total length of connecting lines. -// #define DEBUG_SVG_OUTPUT static inline void improve_ordering_by_segment_flipping(Polylines &polylines, bool fixed_start) { #ifndef NDEBUG @@ -487,14 +1093,8 @@ static inline void improve_ordering_by_segment_flipping(Polylines &polylines, bo static int iRun = 0; ++ iRun; - BoundingBox bbox = get_extents(polylines); #ifdef DEBUG_SVG_OUTPUT - { - SVG svg(debug_out_path("improve_ordering_by_segment_flipping-initial-%d.svg", iRun).c_str(), bbox); - svg.draw(polylines); - for (size_t i = 1; i < polylines.size(); ++ i) - svg.draw(Line(polylines[i - 1].last_point(), polylines[i].first_point()), "red"); - } + svg_draw_polyline_chain("improve_ordering_by_segment_flipping-initial", iRun, polylines); #endif /* DEBUG_SVG_OUTPUT */ #endif /* NDEBUG */ @@ -550,7 +1150,7 @@ static inline void improve_ordering_by_segment_flipping(Polylines &polylines, bo #endif /* NDEBUG */ // Initialize a MutablePriorityHeap of connections between polylines. - auto queue = make_mutable_priority_queue( + auto queue = make_mutable_priority_queue( [](Connection *connection, size_t idx){ connection->heap_idx = idx; }, // Sort by decreasing connection distance. [&polylines, &connections](Connection *l, Connection *r){ return l->squaredNorm(polylines, connections) > r->squaredNorm(polylines, connections); }); @@ -643,34 +1243,522 @@ static inline void improve_ordering_by_segment_flipping(Polylines &polylines, bo #ifndef NDEBUG double cost_final = cost(); #ifdef DEBUG_SVG_OUTPUT + svg_draw_polyline_chain("improve_ordering_by_segment_flipping-final", iRun, polylines); +#endif /* DEBUG_SVG_OUTPUT */ + assert(cost_final <= cost_prev); + assert(cost_final <= cost_initial); +#endif /* NDEBUG */ +} + +struct FlipEdge { + FlipEdge(const Vec2d &p1, const Vec2d &p2, size_t source_index) : p1(p1), p2(p2), source_index(source_index) {} + void flip() { std::swap(this->p1, this->p2); } + Vec2d p1; + Vec2d p2; + size_t source_index; +}; + +struct ConnectionCost { + ConnectionCost(double cost, double cost_flipped) : cost(cost), cost_flipped(cost_flipped) {} + ConnectionCost() : cost(0.), cost_flipped(0.) {} + void flip() { std::swap(this->cost, this->cost_flipped); } + double cost = 0; + double cost_flipped = 0; +}; +static inline ConnectionCost operator-(const ConnectionCost &lhs, const ConnectionCost& rhs) { return ConnectionCost(lhs.cost - rhs.cost, lhs.cost_flipped - rhs.cost_flipped); } + +static inline std::pair minimum_crossover_cost( + const std::vector &edges, + const std::pair &span1, const ConnectionCost &cost1, + const std::pair &span2, const ConnectionCost &cost2, + const std::pair &span3, const ConnectionCost &cost3, + const double cost_current) +{ + auto connection_cost = [&edges]( + const std::pair &span1, const ConnectionCost &cost1, bool reversed1, bool flipped1, + const std::pair &span2, const ConnectionCost &cost2, bool reversed2, bool flipped2, + const std::pair &span3, const ConnectionCost &cost3, bool reversed3, bool flipped3) { + auto first_point = [&edges](const std::pair &span, bool flipped) { return flipped ? edges[span.first].p2 : edges[span.first].p1; }; + auto last_point = [&edges](const std::pair &span, bool flipped) { return flipped ? edges[span.second - 1].p1 : edges[span.second - 1].p2; }; + auto point = [first_point, last_point](const std::pair &span, bool start, bool flipped) { return start ? first_point(span, flipped) : last_point(span, flipped); }; + auto cost = [](const ConnectionCost &acost, bool flipped) { + assert(acost.cost >= 0. && acost.cost_flipped >= 0.); + return flipped ? acost.cost_flipped : acost.cost; + }; + // Ignore reversed single segment spans. + auto simple_span_ignore = [](const std::pair& span, bool reversed) { + return span.first + 1 == span.second && reversed; + }; + assert(span1.first < span1.second); + assert(span2.first < span2.second); + assert(span3.first < span3.second); + return + simple_span_ignore(span1, reversed1) || simple_span_ignore(span2, reversed2) || simple_span_ignore(span3, reversed3) ? + // Don't perform unnecessary calculations simulating reversion of single segment spans. + std::numeric_limits::max() : + // Calculate the cost of reverting chains and / or flipping segment orientations. + cost(cost1, flipped1) + cost(cost2, flipped2) + cost(cost3, flipped3) + + (point(span2, ! reversed2, flipped2) - point(span1, reversed1, flipped1)).norm() + + (point(span3, ! reversed3, flipped3) - point(span2, reversed2, flipped2)).norm(); + }; + +#ifndef NDEBUG { - SVG svg(debug_out_path("improve_ordering_by_segment_flipping-final-%d.svg", iRun).c_str(), bbox); - svg.draw(polylines); - for (size_t i = 1; i < polylines.size(); ++ i) - svg.draw(Line(polylines[i - 1].last_point(), polylines[i].first_point()), "red"); + double c = connection_cost(span1, cost1, false, false, span2, cost2, false, false, span3, cost3, false, false); + assert(std::abs(c - cost_current) < SCALED_EPSILON); } +#endif /* NDEBUG */ + + double cost_min = cost_current; + size_t flip_min = 0; // no flip, no improvement + for (size_t i = 0; i < (1 << 6); ++ i) { + // From the three combinations of 1,2,3 ordering, the other three are reversals of the first three. + double c1 = (i == 0) ? cost_current : + connection_cost(span1, cost1, (i & 1) != 0, (i & (1 << 1)) != 0, span2, cost2, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span3, cost3, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0); + double c2 = connection_cost(span1, cost1, (i & 1) != 0, (i & (1 << 1)) != 0, span3, cost3, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span2, cost2, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0); + double c3 = connection_cost(span2, cost2, (i & 1) != 0, (i & (1 << 1)) != 0, span1, cost1, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span3, cost3, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0); + if (c1 < cost_min) { + cost_min = c1; + flip_min = i; + } + if (c2 < cost_min) { + cost_min = c2; + flip_min = i + (1 << 6); + } + if (c3 < cost_min) { + cost_min = c3; + flip_min = i + (2 << 6); + } + } + return std::make_pair(cost_min, flip_min); +} + +static inline std::pair minimum_crossover_cost( + const std::vector &edges, + const std::pair &span1, const ConnectionCost &cost1, + const std::pair &span2, const ConnectionCost &cost2, + const std::pair &span3, const ConnectionCost &cost3, + const std::pair &span4, const ConnectionCost &cost4, + const double cost_current) +{ + auto connection_cost = [&edges]( + const std::pair &span1, const ConnectionCost &cost1, bool reversed1, bool flipped1, + const std::pair &span2, const ConnectionCost &cost2, bool reversed2, bool flipped2, + const std::pair &span3, const ConnectionCost &cost3, bool reversed3, bool flipped3, + const std::pair &span4, const ConnectionCost &cost4, bool reversed4, bool flipped4) { + auto first_point = [&edges](const std::pair &span, bool flipped) { return flipped ? edges[span.first].p2 : edges[span.first].p1; }; + auto last_point = [&edges](const std::pair &span, bool flipped) { return flipped ? edges[span.second - 1].p1 : edges[span.second - 1].p2; }; + auto point = [first_point, last_point](const std::pair &span, bool start, bool flipped) { return start ? first_point(span, flipped) : last_point(span, flipped); }; + auto cost = [](const ConnectionCost &acost, bool flipped) { + assert(acost.cost >= 0. && acost.cost_flipped >= 0.); + return flipped ? acost.cost_flipped : acost.cost; + }; + // Ignore reversed single segment spans. + auto simple_span_ignore = [](const std::pair& span, bool reversed) { + return span.first + 1 == span.second && reversed; + }; + assert(span1.first < span1.second); + assert(span2.first < span2.second); + assert(span3.first < span3.second); + assert(span4.first < span4.second); + return + simple_span_ignore(span1, reversed1) || simple_span_ignore(span2, reversed2) || simple_span_ignore(span3, reversed3) || simple_span_ignore(span4, reversed4) ? + // Don't perform unnecessary calculations simulating reversion of single segment spans. + std::numeric_limits::max() : + // Calculate the cost of reverting chains and / or flipping segment orientations. + cost(cost1, flipped1) + cost(cost2, flipped2) + cost(cost3, flipped3) + cost(cost4, flipped4) + + (point(span2, ! reversed2, flipped2) - point(span1, reversed1, flipped1)).norm() + + (point(span3, ! reversed3, flipped3) - point(span2, reversed2, flipped2)).norm() + + (point(span4, ! reversed4, flipped4) - point(span3, reversed3, flipped3)).norm(); + }; + +#ifndef NDEBUG + { + double c = connection_cost(span1, cost1, false, false, span2, cost2, false, false, span3, cost3, false, false, span4, cost4, false, false); + assert(std::abs(c - cost_current) < SCALED_EPSILON); + } +#endif /* NDEBUG */ + + double cost_min = cost_current; + size_t flip_min = 0; // no flip, no improvement + for (size_t i = 0; i < (1 << 8); ++ i) { + // From the three combinations of 1,2,3 ordering, the other three are reversals of the first three. + size_t permutation = 0; + for (double c : { + (i == 0) ? cost_current : + connection_cost(span1, cost1, (i & 1) != 0, (i & (1 << 1)) != 0, span2, cost2, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span3, cost3, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span4, cost4, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0), + connection_cost(span1, cost1, (i & 1) != 0, (i & (1 << 1)) != 0, span2, cost2, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span4, cost4, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span3, cost3, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0), + connection_cost(span1, cost1, (i & 1) != 0, (i & (1 << 1)) != 0, span3, cost3, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span2, cost2, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span4, cost4, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0), + connection_cost(span1, cost1, (i & 1) != 0, (i & (1 << 1)) != 0, span3, cost3, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span4, cost4, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span2, cost2, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0), + connection_cost(span1, cost1, (i & 1) != 0, (i & (1 << 1)) != 0, span4, cost4, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span2, cost2, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span3, cost3, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0), + connection_cost(span1, cost1, (i & 1) != 0, (i & (1 << 1)) != 0, span4, cost4, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span3, cost3, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span2, cost2, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0), + connection_cost(span2, cost2, (i & 1) != 0, (i & (1 << 1)) != 0, span1, cost1, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span3, cost3, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span4, cost4, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0), + connection_cost(span2, cost2, (i & 1) != 0, (i & (1 << 1)) != 0, span1, cost1, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span4, cost4, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span3, cost3, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0), + connection_cost(span2, cost2, (i & 1) != 0, (i & (1 << 1)) != 0, span3, cost3, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span1, cost1, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span4, cost4, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0), + connection_cost(span2, cost2, (i & 1) != 0, (i & (1 << 1)) != 0, span4, cost4, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span1, cost1, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span3, cost3, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0), + connection_cost(span3, cost3, (i & 1) != 0, (i & (1 << 1)) != 0, span1, cost1, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span2, cost2, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span4, cost4, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0), + connection_cost(span3, cost3, (i & 1) != 0, (i & (1 << 1)) != 0, span2, cost2, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span1, cost1, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span4, cost4, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0) + }) { + if (c < cost_min) { + cost_min = c; + flip_min = i + (permutation << 8); + } + ++ permutation; + } + } + return std::make_pair(cost_min, flip_min); +} + +static inline void do_crossover(const std::vector &edges_in, std::vector &edges_out, + const std::pair &span1, const std::pair &span2, const std::pair &span3, + size_t i) +{ + assert(edges_in.size() == edges_out.size()); + auto do_it = [&edges_in, &edges_out]( + const std::pair &span1, bool reversed1, bool flipped1, + const std::pair &span2, bool reversed2, bool flipped2, + const std::pair &span3, bool reversed3, bool flipped3) { + auto it_edges_out = edges_out.begin(); + auto copy_span = [&edges_in, &edges_out, &it_edges_out](std::pair span, bool reversed, bool flipped) { + assert(span.first < span.second); + auto it = it_edges_out; + if (reversed) + std::reverse_copy(edges_in.begin() + span.first, edges_in.begin() + span.second, it_edges_out); + else + std::copy (edges_in.begin() + span.first, edges_in.begin() + span.second, it_edges_out); + it_edges_out += span.second - span.first; + if (reversed != flipped) { + for (; it != it_edges_out; ++ it) + it->flip(); + } + }; + copy_span(span1, reversed1, flipped1); + copy_span(span2, reversed2, flipped2); + copy_span(span3, reversed3, flipped3); + }; + switch (i >> 6) { + case 0: + do_it(span1, (i & 1) != 0, (i & (1 << 1)) != 0, span2, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span3, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0); + break; + case 1: + do_it(span1, (i & 1) != 0, (i & (1 << 1)) != 0, span3, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span2, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0); + break; + default: + assert((i >> 6) == 2); + do_it(span2, (i & 1) != 0, (i & (1 << 1)) != 0, span1, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span3, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0); + } + assert(edges_in.size() == edges_out.size()); +} + + +static inline void do_crossover(const std::vector &edges_in, std::vector &edges_out, + const std::pair &span1, const std::pair &span2, const std::pair &span3, const std::pair &span4, + size_t i) +{ + assert(edges_in.size() == edges_out.size()); + auto do_it = [&edges_in, &edges_out]( + const std::pair &span1, bool reversed1, bool flipped1, + const std::pair &span2, bool reversed2, bool flipped2, + const std::pair &span3, bool reversed3, bool flipped3, + const std::pair &span4, bool reversed4, bool flipped4) { + auto it_edges_out = edges_out.begin(); + auto copy_span = [&edges_in, &edges_out, &it_edges_out](std::pair span, bool reversed, bool flipped) { + assert(span.first < span.second); + auto it = it_edges_out; + if (reversed) + std::reverse_copy(edges_in.begin() + span.first, edges_in.begin() + span.second, it_edges_out); + else + std::copy (edges_in.begin() + span.first, edges_in.begin() + span.second, it_edges_out); + it_edges_out += span.second - span.first; + if (reversed != flipped) { + for (; it != it_edges_out; ++ it) + it->flip(); + } + }; + copy_span(span1, reversed1, flipped1); + copy_span(span2, reversed2, flipped2); + copy_span(span3, reversed3, flipped3); + copy_span(span4, reversed4, flipped4); + }; + switch (i >> 8) { + case 0: + assert(i != 0); // otherwise it would be a no-op + do_it(span1, (i & 1) != 0, (i & (1 << 1)) != 0, span2, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span3, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span4, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0); + break; + case 1: + do_it(span1, (i & 1) != 0, (i & (1 << 1)) != 0, span2, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span4, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span3, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0); + break; + case 2: + do_it(span1, (i & 1) != 0, (i & (1 << 1)) != 0, span3, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span2, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span4, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0); + break; + case 3: + do_it(span1, (i & 1) != 0, (i & (1 << 1)) != 0, span3, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span4, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span2, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0); + break; + case 4: + do_it(span1, (i & 1) != 0, (i & (1 << 1)) != 0, span4, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span2, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span3, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0); + break; + case 5: + do_it(span1, (i & 1) != 0, (i & (1 << 1)) != 0, span4, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span3, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span2, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0); + break; + case 6: + do_it(span2, (i & 1) != 0, (i & (1 << 1)) != 0, span1, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span3, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span4, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0); + break; + case 7: + do_it(span2, (i & 1) != 0, (i & (1 << 1)) != 0, span1, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span4, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span3, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0); + break; + case 8: + do_it(span2, (i & 1) != 0, (i & (1 << 1)) != 0, span3, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span1, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span4, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0); + break; + case 9: + do_it(span2, (i & 1) != 0, (i & (1 << 1)) != 0, span4, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span1, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span3, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0); + break; + case 10: + do_it(span3, (i & 1) != 0, (i & (1 << 1)) != 0, span1, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span2, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span4, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0); + break; + default: + assert((i >> 8) == 11); + do_it(span3, (i & 1) != 0, (i & (1 << 1)) != 0, span2, (i & (1 << 2)) != 0, (i & (1 << 3)) != 0, span1, (i & (1 << 4)) != 0, (i & (1 << 5)) != 0, span4, (i & (1 << 6)) != 0, (i & (1 << 7)) != 0); + break; + } + assert(edges_in.size() == edges_out.size()); +} + +static inline void reorder_by_two_exchanges_with_segment_flipping(std::vector &edges) +{ + if (edges.size() < 2) + return; + + std::vector connections(edges.size()); + std::vector edges_tmp(edges); + std::vector> connection_lengths(edges.size() - 1, std::pair(0., 0)); + std::vector connection_tried(edges.size(), false); + for (size_t iter = 0; iter < edges.size(); ++ iter) { + // Initialize connection costs and connection lengths. + for (size_t i = 1; i < edges.size(); ++ i) { + const FlipEdge &e1 = edges[i - 1]; + const FlipEdge &e2 = edges[i]; + ConnectionCost &c = connections[i]; + c = connections[i - 1]; + double l = (e2.p1 - e1.p2).norm(); + c.cost += l; + c.cost_flipped += (e2.p2 - e1.p1).norm(); + connection_lengths[i - 1] = std::make_pair(l, i); + } + std::sort(connection_lengths.begin(), connection_lengths.end(), [](const std::pair &l, const std::pair &r) { return l.first > r.first; }); + std::fill(connection_tried.begin(), connection_tried.end(), false); + size_t crossover1_pos_final = std::numeric_limits::max(); + size_t crossover2_pos_final = std::numeric_limits::max(); + size_t crossover_flip_final = 0; + for (const std::pair &first_crossover_candidate : connection_lengths) { + double longest_connection_length = first_crossover_candidate.first; + size_t longest_connection_idx = first_crossover_candidate.second; + connection_tried[longest_connection_idx] = true; + // Find the second crossover connection with the lowest total chain cost. + size_t crossover_pos_min = std::numeric_limits::max(); + double crossover_cost_min = connections.back().cost; + size_t crossover_flip_min = 0; + for (size_t j = 1; j < connections.size(); ++ j) + if (! connection_tried[j]) { + size_t a = j; + size_t b = longest_connection_idx; + if (a > b) + std::swap(a, b); + std::pair cost_and_flip = minimum_crossover_cost(edges, + std::make_pair(size_t(0), a), connections[a - 1], std::make_pair(a, b), connections[b - 1] - connections[a], std::make_pair(b, edges.size()), connections.back() - connections[b], + connections.back().cost); + if (cost_and_flip.second > 0 && cost_and_flip.first < crossover_cost_min) { + crossover_pos_min = j; + crossover_cost_min = cost_and_flip.first; + crossover_flip_min = cost_and_flip.second; + assert(crossover_cost_min < connections.back().cost + EPSILON); + } + } + if (crossover_cost_min < connections.back().cost) { + // The cost of the chain with the proposed two crossovers has a lower total cost than the current chain. Apply the crossover. + crossover1_pos_final = longest_connection_idx; + crossover2_pos_final = crossover_pos_min; + crossover_flip_final = crossover_flip_min; + break; + } else { + // Continue with another long candidate edge. + } + } + if (crossover_flip_final > 0) { + // Pair of cross over positions and flip / reverse constellation has been found, which improves the total cost of the connection. + // Perform a crossover. + if (crossover1_pos_final > crossover2_pos_final) + std::swap(crossover1_pos_final, crossover2_pos_final); + do_crossover(edges, edges_tmp, std::make_pair(size_t(0), crossover1_pos_final), std::make_pair(crossover1_pos_final, crossover2_pos_final), std::make_pair(crossover2_pos_final, edges.size()), crossover_flip_final); + edges.swap(edges_tmp); + } else { + // No valid pair of cross over positions was found improving the total cost. Giving up. + break; + } + } +} + + +static inline void reorder_by_three_exchanges_with_segment_flipping(std::vector &edges) +{ + if (edges.size() < 3) { + reorder_by_two_exchanges_with_segment_flipping(edges); + return; + } + + std::vector connections(edges.size()); + std::vector edges_tmp(edges); + std::vector> connection_lengths(edges.size() - 1, std::pair(0., 0)); + std::vector connection_tried(edges.size(), false); + for (size_t iter = 0; iter < edges.size(); ++ iter) { + // Initialize connection costs and connection lengths. + for (size_t i = 1; i < edges.size(); ++ i) { + const FlipEdge &e1 = edges[i - 1]; + const FlipEdge &e2 = edges[i]; + ConnectionCost &c = connections[i]; + c = connections[i - 1]; + double l = (e2.p1 - e1.p2).norm(); + c.cost += l; + c.cost_flipped += (e2.p2 - e1.p1).norm(); + connection_lengths[i - 1] = std::make_pair(l, i); + } + std::sort(connection_lengths.begin(), connection_lengths.end(), [](const std::pair &l, const std::pair &r) { return l.first > r.first; }); + std::fill(connection_tried.begin(), connection_tried.end(), false); + size_t crossover1_pos_final = std::numeric_limits::max(); + size_t crossover2_pos_final = std::numeric_limits::max(); + size_t crossover3_pos_final = std::numeric_limits::max(); + size_t crossover_flip_final = 0; + for (const std::pair &first_crossover_candidate : connection_lengths) { + double longest_connection_length = first_crossover_candidate.first; + size_t longest_connection_idx = first_crossover_candidate.second; + connection_tried[longest_connection_idx] = true; + // Find the second crossover connection with the lowest total chain cost. + size_t crossover_pos_min = std::numeric_limits::max(); + double crossover_cost_min = connections.back().cost; + for (size_t j = 1; j < connections.size(); ++ j) + if (! connection_tried[j]) { + for (size_t k = j + 1; k < connections.size(); ++ k) + if (! connection_tried[k]) { + size_t a = longest_connection_idx; + size_t b = j; + size_t c = k; + if (a > c) + std::swap(a, c); + if (a > b) + std::swap(a, b); + if (b > c) + std::swap(b, c); + std::pair cost_and_flip = minimum_crossover_cost(edges, + std::make_pair(size_t(0), a), connections[a - 1], std::make_pair(a, b), connections[b - 1] - connections[a], + std::make_pair(b, c), connections[c - 1] - connections[b], std::make_pair(c, edges.size()), connections.back() - connections[c], + connections.back().cost); + if (cost_and_flip.second > 0 && cost_and_flip.first < crossover_cost_min) { + crossover_cost_min = cost_and_flip.first; + crossover1_pos_final = a; + crossover2_pos_final = b; + crossover3_pos_final = c; + crossover_flip_final = cost_and_flip.second; + assert(crossover_cost_min < connections.back().cost + EPSILON); + } + } + } + if (crossover_flip_final > 0) { + // The cost of the chain with the proposed two crossovers has a lower total cost than the current chain. Apply the crossover. + break; + } else { + // Continue with another long candidate edge. + } + } + if (crossover_flip_final > 0) { + // Pair of cross over positions and flip / reverse constellation has been found, which improves the total cost of the connection. + // Perform a crossover. + do_crossover(edges, edges_tmp, std::make_pair(size_t(0), crossover1_pos_final), std::make_pair(crossover1_pos_final, crossover2_pos_final), + std::make_pair(crossover2_pos_final, crossover3_pos_final), std::make_pair(crossover3_pos_final, edges.size()), crossover_flip_final); + edges.swap(edges_tmp); + } else { + // No valid pair of cross over positions was found improving the total cost. Giving up. + break; + } + } +} + +// Flip the sequences of polylines to lower the total length of connecting lines. +static inline void improve_ordering_by_two_exchanges_with_segment_flipping(Polylines &polylines, bool fixed_start) +{ +#ifndef NDEBUG + auto cost = [&polylines]() { + double sum = 0.; + for (size_t i = 1; i < polylines.size(); ++i) + sum += (polylines[i].first_point() - polylines[i - 1].last_point()).cast().norm(); + return sum; + }; + double cost_initial = cost(); + + static int iRun = 0; + ++ iRun; +#ifdef DEBUG_SVG_OUTPUT + svg_draw_polyline_chain("improve_ordering_by_two_exchanges_with_segment_flipping-initial", iRun, polylines); #endif /* DEBUG_SVG_OUTPUT */ #endif /* NDEBUG */ - assert(cost_final <= cost_prev); + std::vector edges; + edges.reserve(polylines.size()); + std::transform(polylines.begin(), polylines.end(), std::back_inserter(edges), + [&polylines](const Polyline &pl){ return FlipEdge(pl.first_point().cast(), pl.last_point().cast(), &pl - polylines.data()); }); +#if 1 + reorder_by_two_exchanges_with_segment_flipping(edges); +#else + reorder_by_three_exchanges_with_segment_flipping(edges); +#endif + Polylines out; + out.reserve(polylines.size()); + for (const FlipEdge &edge : edges) { + Polyline &pl = polylines[edge.source_index]; + out.emplace_back(std::move(pl)); + if (edge.p2 == pl.first_point().cast()) { + // Polyline is flipped. + out.back().reverse(); + } else { + // Polyline is not flipped. + assert(edge.p1 == pl.first_point().cast()); + } + } + +#ifndef NDEBUG + double cost_final = cost(); +#ifdef DEBUG_SVG_OUTPUT + svg_draw_polyline_chain("improve_ordering_by_two_exchanges_with_segment_flipping-final", iRun, out); +#endif /* DEBUG_SVG_OUTPUT */ assert(cost_final <= cost_initial); +#endif /* NDEBUG */ } Polylines chain_polylines(Polylines &&polylines, const Point *start_near) { +#ifdef DEBUG_SVG_OUTPUT + static int iRun = 0; + ++ iRun; + svg_draw_polyline_chain("chain_polylines-initial", iRun, polylines); +#endif /* DEBUG_SVG_OUTPUT */ + Polylines out; if (! polylines.empty()) { auto segment_end_point = [&polylines](size_t idx, bool first_point) -> const Point& { return first_point ? polylines[idx].first_point() : polylines[idx].last_point(); }; - std::vector> ordered = chain_segments_greedy(segment_end_point, polylines.size(), start_near); + std::vector> ordered = chain_segments_greedy2(segment_end_point, polylines.size(), start_near); out.reserve(polylines.size()); for (auto &segment_and_reversal : ordered) { out.emplace_back(std::move(polylines[segment_and_reversal.first])); if (segment_and_reversal.second) out.back().reverse(); } - if (out.size() > 1) - improve_ordering_by_segment_flipping(out, start_near != nullptr); + if (out.size() > 1 && start_near == nullptr) { + improve_ordering_by_two_exchanges_with_segment_flipping(out, start_near != nullptr); + //improve_ordering_by_segment_flipping(out, start_near != nullptr); + } } + +#ifdef DEBUG_SVG_OUTPUT + svg_draw_polyline_chain("chain_polylines-final", iRun, out); +#endif /* DEBUG_SVG_OUTPUT */ return out; } diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index c62736ffe..9af6048ab 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -224,40 +224,59 @@ std::vector layer_height_profile_from_ranges( // Based on the work of @platsch // Fill layer_height_profile by heights ensuring a prescribed maximum cusp height. +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE +std::vector layer_height_profile_adaptive(const SlicingParameters& slicing_params, + const ModelObject& object, float cusp_value) +#else std::vector layer_height_profile_adaptive( const SlicingParameters &slicing_params, const t_layer_config_ranges & /* layer_config_ranges */, const ModelVolumePtrs &volumes) +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE { +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // 1) Initialize the SlicingAdaptive class with the object meshes. SlicingAdaptive as; as.set_slicing_parameters(slicing_params); - for (const ModelVolume *volume : volumes) + as.set_object(object); +#else + // 1) Initialize the SlicingAdaptive class with the object meshes. + SlicingAdaptive as; + as.set_slicing_parameters(slicing_params); + for (const ModelVolume* volume : volumes) if (volume->is_model_part()) as.add_mesh(&volume->mesh()); +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + as.prepare(); // 2) Generate layers using the algorithm of @platsch // loop until we have at least one layer and the max slice_z reaches the object height - //FIXME make it configurable - // Cusp value: A maximum allowed distance from a corner of a rectangular extrusion to a chrodal line, in mm. - const coordf_t cusp_value = 0.2; // $self->config->get_value('cusp_value'); +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + double cusp_value = 0.2; +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - std::vector layer_height_profile; - layer_height_profile.push_back(0.); + std::vector layer_height_profile; + layer_height_profile.push_back(0.0); layer_height_profile.push_back(slicing_params.first_object_layer_height); if (slicing_params.first_object_layer_height_fixed()) { layer_height_profile.push_back(slicing_params.first_object_layer_height); layer_height_profile.push_back(slicing_params.first_object_layer_height); } - coordf_t slice_z = slicing_params.first_object_layer_height; - coordf_t height = slicing_params.first_object_layer_height; + double slice_z = slicing_params.first_object_layer_height; int current_facet = 0; +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + while (slice_z <= slicing_params.object_print_z_height()) { + double height = slicing_params.max_layer_height; +#else + double height = slicing_params.first_object_layer_height; while ((slice_z - height) <= slicing_params.object_print_z_height()) { - height = 999; + height = 999.0; +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // Slic3r::debugf "\n Slice layer: %d\n", $id; // determine next layer height - coordf_t cusp_height = as.cusp_height(slice_z, cusp_value, current_facet); + double cusp_height = as.cusp_height((float)slice_z, cusp_value, current_facet); + // check for horizontal features and object size /* if($self->config->get_value('match_horizontal_surfaces')) { @@ -303,19 +322,113 @@ std::vector layer_height_profile_adaptive( layer_height_profile.push_back(slice_z); layer_height_profile.push_back(height); slice_z += height; +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE layer_height_profile.push_back(slice_z); layer_height_profile.push_back(height); +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE } - coordf_t last = std::max(slicing_params.first_object_layer_height, layer_height_profile[layer_height_profile.size() - 2]); +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + double z_gap = slicing_params.object_print_z_height() - layer_height_profile[layer_height_profile.size() - 2]; + if (z_gap > 0.0) + { + layer_height_profile.push_back(slicing_params.object_print_z_height()); + layer_height_profile.push_back(clamp(slicing_params.min_layer_height, slicing_params.max_layer_height, z_gap)); + } +#else + double last = std::max(slicing_params.first_object_layer_height, layer_height_profile[layer_height_profile.size() - 2]); layer_height_profile.push_back(last); layer_height_profile.push_back(slicing_params.first_object_layer_height); layer_height_profile.push_back(slicing_params.object_print_z_height()); layer_height_profile.push_back(slicing_params.first_object_layer_height); +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE return layer_height_profile; } +std::vector smooth_height_profile(const std::vector& profile, const SlicingParameters& slicing_params, const HeightProfileSmoothingParams& smoothing_params) +{ + auto gauss_blur = [&slicing_params](const std::vector& profile, const HeightProfileSmoothingParams& smoothing_params) -> std::vector { + auto gauss_kernel = [] (unsigned int radius) -> std::vector { + unsigned int size = 2 * radius + 1; + std::vector ret; + ret.reserve(size); + + // Reworked from static inline int getGaussianKernelSize(float sigma) taken from opencv-4.1.2\modules\features2d\src\kaze\AKAZEFeatures.cpp + double sigma = 0.3 * (double)(radius - 1) + 0.8; + double two_sq_sigma = 2.0 * sigma * sigma; + double inv_root_two_pi_sq_sigma = 1.0 / ::sqrt(M_PI * two_sq_sigma); + + for (unsigned int i = 0; i < size; ++i) + { + double x = (double)i - (double)radius; + ret.push_back(inv_root_two_pi_sq_sigma * ::exp(-x * x / two_sq_sigma)); + } + + return ret; + }; + + // skip first layer ? + size_t skip_count = slicing_params.first_object_layer_height_fixed() ? 4 : 0; + + // not enough data to smmoth + if ((int)profile.size() - (int)skip_count < 6) + return profile; + + unsigned int radius = std::max(smoothing_params.radius, (unsigned int)1); + std::vector kernel = gauss_kernel(radius); + int two_radius = 2 * (int)radius; + + std::vector ret; + size_t size = profile.size(); + ret.reserve(size); + + // leave first layer untouched + for (size_t i = 0; i < skip_count; ++i) + { + ret.push_back(profile[i]); + } + + // smooth the rest of the profile by biasing a gaussian blur + // the bias moves the smoothed profile closer to the min_layer_height + double delta_h = slicing_params.max_layer_height - slicing_params.min_layer_height; + double inv_delta_h = (delta_h != 0.0) ? 1.0 / delta_h : 1.0; + + double max_dz_band = (double)radius * slicing_params.layer_height; + for (size_t i = skip_count; i < size; i += 2) + { + double zi = profile[i]; + double hi = profile[i + 1]; + ret.push_back(zi); + ret.push_back(0.0); + double& height = ret.back(); + int begin = std::max((int)i - two_radius, (int)skip_count); + int end = std::min((int)i + two_radius, (int)size - 2); + double weight_total = 0.0; + for (int j = begin; j <= end; j += 2) + { + int kernel_id = radius + (j - (int)i) / 2; + double dz = std::abs(zi - profile[j]); + if (dz * slicing_params.layer_height <= max_dz_band) + { + double dh = std::abs(slicing_params.max_layer_height - profile[j + 1]); + double weight = kernel[kernel_id] * sqrt(dh * inv_delta_h); + height += weight * profile[j + 1]; + weight_total += weight; + } + } + + height = clamp(slicing_params.min_layer_height, slicing_params.max_layer_height, (weight_total != 0.0) ? height /= weight_total : hi); + if (smoothing_params.keep_min) + height = std::min(height, hi); + } + + return ret; + }; + + return gauss_blur(profile, smoothing_params); +} + void adjust_layer_height_profile( const SlicingParameters &slicing_params, std::vector &layer_height_profile, @@ -609,7 +722,11 @@ int generate_layer_height_texture( const Vec3crd &color1 = palette_raw[idx1]; const Vec3crd &color2 = palette_raw[idx2]; coordf_t z = cell_to_z * coordf_t(cell); - assert(z >= lo && z <= hi); +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + assert((lo - EPSILON <= z) && (z <= hi + EPSILON)); +#else + assert(z >= lo && z <= hi); +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // Intensity profile to visualize the layers. coordf_t intensity = cos(M_PI * 0.7 * (mid - z) / h); // Color mapping from layer height to RGB. diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp index 064363ec2..03ef7e67d 100644 --- a/src/libslic3r/Slicing.hpp +++ b/src/libslic3r/Slicing.hpp @@ -18,8 +18,12 @@ namespace Slic3r class PrintConfig; class PrintObjectConfig; +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE +class ModelObject; +#else class ModelVolume; typedef std::vector ModelVolumePtrs; +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // Parameters to guide object slicing and support generation. // The slicing parameters account for a raft and whether the 1st object layer is printed with a normal or a bridging flow @@ -138,11 +142,29 @@ extern std::vector layer_height_profile_from_ranges( const SlicingParameters &slicing_params, const t_layer_config_ranges &layer_config_ranges); +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE +extern std::vector layer_height_profile_adaptive( + const SlicingParameters& slicing_params, + const ModelObject& object, float cusp_value); + +struct HeightProfileSmoothingParams +{ + unsigned int radius; + bool keep_min; + + HeightProfileSmoothingParams() : radius(5), keep_min(false) {} + HeightProfileSmoothingParams(unsigned int radius, bool keep_min) : radius(radius), keep_min(keep_min) {} +}; + +extern std::vector smooth_height_profile( + const std::vector& profile, const SlicingParameters& slicing_params, + const HeightProfileSmoothingParams& smoothing_params); +#else extern std::vector layer_height_profile_adaptive( const SlicingParameters &slicing_params, const t_layer_config_ranges &layer_config_ranges, const ModelVolumePtrs &volumes); - +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE enum LayerHeightEditActionType : unsigned int { LAYER_HEIGHT_EDIT_ACTION_INCREASE = 0, diff --git a/src/libslic3r/SlicingAdaptive.cpp b/src/libslic3r/SlicingAdaptive.cpp index ad03b550b..6776d8d71 100644 --- a/src/libslic3r/SlicingAdaptive.cpp +++ b/src/libslic3r/SlicingAdaptive.cpp @@ -1,16 +1,22 @@ #include "libslic3r.h" +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE +#include "Model.hpp" +#else #include "TriangleMesh.hpp" +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE #include "SlicingAdaptive.hpp" namespace Slic3r { +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE void SlicingAdaptive::clear() { - m_meshes.clear(); + m_meshes.clear(); m_faces.clear(); m_face_normal_z.clear(); } +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE std::pair face_z_span(const stl_facet *f) { @@ -21,21 +27,42 @@ std::pair face_z_span(const stl_facet *f) void SlicingAdaptive::prepare() { - // 1) Collect faces of all meshes. - int nfaces_total = 0; - for (std::vector::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh) +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + if (m_object == nullptr) + return; + + m_faces.clear(); + m_face_normal_z.clear(); + + m_mesh = m_object->raw_mesh(); + const ModelInstance* first_instance = m_object->instances.front(); + m_mesh.transform(first_instance->get_matrix(), first_instance->is_left_handed()); + for (stl_facet& facet : m_mesh.stl.facet_start) + { + facet.normal.normalize(); + } + + // 1) Collect faces from mesh. + m_faces.reserve(m_mesh.stl.stats.number_of_facets); + for (const stl_facet& face : m_mesh.stl.facet_start) + m_faces.emplace_back(&face); +#else + // 1) Collect faces of all meshes. + int nfaces_total = 0; + for (std::vector::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh) nfaces_total += (*it_mesh)->stl.stats.number_of_facets; - m_faces.reserve(nfaces_total); - for (std::vector::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh) - for (const stl_facet &face : (*it_mesh)->stl.facet_start) - m_faces.emplace_back(&face); + m_faces.reserve(nfaces_total); + for (std::vector::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh) + for (const stl_facet& face : (*it_mesh)->stl.facet_start) + m_faces.emplace_back(&face); +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // 2) Sort faces lexicographically by their Z span. std::sort(m_faces.begin(), m_faces.end(), [](const stl_facet *f1, const stl_facet *f2) { - std::pair span1 = face_z_span(f1); + std::pair span1 = face_z_span(f1); std::pair span2 = face_z_span(f2); - return span1 < span2; - }); + return span1 < span2; + }); // 3) Generate Z components of the facet normals. m_face_normal_z.assign(m_faces.size(), 0.f); @@ -45,14 +72,14 @@ void SlicingAdaptive::prepare() float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet) { - float height = m_slicing_params.max_layer_height; + float height = (float)m_slicing_params.max_layer_height; bool first_hit = false; // find all facets intersecting the slice-layer int ordered_id = current_facet; for (; ordered_id < int(m_faces.size()); ++ ordered_id) { - std::pair zspan = face_z_span(m_faces[ordered_id]); - // facet's minimum is higher than slice_z -> end loop + std::pair zspan = face_z_span(m_faces[ordered_id]); + // facet's minimum is higher than slice_z -> end loop if (zspan.first >= z) break; // facet's maximum is higher than slice_z -> store the first event for next cusp_height call to begin at this point @@ -67,8 +94,8 @@ float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet continue; // compute cusp-height for this facet and store minimum of all heights float normal_z = m_face_normal_z[ordered_id]; - height = std::min(height, (normal_z == 0.f) ? 9999.f : std::abs(cusp_value / normal_z)); - } + height = std::min(height, (normal_z == 0.0f) ? (float)m_slicing_params.max_layer_height : std::abs(cusp_value / normal_z)); + } } // lower height limit due to printer capabilities @@ -77,8 +104,8 @@ float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet // check for sloped facets inside the determined layer and correct height if necessary if (height > m_slicing_params.min_layer_height) { for (; ordered_id < int(m_faces.size()); ++ ordered_id) { - std::pair zspan = face_z_span(m_faces[ordered_id]); - // facet's minimum is higher than slice_z + height -> end loop + std::pair zspan = face_z_span(m_faces[ordered_id]); + // facet's minimum is higher than slice_z + height -> end loop if (zspan.first >= z + height) break; @@ -88,13 +115,13 @@ float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet // Compute cusp-height for this facet and check against height. float normal_z = m_face_normal_z[ordered_id]; - float cusp = (normal_z == 0) ? 9999 : abs(cusp_value / normal_z); - + float cusp = (normal_z == 0.0f) ? (float)m_slicing_params.max_layer_height : abs(cusp_value / normal_z); + float z_diff = zspan.first - z; // handle horizontal facets - if (m_face_normal_z[ordered_id] > 0.999) { - // Slic3r::debugf "cusp computation, height is reduced from %f", $height; + if (normal_z > 0.999f) { + // Slic3r::debugf "cusp computation, height is reduced from %f", $height; height = z_diff; // Slic3r::debugf "to %f due to near horizontal facet\n", $height; } else if (cusp > z_diff) { @@ -112,29 +139,30 @@ float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet // lower height limit due to printer capabilities again height = std::max(height, float(m_slicing_params.min_layer_height)); } - + // Slic3r::debugf "cusp computation, layer-bottom at z:%f, cusp_value:%f, resulting layer height:%f\n", unscale $z, $cusp_value, $height; return height; } +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // Returns the distance to the next horizontal facet in Z-dir // to consider horizontal object features in slice thickness float SlicingAdaptive::horizontal_facet_distance(float z) { for (size_t i = 0; i < m_faces.size(); ++ i) { - std::pair zspan = face_z_span(m_faces[i]); - // facet's minimum is higher than max forward distance -> end loop + std::pair zspan = face_z_span(m_faces[i]); + // facet's minimum is higher than max forward distance -> end loop if (zspan.first > z + m_slicing_params.max_layer_height) break; // min_z == max_z -> horizontal facet - if (zspan.first > z && zspan.first == zspan.second) + if ((zspan.first > z) && (zspan.first == zspan.second)) return zspan.first - z; } // objects maximum? - return (z + m_slicing_params.max_layer_height > m_slicing_params.object_print_z_height()) ? - std::max(m_slicing_params.object_print_z_height() - z, 0.f) : - m_slicing_params.max_layer_height; + return (z + (float)m_slicing_params.max_layer_height > (float)m_slicing_params.object_print_z_height()) ? + std::max((float)m_slicing_params.object_print_z_height() - z, 0.f) : (float)m_slicing_params.max_layer_height; } +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE }; // namespace Slic3r diff --git a/src/libslic3r/SlicingAdaptive.hpp b/src/libslic3r/SlicingAdaptive.hpp index bfd081d81..1d2996986 100644 --- a/src/libslic3r/SlicingAdaptive.hpp +++ b/src/libslic3r/SlicingAdaptive.hpp @@ -5,29 +5,49 @@ #include "Slicing.hpp" #include "admesh/stl.h" +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE +#include "TriangleMesh.hpp" +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE namespace Slic3r { +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE +class ModelVolume; +#else class TriangleMesh; +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE class SlicingAdaptive { public: - void clear(); - void set_slicing_parameters(SlicingParameters params) { m_slicing_params = params; } - void add_mesh(const TriangleMesh *mesh) { m_meshes.push_back(mesh); } - void prepare(); +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + void clear(); +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + void set_slicing_parameters(SlicingParameters params) { m_slicing_params = params; } +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + void set_object(const ModelObject& object) { m_object = &object; } +#else + void add_mesh(const TriangleMesh* mesh) { m_meshes.push_back(mesh); } +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + void prepare(); float cusp_height(float z, float cusp_value, int ¤t_facet); - float horizontal_facet_distance(float z); +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + float horizontal_facet_distance(float z); +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE protected: SlicingParameters m_slicing_params; - std::vector m_meshes; - // Collected faces of all meshes, sorted by raising Z of the bottom most face. +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + const ModelObject* m_object; + TriangleMesh m_mesh; +#else + std::vector m_meshes; +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + // Collected faces of all meshes, sorted by raising Z of the bottom most face. std::vector m_faces; - // Z component of face normals, normalized. + // Z component of face normals, normalized. std::vector m_face_normal_z; }; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 5d0a7592c..7a6a682b1 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -40,6 +40,8 @@ // Enable thumbnail generator #define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1) #define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR) -#define ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE (1 && ENABLE_THUMBNAIL_GENERATOR) + +// Enable adaptive layer height profile +#define ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE (1 && ENABLE_2_2_0_ALPHA1) #endif // _technologies_h_ diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index f8d9291ff..7f06cac29 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -138,6 +138,8 @@ set(SLIC3R_GUI_SOURCES GUI/ProgressStatusBar.cpp GUI/PrintHostDialogs.cpp GUI/PrintHostDialogs.hpp + GUI/Mouse3DController.cpp + GUI/Mouse3DController.hpp Utils/Http.cpp Utils/Http.hpp Utils/FixModelByWin10.cpp @@ -172,7 +174,7 @@ add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES}) encoding_check(libslic3r_gui) -target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui ${GLEW_LIBRARIES}) +target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui ${GLEW_LIBRARIES} hidapi) if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY) add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE) endif () diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 6b3f54f3a..60f4edf47 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -271,6 +271,80 @@ void AppConfig::set_recent_projects(const std::vector& recent_proje } } +void AppConfig::set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone) +{ + std::string key = std::string("mouse_device:") + name; + auto it = m_storage.find(key); + if (it == m_storage.end()) + it = m_storage.insert(std::map>::value_type(key, std::map())).first; + + it->second.clear(); + it->second["translation_speed"] = std::to_string(translation_speed); + it->second["translation_deadzone"] = std::to_string(translation_deadzone); + it->second["rotation_speed"] = std::to_string(rotation_speed); + it->second["rotation_deadzone"] = std::to_string(rotation_deadzone); +} + +bool AppConfig::get_mouse_device_translation_speed(const std::string& name, double& speed) +{ + std::string key = std::string("mouse_device:") + name; + auto it = m_storage.find(key); + if (it == m_storage.end()) + return false; + + auto it_val = it->second.find("translation_speed"); + if (it_val == it->second.end()) + return false; + + speed = ::atof(it_val->second.c_str()); + return true; +} + +bool AppConfig::get_mouse_device_translation_deadzone(const std::string& name, double& deadzone) +{ + std::string key = std::string("mouse_device:") + name; + auto it = m_storage.find(key); + if (it == m_storage.end()) + return false; + + auto it_val = it->second.find("translation_deadzone"); + if (it_val == it->second.end()) + return false; + + deadzone = ::atof(it_val->second.c_str()); + return true; +} + +bool AppConfig::get_mouse_device_rotation_speed(const std::string& name, float& speed) +{ + std::string key = std::string("mouse_device:") + name; + auto it = m_storage.find(key); + if (it == m_storage.end()) + return false; + + auto it_val = it->second.find("rotation_speed"); + if (it_val == it->second.end()) + return false; + + speed = (float)::atof(it_val->second.c_str()); + return true; +} + +bool AppConfig::get_mouse_device_rotation_deadzone(const std::string& name, float& deadzone) +{ + std::string key = std::string("mouse_device:") + name; + auto it = m_storage.find(key); + if (it == m_storage.end()) + return false; + + auto it_val = it->second.find("rotation_deadzone"); + if (it_val == it->second.end()) + return false; + + deadzone = (float)::atof(it_val->second.c_str()); + return true; +} + void AppConfig::update_config_dir(const std::string &dir) { this->set("recent", "config_directory", dir); diff --git a/src/slic3r/GUI/AppConfig.hpp b/src/slic3r/GUI/AppConfig.hpp index 97c369ab6..355370450 100644 --- a/src/slic3r/GUI/AppConfig.hpp +++ b/src/slic3r/GUI/AppConfig.hpp @@ -131,8 +131,15 @@ public: std::vector get_recent_projects() const; void set_recent_projects(const std::vector& recent_projects); + void set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone); + bool get_mouse_device_translation_speed(const std::string& name, double& speed); + bool get_mouse_device_translation_deadzone(const std::string& name, double& deadzone); + bool get_mouse_device_rotation_speed(const std::string& name, float& speed); + bool get_mouse_device_rotation_deadzone(const std::string& name, float& deadzone); + static const std::string SECTION_FILAMENTS; static const std::string SECTION_MATERIALS; + private: // Map of section, name -> value std::map> m_storage; diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 474886863..9108fd196 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -20,9 +20,6 @@ #include "libslic3r/Utils.hpp" #include "libslic3r/GCode/PostProcessor.hpp" #include "libslic3r/GCode/PreviewData.hpp" -#if ENABLE_THUMBNAIL_GENERATOR -#include "libslic3r/GCode/ThumbnailData.hpp" -#endif // ENABLE_THUMBNAIL_GENERATOR #include "libslic3r/libslic3r.h" #include @@ -92,7 +89,7 @@ void BackgroundSlicingProcess::process_fff() m_print->process(); wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_slicing_completed_id)); #if ENABLE_THUMBNAIL_GENERATOR - m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_thumbnail_data); + m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_thumbnail_cb); #else m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data); #endif // ENABLE_THUMBNAIL_GENERATOR @@ -148,9 +145,12 @@ void BackgroundSlicingProcess::process_sla() m_sla_print->export_raster(zipper); #if ENABLE_THUMBNAIL_GENERATOR - if (m_thumbnail_data != nullptr) + if (m_thumbnail_cb != nullptr) { - for (const ThumbnailData& data : *m_thumbnail_data) + ThumbnailsList thumbnails; + m_thumbnail_cb(thumbnails, current_print()->full_print_config().option("thumbnails")->values, true, true, true); +// m_thumbnail_cb(thumbnails, current_print()->full_print_config().option("thumbnails")->values, true, false, true); // renders also supports and pad + for (const ThumbnailData& data : thumbnails) { if (data.is_valid()) write_thumbnail(zipper, data); @@ -470,9 +470,12 @@ void BackgroundSlicingProcess::prepare_upload() Zipper zipper{source_path.string()}; m_sla_print->export_raster(zipper, m_upload_job.upload_data.upload_path.string()); #if ENABLE_THUMBNAIL_GENERATOR - if (m_thumbnail_data != nullptr) + if (m_thumbnail_cb != nullptr) { - for (const ThumbnailData& data : *m_thumbnail_data) + ThumbnailsList thumbnails; + m_thumbnail_cb(thumbnails, current_print()->full_print_config().option("thumbnails")->values, true, true, true); +// m_thumbnail_cb(thumbnails, current_print()->full_print_config().option("thumbnails")->values, true, false, true); // renders also supports and pad + for (const ThumbnailData& data : thumbnails) { if (data.is_valid()) write_thumbnail(zipper, data); diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index 03dc0a1af..a66dcf39c 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -17,9 +17,6 @@ namespace Slic3r { class DynamicPrintConfig; class GCodePreviewData; -#if ENABLE_THUMBNAIL_GENERATOR -struct ThumbnailData; -#endif // ENABLE_THUMBNAIL_GENERATOR class Model; class SLAPrint; @@ -53,7 +50,7 @@ public: void set_sla_print(SLAPrint *print) { m_sla_print = print; } void set_gcode_preview_data(GCodePreviewData *gpd) { m_gcode_preview_data = gpd; } #if ENABLE_THUMBNAIL_GENERATOR - void set_thumbnail_data(const std::vector* data) { m_thumbnail_data = data; } + void set_thumbnail_cb(ThumbnailsGeneratorCallback cb) { m_thumbnail_cb = cb; } #endif // ENABLE_THUMBNAIL_GENERATOR // The following wxCommandEvent will be sent to the UI thread / Platter window, when the slicing is finished @@ -164,8 +161,8 @@ private: // Data structure, to which the G-code export writes its annotations. GCodePreviewData *m_gcode_preview_data = nullptr; #if ENABLE_THUMBNAIL_GENERATOR - // Data structures, used to write thumbnails into gcode. - const std::vector* m_thumbnail_data = nullptr; + // Callback function, used to write thumbnails into gcode. + ThumbnailsGeneratorCallback m_thumbnail_cb = nullptr; #endif // ENABLE_THUMBNAIL_GENERATOR // Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID. std::string m_temp_output_path; diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 9fbabe930..6ccb5af49 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -91,10 +91,16 @@ void Camera::select_next_type() void Camera::set_target(const Vec3d& target) { - m_target = target; - m_target(0) = clamp(m_scene_box.min(0), m_scene_box.max(0), m_target(0)); - m_target(1) = clamp(m_scene_box.min(1), m_scene_box.max(1), m_target(1)); - m_target(2) = clamp(m_scene_box.min(2), m_scene_box.max(2), m_target(2)); + BoundingBoxf3 test_box = m_scene_box; + test_box.translate(-m_scene_box.center()); + // We may let this factor be customizable + static const double ScaleFactor = 1.5; + test_box.scale(ScaleFactor); + test_box.translate(m_scene_box.center()); + + m_target(0) = clamp(test_box.min(0), test_box.max(0), target(0)); + m_target(1) = clamp(test_box.min(1), test_box.max(1), target(1)); + m_target(2) = clamp(test_box.min(2), test_box.max(2), target(2)); } void Camera::set_theta(float theta, bool apply_limit) @@ -109,20 +115,20 @@ void Camera::set_theta(float theta, bool apply_limit) } } -void Camera::set_zoom(double zoom, const BoundingBoxf3& max_box, int canvas_w, int canvas_h) +void Camera::update_zoom(double delta_zoom) { - zoom = std::max(std::min(zoom, 4.0), -4.0) / 10.0; - zoom = m_zoom / (1.0 - zoom); + set_zoom(m_zoom / (1.0 - std::max(std::min(delta_zoom, 4.0), -4.0) * 0.1)); +} +void Camera::set_zoom(double zoom) +{ // Don't allow to zoom too far outside the scene. - double zoom_min = calc_zoom_to_bounding_box_factor(max_box, canvas_w, canvas_h); + double zoom_min = calc_zoom_to_bounding_box_factor(m_scene_box, (int)m_viewport[2], (int)m_viewport[3]); if (zoom_min > 0.0) zoom = std::max(zoom, zoom_min * 0.7); // Don't allow to zoom too close to the scene. - zoom = std::min(zoom, 100.0); - - m_zoom = zoom; + m_zoom = std::min(zoom, 100.0); } bool Camera::select_view(const std::string& direction) diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index cb634138f..0674409aa 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -70,8 +70,8 @@ public: void set_theta(float theta, bool apply_limit); double get_zoom() const { return m_zoom; } - void set_zoom(double zoom, const BoundingBoxf3& max_box, int canvas_w, int canvas_h); - void set_zoom(double zoom) { m_zoom = zoom; } + void update_zoom(double delta_zoom); + void set_zoom(double zoom); const BoundingBoxf3& get_scene_box() const { return m_scene_box; } void set_scene_box(const BoundingBoxf3& box) { m_scene_box = box; } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 909907e81..475a81ad8 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -22,9 +22,11 @@ #include "slic3r/GUI/PresetBundle.hpp" #include "slic3r/GUI/Tab.hpp" #include "slic3r/GUI/GUI_Preview.hpp" + #include "GUI_App.hpp" #include "GUI_ObjectList.hpp" #include "GUI_ObjectManipulation.hpp" +#include "Mouse3DController.hpp" #include "I18N.hpp" #if ENABLE_RETINA_GL @@ -130,6 +132,9 @@ GLCanvas3D::LayersEditing::LayersEditing() , m_object_max_z(0.f) , m_slicing_parameters(nullptr) , m_layer_height_profile_modified(false) +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + , m_adaptive_cusp(0.2f) +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE , state(Unknown) , band_width(2.0f) , strength(0.005f) @@ -150,7 +155,9 @@ GLCanvas3D::LayersEditing::~LayersEditing() } const float GLCanvas3D::LayersEditing::THICKNESS_BAR_WIDTH = 70.0f; +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE const float GLCanvas3D::LayersEditing::THICKNESS_RESET_BUTTON_HEIGHT = 22.0f; +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE bool GLCanvas3D::LayersEditing::init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename) { @@ -217,13 +224,103 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const if (!m_enabled) return; +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + static const ImVec4 orange(0.757f, 0.404f, 0.216f, 1.0f); + + const Size& cnv_size = canvas.get_canvas_size(); + float canvas_w = (float)cnv_size.get_width(); + float canvas_h = (float)cnv_size.get_height(); + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + imgui.set_next_window_pos(canvas_w - imgui.get_style_scaling() * THICKNESS_BAR_WIDTH, canvas_h, ImGuiCond_Always, 1.0f, 1.0f); + imgui.set_next_window_bg_alpha(0.5f); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + + imgui.begin(_(L("Layer height profile")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse); + + ImGui::PushStyleColor(ImGuiCol_Text, orange); + imgui.text(_(L("Left mouse button:"))); + ImGui::PopStyleColor(); + ImGui::SameLine(); + imgui.text(_(L("Add detail"))); + + ImGui::PushStyleColor(ImGuiCol_Text, orange); + imgui.text(_(L("Right mouse button:"))); + ImGui::PopStyleColor(); + ImGui::SameLine(); + imgui.text(_(L("Remove detail"))); + + ImGui::PushStyleColor(ImGuiCol_Text, orange); + imgui.text(_(L("Shift + Left mouse button:"))); + ImGui::PopStyleColor(); + ImGui::SameLine(); + imgui.text(_(L("Reset to base"))); + + ImGui::PushStyleColor(ImGuiCol_Text, orange); + imgui.text(_(L("Shift + Right mouse button:"))); + ImGui::PopStyleColor(); + ImGui::SameLine(); + imgui.text(_(L("Smoothing"))); + + ImGui::PushStyleColor(ImGuiCol_Text, orange); + imgui.text(_(L("Mouse wheel:"))); + ImGui::PopStyleColor(); + ImGui::SameLine(); + imgui.text(_(L("Increase/decrease edit area"))); + + ImGui::Separator(); + if (imgui.button(_(L("Adaptive")))) + wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), Event(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, m_adaptive_cusp)); + + ImGui::SameLine(); + float text_align = ImGui::GetCursorPosX(); + imgui.text(_(L("Cusp (mm)"))); + ImGui::SameLine(); + float widget_align = ImGui::GetCursorPosX(); + ImGui::PushItemWidth(imgui.get_style_scaling() * 120.0f); + m_adaptive_cusp = clamp((float)m_slicing_parameters->min_layer_height, (float)m_slicing_parameters->max_layer_height, m_adaptive_cusp); + ImGui::SliderFloat("", &m_adaptive_cusp, (float)m_slicing_parameters->min_layer_height, (float)m_slicing_parameters->max_layer_height, "%.2f"); + + ImGui::Separator(); + if (imgui.button(_(L("Smooth")))) + wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), HeightProfileSmoothEvent(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, m_smooth_params )); + + ImGui::SameLine(); + ImGui::SetCursorPosX(text_align); + imgui.text(_(L("Radius"))); + ImGui::SameLine(); + ImGui::SetCursorPosX(widget_align); + ImGui::PushItemWidth(imgui.get_style_scaling() * 120.0f); + int radius = (int)m_smooth_params.radius; + if (ImGui::SliderInt("##1", &radius, 1, 10)) + m_smooth_params.radius = (unsigned int)radius; + + ImGui::SetCursorPosX(text_align); + imgui.text(_(L("Keep min"))); + ImGui::SameLine(); + ImGui::SetCursorPosX(widget_align); + ImGui::PushItemWidth(imgui.get_style_scaling() * 120.0f); + imgui.checkbox("##2", m_smooth_params.keep_min); + + ImGui::Separator(); + if (imgui.button(_(L("Reset")))) + wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), SimpleEvent(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE)); + + imgui.end(); + + ImGui::PopStyleVar(); + + const Rect& bar_rect = get_bar_rect_viewport(canvas); +#else const Rect& bar_rect = get_bar_rect_viewport(canvas); const Rect& reset_rect = get_reset_rect_viewport(canvas); _render_tooltip_texture(canvas, bar_rect, reset_rect); _render_reset_texture(reset_rect); - _render_active_object_annotations(canvas, bar_rect); - _render_profile(bar_rect); +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + render_active_object_annotations(canvas, bar_rect); + render_profile(bar_rect); } float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas) @@ -248,11 +345,13 @@ bool GLCanvas3D::LayersEditing::bar_rect_contains(const GLCanvas3D& canvas, floa return (rect.get_left() <= x) && (x <= rect.get_right()) && (rect.get_top() <= y) && (y <= rect.get_bottom()); } +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE bool GLCanvas3D::LayersEditing::reset_rect_contains(const GLCanvas3D& canvas, float x, float y) { const Rect& rect = get_reset_rect_screen(canvas); return (rect.get_left() <= x) && (x <= rect.get_right()) && (rect.get_top() <= y) && (y <= rect.get_bottom()); } +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas) { @@ -260,9 +359,14 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas) float w = (float)cnv_size.get_width(); float h = (float)cnv_size.get_height(); +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + return Rect(w - thickness_bar_width(canvas), 0.0f, w, h); +#else return Rect(w - thickness_bar_width(canvas), 0.0f, w, h - reset_button_height(canvas)); +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE } +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE Rect GLCanvas3D::LayersEditing::get_reset_rect_screen(const GLCanvas3D& canvas) { const Size& cnv_size = canvas.get_canvas_size(); @@ -271,6 +375,7 @@ Rect GLCanvas3D::LayersEditing::get_reset_rect_screen(const GLCanvas3D& canvas) return Rect(w - thickness_bar_width(canvas), h - reset_button_height(canvas), w, h); } +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas) { @@ -281,9 +386,14 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas) float zoom = (float)canvas.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom); +#else return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom); +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE } +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE Rect GLCanvas3D::LayersEditing::get_reset_rect_viewport(const GLCanvas3D& canvas) { const Size& cnv_size = canvas.get_canvas_size(); @@ -295,13 +405,43 @@ Rect GLCanvas3D::LayersEditing::get_reset_rect_viewport(const GLCanvas3D& canvas return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom); } +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE - -bool GLCanvas3D::LayersEditing::_is_initialized() const +bool GLCanvas3D::LayersEditing::is_initialized() const { return m_shader.is_initialized(); } +std::string GLCanvas3D::LayersEditing::get_tooltip(const GLCanvas3D& canvas) const +{ + std::string ret; + if (m_enabled && (m_layer_height_profile.size() >= 4)) + { + float z = get_cursor_z_relative(canvas); + if (z != -1000.0f) + { + z *= m_object_max_z; + + float h = 0.0f; + for (size_t i = m_layer_height_profile.size() - 2; i >= 2; i -= 2) + { + float zi = m_layer_height_profile[i]; + float zi_1 = m_layer_height_profile[i - 2]; + if ((zi_1 <= z) && (z <= zi)) + { + float dz = zi - zi_1; + h = (dz != 0.0f) ? lerp(m_layer_height_profile[i - 1], m_layer_height_profile[i + 1], (z - zi_1) / dz) : m_layer_height_profile[i + 1]; + break; + } + } + if (h > 0.0f) + ret = std::to_string(h); + } + } + return ret; +} + +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE void GLCanvas3D::LayersEditing::_render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const { // TODO: do this with ImGui @@ -347,8 +487,9 @@ void GLCanvas3D::LayersEditing::_render_reset_texture(const Rect& reset_rect) co GLTexture::render_texture(m_reset_texture.get_id(), reset_rect.get_left(), reset_rect.get_right(), reset_rect.get_bottom(), reset_rect.get_top()); } +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE -void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const +void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const { m_shader.start_using(); @@ -379,7 +520,7 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas m_shader.stop_using(); } -void GLCanvas3D::LayersEditing::_render_profile(const Rect& bar_rect) const +void GLCanvas3D::LayersEditing::render_profile(const Rect& bar_rect) const { //FIXME show some kind of legend. @@ -496,6 +637,24 @@ void GLCanvas3D::LayersEditing::reset_layer_height_profile(GLCanvas3D& canvas) canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE +void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float cusp) +{ + m_layer_height_profile = layer_height_profile_adaptive(*m_slicing_parameters, *m_model_object, cusp); + const_cast(m_model_object)->layer_height_profile = m_layer_height_profile; + m_layers_texture.valid = false; + canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); +} + +void GLCanvas3D::LayersEditing::smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_params) +{ + m_layer_height_profile = smooth_height_profile(m_layer_height_profile, *m_slicing_parameters, smoothing_params); + const_cast(m_model_object)->layer_height_profile = m_layer_height_profile; + m_layers_texture.valid = false; + canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); +} +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + void GLCanvas3D::LayersEditing::generate_layer_height_texture() { this->update_slicing_parameters(); @@ -530,7 +689,7 @@ void GLCanvas3D::LayersEditing::accept_changes(GLCanvas3D& canvas) { if (last_object_id >= 0) { if (m_layer_height_profile_modified) { - wxGetApp().plater()->take_snapshot(_(L("Layers heights"))); + wxGetApp().plater()->take_snapshot(_(L("Layer height profile-Manual edit"))); const_cast(m_model_object)->layer_height_profile = m_layer_height_profile; canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } @@ -557,6 +716,7 @@ float GLCanvas3D::LayersEditing::thickness_bar_width(const GLCanvas3D &canvas) * THICKNESS_BAR_WIDTH; } +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE float GLCanvas3D::LayersEditing::reset_button_height(const GLCanvas3D &canvas) { return @@ -567,6 +727,7 @@ float GLCanvas3D::LayersEditing::reset_button_height(const GLCanvas3D &canvas) #endif * THICKNESS_RESET_BUTTON_HEIGHT; } +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE const Point GLCanvas3D::Mouse::Drag::Invalid_2D_Point(INT_MAX, INT_MAX); @@ -1196,6 +1357,11 @@ wxDEFINE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent); wxDEFINE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent); wxDEFINE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent); +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE +wxDEFINE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent); +wxDEFINE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event); +wxDEFINE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent); +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE #if ENABLE_THUMBNAIL_GENERATOR const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25; @@ -1450,7 +1616,7 @@ void GLCanvas3D::set_model(Model* model) void GLCanvas3D::bed_shape_changed() { - m_camera.set_scene_box(scene_bounding_box()); + refresh_camera_scene_box(); m_camera.requires_zoom_to_bed = true; m_dirty = true; if (m_bed.is_prusa()) @@ -1476,7 +1642,7 @@ BoundingBoxf3 GLCanvas3D::volumes_bounding_box() const BoundingBoxf3 GLCanvas3D::scene_bounding_box() const { BoundingBoxf3 bb = volumes_bounding_box(); - bb.merge(m_bed.get_bounding_box(false)); + bb.merge(m_bed.get_bounding_box(true)); if (m_config != nullptr) { @@ -1498,6 +1664,32 @@ bool GLCanvas3D::is_layers_editing_allowed() const return m_layers_editing.is_allowed(); } +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE +void GLCanvas3D::reset_layer_height_profile() +{ + wxGetApp().plater()->take_snapshot(_(L("Layer height profile-Reset"))); + m_layers_editing.reset_layer_height_profile(*this); + m_layers_editing.state = LayersEditing::Completed; + m_dirty = true; +} + +void GLCanvas3D::adaptive_layer_height_profile(float cusp) +{ + wxGetApp().plater()->take_snapshot(_(L("Layer height profile-Adaptive"))); + m_layers_editing.adaptive_layer_height_profile(*this, cusp); + m_layers_editing.state = LayersEditing::Completed; + m_dirty = true; +} + +void GLCanvas3D::smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params) +{ + wxGetApp().plater()->take_snapshot(_(L("Layer height profile-Smooth all"))); + m_layers_editing.smooth_layer_height_profile(*this, smoothing_params); + m_layers_editing.state = LayersEditing::Completed; + m_dirty = true; +} +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + bool GLCanvas3D::is_reload_delayed() const { return m_reload_delayed; @@ -1624,10 +1816,11 @@ void GLCanvas3D::render() return; } + const Size& cnv_size = get_canvas_size(); + if (m_camera.requires_zoom_to_bed) { zoom_to_bed(); - const Size& cnv_size = get_canvas_size(); _resize((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height()); m_camera.requires_zoom_to_bed = false; } @@ -1718,6 +1911,8 @@ void GLCanvas3D::render() m_camera.debug_render(); #endif // ENABLE_CAMERA_STATISTICS + wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height()); + wxGetApp().imgui()->render(); m_canvas->SwapBuffers(); @@ -2176,7 +2371,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false)); } - m_camera.set_scene_box(scene_bounding_box()); + refresh_camera_scene_box(); if (m_selection.is_empty()) { @@ -2212,12 +2407,12 @@ static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume& 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; + volume_index.first_volumes.emplace_back(extrusion_type, 0, (unsigned int)volumes.volumes.size()); + GLVolume *volume = volumes.new_nontoolpath_volume(retractions.color.rgba, VERTEX_BUFFER_RESERVE_SIZE); GCodePreviewData::Retraction::PositionsList copy(retractions.positions); @@ -2283,6 +2478,9 @@ void GLCanvas3D::load_gcode_preview(const GCodePreviewData& preview_data, const ++ idx_volume_index_src; idx_volume_of_this_type_last = (idx_volume_index_src + 1 == m_gcode_preview_volume_index.first_volumes.size()) ? m_volumes.volumes.size() : m_gcode_preview_volume_index.first_volumes[idx_volume_index_src + 1].id; idx_volume_of_this_type_first_new = idx_volume_dst; + if (idx_volume_src == idx_volume_of_this_type_last) + // Empty sequence of volumes for the current index item. + continue; } if (! m_volumes.volumes[idx_volume_src]->print_zs.empty()) m_volumes.volumes[idx_volume_dst ++] = m_volumes.volumes[idx_volume_src]; @@ -2416,14 +2614,21 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt) m_dirty |= m_main_toolbar.update_items_state(); m_dirty |= m_undoredo_toolbar.update_items_state(); m_dirty |= m_view_toolbar.update_items_state(); + bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(m_camera); + m_dirty |= mouse3d_controller_applied; if (!m_dirty) return; _refresh_if_shown_on_screen(); - if (m_keep_dirty) + if (m_keep_dirty || mouse3d_controller_applied) + { m_dirty = true; + evt.RequestMore(); + } + else + m_dirty = false; } void GLCanvas3D::on_char(wxKeyEvent& evt) @@ -2468,6 +2673,20 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) #endif /* __APPLE__ */ post_event(SimpleEvent(EVT_GLTOOLBAR_COPY)); break; + +#ifdef __APPLE__ + case 'm': + case 'M': +#else /* __APPLE__ */ + case WXK_CONTROL_M: +#endif /* __APPLE__ */ + { + Mouse3DController& controller = wxGetApp().plater()->get_mouse3d_controller(); + controller.show_settings_dialog(!controller.is_settings_dialog_shown()); + m_dirty = true; + break; + } + #ifdef __APPLE__ case 'v': case 'V': @@ -2535,11 +2754,11 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'B': case 'b': { zoom_to_bed(); break; } case 'I': - case 'i': { set_camera_zoom(1.0); break; } + case 'i': { _update_camera_zoom(1.0); break; } case 'K': case 'k': { m_camera.select_next_type(); m_dirty = true; break; } case 'O': - case 'o': { set_camera_zoom(-1.0); break; } + case 'o': { _update_camera_zoom(-1.0); break; } #if ENABLE_RENDER_PICKING_PASS case 'T': case 't': { @@ -2642,6 +2861,11 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) { + // try to filter out events coming from mouse 3d + Mouse3DController& controller = wxGetApp().plater()->get_mouse3d_controller(); + if (controller.process_mouse_wheel()) + return; + if (!m_initialized) return; @@ -2686,7 +2910,7 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) return; // Calculate the zoom delta and apply it to the current zoom factor - set_camera_zoom((double)evt.GetWheelRotation() / (double)evt.GetWheelDelta()); + _update_camera_zoom((double)evt.GetWheelRotation() / (double)evt.GetWheelDelta()); } void GLCanvas3D::on_timer(wxTimerEvent& evt) @@ -2878,6 +3102,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_layers_editing.state = LayersEditing::Editing; _perform_layer_editing_action(&evt); } +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE else if ((layer_editing_object_idx != -1) && m_layers_editing.reset_rect_contains(*this, pos(0), pos(1))) { if (evt.LeftDown()) @@ -2890,6 +3115,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } } +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE else if (evt.LeftDown() && (evt.ShiftDown() || evt.AltDown()) && m_picking_enabled) { if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports) @@ -3021,6 +3247,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if ((m_layers_editing.state != LayersEditing::Unknown) && (layer_editing_object_idx != -1)) { + set_tooltip(""); if (m_layers_editing.state == LayersEditing::Editing) _perform_layer_editing_action(&evt); } @@ -3130,6 +3357,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.position = pos.cast(); std::string tooltip = ""; + if (tooltip.empty()) + tooltip = m_layers_editing.get_tooltip(*this); + if (tooltip.empty()) tooltip = m_gizmos.get_tooltip(); @@ -3469,13 +3699,6 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type) m_dirty = true; } -void GLCanvas3D::set_camera_zoom(double zoom) -{ - const Size& cnv_size = get_canvas_size(); - m_camera.set_zoom(zoom, _max_bounding_box(false, true), cnv_size.get_width(), cnv_size.get_height()); - m_dirty = true; -} - void GLCanvas3D::update_gizmos_on_off_state() { set_as_dirty(); @@ -3702,7 +3925,7 @@ static void render_volumes_in_thumbnail(Shader& shader, const GLVolumePtrs& volu camera.apply_projection(box); if (transparent_background) - glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 0.0f)); + glsafe(::glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); glsafe(::glEnable(GL_DEPTH_TEST)); @@ -4261,8 +4484,6 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) // updates camera m_camera.apply_viewport(0, 0, w, h); - - m_dirty = false; } BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_bed_model) const @@ -4299,6 +4520,12 @@ void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box) } #endif // ENABLE_THUMBNAIL_GENERATOR +void GLCanvas3D::_update_camera_zoom(double zoom) +{ + m_camera.update_zoom(zoom); + m_dirty = true; +} + void GLCanvas3D::_refresh_if_shown_on_screen() { if (_is_shown_on_screen()) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 729b707d2..ef91f8265 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -81,6 +81,8 @@ template using Vec2dsEvent = ArrayEvent; using Vec3dEvent = Event; template using Vec3dsEvent = ArrayEvent; +using HeightProfileSmoothEvent = Event; + wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent); @@ -104,6 +106,11 @@ wxDECLARE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent); wxDECLARE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent); wxDECLARE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent); +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE +wxDECLARE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent); +wxDECLARE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event); +wxDECLARE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent); +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE class GLCanvas3D { @@ -153,13 +160,17 @@ private: private: static const float THICKNESS_BAR_WIDTH; +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE static const float THICKNESS_RESET_BUTTON_HEIGHT; +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE bool m_enabled; Shader m_shader; unsigned int m_z_texture_id; +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE mutable GLTexture m_tooltip_texture; mutable GLTexture m_reset_texture; +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // Not owned by LayersEditing. const DynamicPrintConfig *m_config; // ModelObject for the currently selected object (Model::objects[last_object_id]). @@ -168,9 +179,14 @@ private: float m_object_max_z; // Owned by LayersEditing. SlicingParameters *m_slicing_parameters; - std::vector m_layer_height_profile; + std::vector m_layer_height_profile; bool m_layer_height_profile_modified; +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + mutable float m_adaptive_cusp; + mutable HeightProfileSmoothingParams m_smooth_params; +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + class LayersTexture { public: @@ -217,28 +233,44 @@ private: void adjust_layer_height_profile(); void accept_changes(GLCanvas3D& canvas); void reset_layer_height_profile(GLCanvas3D& canvas); +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + void adaptive_layer_height_profile(GLCanvas3D& canvas, float cusp); + void smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_paramsn); +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE static float get_cursor_z_relative(const GLCanvas3D& canvas); static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y); +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE static bool reset_rect_contains(const GLCanvas3D& canvas, float x, float y); +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE static Rect get_bar_rect_screen(const GLCanvas3D& canvas); +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE static Rect get_reset_rect_screen(const GLCanvas3D& canvas); +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE static Rect get_bar_rect_viewport(const GLCanvas3D& canvas); +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE static Rect get_reset_rect_viewport(const GLCanvas3D& canvas); +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE float object_max_z() const { return m_object_max_z; } + std::string get_tooltip(const GLCanvas3D& canvas) const; + private: - bool _is_initialized() const; + bool is_initialized() const; void generate_layer_height_texture(); +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE void _render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const; void _render_reset_texture(const Rect& reset_rect) const; - void _render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const; - void _render_profile(const Rect& bar_rect) const; +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + void render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const; + void render_profile(const Rect& bar_rect) const; void update_slicing_parameters(); static float thickness_bar_width(const GLCanvas3D &canvas); +#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE static float reset_button_height(const GLCanvas3D &canvas); +#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE }; struct Mouse @@ -496,6 +528,7 @@ public: void set_color_by(const std::string& value); const Camera& get_camera() const { return m_camera; } + Camera& get_camera() { return m_camera; } BoundingBoxf3 volumes_bounding_box() const; BoundingBoxf3 scene_bounding_box() const; @@ -503,6 +536,12 @@ public: bool is_layers_editing_enabled() const; bool is_layers_editing_allowed() const; +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + void reset_layer_height_profile(); + void adaptive_layer_height_profile(float cusp); + void smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params); +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + bool is_reload_delayed() const; void enable_layers_editing(bool enable); @@ -579,8 +618,6 @@ public: void do_flatten(const Vec3d& normal, const std::string& snapshot_type); void do_mirror(const std::string& snapshot_type); - void set_camera_zoom(double zoom); - void update_gizmos_on_off_state(); void reset_all_gizmos() { m_gizmos.reset_all_states(); } @@ -659,6 +696,7 @@ private: #else void _zoom_to_box(const BoundingBoxf3& box); #endif // ENABLE_THUMBNAIL_GENERATOR + void _update_camera_zoom(double zoom); void _refresh_if_shown_on_screen(); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 7d37baa66..a74c6b0c0 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1126,7 +1126,6 @@ void GUI_App::gcode_thumbnails_debug() } else if (reading_image && boost::starts_with(gcode_line, END_MASK)) { -#if ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE std::string out_filename = out_path + std::to_string(width) + "x" + std::to_string(height) + ".png"; boost::nowide::ofstream out_file(out_filename.c_str(), std::ios::binary); if (out_file.good()) @@ -1138,46 +1137,6 @@ void GUI_App::gcode_thumbnails_debug() out_file.write(decoded.c_str(), decoded.size()); out_file.close(); } -#else - if (!row.empty()) - { - rows.push_back(row); - row.clear(); - } - - if ((unsigned int)rows.size() == height) - { - std::vector thumbnail(4 * width * height, 0); - for (unsigned int r = 0; r < (unsigned int)rows.size(); ++r) - { - std::string decoded_row; - decoded_row.resize(boost::beast::detail::base64::decoded_size(rows[r].size())); - decoded_row.resize(boost::beast::detail::base64::decode((void*)&decoded_row[0], rows[r].data(), rows[r].size()).first); - - if ((unsigned int)decoded_row.size() == width * 4) - { - void* image_ptr = (void*)(thumbnail.data() + r * width * 4); - ::memcpy(image_ptr, (const void*)decoded_row.c_str(), width * 4); - } - } - - wxImage image(width, height); - image.InitAlpha(); - - for (unsigned int r = 0; r < height; ++r) - { - unsigned int rr = r * width; - for (unsigned int c = 0; c < width; ++c) - { - unsigned char* px = thumbnail.data() + 4 * (rr + c); - image.SetRGB((int)c, (int)r, px[0], px[1], px[2]); - image.SetAlpha((int)c, (int)r, px[3]); - } - } - - image.SaveFile(out_path + std::to_string(width) + "x" + std::to_string(height) + ".png", wxBITMAP_TYPE_PNG); - } -#endif // ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE reading_image = false; width = 0; @@ -1185,17 +1144,7 @@ void GUI_App::gcode_thumbnails_debug() rows.clear(); } else if (reading_image) - { -#if !ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE - if (!row.empty() && (gcode_line[1] == ' ')) - { - rows.push_back(row); - row.clear(); - } -#endif // !ENABLE_THUMBNAIL_GENERATOR_PNG_TO_GCODE - row += gcode_line.substr(2); - } } } diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 8e4d9eebf..9dfe39bdd 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -528,6 +528,9 @@ void ImGuiWrapper::init_style() // Slider set_color(ImGuiCol_SliderGrab, COL_ORANGE_DARK); set_color(ImGuiCol_SliderGrabActive, COL_ORANGE_LIGHT); + + // Separator + set_color(ImGuiCol_Separator, COL_ORANGE_LIGHT); } void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index e3ef335e6..268682b81 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -157,6 +157,7 @@ void KBShortcutsDialog::fill_shortcuts() plater_shortcuts.push_back(Shortcut("Z", L("Zoom to selected object"))); plater_shortcuts.push_back(Shortcut("I", L("Zoom in"))); plater_shortcuts.push_back(Shortcut("O", L("Zoom out"))); + plater_shortcuts.push_back(Shortcut(ctrl+"M", L("Show/Hide 3Dconnexion devices settings dialog"))); plater_shortcuts.push_back(Shortcut("ESC", L("Unselect gizmo / Clear selection"))); #if ENABLE_RENDER_PICKING_PASS // Don't localize debugging texts. diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index b76110a87..ef707d47b 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -24,6 +24,7 @@ #include "PrintHostDialogs.hpp" #include "wxExtensions.hpp" #include "GUI_ObjectList.hpp" +#include "Mouse3DController.hpp" #include "I18N.hpp" #include diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp new file mode 100644 index 000000000..e69ef4857 --- /dev/null +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -0,0 +1,821 @@ +#include "libslic3r/libslic3r.h" +#include "Mouse3DController.hpp" + +#include "Camera.hpp" +#include "GUI_App.hpp" +#include "PresetBundle.hpp" +#include "AppConfig.hpp" + +#include + +#include +#include +#include "I18N.hpp" + +#include + +// WARN: If updating these lists, please also update resources/udev/90-3dconnexion.rules + +static const std::vector _3DCONNEXION_VENDORS = +{ + 0x046d, // LOGITECH = 1133 // Logitech (3Dconnexion is made by Logitech) + 0x256F // 3DCONNECTION = 9583 // 3Dconnexion +}; + +// See: https://github.com/FreeSpacenav/spacenavd/blob/a9eccf34e7cac969ee399f625aef827f4f4aaec6/src/dev.c#L202 +static const std::vector _3DCONNEXION_DEVICES = +{ + 0xc603, /* 50691 spacemouse plus XT */ + 0xc605, /* 50693 cadman */ + 0xc606, /* 50694 spacemouse classic */ + 0xc621, /* 50721 spaceball 5000 */ + 0xc623, /* 50723 space traveller */ + 0xc625, /* 50725 space pilot */ + 0xc626, /* 50726 space navigator *TESTED* */ + 0xc627, /* 50727 space explorer */ + 0xc628, /* 50728 space navigator for notebooks*/ + 0xc629, /* 50729 space pilot pro*/ + 0xc62b, /* 50731 space mouse pro*/ + 0xc62e, /* 50734 spacemouse wireless (USB cable) *TESTED* */ + 0xc62f, /* 50735 spacemouse wireless receiver */ + 0xc631, /* 50737 spacemouse pro wireless *TESTED* */ + 0xc632, /* 50738 spacemouse pro wireless receiver */ + 0xc633, /* 50739 spacemouse enterprise */ + 0xc635, /* 50741 spacemouse compact *TESTED* */ + 0xc636, /* 50742 spacemouse module */ + 0xc640, /* 50752 nulooq */ + 0xc652, /* 50770 3Dconnexion universal receiver *TESTED* */ +}; + +namespace Slic3r { +namespace GUI { + +const double Mouse3DController::State::DefaultTranslationScale = 2.5; +const double Mouse3DController::State::MaxTranslationDeadzone = 0.2; +const double Mouse3DController::State::DefaultTranslationDeadzone = 0.5 * Mouse3DController::State::MaxTranslationDeadzone; +const float Mouse3DController::State::DefaultRotationScale = 1.0f; +const float Mouse3DController::State::MaxRotationDeadzone = (float)Mouse3DController::State::MaxTranslationDeadzone; +const float Mouse3DController::State::DefaultRotationDeadzone = 0.5f * Mouse3DController::State::MaxRotationDeadzone; + +Mouse3DController::State::State() + : m_buttons_enabled(false) + , m_translation_params(DefaultTranslationScale, DefaultTranslationDeadzone) + , m_rotation_params(DefaultRotationScale, DefaultRotationDeadzone) + , m_mouse_wheel_counter(0) +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + , m_translation_queue_max_size(0) + , m_rotation_queue_max_size(0) + , m_buttons_queue_max_size(0) +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT +{ +} + +void Mouse3DController::State::append_translation(const Vec3d& translation) +{ + while (m_translation.queue.size() >= m_translation.max_size) + { + m_translation.queue.pop(); + } + m_translation.queue.push(translation); +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + m_translation_queue_max_size = std::max(m_translation_queue_max_size, m_translation.queue.size()); +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT +} + +void Mouse3DController::State::append_rotation(const Vec3f& rotation) +{ + while (m_rotation.queue.size() >= m_rotation.max_size) + { + m_rotation.queue.pop(); + } + m_rotation.queue.push(rotation); +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + m_rotation_queue_max_size = std::max(m_rotation_queue_max_size, m_rotation.queue.size()); +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + if (rotation(0) != 0.0f) + ++m_mouse_wheel_counter; +} + +void Mouse3DController::State::append_button(unsigned int id) +{ + if (!m_buttons_enabled) + return; + + m_buttons.push(id); +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + m_buttons_queue_max_size = std::max(m_buttons_queue_max_size, m_buttons.size()); +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT +} + +bool Mouse3DController::State::process_mouse_wheel() +{ + if (m_mouse_wheel_counter == 0) + return false; + else if (!m_rotation.queue.empty()) + { + --m_mouse_wheel_counter; + return true; + } + + m_mouse_wheel_counter = 0; + return true; +} + +void Mouse3DController::State::set_queues_max_size(size_t size) +{ + if (size > 0) + { + m_translation.max_size = size; + m_rotation.max_size = size; + +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + m_translation_queue_max_size = 0; + m_rotation_queue_max_size = 0; + m_buttons_queue_max_size = 0; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + } +} + +bool Mouse3DController::State::apply(Camera& camera) +{ + if (!wxGetApp().IsActive()) + return false; + + bool ret = false; + + if (has_translation()) + { + const Vec3d& translation = m_translation.queue.front(); + camera.set_target(camera.get_target() + m_translation_params.scale * (translation(0) * camera.get_dir_right() + translation(1) * camera.get_dir_forward() + translation(2) * camera.get_dir_up())); + m_translation.queue.pop(); + ret = true; + } + + if (has_rotation()) + { + const Vec3f& rotation = m_rotation.queue.front(); + float theta = m_rotation_params.scale * rotation(0); + float phi = m_rotation_params.scale * rotation(2); + float sign = camera.inverted_phi ? -1.0f : 1.0f; + camera.phi += sign * phi; + camera.set_theta(camera.get_theta() + theta, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA); + m_rotation.queue.pop(); + ret = true; + } + + if (m_buttons_enabled && has_button()) + { + unsigned int button = m_buttons.front(); + switch (button) + { + case 0: { camera.update_zoom(1.0); break; } + case 1: { camera.update_zoom(-1.0); break; } + default: { break; } + } + m_buttons.pop(); + ret = true; + } + + return ret; +} + +Mouse3DController::Mouse3DController() + : m_initialized(false) + , m_device(nullptr) + , m_device_str("") + , m_running(false) + , m_settings_dialog(false) +{ + m_last_time = std::chrono::high_resolution_clock::now(); +} + +void Mouse3DController::init() +{ + if (m_initialized) + return; + + // Initialize the hidapi library + int res = hid_init(); + if (res != 0) + { + BOOST_LOG_TRIVIAL(error) << "Unable to initialize hidapi library"; + return; + } + + m_initialized = true; +} + +void Mouse3DController::shutdown() +{ + if (!m_initialized) + return; + + stop(); + disconnect_device(); + + // Finalize the hidapi library + hid_exit(); + m_initialized = false; +} + +bool Mouse3DController::apply(Camera& camera) +{ + if (!m_initialized) + return false; + + std::lock_guard lock(m_mutex); + + // check if the user unplugged the device + if (!m_running && is_device_connected()) + { + disconnect_device(); + // hides the settings dialog if the user re-plug the device + m_settings_dialog = false; + } + + // check if the user plugged the device + if (connect_device()) + start(); + + return is_device_connected() ? m_state.apply(camera) : false; +} + +void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const +{ + if (!m_running || !m_settings_dialog) + return; + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + + imgui.set_next_window_pos(0.5f * (float)canvas_width, 0.5f * (float)canvas_height, ImGuiCond_Always, 0.5f, 0.5f); + imgui.set_next_window_bg_alpha(0.5f); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + + imgui.begin(_(L("3Dconnexion settings")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse); + + const ImVec4& color = ImGui::GetStyleColorVec4(ImGuiCol_Separator); + ImGui::PushStyleColor(ImGuiCol_Text, color); + imgui.text(_(L("Device:"))); + ImGui::PopStyleColor(); + ImGui::SameLine(); + imgui.text(m_device_str); + + ImGui::Separator(); + ImGui::PushStyleColor(ImGuiCol_Text, color); + imgui.text(_(L("Speed:"))); + ImGui::PopStyleColor(); + + float translation_scale = (float)m_state.get_translation_scale() / State::DefaultTranslationScale; + if (ImGui::SliderFloat(_(L("Translation##1")), &translation_scale, 0.5f, 2.0f, "%.1f")) + m_state.set_translation_scale(State::DefaultTranslationScale * (double)translation_scale); + + float rotation_scale = m_state.get_rotation_scale() / State::DefaultRotationScale; + if (ImGui::SliderFloat(_(L("Rotation##1")), &rotation_scale, 0.5f, 2.0f, "%.1f")) + m_state.set_rotation_scale(State::DefaultRotationScale * rotation_scale); + + ImGui::Separator(); + ImGui::PushStyleColor(ImGuiCol_Text, color); + imgui.text(_(L("Deadzone:"))); + ImGui::PopStyleColor(); + + float translation_deadzone = (float)m_state.get_translation_deadzone(); + if (ImGui::SliderFloat(_(L("Translation##2")), &translation_deadzone, 0.0f, (float)State::MaxTranslationDeadzone, "%.2f")) + m_state.set_translation_deadzone((double)translation_deadzone); + + float rotation_deadzone = m_state.get_rotation_deadzone(); + if (ImGui::SliderFloat(_(L("Rotation##2")), &rotation_deadzone, 0.0f, State::MaxRotationDeadzone, "%.2f")) + m_state.set_rotation_deadzone(rotation_deadzone); + +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + ImGui::Separator(); + ImGui::Separator(); + ImGui::PushStyleColor(ImGuiCol_Text, color); + imgui.text("DEBUG:"); + imgui.text("Vectors:"); + ImGui::PopStyleColor(); + Vec3f translation = m_state.get_translation().cast(); + Vec3f rotation = m_state.get_rotation(); + ImGui::InputFloat3("Translation##3", translation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly); + ImGui::InputFloat3("Rotation##3", rotation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly); + + ImGui::PushStyleColor(ImGuiCol_Text, color); + imgui.text("Queue size:"); + ImGui::PopStyleColor(); + + int translation_size[2] = { (int)m_state.get_translation_queue_size(), (int)m_state.get_translation_queue_max_size() }; + int rotation_size[2] = { (int)m_state.get_rotation_queue_size(), (int)m_state.get_rotation_queue_max_size() }; + int buttons_size[2] = { (int)m_state.get_buttons_queue_size(), (int)m_state.get_buttons_queue_max_size() }; + + ImGui::InputInt2("Translation##4", translation_size, ImGuiInputTextFlags_ReadOnly); + ImGui::InputInt2("Rotation##4", rotation_size, ImGuiInputTextFlags_ReadOnly); + ImGui::InputInt2("Buttons", buttons_size, ImGuiInputTextFlags_ReadOnly); + + int queue_size = (int)m_state.get_queues_max_size(); + if (ImGui::InputInt("Max size", &queue_size, 1, 1, ImGuiInputTextFlags_ReadOnly)) + { + if (queue_size > 0) + m_state.set_queues_max_size(queue_size); + } + + ImGui::Separator(); + ImGui::PushStyleColor(ImGuiCol_Text, color); + imgui.text("Camera:"); + ImGui::PopStyleColor(); + Vec3f target = wxGetApp().plater()->get_camera().get_target().cast(); + ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly); +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + + imgui.end(); + + ImGui::PopStyleVar(); +} + +bool Mouse3DController::connect_device() +{ + static const long long DETECTION_TIME_MS = 2000; // seconds + + if (is_device_connected()) + return false; + + // check time since last detection took place + if (std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_last_time).count() < DETECTION_TIME_MS) + return false; + + m_last_time = std::chrono::high_resolution_clock::now(); + + // Enumerates devices + hid_device_info* devices = hid_enumerate(0, 0); + if (devices == nullptr) + { + BOOST_LOG_TRIVIAL(error) << "Unable to enumerate HID devices"; + return false; + } + + // Searches for 1st connected 3Dconnexion device + struct DeviceData + { + std::string path; + unsigned short usage_page; + unsigned short usage; + + DeviceData() + : path(""), usage_page(0), usage(0) + {} + DeviceData(const std::string& path, unsigned short usage_page, unsigned short usage) + : path(path), usage_page(usage_page), usage(usage) + {} + + bool has_valid_usage() const { return (usage_page == 1) && (usage == 8); } + }; + +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + hid_device_info* cur = devices; + std::cout << std::endl << "======================================================================================================================================" << std::endl; + std::cout << "Detected devices:" << std::endl; + while (cur != nullptr) + { + std::cout << "\""; + std::wcout << ((cur->manufacturer_string != nullptr) ? cur->manufacturer_string : L"Unknown"); + std::cout << "/"; + std::wcout << ((cur->product_string != nullptr) ? cur->product_string : L"Unknown"); + std::cout << "\" code: " << cur->vendor_id << "/" << cur->product_id << " (" << std::hex << cur->vendor_id << "/" << cur->product_id << std::dec << ")"; + std::cout << " serial number: '"; + std::wcout << ((cur->serial_number != nullptr) ? cur->serial_number : L"Unknown"); + std::cout << "' usage page: " << cur->usage_page << " usage: " << cur->usage << " interface number: " << cur->interface_number << std::endl; + + cur = cur->next; + } +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + + // When using 3Dconnexion universal receiver, multiple devices are detected sharing the same vendor_id and product_id. + // To choose from them the right one we use: + // On Windows and Mac: usage_page == 1 and usage == 8 + // On Linux: as usage_page and usage are not defined (see hidapi.h) we try all detected devices until one is succesfully open + // When only a single device is detected, as for wired connections, vendor_id and product_id are enough + + // First we count all the valid devices from the enumerated list, + + hid_device_info* current = devices; + typedef std::pair DeviceIds; + typedef std::vector DeviceDataList; + typedef std::map DetectedDevices; + DetectedDevices detected_devices; +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + std::cout << std::endl << "Detected 3D connexion devices:" << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + while (current != nullptr) + { + unsigned short vendor_id = 0; + unsigned short product_id = 0; + + for (size_t i = 0; i < _3DCONNEXION_VENDORS.size(); ++i) + { + if (_3DCONNEXION_VENDORS[i] == current->vendor_id) + { + vendor_id = current->vendor_id; + break; + } + } + + if (vendor_id != 0) + { + for (size_t i = 0; i < _3DCONNEXION_DEVICES.size(); ++i) + { + if (_3DCONNEXION_DEVICES[i] == current->product_id) + { + product_id = current->product_id; + DeviceIds detected_device(vendor_id, product_id); + DetectedDevices::iterator it = detected_devices.find(detected_device); + if (it == detected_devices.end()) + it = detected_devices.insert(DetectedDevices::value_type(detected_device, DeviceDataList())).first; + + it->second.emplace_back(current->path, current->usage_page, current->usage); + +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + std::wcout << "\"" << ((current->manufacturer_string != nullptr) ? current->manufacturer_string : L"Unknown"); + std::cout << "/"; + std::wcout << ((current->product_string != nullptr) ? current->product_string : L"Unknown"); + std::cout << "\" code: " << current->vendor_id << "/" << current->product_id << " (" << std::hex << current->vendor_id << "/" << current->product_id << std::dec << ")"; + std::cout << " serial number: '"; + std::wcout << ((current->serial_number != nullptr) ? current->serial_number : L"Unknown"); + std::cout << "' usage page: " << current->usage_page << " usage: " << current->usage << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + } + } + } + + current = current->next; + } + + // Free enumerated devices + hid_free_enumeration(devices); + + if (detected_devices.empty()) + return false; + + std::string path = ""; + unsigned short vendor_id = 0; + unsigned short product_id = 0; + + // Then we'll decide the choosing logic to apply in dependence of the device count and operating system + + for (const DetectedDevices::value_type& device : detected_devices) + { + if (device.second.size() == 1) + { +#ifdef __linux__ + hid_device* test_device = hid_open(device.first.first, device.first.second, nullptr); + if (test_device != nullptr) + { + hid_close(test_device); +#else + if (device.second.front().has_valid_usage()) + { +#endif // __linux__ + vendor_id = device.first.first; + product_id = device.first.second; + break; + } + } + else + { + bool found = false; +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + std::cout << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + for (const DeviceData& data : device.second) + { +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + std::cout << "Test device: " << std::hex << device.first.first << std::dec << "/" << std::hex << device.first.second << std::dec << " \"" << data.path << "\""; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT +#ifdef __linux__ + hid_device* test_device = hid_open_path(data.path.c_str()); + if (test_device != nullptr) + { + path = data.path; + vendor_id = device.first.first; + product_id = device.first.second; + found = true; +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + std::cout << "-> PASSED" << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + hid_close(test_device); + break; + } +#else + if (data.has_valid_usage()) + { + path = data.path; + vendor_id = device.first.first; + product_id = device.first.second; + found = true; +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + std::cout << "-> PASSED" << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + break; + } +#endif // __linux__ +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + else + std::cout << "-> NOT PASSED" << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + } + + if (found) + break; + } + } + + if (path.empty()) + { + if ((vendor_id != 0) && (product_id != 0)) + { + // Open the 3Dconnexion device using vendor_id and product_id +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + std::cout << std::endl << "Opening device: " << std::hex << vendor_id << std::dec << "/" << std::hex << product_id << std::dec << " using hid_open()" << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + m_device = hid_open(vendor_id, product_id, nullptr); + } + else + return false; + } + else + { + // Open the 3Dconnexion device using the device path +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + std::cout << std::endl << "Opening device: " << std::hex << vendor_id << std::dec << "/" << std::hex << product_id << std::dec << "\"" << path << "\" using hid_open_path()" << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + m_device = hid_open_path(path.c_str()); + } + + if (m_device != nullptr) + { + std::vector manufacturer(1024, 0); + hid_get_manufacturer_string(m_device, manufacturer.data(), 1024); + m_device_str = boost::nowide::narrow(manufacturer.data()); + + std::vector product(1024, 0); + hid_get_product_string(m_device, product.data(), 1024); + m_device_str += "/" + boost::nowide::narrow(product.data()); + + BOOST_LOG_TRIVIAL(info) << "Connected device: " << m_device_str; + +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + std::cout << std::endl << "Connected device:" << std::endl; + std::cout << "Manufacturer/product: " << m_device_str << std::endl; + std::cout << "Manufacturer id.....: " << vendor_id << " (" << std::hex << vendor_id << std::dec << ")" << std::endl; + std::cout << "Product id..........: " << product_id << " (" << std::hex << product_id << std::dec << ")" << std::endl; + std::cout << "Path................: '" << path << "'" << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + + // get device parameters from the config, if present + double translation_speed = 1.0; + float rotation_speed = 1.0; + double translation_deadzone = State::DefaultTranslationDeadzone; + float rotation_deadzone = State::DefaultRotationDeadzone; + wxGetApp().app_config->get_mouse_device_translation_speed(m_device_str, translation_speed); + wxGetApp().app_config->get_mouse_device_translation_deadzone(m_device_str, translation_deadzone); + wxGetApp().app_config->get_mouse_device_rotation_speed(m_device_str, rotation_speed); + wxGetApp().app_config->get_mouse_device_rotation_deadzone(m_device_str, rotation_deadzone); + // clamp to valid values + m_state.set_translation_scale(State::DefaultTranslationScale * std::max(0.5, std::min(2.0, translation_speed))); + m_state.set_translation_deadzone(std::max(0.0, std::min(State::MaxTranslationDeadzone, translation_deadzone))); + m_state.set_rotation_scale(State::DefaultRotationScale * std::max(0.5f, std::min(2.0f, rotation_speed))); + m_state.set_rotation_deadzone(std::max(0.0f, std::min(State::MaxRotationDeadzone, rotation_deadzone))); + } +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + else + { + std::cout << std::endl << "Unable to connect to device:" << std::endl; + std::cout << "Manufacturer/product: " << m_device_str << std::endl; + std::cout << "Manufacturer id.....: " << vendor_id << " (" << std::hex << vendor_id << std::dec << ")" << std::endl; + std::cout << "Product id..........: " << product_id << " (" << std::hex << product_id << std::dec << ")" << std::endl; + std::cout << "Path................: '" << path << "'" << std::endl; + } +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + + return (m_device != nullptr); +} + +void Mouse3DController::disconnect_device() +{ + if (!is_device_connected()) + return; + + // Stop the secondary thread, if running + if (m_thread.joinable()) + m_thread.join(); + + // Store current device parameters into the config + wxGetApp().app_config->set_mouse_device(m_device_str, m_state.get_translation_scale() / State::DefaultTranslationScale, m_state.get_translation_deadzone(), + m_state.get_rotation_scale() / State::DefaultRotationScale, m_state.get_rotation_deadzone()); + wxGetApp().app_config->save(); + + // Close the 3Dconnexion device + hid_close(m_device); + m_device = nullptr; + + BOOST_LOG_TRIVIAL(info) << "Disconnected device: " << m_device_str; + + m_device_str = ""; +} + +void Mouse3DController::start() +{ + if (!is_device_connected() || m_running) + return; + + m_thread = std::thread(&Mouse3DController::run, this); +} + +void Mouse3DController::run() +{ + m_running = true; + while (m_running) + { + collect_input(); + } +} + +void Mouse3DController::collect_input() +{ + DataPacket packet = { 0 }; + int res = hid_read_timeout(m_device, packet.data(), packet.size(), 100); + if (res < 0) + { + // An error occourred (device detached from pc ?) + stop(); + return; + } + + if (!wxGetApp().IsActive()) + return; + + std::lock_guard lock(m_mutex); + + bool updated = false; + + if (res == 7) + updated = handle_packet(packet); + else if (res == 13) + updated = handle_wireless_packet(packet); + else if ((res == 3) && (packet[0] == 3)) + // On Mac button packets can be 3 bytes long + updated = handle_packet(packet); +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + else if (res > 0) + std::cout << "Got unknown data packet of length: " << res << ", code:" << (int)packet[0] << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + + if (updated) + // ask for an idle event to update 3D scene + wxWakeUpIdle(); +} + +bool Mouse3DController::handle_packet(const DataPacket& packet) +{ + switch (packet[0]) + { + case 1: // Translation + { + if (handle_packet_translation(packet)) + return true; + + break; + } + case 2: // Rotation + { + if (handle_packet_rotation(packet, 1)) + return true; + + break; + } + case 3: // Button + { + if (handle_packet_button(packet, packet.size() - 1)) + return true; + + break; + } + case 23: // Battery charge + { +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + std::cout << m_device_str << " - battery level: " << (int)packet[1] << " percent" << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + break; + } + default: + { +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + std::cout << "Got unknown data packet of code: " << (int)packet[0] << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + break; + } + } + + return false; +} + +bool Mouse3DController::handle_wireless_packet(const DataPacket& packet) +{ + switch (packet[0]) + { + case 1: // Translation + Rotation + { + bool updated = handle_packet_translation(packet); + updated |= handle_packet_rotation(packet, 7); + + if (updated) + return true; + + break; + } + case 3: // Button + { + if (handle_packet_button(packet, 12)) + return true; + + break; + } + case 23: // Battery charge + { +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + std::cout << m_device_str << " - battery level: " << (int)packet[1] << " percent" << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + break; + } + default: + { +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + std::cout << "Got unknown data packet of code: " << (int)packet[0] << std::endl; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + break; + } + } + + return false; +} + +double convert_input(unsigned char first, unsigned char second, double deadzone) +{ + short value = first | second << 8; + double ret = (double)value / 350.0; + return (std::abs(ret) > deadzone) ? ret : 0.0; +} + +bool Mouse3DController::handle_packet_translation(const DataPacket& packet) +{ + double deadzone = m_state.get_translation_deadzone(); + Vec3d translation(-convert_input(packet[1], packet[2], deadzone), + convert_input(packet[3], packet[4], deadzone), + convert_input(packet[5], packet[6], deadzone)); + + if (!translation.isApprox(Vec3d::Zero())) + { + m_state.append_translation(translation); + return true; + } + + return false; +} + +bool Mouse3DController::handle_packet_rotation(const DataPacket& packet, unsigned int first_byte) +{ + double deadzone = (double)m_state.get_rotation_deadzone(); + Vec3f rotation(-(float)convert_input(packet[first_byte + 0], packet[first_byte + 1], deadzone), + (float)convert_input(packet[first_byte + 2], packet[first_byte + 3], deadzone), + -(float)convert_input(packet[first_byte + 4], packet[first_byte + 5], deadzone)); + + if (!rotation.isApprox(Vec3f::Zero())) + { + m_state.append_rotation(rotation); + return true; + } + + return false; +} + +bool Mouse3DController::handle_packet_button(const DataPacket& packet, unsigned int packet_size) +{ + unsigned int data = 0; + for (unsigned int i = 1; i < packet_size; ++i) + { + data |= packet[i] << 8 * (i - 1); + } + + const std::bitset<32> data_bits{ data }; + for (size_t i = 0; i < data_bits.size(); ++i) + { + if (data_bits.test(i)) + { + m_state.append_button((unsigned int)i); + return true; + } + } + + return false; +} + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/Mouse3DController.hpp b/src/slic3r/GUI/Mouse3DController.hpp new file mode 100644 index 000000000..cc03d4a24 --- /dev/null +++ b/src/slic3r/GUI/Mouse3DController.hpp @@ -0,0 +1,175 @@ +#ifndef slic3r_Mouse3DController_hpp_ +#define slic3r_Mouse3DController_hpp_ + +// Enabled debug output to console and extended imgui dialog +#define ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT 0 + +#include "libslic3r/Point.hpp" + +#include "hidapi.h" + +#include +#include +#include +#include +#include + +namespace Slic3r { +namespace GUI { + +struct Camera; + +class Mouse3DController +{ + class State + { + public: + static const double DefaultTranslationScale; + static const double MaxTranslationDeadzone; + static const double DefaultTranslationDeadzone; + static const float DefaultRotationScale; + static const float MaxRotationDeadzone; + static const float DefaultRotationDeadzone; + + private: + template + struct CustomParameters + { + Number scale; + Number deadzone; + + CustomParameters(Number scale, Number deadzone) : scale(scale), deadzone(deadzone) {} + }; + + template + struct InputQueue + { + size_t max_size; + std::queue queue; + + // The default value of 5 for max_size seems to work fine on all platforms + // The effects of changing this value can be tested by setting ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT to 1 + // and playing with the imgui dialog which shows by pressing CTRL+M + InputQueue() : max_size(5) {} + }; + + InputQueue m_translation; + InputQueue m_rotation; + std::queue m_buttons; + + bool m_buttons_enabled; + + CustomParameters m_translation_params; + CustomParameters m_rotation_params; + + // When the 3Dconnexion driver is running the system gets, by default, mouse wheel events when rotations around the X axis are detected. + // We want to filter these out because we are getting the data directly from the device, bypassing the driver, and those mouse wheel events interfere + // by triggering unwanted zoom in/out of the scene + // The following variable is used to count the potential mouse wheel events triggered and is updated by: + // Mouse3DController::collect_input() through the call to the append_rotation() method + // GLCanvas3D::on_mouse_wheel() through the call to the process_mouse_wheel() method + // GLCanvas3D::on_idle() through the call to the apply() method + unsigned int m_mouse_wheel_counter; + +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + size_t m_translation_queue_max_size; + size_t m_rotation_queue_max_size; + size_t m_buttons_queue_max_size; +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + + public: + State(); + + void append_translation(const Vec3d& translation); + void append_rotation(const Vec3f& rotation); + void append_button(unsigned int id); + + bool has_translation() const { return !m_translation.queue.empty(); } + bool has_rotation() const { return !m_rotation.queue.empty(); } + bool has_button() const { return !m_buttons.empty(); } + + bool process_mouse_wheel(); + + double get_translation_scale() const { return m_translation_params.scale; } + void set_translation_scale(double scale) { m_translation_params.scale = scale; } + + float get_rotation_scale() const { return m_rotation_params.scale; } + void set_rotation_scale(float scale) { m_rotation_params.scale = scale; } + + double get_translation_deadzone() const { return m_translation_params.deadzone; } + void set_translation_deadzone(double deadzone) { m_translation_params.deadzone = deadzone; } + + float get_rotation_deadzone() const { return m_rotation_params.deadzone; } + void set_rotation_deadzone(float deadzone) { m_rotation_params.deadzone = deadzone; } + +#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + Vec3d get_translation() const { return has_translation() ? m_translation.queue.front() : Vec3d::Zero(); } + Vec3f get_rotation() const { return has_rotation() ? m_rotation.queue.front() : Vec3f::Zero(); } + unsigned int get_button() const { return has_button() ? m_buttons.front() : 0; } + + unsigned int get_translation_queue_size() const { return (unsigned int)m_translation.queue.size(); } + unsigned int get_rotation_queue_size() const { return (unsigned int)m_rotation.queue.size(); } + unsigned int get_buttons_queue_size() const { return (unsigned int)m_buttons.size(); } + + size_t get_translation_queue_max_size() const { return m_translation_queue_max_size; } + size_t get_rotation_queue_max_size() const { return m_rotation_queue_max_size; } + size_t get_buttons_queue_max_size() const { return m_buttons_queue_max_size; } +#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT + + size_t get_queues_max_size() const { return m_translation.max_size; } + void set_queues_max_size(size_t size); + + // return true if any change to the camera took place + bool apply(Camera& camera); + }; + + bool m_initialized; + mutable State m_state; + std::mutex m_mutex; + std::thread m_thread; + hid_device* m_device; + std::string m_device_str; + bool m_running; + bool m_settings_dialog; + std::chrono::time_point m_last_time; + +public: + Mouse3DController(); + + void init(); + void shutdown(); + + bool is_device_connected() const { return m_device != nullptr; } + bool is_running() const { return m_running; } + + bool process_mouse_wheel() { std::lock_guard lock(m_mutex); return m_state.process_mouse_wheel(); } + + bool apply(Camera& camera); + + bool is_settings_dialog_shown() const { return m_settings_dialog; } + void show_settings_dialog(bool show) { m_settings_dialog = show && is_running(); } + void render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const; + +private: + bool connect_device(); + void disconnect_device(); + void start(); + void stop() { m_running = false; } + + // secondary thread methods + void run(); + void collect_input(); + + typedef std::array DataPacket; + bool handle_packet(const DataPacket& packet); + bool handle_wireless_packet(const DataPacket& packet); + bool handle_packet_translation(const DataPacket& packet); + bool handle_packet_rotation(const DataPacket& packet, unsigned int first_byte); + bool handle_packet_button(const DataPacket& packet, unsigned int packet_size); +}; + +} // namespace GUI +} // namespace Slic3r + +#endif // slic3r_Mouse3DController_hpp_ + diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 409e9a11e..614045d16 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -65,6 +65,7 @@ #include "GUI_Preview.hpp" #include "3DBed.hpp" #include "Camera.hpp" +#include "Mouse3DController.hpp" #include "Tab.hpp" #include "PresetBundle.hpp" #include "BackgroundSlicingProcess.hpp" @@ -1387,9 +1388,6 @@ struct Plater::priv Slic3r::Model model; PrinterTechnology printer_technology = ptFFF; Slic3r::GCodePreviewData gcode_preview_data; -#if ENABLE_THUMBNAIL_GENERATOR - std::vector thumbnail_data; -#endif // ENABLE_THUMBNAIL_GENERATOR // GUI elements wxSizer* panel_sizer{ nullptr }; @@ -1398,6 +1396,7 @@ struct Plater::priv Sidebar *sidebar; Bed3D bed; Camera camera; + Mouse3DController mouse3d_controller; View3D* view3D; GLToolbar view_toolbar; Preview *preview; @@ -1946,6 +1945,7 @@ struct Plater::priv #if ENABLE_THUMBNAIL_GENERATOR void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool transparent_background); + void generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background); #endif // ENABLE_THUMBNAIL_GENERATOR void msw_rescale_object_menu(); @@ -2016,7 +2016,15 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) background_process.set_sla_print(&sla_print); background_process.set_gcode_preview_data(&gcode_preview_data); #if ENABLE_THUMBNAIL_GENERATOR - background_process.set_thumbnail_data(&thumbnail_data); + background_process.set_thumbnail_cb([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background) + { + std::packaged_task task([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background) { + generate_thumbnails(thumbnails, sizes, printable_only, parts_only, transparent_background); + }); + std::future result = task.get_future(); + wxTheApp->CallAfter([&]() { task(thumbnails, sizes, printable_only, parts_only, transparent_background); }); + result.wait(); + }); #endif // ENABLE_THUMBNAIL_GENERATOR background_process.set_slicing_completed_event(EVT_SLICING_COMPLETED); background_process.set_finished_event(EVT_PROCESS_COMPLETED); @@ -2087,6 +2095,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D_canvas->Bind(EVT_GLCANVAS_RESETGIZMOS, [this](SimpleEvent&) { reset_all_gizmos(); }); view3D_canvas->Bind(EVT_GLCANVAS_UNDO, [this](SimpleEvent&) { this->undo(); }); view3D_canvas->Bind(EVT_GLCANVAS_REDO, [this](SimpleEvent&) { this->redo(); }); +#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE + view3D_canvas->Bind(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, [this](SimpleEvent&) { this->view3D->get_canvas3d()->reset_layer_height_profile(); }); + view3D_canvas->Bind(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, [this](Event& evt) { this->view3D->get_canvas3d()->adaptive_layer_height_profile(evt.data); }); + view3D_canvas->Bind(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, [this](HeightProfileSmoothEvent& evt) { this->view3D->get_canvas3d()->smooth_layer_height_profile(evt.data); }); +#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE // 3DScene/Toolbar: view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this); @@ -2136,12 +2149,16 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) // updates camera type from .ini file camera.set_type(get_config("use_perspective_camera")); + mouse3d_controller.init(); + // Initialize the Undo / Redo stack with a first snapshot. this->take_snapshot(_(L("New Project"))); } Plater::priv::~priv() { + mouse3d_controller.shutdown(); + if (config != nullptr) delete config; } @@ -3064,37 +3081,6 @@ bool Plater::priv::restart_background_process(unsigned int state) ( ((state & UPDATE_BACKGROUND_PROCESS_FORCE_RESTART) != 0 && ! this->background_process.finished()) || (state & UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT) != 0 || (state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 ) ) { -#if ENABLE_THUMBNAIL_GENERATOR - if (((state & UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT) == 0) && - (this->background_process.state() != BackgroundSlicingProcess::STATE_RUNNING)) - { - // update thumbnail data - const std::vector &thumbnail_sizes = this->background_process.current_print()->full_print_config().option("thumbnails")->values; - if (this->printer_technology == ptFFF) - { - // for ptFFF we need to generate the thumbnails before the export of gcode starts - this->thumbnail_data.clear(); - for (const Vec2d &sized : thumbnail_sizes) - { - this->thumbnail_data.push_back(ThumbnailData()); - Point size(sized); // round to ints - generate_thumbnail(this->thumbnail_data.back(), size.x(), size.y(), true, true, false); - } - } - else if (this->printer_technology == ptSLA) - { - // for ptSLA generate thumbnails without supports and pad (not yet calculated) - // to render also supports and pad see on_slicing_update() - this->thumbnail_data.clear(); - for (const Vec2d &sized : thumbnail_sizes) - { - this->thumbnail_data.push_back(ThumbnailData()); - Point size(sized); // round to ints - generate_thumbnail(this->thumbnail_data.back(), size.x(), size.y(), true, true, false); - } - } - } -#endif // ENABLE_THUMBNAIL_GENERATOR // The print is valid and it can be started. if (this->background_process.start()) { this->statusbar()->set_cancel_callback([this]() { @@ -3193,9 +3179,13 @@ void Plater::priv::reload_from_disk() for (unsigned int idx : selected_volumes_idxs) { const GLVolume* v = selection.get_volume(idx); - int o_idx = v->object_idx(); int v_idx = v->volume_idx(); - selected_volumes.push_back({ o_idx, v_idx }); + if (v_idx >= 0) + { + int o_idx = v->object_idx(); + if ((0 <= o_idx) && (o_idx < (int)model.objects.size())) + selected_volumes.push_back({ o_idx, v_idx }); + } } std::sort(selected_volumes.begin(), selected_volumes.end()); selected_volumes.erase(std::unique(selected_volumes.begin(), selected_volumes.end()), selected_volumes.end()); @@ -3341,6 +3331,7 @@ void Plater::priv::set_current_panel(wxPanel* panel) } else view3D->reload_scene(true); } + // sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably) view3D->set_as_dirty(); view_toolbar.select_item("3D"); @@ -3355,6 +3346,7 @@ void Plater::priv::set_current_panel(wxPanel* panel) this->q->reslice(); // keeps current gcode preview, if any preview->reload_print(true); + preview->set_canvas_as_dirty(); view_toolbar.select_item("Preview"); } @@ -3432,25 +3424,6 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) } else if (evt.status.flags & PrintBase::SlicingStatus::RELOAD_SLA_PREVIEW) { // Update the SLA preview. Only called if not RELOAD_SLA_SUPPORT_POINTS, as the block above will refresh the preview anyways. this->preview->reload_print(); - - // uncomment the following lines if you want to render into the thumbnail also supports and pad for SLA printer -/* -#if ENABLE_THUMBNAIL_GENERATOR - // update thumbnail data - // for ptSLA generate the thumbnail after supports and pad have been calculated to have them rendered - if ((this->printer_technology == ptSLA) && (evt.status.percent == -3)) - { - const std::vector& thumbnail_sizes = this->background_process.current_print()->full_print_config().option("thumbnails")->values; - this->thumbnail_data.clear(); - for (const Vec2d &sized : thumbnail_sizes) - { - this->thumbnail_data.push_back(ThumbnailData()); - Point size(sized); // round to ints - generate_thumbnail(this->thumbnail_data.back(), size.x(), size.y(), true, false, false); - } - } -#endif // ENABLE_THUMBNAIL_GENERATOR -*/ } } @@ -3681,6 +3654,19 @@ void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsig { view3D->get_canvas3d()->render_thumbnail(data, w, h, printable_only, parts_only, transparent_background); } + +void Plater::priv::generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool transparent_background) +{ + thumbnails.clear(); + for (const Vec2d& size : sizes) + { + thumbnails.push_back(ThumbnailData()); + Point isize(size); // round to ints + generate_thumbnail(thumbnails.back(), isize.x(), isize.y(), printable_only, parts_only, transparent_background); + if (!thumbnails.back().is_valid()) + thumbnails.pop_back(); + } +} #endif // ENABLE_THUMBNAIL_GENERATOR void Plater::priv::msw_rescale_object_menu() @@ -4193,6 +4179,7 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator // 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. @@ -5257,6 +5244,16 @@ const Camera& Plater::get_camera() const return p->camera; } +const Mouse3DController& Plater::get_mouse3d_controller() const +{ + return p->mouse3d_controller; +} + +Mouse3DController& Plater::get_mouse3d_controller() +{ + return p->mouse3d_controller; +} + bool Plater::can_delete() const { return p->can_delete(); } bool Plater::can_delete_all() const { return p->can_delete_all(); } bool Plater::can_increase_instances() const { return p->can_increase_instances(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 57d6ae2c0..5c36dbf5e 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -41,6 +41,7 @@ class ObjectSettings; class ObjectLayers; class ObjectList; class GLCanvas3D; +class Mouse3DController; using t_optgroups = std::vector >; @@ -261,6 +262,8 @@ public: void msw_rescale(); const Camera& get_camera() const; + const Mouse3DController& get_mouse3d_controller() const; + Mouse3DController& get_mouse3d_controller(); // ROII wrapper for suppressing the Undo / Redo snapshot to be taken. class SuppressSnapshots diff --git a/tests/libslic3r/test_geometry.cpp b/tests/libslic3r/test_geometry.cpp index 4a800b3d3..6f2bd1c39 100644 --- a/tests/libslic3r/test_geometry.cpp +++ b/tests/libslic3r/test_geometry.cpp @@ -263,6 +263,42 @@ SCENARIO("Path chaining", "[Geometry]") { } } } + GIVEN("Gyroid infill end points") { + Polylines polylines = { + { {28122608, 3221037}, {27919139, 56036027} }, + { {33642863, 3400772}, {30875220, 56450360} }, + { {34579315, 3599827}, {35049758, 55971572} }, + { {26483070, 3374004}, {23971830, 55763598} }, + { {38931405, 4678879}, {38740053, 55077714} }, + { {20311895, 5015778}, {20079051, 54551952} }, + { {16463068, 6773342}, {18823514, 53992958} }, + { {44433771, 7424951}, {42629462, 53346059} }, + { {15697614, 7329492}, {15350896, 52089991} }, + { {48085792, 10147132}, {46435427, 50792118} }, + { {48828819, 10972330}, {49126582, 48368374} }, + { {9654526, 12656711}, {10264020, 47691584} }, + { {5726905, 18648632}, {8070762, 45082416} }, + { {54818187, 39579970}, {52974912, 43271272} }, + { {4464342, 37371742}, {5027890, 39106220} }, + { {54139746, 18417661}, {55177987, 38472580} }, + { {56527590, 32058461}, {56316456, 34067185} }, + { {3303988, 29215290}, {3569863, 32985633} }, + { {56255666, 25025857}, {56478310, 27144087} }, + { {4300034, 22805361}, {3667946, 25752601} }, + { {8266122, 14250611}, {6244813, 17751595} }, + { {12177955, 9886741}, {10703348, 11491900} } + }; + Polylines chained = chain_polylines(polylines); + THEN("Chained taking the shortest path") { + double connection_length = 0.; + for (size_t i = 1; i < chained.size(); ++i) { + const Polyline &pl1 = chained[i - 1]; + const Polyline &pl2 = chained[i]; + connection_length += (pl2.first_point() - pl1.last_point()).cast().norm(); + } + REQUIRE(connection_length < 85206000.); + } + } GIVEN("Loop pieces") { Point a { 2185796, 19058485 }; Point b { 3957902, 18149382 };