diff --git a/CMakeLists.txt b/CMakeLists.txt index 70b7ed567..e19d3147b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,14 @@ set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux") set(IS_CROSS_COMPILE FALSE) +if (SLIC3R_STATIC) + # Prefer config scripts over find modules. This is helpful when building with + # the static dependencies. Many libraries have their own export scripts + # while having a Find module in standard cmake installation. + # (e.g. CURL) + set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON) +endif () + if (APPLE) set(CMAKE_FIND_FRAMEWORK LAST) set(CMAKE_FIND_APPBUNDLE LAST) @@ -106,6 +114,8 @@ if (MSVC) # C4244: 'conversion' conversion from 'type1' to 'type2', possible loss of data. An integer type is converted to a smaller integer type. # C4267: The compiler detected a conversion from size_t to a smaller type. add_compile_options(/wd4244 /wd4267) + # Enforce strict C++ conformance, so our code that compiles on MSVC also compiles on GCC and clang. + add_compile_options(/permissive-) endif () if (MINGW) @@ -435,6 +445,14 @@ include_directories(BEFORE SYSTEM ${EIGEN3_INCLUDE_DIR}) # no matter what. find_package(EXPAT REQUIRED) +add_library(libexpat INTERFACE) + +if (TARGET EXPAT::EXPAT ) + target_link_libraries(libexpat INTERFACE EXPAT::EXPAT) +elseif(TARGET expat::expat) + target_link_libraries(libexpat INTERFACE expat::expat) +endif () + find_package(PNG REQUIRED) set(OpenGL_GL_PREFERENCE "LEGACY") diff --git a/deps/wxWidgets/wxWidgets.cmake b/deps/wxWidgets/wxWidgets.cmake index 29374974b..8056a01d3 100644 --- a/deps/wxWidgets/wxWidgets.cmake +++ b/deps/wxWidgets/wxWidgets.cmake @@ -13,8 +13,8 @@ if (UNIX AND NOT APPLE) # wxWidgets will not use char as the underlying type for endif() prusaslicer_add_cmake_project(wxWidgets - URL https://github.com/prusa3d/wxWidgets/archive/2a0b365df947138c513a888d707d46248d78a341.zip - URL_HASH SHA256=9ab05cd5179196fad4ae702c78eaae9418e73a402cfd390f7438e469b13eb735 + URL https://github.com/prusa3d/wxWidgets/archive/34b524f8d5134a40a90d93a16360d533af2676ae.zip + URL_HASH SHA256=e76ca0dd998905c4dbb86f41f264e6e0468504dc2398f7e7e3bba8dc37de2f45 DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG dep_NanoSVG CMAKE_ARGS -DwxBUILD_PRECOMP=ON diff --git a/resources/icons/collapse_btn.svg b/resources/icons/collapse_btn.svg new file mode 100644 index 000000000..4ee221a44 --- /dev/null +++ b/resources/icons/collapse_btn.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/icons/cut_.svg b/resources/icons/cut_.svg new file mode 100644 index 000000000..a7f462bb9 --- /dev/null +++ b/resources/icons/cut_.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/icons/cut_connectors.svg b/resources/icons/cut_connectors.svg new file mode 100644 index 000000000..8cd03aa06 --- /dev/null +++ b/resources/icons/cut_connectors.svg @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/resources/icons/expand_btn.svg b/resources/icons/expand_btn.svg new file mode 100644 index 000000000..32d7f9959 --- /dev/null +++ b/resources/icons/expand_btn.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/resources/localization/ko/PrusaSlicer.mo b/resources/localization/ko/PrusaSlicer.mo index cfb41c850..a1c7f8756 100644 Binary files a/resources/localization/ko/PrusaSlicer.mo and b/resources/localization/ko/PrusaSlicer.mo differ diff --git a/resources/localization/ko/PrusaSlicer_ko_KR.po b/resources/localization/ko/PrusaSlicer_ko_KR.po index d4667650b..cd5e0fb4e 100644 --- a/resources/localization/ko/PrusaSlicer_ko_KR.po +++ b/resources/localization/ko/PrusaSlicer_ko_KR.po @@ -73,7 +73,7 @@ msgid "" msgstr "" "Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, " "Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Vojtech Bubnik and " -"numerous others. 한국어 번역 울산에테르, 밤송이직박구리" +"numerous others. 한국어 번역 울산에테르, 밤송이직박구리,brightstone song" #: src/slic3r/GUI/AboutDialog.cpp:310 msgid "Copy Version Info" @@ -93,13 +93,13 @@ msgstr "" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:84 #, boost-format msgid "PrusaSlicer has encountered a fatal error: \"%1%\"" -msgstr "" +msgstr "슬라이서에 치명적인 오류가 발생했습니다: \"%1%\"" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:85 msgid "" "Please save your project and restart PrusaSlicer. We would be glad if you " "reported the issue." -msgstr "" +msgstr "작업물을 저장하시고 슬라이서를 재시작하시기 바랍니다. 이 이슈를 보고해주시면 감사하겠습니다." #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:162 #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:204 @@ -109,27 +109,27 @@ msgstr "슬라이스 완료" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:199 #, boost-format msgid "Masked SLA file exported to %1%" -msgstr "마스크 된 SLA 파일을 %1%로 내보냅니" +msgstr "마스크 된 SLA 파일을 %1%로 내보냅니다." #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:286 msgid "Access violation" -msgstr "" +msgstr "접근 위반" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:288 msgid "Illegal instruction" -msgstr "" +msgstr "잘못된 명령" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:290 msgid "Divide by zero" -msgstr "" +msgstr "0" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:292 msgid "Overflow" -msgstr "" +msgstr "오버플로우" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:294 msgid "Underflow" -msgstr "" +msgstr "언더플로우" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:297 msgid "Floating reserved operand" @@ -137,7 +137,7 @@ msgstr "" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:300 msgid "Stack overflow" -msgstr "" +msgstr "스택 오버플로우" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:659 #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:726 @@ -147,7 +147,7 @@ msgstr "포스트 프로세싱 스크립트" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:690 #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:710 msgid "Unknown error occured during exporting G-code." -msgstr "" +msgstr "G고드 제작중 알 수 없는 오류가 발생" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:695 #, boost-format @@ -189,7 +189,7 @@ msgstr "" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:715 #, boost-format msgid "G-code file exported to %1%" -msgstr "%1%로 내보낸 G 코드 파일" +msgstr "%1%로 G코드 파일이 저장되었습니다." #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:729 msgid "Copying of the temporary G-code to the output G-code failed" @@ -218,13 +218,13 @@ msgstr "노즐 직경" #: src/slic3r/GUI/BedShapeDialog.cpp:49 msgid "Size in X and Y of the rectangular plate." -msgstr "사각 플레이트 X 및 Y 크기." +msgstr "사각형 베드의 X와 Y크기." #: src/slic3r/GUI/BedShapeDialog.cpp:58 msgid "" "Distance of the 0,0 G-code coordinate from the front left corner of the " "rectangle." -msgstr "사각 전면 왼쪽 모서리에서 원저(0, 0) G-code 좌표 거리입니다." +msgstr "전면부 왼쪽 모서리부터 원점까지의(0, 0) G-code 좌표 거리입니다." #: src/slic3r/GUI/BedShapeDialog.cpp:64 src/slic3r/GUI/ConfigWizard.cpp:262 #: src/slic3r/GUI/ConfigWizard.cpp:1476 src/slic3r/GUI/ConfigWizard.cpp:1490 @@ -281,7 +281,7 @@ msgstr "mm" msgid "" "Diameter of the print bed. It is assumed that origin (0,0) is located in the " "center." -msgstr "인쇄 배드의 직경. 원점 (0,0) 은 중재봉선에 있다고 가정합니다." +msgstr "인쇄 배드의 직경. 원점 (0,0) 은 중앙에 있다고 가정됩니다." #: src/slic3r/GUI/BedShapeDialog.cpp:79 msgid "Rectangular" @@ -303,7 +303,7 @@ msgstr "모양" #: src/slic3r/GUI/BedShapeDialog.cpp:203 msgid "Load shape from STL..." -msgstr "STL파일 로드." +msgstr "STL파일 로드하기." #: src/slic3r/GUI/BedShapeDialog.cpp:249 src/slic3r/GUI/GCodeViewer.cpp:3709 #: src/slic3r/GUI/MainFrame.cpp:2147 @@ -325,7 +325,7 @@ msgstr "제거" #: src/slic3r/GUI/BedShapeDialog.cpp:317 src/slic3r/GUI/BedShapeDialog.cpp:388 msgid "Not found:" -msgstr "" +msgstr "찾지 못함" #: src/slic3r/GUI/BedShapeDialog.cpp:344 msgid "Model" @@ -346,25 +346,25 @@ msgstr "오류! 잘못된 모델" #: src/slic3r/GUI/BedShapeDialog.cpp:533 msgid "The selected file contains no geometry." -msgstr "선택한 파일에 없는 형상이 있습니다." +msgstr "선택한 파일에는 형상이 존재하지 않습니다." #: src/slic3r/GUI/BedShapeDialog.cpp:537 msgid "" "The selected file contains several disjoint areas. This is not supported." msgstr "" -"선택한 파일은 여러개의 분리 된 영역을 포함 되어 있어 지원 되지 않습니다." +"이 파일은 몇몇 끊어진 부분이 있습니다. 지원이 불가능합니다." #: src/slic3r/GUI/BedShapeDialog.cpp:552 msgid "Choose a file to import bed texture from (PNG/SVG):" -msgstr "(PNG /SVG)에서 배드 텍스처를 가져올 파일을 선택합니다." +msgstr "베드 텍스처를 가져올 (PNG /SVG)파일을 선택하십시오." #: src/slic3r/GUI/BedShapeDialog.cpp:574 msgid "Choose an STL file to import bed model from:" -msgstr "다음에서 베드 모델을 가져올 STL 파일을 선택합니다:" +msgstr "베드 모델을 가져올 STL 파일을 선택하십시오:" #: src/slic3r/GUI/BedShapeDialog.hpp:95 src/slic3r/GUI/ConfigWizard.cpp:1396 msgid "Bed Shape" -msgstr "배드 모양" +msgstr "베드 모양" #: src/slic3r/GUI/BonjourDialog.cpp:55 msgid "Network lookup" @@ -376,7 +376,7 @@ msgstr "주소" #: src/slic3r/GUI/BonjourDialog.cpp:73 msgid "Hostname" -msgstr "호스트이름" +msgstr "호스트 이름" #: src/slic3r/GUI/BonjourDialog.cpp:74 msgid "Service name" @@ -388,7 +388,7 @@ msgstr "옥토프린트 버전" #: src/slic3r/GUI/BonjourDialog.cpp:224 msgid "Searching for devices" -msgstr "디바이스 검색" +msgstr "디바이스 검색중" #: src/slic3r/GUI/BonjourDialog.cpp:231 msgid "Finished" @@ -406,7 +406,7 @@ msgstr "이 값은 시스템 값과 같습니다" msgid "" "Value was changed and is not equal to the system value or the last saved " "preset" -msgstr "값이 변경 되었고, 시스템 값 또는 마지막으로 저장된 설정값과 다릅니다." +msgstr "수치가 변경 되었고, 시스템 값 또는 마지막으로 저장된 설정값과 다릅니다." #: src/slic3r/GUI/ButtonsDescription.cpp:62 msgid "Buttons And Text Colors Description" @@ -418,6 +418,9 @@ msgid "" "\n" "The layer height will be reset to 0.01." msgstr "" +"레이어 높이가 유호하지 않습니다.\n" +"\n" +"높이가 0.01로 재설정됩니다." #: src/slic3r/GUI/ConfigManipulation.cpp:50 #: src/slic3r/GUI/GUI_ObjectLayers.cpp:29 src/slic3r/GUI/Tab.cpp:1449 @@ -431,6 +434,9 @@ msgid "" "\n" "The first layer height will be reset to 0.01." msgstr "" +"첫 레이어 높이가 유호하지 않습니다.\n" +"\n" +"첫 레이어 높이가 0.01로 재설정됩니다." #: src/slic3r/GUI/ConfigManipulation.cpp:62 src/libslic3r/PrintConfig.cpp:1227 msgid "First layer height" @@ -446,14 +452,21 @@ msgid "" "- Ensure vertical shell thickness enabled\n" "- Detect thin walls disabled" msgstr "" +"꽃병 모드는 다음과 같은 설정이 필요합니다:\n" +"- 외벽 1\n" +"- 상부 레이어 없음\n" +"- 내부 밀도 0%\n" +"- 서포트 없음\n" +"- 외벽 두께 보장 활성화\n" +"- 얇은 외벽 감지 비활성화" #: src/slic3r/GUI/ConfigManipulation.cpp:90 msgid "Shall I adjust those settings in order to enable Spiral Vase?" -msgstr "나선형 꽃병을 활성화하기 위해 이러한 설정을 조정해야 합니까?" +msgstr "꽃병 모드를 활성화하기 위해 이 설정들을 변경하시겠습니까?" #: src/slic3r/GUI/ConfigManipulation.cpp:91 msgid "Spiral Vase" -msgstr "스파이럴 바이스" +msgstr "꾳병 모드" #: src/slic3r/GUI/ConfigManipulation.cpp:121 msgid "" @@ -463,14 +476,14 @@ msgid "" "(both support_material_extruder and support_material_interface_extruder need " "to be set to 0)." msgstr "" -"와이프 타워(프라임 타워)는 현재 비수용성 지원만 지원합니다.\n" -"공구 교환을 트리거하지 않고 현재 압출기로 인쇄된 경우\n" -"(support_material_extruder support_material_interface_extruder 모두 0으로 설" +"와이프 타워(프라임 타워)는 현재 비수용성 서포트만 지원합니다.\n" +"툴체인지를 사용하지 않고 현재 노즐로 출력시\n" +"(support_material_extruder support_material_interface_extruder를 모두 0으로 설" "정해야 합니다)." #: src/slic3r/GUI/ConfigManipulation.cpp:125 msgid "Shall I adjust those settings in order to enable the Wipe Tower?" -msgstr "와이프 타워를 활성화하기 위해 이러한 설정을 조정해야 합니까?" +msgstr "와이프 타워를 활성화하기 위해 이 설정들을 변경하시겠습니까?" #: src/slic3r/GUI/ConfigManipulation.cpp:126 #: src/slic3r/GUI/ConfigManipulation.cpp:146 @@ -482,37 +495,37 @@ msgid "" "For the Wipe Tower to work with the soluble supports, the support layers\n" "need to be synchronized with the object layers." msgstr "" -"와이프 타워(프라임 타워)가 가용성 지지체와 함께 작동 하려면 서포트 레이어를 " +"와이프 타워(프라임 타워)를 수용성 서포트와 함께 사용하기 위해서는 서포트 레이어를 " "객체(object) 레이어와 동기화 해야 합니다." #: src/slic3r/GUI/ConfigManipulation.cpp:145 msgid "Shall I synchronize support layers in order to enable the Wipe Tower?" -msgstr "와이프 타워를 활성화하기 위해 지원 레이어를 동기화해야 합니까?" +msgstr "와이프 타워를 사용하기 위해 서포트 레이어 설정을 변경하시겠습니까?" #: src/slic3r/GUI/ConfigManipulation.cpp:164 msgid "" "Supports work better, if the following feature is enabled:\n" "- Detect bridging perimeters" msgstr "" -"다음 기능이 활성화된 경우 더 나은 작업을 지원합니다.\n" -"- 브리징 경계를 감지" +"서포트는 다음 기능이 활성화되어 있으면 더 효율적으로 생성됩니다.\n" +"- 브릿징 동작 감지" #: src/slic3r/GUI/ConfigManipulation.cpp:167 msgid "Shall I adjust those settings for supports?" -msgstr "지원에 대한 설정을 조정해야 합니까?" +msgstr "서포트 세팅을 변경하시겠습니까?" #: src/slic3r/GUI/ConfigManipulation.cpp:168 msgid "Support Generator" -msgstr "서포트 생성" +msgstr "서포트 생성기" #: src/slic3r/GUI/ConfigManipulation.cpp:195 #, boost-format msgid "The %1% infill pattern is not supposed to work at 100%% density." -msgstr "%1% 채우기 패턴은 100%% 밀도로 작동하도록 되어 있지 않습니다." +msgstr "%1% 패턴은 100%% 밀도로 작동하도록 되어 있지 않습니다." #: src/slic3r/GUI/ConfigManipulation.cpp:198 msgid "Shall I switch to rectilinear fill pattern?" -msgstr "직선 채우기 패턴으로 전환해야 합니까?" +msgstr "직선 패턴으로 전환하시겠습니까?" #: src/slic3r/GUI/ConfigManipulation.cpp:199 #: src/slic3r/GUI/GUI_Factories.cpp:55 src/slic3r/GUI/GUI_Factories.cpp:128 @@ -525,19 +538,19 @@ msgstr "직선 채우기 패턴으로 전환해야 합니까?" #: src/libslic3r/PrintConfig.cpp:1493 src/libslic3r/PrintConfig.cpp:1512 #: src/libslic3r/PrintConfig.cpp:2333 src/libslic3r/PrintConfig.cpp:2350 msgid "Infill" -msgstr "인필(채움)" +msgstr "인필" #: src/slic3r/GUI/ConfigManipulation.cpp:336 msgid "Head penetration should not be greater than the head width." -msgstr "헤드 관통은 헤드 폭 보다 크지 않아야 합니다." +msgstr "헤드 접촉길이는 헤드의 지름보다 클 수 없습니다." #: src/slic3r/GUI/ConfigManipulation.cpp:338 msgid "Invalid Head penetration" -msgstr "잘못된 헤드 관통" +msgstr "헤드 관통 불가" #: src/slic3r/GUI/ConfigManipulation.cpp:349 msgid "Pinhead diameter should be smaller than the pillar diameter." -msgstr "핀헤드 지름은 기둥 지름 보다 작아야 합니다." +msgstr "핀헤드 지름은 기둥 지름보다 클 수 ." #: src/slic3r/GUI/ConfigManipulation.cpp:351 msgid "Invalid pinhead diameter" @@ -596,7 +609,7 @@ msgstr "프린터" #: src/slic3r/GUI/ConfigSnapshotDialog.cpp:75 src/slic3r/GUI/Tab.cpp:1366 msgid "vendor" -msgstr "제조 회사" +msgstr "제조사" #: src/slic3r/GUI/ConfigSnapshotDialog.cpp:75 msgid "version" @@ -641,7 +654,7 @@ msgstr "대체 노즐:" #: src/slic3r/GUI/ConfigWizard.cpp:330 msgid "All standard" -msgstr "모두 표준설정" +msgstr "전부 표준설정으로" #: src/slic3r/GUI/ConfigWizard.cpp:330 msgid "Standard" @@ -680,12 +693,12 @@ 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 "" -"안녕하세요 ,%s에 오신 것을 환영 합니다! 이 %s는 초기 구성에 도움이 됩니다. " -"몇 가지 설정만으로 인쇄 준비가 될 것입니다." +"안녕하세요 ,%s에 오신 것을 환영 합니다! 이 %s는 초기 설정에 도움이 됩니다. " +"몇 가지 설정 후 프린팅할 준비가 될 것입니다." #: src/slic3r/GUI/ConfigWizard.cpp:495 msgid "Remove user profiles (a snapshot will be taken beforehand)" -msgstr "" +msgstr "유저 프로필 제거(제거 전 스냅샷이 생성될 것입니다.)" #: src/slic3r/GUI/ConfigWizard.cpp:498 msgid "" @@ -696,7 +709,7 @@ msgstr "" #: src/slic3r/GUI/ConfigWizard.cpp:550 #, c-format, boost-format msgid "%s Family" -msgstr "%s의 가족들" +msgstr "%s사 제품들" #: src/slic3r/GUI/ConfigWizard.cpp:640 msgid "Printer:" @@ -729,7 +742,7 @@ msgstr "필라멘트" #: src/slic3r/GUI/ConfigWizard.cpp:752 msgid "SLA materials" -msgstr "" +msgstr "SLA 레진" #: src/slic3r/GUI/ConfigWizard.cpp:755 #, boost-format @@ -754,19 +767,19 @@ msgstr "" #: src/slic3r/GUI/ConfigWizard.cpp:1175 msgid "Custom Printer Setup" -msgstr "사용자 지정 프린터 설정" +msgstr "커스텀 프린터 설정" #: src/slic3r/GUI/ConfigWizard.cpp:1175 msgid "Custom Printer" -msgstr "사용자 정의 프린터" +msgstr "커스텀 프린터" #: src/slic3r/GUI/ConfigWizard.cpp:1177 msgid "Define a custom printer profile" -msgstr "사용자 정의 프린터 프로필" +msgstr "커스텀 프린터 세팅 입력" #: src/slic3r/GUI/ConfigWizard.cpp:1179 msgid "Custom profile name:" -msgstr "사용자 정의 프로필 명칭:" +msgstr "커스텀 프로필 명칭:" #: src/slic3r/GUI/ConfigWizard.cpp:1206 msgid "Automatic updates" @@ -788,9 +801,9 @@ msgid "" "application startup (never during program usage). This is only a " "notification mechanisms, no automatic installation is done." msgstr "" -"활성화 된 경우 %s은 온라인의 새 버전을 확인합니다. 새 버전을 사용할 수 있게 " -"되면, 다음 응용 프로그램 시작시 알림이 표시됩니다 (프로그램 사용 중에는 절대" -"로 사용하지 마십시오).이것은 단순한 알림 일뿐 자동으로 설치가 되지 않습니다." +"활성화시 %s는 최신버전을 온라인에서 확인합니다. 새 버전이 있을시 " +"프로그램이 켜질 때 알림이 표시됩니다 (켜져있을 때는 알림이" +"표시되지 않습니다).자동으로 설치는 되지 않습니다." #: src/slic3r/GUI/ConfigWizard.cpp:1224 src/slic3r/GUI/Preferences.cpp:175 msgid "Update built-in Presets automatically" @@ -877,7 +890,7 @@ msgstr "" #: src/slic3r/GUI/ConfigWizard.cpp:1279 msgid "Simple mode" -msgstr "단순 모드" +msgstr "초보자 모드" #: src/slic3r/GUI/ConfigWizard.cpp:1280 msgid "Advanced mode" @@ -889,20 +902,20 @@ msgstr "전문가 모드" #: src/slic3r/GUI/ConfigWizard.cpp:1287 msgid "The size of the object can be specified in inches" -msgstr "" +msgstr "물체의 크기를 인치로 표시 가능합니다" #: src/slic3r/GUI/ConfigWizard.cpp:1288 msgid "Use inches" -msgstr "" +msgstr "인치 사용" #: src/slic3r/GUI/ConfigWizard.cpp:1322 msgid "Other Vendors" -msgstr "다른 공급 업체" +msgstr "다른 벤더" #: src/slic3r/GUI/ConfigWizard.cpp:1326 #, c-format, boost-format msgid "Pick another vendor supported by %s" -msgstr "%s가 지원하는 다른 공급 업체를 선택하십시오:" +msgstr "%s가 지원하는 다른 벤더를 선택하십시오:" #: src/slic3r/GUI/ConfigWizard.cpp:1357 msgid "Firmware Type" @@ -914,7 +927,7 @@ msgstr "펌웨어" #: src/slic3r/GUI/ConfigWizard.cpp:1361 msgid "Choose the type of firmware used by your printer." -msgstr "프린터에 업로드 할 펌웨어를 선택하세요." +msgstr "프린터가 사용하는 펌웨어를 선택하세요." #: src/slic3r/GUI/ConfigWizard.cpp:1396 msgid "Bed Shape and Size" @@ -922,13 +935,13 @@ msgstr "배드 모양과 크기" #: src/slic3r/GUI/ConfigWizard.cpp:1399 msgid "Set the shape of your printer's bed." -msgstr "프린터 배드모양을 설정하세요." +msgstr "프린터의 배드 모양을 설정하세요." #: src/slic3r/GUI/ConfigWizard.cpp:1433 src/slic3r/GUI/Field.cpp:255 #: src/slic3r/GUI/Field.cpp:324 src/slic3r/GUI/Field.cpp:1561 #: src/slic3r/GUI/GUI_ObjectLayers.cpp:435 msgid "Invalid numeric input." -msgstr "숫자 입력이 잘못 되었습니다." +msgstr "잘못된 수치." #: src/slic3r/GUI/ConfigWizard.cpp:1457 msgid "Filament and Nozzle Diameters" @@ -936,11 +949,11 @@ msgstr "필라멘트와 노즐 크기" #: src/slic3r/GUI/ConfigWizard.cpp:1457 msgid "Print Diameters" -msgstr "인쇄 직경" +msgstr "노즐,필라멘트 직경" #: src/slic3r/GUI/ConfigWizard.cpp:1472 msgid "Enter the diameter of your printer's hot end nozzle." -msgstr "핫 엔드 노즐 직경을 입력하십시오." +msgstr "노즐 직경을 입력하십시오." #: src/slic3r/GUI/ConfigWizard.cpp:1475 msgid "Nozzle Diameter:" @@ -948,15 +961,15 @@ msgstr "노즐 직경:" #: src/slic3r/GUI/ConfigWizard.cpp:1485 msgid "Enter the diameter of your filament." -msgstr "필라멘트의 직경을 입력하십시오." +msgstr "필라멘트 직경을 입력하십시오." #: src/slic3r/GUI/ConfigWizard.cpp:1486 msgid "" "Good precision is required, so use a caliper and do multiple measurements " "along the filament, then compute the average." msgstr "" -"정밀도가 필요하므로 캘리퍼를 사용하여 필라멘트를 따라 여러 번 측정 한 다음 평" -"균을 계산하십시오." +"정확한 수치가 필요하므로 버니어 캘리퍼로 여러번 측정하여" +"평균값을 입력하십시오." #: src/slic3r/GUI/ConfigWizard.cpp:1489 msgid "Filament Diameter:" @@ -964,7 +977,7 @@ msgstr "필라멘트 직경:" #: src/slic3r/GUI/ConfigWizard.cpp:1547 msgid "Nozzle and Bed Temperatures" -msgstr "" +msgstr "노즐, 베드 온도" #: src/slic3r/GUI/ConfigWizard.cpp:1547 msgid "Temperatures" @@ -992,14 +1005,14 @@ msgstr "°C" msgid "" "Enter the bed temperature needed for getting your filament to stick to your " "heated bed." -msgstr "필라멘트가 핫배드에 접착하는데 필요한 온도를 입력하십시오." +msgstr "필라멘트가 온열배드에 안착하는데 필요한 온도를 입력하십시오." #: src/slic3r/GUI/ConfigWizard.cpp:1578 msgid "" "A rule of thumb is 60 °C for PLA and 110 °C for ABS. Leave zero if you have " "no heated bed." msgstr "" -"보통은 PLA의 경우 60 ° C이고 ABS의 경우 110 ° C입니다. 핫배드가 없는 경우에" +"보통 PLA는 60 ° C이고 ABS는 110 ° C입니다. 온열배드가 없는 경우에" "는 0으로 두십시오." #: src/slic3r/GUI/ConfigWizard.cpp:1581 @@ -1008,7 +1021,7 @@ msgstr "배드 온도 :" #: src/slic3r/GUI/ConfigWizard.cpp:2043 src/slic3r/GUI/ConfigWizard.cpp:2915 msgid "SLA Materials" -msgstr "SLA 재료" +msgstr "SLA 레진" #: src/slic3r/GUI/ConfigWizard.cpp:2097 msgid "FFF Technology Printers" @@ -1024,6 +1037,8 @@ msgid "" "Following printer profiles has no default filament: %1%Please select one " "manually." msgstr "" +"프린터 프로필에 기본 필라멘트가 없습니다: %1%하나를 " +"선택하십시오." #: src/slic3r/GUI/ConfigWizard.cpp:2339 #, boost-format @@ -1031,6 +1046,8 @@ msgid "" "Following printer profiles has no default material: %1%Please select one " "manually." msgstr "" +"프린터 프로필에 기본 레진이 없습니다: %1%하나를 " +"선택하십시오." #: src/slic3r/GUI/ConfigWizard.cpp:2340 src/slic3r/GUI/ConfigWizard.cpp:2438 #: src/slic3r/GUI/DoubleSlider.cpp:2522 src/slic3r/GUI/DoubleSlider.cpp:2543 diff --git a/resources/localization/list.txt b/resources/localization/list.txt index bc8c9f272..dc30cdcc8 100644 --- a/resources/localization/list.txt +++ b/resources/localization/list.txt @@ -32,6 +32,7 @@ src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp src/slic3r/GUI/Gizmos/GLGizmosManager.cpp src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp src/slic3r/GUI/GUI.cpp diff --git a/resources/localization/nl/PrusaSlicer.mo b/resources/localization/nl/PrusaSlicer.mo index 097521c94..2d12b74c6 100644 Binary files a/resources/localization/nl/PrusaSlicer.mo and b/resources/localization/nl/PrusaSlicer.mo differ diff --git a/resources/localization/nl/PrusaSlicer_nl.po b/resources/localization/nl/PrusaSlicer_nl.po index 47911b32a..ccce8f9a2 100644 --- a/resources/localization/nl/PrusaSlicer_nl.po +++ b/resources/localization/nl/PrusaSlicer_nl.po @@ -1,18 +1,22 @@ +# 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: 2022-09-05 15:33+0200\n" -"PO-Revision-Date: 2021-12-14 09:56+0100\n" +"POT-Creation-Date: 2022-08-12 10:25+0200\n" +"PO-Revision-Date: 2022-09-27 15:39+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 3.0\n" -"X-Poedit-Basepath: .\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.1.1\n" #: src/slic3r/GUI/AboutDialog.cpp:45 src/slic3r/GUI/AboutDialog.cpp:305 msgid "Portions copyright" @@ -20,7 +24,7 @@ msgstr "Gedeeltelijk auteursrecht" #: src/slic3r/GUI/AboutDialog.cpp:141 src/slic3r/GUI/AboutDialog.cpp:269 msgid "Copyright" -msgstr "Copyright" +msgstr "Auteursrecht" #. TRN "Slic3r _is licensed under the_ License" #: src/slic3r/GUI/AboutDialog.cpp:143 @@ -79,14 +83,14 @@ msgid "" "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 "" -"Fout in %s. Mogelijk komt dit door een tekort aan RAM geheugen. Als u er " -"zeker van bent genoeg RAM geheugen te hebben, kan dit een andere oorzaak " -"hebben. We stellen het op prijs als u het aan ons rapporteert." +"%s heeft een fout opgelopen. Mogelijk komt dit door een tekort aan RAM " +"geheugen. Als u zeker weet genoeg RAM geheugen te hebben, kan dit een andere " +"oorzaak hebben. We stellen het op prijs als u het aan ons rapporteert." #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:84 #, boost-format msgid "PrusaSlicer has encountered a fatal error: \"%1%\"" -msgstr "" +msgstr "PrusaSlicer heeft een fatale fout opgelopen: \"%1%\"" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:85 msgid "" @@ -142,7 +146,7 @@ msgstr "Uitvoeren van nabewerkingsscripts" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:690 #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:710 msgid "Unknown error occured during exporting G-code." -msgstr "Onbekende error opgetreden tijdens exporteren van de G-code." +msgstr "Onbekende fout opgetreden tijdens exporteren van de G-code." #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:695 #, boost-format @@ -196,11 +200,11 @@ msgstr "" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:715 #, boost-format msgid "G-code file exported to %1%" -msgstr "G-code-bestand geëxporteerd naar %1%" +msgstr ".gcode-bestand geëxporteerd naar %1%" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:729 msgid "Copying of the temporary G-code to the output G-code failed" -msgstr "Fout bij het exporteren naar de output-G-code" +msgstr "Fout bij het exporteren naar output-G-code" #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:751 #, boost-format @@ -251,36 +255,36 @@ msgstr "" #: src/libslic3r/PrintConfig.cpp:628 src/libslic3r/PrintConfig.cpp:678 #: src/libslic3r/PrintConfig.cpp:809 src/libslic3r/PrintConfig.cpp:820 #: src/libslic3r/PrintConfig.cpp:838 src/libslic3r/PrintConfig.cpp:1019 -#: src/libslic3r/PrintConfig.cpp:1231 src/libslic3r/PrintConfig.cpp:1298 -#: src/libslic3r/PrintConfig.cpp:1308 src/libslic3r/PrintConfig.cpp:1588 -#: src/libslic3r/PrintConfig.cpp:1782 src/libslic3r/PrintConfig.cpp:1843 -#: src/libslic3r/PrintConfig.cpp:1861 src/libslic3r/PrintConfig.cpp:1879 -#: src/libslic3r/PrintConfig.cpp:1942 src/libslic3r/PrintConfig.cpp:1952 -#: src/libslic3r/PrintConfig.cpp:2066 src/libslic3r/PrintConfig.cpp:2075 -#: src/libslic3r/PrintConfig.cpp:2094 src/libslic3r/PrintConfig.cpp:2115 -#: src/libslic3r/PrintConfig.cpp:2127 src/libslic3r/PrintConfig.cpp:2135 -#: src/libslic3r/PrintConfig.cpp:2176 src/libslic3r/PrintConfig.cpp:2184 -#: src/libslic3r/PrintConfig.cpp:2194 src/libslic3r/PrintConfig.cpp:2202 -#: src/libslic3r/PrintConfig.cpp:2210 src/libslic3r/PrintConfig.cpp:2272 -#: src/libslic3r/PrintConfig.cpp:2502 src/libslic3r/PrintConfig.cpp:2572 -#: src/libslic3r/PrintConfig.cpp:2589 src/libslic3r/PrintConfig.cpp:2690 -#: src/libslic3r/PrintConfig.cpp:2699 src/libslic3r/PrintConfig.cpp:2749 -#: src/libslic3r/PrintConfig.cpp:2901 src/libslic3r/PrintConfig.cpp:2989 -#: src/libslic3r/PrintConfig.cpp:2996 src/libslic3r/PrintConfig.cpp:3003 -#: src/libslic3r/PrintConfig.cpp:3017 src/libslic3r/PrintConfig.cpp:3041 -#: src/libslic3r/PrintConfig.cpp:3051 src/libslic3r/PrintConfig.cpp:3061 -#: src/libslic3r/PrintConfig.cpp:3341 src/libslic3r/PrintConfig.cpp:3382 -#: src/libslic3r/PrintConfig.cpp:3542 src/libslic3r/PrintConfig.cpp:3551 -#: src/libslic3r/PrintConfig.cpp:3560 src/libslic3r/PrintConfig.cpp:3570 -#: src/libslic3r/PrintConfig.cpp:3635 src/libslic3r/PrintConfig.cpp:3645 -#: src/libslic3r/PrintConfig.cpp:3657 src/libslic3r/PrintConfig.cpp:3677 -#: src/libslic3r/PrintConfig.cpp:3687 src/libslic3r/PrintConfig.cpp:3697 -#: src/libslic3r/PrintConfig.cpp:3715 src/libslic3r/PrintConfig.cpp:3730 -#: src/libslic3r/PrintConfig.cpp:3744 src/libslic3r/PrintConfig.cpp:3755 -#: src/libslic3r/PrintConfig.cpp:3768 src/libslic3r/PrintConfig.cpp:3813 -#: src/libslic3r/PrintConfig.cpp:3823 src/libslic3r/PrintConfig.cpp:3832 -#: src/libslic3r/PrintConfig.cpp:3842 src/libslic3r/PrintConfig.cpp:3858 -#: src/libslic3r/PrintConfig.cpp:3882 +#: src/libslic3r/PrintConfig.cpp:1230 src/libslic3r/PrintConfig.cpp:1297 +#: src/libslic3r/PrintConfig.cpp:1307 src/libslic3r/PrintConfig.cpp:1587 +#: src/libslic3r/PrintConfig.cpp:1781 src/libslic3r/PrintConfig.cpp:1842 +#: src/libslic3r/PrintConfig.cpp:1860 src/libslic3r/PrintConfig.cpp:1878 +#: src/libslic3r/PrintConfig.cpp:1941 src/libslic3r/PrintConfig.cpp:1951 +#: src/libslic3r/PrintConfig.cpp:2065 src/libslic3r/PrintConfig.cpp:2074 +#: src/libslic3r/PrintConfig.cpp:2093 src/libslic3r/PrintConfig.cpp:2114 +#: src/libslic3r/PrintConfig.cpp:2126 src/libslic3r/PrintConfig.cpp:2134 +#: src/libslic3r/PrintConfig.cpp:2175 src/libslic3r/PrintConfig.cpp:2183 +#: src/libslic3r/PrintConfig.cpp:2193 src/libslic3r/PrintConfig.cpp:2201 +#: src/libslic3r/PrintConfig.cpp:2209 src/libslic3r/PrintConfig.cpp:2271 +#: src/libslic3r/PrintConfig.cpp:2501 src/libslic3r/PrintConfig.cpp:2571 +#: src/libslic3r/PrintConfig.cpp:2588 src/libslic3r/PrintConfig.cpp:2689 +#: src/libslic3r/PrintConfig.cpp:2698 src/libslic3r/PrintConfig.cpp:2748 +#: src/libslic3r/PrintConfig.cpp:2900 src/libslic3r/PrintConfig.cpp:2988 +#: src/libslic3r/PrintConfig.cpp:2995 src/libslic3r/PrintConfig.cpp:3002 +#: src/libslic3r/PrintConfig.cpp:3016 src/libslic3r/PrintConfig.cpp:3040 +#: src/libslic3r/PrintConfig.cpp:3050 src/libslic3r/PrintConfig.cpp:3060 +#: src/libslic3r/PrintConfig.cpp:3340 src/libslic3r/PrintConfig.cpp:3381 +#: src/libslic3r/PrintConfig.cpp:3541 src/libslic3r/PrintConfig.cpp:3550 +#: src/libslic3r/PrintConfig.cpp:3559 src/libslic3r/PrintConfig.cpp:3569 +#: src/libslic3r/PrintConfig.cpp:3634 src/libslic3r/PrintConfig.cpp:3644 +#: src/libslic3r/PrintConfig.cpp:3656 src/libslic3r/PrintConfig.cpp:3676 +#: src/libslic3r/PrintConfig.cpp:3686 src/libslic3r/PrintConfig.cpp:3696 +#: src/libslic3r/PrintConfig.cpp:3714 src/libslic3r/PrintConfig.cpp:3729 +#: src/libslic3r/PrintConfig.cpp:3743 src/libslic3r/PrintConfig.cpp:3754 +#: src/libslic3r/PrintConfig.cpp:3767 src/libslic3r/PrintConfig.cpp:3812 +#: src/libslic3r/PrintConfig.cpp:3822 src/libslic3r/PrintConfig.cpp:3831 +#: src/libslic3r/PrintConfig.cpp:3841 src/libslic3r/PrintConfig.cpp:3857 +#: src/libslic3r/PrintConfig.cpp:3881 msgid "mm" msgstr "mm" @@ -342,7 +346,7 @@ msgstr "Model" #: src/slic3r/GUI/BedShapeDialog.cpp:508 msgid "Choose an STL file to import bed shape from:" -msgstr "Kies een STL-bestand om te importeren als bedvorm:" +msgstr "Kies een .STL-bestand om te importeren als bedvorm:" #: src/slic3r/GUI/BedShapeDialog.cpp:514 src/slic3r/GUI/BedShapeDialog.cpp:562 #: src/slic3r/GUI/BedShapeDialog.cpp:584 @@ -370,7 +374,7 @@ msgstr "Kies een bestand om te importeren als bedtextuur (PNG/SVG):" #: src/slic3r/GUI/BedShapeDialog.cpp:574 msgid "Choose an STL file to import bed model from:" -msgstr "Kies een STL-bestand om te importeren als bedvorm:" +msgstr "Kies een .STL-bestand om te importeren als bedvorm:" #: src/slic3r/GUI/BedShapeDialog.hpp:95 src/slic3r/GUI/ConfigWizard.cpp:1396 msgid "Bed Shape" @@ -402,7 +406,7 @@ msgstr "Zoeken naar apparaten" #: src/slic3r/GUI/BonjourDialog.cpp:231 msgid "Finished" -msgstr "Klaar" +msgstr "Gereed" #: src/slic3r/GUI/ButtonsDescription.cpp:42 msgid "Revert color to default" @@ -450,7 +454,7 @@ msgstr "" "\n" "De laagdikte wordt ingesteld op 0,01." -#: src/slic3r/GUI/ConfigManipulation.cpp:62 src/libslic3r/PrintConfig.cpp:1227 +#: src/slic3r/GUI/ConfigManipulation.cpp:62 src/libslic3r/PrintConfig.cpp:1226 msgid "First layer height" msgstr "Laagdikte eerste laag" @@ -515,7 +519,7 @@ msgstr "" #: src/slic3r/GUI/ConfigManipulation.cpp:145 msgid "Shall I synchronize support layers in order to enable the Wipe Tower?" msgstr "" -"Moeten de supportlagen gesynchroniseerd worden met de overage lagen om het " +"Moeten de supportlagen gesynchroniseerd worden met de overige lagen om het " "afveegblok te activeren?" #: src/slic3r/GUI/ConfigManipulation.cpp:164 @@ -549,11 +553,11 @@ msgstr "Moet dit aangepast worden naar het rechtlijnig patroon?" #: src/slic3r/GUI/Plater.cpp:460 src/slic3r/GUI/Tab.cpp:1503 #: src/slic3r/GUI/Tab.cpp:1505 src/libslic3r/PrintConfig.cpp:474 #: src/libslic3r/PrintConfig.cpp:715 src/libslic3r/PrintConfig.cpp:739 -#: src/libslic3r/PrintConfig.cpp:1094 src/libslic3r/PrintConfig.cpp:1108 -#: src/libslic3r/PrintConfig.cpp:1145 src/libslic3r/PrintConfig.cpp:1394 -#: src/libslic3r/PrintConfig.cpp:1404 src/libslic3r/PrintConfig.cpp:1473 -#: src/libslic3r/PrintConfig.cpp:1493 src/libslic3r/PrintConfig.cpp:1512 -#: src/libslic3r/PrintConfig.cpp:2333 src/libslic3r/PrintConfig.cpp:2350 +#: src/libslic3r/PrintConfig.cpp:1093 src/libslic3r/PrintConfig.cpp:1107 +#: src/libslic3r/PrintConfig.cpp:1144 src/libslic3r/PrintConfig.cpp:1393 +#: src/libslic3r/PrintConfig.cpp:1403 src/libslic3r/PrintConfig.cpp:1472 +#: src/libslic3r/PrintConfig.cpp:1492 src/libslic3r/PrintConfig.cpp:1511 +#: src/libslic3r/PrintConfig.cpp:2332 src/libslic3r/PrintConfig.cpp:2349 msgid "Infill" msgstr "Vulling" @@ -651,7 +655,7 @@ msgstr "varianten" #: src/slic3r/GUI/ConfigSnapshotDialog.cpp:93 #, c-format, boost-format msgid "Incompatible with this %s" -msgstr "Niet geschikt voor deze %s" +msgstr "Niet compatibel met deze %s" #: src/slic3r/GUI/ConfigSnapshotDialog.cpp:96 msgid "Activate" @@ -686,7 +690,7 @@ msgstr "Alles" #: src/slic3r/GUI/ConfigWizard.cpp:332 src/slic3r/GUI/ConfigWizard.cpp:652 #: src/slic3r/GUI/DoubleSlider.cpp:2030 src/slic3r/GUI/Plater.cpp:432 #: src/slic3r/GUI/Plater.cpp:579 src/slic3r/GUI/Preferences.cpp:436 -#: src/libslic3r/PrintConfig.cpp:1287 +#: src/libslic3r/PrintConfig.cpp:1286 msgid "None" msgstr "Geen" @@ -715,15 +719,15 @@ msgstr "" #: src/slic3r/GUI/ConfigWizard.cpp:495 msgid "Remove user profiles (a snapshot will be taken beforehand)" -msgstr "Verwijder gebruikersprofielen (vooraf wordt een opname gemaakt)" +msgstr "Verwijder gebruikersprofielen (vooraf wordt een snapshot gemaakt)" #: src/slic3r/GUI/ConfigWizard.cpp:498 msgid "" "Perform desktop integration (Sets this binary to be searchable by the " "system)." msgstr "" -"Voer desktopintegratie uit (stel in op binary om zodat deze door het systeem " -"bezocht kan worden)." +"Voer desktopintegratie uit (stel in op binair zodat deze door het systeem " +"gezocht kan worden)." #: src/slic3r/GUI/ConfigWizard.cpp:550 #, c-format, boost-format @@ -826,7 +830,7 @@ msgid "" "application startup (never during program usage). This is only a " "notification mechanisms, no automatic installation is done." msgstr "" -"%s controleert op nieuwe versie online als dit is geactiveerd. Als een " +"%s controleert naar nieuwe versies online als dit is ingeschakeld. Als een " "nieuwe versie beschikbaar komt, wordt bij de volgende keer opstarten een " "melding getoond (nooit tijdens gebruik). Dit is slechts een melding." @@ -842,8 +846,8 @@ msgid "" "When a new preset version becomes available it is offered at application " "startup." msgstr "" -"%s download updates op ingebouwde presets in de achtergrond als dit is " -"geactiveerd. De updates worden in een tijdelijke locatie opgeslagen. Wanneer " +"Als dit aanstaat download %s updates op ingebouwde presets in de " +"achtergrond. De updates worden in een tijdelijke locatie opgeslagen. Wanneer " "een nieuwe preset beschikbaar komt, wordt een melding getoond tijdens het " "opstarten." @@ -864,7 +868,7 @@ msgstr "" "update wordt toegepast." #: src/slic3r/GUI/ConfigWizard.cpp:1243 src/slic3r/GUI/GUI_Factories.cpp:726 -#: src/slic3r/GUI/Plater.cpp:3582 +#: src/slic3r/GUI/Plater.cpp:3569 msgid "Reload from disk" msgstr "Herlaad van schijf" @@ -872,7 +876,8 @@ msgstr "Herlaad van schijf" msgid "" "Export full pathnames of models and parts sources into 3mf and amf files" msgstr "" -"Exporteer volledige padnaam van modellen en bronnen in 3MF en AMF bestanden" +"Exporteer volledige padnaam van modellen en bronnen in .3MF- en .AMF-" +"bestanden" #: src/slic3r/GUI/ConfigWizard.cpp:1250 msgid "" @@ -882,7 +887,7 @@ msgid "" "using an open file dialog." msgstr "" "Sta toe om bestanden automatisch te vinden bij het herladen van de schijf " -"als dit is geactiveerd.\n" +"als dit is ingeschakeld.\n" "Als dit niet is geactiveerd vraagt het programma elke bestand apart te " "selecteren." @@ -892,11 +897,11 @@ msgstr "Bestandsassociatie" #: src/slic3r/GUI/ConfigWizard.cpp:1261 src/slic3r/GUI/Preferences.cpp:157 msgid "Associate .3mf files to PrusaSlicer" -msgstr "Open .3mf-bestanden met PrusaSlicer" +msgstr "Open .3MF-bestanden met PrusaSlicer" #: src/slic3r/GUI/ConfigWizard.cpp:1262 src/slic3r/GUI/Preferences.cpp:164 msgid "Associate .stl files to PrusaSlicer" -msgstr "Open .stl-bestanden met PrusaSlicer" +msgstr "Open .STL-bestanden met PrusaSlicer" #: src/slic3r/GUI/ConfigWizard.cpp:1272 msgid "View mode" @@ -1024,8 +1029,8 @@ msgid "Extrusion Temperature:" msgstr "Extrusietemperatuur:" #: src/slic3r/GUI/ConfigWizard.cpp:1568 src/slic3r/GUI/ConfigWizard.cpp:1582 -#: src/libslic3r/PrintConfig.cpp:417 src/libslic3r/PrintConfig.cpp:1207 -#: src/libslic3r/PrintConfig.cpp:1262 src/libslic3r/PrintConfig.cpp:2811 +#: src/libslic3r/PrintConfig.cpp:417 src/libslic3r/PrintConfig.cpp:1206 +#: src/libslic3r/PrintConfig.cpp:1261 src/libslic3r/PrintConfig.cpp:2810 msgid "°C" msgstr "°C" @@ -1158,15 +1163,15 @@ msgstr "Select alle standaardprinters" #: src/slic3r/GUI/ConfigWizard.cpp:2861 msgid "< &Back" -msgstr "< &Terug" +msgstr "< Terug" #: src/slic3r/GUI/ConfigWizard.cpp:2862 msgid "&Next >" -msgstr "&Volgende >" +msgstr "Volgende >" #: src/slic3r/GUI/ConfigWizard.cpp:2863 msgid "&Finish" -msgstr "&Voltooi" +msgstr "Voltooi" #: src/slic3r/GUI/ConfigWizard.cpp:2864 #: src/slic3r/GUI/DesktopIntegrationDialog.cpp:490 @@ -1191,7 +1196,7 @@ msgid "Filament Profiles Selection" msgstr "Filament profielselectie" #: src/slic3r/GUI/ConfigWizard.cpp:2912 src/slic3r/GUI/ConfigWizard.cpp:2915 -#: src/slic3r/GUI/GUI_ObjectList.cpp:3790 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3781 msgid "Type:" msgstr "Type:" @@ -1205,7 +1210,7 @@ msgstr "Configuratie-assistent" #: src/slic3r/GUI/ConfigWizard.cpp:3037 msgid "Configuration &Assistant" -msgstr "Configuratie-&assistent" +msgstr "Configuratie-assistent" #: src/slic3r/GUI/ConfigWizard.cpp:3039 msgid "Configuration Wizard" @@ -1213,7 +1218,7 @@ msgstr "Configuratie-assistent" #: src/slic3r/GUI/ConfigWizard.cpp:3040 msgid "Configuration &Wizard" -msgstr "Configuratie-&assistent" +msgstr "Configuratie-assistent" #: src/slic3r/GUI/DesktopIntegrationDialog.cpp:232 msgid "" @@ -1245,7 +1250,7 @@ msgstr "" "aangemaakt." #: src/slic3r/GUI/DesktopIntegrationDialog.cpp:459 -#: src/slic3r/GUI/GUI_App.cpp:2245 +#: src/slic3r/GUI/GUI_App.cpp:2244 msgid "Desktop Integration" msgstr "Desktopintegratie" @@ -1671,7 +1676,7 @@ msgstr "" #: src/slic3r/GUI/ExtraRenderers.cpp:316 src/slic3r/GUI/GUI_ObjectList.cpp:538 #: src/slic3r/GUI/GUI_ObjectList.cpp:550 src/slic3r/GUI/GUI_ObjectList.cpp:979 #: src/slic3r/GUI/GUI_ObjectList.cpp:1966 -#: src/slic3r/GUI/GUI_ObjectList.cpp:4291 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4282 #: src/slic3r/GUI/ObjectDataViewModel.cpp:250 #: src/slic3r/GUI/ObjectDataViewModel.cpp:352 #: src/slic3r/GUI/ObjectDataViewModel.cpp:376 @@ -1688,10 +1693,10 @@ msgid "Set extruder change for every" msgstr "Stel toolwissel in voor elke" #: src/slic3r/GUI/ExtruderSequenceDialog.cpp:60 -#: src/libslic3r/PrintConfig.cpp:661 src/libslic3r/PrintConfig.cpp:1407 -#: src/libslic3r/PrintConfig.cpp:2104 src/libslic3r/PrintConfig.cpp:2279 -#: src/libslic3r/PrintConfig.cpp:2355 src/libslic3r/PrintConfig.cpp:2608 -#: src/libslic3r/PrintConfig.cpp:2656 src/libslic3r/PrintConfig.cpp:2675 +#: src/libslic3r/PrintConfig.cpp:661 src/libslic3r/PrintConfig.cpp:1406 +#: src/libslic3r/PrintConfig.cpp:2103 src/libslic3r/PrintConfig.cpp:2278 +#: src/libslic3r/PrintConfig.cpp:2354 src/libslic3r/PrintConfig.cpp:2607 +#: src/libslic3r/PrintConfig.cpp:2655 src/libslic3r/PrintConfig.cpp:2674 msgid "layers" msgstr "lagen" @@ -1703,7 +1708,7 @@ msgstr "Willekeurige volgorde" msgid "If enabled, random sequence of the selected extruders will be used." msgstr "" "Willekeurige volgorde van de geselecteerde extruders wordt toegestaan als " -"dit aan staat." +"dit is ingeschakeld." #: src/slic3r/GUI/ExtruderSequenceDialog.cpp:172 msgid "Allow next color repetition" @@ -1712,8 +1717,8 @@ msgstr "Sta volgende kleur volgorde toe" #: src/slic3r/GUI/ExtruderSequenceDialog.cpp:174 msgid "If enabled, a repetition of the next random color will be allowed." msgstr "" -"Een herhaling van de volgende willekeurige kleur wordt toegestaan als dit " -"aan staat." +"Een herhaling van de volgende willekeurige kleur wordt toegestaan als dit is " +"ingeschakeld." #: src/slic3r/GUI/ExtruderSequenceDialog.cpp:177 msgid "Set extruder(tool) sequence" @@ -1867,7 +1872,7 @@ msgstr "Firmwarebestand:" #: src/slic3r/GUI/FirmwareDialog.cpp:813 msgid "Select a file" -msgstr "" +msgstr "Selecteer een bestand" #: src/slic3r/GUI/FirmwareDialog.cpp:815 #: src/slic3r/GUI/PhysicalPrinterDialog.cpp:297 @@ -1951,7 +1956,7 @@ msgstr "Voeg toe" msgid "Add one or more custom shapes" msgstr "Voeg een of meer aangepaste vormen toe" -#: src/slic3r/GUI/GalleryDialog.cpp:118 src/slic3r/GUI/GalleryDialog.cpp:506 +#: src/slic3r/GUI/GalleryDialog.cpp:118 src/slic3r/GUI/GalleryDialog.cpp:508 #: src/slic3r/GUI/GLCanvas3D.cpp:4490 src/slic3r/GUI/GUI_Factories.cpp:444 #: src/slic3r/GUI/Tab.cpp:3748 msgid "Delete" @@ -1963,11 +1968,11 @@ msgstr "" "Verwijder een of meer aangepaste vormen. U kunt geen standaardvormen " "verwijderen" -#: src/slic3r/GUI/GalleryDialog.cpp:400 +#: src/slic3r/GUI/GalleryDialog.cpp:402 msgid "Choose one or more files (STL, OBJ):" msgstr "Kies een of meer bestanden (STL, OBJ):" -#: src/slic3r/GUI/GalleryDialog.cpp:440 +#: src/slic3r/GUI/GalleryDialog.cpp:442 #, boost-format msgid "" "It looks like selected %1%-file has an error or is destructed.\n" @@ -1977,19 +1982,19 @@ msgstr "" "vernietigd.\n" "Het bestand kan niet geladen worden" -#: src/slic3r/GUI/GalleryDialog.cpp:451 +#: src/slic3r/GUI/GalleryDialog.cpp:453 msgid "Choose one PNG file:" msgstr "Kies een PNG-bestand:" -#: src/slic3r/GUI/GalleryDialog.cpp:464 +#: src/slic3r/GUI/GalleryDialog.cpp:466 msgid "Replacing of the PNG" msgstr "Herplaats de PNG" -#: src/slic3r/GUI/GalleryDialog.cpp:508 +#: src/slic3r/GUI/GalleryDialog.cpp:510 msgid "Change thumbnail" msgstr "Verander miniatuur" -#: src/slic3r/GUI/GalleryDialog.cpp:549 src/slic3r/GUI/GalleryDialog.cpp:554 +#: src/slic3r/GUI/GalleryDialog.cpp:551 src/slic3r/GUI/GalleryDialog.cpp:556 #, boost-format msgid "Loading of the \"%1%\"" msgstr "Laden van de \"%1%\"" @@ -2127,7 +2132,7 @@ msgid "Duration" msgstr "Duur" #: src/slic3r/GUI/GCodeViewer.cpp:3609 src/slic3r/GUI/GUI_Preview.cpp:1049 -#: src/libslic3r/PrintConfig.cpp:2906 +#: src/libslic3r/PrintConfig.cpp:2905 msgid "Travel" msgstr "Beweging" @@ -2211,9 +2216,9 @@ msgstr "Normale modus" msgid "Stealth mode" msgstr "Stille modus" -#: src/slic3r/GUI/GCodeViewer.cpp:3766 src/libslic3r/PrintConfig.cpp:1185 -#: src/libslic3r/PrintConfig.cpp:1203 src/libslic3r/PrintConfig.cpp:1213 -#: src/libslic3r/PrintConfig.cpp:1258 +#: src/slic3r/GUI/GCodeViewer.cpp:3766 src/libslic3r/PrintConfig.cpp:1184 +#: src/libslic3r/PrintConfig.cpp:1202 src/libslic3r/PrintConfig.cpp:1212 +#: src/libslic3r/PrintConfig.cpp:1257 msgid "First layer" msgstr "Eerste laag" @@ -2320,7 +2325,7 @@ msgstr "Variabele laagdikte - adaptief" #: src/slic3r/GUI/GLCanvas3D.cpp:1281 msgid "Variable layer height - Smooth all" -msgstr "Variable laagdikte - egaliseer alles" +msgstr "Variabele laagdikte - egaliseer alles" #: src/slic3r/GUI/GLCanvas3D.cpp:1688 msgid "Mirror Object" @@ -2419,7 +2424,7 @@ msgid "Add..." msgstr "Voeg toe..." #: src/slic3r/GUI/GLCanvas3D.cpp:4499 src/slic3r/GUI/KBShortcutsDialog.cpp:96 -#: src/slic3r/GUI/Plater.cpp:5509 src/slic3r/GUI/Tab.cpp:4155 +#: src/slic3r/GUI/Plater.cpp:5496 src/slic3r/GUI/Tab.cpp:4155 msgid "Delete all" msgstr "Verwijder alles" @@ -2508,7 +2513,7 @@ msgid "Selection-Remove from rectangle" msgstr "Selectie - Verwijder van boxselectie" #: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:50 -#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:160 src/libslic3r/PrintConfig.cpp:4447 +#: src/slic3r/GUI/Gizmos/GLGizmoCut.cpp:160 src/libslic3r/PrintConfig.cpp:4446 msgid "Cut" msgstr "Snij door" @@ -2624,7 +2629,7 @@ msgstr "Bol" #: src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp:55 #: src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp:124 #: src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp:68 -#: src/libslic3r/PrintConfig.cpp:1168 +#: src/libslic3r/PrintConfig.cpp:1167 msgid "Triangles" msgstr "Facetten" @@ -2770,7 +2775,7 @@ msgid "Quality" msgstr "Kwaliteit" #: src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp:34 -#: src/libslic3r/PrintConfig.cpp:3874 +#: src/libslic3r/PrintConfig.cpp:3873 msgid "Closing distance" msgstr "Sluitafstand" @@ -2877,7 +2882,7 @@ msgstr "Verplaats" #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:543 #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:562 #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:578 -#: src/libslic3r/PrintConfig.cpp:4501 +#: src/libslic3r/PrintConfig.cpp:4500 msgid "Rotate" msgstr "Roteer" @@ -2894,7 +2899,7 @@ msgstr "Toepassen" #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:216 #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:563 #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:579 -#: src/libslic3r/PrintConfig.cpp:4516 +#: src/libslic3r/PrintConfig.cpp:4515 msgid "Scale" msgstr "Verschaal" @@ -3033,7 +3038,7 @@ msgid "Minimal points distance" msgstr "Minimale puntafstand" #: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:46 -#: src/libslic3r/PrintConfig.cpp:3704 +#: src/libslic3r/PrintConfig.cpp:3703 msgid "Support points density" msgstr "Dichtheid van supportpunten" @@ -3310,7 +3315,7 @@ msgstr "Afsluiten, ik zal mijn data nu verplaatsen" msgid "Start the application" msgstr "Start het programma" -#: src/slic3r/GUI/GUI_App.cpp:699 +#: src/slic3r/GUI/GUI_App.cpp:698 #, c-format, boost-format msgid "" "%s has encountered an error. It was likely caused by running out of memory. " @@ -3319,17 +3324,17 @@ msgid "" "\n" "The application will now terminate." msgstr "" -"%s veroorzaakte een fout. Dit komt mogelijk door een geheugentekort. Als u " -"zeker weet dat u genoeg RAM-geheugen heeft, kan dit ook een andere fout " +"%s heeft een fout opgelopen. Dit komt mogelijk door een geheugentekort. Als " +"u zeker weet genoeg RAM geheugen te hebben, kan dit ook een andere fout " "zijn. We waarderen het als u dit meldt.\n" "\n" "Het programma zal nu afsluiten." -#: src/slic3r/GUI/GUI_App.cpp:702 +#: src/slic3r/GUI/GUI_App.cpp:701 msgid "Fatal error" msgstr "Fatale fout" -#: src/slic3r/GUI/GUI_App.cpp:706 +#: src/slic3r/GUI/GUI_App.cpp:705 msgid "" "PrusaSlicer has encountered a localization error. Please report to " "PrusaSlicer team, what language was active and in which scenario this issue " @@ -3337,22 +3342,22 @@ msgid "" "\n" "The application will now terminate." msgstr "" -"PrusaSlicer is een vertalingsprobleem tegengekomen. Gelieve te melden bij " -"het PrusaSlicer team; welke taal actief is en in welk scenario dit gebeurde. " -"Hartelijk dank.\n" +"PrusaSlicer heeft een vertalingsprobleem opgelopen. We zouden het waarderen " +"als u dit meldt bij het PrusaSlicer team; welke taal actief is en in welk " +"scenario dit gebeurde. Hartelijk dank.\n" "\n" "Het programma zal nu sluiten." -#: src/slic3r/GUI/GUI_App.cpp:709 +#: src/slic3r/GUI/GUI_App.cpp:708 msgid "Critical error" msgstr "Kritische fout" -#: src/slic3r/GUI/GUI_App.cpp:714 +#: src/slic3r/GUI/GUI_App.cpp:713 #, boost-format msgid "Internal error: %1%" msgstr "Interne fout: %1%" -#: src/slic3r/GUI/GUI_App.cpp:909 src/slic3r/GUI/GUI_App.cpp:1007 +#: src/slic3r/GUI/GUI_App.cpp:908 src/slic3r/GUI/GUI_App.cpp:1006 msgid "" "Error parsing PrusaSlicer config file, it is probably corrupted. Try to " "manually delete the file to recover from the error. Your user profiles will " @@ -3362,7 +3367,7 @@ msgstr "" "Probeer het bestand handmatig te verwijderen om de fout te herstellen. Uw " "gebruikersprofielen worden niet beïnvloed." -#: src/slic3r/GUI/GUI_App.cpp:915 src/slic3r/GUI/GUI_App.cpp:1013 +#: src/slic3r/GUI/GUI_App.cpp:914 src/slic3r/GUI/GUI_App.cpp:1012 msgid "" "Error parsing PrusaGCodeViewer config file, it is probably corrupted. Try to " "manually delete the file to recover from the error." @@ -3370,12 +3375,12 @@ msgstr "" "Fout tijdens het lezen van PrusaGCodeViewer-configuratiebestand. Het is " "mogelijk beschadigd. Probeer het handmatig te verwijderen." -#: src/slic3r/GUI/GUI_App.cpp:962 +#: src/slic3r/GUI/GUI_App.cpp:961 #, boost-format msgid "You are opening %1% version %2%." msgstr "U opent %1%, versie %2%." -#: src/slic3r/GUI/GUI_App.cpp:965 +#: src/slic3r/GUI/GUI_App.cpp:964 #, boost-format msgid "" "The active configuration was created by %1% %2%,\n" @@ -3394,7 +3399,7 @@ msgstr "" "In dat geval wordt uw actieve configuratie opgeslagen voor het importeren " "van de nieuwe configuratie." -#: src/slic3r/GUI/GUI_App.cpp:973 +#: src/slic3r/GUI/GUI_App.cpp:972 #, boost-format msgid "" "An existing configuration was found in %3%\n" @@ -3403,22 +3408,22 @@ msgid "" "Shall this configuration be imported?" msgstr "" "Een bestaande configuratie is gevonden in %3%,\n" -"aangemaakt door %1% %2%.\n" +"aangemaakt door b>%1% %2%.\n" "Moet de nieuwe configuratie worden geïmporteerd?" -#: src/slic3r/GUI/GUI_App.cpp:981 +#: src/slic3r/GUI/GUI_App.cpp:980 msgid "Import" msgstr "Importeer" -#: src/slic3r/GUI/GUI_App.cpp:982 +#: src/slic3r/GUI/GUI_App.cpp:981 msgid "Don't import" msgstr "Niet importeren" -#: src/slic3r/GUI/GUI_App.cpp:990 +#: src/slic3r/GUI/GUI_App.cpp:989 msgid "Continue and import newer configuration?" -msgstr "" +msgstr "Doorgaan en nieuwere configuraties importeren?" -#: src/slic3r/GUI/GUI_App.cpp:1051 +#: src/slic3r/GUI/GUI_App.cpp:1050 msgid "" "You are running a 32 bit build of PrusaSlicer on 64-bit Windows.\n" "32 bit build of PrusaSlicer will likely not be able to utilize all the RAM " @@ -3434,7 +3439,7 @@ msgstr "" "https://www.prusa3d.com/prusaslicer/.\n" "Wilt u doorgaan?" -#: src/slic3r/GUI/GUI_App.cpp:1134 +#: src/slic3r/GUI/GUI_App.cpp:1133 #, c-format, boost-format msgid "" "%s\n" @@ -3443,46 +3448,46 @@ msgstr "" "%s\n" "Wilt u doorgaan?" -#: src/slic3r/GUI/GUI_App.cpp:1136 src/slic3r/GUI/GUI_App.cpp:3101 +#: src/slic3r/GUI/GUI_App.cpp:1135 src/slic3r/GUI/GUI_App.cpp:3100 #: src/slic3r/GUI/Plater.cpp:1726 src/slic3r/GUI/UnsavedChangesDialog.cpp:889 msgid "Remember my choice" msgstr "Onthoud mijn keuze" -#: src/slic3r/GUI/GUI_App.cpp:1178 +#: src/slic3r/GUI/GUI_App.cpp:1177 msgid "Loading configuration" -msgstr "" +msgstr "Configuratie aan het laden" -#: src/slic3r/GUI/GUI_App.cpp:1209 +#: src/slic3r/GUI/GUI_App.cpp:1208 #, boost-format msgid "New release version %1% is available." msgstr "Nieuwe release versie %1% is beschikbaar." -#: src/slic3r/GUI/GUI_App.cpp:1210 +#: src/slic3r/GUI/GUI_App.cpp:1209 msgid "See Download page." msgstr "Zie downloadpagina." -#: src/slic3r/GUI/GUI_App.cpp:1224 +#: src/slic3r/GUI/GUI_App.cpp:1223 #, boost-format msgid "New prerelease version %1% is available." msgstr "Nieuwe pre-release versie %1% is beschikbaar." -#: src/slic3r/GUI/GUI_App.cpp:1225 +#: src/slic3r/GUI/GUI_App.cpp:1224 msgid "See Releases page." msgstr "Zie Release-pagina." -#: src/slic3r/GUI/GUI_App.cpp:1262 +#: src/slic3r/GUI/GUI_App.cpp:1261 msgid "Preparing settings tabs" msgstr "Instellingentab voorbereiden" -#: src/slic3r/GUI/GUI_App.cpp:1336 src/slic3r/GUI/Preferences.cpp:287 +#: src/slic3r/GUI/GUI_App.cpp:1335 src/slic3r/GUI/Preferences.cpp:287 msgid "Restore window position on start" -msgstr "" +msgstr "Herstel vensterpositie na opstarten" + +#: src/slic3r/GUI/GUI_App.cpp:1337 +msgid "PrusaSlicer started after a crash" +msgstr "PrusaSlicer is opgestart na een crash" #: src/slic3r/GUI/GUI_App.cpp:1338 -msgid "PrusaSlicer started after a crash" -msgstr "" - -#: src/slic3r/GUI/GUI_App.cpp:1339 #, boost-format msgid "" "PrusaSlicer crashed last time when attempting to set window position.\n" @@ -3494,24 +3499,34 @@ msgid "" "To avoid this problem, consider disabling \"%4%\" in \"Preferences\". " "Otherwise, the application will most likely crash again next time." msgstr "" +"PrusaSlicer is de vorige keer gecrasht tijdens een poging om de " +"vensterpositie in te stellen.\n" +"Sorry voor het ongemak. Het gebeurt helaas met sommige meer-schermen " +"opstellingen.\n" +"Exacte reden van de crash: \"%1%\".\n" +"For meer informatie, zie onze Github probleemtracker: \"%2%\" en \"%3%\"\n" +"\n" +"Overweeg om \"%4%\" in voorkeuren uit te zetten om dit probleem te " +"voorkomen. Waarschijnlijk zal anders het programma de volgende keer weer " +"crashen." + +#: src/slic3r/GUI/GUI_App.cpp:1350 +#, boost-format +msgid "Disable \"%1%\"" +msgstr "\"%1%\" uitschakelen" #: src/slic3r/GUI/GUI_App.cpp:1351 #, boost-format -msgid "Disable \"%1%\"" -msgstr "" - -#: src/slic3r/GUI/GUI_App.cpp:1352 -#, boost-format msgid "Leave \"%1%\" enabled" -msgstr "" +msgstr "Laat \"%1%\" aanstaan" -#: src/slic3r/GUI/GUI_App.cpp:1679 +#: src/slic3r/GUI/GUI_App.cpp:1678 msgid "" "You have the following presets with saved options for \"Print Host upload\"" msgstr "" "Je hebt de volgende presets opgeslagen voor de printhost-uploadwachtrij" -#: src/slic3r/GUI/GUI_App.cpp:1683 +#: src/slic3r/GUI/GUI_App.cpp:1682 msgid "" "But since this version of PrusaSlicer we don't show this information in " "Printer Settings anymore.\n" @@ -3519,9 +3534,9 @@ msgid "" msgstr "" "Maar sinds deze versie van PrusaSlicer, wordt de informatie niet meer " "getoond in de printerinstellingen.\n" -"Instellingen zijn beschikbaar in de fysieke printerinstellingen." +"Instellingen zijn beschikbaar in de fysieke-printerinstellingen." -#: src/slic3r/GUI/GUI_App.cpp:1685 +#: src/slic3r/GUI/GUI_App.cpp:1684 msgid "" "By default new Printer devices will be named as \"Printer N\" during its " "creation.\n" @@ -3531,138 +3546,138 @@ msgstr "" "Let op: deze naam kan later worden aangepast in de fysieke-" "printerinstellingen" -#: src/slic3r/GUI/GUI_App.cpp:1689 src/slic3r/GUI/PhysicalPrinterDialog.cpp:722 +#: src/slic3r/GUI/GUI_App.cpp:1688 src/slic3r/GUI/PhysicalPrinterDialog.cpp:722 msgid "Information" msgstr "Informatie" -#: src/slic3r/GUI/GUI_App.cpp:1702 src/slic3r/GUI/GUI_App.cpp:1713 +#: src/slic3r/GUI/GUI_App.cpp:1701 src/slic3r/GUI/GUI_App.cpp:1712 msgid "Recreating" msgstr "Opnieuw aanmaken" -#: src/slic3r/GUI/GUI_App.cpp:1716 +#: src/slic3r/GUI/GUI_App.cpp:1715 msgid "Loading of current presets" msgstr "Laden van huidige presets" -#: src/slic3r/GUI/GUI_App.cpp:1721 +#: src/slic3r/GUI/GUI_App.cpp:1720 msgid "Loading of a mode view" msgstr "Laden van de weergavemodus" -#: src/slic3r/GUI/GUI_App.cpp:1859 +#: src/slic3r/GUI/GUI_App.cpp:1858 msgid "Choose one file (3MF/AMF):" -msgstr "Kies een 3MF- of AMF-bestand:" +msgstr "Kies een .3MF- of .AMF-bestand:" -#: src/slic3r/GUI/GUI_App.cpp:1871 -msgid "Choose one or more files (STL/3MF/STEP/OBJ/AMF/PRUSA):" -msgstr "Kies één of meer STL-, 3MF-, STEP-, OBJ-, AMF- of PRUSA- bestanden:" +#: src/slic3r/GUI/GUI_App.cpp:1870 +msgid "Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):" +msgstr "Kies één of meer .STL-, .OBJ-, .AMF-, .3MF-, of .PRUSA-bestanden:" -#: src/slic3r/GUI/GUI_App.cpp:1883 +#: src/slic3r/GUI/GUI_App.cpp:1882 msgid "Choose one file (GCODE/.GCO/.G/.ngc/NGC):" -msgstr "Kies een bestand (gcode/.GCO/.G/.ngc/NGC):" +msgstr "Kies een bestand (.gcode/.GCO/.G/.ngc):" -#: src/slic3r/GUI/GUI_App.cpp:1894 +#: src/slic3r/GUI/GUI_App.cpp:1893 msgid "Changing of an application language" msgstr "Veranderen van de taal van het programma" -#: src/slic3r/GUI/GUI_App.cpp:2033 +#: src/slic3r/GUI/GUI_App.cpp:2032 msgid "Select the language" msgstr "Taalselectie" -#: src/slic3r/GUI/GUI_App.cpp:2033 +#: src/slic3r/GUI/GUI_App.cpp:2032 msgid "Language" msgstr "Wijzig taal (change language)" -#: src/slic3r/GUI/GUI_App.cpp:2182 +#: src/slic3r/GUI/GUI_App.cpp:2181 msgid "modified" msgstr "aangepast" -#: src/slic3r/GUI/GUI_App.cpp:2236 +#: src/slic3r/GUI/GUI_App.cpp:2235 #, c-format, boost-format msgid "Run %s" msgstr "Voer %s uit" -#: src/slic3r/GUI/GUI_App.cpp:2240 +#: src/slic3r/GUI/GUI_App.cpp:2239 msgid "&Configuration Snapshots" msgstr "Configuratiesnapshots" -#: src/slic3r/GUI/GUI_App.cpp:2240 +#: src/slic3r/GUI/GUI_App.cpp:2239 msgid "Inspect / activate configuration snapshots" msgstr "Inspecteer/activeer configuratiesnapshots" -#: src/slic3r/GUI/GUI_App.cpp:2241 +#: src/slic3r/GUI/GUI_App.cpp:2240 msgid "Take Configuration &Snapshot" msgstr "Neem configuratiesnapshot" -#: src/slic3r/GUI/GUI_App.cpp:2241 +#: src/slic3r/GUI/GUI_App.cpp:2240 msgid "Capture a configuration snapshot" msgstr "Neem een configuratiesnapshot op" -#: src/slic3r/GUI/GUI_App.cpp:2242 +#: src/slic3r/GUI/GUI_App.cpp:2241 msgid "Check for Configuration Updates" msgstr "Controleer op configuratie-updates" -#: src/slic3r/GUI/GUI_App.cpp:2242 +#: src/slic3r/GUI/GUI_App.cpp:2241 msgid "Check for configuration updates" msgstr "Controleer op configuratie-updates" -#: src/slic3r/GUI/GUI_App.cpp:2249 +#: src/slic3r/GUI/GUI_App.cpp:2248 msgid "&Preferences" msgstr "Voorkeuren" -#: src/slic3r/GUI/GUI_App.cpp:2255 +#: src/slic3r/GUI/GUI_App.cpp:2254 msgid "Application preferences" msgstr "Programmavoorkeuren" -#: src/slic3r/GUI/GUI_App.cpp:2260 src/slic3r/GUI/wxExtensions.cpp:708 +#: src/slic3r/GUI/GUI_App.cpp:2259 src/slic3r/GUI/wxExtensions.cpp:708 msgid "Simple" msgstr "Eenvoudig" -#: src/slic3r/GUI/GUI_App.cpp:2260 +#: src/slic3r/GUI/GUI_App.cpp:2259 msgid "Simple View Mode" msgstr "Eenvoudige weergave" -#: src/slic3r/GUI/GUI_App.cpp:2262 src/slic3r/GUI/wxExtensions.cpp:710 +#: src/slic3r/GUI/GUI_App.cpp:2261 src/slic3r/GUI/wxExtensions.cpp:710 msgctxt "Mode" msgid "Advanced" msgstr "Geavanceerd" -#: src/slic3r/GUI/GUI_App.cpp:2262 +#: src/slic3r/GUI/GUI_App.cpp:2261 msgid "Advanced View Mode" msgstr "Geavanceerde weergave" -#: src/slic3r/GUI/GUI_App.cpp:2263 src/slic3r/GUI/wxExtensions.cpp:711 +#: src/slic3r/GUI/GUI_App.cpp:2262 src/slic3r/GUI/wxExtensions.cpp:711 msgid "Expert" msgstr "Expert" -#: src/slic3r/GUI/GUI_App.cpp:2263 +#: src/slic3r/GUI/GUI_App.cpp:2262 msgid "Expert View Mode" msgstr "Expertweergave" -#: src/slic3r/GUI/GUI_App.cpp:2268 +#: src/slic3r/GUI/GUI_App.cpp:2267 msgid "Mode" msgstr "Modus" -#: src/slic3r/GUI/GUI_App.cpp:2268 +#: src/slic3r/GUI/GUI_App.cpp:2267 #, c-format, boost-format msgid "%s View Mode" msgstr "%s-weergavemodus" -#: src/slic3r/GUI/GUI_App.cpp:2271 +#: src/slic3r/GUI/GUI_App.cpp:2270 msgid "&Language" msgstr "Wijzig taal (change language)" -#: src/slic3r/GUI/GUI_App.cpp:2274 +#: src/slic3r/GUI/GUI_App.cpp:2273 msgid "Flash Printer &Firmware" msgstr "Flash printer firmware" -#: src/slic3r/GUI/GUI_App.cpp:2274 +#: src/slic3r/GUI/GUI_App.cpp:2273 msgid "Upload a firmware image into an Arduino based printer" msgstr "Upload een firmwarebestand op een Arduino-gebaseerde printer" -#: src/slic3r/GUI/GUI_App.cpp:2294 +#: src/slic3r/GUI/GUI_App.cpp:2293 msgid "Taking a configuration snapshot" msgstr "Neemt een configuratiesnapshot" -#: src/slic3r/GUI/GUI_App.cpp:2295 +#: src/slic3r/GUI/GUI_App.cpp:2294 msgid "" "Some presets are modified and the unsaved changes will not be captured by " "the configuration snapshot." @@ -3670,32 +3685,32 @@ msgstr "" "Sommige presets zijn aangepast en onopgeslagen instellingen worden niet " "meegenomen bij de configuratiesnapshot." -#: src/slic3r/GUI/GUI_App.cpp:2296 +#: src/slic3r/GUI/GUI_App.cpp:2295 msgid "Snapshot name" msgstr "Snapshotnaam" -#: src/slic3r/GUI/GUI_App.cpp:2312 +#: src/slic3r/GUI/GUI_App.cpp:2311 msgid "Loading a configuration snapshot" msgstr "Laad een configuratiesnapshot" -#: src/slic3r/GUI/GUI_App.cpp:2321 +#: src/slic3r/GUI/GUI_App.cpp:2320 #, boost-format msgid "Continue to activate a configuration snapshot %1%?" msgstr "Doorgaan om configuratiesnapshot %1% te activeren?" -#: src/slic3r/GUI/GUI_App.cpp:2335 +#: src/slic3r/GUI/GUI_App.cpp:2334 msgid "Failed to activate configuration snapshot." msgstr "Activeren van configuratiesnapshot mislukt." -#: src/slic3r/GUI/GUI_App.cpp:2354 +#: src/slic3r/GUI/GUI_App.cpp:2353 msgid "Restart application" msgstr "Herstart programma" -#: src/slic3r/GUI/GUI_App.cpp:2388 +#: src/slic3r/GUI/GUI_App.cpp:2387 msgid "Language selection" msgstr "Taalselectie" -#: src/slic3r/GUI/GUI_App.cpp:2391 +#: src/slic3r/GUI/GUI_App.cpp:2390 msgid "" "Switching the language will trigger application restart.\n" "You will lose content of the plater." @@ -3703,89 +3718,89 @@ msgstr "" "Het veranderen van de taal zorgt dat het programma opnieuw opstart.\n" "U verliest de geladen inhoud zoals getoond in de modelweergave." -#: src/slic3r/GUI/GUI_App.cpp:2393 src/slic3r/GUI/Preferences.cpp:582 +#: src/slic3r/GUI/GUI_App.cpp:2392 src/slic3r/GUI/Preferences.cpp:582 msgid "Do you want to proceed?" msgstr "" "Weet u zeker dat u door wilt gaan?\n" "Do you want to proceed?" -#: src/slic3r/GUI/GUI_App.cpp:2420 +#: src/slic3r/GUI/GUI_App.cpp:2419 msgid "&Configuration" msgstr "Configuratie" -#: src/slic3r/GUI/GUI_App.cpp:2534 src/slic3r/GUI/GUI_App.cpp:2595 +#: src/slic3r/GUI/GUI_App.cpp:2533 src/slic3r/GUI/GUI_App.cpp:2594 msgid "The preset modifications are successfully saved" msgid_plural "The presets modifications are successfully saved" msgstr[0] "De preset-aanpassing is succesvol opgeslagen" msgstr[1] "De presets-aanpassing is succesvol opgeslagen" -#: src/slic3r/GUI/GUI_App.cpp:2598 +#: src/slic3r/GUI/GUI_App.cpp:2597 msgid "For new project all modifications will be reseted" msgstr "Voor nieuwe projecten worden alle aanpassingen gereset" -#: src/slic3r/GUI/GUI_App.cpp:2636 +#: src/slic3r/GUI/GUI_App.cpp:2635 msgid "Loading a new project while the current project is modified." msgstr "Laad een nieuw project terwijl het huidige project is aangepast." -#: src/slic3r/GUI/GUI_App.cpp:2639 +#: src/slic3r/GUI/GUI_App.cpp:2638 msgid "Project is loading" msgstr "Project is aan het laden" -#: src/slic3r/GUI/GUI_App.cpp:2639 +#: src/slic3r/GUI/GUI_App.cpp:2638 msgid "Opening new project while some presets are unsaved." msgstr "Openen van nieuw project terwijl sommige presets niet opgeslagen zijn." -#: src/slic3r/GUI/GUI_App.cpp:2658 +#: src/slic3r/GUI/GUI_App.cpp:2657 msgid "The uploads are still ongoing" msgstr "De uploads zijn nog bezig" -#: src/slic3r/GUI/GUI_App.cpp:2658 +#: src/slic3r/GUI/GUI_App.cpp:2657 msgid "Stop them and continue anyway?" msgstr "Stop ze en ga toch door?" -#: src/slic3r/GUI/GUI_App.cpp:2662 +#: src/slic3r/GUI/GUI_App.cpp:2661 msgid "Ongoing uploads" msgstr "Lopende uploads" -#: src/slic3r/GUI/GUI_App.cpp:2876 +#: src/slic3r/GUI/GUI_App.cpp:2875 msgid "It's impossible to print multi-part object(s) with SLA technology." msgstr "" "Het is niet mogelijk meerdelige objecten te printen met de SLA-technologie." -#: src/slic3r/GUI/GUI_App.cpp:2877 src/slic3r/GUI/Jobs/SLAImportJob.cpp:235 -#: src/slic3r/GUI/Plater.cpp:2459 +#: src/slic3r/GUI/GUI_App.cpp:2876 src/slic3r/GUI/Jobs/SLAImportJob.cpp:235 +#: src/slic3r/GUI/Plater.cpp:2448 msgid "Please check your object list before preset changing." msgstr "Controleer de objectenlijst voor het wijzigen van de preset." -#: src/slic3r/GUI/GUI_App.cpp:2901 +#: src/slic3r/GUI/GUI_App.cpp:2900 msgid "Configuration is editing from ConfigWizard" msgstr "Configuratie is aangepast van de configuratiewizard" -#: src/slic3r/GUI/GUI_App.cpp:2926 +#: src/slic3r/GUI/GUI_App.cpp:2925 msgid "Select a gcode file:" -msgstr "Selecteer een gcode-bestand:" +msgstr "Selecteer een .gcode-bestand:" -#: src/slic3r/GUI/GUI_App.cpp:3100 src/slic3r/GUI/GUI_App.cpp:3123 +#: src/slic3r/GUI/GUI_App.cpp:3099 src/slic3r/GUI/GUI_App.cpp:3122 msgid "Open hyperlink in default browser?" msgstr "Open hyperlinks in de standaardbrowser?" -#: src/slic3r/GUI/GUI_App.cpp:3100 src/slic3r/GUI/GUI_App.cpp:3123 +#: src/slic3r/GUI/GUI_App.cpp:3099 src/slic3r/GUI/GUI_App.cpp:3122 msgid "PrusaSlicer: Open hyperlink" msgstr "PrusaSlicer: Open hyperlink" -#: src/slic3r/GUI/GUI_App.cpp:3105 src/slic3r/GUI/Preferences.cpp:382 +#: src/slic3r/GUI/GUI_App.cpp:3104 src/slic3r/GUI/Preferences.cpp:382 msgid "Suppress to open hyperlink in browser" msgstr "Hyperlinks openen in browser uitzetten" -#: src/slic3r/GUI/GUI_App.cpp:3107 src/slic3r/GUI/Plater.cpp:1732 +#: src/slic3r/GUI/GUI_App.cpp:3106 src/slic3r/GUI/Plater.cpp:1732 msgid "PrusaSlicer will remember your choice." msgstr "PrusaSlicer onthoudt uw keuze." -#: src/slic3r/GUI/GUI_App.cpp:3108 +#: src/slic3r/GUI/GUI_App.cpp:3107 msgid "You will not be asked about it again on hyperlinks hovering." -msgstr "" +msgstr "U wordt niet opnieuw gevraagd over het bewegen over hyperlinks." -#: src/slic3r/GUI/GUI_App.cpp:3109 src/slic3r/GUI/Plater.cpp:1736 +#: src/slic3r/GUI/GUI_App.cpp:3108 src/slic3r/GUI/Plater.cpp:1736 #, boost-format msgid "" "Visit \"Preferences\" and check \"%1%\"\n" @@ -3794,7 +3809,7 @@ msgstr "" "Ga naar Voorkeuren en controleer \"%1%\"\n" "om uw keuze te wijzigen." -#: src/slic3r/GUI/GUI_App.cpp:3111 src/slic3r/GUI/Plater.cpp:1738 +#: src/slic3r/GUI/GUI_App.cpp:3110 src/slic3r/GUI/Plater.cpp:1738 #: src/slic3r/GUI/UnsavedChangesDialog.cpp:906 msgid "PrusaSlicer: Don't ask me again" msgstr "PrusaSlicer: vraag het niet nogmaals" @@ -3812,12 +3827,12 @@ msgstr "Fatale fout, uitzondering gevonden: %1%" #: src/libslic3r/PrintConfig.cpp:286 src/libslic3r/PrintConfig.cpp:403 #: src/libslic3r/PrintConfig.cpp:446 src/libslic3r/PrintConfig.cpp:455 #: src/libslic3r/PrintConfig.cpp:707 src/libslic3r/PrintConfig.cpp:774 -#: src/libslic3r/PrintConfig.cpp:782 src/libslic3r/PrintConfig.cpp:1228 -#: src/libslic3r/PrintConfig.cpp:1315 src/libslic3r/PrintConfig.cpp:1540 -#: src/libslic3r/PrintConfig.cpp:1932 src/libslic3r/PrintConfig.cpp:1999 -#: src/libslic3r/PrintConfig.cpp:2233 src/libslic3r/PrintConfig.cpp:2819 -#: src/libslic3r/PrintConfig.cpp:2827 src/libslic3r/PrintConfig.cpp:2887 -#: src/libslic3r/PrintConfig.cpp:2896 src/libslic3r/PrintConfig.cpp:3067 +#: src/libslic3r/PrintConfig.cpp:782 src/libslic3r/PrintConfig.cpp:1227 +#: src/libslic3r/PrintConfig.cpp:1314 src/libslic3r/PrintConfig.cpp:1539 +#: src/libslic3r/PrintConfig.cpp:1931 src/libslic3r/PrintConfig.cpp:1998 +#: src/libslic3r/PrintConfig.cpp:2232 src/libslic3r/PrintConfig.cpp:2818 +#: src/libslic3r/PrintConfig.cpp:2826 src/libslic3r/PrintConfig.cpp:2886 +#: src/libslic3r/PrintConfig.cpp:2895 src/libslic3r/PrintConfig.cpp:3066 msgid "Layers and Perimeters" msgstr "Lagen en perimeters" @@ -3825,26 +3840,26 @@ msgstr "Lagen en perimeters" #: src/slic3r/GUI/GUI_Preview.cpp:249 src/slic3r/GUI/Tab.cpp:1547 #: src/slic3r/GUI/Tab.cpp:1549 src/libslic3r/ExtrusionEntity.cpp:340 #: src/libslic3r/ExtrusionEntity.cpp:372 src/libslic3r/PrintConfig.cpp:669 -#: src/libslic3r/PrintConfig.cpp:2064 src/libslic3r/PrintConfig.cpp:2073 -#: src/libslic3r/PrintConfig.cpp:2082 src/libslic3r/PrintConfig.cpp:2092 -#: src/libslic3r/PrintConfig.cpp:2101 src/libslic3r/PrintConfig.cpp:2523 -#: src/libslic3r/PrintConfig.cpp:2529 src/libslic3r/PrintConfig.cpp:2537 -#: src/libslic3r/PrintConfig.cpp:2550 src/libslic3r/PrintConfig.cpp:2560 -#: src/libslic3r/PrintConfig.cpp:2568 src/libslic3r/PrintConfig.cpp:2586 -#: src/libslic3r/PrintConfig.cpp:2603 src/libslic3r/PrintConfig.cpp:2624 -#: src/libslic3r/PrintConfig.cpp:2637 src/libslic3r/PrintConfig.cpp:2654 -#: src/libslic3r/PrintConfig.cpp:2672 src/libslic3r/PrintConfig.cpp:2687 -#: src/libslic3r/PrintConfig.cpp:2697 src/libslic3r/PrintConfig.cpp:2706 -#: src/libslic3r/PrintConfig.cpp:2717 src/libslic3r/PrintConfig.cpp:2731 -#: src/libslic3r/PrintConfig.cpp:2747 src/libslic3r/PrintConfig.cpp:2755 -#: src/libslic3r/PrintConfig.cpp:2756 src/libslic3r/PrintConfig.cpp:2765 -#: src/libslic3r/PrintConfig.cpp:2779 src/libslic3r/PrintConfig.cpp:2787 -#: src/libslic3r/PrintConfig.cpp:2801 +#: src/libslic3r/PrintConfig.cpp:2063 src/libslic3r/PrintConfig.cpp:2072 +#: src/libslic3r/PrintConfig.cpp:2081 src/libslic3r/PrintConfig.cpp:2091 +#: src/libslic3r/PrintConfig.cpp:2100 src/libslic3r/PrintConfig.cpp:2522 +#: src/libslic3r/PrintConfig.cpp:2528 src/libslic3r/PrintConfig.cpp:2536 +#: src/libslic3r/PrintConfig.cpp:2549 src/libslic3r/PrintConfig.cpp:2559 +#: src/libslic3r/PrintConfig.cpp:2567 src/libslic3r/PrintConfig.cpp:2585 +#: src/libslic3r/PrintConfig.cpp:2602 src/libslic3r/PrintConfig.cpp:2623 +#: src/libslic3r/PrintConfig.cpp:2636 src/libslic3r/PrintConfig.cpp:2653 +#: src/libslic3r/PrintConfig.cpp:2671 src/libslic3r/PrintConfig.cpp:2686 +#: src/libslic3r/PrintConfig.cpp:2696 src/libslic3r/PrintConfig.cpp:2705 +#: src/libslic3r/PrintConfig.cpp:2716 src/libslic3r/PrintConfig.cpp:2730 +#: src/libslic3r/PrintConfig.cpp:2746 src/libslic3r/PrintConfig.cpp:2754 +#: src/libslic3r/PrintConfig.cpp:2755 src/libslic3r/PrintConfig.cpp:2764 +#: src/libslic3r/PrintConfig.cpp:2778 src/libslic3r/PrintConfig.cpp:2786 +#: src/libslic3r/PrintConfig.cpp:2800 msgid "Support material" msgstr "Support" #: src/slic3r/GUI/GUI_Factories.cpp:59 src/slic3r/GUI/GUI_Factories.cpp:135 -#: src/libslic3r/PrintConfig.cpp:3023 src/libslic3r/PrintConfig.cpp:3031 +#: src/libslic3r/PrintConfig.cpp:3022 src/libslic3r/PrintConfig.cpp:3030 msgid "Wipe options" msgstr "Afveegopties" @@ -3854,41 +3869,41 @@ msgstr "Basisplaat en support" #: src/slic3r/GUI/GUI_Factories.cpp:129 src/slic3r/GUI/GUI_Preview.cpp:245 #: src/slic3r/GUI/Tab.cpp:1513 src/libslic3r/ExtrusionEntity.cpp:336 -#: src/libslic3r/ExtrusionEntity.cpp:364 src/libslic3r/PrintConfig.cpp:1556 -#: src/libslic3r/PrintConfig.cpp:1562 src/libslic3r/PrintConfig.cpp:1576 -#: src/libslic3r/PrintConfig.cpp:1586 src/libslic3r/PrintConfig.cpp:1594 -#: src/libslic3r/PrintConfig.cpp:1596 +#: src/libslic3r/ExtrusionEntity.cpp:364 src/libslic3r/PrintConfig.cpp:1555 +#: src/libslic3r/PrintConfig.cpp:1561 src/libslic3r/PrintConfig.cpp:1575 +#: src/libslic3r/PrintConfig.cpp:1585 src/libslic3r/PrintConfig.cpp:1593 +#: src/libslic3r/PrintConfig.cpp:1595 msgid "Ironing" msgstr "Strijken" -#: src/slic3r/GUI/GUI_Factories.cpp:130 src/libslic3r/PrintConfig.cpp:1279 -#: src/libslic3r/PrintConfig.cpp:1280 src/libslic3r/PrintConfig.cpp:1295 -#: src/libslic3r/PrintConfig.cpp:1305 +#: src/slic3r/GUI/GUI_Factories.cpp:130 src/libslic3r/PrintConfig.cpp:1278 +#: src/libslic3r/PrintConfig.cpp:1279 src/libslic3r/PrintConfig.cpp:1294 +#: src/libslic3r/PrintConfig.cpp:1304 msgid "Fuzzy Skin" msgstr "Oneffen oppervlak" #: src/slic3r/GUI/GUI_Factories.cpp:132 src/slic3r/GUI/GUI_Preview.cpp:220 #: src/slic3r/GUI/Tab.cpp:1581 src/libslic3r/PrintConfig.cpp:506 -#: src/libslic3r/PrintConfig.cpp:762 src/libslic3r/PrintConfig.cpp:1322 -#: src/libslic3r/PrintConfig.cpp:1513 src/libslic3r/PrintConfig.cpp:1595 -#: src/libslic3r/PrintConfig.cpp:1989 src/libslic3r/PrintConfig.cpp:2321 -#: src/libslic3r/PrintConfig.cpp:2374 src/libslic3r/PrintConfig.cpp:2872 +#: src/libslic3r/PrintConfig.cpp:762 src/libslic3r/PrintConfig.cpp:1321 +#: src/libslic3r/PrintConfig.cpp:1512 src/libslic3r/PrintConfig.cpp:1594 +#: src/libslic3r/PrintConfig.cpp:1988 src/libslic3r/PrintConfig.cpp:2320 +#: src/libslic3r/PrintConfig.cpp:2373 src/libslic3r/PrintConfig.cpp:2871 msgid "Speed" msgstr "Snelheid" #: src/slic3r/GUI/GUI_Factories.cpp:133 src/slic3r/GUI/Tab.cpp:1620 #: src/slic3r/GUI/Tab.cpp:2301 src/libslic3r/PrintConfig.cpp:792 -#: src/libslic3r/PrintConfig.cpp:1466 src/libslic3r/PrintConfig.cpp:1966 -#: src/libslic3r/PrintConfig.cpp:2342 src/libslic3r/PrintConfig.cpp:2616 -#: src/libslic3r/PrintConfig.cpp:2644 +#: src/libslic3r/PrintConfig.cpp:1465 src/libslic3r/PrintConfig.cpp:1965 +#: src/libslic3r/PrintConfig.cpp:2341 src/libslic3r/PrintConfig.cpp:2615 +#: src/libslic3r/PrintConfig.cpp:2643 msgid "Extruders" msgstr "Extruders" #: src/slic3r/GUI/GUI_Factories.cpp:134 src/libslic3r/PrintConfig.cpp:750 -#: src/libslic3r/PrintConfig.cpp:860 src/libslic3r/PrintConfig.cpp:1214 -#: src/libslic3r/PrintConfig.cpp:1474 src/libslic3r/PrintConfig.cpp:1975 -#: src/libslic3r/PrintConfig.cpp:2362 src/libslic3r/PrintConfig.cpp:2625 -#: src/libslic3r/PrintConfig.cpp:2859 +#: src/libslic3r/PrintConfig.cpp:860 src/libslic3r/PrintConfig.cpp:1213 +#: src/libslic3r/PrintConfig.cpp:1473 src/libslic3r/PrintConfig.cpp:1974 +#: src/libslic3r/PrintConfig.cpp:2361 src/libslic3r/PrintConfig.cpp:2624 +#: src/libslic3r/PrintConfig.cpp:2858 msgid "Extrusion Width" msgstr "Extrusiebreedte" @@ -3903,48 +3918,48 @@ msgstr "Skirt en brim" #: src/slic3r/GUI/Tab.cpp:1646 src/slic3r/GUI/Tab.cpp:2028 #: src/slic3r/GUI/Tab.cpp:2399 src/slic3r/GUI/Tab.cpp:4726 #: src/libslic3r/PrintConfig.cpp:259 src/libslic3r/PrintConfig.cpp:494 -#: src/libslic3r/PrintConfig.cpp:1415 src/libslic3r/PrintConfig.cpp:1502 -#: src/libslic3r/PrintConfig.cpp:1549 src/libslic3r/PrintConfig.cpp:2499 -#: src/libslic3r/PrintConfig.cpp:2509 src/libslic3r/PrintConfig.cpp:3047 -#: src/libslic3r/PrintConfig.cpp:3082 src/libslic3r/PrintConfig.cpp:3093 -#: src/libslic3r/PrintConfig.cpp:3108 src/libslic3r/PrintConfig.cpp:3121 -#: src/libslic3r/PrintConfig.cpp:3130 src/libslic3r/PrintConfig.cpp:3142 -#: src/libslic3r/PrintConfig.cpp:3339 +#: src/libslic3r/PrintConfig.cpp:1414 src/libslic3r/PrintConfig.cpp:1501 +#: src/libslic3r/PrintConfig.cpp:1548 src/libslic3r/PrintConfig.cpp:2498 +#: src/libslic3r/PrintConfig.cpp:2508 src/libslic3r/PrintConfig.cpp:3046 +#: src/libslic3r/PrintConfig.cpp:3081 src/libslic3r/PrintConfig.cpp:3092 +#: src/libslic3r/PrintConfig.cpp:3107 src/libslic3r/PrintConfig.cpp:3120 +#: src/libslic3r/PrintConfig.cpp:3129 src/libslic3r/PrintConfig.cpp:3141 +#: src/libslic3r/PrintConfig.cpp:3338 msgid "Advanced" msgstr "Geavanceerd" #: src/slic3r/GUI/GUI_Factories.cpp:140 src/slic3r/GUI/Plater.cpp:428 #: src/slic3r/GUI/Tab.cpp:4660 src/slic3r/GUI/Tab.cpp:4661 -#: src/libslic3r/PrintConfig.cpp:3533 src/libslic3r/PrintConfig.cpp:3540 -#: src/libslic3r/PrintConfig.cpp:3549 src/libslic3r/PrintConfig.cpp:3558 -#: src/libslic3r/PrintConfig.cpp:3568 src/libslic3r/PrintConfig.cpp:3578 -#: src/libslic3r/PrintConfig.cpp:3615 src/libslic3r/PrintConfig.cpp:3622 -#: src/libslic3r/PrintConfig.cpp:3633 src/libslic3r/PrintConfig.cpp:3643 -#: src/libslic3r/PrintConfig.cpp:3652 src/libslic3r/PrintConfig.cpp:3665 -#: src/libslic3r/PrintConfig.cpp:3675 src/libslic3r/PrintConfig.cpp:3684 -#: src/libslic3r/PrintConfig.cpp:3694 src/libslic3r/PrintConfig.cpp:3705 -#: src/libslic3r/PrintConfig.cpp:3713 +#: src/libslic3r/PrintConfig.cpp:3532 src/libslic3r/PrintConfig.cpp:3539 +#: src/libslic3r/PrintConfig.cpp:3548 src/libslic3r/PrintConfig.cpp:3557 +#: src/libslic3r/PrintConfig.cpp:3567 src/libslic3r/PrintConfig.cpp:3577 +#: src/libslic3r/PrintConfig.cpp:3614 src/libslic3r/PrintConfig.cpp:3621 +#: src/libslic3r/PrintConfig.cpp:3632 src/libslic3r/PrintConfig.cpp:3642 +#: src/libslic3r/PrintConfig.cpp:3651 src/libslic3r/PrintConfig.cpp:3664 +#: src/libslic3r/PrintConfig.cpp:3674 src/libslic3r/PrintConfig.cpp:3683 +#: src/libslic3r/PrintConfig.cpp:3693 src/libslic3r/PrintConfig.cpp:3704 +#: src/libslic3r/PrintConfig.cpp:3712 msgid "Supports" msgstr "Support" #: src/slic3r/GUI/GUI_Factories.cpp:141 src/slic3r/GUI/Plater.cpp:575 #: src/slic3r/GUI/Tab.cpp:4701 src/slic3r/GUI/Tab.cpp:4702 -#: src/slic3r/GUI/Tab.cpp:4774 src/libslic3r/PrintConfig.cpp:3721 -#: src/libslic3r/PrintConfig.cpp:3728 src/libslic3r/PrintConfig.cpp:3742 -#: src/libslic3r/PrintConfig.cpp:3753 src/libslic3r/PrintConfig.cpp:3763 -#: src/libslic3r/PrintConfig.cpp:3785 src/libslic3r/PrintConfig.cpp:3796 -#: src/libslic3r/PrintConfig.cpp:3803 src/libslic3r/PrintConfig.cpp:3810 -#: src/libslic3r/PrintConfig.cpp:3821 src/libslic3r/PrintConfig.cpp:3830 -#: src/libslic3r/PrintConfig.cpp:3839 +#: src/slic3r/GUI/Tab.cpp:4774 src/libslic3r/PrintConfig.cpp:3720 +#: src/libslic3r/PrintConfig.cpp:3727 src/libslic3r/PrintConfig.cpp:3741 +#: src/libslic3r/PrintConfig.cpp:3752 src/libslic3r/PrintConfig.cpp:3762 +#: src/libslic3r/PrintConfig.cpp:3784 src/libslic3r/PrintConfig.cpp:3795 +#: src/libslic3r/PrintConfig.cpp:3802 src/libslic3r/PrintConfig.cpp:3809 +#: src/libslic3r/PrintConfig.cpp:3820 src/libslic3r/PrintConfig.cpp:3829 +#: src/libslic3r/PrintConfig.cpp:3838 msgid "Pad" msgstr "Basisplaat" #: src/slic3r/GUI/GUI_Factories.cpp:142 src/slic3r/GUI/Tab.cpp:4719 #: src/slic3r/GUI/Tab.cpp:4720 src/libslic3r/SLA/Hollowing.cpp:73 #: src/libslic3r/SLA/Hollowing.cpp:85 src/libslic3r/SLA/Hollowing.cpp:105 -#: src/libslic3r/SLA/Hollowing.cpp:114 src/libslic3r/PrintConfig.cpp:3849 -#: src/libslic3r/PrintConfig.cpp:3856 src/libslic3r/PrintConfig.cpp:3866 -#: src/libslic3r/PrintConfig.cpp:3875 +#: src/libslic3r/SLA/Hollowing.cpp:114 src/libslic3r/PrintConfig.cpp:3848 +#: src/libslic3r/PrintConfig.cpp:3855 src/libslic3r/PrintConfig.cpp:3865 +#: src/libslic3r/PrintConfig.cpp:3874 msgid "Hollowing" msgstr "Uithollen" @@ -4037,13 +4052,13 @@ msgstr "Repareer met NetFabb" #: src/slic3r/GUI/GUI_Factories.cpp:715 msgid "Export as STL" -msgstr "Exporteer als STL-bestand" +msgstr "Exporteer als .STL-bestand" #: src/slic3r/GUI/GUI_Factories.cpp:726 msgid "Reload the selected volumes from disk" msgstr "Herlaad de geselecteerde volumes vanaf schijf" -#: src/slic3r/GUI/GUI_Factories.cpp:733 src/slic3r/GUI/Plater.cpp:3568 +#: src/slic3r/GUI/GUI_Factories.cpp:733 src/slic3r/GUI/Plater.cpp:3555 msgid "Replace with STL" msgstr "Vervang met STL" @@ -4057,7 +4072,7 @@ msgstr "Stel extruder in voor de geselecteerde items" #: src/slic3r/GUI/GUI_Factories.cpp:778 src/slic3r/Utils/Repetier.cpp:126 #: src/slic3r/Utils/Repetier.cpp:209 src/libslic3r/PrintConfig.cpp:634 -#: src/libslic3r/PrintConfig.cpp:2739 +#: src/libslic3r/PrintConfig.cpp:2738 msgid "Default" msgstr "Standaard" @@ -4069,24 +4084,24 @@ msgstr "Verschaal tot printvolume" msgid "Scale the selected object to fit the print volume" msgstr "Verschaal het geselecteerde object tot deze in het printvolume past" -#: src/slic3r/GUI/GUI_Factories.cpp:835 src/slic3r/GUI/Plater.cpp:5655 +#: src/slic3r/GUI/GUI_Factories.cpp:835 src/slic3r/GUI/Plater.cpp:5642 msgid "Convert from imperial units" msgstr "Converteer naar Engelse eenheden" -#: src/slic3r/GUI/GUI_Factories.cpp:836 src/slic3r/GUI/Plater.cpp:5656 +#: src/slic3r/GUI/GUI_Factories.cpp:836 src/slic3r/GUI/Plater.cpp:5643 msgid "Revert conversion from imperial units" msgstr "Conversie van Engelse eenheden ongedaan maken" -#: src/slic3r/GUI/GUI_Factories.cpp:837 src/slic3r/GUI/Plater.cpp:5657 +#: src/slic3r/GUI/GUI_Factories.cpp:837 src/slic3r/GUI/Plater.cpp:5644 msgid "Convert from meters" msgstr "Converteer vanaf meters" -#: src/slic3r/GUI/GUI_Factories.cpp:838 src/slic3r/GUI/Plater.cpp:5657 +#: src/slic3r/GUI/GUI_Factories.cpp:838 src/slic3r/GUI/Plater.cpp:5644 msgid "Revert conversion from meters" msgstr "Omrekenen van meters terugdraaien" -#: src/slic3r/GUI/GUI_Factories.cpp:859 src/slic3r/GUI/GUI_ObjectList.cpp:2135 -#: src/libslic3r/PrintConfig.cpp:4492 +#: src/slic3r/GUI/GUI_Factories.cpp:859 src/slic3r/GUI/GUI_ObjectList.cpp:2133 +#: src/libslic3r/PrintConfig.cpp:4491 msgid "Merge" msgstr "Samenvoegen" @@ -4147,7 +4162,7 @@ msgid "Split the selected object into individual parts" msgstr "Splits de geselecteerde objecten in individuele onderdelen" #: src/slic3r/GUI/GUI_Factories.cpp:944 src/slic3r/GUI/GUI_Factories.cpp:954 -#: src/slic3r/GUI/GUI_Factories.cpp:975 src/libslic3r/PrintConfig.cpp:4521 +#: src/slic3r/GUI/GUI_Factories.cpp:975 src/libslic3r/PrintConfig.cpp:4520 msgid "Split" msgstr "Splits" @@ -4265,7 +4280,7 @@ msgstr "Resterende fouten" #: src/slic3r/GUI/GUI_ObjectList.cpp:436 msgid "Right button click the icon to fix STL through Netfabb" msgstr "" -"Rechtermuisklik op het pictogram om het STL-bestand met NetFabb te repareren" +"Rechtermuisklik op het pictogram om het .STL-bestand met NetFabb te repareren" #: src/slic3r/GUI/GUI_ObjectList.cpp:482 msgid "Right button click the icon to change the object settings" @@ -4296,7 +4311,7 @@ msgid "Rename Sub-object" msgstr "Hernoem subobject" #: src/slic3r/GUI/GUI_ObjectList.cpp:1242 -#: src/slic3r/GUI/GUI_ObjectList.cpp:4006 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3997 msgid "Instances to Separated Objects" msgstr "Zet instanties om in objecten" @@ -4344,7 +4359,7 @@ msgstr "Laad bewerker" msgid "Loading" msgstr "Aan het laden" -#: src/slic3r/GUI/GUI_ObjectList.cpp:1540 src/slic3r/GUI/Plater.cpp:2417 +#: src/slic3r/GUI/GUI_ObjectList.cpp:1540 src/slic3r/GUI/Plater.cpp:2406 msgid "Loading file" msgstr "Bestand laden" @@ -4386,7 +4401,7 @@ msgstr "Verplaats objecten naar bed" #: src/slic3r/GUI/GUI_ObjectList.cpp:1856 msgid "Remove variable layer height" -msgstr "Verwijder variable laagdikte" +msgstr "Verwijder variabele laagdikte" #: src/slic3r/GUI/GUI_ObjectList.cpp:1877 msgid "Delete Settings" @@ -4427,69 +4442,69 @@ msgstr "" msgid "Split to Parts" msgstr "Splits naar onderdelen" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2142 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2140 msgid "Merged" msgstr "Samengevoegd" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2237 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2228 msgid "Merge all parts to the one single object" msgstr "Voeg alle delen samen tot een enkel object" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2269 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2260 msgid "Add Layers" msgstr "Voeg lagen toe" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2438 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2429 msgid "Group manipulation" msgstr "Groep bewerken" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2453 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2444 msgid "Object manipulation" msgstr "Object bewerken" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2486 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2477 msgid "Object Settings to modify" msgstr "Objectinstellingen om te bewerken" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2490 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2481 msgid "Part Settings to modify" msgstr "Onderdeelinstellingen om te bewerken" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2495 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2486 msgid "Layer range Settings to modify" msgstr "Laagbereikinstellingen om te bewerken" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2501 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2492 msgid "Part manipulation" msgstr "Onderdeel bewerken" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2507 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2498 msgid "Instance manipulation" msgstr "Instantie bewerken" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2514 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2505 msgid "Height ranges" msgstr "Hoogtebereik" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2514 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2505 msgid "Settings for height range" msgstr "Instellingen voor hoogtebereik" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2750 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2741 msgid "Delete Selected Item" msgstr "Verwijder geselecteerd item" -#: src/slic3r/GUI/GUI_ObjectList.cpp:2943 +#: src/slic3r/GUI/GUI_ObjectList.cpp:2934 msgid "Delete Selected" msgstr "Verwijder selectie" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3019 -#: src/slic3r/GUI/GUI_ObjectList.cpp:3047 -#: src/slic3r/GUI/GUI_ObjectList.cpp:3067 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3010 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3038 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3058 msgid "Add Height Range" msgstr "Voeg hoogtebereik toe" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3113 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3104 msgid "" "Cannot insert a new layer range after the current layer range.\n" "The next layer range is too thin to be split to two\n" @@ -4499,7 +4514,7 @@ msgstr "" "Het volgende laagbereik is te dun om in tweeën te splitsen\n" "zonder over de minimale laagdikte heen te gaan." -#: src/slic3r/GUI/GUI_ObjectList.cpp:3117 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3108 msgid "" "Cannot insert a new layer range between the current and the next layer " "range.\n" @@ -4511,7 +4526,7 @@ msgstr "" "Het gat tussen het huidige en volgende laagbereik is kleiner dan\n" "de minimum toegestane laagdikte." -#: src/slic3r/GUI/GUI_ObjectList.cpp:3122 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3113 msgid "" "Cannot insert a new layer range after the current layer range.\n" "Current layer range overlaps with the next layer range." @@ -4519,144 +4534,144 @@ msgstr "" "Kan geen nieuw laagbereik toevoegen na het huidige laagbereik.\n" "Het huidige laagbereik overlapt met het volgende laagbereik." -#: src/slic3r/GUI/GUI_ObjectList.cpp:3181 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3172 msgid "Edit Height Range" msgstr "Bewerk hoogtebereik" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3500 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3491 msgid "Selection-Remove from list" msgstr "Selectie - Verwijder van lijst" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3512 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3503 msgid "Selection-Add from list" msgstr "Selectie - Voeg toe aan lijst" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3649 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3640 msgid "Object or Instance" msgstr "Object of instantie" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3650 -#: src/slic3r/GUI/GUI_ObjectList.cpp:3789 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3641 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3780 msgid "Part" msgstr "Onderdeel" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3650 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3641 msgid "Layer" msgstr "Laag" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3652 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3643 msgid "Unsupported selection" msgstr "Niet-ondersteunde selectie" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3653 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3644 #, c-format, boost-format msgid "You started your selection with %s Item." msgstr "De selectie is gestart met item %s." -#: src/slic3r/GUI/GUI_ObjectList.cpp:3654 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3645 #, c-format, boost-format msgid "In this mode you can select only other %s Items%s" msgstr "In deze modus kunt u alleen andere %s items %s selecteren" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3657 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3648 msgid "of a current Object" msgstr "van het huidige object" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3662 -#: src/slic3r/GUI/GUI_ObjectList.cpp:3737 src/slic3r/GUI/Plater.cpp:181 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3653 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3728 src/slic3r/GUI/Plater.cpp:181 msgid "Info" msgstr "Info" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3784 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3775 msgid "You can't change a type of the last solid part of the object." msgstr "" "U kunt het type van het laatste onderdeel van een object niet wijzigen." -#: src/slic3r/GUI/GUI_ObjectList.cpp:3789 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3780 msgid "Negative Volume" msgstr "Negatief volume" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3789 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3780 msgid "Modifier" msgstr "Modificator" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3789 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3780 msgid "Support Blocker" msgstr "Supportblokkering" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3789 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3780 msgid "Support Enforcer" msgstr "Supportforcering" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3790 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3781 msgid "Select type of part" msgstr "Selecteer onderdeeltype" -#: src/slic3r/GUI/GUI_ObjectList.cpp:3795 +#: src/slic3r/GUI/GUI_ObjectList.cpp:3786 msgid "Change Part Type" msgstr "Wijzig onderdeeltype" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4028 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4019 msgid "Enter new name" msgstr "Voer nieuwe naam in" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4028 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4019 msgid "Renaming" msgstr "Hernoemen" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4091 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4082 msgid "Repairing model" msgstr "Model repareren" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4120 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4111 msgid "Fix through NetFabb" msgstr "Repareer met NetFabb" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4123 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4114 msgid "Fixing through NetFabb" msgstr "Repareren met NetFabb" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4153 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4144 msgid "The following model was repaired successfully" msgid_plural "The following models were repaired successfully" msgstr[0] "Het volgende model is succesvol gerepareerd" msgstr[1] "De volgende modellen zijn succesvol gerepareerd" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4159 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4150 msgid "Folowing model repair failed" msgid_plural "Folowing models repair failed" msgstr[0] "Volgende model repareren mislukt" msgstr[1] "Volgende modellen repareren mislukt" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4164 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4155 msgid "Repairing was canceled" msgstr "Repareren is stopgezet" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4276 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4267 msgid "Change Extruders" msgstr "Wijzig extruders" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4416 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4407 msgid "Set Printable group" msgstr "Stel printbare groep in" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4416 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4407 msgid "Set Unprintable group" msgstr "Stel onprintbare groep in" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4418 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4409 msgid "Set Printable" msgstr "Stel in op printbaar" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4418 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4409 msgid "Set Unprintable" msgstr "Stel in op niet-printbaar" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4419 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4410 msgid "Set Printable Instance" msgstr "Stel printbare instanties in" -#: src/slic3r/GUI/GUI_ObjectList.cpp:4419 +#: src/slic3r/GUI/GUI_ObjectList.cpp:4410 msgid "Set Unprintable Instance" msgstr "Stel instantie in op niet-printbaar" @@ -4797,7 +4812,7 @@ msgstr "Weergave" msgid "Height" msgstr "Hoogte" -#: src/slic3r/GUI/GUI_Preview.cpp:219 src/libslic3r/PrintConfig.cpp:3001 +#: src/slic3r/GUI/GUI_Preview.cpp:219 src/libslic3r/PrintConfig.cpp:3000 msgid "Width" msgstr "Breedte" @@ -4842,14 +4857,14 @@ msgid "Internal infill" msgstr "Inwendige vulling" #: src/slic3r/GUI/GUI_Preview.cpp:243 src/libslic3r/ExtrusionEntity.cpp:334 -#: src/libslic3r/ExtrusionEntity.cpp:360 src/libslic3r/PrintConfig.cpp:2361 -#: src/libslic3r/PrintConfig.cpp:2373 +#: src/libslic3r/ExtrusionEntity.cpp:360 src/libslic3r/PrintConfig.cpp:2360 +#: src/libslic3r/PrintConfig.cpp:2372 msgid "Solid infill" msgstr "Dichte vulling" #: src/slic3r/GUI/GUI_Preview.cpp:244 src/libslic3r/ExtrusionEntity.cpp:335 -#: src/libslic3r/ExtrusionEntity.cpp:362 src/libslic3r/PrintConfig.cpp:2858 -#: src/libslic3r/PrintConfig.cpp:2871 +#: src/libslic3r/ExtrusionEntity.cpp:362 src/libslic3r/PrintConfig.cpp:2857 +#: src/libslic3r/PrintConfig.cpp:2870 msgid "Top solid infill" msgstr "Bovenste dichte vulling" @@ -4859,7 +4874,7 @@ msgid "Bridge infill" msgstr "Brugvulling" #: src/slic3r/GUI/GUI_Preview.cpp:247 src/libslic3r/ExtrusionEntity.cpp:338 -#: src/libslic3r/ExtrusionEntity.cpp:368 src/libslic3r/PrintConfig.cpp:1321 +#: src/libslic3r/ExtrusionEntity.cpp:368 src/libslic3r/PrintConfig.cpp:1320 msgid "Gap fill" msgstr "Gatenvulling" @@ -4869,7 +4884,7 @@ msgid "Skirt/Brim" msgstr "Skirt/Brim" #: src/slic3r/GUI/GUI_Preview.cpp:250 src/libslic3r/ExtrusionEntity.cpp:341 -#: src/libslic3r/ExtrusionEntity.cpp:374 src/libslic3r/PrintConfig.cpp:2705 +#: src/libslic3r/ExtrusionEntity.cpp:374 src/libslic3r/PrintConfig.cpp:2704 msgid "Support material interface" msgstr "Supportinterface" @@ -4982,15 +4997,15 @@ msgstr "Er is een onverwachte fout opgetreden" #: src/slic3r/GUI/Jobs/RotoptimizeJob.hpp:21 msgid "Best surface quality" -msgstr "" +msgstr "Beste oppervlaktekwaliteit" #: src/slic3r/GUI/Jobs/RotoptimizeJob.hpp:23 msgid "Optimize object rotation for best surface quality." -msgstr "" +msgstr "Optimaliseer objectrotatie voor beste oppervlaktekwaliteit." #: src/slic3r/GUI/Jobs/RotoptimizeJob.hpp:24 msgid "Reduced overhang slopes" -msgstr "" +msgstr "Gereduceerde overhanghellingen" #: src/slic3r/GUI/Jobs/RotoptimizeJob.hpp:26 msgid "" @@ -4999,14 +5014,18 @@ msgid "" "Note that this method will try to find the best surface of the object for " "touching the print bed if no elevation is set." msgstr "" +"Optimaliseer objectrotatie voor een minimale hoeveelheid overhangingen die " +"support nodig hebben.\n" +"Let op dat deze methode zoekt naar het beste vlak van het object om op het " +"printbed te leggen als geen verhoging ingesteld is." #: src/slic3r/GUI/Jobs/RotoptimizeJob.hpp:30 msgid "Lowest Z height" -msgstr "" +msgstr "Laagste Z-hoogte" #: src/slic3r/GUI/Jobs/RotoptimizeJob.hpp:32 msgid "Rotate the model to have the lowest z height for faster print time." -msgstr "" +msgstr "Roteer het model voor een minimale hoogte voor snellere printtijd." #: src/slic3r/GUI/Jobs/RotoptimizeJob.cpp:59 msgid "Searching for optimal orientation" @@ -5074,7 +5093,7 @@ msgstr "Succesvol geïmporteerd." #: src/slic3r/GUI/Jobs/SLAImportJob.cpp:187 msgid "The file does not exist." -msgstr "" +msgstr "Het bestand bestaat niet." #: src/slic3r/GUI/Jobs/SLAImportJob.cpp:221 msgid "" @@ -5084,11 +5103,11 @@ msgstr "" "Het geïmporteerde SLA-archief bevat geen presets. De huidige SLA-presets " "worden gebruikt als oplossing." -#: src/slic3r/GUI/Jobs/SLAImportJob.cpp:234 src/slic3r/GUI/Plater.cpp:2458 +#: src/slic3r/GUI/Jobs/SLAImportJob.cpp:234 src/slic3r/GUI/Plater.cpp:2447 msgid "You cannot load SLA project with a multi-part object on the bed" msgstr "U kunt geen SLA-project laden met een meerdelig object op het bed" -#: src/slic3r/GUI/Jobs/SLAImportJob.cpp:236 src/slic3r/GUI/Plater.cpp:2460 +#: src/slic3r/GUI/Jobs/SLAImportJob.cpp:236 src/slic3r/GUI/Plater.cpp:2449 msgid "Attention!" msgstr "Attentie!" @@ -5101,42 +5120,44 @@ msgid "New project, clear plater" msgstr "Start nieuw project, verwijder modellen" #: src/slic3r/GUI/KBShortcutsDialog.cpp:78 -msgid "Open project AMF/3MF with config, clear plater" -msgstr "Open AMF- of 3MF-project met configuratie, verwijder huidige modellen" +msgid "Open project STL/OBJ/AMF/3MF with config, clear plater" +msgstr "" +"Open .STL-, .OBJ-, .AMF- of .3MF-project met configuratie, verwijder huidige " +"modellen" #: src/slic3r/GUI/KBShortcutsDialog.cpp:79 msgid "Save project (3mf)" -msgstr "3MF-project opslaan" +msgstr ".3MF-project opslaan" #: src/slic3r/GUI/KBShortcutsDialog.cpp:80 msgid "Save project as (3mf)" -msgstr "3MF-project opslaan als" +msgstr ".3MF-project opslaan als" #: src/slic3r/GUI/KBShortcutsDialog.cpp:81 msgid "(Re)slice" msgstr "(Her)slice" #: src/slic3r/GUI/KBShortcutsDialog.cpp:83 -msgid "Import STL/3MF/STEP/OBJ/AMF without config, keep plater" +msgid "Import STL/OBJ/AMF/3MF without config, keep plater" msgstr "" -"Importeer STL-, 3MF-, STEP-, OBJ- of AMF-bestanden zonder configuratie en " +"Importeer .STL-, .OBJ-, .AMF- of .3MF-bestanden zonder configuratie en " "behoud modellen" #: src/slic3r/GUI/KBShortcutsDialog.cpp:84 msgid "Import Config from ini/amf/3mf/gcode" -msgstr "Importeer configuratie van INI-, AMF-, 3MF- of gcode-bestand" +msgstr "Importeer configuratie van .INI-, .AMF-, .3MF- of .gcode-bestand" #: src/slic3r/GUI/KBShortcutsDialog.cpp:85 msgid "Load Config from ini/amf/3mf/gcode and merge" msgstr "" -"Laad configuratie van INI-, AMF-, 3MF- of gcode-bestanden en voeg samen" +"Laad configuratie van .INI-, .AMF-, .3MF- of .gcode-bestanden en voeg samen" #: src/slic3r/GUI/KBShortcutsDialog.cpp:87 src/slic3r/GUI/Plater.cpp:913 -#: src/slic3r/GUI/Plater.cpp:6543 src/libslic3r/PrintConfig.cpp:4392 +#: src/slic3r/GUI/Plater.cpp:6530 src/libslic3r/PrintConfig.cpp:4391 msgid "Export G-code" -msgstr "Exporteer gcode-bestand" +msgstr "Exporteer .gcode-bestand" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:88 src/slic3r/GUI/Plater.cpp:6544 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:88 src/slic3r/GUI/Plater.cpp:6531 msgid "Send G-code" msgstr "Stuur G-code" @@ -5409,7 +5430,8 @@ msgstr "Klap de zijbalk in/uit" #: src/slic3r/GUI/KBShortcutsDialog.cpp:166 msgid "Show/Hide 3Dconnexion devices settings dialog, if enabled" msgstr "" -"Toon/verberg 3DConnexion-apparaten-instellingenvenster als dit aanstaat" +"Toon/verberg 3DConnexion-apparaten-instellingenvenster als dit is " +"ingeschakeld" #: src/slic3r/GUI/KBShortcutsDialog.cpp:169 #: src/slic3r/GUI/KBShortcutsDialog.cpp:172 @@ -5527,7 +5549,7 @@ msgstr "Toon/verberg legenda en geschatte printtijd" msgid "Show/Hide G-code window" msgstr "Toon/verberg G-code venster" -#: src/slic3r/GUI/KBShortcutsDialog.cpp:230 src/slic3r/GUI/Plater.cpp:4480 +#: src/slic3r/GUI/KBShortcutsDialog.cpp:230 src/slic3r/GUI/Plater.cpp:4467 #: src/slic3r/GUI/Tab.cpp:2829 msgid "Preview" msgstr "Sliceweergave" @@ -5667,7 +5689,7 @@ msgid "Printer Settings" msgstr "Printerinstellingen" #: src/slic3r/GUI/MainFrame.cpp:632 src/slic3r/GUI/Plater.cpp:1719 -#: src/slic3r/GUI/Plater.cpp:2850 +#: src/slic3r/GUI/Plater.cpp:2839 msgid "Untitled" msgstr "Zonder titel" @@ -5694,7 +5716,7 @@ msgstr "Download de laatste softwareversie vanuit uw browser" #: src/slic3r/GUI/MainFrame.cpp:1081 #, c-format, boost-format msgid "%s &Website" -msgstr "%s-&website" +msgstr "%s-website" #: src/slic3r/GUI/MainFrame.cpp:1082 #, c-format, boost-format @@ -5729,7 +5751,7 @@ msgstr "Rapporteer een fout op %s" #: src/slic3r/GUI/MainFrame.cpp:1095 src/slic3r/GUI/MainFrame.cpp:1098 #, c-format, boost-format msgid "&About %s" -msgstr "&Over %s" +msgstr "Over %s" #: src/slic3r/GUI/MainFrame.cpp:1095 src/slic3r/GUI/MainFrame.cpp:1098 msgid "Show about dialog" @@ -5761,8 +5783,8 @@ msgstr "Isometrisch aanzicht" #. 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:1125 src/libslic3r/PrintConfig.cpp:2886 -#: src/libslic3r/PrintConfig.cpp:2895 +#: src/slic3r/GUI/MainFrame.cpp:1125 src/libslic3r/PrintConfig.cpp:2885 +#: src/libslic3r/PrintConfig.cpp:2894 msgid "Top" msgstr "Bovenkant" @@ -5790,7 +5812,7 @@ msgstr "Voorkant" msgid "Front View" msgstr "Vooraanzicht" -#: src/slic3r/GUI/MainFrame.cpp:1132 src/libslic3r/PrintConfig.cpp:2243 +#: src/slic3r/GUI/MainFrame.cpp:1132 src/libslic3r/PrintConfig.cpp:2242 msgid "Rear" msgstr "Achterzijde" @@ -5859,8 +5881,8 @@ msgid "Save current project file as" msgstr "Projectbestand opslaan als" #: src/slic3r/GUI/MainFrame.cpp:1208 -msgid "Import STL/3MF/STEP/OBJ/AM&F" -msgstr "Importeer STL-, 3MF-, STEP-, OBJ- of AMF-bestanden" +msgid "Import STL/OBJ/AM&F/3MF" +msgstr "Importeer .STL-, .OBJ-, .AMF- of .3MF-bestanden" #: src/slic3r/GUI/MainFrame.cpp:1208 msgid "Load a model" @@ -5916,7 +5938,7 @@ msgstr "Exporteer G-code" #: src/slic3r/GUI/MainFrame.cpp:1234 msgid "Export current plate as G-code" -msgstr "Exporteer modellen als gcode-bestand" +msgstr "Exporteer modellen als .gcode-bestand" #: src/slic3r/GUI/MainFrame.cpp:1238 src/slic3r/GUI/MainFrame.cpp:1587 msgid "S&end G-code" @@ -5940,7 +5962,7 @@ msgstr "Exporteer modellen als STL" #: src/slic3r/GUI/MainFrame.cpp:1246 msgid "Export current plate as STL" -msgstr "Exporteer modellen als STL-bestand" +msgstr "Exporteer modellen als .STL-bestand" #: src/slic3r/GUI/MainFrame.cpp:1249 msgid "Export Plate as STL &Including Supports" @@ -5948,7 +5970,7 @@ msgstr "Exporteer modellen inclusief supports als STL" #: src/slic3r/GUI/MainFrame.cpp:1249 msgid "Export current plate as STL including supports" -msgstr "Exporteer modellen met support als STL-bestand" +msgstr "Exporteer modellen met support als .STL-bestand" #: src/slic3r/GUI/MainFrame.cpp:1257 src/slic3r/GUI/MainFrame.cpp:1538 msgid "Export &Toolpaths as OBJ" @@ -5956,7 +5978,7 @@ msgstr "Exporteer toolpaden als OBJ" #: src/slic3r/GUI/MainFrame.cpp:1257 src/slic3r/GUI/MainFrame.cpp:1538 msgid "Export toolpaths as OBJ" -msgstr "Exporteer toolpaden als OBJ-bestand" +msgstr "Exporteer toolpaden als .OBJ-bestand" #: src/slic3r/GUI/MainFrame.cpp:1261 msgid "Export &Config" @@ -6000,7 +6022,7 @@ msgstr "Snel slicen" #: src/slic3r/GUI/MainFrame.cpp:1280 msgid "Slice a file into a G-code" -msgstr "Slice naar een gcode-bestand" +msgstr "Slice naar een .gcode-bestand" #: src/slic3r/GUI/MainFrame.cpp:1286 msgid "Quick Slice and Save As" @@ -6008,7 +6030,7 @@ msgstr "Snel slicen en opslaan als" #: src/slic3r/GUI/MainFrame.cpp:1286 msgid "Slice a file into a G-code, save as" -msgstr "Slice naar gcode-bestand, opslaan als" +msgstr "Slice naar .gcode-bestand, opslaan als" #: src/slic3r/GUI/MainFrame.cpp:1292 msgid "Repeat Last Quick Slice" @@ -6020,7 +6042,7 @@ msgstr "Herhaal laatste snelle slice" #: src/slic3r/GUI/MainFrame.cpp:1300 msgid "(Re)Slice No&w" -msgstr "(&Her)slice nu" +msgstr "(Her)slice nu" #: src/slic3r/GUI/MainFrame.cpp:1300 msgid "Start new slicing process" @@ -6028,11 +6050,11 @@ msgstr "Start nieuw sliceproces" #: src/slic3r/GUI/MainFrame.cpp:1304 msgid "&Repair STL file" -msgstr "&Repareer STL-bestand" +msgstr "Repareer .STL-bestand" #: src/slic3r/GUI/MainFrame.cpp:1304 msgid "Automatically repair an STL file" -msgstr "Automatisch een STL-bestand repareren" +msgstr "Automatisch een .STL-bestand repareren" #: src/slic3r/GUI/MainFrame.cpp:1308 msgid "&G-code Preview" @@ -6231,15 +6253,15 @@ msgstr "Toon" #: src/slic3r/GUI/MainFrame.cpp:1463 src/slic3r/GUI/MainFrame.cpp:1564 msgid "&Help" -msgstr "&Help" +msgstr "Help" #: src/slic3r/GUI/MainFrame.cpp:1525 msgid "&Open G-code" -msgstr "&Open G-code" +msgstr "Open G-code" #: src/slic3r/GUI/MainFrame.cpp:1541 msgid "Open &PrusaSlicer" -msgstr "Open &PrusaSlicer" +msgstr "Open PrusaSlicer" #: src/slic3r/GUI/MainFrame.cpp:1586 msgid "E&xport" @@ -6255,7 +6277,7 @@ msgstr "Materiaalinstellingentab" #: src/slic3r/GUI/MainFrame.cpp:1613 msgid "Choose a file to slice (STL/OBJ/AMF/3MF/PRUSA):" -msgstr "Kies een STL-, OBJ-, AMF-, 3MF- of PRUSA-bestand om te slicen:" +msgstr "Kies een .STL-, .OBJ-, .AMF-, .3MF- of .PRUSA-bestand om te slicen:" #: src/slic3r/GUI/MainFrame.cpp:1625 msgid "No previously sliced file." @@ -6288,10 +6310,10 @@ msgstr "G-code" #: src/slic3r/GUI/MainFrame.cpp:1680 msgid "Save zip file as:" -msgstr "ZIP-bestand opslaan als:" +msgstr ".ZIP-bestand opslaan als:" -#: src/slic3r/GUI/MainFrame.cpp:1689 src/slic3r/GUI/Plater.cpp:3329 -#: src/slic3r/GUI/Plater.cpp:6064 src/slic3r/GUI/Tab.cpp:1663 +#: src/slic3r/GUI/MainFrame.cpp:1689 src/slic3r/GUI/Plater.cpp:3316 +#: src/slic3r/GUI/Plater.cpp:6051 src/slic3r/GUI/Tab.cpp:1663 #: src/slic3r/GUI/Tab.cpp:4727 msgid "Slicing" msgstr "Slicen" @@ -6313,17 +6335,17 @@ msgstr "Slicen klaar!" #: src/slic3r/GUI/MainFrame.cpp:1733 msgid "Select the STL file to repair:" -msgstr "Selecteer het STL-bestand om te repareren:" +msgstr "Selecteer het .STL-bestand om te repareren:" #: src/slic3r/GUI/MainFrame.cpp:1743 msgid "Save OBJ file (less prone to coordinate errors than STL) as:" -msgstr "OBJ-bestand opslaan als:" +msgstr ".OBJ-bestand opslaan als:" #: src/slic3r/GUI/MainFrame.cpp:1754 msgid "Your file was repaired." msgstr "Het bestand is gerepareerd." -#: src/slic3r/GUI/MainFrame.cpp:1754 src/libslic3r/PrintConfig.cpp:4497 +#: src/slic3r/GUI/MainFrame.cpp:1754 src/libslic3r/PrintConfig.cpp:4496 msgid "Repair" msgstr "Repareer" @@ -6406,7 +6428,7 @@ msgstr "%s fout" #: src/slic3r/GUI/MsgDialog.cpp:228 #, c-format, boost-format msgid "%s has encountered an error" -msgstr "%s heeft een fout veroorzaakt" +msgstr "%s heeft een fout opgelopen" #: src/slic3r/GUI/MsgDialog.cpp:247 #, c-format, boost-format @@ -6506,22 +6528,22 @@ msgstr "Annuleer upload" #, c-format, boost-format msgid "%1$d object was loaded with custom supports." msgid_plural "%1$d objects were loaded with custom supports." -msgstr[0] "%1$d object is geladen met aangepaste supports." -msgstr[1] "%1$d objecten zijn geladen met aangepaste supports." +msgstr[0] "%1$d object is geladen met custom supports." +msgstr[1] "%1$d objecten zijn geladen met custom supports." #: src/slic3r/GUI/NotificationManager.cpp:997 #, c-format, boost-format msgid "%1$d object was loaded with custom seam." msgid_plural "%1$d objects were loaded with custom seam." -msgstr[0] "%1$d object is geladen met aangepaste naad." -msgstr[1] "%1$d objecten zijn geladen met aangepaste naad." +msgstr[0] "%1$d object is geladen met een custom naad." +msgstr[1] "%1$d objecten zijn geladen met een custom naad." #: src/slic3r/GUI/NotificationManager.cpp:998 #, c-format, boost-format msgid "%1$d object was loaded with multimaterial painting." msgid_plural "%1$d objects were loaded with multimaterial painting." -msgstr[0] "%1$d object is geladen met multi-material inkleuring." -msgstr[1] "%1$d objecten zijn geladen met multi-material inkleuring." +msgstr[0] "%1$d object is geladen met multi-materiaal schilderingen." +msgstr[1] "%1$d objecten zijn geladen met multi-materiaal schilderingen." #: src/slic3r/GUI/NotificationManager.cpp:999 #, c-format, boost-format @@ -6534,8 +6556,8 @@ msgstr[1] "%1$d objecten zijn geladen met variabele laagdikte." #, c-format, boost-format msgid "%1$d object was loaded with partial sinking." msgid_plural "%1$d objects were loaded with partial sinking." -msgstr[0] "%1$d object is geladen met een (gedeeltelijke) verzakking." -msgstr[1] "%1$d objecten zijn geladen met een (gedeeltelijke) verzakking." +msgstr[0] "%1$d object is geladen met gedeeltelijk verzakken." +msgstr[1] "%1$d objecten zijn geladen met gedeeltelijk verzakken." #: src/slic3r/GUI/NotificationManager.cpp:1113 msgid "Slicing finished." @@ -6560,7 +6582,7 @@ msgstr "Fout:" #: src/slic3r/GUI/NotificationManager.cpp:1459 #: src/slic3r/GUI/NotificationManager.cpp:1486 #: src/slic3r/GUI/NotificationManager.cpp:1494 -#: src/slic3r/GUI/NotificationManager.cpp:1505 src/slic3r/GUI/Plater.cpp:3197 +#: src/slic3r/GUI/NotificationManager.cpp:1505 src/slic3r/GUI/Plater.cpp:3184 msgid "WARNING:" msgstr "Waarschuwing:" @@ -6595,7 +6617,7 @@ msgstr "Lagen" msgid "Range" msgstr "Bereik" -#: src/slic3r/GUI/OpenGLManager.cpp:258 +#: src/slic3r/GUI/OpenGLManager.cpp:257 #, c-format, boost-format msgid "" "PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n" @@ -6604,11 +6626,11 @@ msgstr "" "PrusaSlicer vereist een grafische driver die OpenGL 2.0 kan draaien,\n" "terwijl OpenGL-versie %s, render %s, leverancier %s is gedetecteerd." -#: src/slic3r/GUI/OpenGLManager.cpp:261 +#: src/slic3r/GUI/OpenGLManager.cpp:260 msgid "You may need to update your graphics card driver." msgstr "U moet mogelijk uw grafische kaart updaten." -#: src/slic3r/GUI/OpenGLManager.cpp:264 +#: src/slic3r/GUI/OpenGLManager.cpp:263 msgid "" "As a workaround, you may run PrusaSlicer with a software rendered 3D " "graphics by running prusa-slicer.exe with the --sw-renderer parameter." @@ -6617,11 +6639,11 @@ msgstr "" "modelweergave door prusa-slicer.exe te draaien met de --sw-renderer " "parameter." -#: src/slic3r/GUI/OpenGLManager.cpp:266 +#: src/slic3r/GUI/OpenGLManager.cpp:265 msgid "Unsupported OpenGL version" msgstr "Niet-ondersteunde OpenGL-versie" -#: src/slic3r/GUI/OpenGLManager.cpp:274 +#: src/slic3r/GUI/OpenGLManager.cpp:273 #, c-format, boost-format msgid "" "Unable to load the following shaders:\n" @@ -6630,7 +6652,7 @@ msgstr "" "Kan de volgende sjablonen niet laden:\n" "%s" -#: src/slic3r/GUI/OpenGLManager.cpp:275 +#: src/slic3r/GUI/OpenGLManager.cpp:274 msgid "Error loading shaders" msgstr "Fout bij het laden van de sjablonen" @@ -6732,7 +6754,7 @@ msgstr "De ingevoerde naam is leeg. Kan niet opgeslagen worden." #: src/slic3r/GUI/PhysicalPrinterDialog.cpp:634 msgid "You have to enter a printer name." -msgstr "" +msgstr "U moet een printernaam invoeren." #: src/slic3r/GUI/PhysicalPrinterDialog.cpp:642 #, boost-format @@ -6825,8 +6847,8 @@ msgstr "Aantal toolwisselingen" msgid "Select what kind of support do you need" msgstr "Selecteer welk type support nodig is" -#: src/slic3r/GUI/Plater.cpp:433 src/libslic3r/PrintConfig.cpp:2559 -#: src/libslic3r/PrintConfig.cpp:3614 +#: src/slic3r/GUI/Plater.cpp:433 src/libslic3r/PrintConfig.cpp:2558 +#: src/libslic3r/PrintConfig.cpp:3613 msgid "Support on build plate only" msgstr "Support alleen op het bed" @@ -6864,12 +6886,12 @@ msgstr "Onder het object" msgid "Around object" msgstr "Rondom het object" -#: src/slic3r/GUI/Plater.cpp:894 src/slic3r/GUI/Plater.cpp:6544 +#: src/slic3r/GUI/Plater.cpp:894 src/slic3r/GUI/Plater.cpp:6531 msgid "Send to printer" msgstr "Stuur naar printer" -#: src/slic3r/GUI/Plater.cpp:914 src/slic3r/GUI/Plater.cpp:3329 -#: src/slic3r/GUI/Plater.cpp:6067 +#: src/slic3r/GUI/Plater.cpp:914 src/slic3r/GUI/Plater.cpp:3316 +#: src/slic3r/GUI/Plater.cpp:6054 msgid "Slice now" msgstr "Slice nu" @@ -6923,8 +6945,8 @@ msgstr "Filament in extruder %1%" msgid "(including spool)" msgstr "(inclusief spoel)" -#: src/slic3r/GUI/Plater.cpp:1411 src/libslic3r/PrintConfig.cpp:1068 -#: src/libslic3r/PrintConfig.cpp:3408 src/libslic3r/PrintConfig.cpp:3409 +#: src/slic3r/GUI/Plater.cpp:1411 src/libslic3r/PrintConfig.cpp:1067 +#: src/libslic3r/PrintConfig.cpp:3407 src/libslic3r/PrintConfig.cpp:3408 msgid "Cost" msgstr "Kosten" @@ -6955,7 +6977,7 @@ msgstr "Wilt u de wijzigingen opslaan naar \"%1%\"?" #: src/slic3r/GUI/Plater.cpp:1730 src/slic3r/GUI/Preferences.cpp:222 msgid "Ask for unsaved changes in project" -msgstr "" +msgstr "Vraag naar niet-opgeslagen wijzigingen in dit project" #: src/slic3r/GUI/Plater.cpp:1733 msgid "" @@ -6963,6 +6985,9 @@ msgid "" "- Closing PrusaSlicer,\n" "- Loading or creating a new project" msgstr "" +"U wordt hier niet opnieuw over gevraagd bij:\n" +"- het sluiten van PrusaSlicer;\n" +"- het laden of openen van een nieuw project" #: src/slic3r/GUI/Plater.cpp:2198 #, c-format, boost-format @@ -6978,7 +7003,7 @@ msgstr "" msgid "Ejecting of device %s(%s) has failed." msgstr "Uitwerpen van apparat %s(%s) mislukt." -#: src/slic3r/GUI/Plater.cpp:2222 src/slic3r/GUI/Plater.cpp:5108 +#: src/slic3r/GUI/Plater.cpp:2222 src/slic3r/GUI/Plater.cpp:5095 msgid "New Project" msgstr "Nieuw project" @@ -6986,7 +7011,7 @@ msgstr "Nieuw project" msgid "Expand sidebar" msgstr "Zijbalk uitklappen" -#: src/slic3r/GUI/Plater.cpp:2518 +#: src/slic3r/GUI/Plater.cpp:2507 msgid "" "The preset below was temporarily installed on the active instance of " "PrusaSlicer" @@ -7000,12 +7025,12 @@ msgstr[1] "" "De vorige presets zijn tijdelijk geïnstalleerd op de actieve instantie van " "PrusaSlicer" -#: src/slic3r/GUI/Plater.cpp:2548 +#: src/slic3r/GUI/Plater.cpp:2537 #, boost-format msgid "Failed loading file \"%1%\" due to an invalid configuration." msgstr "Laden van bestand \"%1%\" mislukt dankzij een ongeldige configuratie." -#: src/slic3r/GUI/Plater.cpp:2568 +#: src/slic3r/GUI/Plater.cpp:2557 #, c-format, boost-format msgid "" "Object size from file %s appears to be zero.\n" @@ -7020,11 +7045,11 @@ msgstr[1] "" "Objectengrootte van bestand %s blijken nul te zijn.\n" "Het object is verwijderd van het model" -#: src/slic3r/GUI/Plater.cpp:2572 +#: src/slic3r/GUI/Plater.cpp:2561 msgid "The size of the object is zero" msgstr "De afmetingen van het object zijn nul" -#: src/slic3r/GUI/Plater.cpp:2585 +#: src/slic3r/GUI/Plater.cpp:2574 #, c-format, boost-format msgid "" "The dimensions of the object from file %s seem to be defined in meters.\n" @@ -7043,15 +7068,15 @@ msgstr[1] "" "De gebruikte eenheid van PrusaSlicer is millimeters. Wilt u de afmetingen " "van het object verschalen?" -#: src/slic3r/GUI/Plater.cpp:2589 src/slic3r/GUI/Plater.cpp:2611 +#: src/slic3r/GUI/Plater.cpp:2578 src/slic3r/GUI/Plater.cpp:2600 msgid "The object is too small" msgstr "Het object is te klein" -#: src/slic3r/GUI/Plater.cpp:2590 src/slic3r/GUI/Plater.cpp:2612 +#: src/slic3r/GUI/Plater.cpp:2579 src/slic3r/GUI/Plater.cpp:2601 msgid "Apply to all the remaining small objects being loaded." msgstr "Pas toe op alle resterende kleine objecten die worden geladen." -#: src/slic3r/GUI/Plater.cpp:2607 +#: src/slic3r/GUI/Plater.cpp:2596 #, c-format, boost-format msgid "" "The dimensions of the object from file %s seem to be defined in inches.\n" @@ -7070,7 +7095,7 @@ msgstr[1] "" "De gebruikte eenheid van PrusaSlicer is millimeters. Wilt u de afmetingen " "van het object verschalen?" -#: src/slic3r/GUI/Plater.cpp:2625 +#: src/slic3r/GUI/Plater.cpp:2614 msgid "" "This file contains several objects positioned at multiple heights.\n" "Instead of considering them as multiple objects, should \n" @@ -7081,11 +7106,11 @@ msgstr "" "Moet het bestand worden geladen als één object met meerdere onderdelen\n" "in plaats van deze te beschouwen als meerdere objecten?" -#: src/slic3r/GUI/Plater.cpp:2628 src/slic3r/GUI/Plater.cpp:2683 +#: src/slic3r/GUI/Plater.cpp:2617 src/slic3r/GUI/Plater.cpp:2672 msgid "Multi-part object detected" msgstr "Meerdelig object gedetecteerd" -#: src/slic3r/GUI/Plater.cpp:2636 +#: src/slic3r/GUI/Plater.cpp:2625 msgid "" "This file cannot be loaded in a simple mode. Do you want to switch to an " "advanced mode?" @@ -7093,11 +7118,11 @@ msgstr "" "Dit bestand kan niet geladen worden in eenvoudige modus. Wilt u overstappen " "op geavanceerde modus?" -#: src/slic3r/GUI/Plater.cpp:2637 +#: src/slic3r/GUI/Plater.cpp:2626 msgid "Detected advanced data" msgstr "Geavanceerde data gedetecteerd" -#: src/slic3r/GUI/Plater.cpp:2657 +#: src/slic3r/GUI/Plater.cpp:2646 #, c-format, boost-format msgid "" "You can't to add the object(s) from %s because of one or some of them " @@ -7106,7 +7131,7 @@ msgstr "" "U kan geen objecten toevoegen van %s, omdat sommige daarvan meerdelig kunnen " "zijn" -#: src/slic3r/GUI/Plater.cpp:2680 +#: src/slic3r/GUI/Plater.cpp:2669 msgid "" "Multiple objects were loaded for a multi-material printer.\n" "Instead of considering them as multiple objects, should I consider\n" @@ -7116,7 +7141,7 @@ msgstr "" "Moeten deze objecten beschouwd worden als één object\n" "met meerdere onderdelen, of als meerdere objecten?" -#: src/slic3r/GUI/Plater.cpp:2799 +#: src/slic3r/GUI/Plater.cpp:2788 msgid "" "Your object appears to be too large, so it was automatically scaled down to " "fit your print bed." @@ -7124,39 +7149,39 @@ msgstr "" "Het object is te groot. Daarom is het automatisch verschaald tot de grootte " "van het printbed." -#: src/slic3r/GUI/Plater.cpp:2800 +#: src/slic3r/GUI/Plater.cpp:2789 msgid "Object too large?" msgstr "Object te groot?" -#: src/slic3r/GUI/Plater.cpp:2878 +#: src/slic3r/GUI/Plater.cpp:2867 msgid "Export STL file:" -msgstr "Exporteer STL-bestand:" +msgstr "Exporteer .STL-bestand:" -#: src/slic3r/GUI/Plater.cpp:2885 +#: src/slic3r/GUI/Plater.cpp:2874 msgid "Export AMF file:" -msgstr "Exporteer AMF-bestand:" +msgstr "Exporteer .AMF-bestand:" -#: src/slic3r/GUI/Plater.cpp:2891 +#: src/slic3r/GUI/Plater.cpp:2880 msgid "Save file as:" msgstr "Bestand opslaan als:" -#: src/slic3r/GUI/Plater.cpp:2897 +#: src/slic3r/GUI/Plater.cpp:2886 msgid "Export OBJ file:" -msgstr "Exporteer OBJ-bestand:" +msgstr "Exporteer .OBJ-bestand:" -#: src/slic3r/GUI/Plater.cpp:2995 +#: src/slic3r/GUI/Plater.cpp:2984 msgid "Delete Object" msgstr "Verwijder object" -#: src/slic3r/GUI/Plater.cpp:3007 +#: src/slic3r/GUI/Plater.cpp:2996 msgid "Delete All Objects" msgstr "Verwijder alle objecten" -#: src/slic3r/GUI/Plater.cpp:3035 +#: src/slic3r/GUI/Plater.cpp:3024 msgid "Reset Project" msgstr "Reset project" -#: src/slic3r/GUI/Plater.cpp:3118 +#: src/slic3r/GUI/Plater.cpp:3107 msgid "" "The selected object couldn't be split because it contains only one solid " "part." @@ -7164,103 +7189,103 @@ msgstr "" "Het geselecteerde object kan niet gesplitst worden omdat het maar één " "onderdeel bevat." -#: src/slic3r/GUI/Plater.cpp:3125 +#: src/slic3r/GUI/Plater.cpp:3114 msgid "All non-solid parts (modifiers) were deleted" msgstr "Alle niet-solide onderdelen (bewerkers) zijn verwijderd" -#: src/slic3r/GUI/Plater.cpp:3127 +#: src/slic3r/GUI/Plater.cpp:3116 msgid "Split to Objects" msgstr "Splits op naar objecten" -#: src/slic3r/GUI/Plater.cpp:3179 +#: src/slic3r/GUI/Plater.cpp:3166 msgid "" "An object has custom support enforcers which will not be used because " "supports are disabled." msgstr "" -"Een object heeft aangepaste supportforcering die niet gebruikt worden omdat " +"Een object heeft custom supportforcering die niet gebruikt worden omdat " "supports uit staan." -#: src/slic3r/GUI/Plater.cpp:3181 +#: src/slic3r/GUI/Plater.cpp:3168 msgid "Enable supports for enforcers only" msgstr "Sta supports voor forceringen alleen toe" -#: src/slic3r/GUI/Plater.cpp:3310 src/slic3r/GUI/Plater.cpp:4176 +#: src/slic3r/GUI/Plater.cpp:3297 src/slic3r/GUI/Plater.cpp:4163 msgid "Invalid data" msgstr "Ongeldige data" -#: src/slic3r/GUI/Plater.cpp:3380 +#: src/slic3r/GUI/Plater.cpp:3367 msgid "Another export job is currently running." msgstr "Een andere export loopt op dit moment." -#: src/slic3r/GUI/Plater.cpp:3466 +#: src/slic3r/GUI/Plater.cpp:3453 msgid "Replace from:" msgstr "Vervangen door:" -#: src/slic3r/GUI/Plater.cpp:3484 +#: src/slic3r/GUI/Plater.cpp:3471 msgid "Unable to replace with more than one volume" msgstr "Niet mogelijk om te vervangen met meer dan één volume" -#: src/slic3r/GUI/Plater.cpp:3484 src/slic3r/GUI/Plater.cpp:3563 +#: src/slic3r/GUI/Plater.cpp:3471 src/slic3r/GUI/Plater.cpp:3550 msgid "Error during replace" msgstr "Fout tijdens vervangen" -#: src/slic3r/GUI/Plater.cpp:3555 +#: src/slic3r/GUI/Plater.cpp:3542 msgid "Select the new file" msgstr "Selecteer het nieuwe bestand" -#: src/slic3r/GUI/Plater.cpp:3563 +#: src/slic3r/GUI/Plater.cpp:3550 msgid "File for the replace wasn't selected" msgstr "Vervangbestand is niet geselecteerd" -#: src/slic3r/GUI/Plater.cpp:3654 +#: src/slic3r/GUI/Plater.cpp:3641 msgid "Please select the file to reload" msgstr "Selecteer het bestand om te herladen" -#: src/slic3r/GUI/Plater.cpp:3685 src/slic3r/GUI/Plater.cpp:5243 +#: src/slic3r/GUI/Plater.cpp:3672 src/slic3r/GUI/Plater.cpp:5230 msgid "The selected file" msgstr "Het geselecteerde bestand" -#: src/slic3r/GUI/Plater.cpp:3686 +#: src/slic3r/GUI/Plater.cpp:3673 msgid "differs from the original file" msgstr "verschilt ten opzichte van het originele bestand" -#: src/slic3r/GUI/Plater.cpp:3686 +#: src/slic3r/GUI/Plater.cpp:3673 msgid "Do you want to replace it" msgstr "Wilt u het vervangen" -#: src/slic3r/GUI/Plater.cpp:3703 src/slic3r/GUI/Plater.cpp:3709 +#: src/slic3r/GUI/Plater.cpp:3690 src/slic3r/GUI/Plater.cpp:3696 msgid "Reload from:" msgstr "Herladen van:" -#: src/slic3r/GUI/Plater.cpp:3812 +#: src/slic3r/GUI/Plater.cpp:3799 msgid "Unable to reload:" msgstr "Niet in staat om te herladen:" -#: src/slic3r/GUI/Plater.cpp:3817 +#: src/slic3r/GUI/Plater.cpp:3804 msgid "Error during reload" msgstr "Fout tijdens herladen" -#: src/slic3r/GUI/Plater.cpp:3835 +#: src/slic3r/GUI/Plater.cpp:3822 msgid "Reload all from disk" msgstr "Herlaad alles van schijf" -#: src/slic3r/GUI/Plater.cpp:4130 +#: src/slic3r/GUI/Plater.cpp:4117 msgid "There are active warnings concerning sliced models:" msgstr "Er zijn actieve waarschuwingen wat betreft de slice:" -#: src/slic3r/GUI/Plater.cpp:4141 +#: src/slic3r/GUI/Plater.cpp:4128 msgid "generated warnings" msgstr "gegeven waarschuwingen" -#: src/slic3r/GUI/Plater.cpp:4472 +#: src/slic3r/GUI/Plater.cpp:4459 msgid "3D editor view" msgstr "3D-bewerkingsweergave" -#: src/slic3r/GUI/Plater.cpp:4893 +#: src/slic3r/GUI/Plater.cpp:4880 msgid "Undo / Redo is processing" msgstr "Ongedaan maken / opnieuw doen wordt verwerkt" -#: src/slic3r/GUI/Plater.cpp:4895 +#: src/slic3r/GUI/Plater.cpp:4882 #, boost-format msgid "" "Switching the printer technology from %1% to %2%.\n" @@ -7271,21 +7296,21 @@ msgstr "" "Sommige %1% presets zijn aangepast. Deze gaan verloren bij het wijzigen van " "het soort printer." -#: src/slic3r/GUI/Plater.cpp:5092 +#: src/slic3r/GUI/Plater.cpp:5079 msgid "Creating a new project while the current project is modified." msgstr "Een nieuw project aanmaken terwijl het huidige project is aangepast." -#: src/slic3r/GUI/Plater.cpp:5095 +#: src/slic3r/GUI/Plater.cpp:5082 msgid "Creating a new project while some presets are modified." msgstr "Een nieuw project aanmaken terwijl sommige presets zijn aangepast." -#: src/slic3r/GUI/Plater.cpp:5096 +#: src/slic3r/GUI/Plater.cpp:5083 msgid "You can keep presets modifications to the new project or discard them" msgstr "" "U kunt de aanpassingen in de preset behouden bij het nieuwe project, of deze " "verwijderen" -#: src/slic3r/GUI/Plater.cpp:5097 +#: src/slic3r/GUI/Plater.cpp:5084 msgid "" "You can keep presets modifications to the new project, discard them or save " "changes as new presets.\n" @@ -7296,126 +7321,126 @@ msgstr "" "Let op dat als de wijzigingen worden opgeslagen, deze niet bewaard worden in " "het nieuwe project" -#: src/slic3r/GUI/Plater.cpp:5103 +#: src/slic3r/GUI/Plater.cpp:5090 msgid "Creating a new project" msgstr "Maak een nieuw project aan" -#: src/slic3r/GUI/Plater.cpp:5137 +#: src/slic3r/GUI/Plater.cpp:5124 msgid "Load Project" msgstr "Laad project" -#: src/slic3r/GUI/Plater.cpp:5167 src/slic3r/GUI/Plater.cpp:5432 +#: src/slic3r/GUI/Plater.cpp:5154 src/slic3r/GUI/Plater.cpp:5419 msgid "Import Object" msgstr "Importeer object" -#: src/slic3r/GUI/Plater.cpp:5171 +#: src/slic3r/GUI/Plater.cpp:5158 msgid "Import Objects" msgstr "Importeer objecten" -#: src/slic3r/GUI/Plater.cpp:5243 +#: src/slic3r/GUI/Plater.cpp:5230 msgid "does not contain valid gcode." msgstr "bevat geen geldige G-code." -#: src/slic3r/GUI/Plater.cpp:5244 +#: src/slic3r/GUI/Plater.cpp:5231 msgid "Error while loading .gcode file" -msgstr "Probleem bij het laden van het gcode-bestand" +msgstr "Probleem bij het laden van het .gcode-bestand" -#: src/slic3r/GUI/Plater.cpp:5297 +#: src/slic3r/GUI/Plater.cpp:5284 #, c-format, boost-format msgid "%s - Drop project file" msgstr "%s - Plaats projectbestand" -#: src/slic3r/GUI/Plater.cpp:5304 +#: src/slic3r/GUI/Plater.cpp:5291 msgid "Open as project" msgstr "Open als project" -#: src/slic3r/GUI/Plater.cpp:5305 +#: src/slic3r/GUI/Plater.cpp:5292 msgid "Import geometry only" msgstr "Importeer alleen het model" -#: src/slic3r/GUI/Plater.cpp:5306 +#: src/slic3r/GUI/Plater.cpp:5293 msgid "Import config only" msgstr "Importeer alleen de configuratie" -#: src/slic3r/GUI/Plater.cpp:5309 +#: src/slic3r/GUI/Plater.cpp:5296 msgid "Select an action to apply to the file" msgstr "Selecteer een commando om toe te passen op het bestand" -#: src/slic3r/GUI/Plater.cpp:5314 +#: src/slic3r/GUI/Plater.cpp:5301 msgid "Action" -msgstr "Commando" +msgstr "Actie" -#: src/slic3r/GUI/Plater.cpp:5330 +#: src/slic3r/GUI/Plater.cpp:5317 msgid "Don't show again" msgstr "Laat niet meer zien" -#: src/slic3r/GUI/Plater.cpp:5371 +#: src/slic3r/GUI/Plater.cpp:5358 msgid "You can open only one .gcode file at a time." -msgstr "Je kunt maar één gcode-bestand tegelijk openen." +msgstr "Je kunt maar één .gcode-bestand tegelijk openen." -#: src/slic3r/GUI/Plater.cpp:5372 +#: src/slic3r/GUI/Plater.cpp:5359 msgid "Drag and drop G-code file" msgstr "Versleep en plaats G-code-bestand" -#: src/slic3r/GUI/Plater.cpp:5454 +#: src/slic3r/GUI/Plater.cpp:5441 msgid "Load File" msgstr "Laad bestand" -#: src/slic3r/GUI/Plater.cpp:5459 +#: src/slic3r/GUI/Plater.cpp:5446 msgid "Load Files" msgstr "Laad bestanden" -#: src/slic3r/GUI/Plater.cpp:5509 +#: src/slic3r/GUI/Plater.cpp:5496 msgid "All objects will be removed, continue?" msgstr "Alle objecten worden verwijderd. Doorgaan?" -#: src/slic3r/GUI/Plater.cpp:5520 +#: src/slic3r/GUI/Plater.cpp:5507 msgid "Delete Selected Objects" msgstr "Verwijder geselecteerde objecten" -#: src/slic3r/GUI/Plater.cpp:5529 +#: src/slic3r/GUI/Plater.cpp:5516 msgid "Increase Instances" msgstr "Verhoog aantal instanties" -#: src/slic3r/GUI/Plater.cpp:5563 +#: src/slic3r/GUI/Plater.cpp:5550 msgid "Decrease Instances" msgstr "Verlaag aantal instanties" -#: src/slic3r/GUI/Plater.cpp:5614 +#: src/slic3r/GUI/Plater.cpp:5601 msgid "Enter the number of copies:" msgstr "Voer het aantal kopieën in:" -#: src/slic3r/GUI/Plater.cpp:5615 +#: src/slic3r/GUI/Plater.cpp:5602 msgid "Copies of the selected object" msgstr "Kopieën van het geselecteerde object" -#: src/slic3r/GUI/Plater.cpp:5619 +#: src/slic3r/GUI/Plater.cpp:5606 #, c-format, boost-format msgid "Set numbers of copies to %d" msgstr "Stel aantal kopieën in voor %d" -#: src/slic3r/GUI/Plater.cpp:5697 +#: src/slic3r/GUI/Plater.cpp:5684 msgid "Cut by Plane" msgstr "Snij met behulp van vlak" -#: src/slic3r/GUI/Plater.cpp:5757 +#: src/slic3r/GUI/Plater.cpp:5744 msgid "Save G-code file as:" -msgstr "G-code-bestand opslaan als:" +msgstr ".gcode-bestand opslaan als:" -#: src/slic3r/GUI/Plater.cpp:5757 +#: src/slic3r/GUI/Plater.cpp:5744 msgid "Save SL1 / SL1S file as:" msgstr "SL1 / SL1S bestand opslaan als:" -#: src/slic3r/GUI/Plater.cpp:5766 +#: src/slic3r/GUI/Plater.cpp:5753 msgid "The provided file name is not valid." msgstr "De gegeven naam is niet geldig." -#: src/slic3r/GUI/Plater.cpp:5767 +#: src/slic3r/GUI/Plater.cpp:5754 msgid "The following characters are not allowed by a FAT file system:" msgstr "" "De volgende karakters worden niet toegestaan in een FAT-bestandssysteem:" -#: src/slic3r/GUI/Plater.cpp:5957 +#: src/slic3r/GUI/Plater.cpp:5944 msgid "" "The plater is empty.\n" "Do you want to save the project?" @@ -7423,15 +7448,15 @@ msgstr "" "Het bed is leeg.\n" "Wilt u toch het project opslaan?" -#: src/slic3r/GUI/Plater.cpp:5957 +#: src/slic3r/GUI/Plater.cpp:5944 msgid "Save project" msgstr "Project opslaan" -#: src/slic3r/GUI/Plater.cpp:6543 +#: src/slic3r/GUI/Plater.cpp:6530 msgid "Export" msgstr "Exporteer" -#: src/slic3r/GUI/Plater.cpp:6575 +#: src/slic3r/GUI/Plater.cpp:6562 msgid "" "Custom supports, seams and multimaterial painting were removed after " "repairing the mesh." @@ -7439,7 +7464,7 @@ msgstr "" "Aangepaste supports, naden en multi-material schilderingen zijn verwijderd " "bij het repareren van de mesh." -#: src/slic3r/GUI/Plater.cpp:6689 +#: src/slic3r/GUI/Plater.cpp:6676 msgid "Paste From Clipboard" msgstr "Plak van klembord" @@ -7488,7 +7513,7 @@ msgstr "" #: src/slic3r/GUI/Preferences.cpp:148 msgid "Export sources full pathnames to 3mf and amf" -msgstr "Exporteer de volledige padnamen naar 3MF- en AMF-bestanden" +msgstr "Exporteer de volledige padnamen naar .3MF- en .AMF-bestanden" #: src/slic3r/GUI/Preferences.cpp:150 msgid "" @@ -7501,13 +7526,13 @@ msgstr "" #: src/slic3r/GUI/Preferences.cpp:159 msgid "If enabled, sets PrusaSlicer as default application to open .3mf files." msgstr "" -"Als dit aanstaat wordt PrusaSlicer als standaardprogramma ingesteld om 3MF-" +"Als dit aanstaat wordt PrusaSlicer als standaardprogramma ingesteld om .3MF-" "bestanden te openen." #: src/slic3r/GUI/Preferences.cpp:166 msgid "If enabled, sets PrusaSlicer as default application to open .stl files." msgstr "" -"Als dit aanstaat wordt PrusaSlicer als standaardprogramma ingesteld om STL-" +"Als dit aanstaat wordt PrusaSlicer als standaardprogramma ingesteld om .STL-" "bestanden te openen." #: src/slic3r/GUI/Preferences.cpp:177 @@ -7536,7 +7561,7 @@ msgstr "" #: src/slic3r/GUI/Preferences.cpp:190 msgid "Show incompatible print and filament presets" -msgstr "Toon niet geschikte print- en filamentpresets" +msgstr "Toon niet compatibele print- en filamentpresets" #: src/slic3r/GUI/Preferences.cpp:192 msgid "" @@ -7544,7 +7569,7 @@ msgid "" "even if they are marked as incompatible with the active printer" msgstr "" "Als dit aan staat worden de print- en filamentpresets getoond in de presets-" -"editor, zelfs als ze als niet geschikt voor de actieve printer zijn " +"editor, zelfs als ze als niet compatibel met de actieve printer zijn " "gemarkeerd" #: src/slic3r/GUI/Preferences.cpp:200 @@ -7591,6 +7616,9 @@ msgid "" "- Closing PrusaSlicer,\n" "- Loading or creating a new project" msgstr "" +"Vraag altijd naar niet-opgeslagen wijzigingen in het project als:\n" +"- PrusaSlicer afgesloten wordt,\n" +"- Een nieuw project wordt geladen of aangemaakt" #: src/slic3r/GUI/Preferences.cpp:233 #: src/slic3r/GUI/UnsavedChangesDialog.cpp:897 @@ -7598,6 +7626,8 @@ msgid "" "Ask to save unsaved changes in presets when closing the application or when " "loading a new project" msgstr "" +"Vraag om niet-opgeslagen wijziging op te slaan in presets bij het sluiten " +"van het programma of het laden van een nieuw project" #: src/slic3r/GUI/Preferences.cpp:235 msgid "" @@ -7605,26 +7635,37 @@ msgid "" "- Closing PrusaSlicer while some presets are modified,\n" "- Loading a new project while some presets are modified" msgstr "" +"Vraag altijd naar niet-opgeslagen wijzigingen in presets als:\n" +"- PrusaSlicer afgesloten wordt terwijl presets zijn gewijzigd,\n" +"- Een nieuw project wordt geladen terwijl sommige presets zijn gewijzigd" #: src/slic3r/GUI/Preferences.cpp:242 #: src/slic3r/GUI/UnsavedChangesDialog.cpp:896 msgid "Ask for unsaved changes in presets when selecting new preset" msgstr "" +"Vraag naar niet-opgeslagen wijzigingen in presets bij het selecteren van een " +"nieuwe preset" #: src/slic3r/GUI/Preferences.cpp:244 msgid "" "Always ask for unsaved changes in presets when selecting new preset or " "resetting a preset" msgstr "" +"Vraag altijd naar niet-opgeslagen wijzigingen in presets bij het resetten " +"van een preset of het selecteren van een nieuwe preset" #: src/slic3r/GUI/Preferences.cpp:249 #: src/slic3r/GUI/UnsavedChangesDialog.cpp:895 msgid "Ask for unsaved changes in presets when creating new project" msgstr "" +"Vraag naar niet-opgeslagen wijzigingen in presets bij het aanmaken van een " +"nieuw project" #: src/slic3r/GUI/Preferences.cpp:251 msgid "Always ask for unsaved changes in presets when creating new project" msgstr "" +"Vraag altijd naar niet-opgeslagen wijzigingen in presets bij het aanmaken " +"van een new project" #: src/slic3r/GUI/Preferences.cpp:258 msgid "Associate .gcode files to PrusaSlicer G-code Viewer" @@ -7640,16 +7681,16 @@ msgstr "" #: src/slic3r/GUI/Preferences.cpp:268 msgid "Use Retina resolution for the 3D scene" -msgstr "Gebruik hoge resolutie voor de 3D-scène" +msgstr "Gebruik hoge resolutie voor de modelweergave" #: src/slic3r/GUI/Preferences.cpp:270 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 "" -"Als dit is ingeschakeld zal de 3D-scène worden gerenderd in hoge resolutie. " -"Als u problemen ondervindt met de prestaties kan het uitschakelen van deze " -"optie mogelijk helpen." +"Als dit is ingeschakeld zal de modelweergave worden gerenderd in hoge " +"resolutie. Als u problemen ondervindt met de prestaties kan het uitschakelen " +"van deze optie mogelijk helpen." #: src/slic3r/GUI/Preferences.cpp:280 src/slic3r/GUI/Preferences.cpp:282 msgid "Show splash screen" @@ -7658,6 +7699,8 @@ msgstr "Toon startscherm" #: src/slic3r/GUI/Preferences.cpp:289 msgid "If enabled, PrusaSlicer will be open at the position it was closed" msgstr "" +"Als dit is ingeschakeld zal PrusaSlicer openen op de positie waarop die is " +"afgesloten" #: src/slic3r/GUI/Preferences.cpp:295 msgid "Clear Undo / Redo stack on new project" @@ -7730,8 +7773,8 @@ msgid "" "in preview, apply to the whole gcode." msgstr "" "Sta toe om wijzigingen van de opeenvolgende schuif in de voorbeeldweergave " -"alleen toe te passen op de toplaag. Als dit uitstaat worden wijzigingen " -"toegepast op de hele G-code." +"alleen toe te passen op de toplaag. Als dit is uitgeschakeld worden " +"wijzigingen toegepast op de hele G-code." #: src/slic3r/GUI/Preferences.cpp:375 msgid "Show sidebar collapse/expand button" @@ -7743,11 +7786,12 @@ msgid "" "right corner of the 3D Scene" msgstr "" "Als dit is ingeschakeld zal de knop om de zijbalk in te klappen getoond " -"worden in de rechterbovenhoek van de 3D-bewerkingsweergave" +"worden in de rechterbovenhoek van de modelweergave" #: src/slic3r/GUI/Preferences.cpp:384 msgid "If enabled, PrusaSlicer will not open hyperlinks in your browser." msgstr "" +"Als dit is ingeschakeld zal PrusaSlicer hyperlinks niet openen in uw browser." #: src/slic3r/GUI/Preferences.cpp:391 msgid "Use colors for axes values in Manipulation panel" @@ -7758,8 +7802,8 @@ msgid "" "If enabled, the axes names and axes values will be colorized according to " "the axes colors. If disabled, old UI will be used." msgstr "" -"Als dit aanstaat worden namen en waarden van assen gekleurd volgens de kleur " -"van de as. Als dit uitstaat wordt de oude interface gebruikt." +"Als dit is ingeschakeld worden namen en waarden van assen gekleurd volgens " +"de kleur van de as. Als dit uitstaat wordt de oude interface gebruikt." #: src/slic3r/GUI/Preferences.cpp:399 msgid "Order object volumes by types" @@ -7772,8 +7816,8 @@ msgid "" "Enforcer. If disabled, you can reorder Model Parts, Negative Volumes and " "Modifiers. But one of the model parts have to be on the first place." msgstr "" -"Als dit aanstaat worden volumes altijd gesorteerd binnen een object. De " -"juiste volgorde is Model - Negatieve volumes - Modificators - " +"Als dit is ingeschakeld worden volumes altijd gesorteerd binnen een object. " +"De juiste volgorde is Model - Negatieve volumes - Modificators - " "Supportblokkering - Supportforcering. Als dit uitstaat kan u de onderdelen " "zelf schikken. Een van de modellen moet op de eerste plaats staan." @@ -7786,8 +7830,8 @@ msgid "" "If enabled, Settings Tabs will be placed as menu items. If disabled, old UI " "will be used." msgstr "" -"Als dit aanstaat worden instellingentabs geplaatst als menu-onderdelen. Als " -"dit uitstaat wordt de oude interface gebruikt." +"Als dit is ingeschakeld worden instellingentabs geplaatst als menu-" +"onderdelen. Als dit uitstaat wordt de oude interface gebruikt." #: src/slic3r/GUI/Preferences.cpp:419 msgid "Show \"Tip of the day\" notification after start" @@ -7795,7 +7839,7 @@ msgstr "Toon \"Tip van de dag\" melding bij het starten" #: src/slic3r/GUI/Preferences.cpp:421 msgid "If enabled, useful hints are displayed at startup." -msgstr "Als dit aanstaat worden handige tips getoond bij het starten." +msgstr "Als dit is ingeschakeld worden handige tips getoond bij het starten." #: src/slic3r/GUI/Preferences.cpp:427 msgid "Notify about new releases" @@ -7833,7 +7877,8 @@ msgstr "Gebruik omgevingskaart" #: src/slic3r/GUI/Preferences.cpp:478 msgid "If enabled, renders object using the environment map." -msgstr "Als dit aanstaat worden objecten gerenderd met de omgevingskaart." +msgstr "" +"Als dit is ingeschakeld worden objecten gerenderd met de omgevingskaart." #: src/slic3r/GUI/Preferences.cpp:491 msgid "Dark mode (experimental)" @@ -7847,8 +7892,8 @@ msgstr "Gebruik donkere modus" msgid "" "If enabled, UI will use Dark mode colors. If disabled, old UI will be used." msgstr "" -"Als dit aan staat worden kleuren van de donkere modus gebruikt. De oude " -"kleuren worden gebruikt als dit uit staat." +"Als dit is ingeschakeld worden kleuren van de donkere modus gebruikt. De " +"oude kleuren worden gebruikt als dit uit staat." #: src/slic3r/GUI/Preferences.cpp:507 msgid "Use system menu for application" @@ -7860,7 +7905,7 @@ msgid "" "but on some combination of display scales it can looks ugly. If disabled, " "old UI will be used." msgstr "" -"Als dit aan staat worden de standaard Windows-menukleuren gebruikt,\n" +"Als dit is ingeschakeld worden de standaard Windows-menukleuren gebruikt,\n" "maar op sommige combinaties van displaygroottes kan die lelijk lijken. Als " "dit uitstaat wordt de oude interface gebruikt." @@ -7923,7 +7968,7 @@ msgstr "Presets van de gebruiker" #: src/slic3r/GUI/PresetComboBoxes.cpp:302 msgid "Incompatible presets" -msgstr "Ongeschikte presets" +msgstr "Niet compatibele presets" #: src/slic3r/GUI/PresetComboBoxes.cpp:337 #, boost-format @@ -8268,11 +8313,11 @@ msgstr "Fout: geen ramming" #: src/slic3r/GUI/RammingChart.cpp:90 src/slic3r/GUI/WipeTowerDialog.cpp:114 #: src/libslic3r/PrintConfig.cpp:951 src/libslic3r/PrintConfig.cpp:995 -#: src/libslic3r/PrintConfig.cpp:1010 src/libslic3r/PrintConfig.cpp:3266 -#: src/libslic3r/PrintConfig.cpp:3275 src/libslic3r/PrintConfig.cpp:3284 -#: src/libslic3r/PrintConfig.cpp:3425 src/libslic3r/PrintConfig.cpp:3433 -#: src/libslic3r/PrintConfig.cpp:3441 src/libslic3r/PrintConfig.cpp:3448 -#: src/libslic3r/PrintConfig.cpp:3456 src/libslic3r/PrintConfig.cpp:3464 +#: src/libslic3r/PrintConfig.cpp:1010 src/libslic3r/PrintConfig.cpp:3265 +#: src/libslic3r/PrintConfig.cpp:3274 src/libslic3r/PrintConfig.cpp:3283 +#: src/libslic3r/PrintConfig.cpp:3424 src/libslic3r/PrintConfig.cpp:3432 +#: src/libslic3r/PrintConfig.cpp:3440 src/libslic3r/PrintConfig.cpp:3447 +#: src/libslic3r/PrintConfig.cpp:3455 src/libslic3r/PrintConfig.cpp:3463 msgid "s" msgstr "s" @@ -8281,7 +8326,7 @@ msgid "Volumetric speed" msgstr "Volumetrische snelheid" #: src/slic3r/GUI/RammingChart.cpp:95 src/libslic3r/PrintConfig.cpp:908 -#: src/libslic3r/PrintConfig.cpp:1801 +#: src/libslic3r/PrintConfig.cpp:1800 msgid "mm³/s" msgstr "mm³/s" @@ -8322,7 +8367,7 @@ msgid "" "Preset with name \"%1%\" already exists and is incompatible with selected " "printer." msgstr "" -"Preset met de naam \"%1%\" bestaat al en is incompatibel met de " +"Preset met de naam \"%1%\" bestaat al en is niet compatibel met de " "geselecteerde printer." #: src/slic3r/GUI/SavePresetDialog.cpp:137 @@ -8460,7 +8505,7 @@ msgid "" msgstr "" "Als we uw hardware, besturingssysteem, etc. kennen, zal dit ons erg helpen " "bij de ontwikkeling en prioritering, omdat we dan beter weten waar de focus " -"ligt, en efficiënter de tijd besteden op onderdelen die veel tijd kosten." +"ligt, en efficiënter de tijd besteden op delen die veel tijd kosten." #: src/slic3r/GUI/SendSystemInfoDialog.cpp:588 msgid "Is it safe?" @@ -8530,19 +8575,19 @@ msgstr "Kopieer van klembord" #: src/slic3r/GUI/Tab.cpp:114 src/libslic3r/PrintConfig.cpp:564 msgid "Compatible printers" -msgstr "Geschikte printers" +msgstr "Compatibele printers" #: src/slic3r/GUI/Tab.cpp:115 msgid "Select the printers this profile is compatible with." -msgstr "Selecteer de printers die geschikt voor dit profiel zijn." +msgstr "Selecteer de printers die compatibel zijn met dit profiel." #: src/slic3r/GUI/Tab.cpp:120 src/libslic3r/PrintConfig.cpp:579 msgid "Compatible print profiles" -msgstr "Geschikte printprofielen" +msgstr "Compatibele printprofielen" #: src/slic3r/GUI/Tab.cpp:121 msgid "Select the print profiles this profile is compatible with." -msgstr "Selecteer de printprofielen die geschikt voor dit profiel zijn." +msgstr "Selecteer de printprofielen die compatibel zijn met dit profiel." #: src/slic3r/GUI/Tab.cpp:216 msgid "Compare this preset with some another" @@ -8671,7 +8716,7 @@ msgstr "Verticale shells" msgid "Horizontal shells" msgstr "Horizontale shells" -#: src/slic3r/GUI/Tab.cpp:1466 src/libslic3r/PrintConfig.cpp:2386 +#: src/slic3r/GUI/Tab.cpp:1466 src/libslic3r/PrintConfig.cpp:2385 msgid "Solid layers" msgstr "Dichte lagen" @@ -8725,7 +8770,7 @@ msgstr "Automatische snelheid (geavanceerd)" #: src/slic3r/GUI/Tab.cpp:1615 msgid "Pressure equalizer (experimental)" -msgstr "" +msgstr "Drukverdeler (experimenteel)" #: src/slic3r/GUI/Tab.cpp:1619 msgid "Multiple Extruders" @@ -8753,7 +8798,7 @@ msgstr "Overige" #: src/slic3r/GUI/Tab.cpp:1674 msgid "Arachne perimeter generator" -msgstr "" +msgstr "Arachne-perimetergeneratie" #: src/slic3r/GUI/Tab.cpp:1682 src/slic3r/GUI/Tab.cpp:4731 msgid "Output options" @@ -8771,7 +8816,7 @@ msgstr "Extruderruimte" msgid "Output file" msgstr "Outputbestand" -#: src/slic3r/GUI/Tab.cpp:1709 src/libslic3r/PrintConfig.cpp:2011 +#: src/slic3r/GUI/Tab.cpp:1709 src/libslic3r/PrintConfig.cpp:2010 msgid "Post-processing scripts" msgstr "Scripts voor nabewerking" @@ -8839,8 +8884,8 @@ msgstr "Bed" msgid "Cooling" msgstr "Koeling" -#: src/slic3r/GUI/Tab.cpp:2001 src/libslic3r/PrintConfig.cpp:1913 -#: src/libslic3r/PrintConfig.cpp:2963 +#: src/slic3r/GUI/Tab.cpp:2001 src/libslic3r/PrintConfig.cpp:1912 +#: src/libslic3r/PrintConfig.cpp:2962 msgid "Enable" msgstr "Toestaan" @@ -8874,13 +8919,13 @@ msgstr "Ramming-instellingen" #: src/slic3r/GUI/Tab.cpp:2086 src/slic3r/GUI/Tab.cpp:2407 #: src/slic3r/GUI/Tab.cpp:4261 src/libslic3r/GCode.cpp:733 -#: src/libslic3r/PrintConfig.cpp:2469 +#: src/libslic3r/PrintConfig.cpp:2468 msgid "Custom G-code" msgstr "Custom G-code" #: src/slic3r/GUI/Tab.cpp:2087 src/slic3r/GUI/Tab.cpp:2408 -#: src/libslic3r/GCode.cpp:707 src/libslic3r/PrintConfig.cpp:2419 -#: src/libslic3r/PrintConfig.cpp:2434 +#: src/libslic3r/GCode.cpp:707 src/libslic3r/PrintConfig.cpp:2418 +#: src/libslic3r/PrintConfig.cpp:2433 msgid "Start G-code" msgstr "Start G-code" @@ -8906,7 +8951,7 @@ msgid "" "The Physical Printer profiles are being stored into PrusaSlicer/" "physical_printer directory." msgstr "" -"Let op dat alle parameters van deze groep zijn verplaatst naar de fysieke " +"Let op dat alle parameters van deze groep zijn verplaatst naar de fysieke-" "printerinstellingen (zie wijzigingslogboek).\n" "\n" "Een nieuw fysieke printerprofiel wordt aangemaakt door te klikken op het " @@ -8942,7 +8987,7 @@ msgstr "" "eerste extruder?" #: src/slic3r/GUI/Tab.cpp:2335 src/slic3r/GUI/Tab.cpp:2779 -#: src/libslic3r/PrintConfig.cpp:1877 +#: src/libslic3r/PrintConfig.cpp:1876 msgid "Nozzle diameter" msgstr "Nozzlediameter" @@ -8952,12 +8997,12 @@ msgid "Before layer change G-code" msgstr "G-code die komt vóór de laagwisseling" #: src/slic3r/GUI/Tab.cpp:2438 src/libslic3r/GCode.cpp:710 -#: src/libslic3r/PrintConfig.cpp:1603 +#: src/libslic3r/PrintConfig.cpp:1602 msgid "After layer change G-code" msgstr "G-code die komt na de laagwisseling" #: src/slic3r/GUI/Tab.cpp:2448 src/libslic3r/GCode.cpp:711 -#: src/libslic3r/PrintConfig.cpp:2846 +#: src/libslic3r/PrintConfig.cpp:2845 msgid "Tool change G-code" msgstr "Toolwisseling G-code" @@ -8970,7 +9015,7 @@ msgid "Color Change G-code" msgstr "Kleurwissel G-code" #: src/slic3r/GUI/Tab.cpp:2477 src/libslic3r/GCode.cpp:714 -#: src/libslic3r/PrintConfig.cpp:2460 +#: src/libslic3r/PrintConfig.cpp:2459 msgid "Pause Print G-code" msgstr "Pauzeer print G-code" @@ -8999,11 +9044,11 @@ msgid "Exposure" msgstr "Belichtingstijd" #: src/slic3r/GUI/Tab.cpp:2619 src/slic3r/GUI/Tab.cpp:2706 -#: src/libslic3r/PrintConfig.cpp:1632 src/libslic3r/PrintConfig.cpp:1667 -#: src/libslic3r/PrintConfig.cpp:1684 src/libslic3r/PrintConfig.cpp:1701 -#: src/libslic3r/PrintConfig.cpp:1717 src/libslic3r/PrintConfig.cpp:1727 -#: src/libslic3r/PrintConfig.cpp:1737 src/libslic3r/PrintConfig.cpp:1750 -#: src/libslic3r/PrintConfig.cpp:1760 +#: src/libslic3r/PrintConfig.cpp:1631 src/libslic3r/PrintConfig.cpp:1666 +#: src/libslic3r/PrintConfig.cpp:1683 src/libslic3r/PrintConfig.cpp:1700 +#: src/libslic3r/PrintConfig.cpp:1716 src/libslic3r/PrintConfig.cpp:1726 +#: src/libslic3r/PrintConfig.cpp:1736 src/libslic3r/PrintConfig.cpp:1749 +#: src/libslic3r/PrintConfig.cpp:1759 msgid "Machine limits" msgstr "Machinelimieten" @@ -9058,7 +9103,7 @@ msgstr "Positie (voor multi-extruderprinters)" #: src/slic3r/GUI/Tab.cpp:2812 msgid "Only lift Z" -msgstr "Beweeg alleen Z omhoog" +msgstr "Beweeg alleen omhoog" #: src/slic3r/GUI/Tab.cpp:2825 msgid "" @@ -9178,31 +9223,31 @@ msgstr "Stel in" #: src/slic3r/GUI/Tab.cpp:3952 msgid "Find" -msgstr "Zoeken" +msgstr "Zoek" #: src/slic3r/GUI/Tab.cpp:3953 msgid "Replace with" -msgstr "" +msgstr "Vervang met" #: src/slic3r/GUI/Tab.cpp:4042 msgid "Regular expression" -msgstr "" +msgstr "Reguliere uitdrukking" #: src/slic3r/GUI/Tab.cpp:4046 msgid "Case insensitive" -msgstr "" +msgstr "Hoofdletterongevoelig" #: src/slic3r/GUI/Tab.cpp:4050 msgid "Whole word" -msgstr "Alleen hele woorden" +msgstr "Geheel woord" #: src/slic3r/GUI/Tab.cpp:4054 msgid "Match single line" -msgstr "" +msgstr "Laat overeenkomen met enkele lijn" #: src/slic3r/GUI/Tab.cpp:4157 msgid "Are you sure you want to delete all substitutions?" -msgstr "" +msgstr "Weet je zeker dat je alle substituties wilt verwijderen?" #: src/slic3r/GUI/Tab.cpp:4289 msgid "" @@ -9402,11 +9447,11 @@ msgstr "" "\"%1%\" is uitgeschakeld omdat \"%2%\" aanstaat in \"%3%\"-categorie.\n" "Om \"%1%\" aan te zetten moet \"%2%\" uit staan" -#: src/slic3r/GUI/Tab.cpp:4774 src/libslic3r/PrintConfig.cpp:3693 +#: src/slic3r/GUI/Tab.cpp:4774 src/libslic3r/PrintConfig.cpp:3692 msgid "Object elevation" msgstr "Objectverhoging" -#: src/slic3r/GUI/Tab.cpp:4774 src/libslic3r/PrintConfig.cpp:3795 +#: src/slic3r/GUI/Tab.cpp:4774 src/libslic3r/PrintConfig.cpp:3794 msgid "Pad around object" msgstr "Basisplaat rondom object" @@ -9462,12 +9507,16 @@ msgid "" "You will not be asked about the unsaved changes in presets the next time you " "create new project" msgstr "" +"U wordt niet gevraagd naar niet-opgeslagen wijzigingen in presets de " +"volgende keer als u een nieuw project aanmaakt" #: src/slic3r/GUI/UnsavedChangesDialog.cpp:899 msgid "" "You will not be asked about the unsaved changes in presets the next time you " "switch a preset" msgstr "" +"U wordt niet gevraagd naar niet-opgeslagen wijzigingen in presets de " +"volgende keer als u wisselt van preset" #: src/slic3r/GUI/UnsavedChangesDialog.cpp:900 msgid "" @@ -9476,6 +9525,10 @@ msgid "" "- Closing PrusaSlicer while some presets are modified,\n" "- Loading a new project while some presets are modified" msgstr "" +"U wordt niet gevraagd naar niet-opgeslagen wijzigingen in presets de " +"volgende keer als:\n" +"- PrusaSlicer afgesloten wordt terwijl sommige presets zijn aangepast;\n" +"- een nieuw project wordt geladen terwijl sommige presets zijn aangepast" #: src/slic3r/GUI/UnsavedChangesDialog.cpp:903 msgid "PrusaSlicer will remember your action." @@ -9546,7 +9599,7 @@ msgid "" "Preset \"%1%\" is not compatible with the new printer profile and it has the " "following unsaved changes:" msgstr "" -"Preset \"%1%\" is niet geschikt voor het nieuwe printerprofiel en heeft de " +"Preset \"%1%\" is niet compatibel met het nieuwe printerprofiel en heeft de " "volgende niet-opgeslagen wijzigingen:" #: src/slic3r/GUI/UnsavedChangesDialog.cpp:1235 @@ -9555,7 +9608,7 @@ msgid "" "Preset \"%1%\" is not compatible with the new print profile and it has the " "following unsaved changes:" msgstr "" -"Preset \"%1%\" is niet geschikt voor het nieuwe printprofiel en heeft de " +"Preset \"%1%\" is niet compatibel met het nieuwe printprofiel en heeft de " "volgende niet-opgeslagen wijzigingen:" #: src/slic3r/GUI/UnsavedChangesDialog.cpp:1283 @@ -9565,11 +9618,11 @@ msgstr "Aantal extruders" #: src/slic3r/GUI/UnsavedChangesDialog.cpp:1456 msgid "Select presets to compare" -msgstr "" +msgstr "Selecteer presets om te vergelijken" #: src/slic3r/GUI/UnsavedChangesDialog.cpp:1505 msgid "Show all presets (including incompatible)" -msgstr "Toon alle presets (inclusief incompatibele)" +msgstr "Toon alle presets (inclusief niet compatibele)" #: src/slic3r/GUI/UnsavedChangesDialog.cpp:1520 msgid "Left Preset Value" @@ -9627,7 +9680,7 @@ msgstr "Nieuwe versie:" #: src/slic3r/GUI/UpdateDialogs.cpp:52 msgid "Changelog & Download" -msgstr "" +msgstr "Wijzigingslogboek downloaden" #: src/slic3r/GUI/UpdateDialogs.cpp:59 src/slic3r/GUI/UpdateDialogs.cpp:133 #: src/slic3r/GUI/UpdateDialogs.cpp:191 @@ -9727,7 +9780,7 @@ msgstr "%s afsluiten" #: src/slic3r/GUI/UpdateDialogs.cpp:213 #, c-format, boost-format msgid "%s configuration is incompatible" -msgstr "%s configuratie is niet geschikt" +msgstr "%s configuratie is niet compatibel" #: src/slic3r/GUI/UpdateDialogs.cpp:216 #, c-format, boost-format @@ -9741,7 +9794,7 @@ msgid "" "the initial configuration. Doing so will create a backup snapshot of the " "existing configuration before installing files compatible with this %s." msgstr "" -"Deze versie van %s is niet geschikt voor de huidig geïnstalleerde " +"Deze versie van %s is niet compatibel voor de huidig geïnstalleerde " "configuratiebundels.\n" "Dit kan mogelijk ontstaan als resultaat van het draaien van een ouder %s na " "het gebruik van een nieuwere.\n" @@ -9758,7 +9811,7 @@ msgstr "Deze %s versie: %s" #: src/slic3r/GUI/UpdateDialogs.cpp:230 msgid "Incompatible bundles:" -msgstr "Ongeschikte bundels:" +msgstr "Niet compatibele bundels:" #: src/slic3r/GUI/UpdateDialogs.cpp:246 msgid "Re-configure" @@ -9994,27 +10047,27 @@ msgstr "Opslaan van mesh in 3MF-container mislukt." #: src/slic3r/Utils/FixModelByWin10.cpp:378 msgid "Export of a temporary 3mf file failed" -msgstr "Exporteren van tijdelijk 3MF-bestand mislukt" +msgstr "Exporteren van tijdelijk .3MF-bestand mislukt" #: src/slic3r/Utils/FixModelByWin10.cpp:394 msgid "Import of the repaired 3mf file failed" -msgstr "Importeren van het gerepareerde 3MF-bestand mislukt" +msgstr "Importeren van het gerepareerde .3MF-bestand mislukt" #: src/slic3r/Utils/FixModelByWin10.cpp:396 msgid "Repaired 3MF file does not contain any object" -msgstr "Gerepareerd 3MF-bestand bevat geen object" +msgstr "Gerepareerd .3MF-bestand bevat geen object" #: src/slic3r/Utils/FixModelByWin10.cpp:398 msgid "Repaired 3MF file contains more than one object" -msgstr "Gerepareerd 3MF-bestand bevat meer dan één object" +msgstr "Gerepareerd .3MF-bestand bevat meer dan één object" #: src/slic3r/Utils/FixModelByWin10.cpp:400 msgid "Repaired 3MF file does not contain any volume" -msgstr "Gerepareerd 3MF-bestand bevat geen volume" +msgstr "Gerepareerd .3MF-bestand bevat geen volume" #: src/slic3r/Utils/FixModelByWin10.cpp:402 msgid "Repaired 3MF file contains more than one volume" -msgstr "Gerepareerd 3MF-bestand bevat meer dan één volume" +msgstr "Gerepareerd .3MF-bestand bevat meer dan één volume" #: src/slic3r/Utils/FixModelByWin10.cpp:412 msgid "Model repair finished" @@ -10144,7 +10197,7 @@ msgstr "" #: src/slic3r/Utils/Process.cpp:157 msgid "Open G-code file:" -msgstr "Open G-code bestand:" +msgstr "Open .gcode-bestand:" #: src/slic3r/Utils/Repetier.cpp:84 msgid "Connection to Repetier works correctly." @@ -10191,24 +10244,26 @@ msgstr "" #: src/slic3r/Config/Snapshot.cpp:584 msgid "Taking a configuration snapshot failed." -msgstr "" +msgstr "Configuratiesnapshot nemen is mislukt." #: src/slic3r/Config/Snapshot.cpp:598 msgid "" "PrusaSlicer has encountered an error while taking a configuration snapshot." msgstr "" +"PrusaSlicer heeft een fout opgelopen bij het maken van een " +"configuratiesnapshot." #: src/slic3r/Config/Snapshot.cpp:599 msgid "PrusaSlicer error" -msgstr "" +msgstr "PrusaSlicer-fout" #: src/slic3r/Config/Snapshot.cpp:601 msgid "Continue" -msgstr "" +msgstr "Doorgaan" #: src/slic3r/Config/Snapshot.cpp:601 msgid "Abort" -msgstr "" +msgstr "Stoppen" #: src/libslic3r/GCode.cpp:539 msgid "There is an object with no extrusions in the first layer." @@ -10258,7 +10313,7 @@ msgstr "" #: src/libslic3r/GCode.cpp:1200 src/libslic3r/GCode.cpp:1211 msgid "No extrusions were generated for objects." -msgstr "" +msgstr "Geen extrusies werden gegenereerd voor de objecten." #: src/libslic3r/GCode.cpp:1406 msgid "" @@ -10286,8 +10341,8 @@ msgid "" "The selected 3mf file has been saved with a newer version of %1% and is not " "compatible." msgstr "" -"Het geselecteerde 3MF-bestand is opgeslagen in een nieuwere versie van %1% " -"en is niet geschikt." +"Het geselecteerde .3MF-bestand is opgeslagen in een nieuwere versie van %1% " +"en is niet compatibel." #: src/libslic3r/Format/3mf.cpp:1746 msgid "" @@ -10319,8 +10374,8 @@ msgid "" "The selected amf file has been saved with a newer version of %1% and is not " "compatible." msgstr "" -"Het geselecteerde AMF-bestand is opgeslagen in een nieuwere versie van %1% " -"en is niet geschikt." +"Het geselecteerde .AMF-bestand is opgeslagen in een nieuwere versie van %1% " +"en is niet compatibel." #: src/libslic3r/GCode/PostProcessor.cpp:289 #, boost-format @@ -10335,10 +10390,10 @@ msgid "" msgstr "" "Nabewerkscript %1% gaf een fout.\n" "\n" -"Het nabewerkscript zou de het gcode-bestand %2% moeten aanpassen, maar het " +"Het nabewerkscript zou de het .gcode-bestand %2% moeten aanpassen, maar het " "bestand is verwijderd en waarschijnlijk opgeslagen onder een andere naam.\n" "Pas alstublieft het nabewerkscript aan om de G-code aan te passen en " -"raadpleeg de handleiding over de benoeming van het nabewerkte gcode-" +"raadpleeg de handleiding over de benoeming van het nabewerkte .gcode-" "bestand.\n" #: src/libslic3r/miniz_extension.cpp:91 @@ -10650,18 +10705,25 @@ msgid "" "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " "layer_gcode." msgstr "" +"Relatieve extruderwaarden vereist het resetten van de extruderpositie op " +"elke laag om decimale onnauwkeurigheid te voorkomen. Voeg \"G92 E0\" toe aan " +"layer_gcode." #: src/libslic3r/Print.cpp:679 msgid "" "\"G92 E0\" was found in before_layer_gcode, which is incompatible with " "absolute extruder addressing." msgstr "" +"\"G92 E0\" gevonden in before_layer_gcode, wat niet compatibel is met " +"absolute positionering." #: src/libslic3r/Print.cpp:681 msgid "" "\"G92 E0\" was found in layer_gcode, which is incompatible with absolute " "extruder addressing." msgstr "" +"\"G92 E0\" gevonden in layer_gcode, wat niet compatibel is met absolute " +"positionering." #: src/libslic3r/Print.cpp:823 msgid "Infilling layers" @@ -10849,18 +10911,20 @@ msgid "" "Picture sizes to be stored into a .gcode and .sl1 / .sl1s files, in the " "following format: \"XxY, XxY, ...\"" msgstr "" -"Afbeeldingsgrootte wordt opgeslagen in de .gcode en .sl1 / .sl1s bestanden " -"in het formaat: \"XxY, XxY, ...\"" +"Afbeeldingsgrootte wordt opgeslagen in de .gcode en .sl1/.sl1s-bestanden in " +"het formaat: \"XxY, XxY, ...\"" #: src/libslic3r/PrintConfig.cpp:275 msgid "Format of G-code thumbnails" -msgstr "" +msgstr "Bestandstype van G-code-voorbeelden" #: src/libslic3r/PrintConfig.cpp:276 msgid "" "Format of G-code thumbnails: PNG for best quality, JPG for smallest size, " "QOI for low memory firmware" msgstr "" +"Bestandstype van G-code-voorbeelden: PNG voor de beste kwaliteit, JPG voor " +"kleinste bestand, QOI voor firmware met weinig geheugen" #: src/libslic3r/PrintConfig.cpp:287 msgid "" @@ -10893,7 +10957,7 @@ msgid "" "name and password into the URL in the following format: https://username:" "password@your-octopi-address/" msgstr "" -"PrusaSlicer kan G-code-bestanden uploaden naar een printerhost. Dit tekstvak " +"PrusaSlicer kan .gcode-bestanden uploaden naar een printerhost. Dit tekstvak " "bevat de hostnaam, IP-adres of URL van de printerhostinstantie. Als de " "printerhost achter HAProxy met basis-authorisatie aan staat, kan toegang " "worden verkregen door gebruikersnaam en wachtwoord in te voeren in bij de " @@ -10908,8 +10972,8 @@ 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 "" -"PrusaSlicer kan gcode-bestanden naar een printerhost uploaden. Dit veld moet " -"de API-key of het wachtwoord voor authenticatie bevatten." +"PrusaSlicer kan .gcode-bestanden naar een printerhost uploaden. Dit veld " +"moet de API-key of het wachtwoord voor authenticatie bevatten." #: src/libslic3r/PrintConfig.cpp:322 msgid "Name of the printer" @@ -10961,7 +11025,7 @@ msgstr "API-sleutel" #: src/libslic3r/PrintConfig.cpp:374 msgid "HTTP digest" -msgstr "HTTP authenticatie" +msgstr "HTTP weergave" #: src/libslic3r/PrintConfig.cpp:394 msgid "Avoid crossing perimeters" @@ -10998,7 +11062,7 @@ msgstr "" msgid "mm or % (zero to disable)" msgstr "mm of % (stel in op 0 om uit te zetten)" -#: src/libslic3r/PrintConfig.cpp:414 src/libslic3r/PrintConfig.cpp:2808 +#: src/libslic3r/PrintConfig.cpp:414 src/libslic3r/PrintConfig.cpp:2807 msgid "Other layers" msgstr "Overige lagen" @@ -11076,10 +11140,10 @@ msgstr "" "op 0, wordt de acceleratie-instelling voor bruggen uitgezet." #: src/libslic3r/PrintConfig.cpp:467 src/libslic3r/PrintConfig.cpp:638 -#: src/libslic3r/PrintConfig.cpp:1188 src/libslic3r/PrintConfig.cpp:1197 -#: src/libslic3r/PrintConfig.cpp:1397 src/libslic3r/PrintConfig.cpp:1690 -#: src/libslic3r/PrintConfig.cpp:1741 src/libslic3r/PrintConfig.cpp:1752 -#: src/libslic3r/PrintConfig.cpp:1762 src/libslic3r/PrintConfig.cpp:1960 +#: src/libslic3r/PrintConfig.cpp:1187 src/libslic3r/PrintConfig.cpp:1196 +#: src/libslic3r/PrintConfig.cpp:1396 src/libslic3r/PrintConfig.cpp:1689 +#: src/libslic3r/PrintConfig.cpp:1740 src/libslic3r/PrintConfig.cpp:1751 +#: src/libslic3r/PrintConfig.cpp:1761 src/libslic3r/PrintConfig.cpp:1959 msgid "mm/s²" msgstr "mm/s²" @@ -11097,11 +11161,11 @@ msgstr "" "automatisch berekend, anders wordt de opgegeven hoek voor alle bruggen " "gebruikt. 180° staat gelijk aan 0°." -#: src/libslic3r/PrintConfig.cpp:478 src/libslic3r/PrintConfig.cpp:1098 -#: src/libslic3r/PrintConfig.cpp:2251 src/libslic3r/PrintConfig.cpp:2261 -#: src/libslic3r/PrintConfig.cpp:2552 src/libslic3r/PrintConfig.cpp:2793 -#: src/libslic3r/PrintConfig.cpp:3010 src/libslic3r/PrintConfig.cpp:3113 -#: src/libslic3r/PrintConfig.cpp:3667 src/libslic3r/PrintConfig.cpp:3788 +#: src/libslic3r/PrintConfig.cpp:478 src/libslic3r/PrintConfig.cpp:1097 +#: src/libslic3r/PrintConfig.cpp:2250 src/libslic3r/PrintConfig.cpp:2260 +#: src/libslic3r/PrintConfig.cpp:2551 src/libslic3r/PrintConfig.cpp:2792 +#: src/libslic3r/PrintConfig.cpp:3009 src/libslic3r/PrintConfig.cpp:3112 +#: src/libslic3r/PrintConfig.cpp:3666 src/libslic3r/PrintConfig.cpp:3787 msgid "°" msgstr "°" @@ -11113,11 +11177,11 @@ msgstr "Ventilatorsnelheid voor bruggen" msgid "This fan speed is enforced during all bridges and overhangs." msgstr "Deze ventilatorsnelheid wordt aangehouden bij bruggen en overhanging." -#: src/libslic3r/PrintConfig.cpp:486 src/libslic3r/PrintConfig.cpp:1110 -#: src/libslic3r/PrintConfig.cpp:1578 src/libslic3r/PrintConfig.cpp:1770 -#: src/libslic3r/PrintConfig.cpp:1833 src/libslic3r/PrintConfig.cpp:2084 -#: src/libslic3r/PrintConfig.cpp:2143 src/libslic3r/PrintConfig.cpp:3292 -#: src/libslic3r/PrintConfig.cpp:3581 src/libslic3r/PrintConfig.cpp:3707 +#: src/libslic3r/PrintConfig.cpp:486 src/libslic3r/PrintConfig.cpp:1109 +#: src/libslic3r/PrintConfig.cpp:1577 src/libslic3r/PrintConfig.cpp:1769 +#: src/libslic3r/PrintConfig.cpp:1832 src/libslic3r/PrintConfig.cpp:2083 +#: src/libslic3r/PrintConfig.cpp:2142 src/libslic3r/PrintConfig.cpp:3291 +#: src/libslic3r/PrintConfig.cpp:3580 src/libslic3r/PrintConfig.cpp:3706 msgid "%" msgstr "%" @@ -11148,14 +11212,14 @@ msgstr "Printsnelheid voor bruggen." #: src/libslic3r/PrintConfig.cpp:508 src/libslic3r/PrintConfig.cpp:916 #: src/libslic3r/PrintConfig.cpp:924 src/libslic3r/PrintConfig.cpp:933 #: src/libslic3r/PrintConfig.cpp:941 src/libslic3r/PrintConfig.cpp:968 -#: src/libslic3r/PrintConfig.cpp:987 src/libslic3r/PrintConfig.cpp:1325 -#: src/libslic3r/PrintConfig.cpp:1515 src/libslic3r/PrintConfig.cpp:1597 -#: src/libslic3r/PrintConfig.cpp:1673 src/libslic3r/PrintConfig.cpp:1707 -#: src/libslic3r/PrintConfig.cpp:1719 src/libslic3r/PrintConfig.cpp:1729 -#: src/libslic3r/PrintConfig.cpp:1792 src/libslic3r/PrintConfig.cpp:1851 -#: src/libslic3r/PrintConfig.cpp:1991 src/libslic3r/PrintConfig.cpp:2218 -#: src/libslic3r/PrintConfig.cpp:2227 src/libslic3r/PrintConfig.cpp:2758 -#: src/libslic3r/PrintConfig.cpp:2908 src/libslic3r/PrintConfig.cpp:2918 +#: src/libslic3r/PrintConfig.cpp:987 src/libslic3r/PrintConfig.cpp:1324 +#: src/libslic3r/PrintConfig.cpp:1514 src/libslic3r/PrintConfig.cpp:1596 +#: src/libslic3r/PrintConfig.cpp:1672 src/libslic3r/PrintConfig.cpp:1706 +#: src/libslic3r/PrintConfig.cpp:1718 src/libslic3r/PrintConfig.cpp:1728 +#: src/libslic3r/PrintConfig.cpp:1791 src/libslic3r/PrintConfig.cpp:1850 +#: src/libslic3r/PrintConfig.cpp:1990 src/libslic3r/PrintConfig.cpp:2217 +#: src/libslic3r/PrintConfig.cpp:2226 src/libslic3r/PrintConfig.cpp:2757 +#: src/libslic3r/PrintConfig.cpp:2907 src/libslic3r/PrintConfig.cpp:2917 msgid "mm/s" msgstr "mm/s" @@ -11236,7 +11300,7 @@ msgstr "Hoogte waarbij de filamentwissel plaatsvindt." #: src/libslic3r/PrintConfig.cpp:570 msgid "Compatible printers condition" -msgstr "Voorwaarden geschikte printers" +msgstr "Voorwaarden compatibele printers" #: src/libslic3r/PrintConfig.cpp:571 msgid "" @@ -11246,11 +11310,11 @@ msgid "" msgstr "" "Een waar/niet waar aanduiding die gebruik maakt van configuratiewaarden van " "een actief printerprofiel. Als deze aanduiding op waar staat, wordt dit " -"profiel beschouwd als geschikt voor het actieve printerprofiel." +"profiel beschouwd als compatibel voor het actieve printerprofiel." #: src/libslic3r/PrintConfig.cpp:585 msgid "Compatible print profiles condition" -msgstr "Voorwaarden geschikte printprofielen" +msgstr "Voorwaarden compatibele printprofielen" #: src/libslic3r/PrintConfig.cpp:586 msgid "" @@ -11260,7 +11324,7 @@ msgid "" msgstr "" "Een waar/niet waar aanduiding die gebruik maakt van configuratiewaarden van " "een actief printprofiel. Als deze aanduiding op waar staat, wordt dit " -"profiel beschouwd als geschikt voor het actieve printprofiel." +"profiel beschouwd als compatibel met het actieve printprofiel." #: src/libslic3r/PrintConfig.cpp:603 msgid "Complete individual objects" @@ -11335,8 +11399,8 @@ msgstr "" msgid "Default print profile" msgstr "Standaard printprofiel" -#: src/libslic3r/PrintConfig.cpp:652 src/libslic3r/PrintConfig.cpp:3511 -#: src/libslic3r/PrintConfig.cpp:3522 +#: src/libslic3r/PrintConfig.cpp:652 src/libslic3r/PrintConfig.cpp:3510 +#: src/libslic3r/PrintConfig.cpp:3521 msgid "" "Default print profile associated with the current printer profile. On " "selection of the current printer profile, this print profile will be " @@ -11422,8 +11486,8 @@ msgstr "" "Vullingspatroon voor bovenste lagen. Dit heeft alleen invloed op de bovenste " "zichtbare laag en niet de aangrenzende horizontale dichte shells." -#: src/libslic3r/PrintConfig.cpp:726 src/libslic3r/PrintConfig.cpp:1165 -#: src/libslic3r/PrintConfig.cpp:2723 src/libslic3r/PrintConfig.cpp:2740 +#: src/libslic3r/PrintConfig.cpp:726 src/libslic3r/PrintConfig.cpp:1164 +#: src/libslic3r/PrintConfig.cpp:2722 src/libslic3r/PrintConfig.cpp:2739 msgid "Rectilinear" msgstr "Rechtlijnig" @@ -11431,24 +11495,24 @@ msgstr "Rechtlijnig" msgid "Monotonic" msgstr "Monotoon" -#: src/libslic3r/PrintConfig.cpp:728 src/libslic3r/PrintConfig.cpp:1166 +#: src/libslic3r/PrintConfig.cpp:728 src/libslic3r/PrintConfig.cpp:1165 msgid "Aligned Rectilinear" msgstr "Parallel rechtlijnig" -#: src/libslic3r/PrintConfig.cpp:729 src/libslic3r/PrintConfig.cpp:1172 -#: src/libslic3r/PrintConfig.cpp:2741 +#: src/libslic3r/PrintConfig.cpp:729 src/libslic3r/PrintConfig.cpp:1171 +#: src/libslic3r/PrintConfig.cpp:2740 msgid "Concentric" msgstr "Concentrisch" -#: src/libslic3r/PrintConfig.cpp:730 src/libslic3r/PrintConfig.cpp:1176 +#: src/libslic3r/PrintConfig.cpp:730 src/libslic3r/PrintConfig.cpp:1175 msgid "Hilbert Curve" msgstr "Hilbert-kromme" -#: src/libslic3r/PrintConfig.cpp:731 src/libslic3r/PrintConfig.cpp:1177 +#: src/libslic3r/PrintConfig.cpp:731 src/libslic3r/PrintConfig.cpp:1176 msgid "Archimedean Chords" msgstr "Archimedes-spiraal" -#: src/libslic3r/PrintConfig.cpp:732 src/libslic3r/PrintConfig.cpp:1178 +#: src/libslic3r/PrintConfig.cpp:732 src/libslic3r/PrintConfig.cpp:1177 msgid "Octagram Spiral" msgstr "Octagramspiraal" @@ -11481,13 +11545,13 @@ msgstr "" "percentage, wordt dit berekend over de laagdikte." #: src/libslic3r/PrintConfig.cpp:754 src/libslic3r/PrintConfig.cpp:865 -#: src/libslic3r/PrintConfig.cpp:1219 src/libslic3r/PrintConfig.cpp:1422 -#: src/libslic3r/PrintConfig.cpp:1479 src/libslic3r/PrintConfig.cpp:1506 -#: src/libslic3r/PrintConfig.cpp:1980 src/libslic3r/PrintConfig.cpp:2366 -#: src/libslic3r/PrintConfig.cpp:2540 src/libslic3r/PrintConfig.cpp:2629 -#: src/libslic3r/PrintConfig.cpp:2864 src/libslic3r/PrintConfig.cpp:3086 -#: src/libslic3r/PrintConfig.cpp:3101 src/libslic3r/PrintConfig.cpp:3135 -#: src/libslic3r/PrintConfig.cpp:3147 +#: src/libslic3r/PrintConfig.cpp:1218 src/libslic3r/PrintConfig.cpp:1421 +#: src/libslic3r/PrintConfig.cpp:1478 src/libslic3r/PrintConfig.cpp:1505 +#: src/libslic3r/PrintConfig.cpp:1979 src/libslic3r/PrintConfig.cpp:2365 +#: src/libslic3r/PrintConfig.cpp:2539 src/libslic3r/PrintConfig.cpp:2628 +#: src/libslic3r/PrintConfig.cpp:2863 src/libslic3r/PrintConfig.cpp:3085 +#: src/libslic3r/PrintConfig.cpp:3100 src/libslic3r/PrintConfig.cpp:3134 +#: src/libslic3r/PrintConfig.cpp:3146 msgid "mm or %" msgstr "mm of %" @@ -11502,10 +11566,10 @@ msgstr "" "perimeters. Als dit ingesteld is op 0, wordt een automatische snelheid " "genomen." -#: src/libslic3r/PrintConfig.cpp:766 src/libslic3r/PrintConfig.cpp:1241 -#: src/libslic3r/PrintConfig.cpp:1252 src/libslic3r/PrintConfig.cpp:2325 -#: src/libslic3r/PrintConfig.cpp:2378 src/libslic3r/PrintConfig.cpp:2709 -#: src/libslic3r/PrintConfig.cpp:2878 +#: src/libslic3r/PrintConfig.cpp:766 src/libslic3r/PrintConfig.cpp:1240 +#: src/libslic3r/PrintConfig.cpp:1251 src/libslic3r/PrintConfig.cpp:2324 +#: src/libslic3r/PrintConfig.cpp:2377 src/libslic3r/PrintConfig.cpp:2708 +#: src/libslic3r/PrintConfig.cpp:2877 msgid "mm/s or %" msgstr "mm/s of %" @@ -11572,7 +11636,7 @@ msgid "Extruder Color" msgstr "Extruderkleur" #: src/libslic3r/PrintConfig.cpp:827 src/libslic3r/PrintConfig.cpp:890 -#: src/libslic3r/PrintConfig.cpp:3363 +#: src/libslic3r/PrintConfig.cpp:3362 msgid "This is only used in the Slic3r interface as a visual help." msgstr "" "Dit wordt alleen gebruikt in de PrusaSlicer-interface als een visueel " @@ -11666,11 +11730,11 @@ msgstr "" "ventilator aangezet worden en wordt de snelheid berekend door te " "interpoleren tussen de minimale en maximale snelheid." -#: src/libslic3r/PrintConfig.cpp:882 src/libslic3r/PrintConfig.cpp:2313 +#: src/libslic3r/PrintConfig.cpp:882 src/libslic3r/PrintConfig.cpp:2312 msgid "approximate seconds" msgstr "geschat aantal seconden" -#: src/libslic3r/PrintConfig.cpp:889 src/libslic3r/PrintConfig.cpp:3362 +#: src/libslic3r/PrintConfig.cpp:889 src/libslic3r/PrintConfig.cpp:3361 msgid "Color" msgstr "Kleur" @@ -11682,7 +11746,7 @@ msgstr "Filamentopmerkingen" msgid "You can put your notes regarding the filament here." msgstr "Hier kunt u opmerkingen over het filament plaatsen." -#: src/libslic3r/PrintConfig.cpp:904 src/libslic3r/PrintConfig.cpp:1798 +#: src/libslic3r/PrintConfig.cpp:904 src/libslic3r/PrintConfig.cpp:1797 msgid "Max volumetric speed" msgstr "Maximale volumetrische snelheid" @@ -11851,8 +11915,8 @@ msgstr "" "daarom een schuifmaat en doe meerdere metingen over het hele filament. " "Bereken vervolgens het gemiddelde." -#: src/libslic3r/PrintConfig.cpp:1024 src/libslic3r/PrintConfig.cpp:3401 -#: src/libslic3r/PrintConfig.cpp:3402 +#: src/libslic3r/PrintConfig.cpp:1024 src/libslic3r/PrintConfig.cpp:3400 +#: src/libslic3r/PrintConfig.cpp:3401 msgid "Density" msgstr "Dichtheid" @@ -11880,15 +11944,15 @@ msgstr "Filamenttype" msgid "The filament material type for use in custom G-codes." msgstr "Het filamenttype voor het gebruik van de custom G-codes." -#: src/libslic3r/PrintConfig.cpp:1062 +#: src/libslic3r/PrintConfig.cpp:1061 msgid "Soluble material" msgstr "Oplosbaar materiaal" -#: src/libslic3r/PrintConfig.cpp:1063 +#: src/libslic3r/PrintConfig.cpp:1062 msgid "Soluble material is most likely used for a soluble support." msgstr "Oplosbaar materiaal wordt vaak gebruikt voor oplosbaar support." -#: src/libslic3r/PrintConfig.cpp:1069 +#: src/libslic3r/PrintConfig.cpp:1068 msgid "" "Enter your filament cost per kg here. This is only for statistical " "information." @@ -11896,15 +11960,15 @@ msgstr "" "Voer hier de filamentkosten per kilogram in. Dit is alleen voor statistische " "informatie." -#: src/libslic3r/PrintConfig.cpp:1070 +#: src/libslic3r/PrintConfig.cpp:1069 msgid "money/kg" msgstr "€/kg" -#: src/libslic3r/PrintConfig.cpp:1075 +#: src/libslic3r/PrintConfig.cpp:1074 msgid "Spool weight" msgstr "Spoelgewicht" -#: src/libslic3r/PrintConfig.cpp:1076 +#: src/libslic3r/PrintConfig.cpp:1075 msgid "" "Enter weight of the empty filament spool. One may weigh a partially consumed " "filament spool before printing and one may compare the measured weight with " @@ -11916,19 +11980,19 @@ msgstr "" "berekende gewicht van de filamentspoel om te weten te komen of de " "hoeveelheid filament op de spoel voldoende is om de print te voltooien." -#: src/libslic3r/PrintConfig.cpp:1080 +#: src/libslic3r/PrintConfig.cpp:1079 msgid "g" msgstr "g" -#: src/libslic3r/PrintConfig.cpp:1089 src/libslic3r/PrintConfig.cpp:3506 +#: src/libslic3r/PrintConfig.cpp:1088 src/libslic3r/PrintConfig.cpp:3505 msgid "(Unknown)" msgstr "(Onbekend)" -#: src/libslic3r/PrintConfig.cpp:1093 +#: src/libslic3r/PrintConfig.cpp:1092 msgid "Fill angle" msgstr "Vullingshoek" -#: src/libslic3r/PrintConfig.cpp:1095 +#: src/libslic3r/PrintConfig.cpp:1094 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, " @@ -11938,64 +12002,64 @@ msgstr "" "geprint. Bruggen worden geprint met de optimale richting. Deze instelling " "zal die richting niet beïnvloeden." -#: src/libslic3r/PrintConfig.cpp:1107 +#: src/libslic3r/PrintConfig.cpp:1106 msgid "Fill density" msgstr "Vullingsdichtheid" -#: src/libslic3r/PrintConfig.cpp:1109 +#: src/libslic3r/PrintConfig.cpp:1108 msgid "Density of internal infill, expressed in the range 0% - 100%." msgstr "" "Dichtheid van inwendige vulling, uitgedrukt in een percentage (0 - 100%)" -#: src/libslic3r/PrintConfig.cpp:1144 +#: src/libslic3r/PrintConfig.cpp:1143 msgid "Fill pattern" msgstr "Vullingspatroon" -#: src/libslic3r/PrintConfig.cpp:1146 +#: src/libslic3r/PrintConfig.cpp:1145 msgid "Fill pattern for general low-density infill." msgstr "Vulpatroon voor algemene lagere-dichtheidsvulling." -#: src/libslic3r/PrintConfig.cpp:1167 src/libslic3r/PrintConfig.cpp:2772 +#: src/libslic3r/PrintConfig.cpp:1166 src/libslic3r/PrintConfig.cpp:2771 msgid "Grid" msgstr "Raster" -#: src/libslic3r/PrintConfig.cpp:1169 +#: src/libslic3r/PrintConfig.cpp:1168 msgid "Stars" msgstr "Sterren" -#: src/libslic3r/PrintConfig.cpp:1170 +#: src/libslic3r/PrintConfig.cpp:1169 msgid "Cubic" msgstr "Kubisch" -#: src/libslic3r/PrintConfig.cpp:1171 +#: src/libslic3r/PrintConfig.cpp:1170 msgid "Line" msgstr "Lijn" -#: src/libslic3r/PrintConfig.cpp:1173 src/libslic3r/PrintConfig.cpp:2725 +#: src/libslic3r/PrintConfig.cpp:1172 src/libslic3r/PrintConfig.cpp:2724 msgid "Honeycomb" msgstr "Honingraat" -#: src/libslic3r/PrintConfig.cpp:1174 +#: src/libslic3r/PrintConfig.cpp:1173 msgid "3D Honeycomb" msgstr "3D-honingraat" -#: src/libslic3r/PrintConfig.cpp:1175 +#: src/libslic3r/PrintConfig.cpp:1174 msgid "Gyroid" msgstr "Gyroïde" -#: src/libslic3r/PrintConfig.cpp:1179 +#: src/libslic3r/PrintConfig.cpp:1178 msgid "Adaptive Cubic" msgstr "Adaptief kubisch" -#: src/libslic3r/PrintConfig.cpp:1180 +#: src/libslic3r/PrintConfig.cpp:1179 msgid "Support Cubic" msgstr "Ondersteunend kubisch" -#: src/libslic3r/PrintConfig.cpp:1181 +#: src/libslic3r/PrintConfig.cpp:1180 msgid "Lightning" -msgstr "Belichting" +msgstr "Bliksem" -#: src/libslic3r/PrintConfig.cpp:1186 +#: src/libslic3r/PrintConfig.cpp:1185 msgid "" "This is the acceleration your printer will use for first layer. Set zero to " "disable acceleration control for first layer." @@ -12003,11 +12067,11 @@ msgstr "" "Deze acceleratie zal uw printer gebruiken voor de eerste laag. Als dit " "ingesteld is op 0, wordt de standaard acceleratie gebruikt." -#: src/libslic3r/PrintConfig.cpp:1194 +#: src/libslic3r/PrintConfig.cpp:1193 msgid "First object layer over raft interface" msgstr "Eerste laag van het object boven de raft-interface" -#: src/libslic3r/PrintConfig.cpp:1195 +#: src/libslic3r/PrintConfig.cpp:1194 msgid "" "This is the acceleration your printer will use for first layer of object " "above raft interface. Set zero to disable acceleration control for first " @@ -12017,11 +12081,11 @@ msgstr "" "raft-interface. Stel in op 0 om acceleratiecontrole uit te schakelen voor de " "eerste laag boven de raft-interface." -#: src/libslic3r/PrintConfig.cpp:1204 +#: src/libslic3r/PrintConfig.cpp:1203 msgid "First layer bed temperature" msgstr "Bedtemperatuur eerste laag" -#: src/libslic3r/PrintConfig.cpp:1205 +#: src/libslic3r/PrintConfig.cpp:1204 msgid "" "Heated build plate temperature for the first layer. Set this to zero to " "disable bed temperature control commands in the output." @@ -12029,7 +12093,7 @@ msgstr "" "Bedtemperatuur voor de eerste laag. Als dit ingesteld is op 0, worden " "bedtemperatuur-commando's weggelaten in de output." -#: src/libslic3r/PrintConfig.cpp:1215 +#: src/libslic3r/PrintConfig.cpp:1214 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 " @@ -12042,7 +12106,7 @@ msgstr "" "wordt dit berekend over de laagdikte van de eerste laag. Als dit is " "ingesteld op 0, wordt de standaard extrusiebreedte gebruikt." -#: src/libslic3r/PrintConfig.cpp:1229 +#: src/libslic3r/PrintConfig.cpp:1228 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 " @@ -12052,11 +12116,11 @@ msgstr "" "printen om bedhechting en tolerantie te verbeteren op niet-perfecte " "printbedden." -#: src/libslic3r/PrintConfig.cpp:1237 +#: src/libslic3r/PrintConfig.cpp:1236 msgid "First layer speed" msgstr "Snelheid eerste laag" -#: src/libslic3r/PrintConfig.cpp:1238 +#: src/libslic3r/PrintConfig.cpp:1237 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 " @@ -12067,11 +12131,11 @@ msgstr "" "van het type. Als dit is uitgedrukt als percentage, wordt dit berekend over " "de standaardsnelheid." -#: src/libslic3r/PrintConfig.cpp:1248 +#: src/libslic3r/PrintConfig.cpp:1247 msgid "Speed of object first layer over raft interface" msgstr "Snelheid van de eerste laag boven de raft-interface" -#: src/libslic3r/PrintConfig.cpp:1249 +#: src/libslic3r/PrintConfig.cpp:1248 msgid "" "If expressed as absolute value in mm/s, this speed will be applied to all " "the print moves of the first object layer above raft interface, regardless " @@ -12083,11 +12147,11 @@ msgstr "" "interface, onafhankelijk van het type. Als dit is uitgedrukt als percentage " "(bijv. 40%) worden de standaard snelheden verschaald." -#: src/libslic3r/PrintConfig.cpp:1259 +#: src/libslic3r/PrintConfig.cpp:1258 msgid "First layer nozzle temperature" msgstr "Nozzletemperatuur eerste laag" -#: src/libslic3r/PrintConfig.cpp:1260 +#: src/libslic3r/PrintConfig.cpp:1259 msgid "" "Nozzle temperature for the first layer. If you want to control temperature " "manually during print, set this to zero to disable temperature control " @@ -12097,11 +12161,11 @@ msgstr "" "wijzigen in de print, stel dit dan in op 0 om temperatuurregeling uit te " "zetten in de G-code." -#: src/libslic3r/PrintConfig.cpp:1268 +#: src/libslic3r/PrintConfig.cpp:1267 msgid "Full fan speed at layer" msgstr "Volledige ventilatorsnelheid op laag" -#: src/libslic3r/PrintConfig.cpp:1269 +#: src/libslic3r/PrintConfig.cpp:1268 msgid "" "Fan speed will be ramped up linearly from zero at layer " "\"disable_fan_first_layers\" to maximum at layer \"full_fan_speed_layer\". " @@ -12115,23 +12179,23 @@ msgstr "" "\"disable_fan_first_layers\" in welk geval de ventilator zal draaien op de " "maximaal toegestane snelheid op laag \"disable_fan_first_layers\" + 1." -#: src/libslic3r/PrintConfig.cpp:1281 +#: src/libslic3r/PrintConfig.cpp:1280 msgid "Fuzzy skin type." msgstr "Type oneffen oppervlak." -#: src/libslic3r/PrintConfig.cpp:1288 +#: src/libslic3r/PrintConfig.cpp:1287 msgid "Outside walls" msgstr "Alleen buitenwanden" -#: src/libslic3r/PrintConfig.cpp:1289 +#: src/libslic3r/PrintConfig.cpp:1288 msgid "All walls" msgstr "Alle wanden" -#: src/libslic3r/PrintConfig.cpp:1294 +#: src/libslic3r/PrintConfig.cpp:1293 msgid "Fuzzy skin thickness" msgstr "Dikte van oneffen oppervlak" -#: src/libslic3r/PrintConfig.cpp:1296 +#: src/libslic3r/PrintConfig.cpp:1295 msgid "" "The maximum distance that each skin point can be offset (both ways), " "measured perpendicular to the perimeter wall." @@ -12139,11 +12203,11 @@ msgstr "" "De maximale afstand die elke punt kan hebben (naar beide kanten), haaks " "gemeten op de perimeterwand." -#: src/libslic3r/PrintConfig.cpp:1304 +#: src/libslic3r/PrintConfig.cpp:1303 msgid "Fuzzy skin point distance" msgstr "Puntafstand van oneffen oppervlak" -#: src/libslic3r/PrintConfig.cpp:1306 +#: src/libslic3r/PrintConfig.cpp:1305 msgid "" "Perimeters will be split into multiple segments by inserting Fuzzy skin " "points. Lowering the Fuzzy skin point distance will increase the number of " @@ -12153,11 +12217,11 @@ msgstr "" "punten voor oneffen oppervlak. Verlagen van de afstand zorgt voor een " "verhoging van het aantal willekeurige punten op de perimeterwand." -#: src/libslic3r/PrintConfig.cpp:1314 +#: src/libslic3r/PrintConfig.cpp:1313 msgid "Fill gaps" msgstr "Vul gaten" -#: src/libslic3r/PrintConfig.cpp:1316 +#: src/libslic3r/PrintConfig.cpp:1315 msgid "" "Enables filling of gaps between perimeters and between the inner most " "perimeters and infill." @@ -12165,7 +12229,7 @@ msgstr "" "Toestaan van het vullen van gaten tussen perimeters en de binnenste " "perimeter en vulling." -#: src/libslic3r/PrintConfig.cpp:1323 +#: src/libslic3r/PrintConfig.cpp:1322 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 " @@ -12175,11 +12239,11 @@ msgstr "" "Houd deze waarde laag om schudden te voorkomen (wat resulteert in " "resonantieproblemen). Als dit is ingesteld op 0, worden gaten niet gevuld." -#: src/libslic3r/PrintConfig.cpp:1331 +#: src/libslic3r/PrintConfig.cpp:1330 msgid "Verbose G-code" msgstr "Opmerkingen in G-code" -#: src/libslic3r/PrintConfig.cpp:1332 +#: src/libslic3r/PrintConfig.cpp:1331 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 " @@ -12189,11 +12253,11 @@ msgstr "" "commando's wordt een opmerking geplaatst. Als u print vanaf een SD-kaart, " "kan de extra grootte van het bestand de firmware vertragen." -#: src/libslic3r/PrintConfig.cpp:1339 +#: src/libslic3r/PrintConfig.cpp:1338 msgid "G-code flavor" msgstr "G-code-variant" -#: src/libslic3r/PrintConfig.cpp:1340 +#: src/libslic3r/PrintConfig.cpp:1339 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 " @@ -12201,18 +12265,18 @@ msgid "" "extrusion value at all." msgstr "" "Sommige G- en M-commando's zijn niet universeel. Stel deze optie in om een " -"geschikte uitvoer te krijgen voor uw printer. De 'Geen extrusie'-instelling " -"kan gebruikt worden om te printen zonder materiaal te extruderen." +"compatibele uitvoer te krijgen voor uw printer. De 'Geen extrusie'-" +"instelling kan gebruikt worden om te printen zonder materiaal te extruderen." -#: src/libslic3r/PrintConfig.cpp:1367 +#: src/libslic3r/PrintConfig.cpp:1366 msgid "No extrusion" msgstr "Geen extrusie" -#: src/libslic3r/PrintConfig.cpp:1372 +#: src/libslic3r/PrintConfig.cpp:1371 msgid "Label objects" msgstr "Label objecten" -#: src/libslic3r/PrintConfig.cpp:1373 +#: src/libslic3r/PrintConfig.cpp:1372 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 " @@ -12221,22 +12285,22 @@ msgid "" msgstr "" "Schakel dit in om opmerkingen in de G-code toe te voegen voor bewegingen die " "behoren tot een object. Dit is handig voor de OctoPrint CancelObject-plugin. " -"Deze instelling is NIET geschikt voor een multi-materialsetup met één " +"Deze instelling is NIET compatibel met een multi-materialsetup met één " "extruder en 'Afvegen in object' en 'Afvegen in vulling'." -#: src/libslic3r/PrintConfig.cpp:1380 +#: src/libslic3r/PrintConfig.cpp:1379 msgid "G-code substitutions" -msgstr "" +msgstr "G-code-substituties" -#: src/libslic3r/PrintConfig.cpp:1381 +#: src/libslic3r/PrintConfig.cpp:1380 msgid "Find / replace patterns in G-code lines and substitute them." -msgstr "" +msgstr "Zoek / vervang patronen in G-coderegels en substitueer ze." -#: src/libslic3r/PrintConfig.cpp:1386 +#: src/libslic3r/PrintConfig.cpp:1385 msgid "High extruder current on filament swap" msgstr "Hoge stroomsterkte bij extruder voor filamentwissel" -#: src/libslic3r/PrintConfig.cpp:1387 +#: src/libslic3r/PrintConfig.cpp:1386 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 " @@ -12247,7 +12311,7 @@ msgstr "" "maken en om weerstand te overwinnen tijdens het laden van filament met een " "misvormde kop." -#: src/libslic3r/PrintConfig.cpp:1395 +#: src/libslic3r/PrintConfig.cpp:1394 msgid "" "This is the acceleration your printer will use for infill. Set zero to " "disable acceleration control for infill." @@ -12255,11 +12319,11 @@ msgstr "" "Deze acceleratie zal uw printer gebruiken voor de vulling. Als dit is " "ingesteld op 0, wordt de acceleratiecontrole uitgeschakeld." -#: src/libslic3r/PrintConfig.cpp:1403 +#: src/libslic3r/PrintConfig.cpp:1402 msgid "Combine infill every" msgstr "Combineer vulling elke" -#: src/libslic3r/PrintConfig.cpp:1405 +#: src/libslic3r/PrintConfig.cpp:1404 msgid "" "This feature allows to combine infill and speed up your print by extruding " "thicker infill layers while preserving thin perimeters, thus accuracy." @@ -12268,15 +12332,15 @@ msgstr "" "de vullingslagen stapsgewijs dikker te maken, terwijl de laagdikte van " "perimeters behouden wordt." -#: src/libslic3r/PrintConfig.cpp:1408 +#: src/libslic3r/PrintConfig.cpp:1407 msgid "Combine infill every n layers" msgstr "Combineer vulling elke n lagen" -#: src/libslic3r/PrintConfig.cpp:1414 +#: src/libslic3r/PrintConfig.cpp:1413 msgid "Length of the infill anchor" msgstr "Lengte van de vullingsbevestiging" -#: src/libslic3r/PrintConfig.cpp:1416 +#: src/libslic3r/PrintConfig.cpp:1415 msgid "" "Connect an infill line to an internal perimeter with a short segment of an " "additional perimeter. If expressed as percentage (example: 15%) it is " @@ -12298,35 +12362,35 @@ msgstr "" "deze parameter, maar niet langer dan \"anchor_length_max\". Stel in op 0 om " "uit te zetten." -#: src/libslic3r/PrintConfig.cpp:1432 +#: src/libslic3r/PrintConfig.cpp:1431 msgid "0 (no open anchors)" msgstr "0 (geen losse bevestiging)" -#: src/libslic3r/PrintConfig.cpp:1433 src/libslic3r/PrintConfig.cpp:1456 +#: src/libslic3r/PrintConfig.cpp:1432 src/libslic3r/PrintConfig.cpp:1455 msgid "1 mm" msgstr "1 mm" -#: src/libslic3r/PrintConfig.cpp:1434 src/libslic3r/PrintConfig.cpp:1457 +#: src/libslic3r/PrintConfig.cpp:1433 src/libslic3r/PrintConfig.cpp:1456 msgid "2 mm" msgstr "2 mm" -#: src/libslic3r/PrintConfig.cpp:1435 src/libslic3r/PrintConfig.cpp:1458 +#: src/libslic3r/PrintConfig.cpp:1434 src/libslic3r/PrintConfig.cpp:1457 msgid "5 mm" msgstr "5 mm" -#: src/libslic3r/PrintConfig.cpp:1436 src/libslic3r/PrintConfig.cpp:1459 +#: src/libslic3r/PrintConfig.cpp:1435 src/libslic3r/PrintConfig.cpp:1458 msgid "10 mm" msgstr "10 mm" -#: src/libslic3r/PrintConfig.cpp:1437 src/libslic3r/PrintConfig.cpp:1460 +#: src/libslic3r/PrintConfig.cpp:1436 src/libslic3r/PrintConfig.cpp:1459 msgid "1000 (unlimited)" msgstr "1000 (ongelimiteerd)" -#: src/libslic3r/PrintConfig.cpp:1442 +#: src/libslic3r/PrintConfig.cpp:1441 msgid "Maximum length of the infill anchor" msgstr "Maximale lengte van de vullingsbevestiging" -#: src/libslic3r/PrintConfig.cpp:1444 +#: src/libslic3r/PrintConfig.cpp:1443 msgid "" "Connect an infill line to an internal perimeter with a short segment of an " "additional perimeter. If expressed as percentage (example: 15%) it is " @@ -12347,19 +12411,19 @@ msgstr "" "perimetersegment wordt gelimiteerd tot \"infill_anchor\", maar niet langer " "dan deze parameter. Stel in op 0 om uit te zetten." -#: src/libslic3r/PrintConfig.cpp:1455 +#: src/libslic3r/PrintConfig.cpp:1454 msgid "0 (not anchored)" msgstr "0 (niet bevestigd)" -#: src/libslic3r/PrintConfig.cpp:1465 +#: src/libslic3r/PrintConfig.cpp:1464 msgid "Infill extruder" msgstr "Vullingsextruder" -#: src/libslic3r/PrintConfig.cpp:1467 +#: src/libslic3r/PrintConfig.cpp:1466 msgid "The extruder to use when printing infill." msgstr "De extruder die gebruikt wordt voor het printen van de vulling." -#: src/libslic3r/PrintConfig.cpp:1475 +#: src/libslic3r/PrintConfig.cpp:1474 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 " @@ -12373,11 +12437,11 @@ msgstr "" "printen en het onderdeel sterker maken met deze optie. Als dit is uitgedrukt " "als percentage, wordt dit berekend over de laagdikte." -#: src/libslic3r/PrintConfig.cpp:1486 +#: src/libslic3r/PrintConfig.cpp:1485 msgid "Infill before perimeters" msgstr "Vulling vóór perimeters" -#: src/libslic3r/PrintConfig.cpp:1487 +#: src/libslic3r/PrintConfig.cpp:1486 msgid "" "This option will switch the print order of perimeters and infill, making the " "latter first." @@ -12385,11 +12449,11 @@ msgstr "" "Deze optie verandert de printvolgorde van perimeters en vulling; de " "laatstgenoemde eerst." -#: src/libslic3r/PrintConfig.cpp:1492 +#: src/libslic3r/PrintConfig.cpp:1491 msgid "Only infill where needed" msgstr "Alleen vulling waar nodig" -#: src/libslic3r/PrintConfig.cpp:1494 +#: src/libslic3r/PrintConfig.cpp:1493 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 " @@ -12399,11 +12463,11 @@ msgstr "" "ondersteuning van bovenvlakken (het fungeert als inwendig support). Let op: " "deze optie vertraagt de G-code-generatie." -#: src/libslic3r/PrintConfig.cpp:1501 +#: src/libslic3r/PrintConfig.cpp:1500 msgid "Infill/perimeters overlap" msgstr "Overlapping van vulling/perimeters" -#: src/libslic3r/PrintConfig.cpp:1503 +#: src/libslic3r/PrintConfig.cpp:1502 msgid "" "This setting applies an additional overlap between infill and perimeters for " "better bonding. Theoretically this shouldn't be needed, but backlash might " @@ -12415,25 +12479,25 @@ msgstr "" "maar terugslag kan zorgen voor gaten. Als dit is uitgedrukt als percentage, " "wordt dit berekend over de extrusiebreedte van de perimeters." -#: src/libslic3r/PrintConfig.cpp:1514 +#: src/libslic3r/PrintConfig.cpp:1513 msgid "Speed for printing the internal fill. Set to zero for auto." msgstr "" "Printsnelheid voor vulling. Als dit ingesteld is op 0, wordt de snelheid " "automatisch berekend." -#: src/libslic3r/PrintConfig.cpp:1522 +#: src/libslic3r/PrintConfig.cpp:1521 msgid "Inherits profile" msgstr "Afgeleid profiel" -#: src/libslic3r/PrintConfig.cpp:1523 +#: src/libslic3r/PrintConfig.cpp:1522 msgid "Name of the profile, from which this profile inherits." msgstr "Profielnaam waar profiel op is gebaseerd." -#: src/libslic3r/PrintConfig.cpp:1536 +#: src/libslic3r/PrintConfig.cpp:1535 msgid "Interface shells" msgstr "Interfaceshells" -#: src/libslic3r/PrintConfig.cpp:1537 +#: src/libslic3r/PrintConfig.cpp:1536 msgid "" "Force the generation of solid shells between adjacent materials/volumes. " "Useful for multi-extruder prints with translucent materials or manual " @@ -12443,67 +12507,67 @@ msgstr "" "volumes. Dit is handig voor multi-extruderprints met transparante materialen " "of handmatig oplosbaar support." -#: src/libslic3r/PrintConfig.cpp:1545 +#: src/libslic3r/PrintConfig.cpp:1544 msgid "Maximum width of a segmented region" msgstr "Maximale breedte van een gesegmenteerd gebied" -#: src/libslic3r/PrintConfig.cpp:1546 +#: src/libslic3r/PrintConfig.cpp:1545 msgid "Maximum width of a segmented region. Zero disables this feature." msgstr "" "Maximale breedte van een gesegmenteerd gebied. Stel in op 0 om uit te " "schakelen." -#: src/libslic3r/PrintConfig.cpp:1547 src/libslic3r/PrintConfig.cpp:2158 -#: src/libslic3r/PrintConfig.cpp:2167 +#: src/libslic3r/PrintConfig.cpp:1546 src/libslic3r/PrintConfig.cpp:2157 +#: src/libslic3r/PrintConfig.cpp:2166 msgid "mm (zero to disable)" msgstr "mm (stel in op 0 om uit te schakelen)" -#: src/libslic3r/PrintConfig.cpp:1554 +#: src/libslic3r/PrintConfig.cpp:1553 msgid "Enable ironing" msgstr "Sta strijken toe" -#: src/libslic3r/PrintConfig.cpp:1555 +#: src/libslic3r/PrintConfig.cpp:1554 msgid "" "Enable ironing of the top layers with the hot print head for smooth surface" msgstr "" "Sta strijken van de toplagen toe met het hete hotend voor een gladder " "oppervlak" -#: src/libslic3r/PrintConfig.cpp:1561 src/libslic3r/PrintConfig.cpp:1563 +#: src/libslic3r/PrintConfig.cpp:1560 src/libslic3r/PrintConfig.cpp:1562 msgid "Ironing Type" msgstr "Strijktype" -#: src/libslic3r/PrintConfig.cpp:1568 +#: src/libslic3r/PrintConfig.cpp:1567 msgid "All top surfaces" msgstr "Alle bovenvlakken" -#: src/libslic3r/PrintConfig.cpp:1569 +#: src/libslic3r/PrintConfig.cpp:1568 msgid "Topmost surface only" msgstr "Alleen bovenste vlak" -#: src/libslic3r/PrintConfig.cpp:1570 +#: src/libslic3r/PrintConfig.cpp:1569 msgid "All solid surfaces" msgstr "Alle dichte vlakken" -#: src/libslic3r/PrintConfig.cpp:1575 +#: src/libslic3r/PrintConfig.cpp:1574 msgid "Flow rate" msgstr "Debiet" -#: src/libslic3r/PrintConfig.cpp:1577 +#: src/libslic3r/PrintConfig.cpp:1576 msgid "Percent of a flow rate relative to object's normal layer height." msgstr "" "Percentage van het debiet ten opzichte van de standaard laagdikte van het " "model." -#: src/libslic3r/PrintConfig.cpp:1585 +#: src/libslic3r/PrintConfig.cpp:1584 msgid "Spacing between ironing passes" msgstr "Ruimte tussen strijkpassages" -#: src/libslic3r/PrintConfig.cpp:1587 +#: src/libslic3r/PrintConfig.cpp:1586 msgid "Distance between ironing lines" msgstr "Afstand tussen strijkpaden" -#: src/libslic3r/PrintConfig.cpp:1604 +#: src/libslic3r/PrintConfig.cpp:1603 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 " @@ -12514,11 +12578,11 @@ msgstr "" "beweging en voor de extruder naar het volgende punt beweegt. Hier kunt u " "variabelen gebruiken voor alle instellingen zoals 'layer_num' en 'layer_z'." -#: src/libslic3r/PrintConfig.cpp:1615 +#: src/libslic3r/PrintConfig.cpp:1614 msgid "Supports remaining times" msgstr "Ondersteunt resterende tijd" -#: src/libslic3r/PrintConfig.cpp:1616 +#: src/libslic3r/PrintConfig.cpp:1615 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. " @@ -12530,155 +12594,155 @@ msgstr "" "nu herkent de Prusa i3 MK3 de M73-commando's. Ook ondersteunt de i3 MK3 " "firmware M73 Qxx Sxx voor de stille modus." -#: src/libslic3r/PrintConfig.cpp:1624 +#: src/libslic3r/PrintConfig.cpp:1623 msgid "Supports stealth mode" msgstr "Ondersteunt stille modus" -#: src/libslic3r/PrintConfig.cpp:1625 +#: src/libslic3r/PrintConfig.cpp:1624 msgid "The firmware supports stealth mode" msgstr "De firmware ondersteunt stille modus" -#: src/libslic3r/PrintConfig.cpp:1630 +#: src/libslic3r/PrintConfig.cpp:1629 msgid "How to apply limits" msgstr "Hoe limieten toe te voegen" -#: src/libslic3r/PrintConfig.cpp:1631 +#: src/libslic3r/PrintConfig.cpp:1630 msgid "Purpose of Machine Limits" msgstr "Doel van de machinelimieten" -#: src/libslic3r/PrintConfig.cpp:1633 +#: src/libslic3r/PrintConfig.cpp:1632 msgid "How to apply the Machine Limits" msgstr "Hoe machinelimieten toe te voegen" -#: src/libslic3r/PrintConfig.cpp:1638 +#: src/libslic3r/PrintConfig.cpp:1637 msgid "Emit to G-code" msgstr "Invoegen in de G-code" -#: src/libslic3r/PrintConfig.cpp:1639 +#: src/libslic3r/PrintConfig.cpp:1638 msgid "Use for time estimate" msgstr "Gebruik om tijd te schatten" -#: src/libslic3r/PrintConfig.cpp:1640 +#: src/libslic3r/PrintConfig.cpp:1639 msgid "Ignore" msgstr "Negeren" -#: src/libslic3r/PrintConfig.cpp:1663 +#: src/libslic3r/PrintConfig.cpp:1662 msgid "Maximum feedrate X" msgstr "Maximale snelheid van de X-as" -#: src/libslic3r/PrintConfig.cpp:1664 +#: src/libslic3r/PrintConfig.cpp:1663 msgid "Maximum feedrate Y" msgstr "Maximale snelheid van de Y-as" -#: src/libslic3r/PrintConfig.cpp:1665 +#: src/libslic3r/PrintConfig.cpp:1664 msgid "Maximum feedrate Z" msgstr "Maximale snelheid van de Z-as" -#: src/libslic3r/PrintConfig.cpp:1666 +#: src/libslic3r/PrintConfig.cpp:1665 msgid "Maximum feedrate E" msgstr "Maximale extrusiesnelheid" -#: src/libslic3r/PrintConfig.cpp:1669 +#: src/libslic3r/PrintConfig.cpp:1668 msgid "Maximum feedrate of the X axis" msgstr "Maximale snelheid van de X-as" -#: src/libslic3r/PrintConfig.cpp:1670 +#: src/libslic3r/PrintConfig.cpp:1669 msgid "Maximum feedrate of the Y axis" msgstr "Maximale snelheid van de Y-as" -#: src/libslic3r/PrintConfig.cpp:1671 +#: src/libslic3r/PrintConfig.cpp:1670 msgid "Maximum feedrate of the Z axis" msgstr "Maximale snelheid van de Z-as" -#: src/libslic3r/PrintConfig.cpp:1672 +#: src/libslic3r/PrintConfig.cpp:1671 msgid "Maximum feedrate of the E axis" msgstr "Maximale extrusiesnelheid" -#: src/libslic3r/PrintConfig.cpp:1680 +#: src/libslic3r/PrintConfig.cpp:1679 msgid "Maximum acceleration X" msgstr "Maximale acceleratie X" -#: src/libslic3r/PrintConfig.cpp:1681 +#: src/libslic3r/PrintConfig.cpp:1680 msgid "Maximum acceleration Y" msgstr "Maximale acceleratie Y" -#: src/libslic3r/PrintConfig.cpp:1682 +#: src/libslic3r/PrintConfig.cpp:1681 msgid "Maximum acceleration Z" msgstr "Maximale acceleratie Z" -#: src/libslic3r/PrintConfig.cpp:1683 +#: src/libslic3r/PrintConfig.cpp:1682 msgid "Maximum acceleration E" msgstr "Maximale acceleratie E" -#: src/libslic3r/PrintConfig.cpp:1686 +#: src/libslic3r/PrintConfig.cpp:1685 msgid "Maximum acceleration of the X axis" msgstr "Maximale acceleratie van de X-as" -#: src/libslic3r/PrintConfig.cpp:1687 +#: src/libslic3r/PrintConfig.cpp:1686 msgid "Maximum acceleration of the Y axis" msgstr "Maximale acceleratie van de Y-as" -#: src/libslic3r/PrintConfig.cpp:1688 +#: src/libslic3r/PrintConfig.cpp:1687 msgid "Maximum acceleration of the Z axis" msgstr "Maximale acceleratie van de Z-as" -#: src/libslic3r/PrintConfig.cpp:1689 +#: src/libslic3r/PrintConfig.cpp:1688 msgid "Maximum acceleration of the E axis" msgstr "Maximale extrusie-acceleratie" -#: src/libslic3r/PrintConfig.cpp:1697 +#: src/libslic3r/PrintConfig.cpp:1696 msgid "Maximum jerk X" msgstr "Maximale ruk X" -#: src/libslic3r/PrintConfig.cpp:1698 +#: src/libslic3r/PrintConfig.cpp:1697 msgid "Maximum jerk Y" msgstr "Maximale ruk Y" -#: src/libslic3r/PrintConfig.cpp:1699 +#: src/libslic3r/PrintConfig.cpp:1698 msgid "Maximum jerk Z" msgstr "Maximale ruk Z" -#: src/libslic3r/PrintConfig.cpp:1700 +#: src/libslic3r/PrintConfig.cpp:1699 msgid "Maximum jerk E" msgstr "Maximale ruk E" -#: src/libslic3r/PrintConfig.cpp:1703 +#: src/libslic3r/PrintConfig.cpp:1702 msgid "Maximum jerk of the X axis" msgstr "Maximale ruk van de X-as" -#: src/libslic3r/PrintConfig.cpp:1704 +#: src/libslic3r/PrintConfig.cpp:1703 msgid "Maximum jerk of the Y axis" msgstr "Maximale ruk van de Y-as" -#: src/libslic3r/PrintConfig.cpp:1705 +#: src/libslic3r/PrintConfig.cpp:1704 msgid "Maximum jerk of the Z axis" msgstr "Maximale ruk van de Z-as" -#: src/libslic3r/PrintConfig.cpp:1706 +#: src/libslic3r/PrintConfig.cpp:1705 msgid "Maximum jerk of the E axis" msgstr "Maximale extrusie-ruk" -#: src/libslic3r/PrintConfig.cpp:1716 +#: src/libslic3r/PrintConfig.cpp:1715 msgid "Minimum feedrate when extruding" msgstr "Minimale snelheid tijdens extruderen" -#: src/libslic3r/PrintConfig.cpp:1718 +#: src/libslic3r/PrintConfig.cpp:1717 msgid "Minimum feedrate when extruding (M205 S)" msgstr "Minimale snelheid tijdens extruderen (M205 S)" -#: src/libslic3r/PrintConfig.cpp:1726 +#: src/libslic3r/PrintConfig.cpp:1725 msgid "Minimum travel feedrate" msgstr "Minimale snelheid voor bewegingen" -#: src/libslic3r/PrintConfig.cpp:1728 +#: src/libslic3r/PrintConfig.cpp:1727 msgid "Minimum travel feedrate (M205 T)" msgstr "Minimale snelheid voor bewegingen (M205 T)" -#: src/libslic3r/PrintConfig.cpp:1736 +#: src/libslic3r/PrintConfig.cpp:1735 msgid "Maximum acceleration when extruding" msgstr "Maximale acceleratie tijdens extruderen" -#: src/libslic3r/PrintConfig.cpp:1738 +#: src/libslic3r/PrintConfig.cpp:1737 msgid "" "Maximum acceleration when extruding (M204 P)\n" "\n" @@ -12690,31 +12754,31 @@ msgstr "" "Marlin (legacy) firmware gebruikt deze ook voor bewegingsacceleratie (M204 " "T)." -#: src/libslic3r/PrintConfig.cpp:1749 +#: src/libslic3r/PrintConfig.cpp:1748 msgid "Maximum acceleration when retracting" msgstr "Maximale acceleratie tijdens retracten" -#: src/libslic3r/PrintConfig.cpp:1751 +#: src/libslic3r/PrintConfig.cpp:1750 msgid "Maximum acceleration when retracting (M204 R)" msgstr "Maximale acceleratie tijdens retracten (M204 R)" -#: src/libslic3r/PrintConfig.cpp:1759 +#: src/libslic3r/PrintConfig.cpp:1758 msgid "Maximum acceleration for travel moves" msgstr "Maximale acceleratie voor bewegingen" -#: src/libslic3r/PrintConfig.cpp:1761 +#: src/libslic3r/PrintConfig.cpp:1760 msgid "Maximum acceleration for travel moves (M204 T)" msgstr "Maximale acceleratie voor bewegingen (M204 T)" -#: src/libslic3r/PrintConfig.cpp:1768 src/libslic3r/PrintConfig.cpp:1777 +#: src/libslic3r/PrintConfig.cpp:1767 src/libslic3r/PrintConfig.cpp:1776 msgid "Max" msgstr "Max" -#: src/libslic3r/PrintConfig.cpp:1769 +#: src/libslic3r/PrintConfig.cpp:1768 msgid "This setting represents the maximum speed of your fan." msgstr "Deze instelling gaat over de maximale snelheid van uw ventilator." -#: src/libslic3r/PrintConfig.cpp:1778 +#: src/libslic3r/PrintConfig.cpp:1777 msgid "" "This is the highest printable layer height for this extruder, used to cap " "the variable layer height and support layer height. Maximum recommended " @@ -12726,11 +12790,11 @@ msgstr "" "75% van de extrusiebreedte voor een goede interfacehechting. Als dit op 0 " "staat, wordt de hoogte gelimiteerd tot 75% van de nozzlediameter." -#: src/libslic3r/PrintConfig.cpp:1788 +#: src/libslic3r/PrintConfig.cpp:1787 msgid "Max print speed" msgstr "Maximale printsnelheid" -#: src/libslic3r/PrintConfig.cpp:1789 +#: src/libslic3r/PrintConfig.cpp:1788 msgid "" "When setting other speed settings to 0 Slic3r will autocalculate the optimal " "speed in order to keep constant extruder pressure. This experimental setting " @@ -12741,7 +12805,7 @@ msgstr "" "experimentele instelling wordt gebruikt voor de hoogste printsnelheid die u " "toestaat." -#: src/libslic3r/PrintConfig.cpp:1799 +#: src/libslic3r/PrintConfig.cpp:1798 msgid "" "This experimental setting is used to set the maximum volumetric speed your " "extruder supports." @@ -12749,11 +12813,11 @@ msgstr "" "Deze experimentele instelling wordt gebruikt voor de maximale volumetrische " "snelheid van de extruder." -#: src/libslic3r/PrintConfig.cpp:1807 +#: src/libslic3r/PrintConfig.cpp:1806 msgid "Max volumetric slope positive" msgstr "Maximale volumetrische stijging" -#: src/libslic3r/PrintConfig.cpp:1808 +#: src/libslic3r/PrintConfig.cpp:1807 msgid "" "This experimental setting is used to limit the speed of change in extrusion " "rate for a transition from lower speed to higher speed. A value of 1.8 mm³/" @@ -12761,16 +12825,21 @@ msgid "" "extrusion width, 0.2 mm extrusion height, feedrate 20 mm/s) to 5.4 mm³/s " "(feedrate 60 mm/s) will take at least 2 seconds." msgstr "" +"Deze experimentele instelling wordt gebruikt om de extrusiesnelheidsratio te " +"limiteren voor een transitie van lage tot hoge snelheid. Een waarde van 1,8 " +"mm³/s² verzekert dat een wijziging in extrusieratio van 1,8 mm³/s (0,45 mm " +"extrusiebreedte, 0,2 mm laagdikte, voedingssnelheid 20 mm/s) naar 5,4 mm³/s " +"(voedingssnelheid 60 mm/s) tenminste 2 seconden duurt." -#: src/libslic3r/PrintConfig.cpp:1813 src/libslic3r/PrintConfig.cpp:1825 +#: src/libslic3r/PrintConfig.cpp:1812 src/libslic3r/PrintConfig.cpp:1824 msgid "mm³/s²" msgstr "mm³/s²" -#: src/libslic3r/PrintConfig.cpp:1819 +#: src/libslic3r/PrintConfig.cpp:1818 msgid "Max volumetric slope negative" msgstr "Maximale volumetrische daling" -#: src/libslic3r/PrintConfig.cpp:1820 +#: src/libslic3r/PrintConfig.cpp:1819 msgid "" "This experimental setting is used to limit the speed of change in extrusion " "rate for a transition from higher speed to lower speed. A value of 1.8 mm³/" @@ -12778,18 +12847,23 @@ msgid "" "extrusion width, 0.2 mm extrusion height, feedrate 60 mm/s) to 1.8 mm³/s " "(feedrate 20 mm/s) will take at least 2 seconds." msgstr "" +"Deze experimentele instelling wordt gebruikt om de extrusiesnelheidsratio te " +"limiteren voor een transitie van hoge tot lage snelheid. Een waarde van 1,8 " +"mm³/s² verzekert dat een wijziging in extrusieratio van 5,4 mm³/s (0,45 mm " +"extrusiebreedte, 0,2 mm laagdikte, voedingssnelheid 60 mm/s) naar 1,8 mm³/s " +"(voedingssnelheid 20 mm/s) tenminste 2 seconden duurt." -#: src/libslic3r/PrintConfig.cpp:1831 src/libslic3r/PrintConfig.cpp:1840 +#: src/libslic3r/PrintConfig.cpp:1830 src/libslic3r/PrintConfig.cpp:1839 msgid "Min" msgstr "Min" -#: src/libslic3r/PrintConfig.cpp:1832 +#: src/libslic3r/PrintConfig.cpp:1831 msgid "This setting represents the minimum PWM your fan needs to work." msgstr "" "Deze instelling geeft de minimale snelheid van uw ventilator aan waarbij de " "ventilator draait." -#: src/libslic3r/PrintConfig.cpp:1841 +#: src/libslic3r/PrintConfig.cpp:1840 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 " @@ -12799,20 +12873,20 @@ msgstr "" "resolutie voor variabele laagdikte. Typische waarden zijn tussen 0,05 en 0,1 " "mm." -#: src/libslic3r/PrintConfig.cpp:1849 +#: src/libslic3r/PrintConfig.cpp:1848 msgid "Min print speed" msgstr "Minimale printsnelheid" -#: src/libslic3r/PrintConfig.cpp:1850 +#: src/libslic3r/PrintConfig.cpp:1849 msgid "Slic3r will not scale speed down below this speed." msgstr "" "PrusaSlicer zal de printsnelheid niet verlagen tot onder deze snelheid." -#: src/libslic3r/PrintConfig.cpp:1857 +#: src/libslic3r/PrintConfig.cpp:1856 msgid "Minimal filament extrusion length" msgstr "Minimale extrusielengte" -#: src/libslic3r/PrintConfig.cpp:1858 +#: src/libslic3r/PrintConfig.cpp:1857 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 " @@ -12822,11 +12896,11 @@ msgstr "" "hoeveelheid filament op de eerste laag te verbruiken. Voor multi-" "extruderprinters is dit het minimum voor elke extruder." -#: src/libslic3r/PrintConfig.cpp:1867 +#: src/libslic3r/PrintConfig.cpp:1866 msgid "Configuration notes" msgstr "Configuratie-opmerkingen" -#: src/libslic3r/PrintConfig.cpp:1868 +#: src/libslic3r/PrintConfig.cpp:1867 msgid "" "You can put here your personal notes. This text will be added to the G-code " "header comments." @@ -12834,28 +12908,28 @@ msgstr "" "Hier kunt u eigen opmerkingen plaatsen. Deze tekst wordt bovenin de G-code " "toegevoegd." -#: src/libslic3r/PrintConfig.cpp:1878 +#: src/libslic3r/PrintConfig.cpp:1877 msgid "" "This is the diameter of your extruder nozzle (for example: 0.5, 0.35 etc.)" msgstr "Dit is de diameter van uw extruder-nozzle (bijvoorbeeld 0.4)" -#: src/libslic3r/PrintConfig.cpp:1883 +#: src/libslic3r/PrintConfig.cpp:1882 msgid "Host Type" msgstr "Hosttype" -#: src/libslic3r/PrintConfig.cpp:1884 +#: src/libslic3r/PrintConfig.cpp:1883 msgid "" "Slic3r can upload G-code files to a printer host. This field must contain " "the kind of the host." msgstr "" -"PrusaSlicer kan gcode-bestanden uploaden naar een printerhost. Dit veld moet " -"het type host bevatten." +"PrusaSlicer kan .gcode-bestanden uploaden naar een printerhost. Dit veld " +"moet het type host bevatten." -#: src/libslic3r/PrintConfig.cpp:1906 +#: src/libslic3r/PrintConfig.cpp:1905 msgid "Only retract when crossing perimeters" msgstr "Alleen retracten bij kruisende perimeters" -#: src/libslic3r/PrintConfig.cpp:1907 +#: src/libslic3r/PrintConfig.cpp:1906 msgid "" "Disables retraction when the travel path does not exceed the upper layer's " "perimeters (and thus any ooze will be probably invisible)." @@ -12863,7 +12937,7 @@ msgstr "" "Schakelt retracten uit als de bewegingspaden de perimeters van de bovenste " "laag niet overschrijdt (en maakt eventueel druipen dus onzichtbaar)." -#: src/libslic3r/PrintConfig.cpp:1914 +#: src/libslic3r/PrintConfig.cpp:1913 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 " @@ -12873,11 +12947,11 @@ msgstr "" "voorkomen. Het staat een smalle skirt automatisch toe en beweegt extruders " "buiten zo'n skirt als de temperatuur verandert." -#: src/libslic3r/PrintConfig.cpp:1921 +#: src/libslic3r/PrintConfig.cpp:1920 msgid "Output filename format" msgstr "Formaat van bestandsnaam" -#: src/libslic3r/PrintConfig.cpp:1922 +#: src/libslic3r/PrintConfig.cpp:1921 msgid "" "You can use all configuration options as variables inside this template. For " "example: [layer_height], [fill_density] etc. You can also use [timestamp], " @@ -12889,11 +12963,11 @@ msgstr "" "'year', 'month', 'day', 'hour', 'minute', 'second', 'version', " "'input_filename', 'input_filename_base', etc." -#: src/libslic3r/PrintConfig.cpp:1931 +#: src/libslic3r/PrintConfig.cpp:1930 msgid "Detect bridging perimeters" msgstr "Detecteer brugperimeters" -#: src/libslic3r/PrintConfig.cpp:1933 +#: src/libslic3r/PrintConfig.cpp:1932 msgid "" "Experimental option to adjust flow for overhangs (bridge flow will be used), " "to apply bridge speed to them and enable fan." @@ -12901,11 +12975,11 @@ msgstr "" "Experimentele optie om het debiet voor overhanging aan te passen. Het debiet " "voor bruggen wordt aangehouden, evenals de printsnelheid en de koeling." -#: src/libslic3r/PrintConfig.cpp:1939 +#: src/libslic3r/PrintConfig.cpp:1938 msgid "Filament parking position" msgstr "Filament parkeerpositie" -#: src/libslic3r/PrintConfig.cpp:1940 +#: src/libslic3r/PrintConfig.cpp:1939 msgid "" "Distance of the extruder tip from the position where the filament is parked " "when unloaded. This should match the value in printer firmware." @@ -12914,11 +12988,11 @@ msgstr "" "wanneer dat niet geladen is. Deze moet overeenkomen met de waarde in de " "firmware." -#: src/libslic3r/PrintConfig.cpp:1948 +#: src/libslic3r/PrintConfig.cpp:1947 msgid "Extra loading distance" msgstr "Extra laadafstand" -#: src/libslic3r/PrintConfig.cpp:1949 +#: src/libslic3r/PrintConfig.cpp:1948 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 " @@ -12930,12 +13004,12 @@ msgstr "" "teruggetrokken wordt. Als de waarde positief is, zal het verder geladen " "worden. Als het negatief is, is de laadafstand dus korter." -#: src/libslic3r/PrintConfig.cpp:1957 src/libslic3r/PrintConfig.cpp:1974 -#: src/libslic3r/PrintConfig.cpp:1988 src/libslic3r/PrintConfig.cpp:1998 +#: src/libslic3r/PrintConfig.cpp:1956 src/libslic3r/PrintConfig.cpp:1973 +#: src/libslic3r/PrintConfig.cpp:1987 src/libslic3r/PrintConfig.cpp:1997 msgid "Perimeters" msgstr "Perimeters" -#: src/libslic3r/PrintConfig.cpp:1958 +#: src/libslic3r/PrintConfig.cpp:1957 msgid "" "This is the acceleration your printer will use for perimeters. Set zero to " "disable acceleration control for perimeters." @@ -12943,17 +13017,17 @@ msgstr "" "Deze acceleratie zal uw printer gebruiken voor de perimeters. Als dit is " "ingesteld op 0, wordt de acceleratiecontrole uitgeschakeld." -#: src/libslic3r/PrintConfig.cpp:1965 +#: src/libslic3r/PrintConfig.cpp:1964 msgid "Perimeter extruder" msgstr "Perimeterextruder" -#: src/libslic3r/PrintConfig.cpp:1967 +#: src/libslic3r/PrintConfig.cpp:1966 msgid "" "The extruder to use when printing perimeters and brim. First extruder is 1." msgstr "" "De extruder die gebruikt wordt voor het printen van perimeters en de brim." -#: src/libslic3r/PrintConfig.cpp:1976 +#: src/libslic3r/PrintConfig.cpp:1975 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 " @@ -12967,14 +13041,14 @@ msgstr "" "nozzlediameter. Als dit is uitgedrukt als percentage, wordt dit berekend " "over de laagdikte." -#: src/libslic3r/PrintConfig.cpp:1990 +#: src/libslic3r/PrintConfig.cpp:1989 msgid "" "Speed for perimeters (contours, aka vertical shells). Set to zero for auto." msgstr "" "Printsnelheid voor de perimeters (contouren, ook wel bekend als verticale " "shells). Als dit ingesteld is op 0, wordt een automatische snelheid genomen." -#: src/libslic3r/PrintConfig.cpp:2000 +#: src/libslic3r/PrintConfig.cpp:1999 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 " @@ -12986,11 +13060,11 @@ msgstr "" "een hoger aantal perimeters als de optie voor extra perimeters is " "ingeschakeld." -#: src/libslic3r/PrintConfig.cpp:2004 +#: src/libslic3r/PrintConfig.cpp:2003 msgid "(minimum)" msgstr "(minimum)" -#: src/libslic3r/PrintConfig.cpp:2012 +#: src/libslic3r/PrintConfig.cpp:2011 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. " @@ -13000,38 +13074,38 @@ msgid "" msgstr "" "Als u de output-G-code via custom scripts wilt verwerken, hoeft u alleen de " "paden hier te plaatsen. Scheid meerdere scripts met een puntkomma. Scripts " -"krijgen als eerste argument het pad naar het gcode-bestand. Ze hebben ook " +"krijgen als eerste argument het pad naar het .gcode-bestand. Ze hebben ook " "toegang tot de configuratie-instellingen door het lezen van variabelen." -#: src/libslic3r/PrintConfig.cpp:2024 +#: src/libslic3r/PrintConfig.cpp:2023 msgid "Printer type" msgstr "Printertype" -#: src/libslic3r/PrintConfig.cpp:2025 +#: src/libslic3r/PrintConfig.cpp:2024 msgid "Type of the printer." msgstr "Type van de printer." -#: src/libslic3r/PrintConfig.cpp:2030 +#: src/libslic3r/PrintConfig.cpp:2029 msgid "Printer notes" msgstr "Printeropmerkingen" -#: src/libslic3r/PrintConfig.cpp:2031 +#: src/libslic3r/PrintConfig.cpp:2030 msgid "You can put your notes regarding the printer here." msgstr "Hier kunnen opmerkingen over de printer geplaatst worden." -#: src/libslic3r/PrintConfig.cpp:2039 +#: src/libslic3r/PrintConfig.cpp:2038 msgid "Printer vendor" msgstr "Printerleverancier" -#: src/libslic3r/PrintConfig.cpp:2040 +#: src/libslic3r/PrintConfig.cpp:2039 msgid "Name of the printer vendor." msgstr "Naam van de printerleverancier." -#: src/libslic3r/PrintConfig.cpp:2045 +#: src/libslic3r/PrintConfig.cpp:2044 msgid "Printer variant" msgstr "Printervariant" -#: src/libslic3r/PrintConfig.cpp:2046 +#: src/libslic3r/PrintConfig.cpp:2045 msgid "" "Name of the printer variant. For example, the printer variants may be " "differentiated by a nozzle diameter." @@ -13039,38 +13113,38 @@ msgstr "" "Naam van de printervariant. De nozzlediameter kan bijvoorbeeld afwijken voor " "verschillende varianten." -#: src/libslic3r/PrintConfig.cpp:2063 +#: src/libslic3r/PrintConfig.cpp:2062 msgid "Raft contact Z distance" msgstr "Z-afstand voor raft" -#: src/libslic3r/PrintConfig.cpp:2065 +#: src/libslic3r/PrintConfig.cpp:2064 msgid "" "The vertical distance between object and raft. Ignored for soluble interface." msgstr "" "De verticale afstand tussen object en raft. Wordt genegeerd bij oplosbare " "interface." -#: src/libslic3r/PrintConfig.cpp:2072 +#: src/libslic3r/PrintConfig.cpp:2071 msgid "Raft expansion" msgstr "Raftuitbreiding" -#: src/libslic3r/PrintConfig.cpp:2074 +#: src/libslic3r/PrintConfig.cpp:2073 msgid "Expansion of the raft in XY plane for better stability." msgstr "Uitbreiding van de raft in het XY-vlak voor betere stabiliteit." -#: src/libslic3r/PrintConfig.cpp:2081 +#: src/libslic3r/PrintConfig.cpp:2080 msgid "First layer density" msgstr "Dichtheid eerste laag" -#: src/libslic3r/PrintConfig.cpp:2083 +#: src/libslic3r/PrintConfig.cpp:2082 msgid "Density of the first raft or support layer." msgstr "Dichtheid van de eerste raft- of supportlaag." -#: src/libslic3r/PrintConfig.cpp:2091 +#: src/libslic3r/PrintConfig.cpp:2090 msgid "First layer expansion" msgstr "Uitbreiding van eerste laag" -#: src/libslic3r/PrintConfig.cpp:2093 +#: src/libslic3r/PrintConfig.cpp:2092 msgid "" "Expansion of the first raft or support layer to improve adhesion to print " "bed." @@ -13078,11 +13152,11 @@ msgstr "" "Uitbreiding van de eerste raft- of supportlaag voor verbetering van de " "bedhechting." -#: src/libslic3r/PrintConfig.cpp:2100 +#: src/libslic3r/PrintConfig.cpp:2099 msgid "Raft layers" msgstr "Raftlagen" -#: src/libslic3r/PrintConfig.cpp:2102 +#: src/libslic3r/PrintConfig.cpp:2101 msgid "" "The object will be raised by this number of layers, and support material " "will be generated under it." @@ -13090,11 +13164,11 @@ msgstr "" "Het object wordt verhoogd met dit aantal lagen. Support wordt onder het " "object gegenereerd." -#: src/libslic3r/PrintConfig.cpp:2110 +#: src/libslic3r/PrintConfig.cpp:2109 msgid "Slice resolution" msgstr "Slice-resolutie" -#: src/libslic3r/PrintConfig.cpp:2111 +#: src/libslic3r/PrintConfig.cpp:2110 msgid "" "Minimum detail resolution, used to simplify the input file for speeding up " "the slicing job and reducing memory usage. High-resolution models often " @@ -13106,11 +13180,11 @@ msgstr "" "een hoge resolutie vragen meer van een printer dan mogelijk. Als dit " "ingesteld is op 0, wordt simplificatie uitgeschakeld." -#: src/libslic3r/PrintConfig.cpp:2121 +#: src/libslic3r/PrintConfig.cpp:2120 msgid "G-code resolution" msgstr "G-code-resolutie" -#: src/libslic3r/PrintConfig.cpp:2122 +#: src/libslic3r/PrintConfig.cpp:2121 msgid "" "Maximum deviation of exported G-code paths from their full resolution " "counterparts. Very high resolution G-code requires huge amount of RAM to " @@ -13128,22 +13202,22 @@ msgstr "" "reductie is toegepast per laag, kan dit zorgen voor oneffenheden tijdens het " "printen." -#: src/libslic3r/PrintConfig.cpp:2133 +#: src/libslic3r/PrintConfig.cpp:2132 msgid "Minimum travel after retraction" msgstr "Minimale beweging na retracten" -#: src/libslic3r/PrintConfig.cpp:2134 +#: src/libslic3r/PrintConfig.cpp:2133 msgid "" "Retraction is not triggered when travel moves are shorter than this length." msgstr "" "Retracten is niet geactiveerd als bewegingen korter zijn dan de hier " "ingevoerde lengte." -#: src/libslic3r/PrintConfig.cpp:2140 +#: src/libslic3r/PrintConfig.cpp:2139 msgid "Retract amount before wipe" msgstr "Retracthoeveelheid voor het afvegen" -#: src/libslic3r/PrintConfig.cpp:2141 +#: src/libslic3r/PrintConfig.cpp:2140 msgid "" "With bowden extruders, it may be wise to do some amount of quick retract " "before doing the wipe movement." @@ -13151,23 +13225,23 @@ msgstr "" "Met bowden-extruders is het verstandig om een aantal maal snel te retracten " "voor het afvegen." -#: src/libslic3r/PrintConfig.cpp:2148 +#: src/libslic3r/PrintConfig.cpp:2147 msgid "Retract on layer change" msgstr "Retracten bij laagwisselingen" -#: src/libslic3r/PrintConfig.cpp:2149 +#: src/libslic3r/PrintConfig.cpp:2148 msgid "This flag enforces a retraction whenever a Z move is done." msgstr "Dit vinkje geeft aan of wordt teruggetrokken bij een Z-beweging." -#: src/libslic3r/PrintConfig.cpp:2154 src/libslic3r/PrintConfig.cpp:2162 +#: src/libslic3r/PrintConfig.cpp:2153 src/libslic3r/PrintConfig.cpp:2161 msgid "Length" msgstr "Lengte" -#: src/libslic3r/PrintConfig.cpp:2155 +#: src/libslic3r/PrintConfig.cpp:2154 msgid "Retraction Length" msgstr "Retractielengte" -#: src/libslic3r/PrintConfig.cpp:2156 +#: src/libslic3r/PrintConfig.cpp:2155 msgid "" "When retraction is triggered, filament is pulled back by the specified " "amount (the length is measured on raw filament, before it enters the " @@ -13176,11 +13250,11 @@ msgstr "" "Als retracten is geactiveerd, wordt filament teruggetrokken op de ingestelde " "waarde (filamentlengte voor het de extruder in gaat)." -#: src/libslic3r/PrintConfig.cpp:2163 +#: src/libslic3r/PrintConfig.cpp:2162 msgid "Retraction Length (Toolchange)" msgstr "Retractielengte (toolwissel)" -#: src/libslic3r/PrintConfig.cpp:2164 +#: src/libslic3r/PrintConfig.cpp:2163 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 " @@ -13190,11 +13264,11 @@ msgstr "" "teruggetrokken op de ingestelde waarde (filamentlengte voor het de extruder " "in gaat)." -#: src/libslic3r/PrintConfig.cpp:2172 +#: src/libslic3r/PrintConfig.cpp:2171 msgid "Lift Z" msgstr "Beweeg Z omhoog" -#: src/libslic3r/PrintConfig.cpp:2173 +#: src/libslic3r/PrintConfig.cpp:2172 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 " @@ -13204,15 +13278,15 @@ msgstr "" "enigszins omhoog bij het retracten. Als meerdere extruders worden gebruikt, " "wordt alleen de instelling van de eerste extruder aangehouden." -#: src/libslic3r/PrintConfig.cpp:2180 +#: src/libslic3r/PrintConfig.cpp:2179 msgid "Above Z" msgstr "Boven Z" -#: src/libslic3r/PrintConfig.cpp:2181 +#: src/libslic3r/PrintConfig.cpp:2180 msgid "Only lift Z above" msgstr "Beweeg Z alleen omhoog boven" -#: src/libslic3r/PrintConfig.cpp:2182 +#: src/libslic3r/PrintConfig.cpp:2181 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 " @@ -13222,15 +13296,15 @@ msgstr "" "ingestelde waarde omhoog bewegen voor het retracten. Deze kan aangepast " "worden om warping te voorkomen bij de eerste lagen." -#: src/libslic3r/PrintConfig.cpp:2189 +#: src/libslic3r/PrintConfig.cpp:2188 msgid "Below Z" msgstr "Onder Z" -#: src/libslic3r/PrintConfig.cpp:2190 +#: src/libslic3r/PrintConfig.cpp:2189 msgid "Only lift Z below" msgstr "Beweeg Z alleen omhoog onder" -#: src/libslic3r/PrintConfig.cpp:2191 +#: src/libslic3r/PrintConfig.cpp:2190 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 " @@ -13239,11 +13313,11 @@ msgstr "" "Als dit ingesteld is op een positieve waarde, zal de nozzle alleen onder de " "ingestelde waarde omhoog bewegen bij het retracten." -#: src/libslic3r/PrintConfig.cpp:2199 src/libslic3r/PrintConfig.cpp:2207 +#: src/libslic3r/PrintConfig.cpp:2198 src/libslic3r/PrintConfig.cpp:2206 msgid "Extra length on restart" msgstr "Extra lengte bij herstart" -#: src/libslic3r/PrintConfig.cpp:2200 +#: src/libslic3r/PrintConfig.cpp:2199 msgid "" "When the retraction is compensated after the travel move, the extruder will " "push this additional amount of filament. This setting is rarely needed." @@ -13251,7 +13325,7 @@ msgstr "" "Als retracten wordt gecompenseerd na een beweging, wordt deze extra " "hoeveelheid filament geëxtrudeerd. Deze instelling is zelden van toepassing." -#: src/libslic3r/PrintConfig.cpp:2208 +#: src/libslic3r/PrintConfig.cpp:2207 msgid "" "When the retraction is compensated after changing tool, the extruder will " "push this additional amount of filament." @@ -13259,19 +13333,19 @@ msgstr "" "Als retracten wordt gecompenseerd na een toolwisseling, wordt deze extra " "hoeveelheid filament geëxtrudeerd." -#: src/libslic3r/PrintConfig.cpp:2215 src/libslic3r/PrintConfig.cpp:2216 +#: src/libslic3r/PrintConfig.cpp:2214 src/libslic3r/PrintConfig.cpp:2215 msgid "Retraction Speed" msgstr "Retractiesnelheid" -#: src/libslic3r/PrintConfig.cpp:2217 +#: src/libslic3r/PrintConfig.cpp:2216 msgid "The speed for retractions (it only applies to the extruder motor)." msgstr "De snelheid voor retracties (geldt alleen voor de extrudermotor)." -#: src/libslic3r/PrintConfig.cpp:2223 src/libslic3r/PrintConfig.cpp:2224 +#: src/libslic3r/PrintConfig.cpp:2222 src/libslic3r/PrintConfig.cpp:2223 msgid "Deretraction Speed" msgstr "Deretractiesnelheid" -#: src/libslic3r/PrintConfig.cpp:2225 +#: src/libslic3r/PrintConfig.cpp:2224 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 " @@ -13281,74 +13355,74 @@ msgstr "" "voor de extrudermotor). Als dit ingesteld is op 0, wordt de " "retractiesnelheid gebruikt." -#: src/libslic3r/PrintConfig.cpp:2232 +#: src/libslic3r/PrintConfig.cpp:2231 msgid "Seam position" msgstr "Naadpositie" -#: src/libslic3r/PrintConfig.cpp:2234 +#: src/libslic3r/PrintConfig.cpp:2233 msgid "Position of perimeters starting points." msgstr "Startpuntpositie van perimeters." -#: src/libslic3r/PrintConfig.cpp:2240 +#: src/libslic3r/PrintConfig.cpp:2239 msgid "Random" msgstr "Willekeurig" -#: src/libslic3r/PrintConfig.cpp:2241 +#: src/libslic3r/PrintConfig.cpp:2240 msgid "Nearest" msgstr "Dichtstbijzijnd" -#: src/libslic3r/PrintConfig.cpp:2242 +#: src/libslic3r/PrintConfig.cpp:2241 msgid "Aligned" msgstr "Uitgelijnd" -#: src/libslic3r/PrintConfig.cpp:2250 +#: src/libslic3r/PrintConfig.cpp:2249 msgid "Direction" msgstr "Richting" -#: src/libslic3r/PrintConfig.cpp:2252 +#: src/libslic3r/PrintConfig.cpp:2251 msgid "Preferred direction of the seam" msgstr "Richtingsvoorkeur voor de naad" -#: src/libslic3r/PrintConfig.cpp:2253 +#: src/libslic3r/PrintConfig.cpp:2252 msgid "Seam preferred direction" msgstr "Richtingsvoorkeur voor de naad" -#: src/libslic3r/PrintConfig.cpp:2260 +#: src/libslic3r/PrintConfig.cpp:2259 msgid "Jitter" msgstr "Jitter" -#: src/libslic3r/PrintConfig.cpp:2262 +#: src/libslic3r/PrintConfig.cpp:2261 msgid "Seam preferred direction jitter" msgstr "Voorkeursrichting voor de naad - jitter" -#: src/libslic3r/PrintConfig.cpp:2263 +#: src/libslic3r/PrintConfig.cpp:2262 msgid "Preferred direction of the seam - jitter" msgstr "Voorkeursrichting voor de naad - jitter" -#: src/libslic3r/PrintConfig.cpp:2270 +#: src/libslic3r/PrintConfig.cpp:2269 msgid "Distance from brim/object" msgstr "Afstand van brim en object" -#: src/libslic3r/PrintConfig.cpp:2271 +#: src/libslic3r/PrintConfig.cpp:2270 msgid "" "Distance between skirt and brim (when draft shield is not used) or objects." msgstr "" "Afstand tussen de skirt en de brim of objecten (wanneer tochtscherm niet " "wordt gebruikt)." -#: src/libslic3r/PrintConfig.cpp:2277 +#: src/libslic3r/PrintConfig.cpp:2276 msgid "Skirt height" msgstr "Skirthoogte" -#: src/libslic3r/PrintConfig.cpp:2278 +#: src/libslic3r/PrintConfig.cpp:2277 msgid "Height of skirt expressed in layers." msgstr "Hoogte van de skirt uitgedrukt in het aantal lagen." -#: src/libslic3r/PrintConfig.cpp:2284 +#: src/libslic3r/PrintConfig.cpp:2283 msgid "Draft shield" msgstr "Tochtscherm" -#: src/libslic3r/PrintConfig.cpp:2285 +#: src/libslic3r/PrintConfig.cpp:2284 msgid "" "With draft shield active, the skirt will be printed skirt_distance from the " "object, possibly intersecting brim.\n" @@ -13364,27 +13438,27 @@ msgstr "" "Dit is handig om een ABS of ASA print te beschermen tegen opkrullen en " "loslaten van het printbed door tocht." -#: src/libslic3r/PrintConfig.cpp:2293 +#: src/libslic3r/PrintConfig.cpp:2292 msgid "Disabled" msgstr "Uit" -#: src/libslic3r/PrintConfig.cpp:2294 +#: src/libslic3r/PrintConfig.cpp:2293 msgid "Limited" msgstr "Gelimiteerd" -#: src/libslic3r/PrintConfig.cpp:2295 +#: src/libslic3r/PrintConfig.cpp:2294 msgid "Enabled" msgstr "Aan" -#: src/libslic3r/PrintConfig.cpp:2300 +#: src/libslic3r/PrintConfig.cpp:2299 msgid "Loops (minimum)" msgstr "Rondgangen (minimaal)" -#: src/libslic3r/PrintConfig.cpp:2301 +#: src/libslic3r/PrintConfig.cpp:2300 msgid "Skirt Loops" msgstr "Rondgangen voor de skirt" -#: src/libslic3r/PrintConfig.cpp:2302 +#: src/libslic3r/PrintConfig.cpp:2301 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 " @@ -13394,11 +13468,11 @@ msgstr "" "ingesteld kan dit aantal rondgangen groter zijn dan hier is ingesteld. Als " "dit ingesteld is op 0, wordt de skirt uitgeschakeld." -#: src/libslic3r/PrintConfig.cpp:2310 +#: src/libslic3r/PrintConfig.cpp:2309 msgid "Slow down if layer print time is below" msgstr "Vertraag bij een kortere laagprinttijd dan" -#: src/libslic3r/PrintConfig.cpp:2311 +#: src/libslic3r/PrintConfig.cpp:2310 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." @@ -13406,11 +13480,11 @@ msgstr "" "Als de laagprinttijd wordt berekend onder dit aantal seconden, wordt de " "printsnelheid verlaagd om de laagprinttijd te verlengen." -#: src/libslic3r/PrintConfig.cpp:2320 +#: src/libslic3r/PrintConfig.cpp:2319 msgid "Small perimeters" msgstr "Smalle perimeters" -#: src/libslic3r/PrintConfig.cpp:2322 +#: src/libslic3r/PrintConfig.cpp:2321 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 " @@ -13421,11 +13495,11 @@ msgstr "" "wordt deze genomen over de snelheid van de perimeters. Als dit ingesteld is " "op 0, wordt een automatische snelheid genomen." -#: src/libslic3r/PrintConfig.cpp:2332 +#: src/libslic3r/PrintConfig.cpp:2331 msgid "Solid infill threshold area" msgstr "Dichte vulling bij oppervlak" -#: src/libslic3r/PrintConfig.cpp:2334 +#: src/libslic3r/PrintConfig.cpp:2333 msgid "" "Force solid infill for regions having a smaller area than the specified " "threshold." @@ -13433,23 +13507,23 @@ msgstr "" "Forceer dichte vulling voor delen met een kleiner doorsnee-oppervlak dan de " "hier ingestelde waarde." -#: src/libslic3r/PrintConfig.cpp:2335 +#: src/libslic3r/PrintConfig.cpp:2334 msgid "mm²" msgstr "mm²" -#: src/libslic3r/PrintConfig.cpp:2341 +#: src/libslic3r/PrintConfig.cpp:2340 msgid "Solid infill extruder" msgstr "Extruder voor dichte vulling" -#: src/libslic3r/PrintConfig.cpp:2343 +#: src/libslic3r/PrintConfig.cpp:2342 msgid "The extruder to use when printing solid infill." msgstr "De extruder die gebruikt wordt voor het printen van dichte vullingen." -#: src/libslic3r/PrintConfig.cpp:2349 +#: src/libslic3r/PrintConfig.cpp:2348 msgid "Solid infill every" msgstr "Dichte vulling elke" -#: src/libslic3r/PrintConfig.cpp:2351 +#: src/libslic3r/PrintConfig.cpp:2350 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 " @@ -13461,7 +13535,7 @@ msgstr "" "waarde; PrusaSlicer zal dan automatisch het maximaal aantal lagen kiezen om " "te combineren op basis van de nozzlediameter en de laagdikte." -#: src/libslic3r/PrintConfig.cpp:2363 +#: src/libslic3r/PrintConfig.cpp:2362 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, " @@ -13473,7 +13547,7 @@ msgstr "" "breedte instellen op 1,125x de nozzlediameter. Als dit is uitgedrukt als " "percentage, wordt dit berekend over de laagdikte." -#: src/libslic3r/PrintConfig.cpp:2375 +#: src/libslic3r/PrintConfig.cpp:2374 msgid "" "Speed for printing solid regions (top/bottom/internal horizontal shells). " "This can be expressed as a percentage (for example: 80%) over the default " @@ -13483,19 +13557,19 @@ msgstr "" "dit berekend over de standaard vullingssnelheid. Als dit ingesteld is op 0, " "worden automatische waarden genomen." -#: src/libslic3r/PrintConfig.cpp:2387 +#: src/libslic3r/PrintConfig.cpp:2386 msgid "Number of solid layers to generate on top and bottom surfaces." msgstr "Aantal te genereren dichte lagen voor boven- en ondervlakken." -#: src/libslic3r/PrintConfig.cpp:2393 src/libslic3r/PrintConfig.cpp:2394 +#: src/libslic3r/PrintConfig.cpp:2392 src/libslic3r/PrintConfig.cpp:2393 msgid "Minimum thickness of a top / bottom shell" msgstr "Minimale dikte van top-/bodemshell" -#: src/libslic3r/PrintConfig.cpp:2400 +#: src/libslic3r/PrintConfig.cpp:2399 msgid "Spiral vase" msgstr "Spiraalmodus" -#: src/libslic3r/PrintConfig.cpp:2401 +#: src/libslic3r/PrintConfig.cpp:2400 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, " @@ -13510,11 +13584,11 @@ msgstr "" "skirt- en brimrondgangen. Het werkt niet bij het printen van meer dan één " "object." -#: src/libslic3r/PrintConfig.cpp:2409 +#: src/libslic3r/PrintConfig.cpp:2408 msgid "Temperature variation" msgstr "Temperatuurverschil" -#: src/libslic3r/PrintConfig.cpp:2410 +#: src/libslic3r/PrintConfig.cpp:2409 msgid "" "Temperature difference to be applied when an extruder is not active. Enables " "a full-height \"sacrificial\" skirt on which the nozzles are periodically " @@ -13523,7 +13597,7 @@ msgstr "" "Temperatuurverschil dat wordt toegepast als een extruder niet actief is. Dit " "genereert een afveegblok waarop de nozzle wordt schoongeveegd." -#: src/libslic3r/PrintConfig.cpp:2420 +#: src/libslic3r/PrintConfig.cpp:2419 msgid "" "This start procedure is inserted at the beginning, after bed has reached the " "target temperature and extruder just started heating, and before extruder " @@ -13541,7 +13615,7 @@ msgstr "" "andere aangepaste acties aan te passen. Merk op dat u voor alle PrusaSlicer-" "instellingen variabelen kunt gebruiken." -#: src/libslic3r/PrintConfig.cpp:2435 +#: src/libslic3r/PrintConfig.cpp:2434 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 " @@ -13564,47 +13638,47 @@ msgstr "" "meerdere extruders hebt, wordt de G-code in de volgorde van de extruders " "verwerkt." -#: src/libslic3r/PrintConfig.cpp:2451 +#: src/libslic3r/PrintConfig.cpp:2450 msgid "Color change G-code" msgstr "Kleurwissel-G-code" -#: src/libslic3r/PrintConfig.cpp:2452 +#: src/libslic3r/PrintConfig.cpp:2451 msgid "This G-code will be used as a code for the color change" msgstr "Deze G-code wordt gebruikt voor een kleurwisseling" -#: src/libslic3r/PrintConfig.cpp:2461 +#: src/libslic3r/PrintConfig.cpp:2460 msgid "This G-code will be used as a code for the pause print" msgstr "Deze G-code wordt gebruikt bij het pauzeren van de print" -#: src/libslic3r/PrintConfig.cpp:2470 +#: src/libslic3r/PrintConfig.cpp:2469 msgid "This G-code will be used as a custom code" msgstr "Deze G-code wordt gebruikt als custom G-code" -#: src/libslic3r/PrintConfig.cpp:2478 +#: src/libslic3r/PrintConfig.cpp:2477 msgid "Single Extruder Multi Material" msgstr "Multi-material met één extruder" -#: src/libslic3r/PrintConfig.cpp:2479 +#: src/libslic3r/PrintConfig.cpp:2478 msgid "The printer multiplexes filaments into a single hot end." msgstr "De printer mengt filament in een enkele extruder." -#: src/libslic3r/PrintConfig.cpp:2484 +#: src/libslic3r/PrintConfig.cpp:2483 msgid "Prime all printing extruders" msgstr "Veeg alle printextruders af" -#: src/libslic3r/PrintConfig.cpp:2485 +#: src/libslic3r/PrintConfig.cpp:2484 msgid "" "If enabled, all printing extruders will be primed at the front edge of the " "print bed at the start of the print." msgstr "" "Alle extruders worden afgeveegd aan de voorzijde van het printbed aan het " -"begin van de print als dit aanstaat." +"begin van de print als dit is ingeschakeld." -#: src/libslic3r/PrintConfig.cpp:2490 +#: src/libslic3r/PrintConfig.cpp:2489 msgid "No sparse layers (EXPERIMENTAL)" msgstr "Geen smalle lagen (experimenteel)" -#: src/libslic3r/PrintConfig.cpp:2491 +#: src/libslic3r/PrintConfig.cpp:2490 msgid "" "If enabled, the wipe tower will not be printed on layers with no " "toolchanges. On layers with a toolchange, extruder will travel downward to " @@ -13616,11 +13690,11 @@ msgstr "" "bewegen naar het afveegblok. De gebruiker is verantwoordelijk voor eventuele " "botsingen met de print." -#: src/libslic3r/PrintConfig.cpp:2498 +#: src/libslic3r/PrintConfig.cpp:2497 msgid "Slice gap closing radius" msgstr "Gatvulradius" -#: src/libslic3r/PrintConfig.cpp:2500 +#: src/libslic3r/PrintConfig.cpp:2499 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 " @@ -13630,11 +13704,11 @@ msgstr "" "het slicen. Het vullen kan zorgen dat de printresolutie minder wordt. Daarom " "wordt geadviseerd de waarde laag te houden." -#: src/libslic3r/PrintConfig.cpp:2508 +#: src/libslic3r/PrintConfig.cpp:2507 msgid "Slicing Mode" msgstr "Slicemodus" -#: src/libslic3r/PrintConfig.cpp:2510 +#: src/libslic3r/PrintConfig.cpp:2509 msgid "" "Use \"Even-odd\" for 3DLabPrint airplane models. Use \"Close holes\" to " "close all holes in the model." @@ -13642,31 +13716,31 @@ msgstr "" "Gebruik \"even-oneven\" voor 3DLabPrint vliegtuigmodellen. Gebruik \"Sluit " "gaten\" om alle gaten in het model te vullen." -#: src/libslic3r/PrintConfig.cpp:2515 +#: src/libslic3r/PrintConfig.cpp:2514 msgid "Regular" msgstr "Normaal" -#: src/libslic3r/PrintConfig.cpp:2516 +#: src/libslic3r/PrintConfig.cpp:2515 msgid "Even-odd" msgstr "Even-oneven" -#: src/libslic3r/PrintConfig.cpp:2517 +#: src/libslic3r/PrintConfig.cpp:2516 msgid "Close holes" msgstr "Sluit gaten" -#: src/libslic3r/PrintConfig.cpp:2522 +#: src/libslic3r/PrintConfig.cpp:2521 msgid "Generate support material" msgstr "Genereer support" -#: src/libslic3r/PrintConfig.cpp:2524 +#: src/libslic3r/PrintConfig.cpp:2523 msgid "Enable support material generation." msgstr "Sta de generatie van support toe." -#: src/libslic3r/PrintConfig.cpp:2528 +#: src/libslic3r/PrintConfig.cpp:2527 msgid "Auto generated supports" msgstr "Automatisch gegenereerd support" -#: src/libslic3r/PrintConfig.cpp:2530 +#: src/libslic3r/PrintConfig.cpp:2529 msgid "" "If checked, supports will be generated automatically based on the overhang " "threshold value. If unchecked, supports will be generated inside the " @@ -13675,11 +13749,11 @@ msgstr "" "Support wordt automatisch gegenereerd als dit aan staat. Als dit niet " "aanstaat zal support alleen bij supportforceringen gegenereerd worden." -#: src/libslic3r/PrintConfig.cpp:2536 +#: src/libslic3r/PrintConfig.cpp:2535 msgid "XY separation between an object and its support" msgstr "Horizontale ruimte tussen het object en het support" -#: src/libslic3r/PrintConfig.cpp:2538 +#: src/libslic3r/PrintConfig.cpp:2537 msgid "" "XY separation between an object and its support. If expressed as percentage " "(for example 50%), it will be calculated over external perimeter width." @@ -13687,17 +13761,17 @@ msgstr "" "Horizontale ruimte tussen object en support. Als dit is uitgedrukt als " "percentage, wordt deze berekend over de breedte van de buitenste perimeter." -#: src/libslic3r/PrintConfig.cpp:2549 +#: src/libslic3r/PrintConfig.cpp:2548 msgid "Pattern angle" msgstr "Patroonhoek" -#: src/libslic3r/PrintConfig.cpp:2551 +#: src/libslic3r/PrintConfig.cpp:2550 msgid "" "Use this setting to rotate the support material pattern on the horizontal " "plane." msgstr "Gebruik deze instelling om het patroon van het support te draaien." -#: src/libslic3r/PrintConfig.cpp:2561 src/libslic3r/PrintConfig.cpp:3616 +#: src/libslic3r/PrintConfig.cpp:2560 src/libslic3r/PrintConfig.cpp:3615 msgid "" "Only create support if it lies on a build plate. Don't create support on a " "print." @@ -13705,11 +13779,11 @@ msgstr "" "Genereer alleen support als dit op het bed geplaatst wordt, dus niet op de " "print zelf." -#: src/libslic3r/PrintConfig.cpp:2567 +#: src/libslic3r/PrintConfig.cpp:2566 msgid "Top contact Z distance" msgstr "Z-afstand aan de bovenkant" -#: src/libslic3r/PrintConfig.cpp:2569 +#: src/libslic3r/PrintConfig.cpp:2568 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 " @@ -13719,23 +13793,23 @@ msgstr "" "PrusaSlicer bruginstellingen gebruikt voor de eerste laag boven de " "supportinterface." -#: src/libslic3r/PrintConfig.cpp:2577 +#: src/libslic3r/PrintConfig.cpp:2576 msgid "0 (soluble)" msgstr "0 (oplosbaar)" -#: src/libslic3r/PrintConfig.cpp:2578 +#: src/libslic3r/PrintConfig.cpp:2577 msgid "0.1 (detachable)" msgstr "0,1 (losbreekbaar)" -#: src/libslic3r/PrintConfig.cpp:2579 +#: src/libslic3r/PrintConfig.cpp:2578 msgid "0.2 (detachable)" msgstr "0,2 (losbreekbaar)" -#: src/libslic3r/PrintConfig.cpp:2585 +#: src/libslic3r/PrintConfig.cpp:2584 msgid "Bottom contact Z distance" msgstr "Z-afstand aan de onderkant" -#: src/libslic3r/PrintConfig.cpp:2587 +#: src/libslic3r/PrintConfig.cpp:2586 msgid "" "The vertical distance between the object top surface and the support " "material interface. If set to zero, support_material_contact_distance will " @@ -13747,15 +13821,15 @@ msgstr "" #. TRN To be shown in Print Settings "Bottom contact Z distance". Have to be as short as possible #. TRN To be shown in Print Settings "Bottom interface layers". Have to be as short as possible -#: src/libslic3r/PrintConfig.cpp:2595 src/libslic3r/PrintConfig.cpp:2680 +#: src/libslic3r/PrintConfig.cpp:2594 src/libslic3r/PrintConfig.cpp:2679 msgid "Same as top" msgstr "Zelfde als bovenkant" -#: src/libslic3r/PrintConfig.cpp:2602 +#: src/libslic3r/PrintConfig.cpp:2601 msgid "Enforce support for the first" msgstr "Forceer support voor de eerste" -#: src/libslic3r/PrintConfig.cpp:2604 +#: src/libslic3r/PrintConfig.cpp:2603 msgid "" "Generate support material for the specified number of layers counting from " "bottom, regardless of whether normal support material is enabled or not and " @@ -13767,15 +13841,15 @@ msgstr "" "waarbij de ingesteld hoek wordt aangehouden. Dit is handig om meer hechting " "op het bed te verkrijgen bij objecten met een klein contactoppervlak." -#: src/libslic3r/PrintConfig.cpp:2609 +#: src/libslic3r/PrintConfig.cpp:2608 msgid "Enforce support for the first n layers" msgstr "Forceer support voor de eerste n lagen" -#: src/libslic3r/PrintConfig.cpp:2615 +#: src/libslic3r/PrintConfig.cpp:2614 msgid "Support material/raft/skirt extruder" msgstr "Extruder voor support/raft/skirt" -#: src/libslic3r/PrintConfig.cpp:2617 +#: src/libslic3r/PrintConfig.cpp:2616 msgid "" "The extruder to use when printing support material, raft and skirt (1+, 0 to " "use the current extruder to minimize tool changes)." @@ -13783,7 +13857,7 @@ msgstr "" "De extruder die gebruikt wordt voor support, raft en skirt (stel in op 1 of " "op 0 om de huidige extruder te gebruiken)." -#: src/libslic3r/PrintConfig.cpp:2626 +#: src/libslic3r/PrintConfig.cpp:2625 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, " @@ -13795,22 +13869,22 @@ msgstr "" "zelf bepalen op basis van de nozzlediameter. Als dit is uitgedrukt als " "percentage, wordt dit berekend over de laagdikte." -#: src/libslic3r/PrintConfig.cpp:2636 +#: src/libslic3r/PrintConfig.cpp:2635 msgid "Interface loops" msgstr "Interface rondgangen" -#: src/libslic3r/PrintConfig.cpp:2638 +#: src/libslic3r/PrintConfig.cpp:2637 msgid "" "Cover the top contact layer of the supports with loops. Disabled by default." msgstr "" "Bedek de bovenste interfacelagen van het support met rondgangen. Dit staat " "standaard uit." -#: src/libslic3r/PrintConfig.cpp:2643 +#: src/libslic3r/PrintConfig.cpp:2642 msgid "Support material/raft interface extruder" msgstr "Extruder voor supportinterfacce en de bovenlaag van de raft" -#: src/libslic3r/PrintConfig.cpp:2645 +#: src/libslic3r/PrintConfig.cpp:2644 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." @@ -13819,37 +13893,37 @@ msgstr "" "dan 1 of op 0 om de huidige extruder te gebruiken voor minder " "toolwisselingen). Dit heeft ook effect op de raft." -#: src/libslic3r/PrintConfig.cpp:2653 +#: src/libslic3r/PrintConfig.cpp:2652 msgid "Top interface layers" msgstr "Interfacelagen bovenkant" -#: src/libslic3r/PrintConfig.cpp:2655 +#: src/libslic3r/PrintConfig.cpp:2654 msgid "" "Number of interface layers to insert between the object(s) and support " "material." msgstr "Aantal interfacelagen tussen het support en het object." -#: src/libslic3r/PrintConfig.cpp:2662 +#: src/libslic3r/PrintConfig.cpp:2661 msgid "0 (off)" msgstr "0 (uit)" -#: src/libslic3r/PrintConfig.cpp:2663 +#: src/libslic3r/PrintConfig.cpp:2662 msgid "1 (light)" msgstr "1 (licht)" -#: src/libslic3r/PrintConfig.cpp:2664 +#: src/libslic3r/PrintConfig.cpp:2663 msgid "2 (default)" msgstr "2 (standaard)" -#: src/libslic3r/PrintConfig.cpp:2665 +#: src/libslic3r/PrintConfig.cpp:2664 msgid "3 (heavy)" msgstr "3 (zwaar)" -#: src/libslic3r/PrintConfig.cpp:2671 +#: src/libslic3r/PrintConfig.cpp:2670 msgid "Bottom interface layers" msgstr "Interfacelagen onderkant" -#: src/libslic3r/PrintConfig.cpp:2673 +#: src/libslic3r/PrintConfig.cpp:2672 msgid "" "Number of interface layers to insert between the object(s) and support " "material. Set to -1 to use support_material_interface_layers" @@ -13857,11 +13931,11 @@ msgstr "" "Het aantal interfacelagen tussen de objecten en het supportmateriaal. Stel " "in op -1 om evenveel lagen als op bovenkant te gebruiken" -#: src/libslic3r/PrintConfig.cpp:2686 +#: src/libslic3r/PrintConfig.cpp:2685 msgid "Closing radius" msgstr "Sluitradius" -#: src/libslic3r/PrintConfig.cpp:2688 +#: src/libslic3r/PrintConfig.cpp:2687 msgid "" "For snug supports, the support regions will be merged using morphological " "closing operation. Gaps smaller than the closing radius will be filled in." @@ -13869,17 +13943,17 @@ msgstr "" "Voor handvaste supports worden supportdelen samengevoegd met een " "morfologische sluitmethode. Gaten kleiner dan de sluitradius worden gevuld." -#: src/libslic3r/PrintConfig.cpp:2696 +#: src/libslic3r/PrintConfig.cpp:2695 msgid "Interface pattern spacing" msgstr "Tussenafstand voor interface" -#: src/libslic3r/PrintConfig.cpp:2698 +#: src/libslic3r/PrintConfig.cpp:2697 msgid "Spacing between interface lines. Set zero to get a solid interface." msgstr "" "Ruimte tussen lijnen van supportinterface. Als dit ingesteld is op 0, wordt " "een dichte supportinterface gegenereerd." -#: src/libslic3r/PrintConfig.cpp:2707 +#: src/libslic3r/PrintConfig.cpp:2706 msgid "" "Speed for printing support material interface layers. If expressed as " "percentage (for example 50%) it will be calculated over support material " @@ -13888,23 +13962,23 @@ msgstr "" "Printsnelheid van supportinterfacelagen. Als dit is uitgedrukt als " "percentage, wordt dit berekend over de snelheid van het support." -#: src/libslic3r/PrintConfig.cpp:2716 +#: src/libslic3r/PrintConfig.cpp:2715 msgid "Pattern" msgstr "Patroon" -#: src/libslic3r/PrintConfig.cpp:2718 +#: src/libslic3r/PrintConfig.cpp:2717 msgid "Pattern used to generate support material." msgstr "Patroon dat gebruikt wordt voor het support." -#: src/libslic3r/PrintConfig.cpp:2724 +#: src/libslic3r/PrintConfig.cpp:2723 msgid "Rectilinear grid" msgstr "Rechtlijnig raster" -#: src/libslic3r/PrintConfig.cpp:2730 +#: src/libslic3r/PrintConfig.cpp:2729 msgid "Interface pattern" msgstr "Interfacepatroon" -#: src/libslic3r/PrintConfig.cpp:2732 +#: src/libslic3r/PrintConfig.cpp:2731 msgid "" "Pattern used to generate support material interface. Default pattern for non-" "soluble support interface is Rectilinear, while default pattern for soluble " @@ -13914,23 +13988,23 @@ msgstr "" "niet-oplosbaar support is rechtlijnig, terwijl het patroon voor oplosbaar " "support concentrisch is." -#: src/libslic3r/PrintConfig.cpp:2746 +#: src/libslic3r/PrintConfig.cpp:2745 msgid "Pattern spacing" msgstr "Tussenafstand van het patroon" -#: src/libslic3r/PrintConfig.cpp:2748 +#: src/libslic3r/PrintConfig.cpp:2747 msgid "Spacing between support material lines." msgstr "Afstand tussen supportlijnen." -#: src/libslic3r/PrintConfig.cpp:2757 +#: src/libslic3r/PrintConfig.cpp:2756 msgid "Speed for printing support material." msgstr "Printsnelheid voor support." -#: src/libslic3r/PrintConfig.cpp:2764 +#: src/libslic3r/PrintConfig.cpp:2763 msgid "Style" msgstr "Type" -#: src/libslic3r/PrintConfig.cpp:2766 +#: src/libslic3r/PrintConfig.cpp:2765 msgid "" "Style and shape of the support towers. Projecting the supports into a " "regular grid will create more stable supports, while snug support towers " @@ -13940,15 +14014,15 @@ msgstr "" "regelmatig raster creëert stabielere supports, terwijl handvaste supports " "materiaal besparen en een lelijk oppervlak reduceert." -#: src/libslic3r/PrintConfig.cpp:2773 +#: src/libslic3r/PrintConfig.cpp:2772 msgid "Snug" msgstr "Handvast" -#: src/libslic3r/PrintConfig.cpp:2778 +#: src/libslic3r/PrintConfig.cpp:2777 msgid "Synchronize with object layers" msgstr "Synchroniseer met objectlagen" -#: src/libslic3r/PrintConfig.cpp:2780 +#: src/libslic3r/PrintConfig.cpp:2779 msgid "" "Synchronize support layers with the object print layers. This is useful with " "multi-material printers, where the extruder switch is expensive." @@ -13956,11 +14030,11 @@ msgstr "" "Synchroniseer de supportlagen met de objectlagen. Dit is handig voor multi-" "materialprinters waar een toolwissel duur is." -#: src/libslic3r/PrintConfig.cpp:2786 +#: src/libslic3r/PrintConfig.cpp:2785 msgid "Overhang threshold" msgstr "Maximale overhanghoek" -#: src/libslic3r/PrintConfig.cpp:2788 +#: src/libslic3r/PrintConfig.cpp:2787 msgid "" "Support material will not be generated for overhangs whose slope angle (90° " "= vertical) is above the given threshold. In other words, this value " @@ -13973,11 +14047,11 @@ msgstr "" "geprint moet worden met support. Als dit ingesteld is op 0, wordt dit " "automatisch gedetecteerd (aanbevolen)." -#: src/libslic3r/PrintConfig.cpp:2800 +#: src/libslic3r/PrintConfig.cpp:2799 msgid "With sheath around the support" msgstr "Met schild rond het support" -#: src/libslic3r/PrintConfig.cpp:2802 +#: src/libslic3r/PrintConfig.cpp:2801 msgid "" "Add a sheath (a single perimeter line) around the base support. This makes " "the support more reliable, but also more difficult to remove." @@ -13985,7 +14059,7 @@ msgstr "" "Voeg een schild (één perimeterlijn) rondom het support toe. Dit maakt het " "support betrouwbaarder maar ook moeilijker te verwijderen." -#: src/libslic3r/PrintConfig.cpp:2809 +#: src/libslic3r/PrintConfig.cpp:2808 msgid "" "Nozzle temperature for layers after the first one. Set this to zero to " "disable temperature control commands in the output G-code." @@ -13993,29 +14067,29 @@ msgstr "" "Nozzletemperatuur voor lagen na de eerste laag. Stel in op 0 om " "temperatuurregeling uit te zetten in de G-code." -#: src/libslic3r/PrintConfig.cpp:2812 +#: src/libslic3r/PrintConfig.cpp:2811 msgid "Nozzle temperature" msgstr "Nozzletemperatuur" -#: src/libslic3r/PrintConfig.cpp:2818 +#: src/libslic3r/PrintConfig.cpp:2817 msgid "Thick bridges" msgstr "Dikke bruggen" -#: src/libslic3r/PrintConfig.cpp:2820 +#: src/libslic3r/PrintConfig.cpp:2819 msgid "" "If enabled, bridges are more reliable, can bridge longer distances, but may " "look worse. If disabled, bridges look better but are reliable just for " "shorter bridged distances." msgstr "" -"Als dit aanstaat worden bruggen betrouwbaarder, kunnen langere bruggen " -"printen, maar er minder mooi uitzien. Als dit uitstaat zien bruggen er beter " -"uit, maar zijn alleen betrouwbaar over korte afstanden." +"Als dit is ingeschakeld worden bruggen betrouwbaarder, kunnen langere " +"bruggen printen, maar er minder mooi uitzien. Als dit uitstaat zien bruggen " +"er beter uit, maar zijn alleen betrouwbaar over korte afstanden." -#: src/libslic3r/PrintConfig.cpp:2826 +#: src/libslic3r/PrintConfig.cpp:2825 msgid "Detect thin walls" msgstr "Detecteer dunne wanden" -#: src/libslic3r/PrintConfig.cpp:2828 +#: src/libslic3r/PrintConfig.cpp:2827 msgid "" "Detect single-width walls (parts where two extrusions don't fit and we need " "to collapse them into a single trace)." @@ -14023,11 +14097,11 @@ msgstr "" "Detecteer éénlijnige wanden (delen waar 2 extrusielijnen niet passen en dit " "geprint moet worden met 1 lijn)." -#: src/libslic3r/PrintConfig.cpp:2834 +#: src/libslic3r/PrintConfig.cpp:2833 msgid "Threads" -msgstr "Meerdere processen" +msgstr "Processen" -#: src/libslic3r/PrintConfig.cpp:2835 +#: src/libslic3r/PrintConfig.cpp:2834 msgid "" "Threads are used to parallelize long-running tasks. Optimal threads number " "is slightly above the number of available cores/processors." @@ -14036,7 +14110,7 @@ msgstr "" "draaien. Het optimaal aantal processen is vlak boven het aanwezige aantal " "kernen/processoren." -#: src/libslic3r/PrintConfig.cpp:2847 +#: src/libslic3r/PrintConfig.cpp:2846 msgid "" "This custom code is inserted before every toolchange. Placeholder variables " "for all PrusaSlicer settings as well as {toolchange_z}, {previous_extruder} " @@ -14052,7 +14126,7 @@ msgstr "" "(zoals T{next_extruder}), zal PrusaSlicer deze verder negeren. Het is daarom " "mogelijk om een custom script toe te passen voor en na de toolwisseling." -#: src/libslic3r/PrintConfig.cpp:2860 +#: src/libslic3r/PrintConfig.cpp:2859 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 " @@ -14065,7 +14139,7 @@ msgstr "" "extrudaat in smalle gebieden voor een gladdere afwerking. Als dit is " "uitgedrukt als percentage, wordt dit berekend over de laagdikte." -#: src/libslic3r/PrintConfig.cpp:2873 +#: src/libslic3r/PrintConfig.cpp:2872 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 " @@ -14079,15 +14153,15 @@ msgstr "" "vullingssnelheid. Als dit ingesteld is op 0, wordt een automatische snelheid " "genomen." -#: src/libslic3r/PrintConfig.cpp:2888 +#: src/libslic3r/PrintConfig.cpp:2887 msgid "Number of solid layers to generate on top surfaces." msgstr "Aantal te genereren dichte lagen voor bovenvlakken." -#: src/libslic3r/PrintConfig.cpp:2889 +#: src/libslic3r/PrintConfig.cpp:2888 msgid "Top solid layers" msgstr "Bovenste dichte vulling" -#: src/libslic3r/PrintConfig.cpp:2897 +#: src/libslic3r/PrintConfig.cpp:2896 msgid "" "The number of top solid layers is increased above top_solid_layers if " "necessary to satisfy minimum thickness of top shell. This is useful to " @@ -14097,19 +14171,19 @@ msgstr "" "de minimale shelldikte te garanderen. Dit is handig om kussenvorming te " "voorkomen bij het printen met variabele laagdikte." -#: src/libslic3r/PrintConfig.cpp:2900 +#: src/libslic3r/PrintConfig.cpp:2899 msgid "Minimum top shell thickness" msgstr "Minimale shelldikte aan de bovenzijde" -#: src/libslic3r/PrintConfig.cpp:2907 +#: src/libslic3r/PrintConfig.cpp:2906 msgid "Speed for travel moves (jumps between distant extrusion points)." msgstr "Bewegingssnelheid als niet geëxtrudeerd wordt." -#: src/libslic3r/PrintConfig.cpp:2915 +#: src/libslic3r/PrintConfig.cpp:2914 msgid "Z travel" msgstr "Z-beweging" -#: src/libslic3r/PrintConfig.cpp:2916 +#: src/libslic3r/PrintConfig.cpp:2915 msgid "" "Speed for movements along the Z axis.\n" "When set to zero, the value is ignored and regular travel speed is used " @@ -14119,11 +14193,11 @@ msgstr "" "Als dit ingesteld is op 0, zal de waarde worden genegeerd en " "standaardwaarden worden gebruikt." -#: src/libslic3r/PrintConfig.cpp:2924 +#: src/libslic3r/PrintConfig.cpp:2923 msgid "Use firmware retraction" msgstr "Gebruik de firmware-retractie" -#: src/libslic3r/PrintConfig.cpp:2925 +#: src/libslic3r/PrintConfig.cpp:2924 msgid "" "This experimental setting uses G10 and G11 commands to have the firmware " "handle the retraction. This is only supported in recent Marlin." @@ -14132,11 +14206,11 @@ msgstr "" "retracten in de firmware. Dit wordt alleen ondersteunt bij de recente Marlin-" "variant." -#: src/libslic3r/PrintConfig.cpp:2931 +#: src/libslic3r/PrintConfig.cpp:2930 msgid "Use relative E distances" msgstr "Gebruik relatieve E-waarden" -#: src/libslic3r/PrintConfig.cpp:2932 +#: src/libslic3r/PrintConfig.cpp:2931 msgid "" "If your firmware requires relative E values, check this, otherwise leave it " "unchecked. Most firmwares use absolute values." @@ -14144,11 +14218,11 @@ msgstr "" "Als uw firmware relatieve extrusiewaarden nodig heeft, vink dit dan aan. " "Laat het ander uit staan. De meeste firmware gebruiken absolute waarden." -#: src/libslic3r/PrintConfig.cpp:2938 +#: src/libslic3r/PrintConfig.cpp:2937 msgid "Use volumetric E" msgstr "Gebruik volumetrische E-waarden" -#: src/libslic3r/PrintConfig.cpp:2939 +#: src/libslic3r/PrintConfig.cpp:2938 msgid "" "This experimental setting uses outputs the E values in cubic millimeters " "instead of linear millimeters. If your firmware doesn't already know " @@ -14165,11 +14239,11 @@ msgstr "" "filamentinstellingen. Dit wordt alleen ondersteund in de recente Marlin-" "variant." -#: src/libslic3r/PrintConfig.cpp:2949 +#: src/libslic3r/PrintConfig.cpp:2948 msgid "Enable variable layer height feature" msgstr "Variabele laagdikte toestaan" -#: src/libslic3r/PrintConfig.cpp:2950 +#: src/libslic3r/PrintConfig.cpp:2949 msgid "" "Some printers or printer setups may have difficulties printing with a " "variable layer height. Enabled by default." @@ -14177,11 +14251,11 @@ msgstr "" "Sommige printers of printersetups kunnen niet printen met een variabele " "laagdikte. Staat standaard aan." -#: src/libslic3r/PrintConfig.cpp:2956 +#: src/libslic3r/PrintConfig.cpp:2955 msgid "Wipe while retracting" msgstr "Veeg af bij het retracten" -#: src/libslic3r/PrintConfig.cpp:2957 +#: src/libslic3r/PrintConfig.cpp:2956 msgid "" "This flag will move the nozzle while retracting to minimize the possible " "blob on leaky extruders." @@ -14189,7 +14263,7 @@ msgstr "" "Als u dit aanvinkt beweegt de nozzle tijdens het retracten om een blob of " "lekkende extruders tegen te gaan." -#: src/libslic3r/PrintConfig.cpp:2964 +#: src/libslic3r/PrintConfig.cpp:2963 msgid "" "Multi material printers may need to prime or purge extruders on tool " "changes. Extrude the excess material into the wipe tower." @@ -14197,11 +14271,11 @@ msgstr "" "Multi-materialprinters moeten afvegen bij toolwisselingen. Extrudeer het " "overtollige materiaal op het afveegblok." -#: src/libslic3r/PrintConfig.cpp:2970 +#: src/libslic3r/PrintConfig.cpp:2969 msgid "Purging volumes - load/unload volumes" msgstr "Afveegvolume - laad/ontlaad volumes" -#: src/libslic3r/PrintConfig.cpp:2971 +#: src/libslic3r/PrintConfig.cpp:2970 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 " @@ -14212,11 +14286,11 @@ msgstr "" "het creëren van de onderstaande volledige reinigingsvolumes te " "vereenvoudigen." -#: src/libslic3r/PrintConfig.cpp:2977 +#: src/libslic3r/PrintConfig.cpp:2976 msgid "Purging volumes - matrix" msgstr "Afveegvolume - matrix" -#: src/libslic3r/PrintConfig.cpp:2978 +#: src/libslic3r/PrintConfig.cpp:2977 msgid "" "This matrix describes volumes (in cubic milimetres) required to purge the " "new filament on the wipe tower for any given pair of tools." @@ -14224,43 +14298,43 @@ msgstr "" "Deze matrix beschrijft volume (in mm³) dat is vereist om nieuw filament af " "te vegen aan het afveegblok voor elk paar van extruders." -#: src/libslic3r/PrintConfig.cpp:2987 +#: src/libslic3r/PrintConfig.cpp:2986 msgid "Position X" msgstr "X-positie" -#: src/libslic3r/PrintConfig.cpp:2988 +#: src/libslic3r/PrintConfig.cpp:2987 msgid "X coordinate of the left front corner of a wipe tower" msgstr "X-coördinaat van de linkervoorhoek van het afveegblok" -#: src/libslic3r/PrintConfig.cpp:2994 +#: src/libslic3r/PrintConfig.cpp:2993 msgid "Position Y" msgstr "Y-positie" -#: src/libslic3r/PrintConfig.cpp:2995 +#: src/libslic3r/PrintConfig.cpp:2994 msgid "Y coordinate of the left front corner of a wipe tower" msgstr "Y-coördinaat van de linkervoorhoek van het afveegblok" -#: src/libslic3r/PrintConfig.cpp:3002 +#: src/libslic3r/PrintConfig.cpp:3001 msgid "Width of a wipe tower" msgstr "Breedte van het afveegblok" -#: src/libslic3r/PrintConfig.cpp:3008 +#: src/libslic3r/PrintConfig.cpp:3007 msgid "Wipe tower rotation angle" msgstr "Rotatie van het afveegblok" -#: src/libslic3r/PrintConfig.cpp:3009 +#: src/libslic3r/PrintConfig.cpp:3008 msgid "Wipe tower rotation angle with respect to x-axis." msgstr "Rotatie van het afveegblok ten opzichte van de X-as." -#: src/libslic3r/PrintConfig.cpp:3015 src/libslic3r/PrintConfig.cpp:3016 +#: src/libslic3r/PrintConfig.cpp:3014 src/libslic3r/PrintConfig.cpp:3015 msgid "Wipe tower brim width" msgstr "Brimbreedte van het afveegblok" -#: src/libslic3r/PrintConfig.cpp:3024 +#: src/libslic3r/PrintConfig.cpp:3023 msgid "Wipe into this object's infill" msgstr "Afvegen in de vulling van het object" -#: src/libslic3r/PrintConfig.cpp:3025 +#: src/libslic3r/PrintConfig.cpp:3024 msgid "" "Purging after toolchange will be done inside this object's infills. This " "lowers the amount of waste but may result in longer print time due to " @@ -14270,11 +14344,11 @@ msgstr "" "reduceert de hoeveelheid afval, maar kan resulteren in langere printtijden " "door meer bewegingen." -#: src/libslic3r/PrintConfig.cpp:3032 +#: src/libslic3r/PrintConfig.cpp:3031 msgid "Wipe into this object" msgstr "Afvegen in dit object" -#: src/libslic3r/PrintConfig.cpp:3033 +#: src/libslic3r/PrintConfig.cpp:3032 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. " @@ -14284,19 +14358,19 @@ msgstr "" "materiaal dat anders in het afveegblok gebruikt wordt te besparen. Kleuren " "kunnen dan gemengd worden." -#: src/libslic3r/PrintConfig.cpp:3039 +#: src/libslic3r/PrintConfig.cpp:3038 msgid "Maximal bridging distance" msgstr "Maximale brugafstand" -#: src/libslic3r/PrintConfig.cpp:3040 +#: src/libslic3r/PrintConfig.cpp:3039 msgid "Maximal distance between supports on sparse infill sections." msgstr "Maximale afstand tussen support op dunne vullingsdelen." -#: src/libslic3r/PrintConfig.cpp:3046 +#: src/libslic3r/PrintConfig.cpp:3045 msgid "XY Size Compensation" msgstr "Compensatie voor X- en Y-grootte" -#: src/libslic3r/PrintConfig.cpp:3048 +#: src/libslic3r/PrintConfig.cpp:3047 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-" @@ -14306,11 +14380,11 @@ msgstr "" "waarde (negatief = naar binnen, positief = naar buiten). Dit kan handig zijn " "voor het verfijnen van gaten." -#: src/libslic3r/PrintConfig.cpp:3056 +#: src/libslic3r/PrintConfig.cpp:3055 msgid "Z offset" msgstr "Z-hoogte" -#: src/libslic3r/PrintConfig.cpp:3057 +#: src/libslic3r/PrintConfig.cpp:3056 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 " @@ -14322,43 +14396,51 @@ msgstr "" "eindstop bijvoorbeeld een waarde gebruikt die 0.3mm van het printbed is, kan " "dit ingesteld worden op -0.3mm." -#: src/libslic3r/PrintConfig.cpp:3066 +#: src/libslic3r/PrintConfig.cpp:3065 msgid "Perimeter generator" -msgstr "" +msgstr "Perimetergeneratie" -#: src/libslic3r/PrintConfig.cpp:3068 +#: src/libslic3r/PrintConfig.cpp:3067 msgid "" "Classic perimeter generator produces perimeters with constant extrusion " "width and for very thin areas is used gap-fill. Arachne engine produces " "perimeters with variable extrusion width. This setting also affects the " "Concentric infill." msgstr "" +"Klassieke perimetergeneratie produceert perimeters met constante " +"extrusiebreedte en gebruikt gatenvulling voor dunne stukken. Arachne " +"produceert perimeters met variabele extrusiebreedte. Deze instelling heeft " +"ook effect op concentrische vulling." + +#: src/libslic3r/PrintConfig.cpp:3074 +msgid "Classic" +msgstr "Klassiek" #: src/libslic3r/PrintConfig.cpp:3075 -msgid "Classic" -msgstr "" - -#: src/libslic3r/PrintConfig.cpp:3076 msgid "Arachne" -msgstr "" +msgstr "Arachne" -#: src/libslic3r/PrintConfig.cpp:3081 +#: src/libslic3r/PrintConfig.cpp:3080 msgid "Perimeter transition length" -msgstr "" +msgstr "Transitielengte voor perimeters" -#: src/libslic3r/PrintConfig.cpp:3083 +#: src/libslic3r/PrintConfig.cpp:3082 msgid "" "When transitioning between different numbers of perimeters as the part " "becomes thinner, a certain amount of space is allotted to split or join the " "perimeter segments. If expressed as a percentage (for example 100%), it will " "be computed based on the nozzle diameter." msgstr "" +"Bij de overgang naar een verschillend aantal perimeters bij dunnere diktes " +"wordt een bepaalde ruimte gebruikt om te splitten of samenvoegen van " +"perimetersegmenten. Als dit wordt uitgedrukt als percentage (bijvoorbeeld " +"100%), wordt deze berekend op basis van de nozzlediameter." -#: src/libslic3r/PrintConfig.cpp:3092 +#: src/libslic3r/PrintConfig.cpp:3091 msgid "Perimeter transitioning filter margin" -msgstr "" +msgstr "Marge voor transitielengte voor perimeters" -#: src/libslic3r/PrintConfig.cpp:3094 +#: src/libslic3r/PrintConfig.cpp:3093 msgid "" "Prevent transitioning back and forth between one extra perimeter and one " "less. This margin extends the range of extrusion widths which follow to " @@ -14369,12 +14451,19 @@ msgid "" "as a percentage (for example 25%), it will be computed based on the nozzle " "diameter." msgstr "" +"Voorkom transities tussen één en meerdere perimeters. Deze marge breidt het " +"bereik uit van de extrusiebreedte die volgt op [minimale perimeterbreedte - " +"marge, 2x minimale perimeterbreedte + marge]. Verhogen van deze marge " +"reduceert het aantal transities, wat het aantal terugtrekkingen verlaagt. " +"Hoewel, een hogere variatie van de extrusiebreedte kan leiden tot onder- of " +"overextrusie problemen. Als dit wordt uitgedrukt als percentage " +"(bijvoorbeeld 25%) wordt dit berekend op basis van de nozzlediameter." -#: src/libslic3r/PrintConfig.cpp:3107 +#: src/libslic3r/PrintConfig.cpp:3106 msgid "Perimeter transitioning threshold angle" -msgstr "" +msgstr "Transitiehoek voor perimeters" -#: src/libslic3r/PrintConfig.cpp:3109 +#: src/libslic3r/PrintConfig.cpp:3108 msgid "" "When to create transitions between even and odd numbers of perimeters. A " "wedge shape with an angle greater than this setting will not have " @@ -14382,23 +14471,31 @@ msgid "" "remaining space. Reducing this setting reduces the number and length of " "these center perimeters, but may leave gaps or overextrude." msgstr "" +"When to create transitions between even and odd numbers of perimeters. A " +"wedge shape with an angle greater than this setting will not have " +"transitions and no perimeters will be printed in the center to fill the " +"remaining space. Reducing this setting reduces the number and length of " +"these center perimeters, but may leave gaps or overextrude." -#: src/libslic3r/PrintConfig.cpp:3120 +#: src/libslic3r/PrintConfig.cpp:3119 msgid "Perimeter distribution count" -msgstr "" +msgstr "Perimeterdistributieaantal" -#: src/libslic3r/PrintConfig.cpp:3122 +#: src/libslic3r/PrintConfig.cpp:3121 msgid "" "The number of perimeters, counted from the center, over which the variation " "needs to be spread. Lower values mean that the outer perimeters don't change " "in width." msgstr "" +"Het aantal perimeters, geteld vanaf het midden waarover de variatie gespreid " +"wordt. Lagere waarde betekenen dat de buitenste perimeter niet in breedte " +"verandert." -#: src/libslic3r/PrintConfig.cpp:3129 +#: src/libslic3r/PrintConfig.cpp:3128 msgid "Minimum feature size" -msgstr "" +msgstr "Minimale objectgrootte" -#: src/libslic3r/PrintConfig.cpp:3131 +#: src/libslic3r/PrintConfig.cpp:3130 msgid "" "Minimum thickness of thin features. Model features that are thinner than " "this value will not be printed, while features thicker than the Minimum " @@ -14406,12 +14503,17 @@ msgid "" "a percentage (for example 25%), it will be computed based on the nozzle " "diameter." msgstr "" +"Minimale dikte van dunne delen. Delen van het model die dunner zijn dan deze " +"waarde worden niet geprint, terwijl delen van het model dikker dan de " +"minimale dikte van dunnen delen worden verbreed tot de minimale " +"perimeterbreedte. Als dit is uitgedrukt als percentage (bijvoorbeeld 25%), " +"wordt dit berekend op basis van de nozzlediameter." -#: src/libslic3r/PrintConfig.cpp:3141 +#: src/libslic3r/PrintConfig.cpp:3140 msgid "Minimum perimeter width" -msgstr "" +msgstr "Minimale perimeterbreedte" -#: src/libslic3r/PrintConfig.cpp:3143 +#: src/libslic3r/PrintConfig.cpp:3142 msgid "" "Width of the perimeter that will replace thin features (according to the " "Minimum feature size) of the model. If the Minimum perimeter width is " @@ -14419,64 +14521,69 @@ msgid "" "thick as the feature itself. If expressed as a percentage (for example 85%), " "it will be computed based on the nozzle diameter." msgstr "" +"Perimeterbreedte die dunne delen vervangt (volgens de minimale dikte van " +"dunne delen) van het model. Als die minimale perimeterbreedte dunner is dan " +"de dikte van de dunne delen, wordt de perimeter net zo dik als het de dunne " +"delen. Als dit is uitgedrukt als percentage (bijvoorbeeld 85%), dan wordt " +"dit berekend op basis van de nozzlediameter." -#: src/libslic3r/PrintConfig.cpp:3211 +#: src/libslic3r/PrintConfig.cpp:3210 msgid "Display width" msgstr "Schermbreedte" -#: src/libslic3r/PrintConfig.cpp:3212 +#: src/libslic3r/PrintConfig.cpp:3211 msgid "Width of the display" msgstr "Breedte van het scherm" -#: src/libslic3r/PrintConfig.cpp:3217 +#: src/libslic3r/PrintConfig.cpp:3216 msgid "Display height" msgstr "Schermhoogte" -#: src/libslic3r/PrintConfig.cpp:3218 +#: src/libslic3r/PrintConfig.cpp:3217 msgid "Height of the display" msgstr "Hoogte van het scherm" -#: src/libslic3r/PrintConfig.cpp:3223 +#: src/libslic3r/PrintConfig.cpp:3222 msgid "Number of pixels in" msgstr "Aantal pixels" -#: src/libslic3r/PrintConfig.cpp:3225 +#: src/libslic3r/PrintConfig.cpp:3224 msgid "Number of pixels in X" msgstr "Aantal pixels in de breedte" -#: src/libslic3r/PrintConfig.cpp:3231 +#: src/libslic3r/PrintConfig.cpp:3230 msgid "Number of pixels in Y" msgstr "Aantal pixels in de hoogte" -#: src/libslic3r/PrintConfig.cpp:3236 +#: src/libslic3r/PrintConfig.cpp:3235 msgid "Display horizontal mirroring" msgstr "Scherm horizontaal spiegelen" -#: src/libslic3r/PrintConfig.cpp:3237 +#: src/libslic3r/PrintConfig.cpp:3236 msgid "Mirror horizontally" msgstr "Spiegel horizontaal" -#: src/libslic3r/PrintConfig.cpp:3238 +#: src/libslic3r/PrintConfig.cpp:3237 msgid "Enable horizontal mirroring of output images" msgstr "Horizontaal spiegelen" -#: src/libslic3r/PrintConfig.cpp:3243 +#: src/libslic3r/PrintConfig.cpp:3242 msgid "Display vertical mirroring" msgstr "Scherm verticaal spiegelen" -#: src/libslic3r/PrintConfig.cpp:3244 +#: src/libslic3r/PrintConfig.cpp:3243 msgid "Mirror vertically" msgstr "Verticaal spiegelen" -#: src/libslic3r/PrintConfig.cpp:3245 +#: src/libslic3r/PrintConfig.cpp:3244 msgid "Enable vertical mirroring of output images" msgstr "Verticaal spiegelen" -#: src/libslic3r/PrintConfig.cpp:3250 +#: src/libslic3r/PrintConfig.cpp:3249 msgid "Display orientation" msgstr "Schermoriëntatie" -#: src/libslic3r/PrintConfig.cpp:3251 +#: src/libslic3r/PrintConfig.cpp:3250 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 " @@ -14486,55 +14593,55 @@ msgstr "" "Staande modus zal de breedte- en hoogteparameters omwisselen en de output " "wordt 90 graden gedraaid." -#: src/libslic3r/PrintConfig.cpp:3257 +#: src/libslic3r/PrintConfig.cpp:3256 msgid "Landscape" msgstr "Liggend" -#: src/libslic3r/PrintConfig.cpp:3258 +#: src/libslic3r/PrintConfig.cpp:3257 msgid "Portrait" msgstr "Staand" -#: src/libslic3r/PrintConfig.cpp:3263 src/libslic3r/PrintConfig.cpp:3898 +#: src/libslic3r/PrintConfig.cpp:3262 src/libslic3r/PrintConfig.cpp:3897 msgid "Fast" msgstr "Snel" -#: src/libslic3r/PrintConfig.cpp:3264 +#: src/libslic3r/PrintConfig.cpp:3263 msgid "Fast tilt" msgstr "Snelle draaiing" -#: src/libslic3r/PrintConfig.cpp:3265 +#: src/libslic3r/PrintConfig.cpp:3264 msgid "Time of the fast tilt" msgstr "Tijd van de snelle draaiing" -#: src/libslic3r/PrintConfig.cpp:3272 src/libslic3r/PrintConfig.cpp:3897 +#: src/libslic3r/PrintConfig.cpp:3271 src/libslic3r/PrintConfig.cpp:3896 msgid "Slow" msgstr "Langzaam" -#: src/libslic3r/PrintConfig.cpp:3273 +#: src/libslic3r/PrintConfig.cpp:3272 msgid "Slow tilt" msgstr "Langzaam draaien" -#: src/libslic3r/PrintConfig.cpp:3274 +#: src/libslic3r/PrintConfig.cpp:3273 msgid "Time of the slow tilt" msgstr "Tijd van de langzame draaiing" -#: src/libslic3r/PrintConfig.cpp:3281 src/libslic3r/PrintConfig.cpp:3899 +#: src/libslic3r/PrintConfig.cpp:3280 src/libslic3r/PrintConfig.cpp:3898 msgid "High viscosity" -msgstr "" +msgstr "Hoge viscositeit" + +#: src/libslic3r/PrintConfig.cpp:3281 +msgid "Tilt for high viscosity resin" +msgstr "Draaiing voor hoogvisceuze resin" #: src/libslic3r/PrintConfig.cpp:3282 -msgid "Tilt for high viscosity resin" -msgstr "" - -#: src/libslic3r/PrintConfig.cpp:3283 msgid "Time of the super slow tilt" -msgstr "" +msgstr "Tijd van de zeer langzame draaiing" -#: src/libslic3r/PrintConfig.cpp:3290 +#: src/libslic3r/PrintConfig.cpp:3289 msgid "Area fill" msgstr "Vulgebied" -#: src/libslic3r/PrintConfig.cpp:3291 +#: src/libslic3r/PrintConfig.cpp:3290 msgid "" "The percentage of the bed area. \n" "If the print area exceeds the specified value, \n" @@ -14544,40 +14651,40 @@ msgstr "" "Als het printgebied buiten een specifieke waarde valt \n" "wordt een korte draaiing gebruikt, anders een snelle" -#: src/libslic3r/PrintConfig.cpp:3298 src/libslic3r/PrintConfig.cpp:3299 -#: src/libslic3r/PrintConfig.cpp:3300 +#: src/libslic3r/PrintConfig.cpp:3297 src/libslic3r/PrintConfig.cpp:3298 +#: src/libslic3r/PrintConfig.cpp:3299 msgid "Printer scaling correction" msgstr "Verschalingscorrectie voor printer" -#: src/libslic3r/PrintConfig.cpp:3306 src/libslic3r/PrintConfig.cpp:3308 +#: src/libslic3r/PrintConfig.cpp:3305 src/libslic3r/PrintConfig.cpp:3307 msgid "Printer scaling correction in X axis" msgstr "Verschalingscorrectie over de X-as" -#: src/libslic3r/PrintConfig.cpp:3307 +#: src/libslic3r/PrintConfig.cpp:3306 msgid "Printer scaling X axis correction" msgstr "Verschalingscorrectie in X-richting" -#: src/libslic3r/PrintConfig.cpp:3314 src/libslic3r/PrintConfig.cpp:3316 +#: src/libslic3r/PrintConfig.cpp:3313 src/libslic3r/PrintConfig.cpp:3315 msgid "Printer scaling correction in Y axis" msgstr "Verschalingscorrectie over de Y-as" -#: src/libslic3r/PrintConfig.cpp:3315 +#: src/libslic3r/PrintConfig.cpp:3314 msgid "Printer scaling Y axis correction" msgstr "Verschalingscorrectie in Y-riching" -#: src/libslic3r/PrintConfig.cpp:3322 src/libslic3r/PrintConfig.cpp:3324 +#: src/libslic3r/PrintConfig.cpp:3321 src/libslic3r/PrintConfig.cpp:3323 msgid "Printer scaling correction in Z axis" msgstr "Verschalingscorrectie over de Z-as" -#: src/libslic3r/PrintConfig.cpp:3323 +#: src/libslic3r/PrintConfig.cpp:3322 msgid "Printer scaling Z axis correction" msgstr "Verschalingscorrectie in Z-riching" -#: src/libslic3r/PrintConfig.cpp:3330 src/libslic3r/PrintConfig.cpp:3331 +#: src/libslic3r/PrintConfig.cpp:3329 src/libslic3r/PrintConfig.cpp:3330 msgid "Printer absolute correction" msgstr "Absolute correctie voor printer" -#: src/libslic3r/PrintConfig.cpp:3332 +#: src/libslic3r/PrintConfig.cpp:3331 msgid "" "Will inflate or deflate the sliced 2D polygons according to the sign of the " "correction." @@ -14585,20 +14692,20 @@ msgstr "" "Zal de geslicede veelhoeken uitrekken of laten krimpen, afhankelijk van de " "correctiewaarde." -#: src/libslic3r/PrintConfig.cpp:3338 +#: src/libslic3r/PrintConfig.cpp:3337 msgid "Elephant foot minimum width" msgstr "Squish-compensatiebreedte" -#: src/libslic3r/PrintConfig.cpp:3340 +#: src/libslic3r/PrintConfig.cpp:3339 msgid "" "Minimum width of features to maintain when doing elephant foot compensation." msgstr "Minimale breedte van delen waarop squish-compensatie wordt toegepast." -#: src/libslic3r/PrintConfig.cpp:3347 src/libslic3r/PrintConfig.cpp:3348 +#: src/libslic3r/PrintConfig.cpp:3346 src/libslic3r/PrintConfig.cpp:3347 msgid "Printer gamma correction" msgstr "Gammacorrectie voor printer" -#: src/libslic3r/PrintConfig.cpp:3349 +#: src/libslic3r/PrintConfig.cpp:3348 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 " @@ -14608,43 +14715,43 @@ msgstr "" "betekent een waarde die in het midden ligt. Dit gedrag elimineert anti-" "aliasing zonder dat gaten in de veelhoeken verloren gaan." -#: src/libslic3r/PrintConfig.cpp:3368 src/libslic3r/PrintConfig.cpp:3369 +#: src/libslic3r/PrintConfig.cpp:3367 src/libslic3r/PrintConfig.cpp:3368 msgid "SLA material type" msgstr "SLA-materiaaltype" -#: src/libslic3r/PrintConfig.cpp:3380 src/libslic3r/PrintConfig.cpp:3381 +#: src/libslic3r/PrintConfig.cpp:3379 src/libslic3r/PrintConfig.cpp:3380 msgid "Initial layer height" msgstr "Laagdikte eerste laag" -#: src/libslic3r/PrintConfig.cpp:3387 src/libslic3r/PrintConfig.cpp:3388 +#: src/libslic3r/PrintConfig.cpp:3386 src/libslic3r/PrintConfig.cpp:3387 msgid "Bottle volume" msgstr "Flesinhoud (volume)" -#: src/libslic3r/PrintConfig.cpp:3389 +#: src/libslic3r/PrintConfig.cpp:3388 msgid "ml" msgstr "ml" -#: src/libslic3r/PrintConfig.cpp:3394 src/libslic3r/PrintConfig.cpp:3395 +#: src/libslic3r/PrintConfig.cpp:3393 src/libslic3r/PrintConfig.cpp:3394 msgid "Bottle weight" msgstr "Flesinhoud (gewicht)" -#: src/libslic3r/PrintConfig.cpp:3396 +#: src/libslic3r/PrintConfig.cpp:3395 msgid "kg" msgstr "kg" -#: src/libslic3r/PrintConfig.cpp:3403 +#: src/libslic3r/PrintConfig.cpp:3402 msgid "g/ml" msgstr "g/ml" -#: src/libslic3r/PrintConfig.cpp:3410 +#: src/libslic3r/PrintConfig.cpp:3409 msgid "money/bottle" msgstr "€/fles" -#: src/libslic3r/PrintConfig.cpp:3415 +#: src/libslic3r/PrintConfig.cpp:3414 msgid "Faded layers" msgstr "Transitielagen" -#: src/libslic3r/PrintConfig.cpp:3416 +#: src/libslic3r/PrintConfig.cpp:3415 msgid "" "Number of the layers needed for the exposure time fade from initial exposure " "time to the exposure time" @@ -14652,103 +14759,103 @@ msgstr "" "Aantal lagen waarin de initiële belichtingstijd stapsgewijs wordt " "teruggebracht naar de standaard belichtingstijd" -#: src/libslic3r/PrintConfig.cpp:3423 src/libslic3r/PrintConfig.cpp:3424 +#: src/libslic3r/PrintConfig.cpp:3422 src/libslic3r/PrintConfig.cpp:3423 msgid "Minimum exposure time" msgstr "Minimale belichtingstijd" -#: src/libslic3r/PrintConfig.cpp:3431 src/libslic3r/PrintConfig.cpp:3432 +#: src/libslic3r/PrintConfig.cpp:3430 src/libslic3r/PrintConfig.cpp:3431 msgid "Maximum exposure time" msgstr "Maximale belichtingstijd" -#: src/libslic3r/PrintConfig.cpp:3439 src/libslic3r/PrintConfig.cpp:3440 +#: src/libslic3r/PrintConfig.cpp:3438 src/libslic3r/PrintConfig.cpp:3439 msgid "Exposure time" msgstr "Belichtingstijd" -#: src/libslic3r/PrintConfig.cpp:3446 src/libslic3r/PrintConfig.cpp:3447 +#: src/libslic3r/PrintConfig.cpp:3445 src/libslic3r/PrintConfig.cpp:3446 msgid "Minimum initial exposure time" msgstr "Minimale initiële belichtingstijd" -#: src/libslic3r/PrintConfig.cpp:3454 src/libslic3r/PrintConfig.cpp:3455 +#: src/libslic3r/PrintConfig.cpp:3453 src/libslic3r/PrintConfig.cpp:3454 msgid "Maximum initial exposure time" msgstr "Maximale initiële belichtingstijd" -#: src/libslic3r/PrintConfig.cpp:3462 src/libslic3r/PrintConfig.cpp:3463 +#: src/libslic3r/PrintConfig.cpp:3461 src/libslic3r/PrintConfig.cpp:3462 msgid "Initial exposure time" msgstr "Initiële belichtingstijd" -#: src/libslic3r/PrintConfig.cpp:3469 src/libslic3r/PrintConfig.cpp:3470 +#: src/libslic3r/PrintConfig.cpp:3468 src/libslic3r/PrintConfig.cpp:3469 msgid "Correction for expansion" msgstr "Vergrotingscorrectie" -#: src/libslic3r/PrintConfig.cpp:3476 src/libslic3r/PrintConfig.cpp:3477 +#: src/libslic3r/PrintConfig.cpp:3475 src/libslic3r/PrintConfig.cpp:3476 msgid "Correction for expansion in X axis" msgstr "Uitzettingscorrectie over de X-as" -#: src/libslic3r/PrintConfig.cpp:3483 src/libslic3r/PrintConfig.cpp:3484 +#: src/libslic3r/PrintConfig.cpp:3482 src/libslic3r/PrintConfig.cpp:3483 msgid "Correction for expansion in Y axis" msgstr "Uitzettingscorrectie over de Y-as" -#: src/libslic3r/PrintConfig.cpp:3490 src/libslic3r/PrintConfig.cpp:3491 +#: src/libslic3r/PrintConfig.cpp:3489 src/libslic3r/PrintConfig.cpp:3490 msgid "Correction for expansion in Z axis" msgstr "Uitzettingscorrectie over de Z-as" -#: src/libslic3r/PrintConfig.cpp:3497 +#: src/libslic3r/PrintConfig.cpp:3496 msgid "SLA print material notes" msgstr "SLA-printmateriaal opmerkingen" -#: src/libslic3r/PrintConfig.cpp:3498 +#: src/libslic3r/PrintConfig.cpp:3497 msgid "You can put your notes regarding the SLA print material here." msgstr "U kunt hier opmerkingen plaatsen wat betreft het SLA-materiaal." -#: src/libslic3r/PrintConfig.cpp:3510 src/libslic3r/PrintConfig.cpp:3521 +#: src/libslic3r/PrintConfig.cpp:3509 src/libslic3r/PrintConfig.cpp:3520 msgid "Default SLA material profile" msgstr "Standaard SLA-materiaalprofiel" -#: src/libslic3r/PrintConfig.cpp:3532 +#: src/libslic3r/PrintConfig.cpp:3531 msgid "Generate supports" msgstr "Genereer support" -#: src/libslic3r/PrintConfig.cpp:3534 +#: src/libslic3r/PrintConfig.cpp:3533 msgid "Generate supports for the models" msgstr "Genereer support voor de modellen" -#: src/libslic3r/PrintConfig.cpp:3539 +#: src/libslic3r/PrintConfig.cpp:3538 msgid "Pinhead front diameter" msgstr "Diameter voorzijde pinkop" -#: src/libslic3r/PrintConfig.cpp:3541 +#: src/libslic3r/PrintConfig.cpp:3540 msgid "Diameter of the pointing side of the head" msgstr "Diameter van de puntige zijde van de kop" -#: src/libslic3r/PrintConfig.cpp:3548 +#: src/libslic3r/PrintConfig.cpp:3547 msgid "Head penetration" msgstr "Koppenetratie" -#: src/libslic3r/PrintConfig.cpp:3550 +#: src/libslic3r/PrintConfig.cpp:3549 msgid "How much the pinhead has to penetrate the model surface" msgstr "Hoe ver de supportkop in het model moet steken" -#: src/libslic3r/PrintConfig.cpp:3557 +#: src/libslic3r/PrintConfig.cpp:3556 msgid "Pinhead width" msgstr "Pinkopbreedte" -#: src/libslic3r/PrintConfig.cpp:3559 +#: src/libslic3r/PrintConfig.cpp:3558 msgid "Width from the back sphere center to the front sphere center" msgstr "Centerafstand van de achterste tot de voorste bol" -#: src/libslic3r/PrintConfig.cpp:3567 +#: src/libslic3r/PrintConfig.cpp:3566 msgid "Pillar diameter" msgstr "Pijlerdiameter" -#: src/libslic3r/PrintConfig.cpp:3569 +#: src/libslic3r/PrintConfig.cpp:3568 msgid "Diameter in mm of the support pillars" msgstr "Diameter van de supportpijlers (in mm)" -#: src/libslic3r/PrintConfig.cpp:3577 +#: src/libslic3r/PrintConfig.cpp:3576 msgid "Small pillar diameter percent" msgstr "Percentage van smalle pijlerdiameter" -#: src/libslic3r/PrintConfig.cpp:3579 +#: src/libslic3r/PrintConfig.cpp:3578 msgid "" "The percentage of smaller pillars compared to the normal pillar diameter " "which are used in problematic areas where a normal pilla cannot fit." @@ -14756,11 +14863,11 @@ msgstr "" "Het percentage van smallere pijlers vergeleken met normale pijlerdiameters " "die worden gebruikt in moeilijk te bereiken plekken." -#: src/libslic3r/PrintConfig.cpp:3588 +#: src/libslic3r/PrintConfig.cpp:3587 msgid "Max bridges on a pillar" msgstr "Maximaal aantal bruggen op een pijler" -#: src/libslic3r/PrintConfig.cpp:3590 +#: src/libslic3r/PrintConfig.cpp:3589 msgid "" "Maximum number of bridges that can be placed on a pillar. Bridges hold " "support point pinheads and connect to pillars as small branches." @@ -14768,11 +14875,11 @@ msgstr "" "Maximaal aantal bruggen dat op een pijler geplaatst kan worden. Bruggen " "houden supportpuntkop bij elkaar en verbinden pijlers as smalle takken." -#: src/libslic3r/PrintConfig.cpp:3598 +#: src/libslic3r/PrintConfig.cpp:3597 msgid "Pillar connection mode" msgstr "Pijlerverbindingsmodus" -#: src/libslic3r/PrintConfig.cpp:3599 +#: src/libslic3r/PrintConfig.cpp:3598 msgid "" "Controls the bridge type between two neighboring pillars. Can be zig-zag, " "cross (double zig-zag) or dynamic which will automatically switch between " @@ -14782,23 +14889,23 @@ msgstr "" "kruisend (dubbele zigzag) of dynamisch zijn. Dynamisch houdt in dat wordt " "geschakeld tussen de eerste twee, afhankelijk van de pijlerafstand." -#: src/libslic3r/PrintConfig.cpp:3607 +#: src/libslic3r/PrintConfig.cpp:3606 msgid "Zig-Zag" msgstr "Zigzag" -#: src/libslic3r/PrintConfig.cpp:3608 +#: src/libslic3r/PrintConfig.cpp:3607 msgid "Cross" msgstr "Kruisend" -#: src/libslic3r/PrintConfig.cpp:3609 +#: src/libslic3r/PrintConfig.cpp:3608 msgid "Dynamic" msgstr "Dynamisch" -#: src/libslic3r/PrintConfig.cpp:3621 +#: src/libslic3r/PrintConfig.cpp:3620 msgid "Pillar widening factor" msgstr "Pijlervergrotingsfactor" -#: src/libslic3r/PrintConfig.cpp:3623 +#: src/libslic3r/PrintConfig.cpp:3622 msgid "" "Merging bridges or pillars into another pillars can increase the radius. " "Zero means no increase, one means full increase." @@ -14806,27 +14913,27 @@ msgstr "" "Bruggen of pijlers samenvoegen met andere pijlers kan de radius vergroten. 0 " "betekent geen vergroting, 1 betekent volle vergroting." -#: src/libslic3r/PrintConfig.cpp:3632 +#: src/libslic3r/PrintConfig.cpp:3631 msgid "Support base diameter" msgstr "Supportbasis - diameter" -#: src/libslic3r/PrintConfig.cpp:3634 +#: src/libslic3r/PrintConfig.cpp:3633 msgid "Diameter in mm of the pillar base" msgstr "Diameter van de pijlerbasis (in mm)" -#: src/libslic3r/PrintConfig.cpp:3642 +#: src/libslic3r/PrintConfig.cpp:3641 msgid "Support base height" msgstr "Supportbasis - hoogte" -#: src/libslic3r/PrintConfig.cpp:3644 +#: src/libslic3r/PrintConfig.cpp:3643 msgid "The height of the pillar base cone" msgstr "Hoogte van de pijlerbasiskegel" -#: src/libslic3r/PrintConfig.cpp:3651 +#: src/libslic3r/PrintConfig.cpp:3650 msgid "Support base safety distance" msgstr "Supportbasis - veilige afstand" -#: src/libslic3r/PrintConfig.cpp:3654 +#: src/libslic3r/PrintConfig.cpp:3653 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 " @@ -14836,27 +14943,27 @@ msgstr "" "modus zonder verhoging waar een gat volgens deze parameter wordt ingevoegd " "tussen het model en de basisplaat." -#: src/libslic3r/PrintConfig.cpp:3664 +#: src/libslic3r/PrintConfig.cpp:3663 msgid "Critical angle" msgstr "Kritische hoek" -#: src/libslic3r/PrintConfig.cpp:3666 +#: src/libslic3r/PrintConfig.cpp:3665 msgid "The default angle for connecting support sticks and junctions." msgstr "De standaardhoek voor de verbinding van supporttakken en kruisingen." -#: src/libslic3r/PrintConfig.cpp:3674 +#: src/libslic3r/PrintConfig.cpp:3673 msgid "Max bridge length" msgstr "Maximale bruglengte" -#: src/libslic3r/PrintConfig.cpp:3676 +#: src/libslic3r/PrintConfig.cpp:3675 msgid "The max length of a bridge" msgstr "Maximale bruglengte" -#: src/libslic3r/PrintConfig.cpp:3683 +#: src/libslic3r/PrintConfig.cpp:3682 msgid "Max pillar linking distance" msgstr "Maximale pijler-verbindafstand" -#: src/libslic3r/PrintConfig.cpp:3685 +#: src/libslic3r/PrintConfig.cpp:3684 msgid "" "The max distance of two pillars to get linked with each other. A zero value " "will prohibit pillar cascading." @@ -14864,7 +14971,7 @@ msgstr "" "Maximale verbindingsafstand van twee pijlers. Een waarde van 0 schakelt aan " "elkaar verbonden pijlers uit." -#: src/libslic3r/PrintConfig.cpp:3695 +#: src/libslic3r/PrintConfig.cpp:3694 msgid "" "How much the supports should lift up the supported object. If \"Pad around " "object\" is enabled, this value is ignored." @@ -14872,39 +14979,39 @@ msgstr "" "Hoe veel het support omhoog moet bewegen op het ondersteunde object. Als " "'Basisplaat rondom object' is ingeschakeld wordt deze waarde genegeerd." -#: src/libslic3r/PrintConfig.cpp:3706 +#: src/libslic3r/PrintConfig.cpp:3705 msgid "This is a relative measure of support points density." msgstr "Relatieve waarde van de dichtheid van supportpunten." -#: src/libslic3r/PrintConfig.cpp:3712 +#: src/libslic3r/PrintConfig.cpp:3711 msgid "Minimal distance of the support points" msgstr "Minimale supportpuntafstand" -#: src/libslic3r/PrintConfig.cpp:3714 +#: src/libslic3r/PrintConfig.cpp:3713 msgid "No support points will be placed closer than this threshold." msgstr "Minimale afstand tussen supportpunten." -#: src/libslic3r/PrintConfig.cpp:3720 +#: src/libslic3r/PrintConfig.cpp:3719 msgid "Use pad" msgstr "Gebruik basisplaat" -#: src/libslic3r/PrintConfig.cpp:3722 +#: src/libslic3r/PrintConfig.cpp:3721 msgid "Add a pad underneath the supported model" msgstr "Voeg een basisplaat toe onder het model met support" -#: src/libslic3r/PrintConfig.cpp:3727 +#: src/libslic3r/PrintConfig.cpp:3726 msgid "Pad wall thickness" msgstr "Basisplaat - wanddikte" -#: src/libslic3r/PrintConfig.cpp:3729 +#: src/libslic3r/PrintConfig.cpp:3728 msgid "The thickness of the pad and its optional cavity walls." msgstr "Dikte van de basisplaat en optionele wanden." -#: src/libslic3r/PrintConfig.cpp:3737 +#: src/libslic3r/PrintConfig.cpp:3736 msgid "Pad wall height" msgstr "Basisplaat - wandhoogte" -#: src/libslic3r/PrintConfig.cpp:3738 +#: src/libslic3r/PrintConfig.cpp:3737 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 " @@ -14916,19 +15023,19 @@ msgstr "" "sommige resins een sterk zuigeffect in de holte produceren, wat het afpellen " "van de print van het folie lastig kan maken." -#: src/libslic3r/PrintConfig.cpp:3751 +#: src/libslic3r/PrintConfig.cpp:3750 msgid "Pad brim size" msgstr "Basisplaat - expansie" -#: src/libslic3r/PrintConfig.cpp:3752 +#: src/libslic3r/PrintConfig.cpp:3751 msgid "How far should the pad extend around the contained geometry" msgstr "Hoe ver de basisplaat moet uitsteken buiten de geometrie" -#: src/libslic3r/PrintConfig.cpp:3762 +#: src/libslic3r/PrintConfig.cpp:3761 msgid "Max merge distance" msgstr "Maximale combineerafstand" -#: src/libslic3r/PrintConfig.cpp:3764 +#: src/libslic3r/PrintConfig.cpp:3763 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 " @@ -14938,11 +15045,11 @@ msgstr "" "van één grote. Deze parameter bepaalt hoe ver de tussenafstand van de " "kleinere basisplaten mogen zijn." -#: src/libslic3r/PrintConfig.cpp:3784 +#: src/libslic3r/PrintConfig.cpp:3783 msgid "Pad wall slope" msgstr "Basisplaat - zijhoek" -#: src/libslic3r/PrintConfig.cpp:3786 +#: src/libslic3r/PrintConfig.cpp:3785 msgid "" "The slope of the pad wall relative to the bed plane. 90 degrees means " "straight walls." @@ -14950,23 +15057,23 @@ msgstr "" "Hoek van de basisplaatzijde ten opzichte van het bed. 90 graden betekent een " "rechte zijkant." -#: src/libslic3r/PrintConfig.cpp:3797 +#: src/libslic3r/PrintConfig.cpp:3796 msgid "Create pad around object and ignore the support elevation" msgstr "Genereer basisplaat rondom object en schakel objectverhoging uit" -#: src/libslic3r/PrintConfig.cpp:3802 +#: src/libslic3r/PrintConfig.cpp:3801 msgid "Pad around object everywhere" msgstr "Overal basisplaat rondom object" -#: src/libslic3r/PrintConfig.cpp:3804 +#: src/libslic3r/PrintConfig.cpp:3803 msgid "Force pad around object everywhere" msgstr "Forceer basisplaat overal rondom het object" -#: src/libslic3r/PrintConfig.cpp:3809 +#: src/libslic3r/PrintConfig.cpp:3808 msgid "Pad object gap" msgstr "Basisplaat - gat" -#: src/libslic3r/PrintConfig.cpp:3811 +#: src/libslic3r/PrintConfig.cpp:3810 msgid "" "The gap between the object bottom and the generated pad in zero elevation " "mode." @@ -14974,11 +15081,11 @@ msgstr "" "Het gat tussen de onderkant van het object en de gegenereerde basisplaat in " "de modus zonder verhoging." -#: src/libslic3r/PrintConfig.cpp:3820 +#: src/libslic3r/PrintConfig.cpp:3819 msgid "Pad object connector stride" msgstr "Basisplaat - verbindingstakafstand" -#: src/libslic3r/PrintConfig.cpp:3822 +#: src/libslic3r/PrintConfig.cpp:3821 msgid "" "Distance between two connector sticks which connect the object and the " "generated pad." @@ -14986,46 +15093,46 @@ msgstr "" "Afstand tussen twee verbindingstakken die het object verbinden aan de " "basisplaat." -#: src/libslic3r/PrintConfig.cpp:3829 +#: src/libslic3r/PrintConfig.cpp:3828 msgid "Pad object connector width" msgstr "Basisplaat - verbindingstakbreedte" -#: src/libslic3r/PrintConfig.cpp:3831 +#: src/libslic3r/PrintConfig.cpp:3830 msgid "" "Width of the connector sticks which connect the object and the generated pad." msgstr "" "Breedte van de verbindingstakken die het object en de basisplaat met elkaar " "verbinden." -#: src/libslic3r/PrintConfig.cpp:3838 +#: src/libslic3r/PrintConfig.cpp:3837 msgid "Pad object connector penetration" msgstr "Basisplaat - Verbindingstakinsteek" -#: src/libslic3r/PrintConfig.cpp:3841 +#: src/libslic3r/PrintConfig.cpp:3840 msgid "How much should the tiny connectors penetrate into the model body." msgstr "Hoe ver de verbindingstakken in het model steken." -#: src/libslic3r/PrintConfig.cpp:3848 +#: src/libslic3r/PrintConfig.cpp:3847 msgid "Enable hollowing" msgstr "Uithollen toestaan" -#: src/libslic3r/PrintConfig.cpp:3850 +#: src/libslic3r/PrintConfig.cpp:3849 msgid "Hollow out a model to have an empty interior" msgstr "Hol een model uit voor een leeg binnenste" -#: src/libslic3r/PrintConfig.cpp:3855 +#: src/libslic3r/PrintConfig.cpp:3854 msgid "Wall thickness" msgstr "Wanddikte" -#: src/libslic3r/PrintConfig.cpp:3857 +#: src/libslic3r/PrintConfig.cpp:3856 msgid "Minimum wall thickness of a hollowed model." msgstr "Minimale wanddikte van een uitgehold model." -#: src/libslic3r/PrintConfig.cpp:3865 +#: src/libslic3r/PrintConfig.cpp:3864 msgid "Accuracy" msgstr "Nauwkeurigheid" -#: src/libslic3r/PrintConfig.cpp:3867 +#: src/libslic3r/PrintConfig.cpp:3866 msgid "" "Performance vs accuracy of calculation. Lower values may produce unwanted " "artifacts." @@ -15033,7 +15140,7 @@ msgstr "" "Prestatie tegenover nauwkeurigheid van berekenen. Lagere waarde kunnen " "ongewenste artefacten produceren." -#: src/libslic3r/PrintConfig.cpp:3877 +#: src/libslic3r/PrintConfig.cpp:3876 msgid "" "Hollowing is done in two steps: first, an imaginary interior is calculated " "deeper (offset plus the closing distance) in the object and then it's " @@ -15047,11 +15154,11 @@ msgstr "" "binnenste ronder. Bij een waarde van 0 is het binnenste vrijwel gelijk aan " "de buitenzijde." -#: src/libslic3r/PrintConfig.cpp:3889 +#: src/libslic3r/PrintConfig.cpp:3888 msgid "Print speed" msgstr "Printsnelheid" -#: src/libslic3r/PrintConfig.cpp:3891 +#: src/libslic3r/PrintConfig.cpp:3890 msgid "" "A slower printing profile might be necessary when using materials with " "higher viscosity or with some hollowed parts. It slows down the tilt " @@ -15061,63 +15168,63 @@ msgstr "" "vloeibaarheid of met holle delen. Het vertraagt de kantelbeweging en voegt " "een vertraging toe na de belichting." -#: src/libslic3r/PrintConfig.cpp:4359 +#: src/libslic3r/PrintConfig.cpp:4358 msgid "Export OBJ" msgstr "Exporteer OBJ" -#: src/libslic3r/PrintConfig.cpp:4360 +#: src/libslic3r/PrintConfig.cpp:4359 msgid "Export the model(s) as OBJ." -msgstr "Exporteer de modellen als OBJ-bestand." +msgstr "Exporteer de modellen als .OBJ-bestand." -#: src/libslic3r/PrintConfig.cpp:4371 +#: src/libslic3r/PrintConfig.cpp:4370 msgid "Export SLA" msgstr "Exporteer SLA" -#: src/libslic3r/PrintConfig.cpp:4372 +#: src/libslic3r/PrintConfig.cpp:4371 msgid "Slice the model and export SLA printing layers as PNG." -msgstr "Slice het model en exporteer SLA-printlagen als PNG-bestanden." +msgstr "Slice het model en exporteer SLA-printlagen als .PNG-bestanden." -#: src/libslic3r/PrintConfig.cpp:4377 +#: src/libslic3r/PrintConfig.cpp:4376 msgid "Export 3MF" msgstr "Exporteer 3MF" -#: src/libslic3r/PrintConfig.cpp:4378 +#: src/libslic3r/PrintConfig.cpp:4377 msgid "Export the model(s) as 3MF." -msgstr "Exporteer de modellen als 3MF-bestanden." +msgstr "Exporteer de modellen als .3MF-bestanden." -#: src/libslic3r/PrintConfig.cpp:4382 +#: src/libslic3r/PrintConfig.cpp:4381 msgid "Export AMF" msgstr "Exporteer AMF" -#: src/libslic3r/PrintConfig.cpp:4383 +#: src/libslic3r/PrintConfig.cpp:4382 msgid "Export the model(s) as AMF." -msgstr "Exporteer de modellen als AMF-bestanden." +msgstr "Exporteer de modellen als .AMF-bestanden." -#: src/libslic3r/PrintConfig.cpp:4387 +#: src/libslic3r/PrintConfig.cpp:4386 msgid "Export STL" msgstr "Exporteer STL" -#: src/libslic3r/PrintConfig.cpp:4388 +#: src/libslic3r/PrintConfig.cpp:4387 msgid "Export the model(s) as STL." -msgstr "Exporteer de modellen als STL-bestand." +msgstr "Exporteer de modellen als .STL-bestand." -#: src/libslic3r/PrintConfig.cpp:4393 +#: src/libslic3r/PrintConfig.cpp:4392 msgid "Slice the model and export toolpaths as G-code." -msgstr "Slice het model en exporteer de paden als G-code-bestand." +msgstr "Slice het model en exporteer de paden als .gcode-bestand." -#: src/libslic3r/PrintConfig.cpp:4398 +#: src/libslic3r/PrintConfig.cpp:4397 msgid "G-code viewer" msgstr "G-code weergave" -#: src/libslic3r/PrintConfig.cpp:4399 +#: src/libslic3r/PrintConfig.cpp:4398 msgid "Visualize an already sliced and saved G-code" msgstr "Visualiseer een reeds opgeslagen G-code" -#: src/libslic3r/PrintConfig.cpp:4404 +#: src/libslic3r/PrintConfig.cpp:4403 msgid "Slice" msgstr "Slice" -#: src/libslic3r/PrintConfig.cpp:4405 +#: src/libslic3r/PrintConfig.cpp:4404 msgid "" "Slice the model as FFF or SLA based on the printer_technology configuration " "value." @@ -15125,71 +15232,71 @@ msgstr "" "Slice het model als FFF of SLA, gebaseerd op de 'printer_technology'-" "configuratiewaarde." -#: src/libslic3r/PrintConfig.cpp:4410 +#: src/libslic3r/PrintConfig.cpp:4409 msgid "Help" msgstr "Help" -#: src/libslic3r/PrintConfig.cpp:4411 +#: src/libslic3r/PrintConfig.cpp:4410 msgid "Show this help." msgstr "Toon deze hulp zien." -#: src/libslic3r/PrintConfig.cpp:4416 +#: src/libslic3r/PrintConfig.cpp:4415 msgid "Help (FFF options)" msgstr "Help (FFF-opties)" -#: src/libslic3r/PrintConfig.cpp:4417 +#: src/libslic3r/PrintConfig.cpp:4416 msgid "Show the full list of print/G-code configuration options." msgstr "Toon de volledige lijst van print- of G-code-configuratie-opties." -#: src/libslic3r/PrintConfig.cpp:4421 +#: src/libslic3r/PrintConfig.cpp:4420 msgid "Help (SLA options)" msgstr "Help (SLA opties)" -#: src/libslic3r/PrintConfig.cpp:4422 +#: src/libslic3r/PrintConfig.cpp:4421 msgid "Show the full list of SLA print configuration options." msgstr "Toon de volledige lijst van SLA-printconfiguratie-opties." -#: src/libslic3r/PrintConfig.cpp:4426 +#: src/libslic3r/PrintConfig.cpp:4425 msgid "Output Model Info" msgstr "Output model-info" -#: src/libslic3r/PrintConfig.cpp:4427 +#: src/libslic3r/PrintConfig.cpp:4426 msgid "Write information about the model to the console." msgstr "Schrijf informatie over het model naar de console." -#: src/libslic3r/PrintConfig.cpp:4431 +#: src/libslic3r/PrintConfig.cpp:4430 msgid "Save config file" msgstr "Sla configuratiebestand op" -#: src/libslic3r/PrintConfig.cpp:4432 +#: src/libslic3r/PrintConfig.cpp:4431 msgid "Save configuration to the specified file." msgstr "Sla configuratie op in aangegeven bestand." -#: src/libslic3r/PrintConfig.cpp:4442 +#: src/libslic3r/PrintConfig.cpp:4441 msgid "Align XY" msgstr "XY uitlijnen" -#: src/libslic3r/PrintConfig.cpp:4443 +#: src/libslic3r/PrintConfig.cpp:4442 msgid "Align the model to the given point." msgstr "Lijn de modellen uit op het gegeven punt." -#: src/libslic3r/PrintConfig.cpp:4448 +#: src/libslic3r/PrintConfig.cpp:4447 msgid "Cut model at the given Z." msgstr "Snijdt model op de ingestelde hoogte." -#: src/libslic3r/PrintConfig.cpp:4469 +#: src/libslic3r/PrintConfig.cpp:4468 msgid "Center" msgstr "Centreer" -#: src/libslic3r/PrintConfig.cpp:4470 +#: src/libslic3r/PrintConfig.cpp:4469 msgid "Center the print around the given center." msgstr "Centreer de print op het middelpunt." -#: src/libslic3r/PrintConfig.cpp:4474 +#: src/libslic3r/PrintConfig.cpp:4473 msgid "Don't arrange" msgstr "Niet schikken" -#: src/libslic3r/PrintConfig.cpp:4475 +#: src/libslic3r/PrintConfig.cpp:4474 msgid "" "Do not rearrange the given models before merging and keep their original XY " "coordinates." @@ -15197,11 +15304,11 @@ msgstr "" "Herschik de modellen niet voor het samenvoegen en behoudt de originele X- en " "Y-coördinaten." -#: src/libslic3r/PrintConfig.cpp:4478 +#: src/libslic3r/PrintConfig.cpp:4477 msgid "Ensure on bed" msgstr "Plaats op bed" -#: src/libslic3r/PrintConfig.cpp:4479 +#: src/libslic3r/PrintConfig.cpp:4478 msgid "" "Lift the object above the bed when it is partially below. Enabled by " "default, use --no-ensure-on-bed to disable." @@ -15209,23 +15316,23 @@ msgstr "" "Til het object boven het bed als deze er gedeeltelijk onder valt. Staat " "standaard aan. Gebruik \"no_ensure_on_bed\" om uit te zetten." -#: src/libslic3r/PrintConfig.cpp:4483 +#: src/libslic3r/PrintConfig.cpp:4482 msgid "Duplicate" msgstr "Dupliceer" -#: src/libslic3r/PrintConfig.cpp:4484 +#: src/libslic3r/PrintConfig.cpp:4483 msgid "Multiply copies by this factor." msgstr "Meerdere kopieën van dit aantal." -#: src/libslic3r/PrintConfig.cpp:4488 +#: src/libslic3r/PrintConfig.cpp:4487 msgid "Duplicate by grid" msgstr "Dupliceer in raster" -#: src/libslic3r/PrintConfig.cpp:4489 +#: src/libslic3r/PrintConfig.cpp:4488 msgid "Multiply copies by creating a grid." msgstr "Meerdere kopieën in raster." -#: src/libslic3r/PrintConfig.cpp:4493 +#: src/libslic3r/PrintConfig.cpp:4492 msgid "" "Arrange the supplied models in a plate and merge them in a single model in " "order to perform actions once." @@ -15233,7 +15340,7 @@ msgstr "" "Schik de toegevoegde modellen en combineer ze tot één model om eenmalig " "acties uit te voeren." -#: src/libslic3r/PrintConfig.cpp:4498 +#: src/libslic3r/PrintConfig.cpp:4497 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)." @@ -15241,31 +15348,31 @@ msgstr "" "Probeer alle niet-gesloten meshes te repareren (deze optie is impliciet " "toegevoegd om, wanneer dat nodig is, onmogelijke modellen toch te slicen)." -#: src/libslic3r/PrintConfig.cpp:4502 +#: src/libslic3r/PrintConfig.cpp:4501 msgid "Rotation angle around the Z axis in degrees." msgstr "Rotatiehoek rond de Z-as in graden." -#: src/libslic3r/PrintConfig.cpp:4506 +#: src/libslic3r/PrintConfig.cpp:4505 msgid "Rotate around X" msgstr "Draai over de X-as" -#: src/libslic3r/PrintConfig.cpp:4507 +#: src/libslic3r/PrintConfig.cpp:4506 msgid "Rotation angle around the X axis in degrees." msgstr "Rotatiehoek rond de X-as in graden." -#: src/libslic3r/PrintConfig.cpp:4511 +#: src/libslic3r/PrintConfig.cpp:4510 msgid "Rotate around Y" msgstr "Draai over de Y-as" -#: src/libslic3r/PrintConfig.cpp:4512 +#: src/libslic3r/PrintConfig.cpp:4511 msgid "Rotation angle around the Y axis in degrees." msgstr "Rotatiehoek rond de Y-as in graden." -#: src/libslic3r/PrintConfig.cpp:4517 +#: src/libslic3r/PrintConfig.cpp:4516 msgid "Scaling factor or percentage." msgstr "Schalingsfactor of percentage." -#: src/libslic3r/PrintConfig.cpp:4522 +#: src/libslic3r/PrintConfig.cpp:4521 msgid "" "Detect unconnected parts in the given model(s) and split them into separate " "objects." @@ -15273,23 +15380,23 @@ msgstr "" "Detecteer niet-verbonden onderdelen in het model en deel ze op in " "verschillende objecten." -#: src/libslic3r/PrintConfig.cpp:4525 +#: src/libslic3r/PrintConfig.cpp:4524 msgid "Scale to Fit" msgstr "Verschaal naar passing" -#: src/libslic3r/PrintConfig.cpp:4526 +#: src/libslic3r/PrintConfig.cpp:4525 msgid "Scale to fit the given volume." msgstr "Verschaal naar passing in het gegeven volume." -#: src/libslic3r/PrintConfig.cpp:4535 +#: src/libslic3r/PrintConfig.cpp:4534 msgid "Ignore non-existent config files" msgstr "Negeer niet-bestaande configuratiebestanden" -#: src/libslic3r/PrintConfig.cpp:4536 +#: src/libslic3r/PrintConfig.cpp:4535 msgid "Do not fail if a file supplied to --load does not exist." msgstr "Geef geen fout als een bestand om te laden niet bestaat." -#: src/libslic3r/PrintConfig.cpp:4539 +#: src/libslic3r/PrintConfig.cpp:4538 msgid "" "Forward-compatibility rule when loading configurations from config files and " "project files (3MF, AMF)." @@ -15297,7 +15404,7 @@ msgstr "" "Doorgang-compatibiliteitsregel bij het laden van configuraties van " "configuratie- en projectbestanden (3MF, AMF)." -#: src/libslic3r/PrintConfig.cpp:4540 +#: src/libslic3r/PrintConfig.cpp:4539 msgid "" "This version of PrusaSlicer may not understand configurations produced by " "the newest PrusaSlicer versions. For example, newer PrusaSlicer may extend " @@ -15310,11 +15417,11 @@ msgstr "" "onbekende waarde zonder melding of woordelijk te vervangen door een " "standaardwaarde." -#: src/libslic3r/PrintConfig.cpp:4547 +#: src/libslic3r/PrintConfig.cpp:4546 msgid "Bail out on unknown configuration values" msgstr "Sla onbekende configuratiewaarden over" -#: src/libslic3r/PrintConfig.cpp:4548 +#: src/libslic3r/PrintConfig.cpp:4547 msgid "" "Enable reading unknown configuration values by verbosely substituting them " "with defaults." @@ -15322,7 +15429,7 @@ msgstr "" "Sta to om onbekende configuratiewaarden te lezen door woordelijk te " "substitueren met standaardwaarden." -#: src/libslic3r/PrintConfig.cpp:4549 +#: src/libslic3r/PrintConfig.cpp:4548 msgid "" "Enable reading unknown configuration values by silently substituting them " "with defaults." @@ -15330,11 +15437,11 @@ msgstr "" "Sta to om onbekende configuratiewaarden te lezen door zonder melding te " "substitueren met standaardwaarden." -#: src/libslic3r/PrintConfig.cpp:4553 +#: src/libslic3r/PrintConfig.cpp:4552 msgid "Load config file" msgstr "Laad configuratiebestand" -#: src/libslic3r/PrintConfig.cpp:4554 +#: src/libslic3r/PrintConfig.cpp:4553 msgid "" "Load configuration from the specified file. It can be used more than once to " "load options from multiple files." @@ -15342,11 +15449,11 @@ msgstr "" "Laad configuratie uit een specifiek bestand. Dit kan meerdere keren gebruikt " "worden om instellingen uit meerdere bestanden te laden." -#: src/libslic3r/PrintConfig.cpp:4557 +#: src/libslic3r/PrintConfig.cpp:4556 msgid "Output File" msgstr "Outputbestand" -#: src/libslic3r/PrintConfig.cpp:4558 +#: src/libslic3r/PrintConfig.cpp:4557 msgid "" "The file where the output will be written (if not specified, it will be " "based on the input file)." @@ -15354,11 +15461,11 @@ msgstr "" "Het bestand waaroverheen wordt geschreven (als dit niet aangegeven is, wort " "dit gebaseerd op het inputbestand)." -#: src/libslic3r/PrintConfig.cpp:4562 +#: src/libslic3r/PrintConfig.cpp:4561 msgid "Single instance mode" msgstr "Enkele instantiemodus" -#: src/libslic3r/PrintConfig.cpp:4563 +#: src/libslic3r/PrintConfig.cpp:4562 msgid "" "If enabled, the command line arguments are sent to an existing instance of " "GUI PrusaSlicer, or an existing PrusaSlicer window is activated. Overrides " @@ -15369,11 +15476,11 @@ msgstr "" "gestuurd. Dit overschrijft de \"enkele instantie\"-configuratiewaarde van de " "programmavoorkeuren." -#: src/libslic3r/PrintConfig.cpp:4574 +#: src/libslic3r/PrintConfig.cpp:4573 msgid "Data directory" msgstr "Bestandslocatie voor de data" -#: src/libslic3r/PrintConfig.cpp:4575 +#: src/libslic3r/PrintConfig.cpp:4574 msgid "" "Load and store settings at the given directory. This is useful for " "maintaining different profiles or including configurations from a network " @@ -15383,11 +15490,11 @@ msgstr "" "verschillende profielen of het opnemen van configuraties van een " "netwerkopslag." -#: src/libslic3r/PrintConfig.cpp:4578 +#: src/libslic3r/PrintConfig.cpp:4577 msgid "Logging level" msgstr "Logboekniveau" -#: src/libslic3r/PrintConfig.cpp:4579 +#: src/libslic3r/PrintConfig.cpp:4578 msgid "" "Sets logging sensitivity. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" "trace\n" @@ -15397,11 +15504,11 @@ msgstr "" "debug, 5: traceer\n" "Voorbeeld: loglevel = 2 geeft fataal-, fout- en waarschuwingslevelberichten." -#: src/libslic3r/PrintConfig.cpp:4585 +#: src/libslic3r/PrintConfig.cpp:4584 msgid "Render with a software renderer" msgstr "Render met software-renderer" -#: src/libslic3r/PrintConfig.cpp:4586 +#: src/libslic3r/PrintConfig.cpp:4585 msgid "" "Render with a software renderer. The bundled MESA software renderer is " "loaded instead of the default OpenGL driver." @@ -15432,6 +15539,10 @@ msgid "" "your models using theFuzzy skinfeature? You can also use modifiers to " "apply fuzzy-skin only to a portion of your model." msgstr "" +"Oneffen oppervlak\n" +"Wist u dat u een vezelachtige textuur op de zijden van uw object kan " +"aanbrengen met de Oneffen oppervlak optie? U kunt ook modificators " +"toepassen op een oneffen oppervlak voor een gedeelte van het model." #: resources/data/hints.ini: [hint:Shapes gallery] msgid "" @@ -15440,6 +15551,11 @@ msgid "" "models as modifiers, negative volumes or as printable objects. Right-click " "the platter and selectAdd Shape - Gallery." msgstr "" +"Vormengalerij\n" +"Wist u dat PrusaSlicer een vormengalerij heeft? U kunt de vormen daaruit " +"gebruiken als modificators, negatieve volumes, of als printbare objecten. " +"Rechtermuisklik in de modelweergave en selecteer Voeg vorm toe - " +"galerij." #: resources/data/hints.ini: [hint:Arrange settings] msgid "" @@ -15447,6 +15563,9 @@ msgid "" "Did you know that you can right-click theArrange iconto adjust the " "size of the gap between objects and to allow automatic rotations?" msgstr "" +"Schikken-instellingen\n" +"Wist u dat u met de rechtermuisklik op het Schikken icoon de afstand " +"tussen de objecten en automatisch roteren kunt instellen?" #: resources/data/hints.ini: [hint:Negative volume] msgid "" @@ -15456,6 +15575,11 @@ msgid "" "holes directly in PrusaSlicer. Read more in the documentation. (Requires " "Advanced or Expert mode.)" msgstr "" +"Negatief volume\n" +"Wist u dat u volumes van elkaar kunt aftrekken met een negatief volume als " +"modificator? Daarmee kunt u bijvoorbeeld makkelijk verschaalbare gaten " +"aanbrengen, direct in PrusaSlicer. Lees meer in de documentatie (vereist " +"geavanceerde- of expertmodus)." #: resources/data/hints.ini: [hint:Simplify mesh] msgid "" @@ -15464,6 +15588,10 @@ msgid "" "Simplify mesh feature? Right-click the model and select Simplify model. Read " "more in the documentation." msgstr "" +"Mesh vereenvoudigen\n" +"Wist u dat het u het aantal facetten van een mesh kunt reduceren met de Mesh " +"vereenvoudigen optie? Rechtermuisklik op het model en selecteer Mesh " +"vereenvoudigen. Lees meer in de documentatie." #: resources/data/hints.ini: [hint:Reload from disk] msgid "" @@ -15472,6 +15600,10 @@ msgid "" "simply reload it in PrusaSlicer? Right-click the model in the 3D view and " "choose Reload from disk. Read more in the documentation." msgstr "" +"Herlaad van schijf\n" +"Wist u dat als u een nieuwere versie van het model heeft gemaakt, u deze " +"eenvoudig kunt herladen in PrusaSlicer? Rechtermuisklik op het model in de " +"modelweergave en kies Herlaad van schijf. Lees meer in de documentatie." #: resources/data/hints.ini: [hint:Hiding sidebar] msgid "" @@ -15479,6 +15611,9 @@ msgid "" "Did you know that you can hide the right sidebar using the shortcut Shift" "+Tab? You can also enable the icon for this from thePreferences." msgstr "" +"Verberg zijbalk\n" +"Wist u dat u de rechter zijbalk kan verbergen met de sneltoets Shift+Tab? U kunt ook het icoontje aanzetten via de Voorkeuren." #: resources/data/hints.ini: [hint:Perspective camera] msgid "" @@ -15486,6 +15621,9 @@ msgid "" "Did you know that you can use the K key to quickly switch between an " "orthographic and perspective camera?" msgstr "" +"Perspectiefweergave\n" +"Wist u dat u de K-toets kunt gebruiken om snel te schakelen tussen " +"orthografische en perspectiefweergave?" #: resources/data/hints.ini: [hint:Camera Views] msgid "" @@ -15493,6 +15631,9 @@ msgid "" "Did you know that you can use the number keys 0-6 to quickly switch " "between predefined camera angles?" msgstr "" +"Weergave\n" +"Wist us dat u de getallen 0-6 kunt gebruiken voor het snel schakelen " +"tussen vooraf ingestelde camerahoeken?" #: resources/data/hints.ini: [hint:Place on face] msgid "" @@ -15501,6 +15642,10 @@ msgid "" "sits on the print bed? Select thePlace on facefunction or press the " "F key." msgstr "" +"Plaats op vlak\n" +"Wist u dat u snel een model zo kan oriënteren dat het met een vlak van het " +"model op het bed geplaatst wordt? Selecteer Plaats op vlak-functie of " +"druk op de F-toets." #: resources/data/hints.ini: [hint:Set number of instances] msgid "" @@ -15508,6 +15653,9 @@ msgid "" "Did you know that you can right-click a model and set an exact number of " "instances instead of copy-pasting it several times?" msgstr "" +"Stel aantal instanties in\n" +"Wist u dat u met de rechtermuisklik op een model een exact aantal instanties " +"kan instellen zonder meerdere keren te kopiëren en plakken?" #: resources/data/hints.ini: [hint:Combine infill] msgid "" @@ -15516,6 +15664,10 @@ msgid "" "compared to perimeters to save print time using the settingCombine infill " "every." msgstr "" +"Combineer vulling\n" +"Wist u dat u tijd kunt besparen door de laagdikte van de vulling te " +"vermenigvuldigen ten opzichte van die van de perimeters met de instelling " +"Combineer vulling elke." #: resources/data/hints.ini: [hint:Variable layer height] msgid "" @@ -15524,6 +15676,10 @@ msgid "" "different layer height and smooth the transitions between them? Try " "theVariable layer height tool. (Not available for SLA printers.)" msgstr "" +"Variabele laagdikte\n" +"Wist u dat u verschillende delen van uw model kunt printen met een " +"verschillende laagdikte om zo transities tussen delen vloeiender te maken? " +"Probeer de Variabele laagdikte. (Niet beschikbaar voor SLA printers.)" #: resources/data/hints.ini: [hint:Undo/redo history] msgid "" @@ -15531,6 +15687,10 @@ msgid "" "Did you know that you can right-click theundo/redo arrowsto see the " "history of changes and to undo or redo several actions at once?" msgstr "" +"Ongedaan maken / Opnieuw doen lijst\n" +"Wist u dat u met de rechtermuisklik op Ongedaan maken / opnieuw doen " +"pijlen kunt klikken voor een lijst van aanpassingen en meerdere acties " +"tegelijk kunt doen?" #: resources/data/hints.ini: [hint:Different layer height for each model] msgid "" @@ -15540,6 +15700,10 @@ msgid "" "Perimeters and adjust the values in the right panel. Read more in the " "documentation." msgstr "" +"Verschillende laagdikte voor elk model\n" +"Wist u dat u elk model op het bed met een andere laagdikte kunt printen? " +"Rechtermuisklik op het model in de modelweergave, kies Lagen en Perimeters " +"en pas de waarde aan in het rechter menu. Lees meer in de documentatie." #: resources/data/hints.ini: [hint:Solid infill threshold area] msgid "" @@ -15548,6 +15712,10 @@ msgid "" "section be filled with solid infill automatically? Set theSolid infill " "threshold area. (Expert mode only.)" msgstr "" +"Dichte vulling bij oppervlak\n" +"Wist u dat u delen van uw model met een klein doorsnee-oppervlak automatisch " +"met dichte vulling kan vullen? Stel de optie Dichte vulling bij " +"oppervlak in. (alleen in expertmodus)." #: resources/data/hints.ini: [hint:Search functionality] msgid "" @@ -15555,6 +15723,10 @@ msgid "" "Did you know that you use theSearchtool to quickly find a specific " "PrusaSlicer setting? Or use the familiar shortcut Ctrl+F." msgstr "" +"Zoekfuncties\n" +"Wist u dat u de Zoekfunctie kunt gebruiken om snel een specifieke " +"instelling in PrusaSlicer te vinden? Of gebruik de bekende sneltoets Ctrl" +"+F." #: resources/data/hints.ini: [hint:Box selection] msgid "" @@ -15562,6 +15734,10 @@ msgid "" "Did you know that you can do a box selection with Shift+Mouse drag? You can " "also box-deselect objects with Alt+Mouse drag." msgstr "" +"Boxselectie\n" +"Wist u dat u een boxselectie kunt doen door Shift in te drukken en dan met " +"de muis te slepen? U kunt ook deselecteren op deze manier met Alt+muis " +"bewegen." #: resources/data/hints.ini: [hint:Zoom on selected objects or all if none #: selected] @@ -15571,6 +15747,9 @@ msgid "" "b> key? If none are selected, the camera will zoom on all objects in the " "scene." msgstr "" +"Zoom op geselecteerde objecten of op alle objecten als geen geselecteerd is\n" +"Wist u dat u in kunt zoomen op geselecteerde objecten door te drukken op de " +"Z-toets? Als niets geselecteerd is, wordt ingezoomd op alle objecten." #: resources/data/hints.ini: [hint:Printable toggle] msgid "" @@ -15579,6 +15758,10 @@ msgid "" "model without having to move or delete it? Toggle the Printable property of " "a model from the Right-click context menu." msgstr "" +"Als printbaar instellen\n" +"Wist u dat u G-code-generatie kunt uitzetten voor geselecteerde modellen " +"zonder deze te verplaatsen of verwijderen? Zet de Printbaar-optie aan of uit " +"van een model met de rechtermuisklik op een object." #: resources/data/hints.ini: [hint:Mirror] msgid "" @@ -15586,6 +15769,10 @@ msgid "" "Did you know that you can mirror the selected model to create a reversed " "version of it? Right-click the model, select Mirror and pick the mirror axis." msgstr "" +"Spiegelen\n" +"Wist u dat u de geselecteerde modellen kunt spiegelen om een omgekeerd " +"object te verkrijgen? Rechtermuisklik op het model, kies voor Spiegelen en " +"kies over welke as gespiegeld moet worden." #: resources/data/hints.ini: [hint:PageUp / PageDown quick rotation by 45 #: degrees] @@ -15595,6 +15782,10 @@ msgid "" "around the Z-axis clockwise or counter-clockwise by pressing Page Up " "or Page Down respectively?" msgstr "" +"PageUp / PageDown snel roteren bij 45 graden\n" +"Wist u dat u snel modellen kunt roteren over 45 graden rond de Z-as (met de " +"klok mee of er tegenin) door te klikken op de PageUp- of PageDown-toetsen?" #: resources/data/hints.ini: [hint:Load config from G-code] msgid "" @@ -15604,6 +15795,11 @@ msgid "" "can use File-Import-Import SL1 / SL1S archive, which also lets you " "reconstruct 3D models from the voxel data." msgstr "" +"Laad configuratie van G-code\n" +"Wist u dat u een configuratie voor printen, filament, en printerprofielen " +"kunt laden door te klikken op Bestand - Importeer - Importeer configuratie? " +"Dit geldt ook voor SL1 / SL1S archieven die u een 3D-model laten " +"reconstrueren van de voxel-data." #: resources/data/hints.ini: [hint:Ironing] msgid "" @@ -15613,6 +15809,11 @@ msgid "" "holes and flatten any lifted plastic. Read more in the documentation. " "(Requires Advanced or Expert mode.)" msgstr "" +"Strijken\n" +"Wist u dat u een glad bovenoppervlak kunt maken door deze te laten strijken? " +"De nozzle gaat dan nogmaals over het oppervlak om kleine gaatjes te vullen " +"en oneffenheden plat te drukken (vereist geavanceerde of expertmodus). Lees " +"meer in de documentatie." #: resources/data/hints.ini: [hint:Paint-on supports] msgid "" @@ -15621,6 +15822,10 @@ msgid "" "where supports should be enforced or blocked? Try thePaint-on supportsfeature. (Requires Advanced or Expert mode.)" msgstr "" +"Support schilderen\n" +"Wist u dat u direct op het model regios kunt schilderen waar support moet of " +"niet mag worden geplaatst? Probeer de support schilderen-functie " +"(vereist geavanceerde of expertmodus)." #: resources/data/hints.ini: [hint:Paint-on seam] msgid "" @@ -15629,6 +15834,10 @@ msgid "" "place the start/endpoint of each perimeter loop? Try theSeam paintingfeature. (Requires Advanced or Expert mode.)" msgstr "" +"Naad schilderen\n" +"Wist u dat u direct op het model regios kunt schilderen waar de naad zich " +"moet bevinden? Probeer de Naad schilderen-functie (vereist " +"geavanceerde of expertmodus)." #: resources/data/hints.ini: [hint:Insert Pause] msgid "" @@ -15638,6 +15847,11 @@ msgid "" "(M601). This can be used to insert magnets, weights or nuts into your " "prints. Read more in the documentation." msgstr "" +"Pauze invoegen\n" +"Wist u dat u een pauze kunt inplannen op een specifieke laag? " +"Rechtermuisklik op de slider in de sliceweergave en selecteer Voeg pauze toe " +"(M601). Dit kan handig zijn voor het plaatsen van magneetjes, gewichtjes, " +"moertjes, etc. in het model. Lees meer in de documentatie." #: resources/data/hints.ini: [hint:Insert Custom G-code] msgid "" @@ -15647,6 +15861,11 @@ msgid "" "custom G-code. With this function you can, for example, create a temperature " "tower. Read more in the documentation." msgstr "" +"Custom G-code invoegen\n" +"Wist u dat u een custom G-code kunt invoegen op een specifieke laag? " +"Linkermuisklik op de laag in de voorbeeldweergave. Dan rechtermuisklik het " +"plus-icoon en selecteer Voeg custom G-code toe. Met deze functie kunt u " +"bijvoorbeeld een temperatuurtoren printen. Lees meer in de documentatie." #: resources/data/hints.ini: [hint:Configuration snapshots] msgid "" @@ -15655,6 +15874,10 @@ msgid "" "user profiles? You can view and move back and forth between snapshots using " "the Configuration - Configuration snapshots menu." msgstr "" +"Configuratiesnapshots\n" +"Wist u dat u terug kunt gaan naar een complete backup van alle systeem- en " +"gebruikersprofielen? U kunt heen en weer bewegen tussen snapshots door " +"middel van het Configuratiesnapshots-menu." #: resources/data/hints.ini: [hint:Minimum shell thickness] msgid "" @@ -15663,6 +15886,10 @@ msgid "" "define theMinimum shell thicknessin millimeters? This feature is " "especially useful when using the variable layer height function." msgstr "" +"Minimale shelldikte\n" +"Wist u dat u in plaats van het aantal boven- en onderlagen de Minimale " +"shelldikte kunt aangeven? Deze optie is handig wanneer een variabele " +"laagdikte wordt gebruikt." #: resources/data/hints.ini: [hint:Settings in non-modal window] msgid "" @@ -15671,6 +15898,11 @@ msgid "" "means you can have settings open on one screen and the G-code Preview on the " "other. Go to thePreferencesand select Settings in non-modal window." msgstr "" +"Instellingen in niet-modaal venster\n" +"Wist u dat u de instellingen kunt openen in een niet-modaal venster? Dit " +"houdt in dat u de instellingen open kunt hebben staan op één scherm en de " +"sliceweergave op een ander scherm. Ga naar Voorkeuren en selecteer " +"Instellingen in niet-modaal venster." #: resources/data/hints.ini: [hint:Adaptive infills] msgid "" @@ -15679,6 +15911,10 @@ msgid "" "to decrease the print time and lower the filament consumption? Read more in " "the documentation." msgstr "" +"Adaptieve vulling\n" +"Wist u dat u adaptief kubische en ondersteunend kubische vulling kunt " +"gebruiken om de printtijd te verkorten en de hoeveelheid filament te " +"reduceren? Lees meer in de documentatie." #: resources/data/hints.ini: [hint:Lightning infill] msgid "" @@ -15687,6 +15923,10 @@ msgid "" "surfaces, save a lot of the filament, and decrease the print time? Read more " "in the documentation." msgstr "" +"Bliksemvulling\n" +"Wist u dat u bliksemvulling kunt toepassen om alleen topvlakken te " +"ondersteunen? Dit bespaart veel filament en reduceert de printtijd. Lees " +"meer in de documentatie." #: resources/data/hints.ini: [hint:Fullscreen mode] msgid "" @@ -15694,6 +15934,9 @@ msgid "" "Did you know that you can switch PrusaSlicer to fullscreen mode? Use the " "F11 hotkey." msgstr "" +"Volledig scherm\n" +"Wist u dat u in PrusaSlicer kunt wisselen naar volledig scherm? Gebruik " +"daarvoor de F11-toets." #: ../src/common/debugrpt.cpp:586 msgid "" diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index ecb157218..500028525 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -426,7 +426,9 @@ int CLI::run(int argc, char **argv) o->cut(Z, m_config.opt_float("cut"), &out); } #else - model.objects.front()->cut(0, m_config.opt_float("cut"), ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::FlipLower); +// model.objects.front()->cut(0, m_config.opt_float("cut"), ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::FlipLower); + model.objects.front()->cut(0, Geometry::assemble_transform(m_config.opt_float("cut")* Vec3d::UnitZ()), + ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::PlaceOnCutUpper); #endif model.delete_object(size_t(0)); } diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index f2c3ef083..678c8fe20 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -140,6 +140,7 @@ namespace ImGui const wchar_t CancelButton = 0x14; const wchar_t CancelHoverButton = 0x15; // const wchar_t VarLayerHeightMarker = 0x16; + const wchar_t RevertButton = 0x16; const wchar_t RightArrowButton = 0x18; const wchar_t RightArrowHoverButton = 0x19; @@ -168,6 +169,10 @@ namespace ImGui const wchar_t LegendCOG = 0x2615; const wchar_t LegendShells = 0x2616; const wchar_t LegendToolMarker = 0x2617; + const wchar_t WarningMarkerSmall = 0x2618; + const wchar_t ExpandBtn = 0x2619; + const wchar_t CollapseBtn = 0x2620; + const wchar_t InfoMarkerSmall = 0x2621; // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/libslic3r/AStar.hpp b/src/libslic3r/AStar.hpp index b35b6a4af..630257a81 100644 --- a/src/libslic3r/AStar.hpp +++ b/src/libslic3r/AStar.hpp @@ -4,11 +4,14 @@ #include // std::isinf() is here #include -#include "libslic3r/Point.hpp" #include "libslic3r/MutablePriorityQueue.hpp" namespace Slic3r { namespace astar { +// Borrowed from C++20 +template +using remove_cvref_t = std::remove_cv_t>; + // Input interface for the Astar algorithm. Specialize this struct for a // particular type and implement all the 4 methods and specify the Node type // to register the new type for the astar implementation. diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp index 7e22127cd..4de88101c 100644 --- a/src/libslic3r/ExPolygon.cpp +++ b/src/libslic3r/ExPolygon.cpp @@ -19,6 +19,13 @@ void ExPolygon::scale(double factor) hole.scale(factor); } +void ExPolygon::scale(double factor_x, double factor_y) +{ + contour.scale(factor_x, factor_y); + for (Polygon &hole : holes) + hole.scale(factor_x, factor_y); +} + void ExPolygon::translate(const Point &p) { contour.translate(p); diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 179d0aafa..edfe9c874 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -37,6 +37,7 @@ public: void clear() { contour.points.clear(); holes.clear(); } void scale(double factor); + void scale(double factor_x, double factor_y); void translate(double x, double y) { this->translate(Point(coord_t(x), coord_t(y))); } void translate(const Point &vector); void rotate(double angle); diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index bfbdbbc01..d4923c607 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -79,6 +79,7 @@ const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/Prusa_Slicer_layer_config const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt"; const std::string SLA_DRAIN_HOLES_FILE = "Metadata/Slic3r_PE_sla_drain_holes.txt"; const std::string CUSTOM_GCODE_PER_PRINT_Z_FILE = "Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml"; +const std::string CUT_INFORMATION_FILE = "Metadata/Prusa_Slicer_cut_information.xml"; static constexpr const char* MODEL_TAG = "model"; static constexpr const char* RESOURCES_TAG = "resources"; @@ -434,6 +435,19 @@ namespace Slic3r { VolumeMetadataList volumes; }; + struct CutObjectInfo + { + struct Connector + { + int volume_id; + int type; + float r_tolerance; + float h_tolerance; + }; + CutObjectBase id; + std::vector connectors; + }; + // Map from a 1 based 3MF object ID to a 0 based ModelObject index inside m_model->objects. typedef std::map IdToModelObjectMap; typedef std::map IdToAliasesMap; @@ -442,6 +456,7 @@ namespace Slic3r { typedef std::map IdToGeometryMap; typedef std::map> IdToLayerHeightsProfileMap; typedef std::map IdToLayerConfigRangesMap; + typedef std::map IdToCutObjectInfoMap; typedef std::map> IdToSlaSupportPointsMap; typedef std::map> IdToSlaDrainHolesMap; @@ -469,6 +484,7 @@ namespace Slic3r { IdToGeometryMap m_geometries; CurrentConfig m_curr_config; IdToMetadataMap m_objects_metadata; + IdToCutObjectInfoMap m_cut_object_infos; IdToLayerHeightsProfileMap m_layer_heights_profiles; IdToLayerConfigRangesMap m_layer_config_ranges; IdToSlaSupportPointsMap m_sla_support_points; @@ -500,6 +516,7 @@ namespace Slic3r { bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions); bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); + void _extract_cut_information_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions); void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); void _extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions); void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); @@ -704,6 +721,10 @@ namespace Slic3r { // extract slic3r layer heights profile file _extract_layer_heights_profile_config_from_archive(archive, stat); } + else if (boost::algorithm::iequals(name, CUT_INFORMATION_FILE)) { + // extract slic3r layer config ranges file + _extract_cut_information_from_archive(archive, stat, config_substitutions); + } else if (boost::algorithm::iequals(name, LAYER_CONFIG_RANGES_FILE)) { // extract slic3r layer config ranges file _extract_layer_config_ranges_from_archive(archive, stat, config_substitutions); @@ -846,6 +867,19 @@ namespace Slic3r { if (!_generate_volumes(*model_object, obj_geometry->second, *volumes_ptr, config_substitutions)) return false; + + // Apply cut information for object if any was loaded + // m_cut_object_ids are indexed by a 1 based model object index. + IdToCutObjectInfoMap::iterator cut_object_info = m_cut_object_infos.find(object.second + 1); + if (cut_object_info != m_cut_object_infos.end()) { + model_object->cut_id = cut_object_info->second.id; + + for (auto connector : cut_object_info->second.connectors) { + assert(0 <= connector.volume_id && connector.volume_id <= int(model_object->volumes.size())); + model_object->volumes[connector.volume_id]->cut_info = + ModelVolume::CutInfo(CutConnectorType(connector.type), connector.r_tolerance, connector.h_tolerance, true); + } + } } // If instances contain a single volume, the volume offset should be 0,0,0 @@ -972,6 +1006,65 @@ namespace Slic3r { return true; } + void _3MF_Importer::_extract_cut_information_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions) + { + if (stat.m_uncomp_size > 0) { + std::string buffer((size_t)stat.m_uncomp_size, 0); + mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); + if (res == 0) { + add_error("Error while reading cut information data to buffer"); + return; + } + + std::istringstream iss(buffer); // wrap returned xml to istringstream + pt::ptree objects_tree; + pt::read_xml(iss, objects_tree); + + for (const auto& object : objects_tree.get_child("objects")) { + pt::ptree object_tree = object.second; + int obj_idx = object_tree.get(".id", -1); + if (obj_idx <= 0) { + add_error("Found invalid object id"); + continue; + } + + IdToCutObjectInfoMap::iterator object_item = m_cut_object_infos.find(obj_idx); + if (object_item != m_cut_object_infos.end()) { + add_error("Found duplicated cut_object_id"); + continue; + } + + CutObjectBase cut_id; + std::vector connectors; + + for (const auto& obj_cut_info : object_tree) { + if (obj_cut_info.first == "cut_id") { + pt::ptree cut_id_tree = obj_cut_info.second; + cut_id = CutObjectBase(ObjectID( cut_id_tree.get(".id")), + cut_id_tree.get(".check_sum"), + cut_id_tree.get(".connectors_cnt")); + } + if (obj_cut_info.first == "connectors") { + pt::ptree cut_connectors_tree = obj_cut_info.second; + for (const auto& cut_connector : cut_connectors_tree) { + if (cut_connector.first != "connector") + continue; + pt::ptree connector_tree = cut_connector.second; + CutObjectInfo::Connector connector = {connector_tree.get(".volume_id"), + connector_tree.get(".type"), + connector_tree.get(".r_tolerance"), + connector_tree.get(".h_tolerance")}; + connectors.emplace_back(connector); + } + } + } + + CutObjectInfo cut_info {cut_id, connectors}; + m_cut_object_infos.insert({ obj_idx, cut_info }); + } + } + } + void _3MF_Importer::_extract_print_config_from_archive( mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions, @@ -2309,6 +2402,7 @@ namespace Slic3r { bool _add_object_to_model_stream(mz_zip_writer_staged_context &context, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items, VolumeToOffsetsMap& volumes_offsets); bool _add_mesh_to_object_stream(mz_zip_writer_staged_context &context, ModelObject& object, VolumeToOffsetsMap& volumes_offsets); bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items); + bool _add_cut_information_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model); @@ -2371,6 +2465,15 @@ namespace Slic3r { return false; } + // Adds file with information for object cut ("Metadata/Slic3r_PE_cut_information.txt"). + // All information for object cut of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model. + // The index differes from the index of an object ID of an object instance of a 3MF file! + if (!_add_cut_information_file_to_archive(archive, model)) { + close_zip_writer(&archive); + boost::filesystem::remove(filename); + return false; + } + // Adds layer height profile file ("Metadata/Slic3r_PE_layer_heights_profile.txt"). // All layer height profiles of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model. // The index differes from the index of an object ID of an object instance of a 3MF file! @@ -2874,6 +2977,67 @@ namespace Slic3r { return true; } + bool _3MF_Exporter::_add_cut_information_file_to_archive(mz_zip_archive& archive, Model& model) + { + std::string out = ""; + pt::ptree tree; + + unsigned int object_cnt = 0; + for (const ModelObject* object : model.objects) { + object_cnt++; + pt::ptree& obj_tree = tree.add("objects.object", ""); + + obj_tree.put(".id", object_cnt); + + // Store info for cut_id + pt::ptree& cut_id_tree = obj_tree.add("cut_id", ""); + + // store cut_id atributes + cut_id_tree.put(".id", object->cut_id.id().id); + cut_id_tree.put(".check_sum", object->cut_id.check_sum()); + cut_id_tree.put(".connectors_cnt", object->cut_id.connectors_cnt()); + + int volume_idx = -1; + for (const ModelVolume* volume : object->volumes) { + ++volume_idx; + if (volume->is_cut_connector()) { + pt::ptree& connectors_tree = obj_tree.add("connectors.connector", ""); + connectors_tree.put(".volume_id", volume_idx); + connectors_tree.put(".type", int(volume->cut_info.connector_type)); + connectors_tree.put(".r_tolerance", volume->cut_info.radius_tolerance); + connectors_tree.put(".h_tolerance", volume->cut_info.height_tolerance); + } + } + } + + if (!tree.empty()) { + std::ostringstream oss; + pt::write_xml(oss, tree); + out = oss.str(); + + // Post processing("beautification") of the output string for a better preview + boost::replace_all(out, ">\n \n ", ">\n "); + boost::replace_all(out, ">\n ", ">\n "); + boost::replace_all(out, ">\n ", ">\n "); + boost::replace_all(out, ">", ">\n "); + // OR just + boost::replace_all(out, "><", ">\n<"); + } + + if (!out.empty()) { + if (!mz_zip_writer_add_mem(&archive, CUT_INFORMATION_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) { + add_error("Unable to add cut information file to archive"); + return false; + } + } + + return true; + } + bool _3MF_Exporter::_add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model) { assert(is_decimal_separator_point()); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 9f3c142f8..3c4e00454 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -464,12 +464,25 @@ static constexpr const double volume_threshold_inches = 9.0; // 9 = 3*3*3; bool Model::looks_like_imperial_units() const { - if (this->objects.size() == 0) + if (this->objects.empty()) return false; for (ModelObject* obj : this->objects) - if (obj->get_object_stl_stats().volume < volume_threshold_inches) - return true; + if (obj->get_object_stl_stats().volume < volume_threshold_inches) { + if (!obj->is_cut()) + return true; + bool all_cut_parts_look_like_imperial_units = true; + for (ModelObject* obj_other : this->objects) { + if (obj_other == obj) + continue; + if (obj_other->cut_id.is_equal(obj->cut_id) && obj_other->get_object_stl_stats().volume >= volume_threshold_inches) { + all_cut_parts_look_like_imperial_units = false; + break; + } + } + if (all_cut_parts_look_like_imperial_units) + return true; + } return false; } @@ -613,6 +626,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs) this->layer_height_profile = rhs.layer_height_profile; this->printable = rhs.printable; this->origin_translation = rhs.origin_translation; + this->cut_id.copy(rhs.cut_id); m_bounding_box = rhs.m_bounding_box; m_bounding_box_valid = rhs.m_bounding_box_valid; m_raw_bounding_box = rhs.m_raw_bounding_box; @@ -715,6 +729,7 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other, ModelVolumeType t ModelVolume* v = new ModelVolume(this, other); if (type != ModelVolumeType::INVALID && v->type() != type) v->set_type(type); + v->cut_info = other.cut_info; this->volumes.push_back(v); // The volume should already be centered at this point of time when copying shared pointers of the triangle mesh and convex hull. // v->center_geometry_after_creation(); @@ -1189,34 +1204,355 @@ size_t ModelObject::parts_count() const return num; } -ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, ModelObjectCutAttributes attributes) +bool ModelObject::has_connectors() const { - if (! attributes.has(ModelObjectCutAttribute::KeepUpper) && ! attributes.has(ModelObjectCutAttribute::KeepLower)) + assert(is_cut()); + for (const ModelVolume* v : this->volumes) + if (v->cut_info.is_connector) + return true; + + return false; +} + +indexed_triangle_set ModelObject::get_connector_mesh(CutConnectorAttributes connector_attributes) +{ + indexed_triangle_set connector_mesh; + + int sectorCount {1}; + switch (CutConnectorShape(connector_attributes.shape)) { + case CutConnectorShape::Triangle: + sectorCount = 3; + break; + case CutConnectorShape::Square: + sectorCount = 4; + break; + case CutConnectorShape::Circle: + sectorCount = 360; + break; + case CutConnectorShape::Hexagon: + sectorCount = 6; + break; + default: + break; + } + + if (connector_attributes.style == CutConnectorStyle::Prizm) + connector_mesh = its_make_cylinder(1.0, 1.0, (2 * PI / sectorCount)); + else if (connector_attributes.type == CutConnectorType::Plug) + connector_mesh = its_make_cone(1.0, 1.0, (2 * PI / sectorCount)); + else + connector_mesh = its_make_frustum_dowel(1.0, 1.0, sectorCount); + + return connector_mesh; +} + +void ModelObject::apply_cut_connectors(const std::string& new_name) +{ + if (cut_connectors.empty()) + return; + + using namespace Geometry; + + size_t connector_id = cut_id.connectors_cnt(); + for (const CutConnector& connector : cut_connectors) { + TriangleMesh mesh = TriangleMesh(get_connector_mesh(connector.attribs)); + // Mesh will be centered when loading. + ModelVolume* new_volume = add_volume(std::move(mesh), ModelVolumeType::NEGATIVE_VOLUME); + + // Transform the new modifier to be aligned inside the instance + new_volume->set_transformation(assemble_transform(connector.pos) * connector.rotation_m * + scale_transform(Vec3f(connector.radius, connector.radius, connector.height).cast())); + + new_volume->cut_info = { connector.attribs.type, connector.radius_tolerance, connector.height_tolerance }; + new_volume->name = new_name + "-" + std::to_string(++connector_id); + } + cut_id.increase_connectors_cnt(cut_connectors.size()); + + // delete all connectors + cut_connectors.clear(); +} + +void ModelObject::invalidate_cut() +{ + this->cut_id.invalidate(); + for (ModelVolume* volume : this->volumes) + volume->invalidate_cut_info(); +} + +void ModelObject::synchronize_model_after_cut() +{ + for (ModelObject* obj : m_model->objects) { + if (obj == this || obj->cut_id.is_equal(this->cut_id)) + continue; + if (obj->is_cut() && obj->cut_id.has_same_id(this->cut_id)) + obj->cut_id.copy(this->cut_id); + } +} + +void ModelObject::apply_cut_attributes(ModelObjectCutAttributes attributes) +{ + // we don't save cut information, if result will not contains all parts of initial object + if (!attributes.has(ModelObjectCutAttribute::KeepUpper) || !attributes.has(ModelObjectCutAttribute::KeepLower)) + return; + + if (cut_id.id().invalid()) + cut_id.init(); + { + int cut_obj_cnt = -1; + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) cut_obj_cnt++; + if (attributes.has(ModelObjectCutAttribute::KeepLower)) cut_obj_cnt++; + if (attributes.has(ModelObjectCutAttribute::CreateDowels)) cut_obj_cnt++; + if (cut_obj_cnt > 0) + cut_id.increase_check_sum(size_t(cut_obj_cnt)); + } +} + +void ModelObject::clone_for_cut(ModelObject** obj) +{ + (*obj) = ModelObject::new_clone(*this); + (*obj)->set_model(nullptr); + (*obj)->sla_support_points.clear(); + (*obj)->sla_drain_holes.clear(); + (*obj)->sla_points_status = sla::PointsStatus::NoPoints; + (*obj)->clear_volumes(); + (*obj)->input_file.clear(); +} + +void ModelVolume::reset_extra_facets() +{ + this->supported_facets.reset(); + this->seam_facets.reset(); + this->mmu_segmentation_facets.reset(); +} + +void ModelVolume::apply_tolerance() +{ + assert(cut_info.is_connector); + if (cut_info.is_processed) + return; + + Vec3d sf = get_scaling_factor(); +/* + // correct Z offset in respect to the new size + Vec3d pos = vol->get_offset(); + pos[Z] += sf[Z] * 0.5 * vol->cut_info.height_tolerance; + vol->set_offset(pos); +*/ + // make a "hole" wider + sf[X] *= 1. + double(cut_info.radius_tolerance); + sf[Y] *= 1. + double(cut_info.radius_tolerance); + + // make a "hole" dipper + sf[Z] *= 1. + double(cut_info.height_tolerance); + + set_scaling_factor(sf); +} + +void ModelObject::process_connector_cut(ModelVolume* volume, ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower, + std::vector& dowels, Vec3d& local_dowels_displace) +{ + assert(volume->cut_info.is_connector); + volume->cut_info.set_processed(); + + const auto volume_matrix = volume->get_matrix(); + + // ! Don't apply instance transformation for the conntectors. + // This transformation is already there + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) { + ModelVolume* vol = upper->add_volume(*volume); + vol->set_transformation(volume_matrix); + vol->apply_tolerance(); + } + if (attributes.has(ModelObjectCutAttribute::KeepLower)) { + ModelVolume* vol = lower->add_volume(*volume); + vol->set_transformation(volume_matrix); + + if (volume->cut_info.connector_type == CutConnectorType::Dowel) + vol->apply_tolerance(); + else + // for lower part change type of connector from NEGATIVE_VOLUME to MODEL_PART if this connector is a plug + vol->set_type(ModelVolumeType::MODEL_PART); + } + if (volume->cut_info.connector_type == CutConnectorType::Dowel && + attributes.has(ModelObjectCutAttribute::CreateDowels)) { + ModelObject* dowel{ nullptr }; + // Clone the object to duplicate instances, materials etc. + clone_for_cut(&dowel); + + // add one more solid part same as connector if this connector is a dowel + ModelVolume* vol = dowel->add_volume(*volume); + vol->set_type(ModelVolumeType::MODEL_PART); + + // But discard rotation and Z-offset for this volume + vol->set_rotation(Vec3d::Zero()); + vol->set_offset(Z, 0.0); + + // Compute the displacement (in instance coordinates) to be applied to place the dowels + local_dowels_displace = lower->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(1.0, 1.0, 0.0)); + + dowels.push_back(dowel); + } +} + +void ModelObject::process_modifier_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& inverse_cut_matrix, + ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower) +{ + const auto volume_matrix = instance_matrix * volume->get_matrix(); + + // Modifiers are not cut, but we still need to add the instance transformation + // to the modifier volume transformation to preserve their shape properly. + volume->set_transformation(Geometry::Transformation(volume_matrix)); + + // Some logic for the negative volumes/connectors. Add only needed modifiers + auto bb = volume->mesh().transformed_bounding_box(inverse_cut_matrix * volume_matrix); + bool is_crossed_by_cut = bb.min[Z] <= 0 && bb.max[Z] >= 0; + if (attributes.has(ModelObjectCutAttribute::KeepUpper) && (bb.min[Z] >= 0 || is_crossed_by_cut)) + upper->add_volume(*volume); + if (attributes.has(ModelObjectCutAttribute::KeepLower) && (bb.max[Z] <= 0 || is_crossed_by_cut)) + lower->add_volume(*volume); +} + +static void add_cut_volume(TriangleMesh& mesh, ModelObject* object, const ModelVolume* src_volume, const Transform3d& cut_matrix) +{ + if (mesh.empty()) + return; + + mesh.transform(cut_matrix); + ModelVolume* vol = object->add_volume(mesh); + + vol->name = src_volume->name; + // Don't copy the config's ID. + vol->config.assign_config(src_volume->config); + assert(vol->config.id().valid()); + assert(vol->config.id() != src_volume->config.id()); + vol->set_material(src_volume->material_id(), *src_volume->material()); + vol->cut_info = src_volume->cut_info; +} + +void ModelObject::process_solid_part_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, + ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower, Vec3d& local_displace) +{ + const auto volume_matrix = volume->get_matrix(); + + using namespace Geometry; + + const Transformation cut_transformation = Transformation(cut_matrix); + const Transform3d invert_cut_matrix = cut_transformation.get_rotation_matrix().inverse() * assemble_transform(-1 * cut_transformation.get_offset()); + + // Transform the mesh by the combined transformation matrix. + // Flip the triangles in case the composite transformation is left handed. + TriangleMesh mesh(volume->mesh()); + mesh.transform(invert_cut_matrix * instance_matrix * volume_matrix, true); + + volume->reset_mesh(); + // Reset volume transformation except for offset + const Vec3d offset = volume->get_offset(); + volume->set_transformation(Geometry::Transformation()); + volume->set_offset(offset); + + // Perform cut + + TriangleMesh upper_mesh, lower_mesh; + { + indexed_triangle_set upper_its, lower_its; + cut_mesh(mesh.its, 0.0f, &upper_its, &lower_its); + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) + upper_mesh = TriangleMesh(upper_its); + if (attributes.has(ModelObjectCutAttribute::KeepLower)) + lower_mesh = TriangleMesh(lower_its); + } + + // Add required cut parts to the objects + + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) + add_cut_volume(upper_mesh, upper, volume, cut_matrix); + + if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty()) { + add_cut_volume(lower_mesh, lower, volume, cut_matrix); + + // Compute the displacement (in instance coordinates) to be applied to place the upper parts + // The upper part displacement is set to half of the lower part bounding box + // this is done in hope at least a part of the upper part will always be visible and draggable + local_displace = lower->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(-0.5, -0.5, 0.0)); + } +} + +static void invalidate_translations(ModelObject* object, const ModelInstance* src_instance) +{ + if (!object->origin_translation.isApprox(Vec3d::Zero()) && src_instance->get_offset().isApprox(Vec3d::Zero())) { + object->center_around_origin(); + object->translate_instances(-object->origin_translation); + object->origin_translation = Vec3d::Zero(); + } + else { + object->invalidate_bounding_box(); + object->center_around_origin(); + } +} + +static void reset_instance_transformation(ModelObject* object, size_t src_instance_idx, const Transform3d& cut_matrix, + bool place_on_cut = false, bool flip = false, Vec3d local_displace = Vec3d::Zero()) +{ + using namespace Geometry; + + // Reset instance transformation except offset and Z-rotation + + for (size_t i = 0; i < object->instances.size(); ++i) { + auto& obj_instance = object->instances[i]; + const Vec3d offset = obj_instance->get_offset(); + const double rot_z = obj_instance->get_rotation().z(); + + obj_instance->set_transformation(Transformation()); + + const Vec3d displace = local_displace.isApprox(Vec3d::Zero()) ? Vec3d::Zero() : + assemble_transform(Vec3d::Zero(), obj_instance->get_rotation()) * local_displace; + obj_instance->set_offset(offset + displace); + + Vec3d rotation = Vec3d::Zero(); + if (!flip && !place_on_cut) { + if ( i != src_instance_idx) + rotation[Z] = rot_z; + } + else { + Transform3d rotation_matrix = Transform3d::Identity(); + if (flip) + rotation_matrix = rotation_transform(PI * Vec3d::UnitX()); + + if (place_on_cut) + rotation_matrix = rotation_matrix * Transformation(cut_matrix).get_rotation_matrix().inverse(); + + if (i != src_instance_idx) + rotation_matrix = rotation_transform(rot_z * Vec3d::UnitZ()) * rotation_matrix; + + rotation = Transformation(rotation_matrix).get_rotation(); + } + + obj_instance->set_rotation(rotation); + } +} + +ModelObjectPtrs ModelObject::cut(size_t instance, const Transform3d& cut_matrix, ModelObjectCutAttributes attributes) +{ + if (!attributes.has(ModelObjectCutAttribute::KeepUpper) && !attributes.has(ModelObjectCutAttribute::KeepLower)) return {}; BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - start"; + // apply cut attributes for object + apply_cut_attributes(attributes); + // Clone the object to duplicate instances, materials etc. - ModelObject* upper = attributes.has(ModelObjectCutAttribute::KeepUpper) ? ModelObject::new_clone(*this) : nullptr; - ModelObject* lower = attributes.has(ModelObjectCutAttribute::KeepLower) ? ModelObject::new_clone(*this) : nullptr; + ModelObject* upper{ nullptr }; + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) + clone_for_cut(&upper); - if (attributes.has(ModelObjectCutAttribute::KeepUpper)) { - upper->set_model(nullptr); - upper->sla_support_points.clear(); - upper->sla_drain_holes.clear(); - upper->sla_points_status = sla::PointsStatus::NoPoints; - upper->clear_volumes(); - upper->input_file.clear(); - } + ModelObject* lower{ nullptr }; + if (attributes.has(ModelObjectCutAttribute::KeepLower)) + clone_for_cut(&lower); - if (attributes.has(ModelObjectCutAttribute::KeepLower)) { - lower->set_model(nullptr); - lower->sla_support_points.clear(); - lower->sla_drain_holes.clear(); - lower->sla_points_status = sla::PointsStatus::NoPoints; - lower->clear_volumes(); - lower->input_file.clear(); - } + std::vector dowels; + + using namespace Geometry; // Because transformations are going to be applied to meshes directly, // we reset transformation of all instances and volumes, @@ -1224,128 +1560,72 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, ModelObjectCutAttr // in the transformation matrix and not applied to the mesh transform. // const auto instance_matrix = instances[instance]->get_matrix(true); - const auto instance_matrix = Geometry::assemble_transform( + const auto instance_matrix = assemble_transform( Vec3d::Zero(), // don't apply offset - instances[instance]->get_rotation().cwiseProduct(Vec3d(1.0, 1.0, 0.0)), // don't apply Z-rotation + instances[instance]->get_rotation(), instances[instance]->get_scaling_factor(), instances[instance]->get_mirror() ); - z -= instances[instance]->get_offset().z(); + const Transformation cut_transformation = Transformation(cut_matrix); + const Transform3d inverse_cut_matrix = cut_transformation.get_rotation_matrix().inverse() * assemble_transform(-1. * cut_transformation.get_offset()); // Displacement (in instance coordinates) to be applied to place the upper parts Vec3d local_displace = Vec3d::Zero(); + Vec3d local_dowels_displace = Vec3d::Zero(); - for (ModelVolume *volume : volumes) { - const auto volume_matrix = volume->get_matrix(); + for (ModelVolume* volume : volumes) { + volume->reset_extra_facets(); - volume->supported_facets.reset(); - volume->seam_facets.reset(); - volume->mmu_segmentation_facets.reset(); - - if (! volume->is_model_part()) { - // Modifiers are not cut, but we still need to add the instance transformation - // to the modifier volume transformation to preserve their shape properly. - - volume->set_transformation(Geometry::Transformation(instance_matrix * volume_matrix)); - - if (attributes.has(ModelObjectCutAttribute::KeepUpper)) - upper->add_volume(*volume); - if (attributes.has(ModelObjectCutAttribute::KeepLower)) - lower->add_volume(*volume); - } - else if (! volume->mesh().empty()) { - // Transform the mesh by the combined transformation matrix. - // Flip the triangles in case the composite transformation is left handed. - TriangleMesh mesh(volume->mesh()); - mesh.transform(instance_matrix * volume_matrix, true); - volume->reset_mesh(); - // Reset volume transformation except for offset - const Vec3d offset = volume->get_offset(); - volume->set_transformation(Geometry::Transformation()); - volume->set_offset(offset); - - // Perform cut - TriangleMesh upper_mesh, lower_mesh; - { - indexed_triangle_set upper_its, lower_its; - cut_mesh(mesh.its, float(z), &upper_its, &lower_its); - if (attributes.has(ModelObjectCutAttribute::KeepUpper)) - upper_mesh = TriangleMesh(upper_its); - if (attributes.has(ModelObjectCutAttribute::KeepLower)) - lower_mesh = TriangleMesh(lower_its); - } - - if (attributes.has(ModelObjectCutAttribute::KeepUpper) && ! upper_mesh.empty()) { - ModelVolume* vol = upper->add_volume(upper_mesh); - vol->name = volume->name; - // Don't copy the config's ID. - vol->config.assign_config(volume->config); - assert(vol->config.id().valid()); - assert(vol->config.id() != volume->config.id()); - vol->set_material(volume->material_id(), *volume->material()); - } - if (attributes.has(ModelObjectCutAttribute::KeepLower) && ! lower_mesh.empty()) { - ModelVolume* vol = lower->add_volume(lower_mesh); - vol->name = volume->name; - // Don't copy the config's ID. - vol->config.assign_config(volume->config); - assert(vol->config.id().valid()); - assert(vol->config.id() != volume->config.id()); - vol->set_material(volume->material_id(), *volume->material()); - - // Compute the displacement (in instance coordinates) to be applied to place the upper parts - // The upper part displacement is set to half of the lower part bounding box - // this is done in hope at least a part of the upper part will always be visible and draggable - local_displace = lower->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(-0.5, -0.5, 0.0)); - } + if (!volume->is_model_part()) { + if (volume->cut_info.is_processed) + process_modifier_cut(volume, instance_matrix, inverse_cut_matrix, attributes, upper, lower); + else + process_connector_cut(volume, attributes, upper, lower, dowels, local_dowels_displace); } + else if (!volume->mesh().empty()) + process_solid_part_cut(volume, instance_matrix, cut_matrix, attributes, upper, lower, local_displace); } + // Post-process cut parts + ModelObjectPtrs res; - if (attributes.has(ModelObjectCutAttribute::KeepUpper) && upper->volumes.size() > 0) { - if (!upper->origin_translation.isApprox(Vec3d::Zero()) && instances[instance]->get_offset().isApprox(Vec3d::Zero())) { - upper->center_around_origin(); - upper->translate_instances(-upper->origin_translation); - upper->origin_translation = Vec3d::Zero(); - } - - // Reset instance transformation except offset and Z-rotation - for (size_t i = 0; i < instances.size(); ++i) { - auto &instance = upper->instances[i]; - const Vec3d offset = instance->get_offset(); - const double rot_z = instance->get_rotation().z(); - const Vec3d displace = Geometry::assemble_transform(Vec3d::Zero(), instance->get_rotation()) * local_displace; - - instance->set_transformation(Geometry::Transformation()); - instance->set_offset(offset + displace); - instance->set_rotation(Vec3d(0.0, 0.0, rot_z)); - } + if (attributes.has(ModelObjectCutAttribute::KeepUpper) && !upper->volumes.empty()) { + invalidate_translations(upper, instances[instance]); + reset_instance_transformation(upper, instance, cut_matrix, + attributes.has(ModelObjectCutAttribute::PlaceOnCutUpper), + attributes.has(ModelObjectCutAttribute::FlipUpper), + local_displace); res.push_back(upper); } - if (attributes.has(ModelObjectCutAttribute::KeepLower) && lower->volumes.size() > 0) { - if (!lower->origin_translation.isApprox(Vec3d::Zero()) && instances[instance]->get_offset().isApprox(Vec3d::Zero())) { - lower->center_around_origin(); - lower->translate_instances(-lower->origin_translation); - lower->origin_translation = Vec3d::Zero(); - } - // Reset instance transformation except offset and Z-rotation - for (auto *instance : lower->instances) { - const Vec3d offset = instance->get_offset(); - const double rot_z = instance->get_rotation().z(); - instance->set_transformation(Geometry::Transformation()); - instance->set_offset(offset); - instance->set_rotation(Vec3d(attributes.has(ModelObjectCutAttribute::FlipLower) ? Geometry::deg2rad(180.0) : 0.0, 0.0, rot_z)); - } + if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower->volumes.empty()) { + invalidate_translations(lower, instances[instance]); + reset_instance_transformation(lower, instance, cut_matrix, + attributes.has(ModelObjectCutAttribute::PlaceOnCutLower), + attributes.has(ModelObjectCutAttribute::PlaceOnCutLower) ? true : attributes.has(ModelObjectCutAttribute::FlipLower)); res.push_back(lower); } + if (attributes.has(ModelObjectCutAttribute::CreateDowels) && !dowels.empty()) { + for (auto dowel : dowels) { + invalidate_translations(dowel, instances[instance]); + + reset_instance_transformation(dowel, instance, Transform3d::Identity(), false, false, local_dowels_displace); + + local_dowels_displace += dowel->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(-1.5, -1.5, 0.0)); + dowel->name += "-Dowel-" + dowel->volumes[0]->name; + res.push_back(dowel); + } + } + BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - end"; + synchronize_model_after_cut(); + return res; } @@ -2289,6 +2569,14 @@ bool model_has_multi_part_objects(const Model &model) return false; } +bool model_has_connectors(const Model &model) +{ + for (const ModelObject *model_object : model.objects) + if (!model_object->cut_connectors.empty()) + return true; + return false; +} + bool model_has_advanced_features(const Model &model) { auto config_is_advanced = [](const ModelConfig &config) { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 9cb287aa0..204570bd9 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -222,7 +222,102 @@ private: friend class ModelObject; }; -enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, FlipLower }; +enum class CutConnectorType : int { + Plug + , Dowel + , Undef +}; + +enum class CutConnectorStyle : int { + Prizm + , Frustum + , Undef + //,Claw +}; + +enum class CutConnectorShape : int { + Triangle + , Square + , Hexagon + , Circle + , Undef + //,D-shape +}; + +struct CutConnectorAttributes +{ + CutConnectorType type{ CutConnectorType::Plug }; + CutConnectorStyle style{ CutConnectorStyle::Prizm }; + CutConnectorShape shape{ CutConnectorShape::Circle }; + + CutConnectorAttributes() {} + + CutConnectorAttributes(CutConnectorType t, CutConnectorStyle st, CutConnectorShape sh) + : type(t), style(st), shape(sh) + {} + + CutConnectorAttributes(const CutConnectorAttributes& rhs) : + CutConnectorAttributes(rhs.type, rhs.style, rhs.shape) {} + + bool operator==(const CutConnectorAttributes& other) const; + + bool operator!=(const CutConnectorAttributes& other) const { return !(other == (*this)); } + + bool operator<(const CutConnectorAttributes& other) const { + return this->type < other.type || + (this->type == other.type && this->style < other.style) || + (this->type == other.type && this->style == other.style && this->shape < other.shape); + } + + template inline void serialize(Archive& ar) { + ar(type, style, shape); + } +}; + +struct CutConnector +{ + Vec3d pos; + Transform3d rotation_m; + float radius; + float height; + float radius_tolerance;// [0.f : 1.f] + float height_tolerance;// [0.f : 1.f] + CutConnectorAttributes attribs; + + CutConnector() + : pos(Vec3d::Zero()), rotation_m(Transform3d::Identity()), radius(5.f), height(10.f), radius_tolerance(0.f), height_tolerance(0.1f) + {} + + CutConnector(Vec3d p, Transform3d rot, float r, float h, float rt, float ht, CutConnectorAttributes attributes) + : pos(p), rotation_m(rot), radius(r), height(h), radius_tolerance(rt), height_tolerance(ht), attribs(attributes) + {} + + CutConnector(const CutConnector& rhs) : + CutConnector(rhs.pos, rhs.rotation_m, rhs.radius, rhs.height, rhs.radius_tolerance, rhs.height_tolerance, rhs.attribs) {} + + bool operator==(const CutConnector& other) const; + + bool operator!=(const CutConnector& other) const { return !(other == (*this)); } + + template inline void serialize(Archive& ar) { + ar(pos, rotation_m, radius, height, radius_tolerance, height_tolerance, attribs); + } +}; + +using CutConnectors = std::vector; + + +// Declared outside of ModelVolume, so it could be forward declared. +enum class ModelVolumeType : int { + INVALID = -1, + MODEL_PART = 0, + NEGATIVE_VOLUME, + PARAMETER_MODIFIER, + SUPPORT_BLOCKER, + SUPPORT_ENFORCER, +}; + +enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels }; using ModelObjectCutAttributes = enum_bitmask; ENABLE_ENUM_BITMASK_OPERATORS(ModelObjectCutAttribute); @@ -262,6 +357,10 @@ public: // Holes to be drilled into the object so resin can flow out sla::DrainHoles sla_drain_holes; + // Connectors to be added into the object before cut and are used to create a solid/negative volumes during a cut perform + CutConnectors cut_connectors; + CutObjectBase cut_id; + /* This vector accumulates the total translation applied to the object by the center_around_origin() method. Callers might want to apply the same translation to new volumes before adding them to this object in order to preserve alignment @@ -346,8 +445,21 @@ public: size_t materials_count() const; size_t facets_count() const; size_t parts_count() const; - ModelObjectPtrs cut(size_t instance, coordf_t z, ModelObjectCutAttributes attributes); - void split(ModelObjectPtrs* new_objects); + static indexed_triangle_set get_connector_mesh(CutConnectorAttributes connector_attributes); + void apply_cut_connectors(const std::string& name); + // invalidate cut state for this object and its connectors/volumes + void invalidate_cut(); + void synchronize_model_after_cut(); + void apply_cut_attributes(ModelObjectCutAttributes attributes); + void clone_for_cut(ModelObject **obj); + void process_connector_cut(ModelVolume* volume, ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower, + std::vector& dowels, Vec3d& local_dowels_displace); + void process_modifier_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& inverse_cut_matrix, + ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower); + void process_solid_part_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, + ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower, Vec3d& local_displace); + ModelObjectPtrs cut(size_t instance, const Transform3d&cut_matrix, ModelObjectCutAttributes attributes); + void split(ModelObjectPtrs*new_objects); void merge(); // Support for non-uniform scaling of instances. If an instance is rotated by angles, which are not multiples of ninety degrees, // then the scaling in world coordinate system is not representable by the Geometry::Transformation structure. @@ -370,6 +482,9 @@ public: // Get count of errors in the mesh( or all object's meshes, if volume index isn't defined) int get_repaired_errors_count(const int vol_idx = -1) const; + bool is_cut() const { return cut_id.id().valid(); } + bool has_connectors() const; + private: friend class Model; // This constructor assigns new ID to this ModelObject and its config. @@ -490,7 +605,8 @@ private: Internal::StaticSerializationWrapper layer_heigth_profile_wrapper(layer_height_profile); ar(name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_heigth_profile_wrapper, sla_support_points, sla_points_status, sla_drain_holes, printable, origin_translation, - m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid); + m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid, + cut_connectors, cut_id); } // Called by Print::validate() from the UI thread. @@ -609,6 +725,37 @@ public: }; Source source; + // struct used by cut command + // It contains information about connetors + struct CutInfo + { + bool is_connector{ false }; + bool is_processed{ true }; + CutConnectorType connector_type{ CutConnectorType::Plug }; + float radius_tolerance{ 0.f };// [0.f : 1.f] + float height_tolerance{ 0.f };// [0.f : 1.f] + + CutInfo() = default; + CutInfo(CutConnectorType type, float rad_tolerance, float h_tolerance, bool processed = false) : + is_connector(true), + is_processed(processed), + connector_type(type), + radius_tolerance(rad_tolerance), + height_tolerance(h_tolerance) + {} + + void set_processed() { is_processed = true; } + void invalidate() { is_connector = false; } + + template inline void serialize(Archive& ar) { + ar(is_connector, is_processed, connector_type, radius_tolerance, height_tolerance); + } + }; + CutInfo cut_info; + + bool is_cut_connector() const { return cut_info.is_processed && cut_info.is_connector; } + void invalidate_cut_info() { cut_info.invalidate(); } + // The triangular model. const TriangleMesh& mesh() const { return *m_mesh.get(); } #if ENABLE_RAYCAST_PICKING @@ -620,7 +767,7 @@ public: void set_mesh(indexed_triangle_set &&mesh) { m_mesh = std::make_shared(std::move(mesh)); } void set_mesh(std::shared_ptr &mesh) { m_mesh = mesh; } void set_mesh(std::unique_ptr &&mesh) { m_mesh = std::move(mesh); } - void reset_mesh() { m_mesh = std::make_shared(); } + void reset_mesh() { m_mesh = std::make_shared(); } const std::shared_ptr& get_mesh_shared_ptr() const { return m_mesh; } // Configuration parameters specific to an object model geometry or a modifier volume, // overriding the global Slic3r settings and the ModelObject settings. @@ -650,6 +797,8 @@ public: bool is_support_blocker() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER; } bool is_support_modifier() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER || m_type == ModelVolumeType::SUPPORT_ENFORCER; } t_model_material_id material_id() const { return m_material_id; } + void reset_extra_facets(); + void apply_tolerance(); void set_material_id(t_model_material_id material_id); ModelMaterial* material() const; void set_material(t_model_material_id material_id, const ModelMaterial &material); @@ -819,8 +968,9 @@ private: ObjectBase(other), name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation), - supported_facets(other.supported_facets), seam_facets(other.seam_facets), - mmu_segmentation_facets(other.mmu_segmentation_facets), text_configuration(other.text_configuration) + supported_facets(other.supported_facets), seam_facets(other.seam_facets), mmu_segmentation_facets(other.mmu_segmentation_facets), + cut_info(other.cut_info), + text_configuration(other.text_configuration) { assert(this->id().valid()); assert(this->config.id().valid()); @@ -841,6 +991,7 @@ private: // Providing a new mesh, therefore this volume will get a new unique ID assigned. ModelVolume(ModelObject *object, const ModelVolume &other, TriangleMesh &&mesh) : name(other.name), source(other.source), config(other.config), object(object), m_mesh(new TriangleMesh(std::move(mesh))), m_type(other.m_type), m_transformation(other.m_transformation), + cut_info(other.cut_info), text_configuration(other.text_configuration) { assert(this->id().valid()); @@ -883,7 +1034,7 @@ private: } template void load(Archive &ar) { bool has_convex_hull; - ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); + ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull, cut_info); cereal::load_by_value(ar, supported_facets); cereal::load_by_value(ar, seam_facets); cereal::load_by_value(ar, mmu_segmentation_facets); @@ -900,7 +1051,7 @@ private: } template void save(Archive &ar) const { bool has_convex_hull = m_convex_hull.get() != nullptr; - ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); + ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull, cut_info); cereal::save_by_value(ar, supported_facets); cereal::save_by_value(ar, seam_facets); cereal::save_by_value(ar, mmu_segmentation_facets); @@ -1235,6 +1386,8 @@ extern bool model_mmu_segmentation_data_changed(const ModelObject& mo, const Mod // If the model has multi-part objects, then it is currently not supported by the SLA mode. // Either the model cannot be loaded, or a SLA printer has to be activated. bool model_has_multi_part_objects(const Model &model); +// If the model has objects with cut connectrs, then it is currently not supported by the SLA mode. +bool model_has_connectors(const Model& model); // If the model has advanced features, then it cannot be processed in simple mode. bool model_has_advanced_features(const Model &model); diff --git a/src/libslic3r/ObjectID.hpp b/src/libslic3r/ObjectID.hpp index 1030171e7..4f34572d2 100644 --- a/src/libslic3r/ObjectID.hpp +++ b/src/libslic3r/ObjectID.hpp @@ -2,6 +2,7 @@ #define slic3r_ObjectID_hpp_ #include +#include namespace Slic3r { @@ -89,7 +90,9 @@ private: friend class cereal::access; friend class Slic3r::UndoRedo::StackImpl; template void serialize(Archive &ar) { ar(m_id); } +protected: // #vbCHECKME && #ysFIXME ObjectBase(const ObjectID id) : m_id(id) {} +private: template static void load_and_construct(Archive & ar, cereal::construct &construct) { ObjectID id; ar(id); construct(id); } }; @@ -128,6 +131,64 @@ private: template void serialize(Archive &ar) { ar(m_timestamp); } }; +class CutObjectBase : public ObjectBase +{ + // check sum of CutParts in initial Object + size_t m_check_sum{ 1 }; + // connectors count + size_t m_connectors_cnt{ 0 }; + +public: + // Default Constructor to assign an invalid ID + CutObjectBase() : ObjectBase(-1) {} + // Constructor with ignored int parameter to assign an invalid ID, to be replaced + // by an existing ID copied from elsewhere. + CutObjectBase(int) : ObjectBase(-1) {} + // Constructor to initialize full information from 3mf + CutObjectBase(ObjectID id, size_t check_sum, size_t connectors_cnt) : ObjectBase(id), m_check_sum(check_sum), m_connectors_cnt(connectors_cnt) {} + // The class tree will have virtual tables and type information. + virtual ~CutObjectBase() = default; + + bool operator<(const CutObjectBase& other) const { return other.id() > this->id(); } + bool operator==(const CutObjectBase& other) const { return other.id() == this->id(); } + + void copy(const CutObjectBase& rhs) { + this->copy_id(rhs); + this->m_check_sum = rhs.check_sum(); + this->m_connectors_cnt = rhs.connectors_cnt() ; + } + CutObjectBase& operator=(const CutObjectBase& other) { + this->copy(other); + return *this; + } + + void invalidate() { + set_invalid_id(); + m_check_sum = 1; + m_connectors_cnt = 0; + } + + void init() { this->set_new_unique_id(); } + bool has_same_id(const CutObjectBase& rhs) { return this->id() == rhs.id(); } + bool is_equal(const CutObjectBase& rhs) { return this->id() == rhs.id() && + this->check_sum() == rhs.check_sum() && + this->connectors_cnt() == rhs.connectors_cnt() ; } + + size_t check_sum() const { return m_check_sum; } + void set_check_sum(size_t cs) { m_check_sum = cs; } + void increase_check_sum(size_t cnt) { m_check_sum += cnt; } + + size_t connectors_cnt() const { return m_connectors_cnt; } + void increase_connectors_cnt(size_t connectors_cnt) { m_connectors_cnt += connectors_cnt; } + +private: + friend class cereal::access; + template void serialize(Archive& ar) { + ar(cereal::base_class(this)); + ar(m_check_sum, m_connectors_cnt); + } +}; + // Unique object / instance ID for the wipe tower. extern ObjectID wipe_tower_object_id(); extern ObjectID wipe_tower_instance_id(); diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 5553b1df2..41af2c857 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -1061,6 +1061,61 @@ indexed_triangle_set its_make_sphere(double radius, double fa) return mesh; } +// Generates mesh for a frustum dowel centered about the origin, using the count of sectors +// Note: This function uses code for sphere generation, but for stackCount = 2; +indexed_triangle_set its_make_frustum_dowel(double radius, double h, int sectorCount) +{ + int stackCount = 2; + float sectorStep = float(2. * M_PI / sectorCount); + float stackStep = float(M_PI / stackCount); + + indexed_triangle_set mesh; + auto& vertices = mesh.vertices; + vertices.reserve((stackCount - 1) * sectorCount + 2); + for (int i = 0; i <= stackCount; ++i) { + // from pi/2 to -pi/2 + double stackAngle = 0.5 * M_PI - stackStep * i; + double xy = radius * cos(stackAngle); + double z = radius * sin(stackAngle); + if (i == 0 || i == stackCount) + vertices.emplace_back(Vec3f(float(xy), 0.f, float(h * sin(stackAngle)))); + else + for (int j = 0; j < sectorCount; ++j) { + // from 0 to 2pi + double sectorAngle = sectorStep * j; + vertices.emplace_back(Vec3d(xy * std::cos(sectorAngle), xy * std::sin(sectorAngle), z).cast()); + } + } + + auto& facets = mesh.indices; + facets.reserve(2 * (stackCount - 1) * sectorCount); + for (int i = 0; i < stackCount; ++i) { + // Beginning of current stack. + int k1 = (i == 0) ? 0 : (1 + (i - 1) * sectorCount); + int k1_first = k1; + // Beginning of next stack. + int k2 = (i == 0) ? 1 : (k1 + sectorCount); + int k2_first = k2; + for (int j = 0; j < sectorCount; ++j) { + // 2 triangles per sector excluding first and last stacks + int k1_next = k1; + int k2_next = k2; + if (i != 0) { + k1_next = (j + 1 == sectorCount) ? k1_first : (k1 + 1); + facets.emplace_back(k1, k2, k1_next); + } + if (i + 1 != stackCount) { + k2_next = (j + 1 == sectorCount) ? k2_first : (k2 + 1); + facets.emplace_back(k1_next, k2, k2_next); + } + k1 = k1_next; + k2 = k2_next; + } + } + + return mesh; +} + indexed_triangle_set its_convex_hull(const std::vector &pts) { std::vector dst_vertices; diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index ce4357c41..29dff9168 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -309,6 +309,7 @@ indexed_triangle_set its_make_cube(double x, double y, double z); indexed_triangle_set its_make_prism(float width, float length, float height); indexed_triangle_set its_make_cylinder(double r, double h, double fa=(2*PI/360)); indexed_triangle_set its_make_cone(double r, double h, double fa=(2*PI/360)); +indexed_triangle_set its_make_frustum_dowel(double r, double h, int sectorCount); indexed_triangle_set its_make_pyramid(float base, float height); indexed_triangle_set its_make_sphere(double radius, double fa); diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index b3e2e44fd..83608aa72 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -270,9 +270,9 @@ constexpr inline T lerp(const T& a, const T& b, Number t) } template -constexpr inline bool is_approx(Number value, Number test_value) +constexpr inline bool is_approx(Number value, Number test_value, Number precision = EPSILON) { - return std::fabs(double(value) - double(test_value)) < double(EPSILON); + return std::fabs(double(value) - double(test_value)) < double(precision); } template diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 51bc9d4b6..f96738ace 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -276,6 +276,8 @@ set(SLIC3R_GUI_SOURCES Utils/WxFontUtils.hpp ) +find_package(NanoSVG REQUIRED) + if (APPLE) list(APPEND SLIC3R_GUI_SOURCES Utils/RetinaHelperImpl.mm diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index e674b52d0..bedb3718e 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -33,7 +33,7 @@ wxString double_to_string(double const value, const int max_precision /*= 4*/) // Style_NoTrailingZeroes does not work on OSX. It also does not work correctly with some locales on Windows. // return wxNumberFormatter::ToString(value, max_precision, wxNumberFormatter::Style_NoTrailingZeroes); - wxString s = wxNumberFormatter::ToString(value, value < 0.0001 ? 10 : max_precision, wxNumberFormatter::Style_None); + wxString s = wxNumberFormatter::ToString(value, std::abs(value) < 0.0001 ? 10 : max_precision, wxNumberFormatter::Style_None); // The following code comes from wxNumberFormatter::RemoveTrailingZeroes(wxString& s) // with the exception that here one sets the decimal separator explicitely to dot. diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1f8b4e832..6dd4cf8a3 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1367,6 +1367,8 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx) && (mv == nullptr || m_model->objects[vol->composite_id.object_id]->volumes[vol->composite_id.volume_id] == mv)) { vol->is_active = visible; + if (!vol->is_modifier) + vol->color.a(1.f); if (instance_idx == -1) { vol->force_native_color = false; @@ -1375,9 +1377,13 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject const GLGizmosManager& gm = get_gizmos_manager(); auto gizmo_type = gm.get_current_type(); if ( (gizmo_type == GLGizmosManager::FdmSupports - || gizmo_type == GLGizmosManager::Seam) - && ! vol->is_modifier) + || gizmo_type == GLGizmosManager::Seam + || gizmo_type == GLGizmosManager::Cut) + && ! vol->is_modifier) { vol->force_neutral_color = true; + if (gizmo_type == GLGizmosManager::Cut) + vol->color.a(0.95f); + } else if (gizmo_type == GLGizmosManager::MmuSegmentation) vol->is_active = false; else @@ -3371,6 +3377,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) show_sinking_contours(); } } + else if (evt.LeftUp() && + m_gizmos.get_current_type() == GLGizmosManager::EType::Scale && + m_gizmos.get_current()->get_state() == GLGizmoBase::EState::On) { + wxGetApp().obj_list()->selection_changed(); + } return; } @@ -3446,6 +3457,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports && m_gizmos.get_current_type() != GLGizmosManager::FdmSupports && m_gizmos.get_current_type() != GLGizmosManager::Seam && + m_gizmos.get_current_type() != GLGizmosManager::Cut && m_gizmos.get_current_type() != GLGizmosManager::MmuSegmentation) { m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::EState::Select : GLSelectionRectangle::EState::Deselect); m_dirty = true; @@ -3495,7 +3507,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) const int volume_idx = get_first_hover_volume_idx(); BoundingBoxf3 volume_bbox = m_volumes.volumes[volume_idx]->transformed_bounding_box(); volume_bbox.offset(1.0); - if ((!any_gizmo_active || !evt.CmdDown()) && volume_bbox.contains(m_mouse.scene_position)) { + const bool is_cut_connector_selected = m_selection.is_any_connector(); + if ((!any_gizmo_active || !evt.CmdDown()) && volume_bbox.contains(m_mouse.scene_position) && !is_cut_connector_selected) { m_volumes.volumes[volume_idx]->hover = GLVolume::HS_None; // The dragging operation is initiated. m_mouse.drag.move_volume_idx = volume_idx; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 9a9d6250d..161784d95 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2891,6 +2891,13 @@ bool GUI_App::may_switch_to_SLA_preset(const wxString& caption) caption); return false; } + if (model_has_connectors(model())) { + show_info(nullptr, + _L("SLA technology doesn't support cut with connectors") + "\n\n" + + _L("Please check your object list before preset changing."), + caption); + return false; + } return true; } diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 302eedcdd..5cd3cd735 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -572,7 +572,10 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu) for (auto& item : ADD_VOLUME_MENU_ITEMS) { wxMenu* sub_menu = append_submenu_add_generic(menu, ModelVolumeType(type++)); append_submenu(menu, sub_menu, wxID_ANY, _(item.first), "", item.second, - []() { return obj_list()->is_instance_or_object_selected(); }, m_parent); + [type]() { + bool can_add = type < size_t(ModelVolumeType::PARAMETER_MODIFIER) ? !obj_list()->is_selected_object_cut() : true; + return can_add && obj_list()->is_instance_or_object_selected(); + }, m_parent); } append_menu_item_layers_editing(menu); @@ -738,6 +741,21 @@ wxMenuItem* MenuFactory::append_menu_item_printable(wxMenu* menu) return menu_item_printable; } +void MenuFactory::append_menu_item_invalidate_cut_info(wxMenu* menu) +{ + const wxString menu_name = _L("Invalidate cut info"); + + auto menu_item_id = menu->FindItem(menu_name); + if (menu_item_id != wxNOT_FOUND) + // Delete old menu item if selected object isn't cut + menu->Destroy(menu_item_id); + + if (obj_list()->has_selected_cut_object()) + append_menu_item(menu, wxID_ANY, menu_name, "", + [](wxCommandEvent&) { obj_list()->invalidate_cut_info_for_selection(); }, "", menu, + []() { return true; }, m_parent); +} + void MenuFactory::append_menu_items_osx(wxMenu* menu) { append_menu_item(menu, wxID_ANY, _L("Rename"), "", @@ -874,6 +892,8 @@ void MenuFactory::append_menu_items_convert_unit(wxMenu* menu, int insert_pos/* ModelObjectPtrs objects; for (int obj_idx : obj_idxs) { ModelObject* object = obj_list()->object(obj_idx); + if (object->is_cut()) + return false; if (vol_idxs.empty()) { for (ModelVolume* volume : object->volumes) if (volume_respects_conversion(volume, conver_type)) @@ -1118,6 +1138,7 @@ wxMenu* MenuFactory::object_menu() append_menu_item_settings(&m_object_menu); append_menu_item_change_extruder(&m_object_menu); update_menu_items_instance_manipulation(mtObjectFFF); + append_menu_item_invalidate_cut_info(&m_object_menu); return &m_object_menu; } @@ -1127,6 +1148,7 @@ wxMenu* MenuFactory::sla_object_menu() append_menu_items_convert_unit(&m_sla_object_menu, 11); append_menu_item_settings(&m_sla_object_menu); update_menu_items_instance_manipulation(mtObjectSLA); + append_menu_item_invalidate_cut_info(&m_sla_object_menu); return &m_sla_object_menu; } @@ -1165,6 +1187,9 @@ wxMenu* MenuFactory::multi_selection_menu() wxDataViewItemArray sels; obj_list()->GetSelections(sels); + if (sels.IsEmpty()) + return nullptr; + for (const wxDataViewItem& item : sels) if (!(list_model()->GetItemType(item) & (itVolume | itObject | itInstance))) // show this menu only for Objects(Instances mixed with Objects)/Volumes selection diff --git a/src/slic3r/GUI/GUI_Factories.hpp b/src/slic3r/GUI/GUI_Factories.hpp index da45a6aae..ed27655be 100644 --- a/src/slic3r/GUI/GUI_Factories.hpp +++ b/src/slic3r/GUI/GUI_Factories.hpp @@ -97,6 +97,7 @@ private: wxMenuItem* append_menu_item_change_type(wxMenu* menu); wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu); wxMenuItem* append_menu_item_printable(wxMenu* menu); + void append_menu_item_invalidate_cut_info(wxMenu *menu); void append_menu_items_osx(wxMenu* menu); wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu); wxMenuItem* append_menu_item_simplify(wxMenu* menu); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 726a22ad7..d01a709dd 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -12,6 +12,8 @@ #include "GalleryDialog.hpp" #include "MainFrame.hpp" #include "slic3r/Utils/UndoRedo.hpp" +#include "Gizmos/GLGizmoCut.hpp" +#include "Gizmos/GLGizmoScale.hpp" #include "OptionsGroup.hpp" #include "Tab.hpp" @@ -402,6 +404,13 @@ MeshErrorsInfo ObjectList::get_mesh_errors_info(const int obj_idx, const int vol if (obj_idx < 0) return { {}, {} }; // hide tooltip + const ModelObject* object = (*m_objects)[obj_idx]; + if (vol_idx != -1 && vol_idx >= int(object->volumes.size())) { + if (sidebar_info) + *sidebar_info = _L("Wrong volume index "); + return { {}, {} }; // hide tooltip + } + const TriangleMeshStats& stats = vol_idx == -1 ? (*m_objects)[obj_idx]->get_object_stl_stats() : (*m_objects)[obj_idx]->volumes[vol_idx]->mesh().stats(); @@ -682,6 +691,8 @@ void ObjectList::selection_changed() fix_multiselection_conflicts(); + fix_cut_selection(); + // update object selection on Plater if (!m_prevent_canvas_selection_update) update_selections_on_canvas(); @@ -1404,6 +1415,15 @@ bool ObjectList::is_instance_or_object_selected() return selection.is_single_full_instance() || selection.is_single_full_object(); } +bool ObjectList::is_selected_object_cut() +{ + const Selection& selection = scene_selection(); + int obj_idx = selection.get_object_idx(); + if (obj_idx < 0) + return false; + return object(obj_idx)->is_cut(); +} + void ObjectList::load_subobject(ModelVolumeType type, bool from_galery/* = false*/) { if (type == ModelVolumeType::INVALID && from_galery) { @@ -1723,6 +1743,9 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode // update printable state on canvas wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object((size_t)obj_idx); + if (model_object.is_cut()) + update_info_items(obj_idx); + selection_changed(); } @@ -1831,22 +1854,22 @@ void ObjectList::load_mesh_object( #endif /* _DEBUG */ } -void ObjectList::del_object(const int obj_idx) +bool ObjectList::del_object(const int obj_idx) { - wxGetApp().plater()->delete_object_from_model(obj_idx); + return wxGetApp().plater()->delete_object_from_model(obj_idx); } // Delete subobject -void ObjectList::del_subobject_item(wxDataViewItem& item) +bool ObjectList::del_subobject_item(wxDataViewItem& item) { - if (!item) return; + if (!item) return false; int obj_idx, idx; ItemType type; m_objects_model->GetItemInfo(item, type, obj_idx, idx); if (type == itUndef) - return; + return false; wxDataViewItem parent = m_objects_model->GetParent(item); @@ -1860,19 +1883,21 @@ void ObjectList::del_subobject_item(wxDataViewItem& item) del_layer_from_object(obj_idx, m_objects_model->GetLayerRangeByItem(item)); else if (type & itInfo && obj_idx != -1) del_info_item(obj_idx, m_objects_model->GetInfoItemType(item)); - else if (idx == -1) - return; - else if (!del_subobject_from_object(obj_idx, idx, type)) - return; + else if (idx == -1 || !del_subobject_from_object(obj_idx, idx, type)) + return false; // If last volume item with warning was deleted, unmark object item if (type & itVolume) { + add_volumes_to_object_in_list(obj_idx); const std::string& icon_name = get_warning_icon_name(object(obj_idx)->get_object_stl_stats()); m_objects_model->UpdateWarningIcon(parent, icon_name); } + else + m_objects_model->Delete(item); - m_objects_model->Delete(item); update_info_items(obj_idx); + + return true; } void ObjectList::del_info_item(const int obj_idx, InfoItemType type) @@ -1895,6 +1920,10 @@ void ObjectList::del_info_item(const int obj_idx, InfoItemType type) mv->seam_facets.reset(); break; + case InfoItemType::CutConnectors: + show_error(nullptr, _L("Connectors cannot be deleted from cut object.")); + break; + case InfoItemType::MmuSegmentation: cnv->get_gizmos_manager().reset_all_states(); Plater::TakeSnapshot(plater, _L("Remove Multi Material painting")); @@ -2005,6 +2034,16 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con Slic3r::GUI::show_error(nullptr, _L("From Object List You can't delete the last solid part from object.")); return false; } + if (object->is_cut()) { + if (volume->is_model_part()) { + Slic3r::GUI::show_error(nullptr, _L("Solid part cannot be deleted from cut object.")); + return false; + } + if (volume->is_negative_volume()) { + Slic3r::GUI::show_error(nullptr, _L("Negative volume cannot be deleted from cut object.")); + return false; + } + } take_snapshot(_L("Delete Subobject")); @@ -2032,6 +2071,10 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con Slic3r::GUI::show_error(nullptr, _L("Last instance of an object cannot be deleted.")); return false; } + if (object->is_cut()) { + Slic3r::GUI::show_error(nullptr, _L("Instance cannot be deleted from cut object.")); + return false; + } take_snapshot(_L("Delete Instance")); object->delete_instance(idx); @@ -2065,31 +2108,11 @@ void ObjectList::split() volume->split(nozzle_dmrs_cnt); + (*m_objects)[obj_idx]->input_file.clear(); + wxBusyCursor wait; - auto model_object = (*m_objects)[obj_idx]; - - auto parent = m_objects_model->GetTopParent(item); - if (parent) - m_objects_model->DeleteVolumeChildren(parent); - else - parent = item; - - for (const ModelVolume* volume : model_object->volumes) { - const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(parent, from_u8(volume->name), - volume->type(),// is_modifier() ? ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART, - volume->text_configuration.has_value(), - get_warning_icon_name(volume->mesh().stats()), - volume->config.has("extruder") ? volume->config.extruder() : 0, - false); - // add settings to the part, if it has those - add_settings_item(vol_item, &volume->config.get()); - } - - model_object->input_file.clear(); - - if (parent == item) - Expand(parent); + add_volumes_to_object_in_list(obj_idx); changed_object(obj_idx); // update printable state for new volumes on canvas3D @@ -2408,9 +2431,12 @@ bool ObjectList::is_splittable(bool to_objects) auto obj_idx = get_selected_obj_idx(); if (obj_idx < 0) return false; - if ((*m_objects)[obj_idx]->volumes.size() > 1) + const ModelObject* object = (*m_objects)[obj_idx]; + if (object->is_cut()) + return false; + if (object->volumes.size() > 1) return true; - return (*m_objects)[obj_idx]->volumes[0]->is_splittable(); + return object->volumes[0]->is_splittable(); } return false; } @@ -2443,9 +2469,59 @@ bool ObjectList::can_split_instances() return selection.is_multiple_full_instance() || selection.is_single_full_instance(); } +bool ObjectList::has_selected_cut_object() const +{ + wxDataViewItemArray sels; + GetSelections(sels); + if (sels.IsEmpty()) + return false; + + for (wxDataViewItem item : sels) { + const int obj_idx = m_objects_model->GetObjectIdByItem(item); + if (obj_idx >= 0 && object(obj_idx)->is_cut()) + return true; + } + + return false; +} +void ObjectList::invalidate_cut_info_for_selection() +{ + const wxDataViewItem item = GetSelection(); + if (item) { + const int obj_idx = m_objects_model->GetObjectIdByItem(item); + if (obj_idx >= 0) + invalidate_cut_info_for_object(size_t(obj_idx)); + } +} + +void ObjectList::invalidate_cut_info_for_object(size_t obj_idx) +{ + ModelObject* init_obj = object(int(obj_idx)); + if (!init_obj->is_cut()) + return; + + take_snapshot(_L("Invalidate cut info")); + + auto invalidate_cut = [this](size_t obj_idx) { + object(int(obj_idx))->invalidate_cut(); + update_info_items(obj_idx); + add_volumes_to_object_in_list(obj_idx); + }; + + // invalidate cut for related objects (which have the same cut_id) + for (size_t idx = 0; idx < m_objects->size(); idx++) + if (ModelObject* obj = object(idx); obj != init_obj && obj->cut_id.is_equal(init_obj->cut_id)) + invalidate_cut(idx); + + // invalidate own cut information + invalidate_cut(size_t(obj_idx)); + + update_lock_icons_for_model(); +} + bool ObjectList::can_merge_to_multipart_object() const { - if (printer_technology() == ptSLA) + if (printer_technology() == ptSLA || has_selected_cut_object()) return false; wxDataViewItemArray sels; @@ -2473,17 +2549,7 @@ bool ObjectList::can_merge_to_single_object() const wxPoint ObjectList::get_mouse_position_in_control() const { - wxPoint pt = wxGetMousePosition() - this->GetScreenPosition(); - -#ifdef __APPLE__ - // Workaround for OSX. From wxWidgets 3.1.6 Hittest doesn't respect to the header of wxDataViewCtrl - if (wxDataViewItem top_item = this->GetTopItem(); top_item.IsOk()) { - auto rect = this->GetItemRect(top_item, this->GetColumn(0)); - pt.y -= rect.y; - } -#endif // __APPLE__ - - return pt; + return wxGetMousePosition() - this->GetScreenPosition(); } // NO_PARAMETERS function call means that changed object index will be determine from Selection() @@ -2504,14 +2570,65 @@ void ObjectList::part_selection_changed() bool update_and_show_settings = false; bool update_and_show_layers = false; + bool enable_manipulation {true}; + bool disable_ss_manipulation {false}; + bool disable_ununiform_scale {false}; + const auto item = GetSelection(); - if ( multiple_selection() || (item && m_objects_model->GetItemType(item) == itInstanceRoot )) { + GLGizmosManager& gizmos_mgr = wxGetApp().plater()->canvas3D()->get_gizmos_manager(); + + if (item && m_objects_model->GetItemType(item) == itInfo && m_objects_model->GetInfoItemType(item) == InfoItemType::CutConnectors) { + og_name = _L("Cut Connectors information"); + + update_and_show_manipulations = true; + enable_manipulation = false; + disable_ununiform_scale = true; + } + else if ( multiple_selection() || (item && m_objects_model->GetItemType(item) == itInstanceRoot )) { og_name = _L("Group manipulation"); const Selection& selection = scene_selection(); // don't show manipulation panel for case of all Object's parts selection update_and_show_manipulations = !selection.is_single_full_instance(); + + if (int obj_idx = selection.get_object_idx(); obj_idx >= 0) { + if (selection.is_any_volume() || selection.is_any_modifier()) + enable_manipulation = !(*m_objects)[obj_idx]->is_cut(); + else// if (item && m_objects_model->GetItemType(item) == itInstanceRoot) + disable_ss_manipulation = (*m_objects)[obj_idx]->is_cut(); + } + else { + wxDataViewItemArray sels; + GetSelections(sels); + if (selection.is_single_full_object() || selection.is_multiple_full_instance() ) { + int obj_idx = m_objects_model->GetObjectIdByItem(sels.front()); + disable_ss_manipulation = (*m_objects)[obj_idx]->is_cut(); + } + else if (selection.is_mixed() || selection.is_multiple_full_object()) { + std::map> cut_objects; + + // find cut objects + for (auto item : sels) { + int obj_idx = m_objects_model->GetObjectIdByItem(item); + const ModelObject* obj = object(obj_idx); + if (obj->is_cut()) { + if (cut_objects.find(obj->cut_id) == cut_objects.end()) + cut_objects[obj->cut_id] = std::set{ obj_idx }; + else + cut_objects.at(obj->cut_id).insert(obj_idx); + } + } + + // check if selected cut objects are "full selected" + for (auto cut_object : cut_objects) + if (cut_object.first.check_sum() != cut_object.second.size()) { + disable_ss_manipulation = true; + break; + } + disable_ununiform_scale = !cut_objects.empty(); + } + } } else { if (item) { @@ -2519,11 +2636,12 @@ void ObjectList::part_selection_changed() const wxDataViewItem parent = m_objects_model->GetParent(item); const ItemType parent_type = m_objects_model->GetItemType(parent); obj_idx = m_objects_model->GetObjectIdByItem(item); + ModelObject* object = (*m_objects)[obj_idx]; if (parent == wxDataViewItem(nullptr) || type == itInfo) { og_name = _L("Object manipulation"); - m_config = &(*m_objects)[obj_idx]->config; + m_config = &object->config; update_and_show_manipulations = true; if (type == itInfo) { @@ -2539,29 +2657,30 @@ void ObjectList::part_selection_changed() case InfoItemType::CustomSeam: case InfoItemType::MmuSegmentation: { - GLGizmosManager::EType gizmo_type = info_type == InfoItemType::CustomSupports ? GLGizmosManager::EType::FdmSupports : - info_type == InfoItemType::CustomSeam ? GLGizmosManager::EType::Seam : + GLGizmosManager::EType gizmo_type = info_type == InfoItemType::CustomSupports ? GLGizmosManager::EType::FdmSupports : + info_type == InfoItemType::CustomSeam ? GLGizmosManager::EType::Seam : GLGizmosManager::EType::MmuSegmentation; - GLGizmosManager& gizmos_mgr = wxGetApp().plater()->canvas3D()->get_gizmos_manager(); if (gizmos_mgr.get_current_type() != gizmo_type) gizmos_mgr.open_gizmo(gizmo_type); break; } - case InfoItemType::Sinking: { break; } + case InfoItemType::Sinking: default: { break; } } } + else + disable_ss_manipulation = object->is_cut(); } else { if (type & itSettings) { if (parent_type & itObject) { og_name = _L("Object Settings to modify"); - m_config = &(*m_objects)[obj_idx]->config; + m_config = &object->config; } else if (parent_type & itVolume) { og_name = _L("Part Settings to modify"); volume_id = m_objects_model->GetVolumeIdByItem(parent); - m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config; + m_config = &object->volumes[volume_id]->config; } else if (parent_type & itLayer) { og_name = _L("Layer range Settings to modify"); @@ -2572,15 +2691,18 @@ void ObjectList::part_selection_changed() else if (type & itVolume) { og_name = _L("Part manipulation"); volume_id = m_objects_model->GetVolumeIdByItem(item); - m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config; + m_config = &object->volumes[volume_id]->config; update_and_show_manipulations = true; + const ModelVolume* volume = object->volumes[volume_id]; + enable_manipulation = !(object->is_cut() && (volume->is_cut_connector() || volume->is_model_part())); } else if (type & itInstance) { og_name = _L("Instance manipulation"); update_and_show_manipulations = true; // fill m_config by object's values - m_config = &(*m_objects)[obj_idx]->config; + m_config = &object->config; + disable_ss_manipulation = object->is_cut(); } else if (type & (itLayerRoot|itLayer)) { og_name = type & itLayerRoot ? _L("Height ranges") : _L("Settings for height range"); @@ -2599,10 +2721,20 @@ void ObjectList::part_selection_changed() wxGetApp().obj_manipul()->get_og()->set_name(" " + og_name + " "); if (item) { - // wxGetApp().obj_manipul()->get_og()->set_value("object_name", m_objects_model->GetName(item)); wxGetApp().obj_manipul()->update_item_name(m_objects_model->GetName(item)); wxGetApp().obj_manipul()->update_warning_icon_state(get_mesh_errors_info(obj_idx, volume_id)); } + + if (disable_ss_manipulation) + wxGetApp().obj_manipul()->DisableScale(); + else { + wxGetApp().obj_manipul()->Enable(enable_manipulation); + if (disable_ununiform_scale) + wxGetApp().obj_manipul()->DisableUnuniformScale(); + } + + if (GLGizmoScale3D* scale = dynamic_cast(gizmos_mgr.get_gizmo(GLGizmosManager::Scale))) + scale->enable_ununiversal_scale(!disable_ununiform_scale); } if (update_and_show_settings) @@ -2625,6 +2757,7 @@ void ObjectList::part_selection_changed() #else wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false); #endif // ENABLE_WORLD_COORDINATE + wxGetApp().plater()->canvas3D()->enable_moving(enable_manipulation); // ysFIXME wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations); wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings); wxGetApp().obj_layers() ->UpdateAndShow(update_and_show_layers); @@ -2683,6 +2816,7 @@ void ObjectList::update_info_items(size_t obj_idx, wxDataViewItemArray* selectio for (InfoItemType type : {InfoItemType::CustomSupports, InfoItemType::CustomSeam, + InfoItemType::CutConnectors, InfoItemType::MmuSegmentation, InfoItemType::Sinking, InfoItemType::VariableLayerHeight}) { @@ -2703,6 +2837,9 @@ void ObjectList::update_info_items(size_t obj_idx, wxDataViewItemArray* selectio }); break; + case InfoItemType::CutConnectors: + should_show = model_object->is_cut() && model_object->has_connectors() && model_object->volumes.size() > 1; + break; case InfoItemType::VariableLayerHeight : should_show = printer_technology() == ptFFF && ! model_object->layer_height_profile.empty(); @@ -2742,33 +2879,74 @@ void ObjectList::update_info_items(size_t obj_idx, wxDataViewItemArray* selectio } } +static wxString extruder2str(int extruder) +{ + return extruder == 0 ? _L("default") : wxString::Format("%d", extruder); +} +static bool can_add_volumes_to_object(const ModelObject* object) +{ + bool can = object->volumes.size() > 1; + + if (can && object->is_cut()) { + int no_connectors_cnt = 0; + for (const ModelVolume* v : object->volumes) + if (!v->is_cut_connector()) { + if (!v->is_model_part()) + return true; + no_connectors_cnt++; + } + can = no_connectors_cnt > 1; + } + + return can; +} + +wxDataViewItemArray ObjectList::add_volumes_to_object_in_list(size_t obj_idx, std::function add_to_selection/* = nullptr*/) +{ + wxDataViewItem object_item = m_objects_model->GetItemById(int(obj_idx)); + m_objects_model->DeleteVolumeChildren(object_item); + + wxDataViewItemArray items; + + const ModelObject* object = (*m_objects)[obj_idx]; + // add volumes to the object + if (can_add_volumes_to_object(object)) { + int volume_idx{ -1 }; + for (const ModelVolume* volume : object->volumes) { + ++volume_idx; + if (object->is_cut() && volume->is_cut_connector()) + continue; + const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(object_item, + from_u8(volume->name), + volume_idx, + volume->type(), + volume->text_configuration.has_value(), + get_warning_icon_name(volume->mesh().stats()), + extruder2str(volume->config.has("extruder") ? volume->config.extruder() : 0)); + add_settings_item(vol_item, &volume->config.get()); + + if (add_to_selection && add_to_selection(volume)) + items.Add(vol_item); + } + Expand(object_item); + } + + return items; +} void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed) { auto model_object = (*m_objects)[obj_idx]; const wxString& item_name = from_u8(model_object->name); - const auto item = m_objects_model->Add(item_name, - model_object->config.has("extruder") ? model_object->config.extruder() : 0, - get_warning_icon_name(model_object->mesh().stats())); + const auto item = m_objects_model->AddObject(item_name, + extruder2str(model_object->config.has("extruder") ? model_object->config.extruder() : 0), + get_warning_icon_name(model_object->mesh().stats()), + model_object->is_cut()); update_info_items(obj_idx, nullptr, call_selection_changed); - // add volumes to the object - if (model_object->volumes.size() > 1 || - model_object->volumes[0]->text_configuration.has_value()) { - for (const ModelVolume* volume : model_object->volumes) { - const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(item, - from_u8(volume->name), - volume->type(), - volume->text_configuration.has_value(), - get_warning_icon_name(volume->mesh().stats()), - volume->config.has("extruder") ? volume->config.extruder() : 0, - false); - add_settings_item(vol_item, &volume->config.get()); - } - Expand(item); - } + add_volumes_to_object_in_list(obj_idx); // add instances to the object, if it has those if (model_object->instances.size()>1) @@ -2822,29 +3000,39 @@ void ObjectList::delete_instance_from_list(const size_t obj_idx, const size_t in select_item([this, obj_idx, inst_idx]() { return m_objects_model->Delete(m_objects_model->GetItemByInstanceId(obj_idx, inst_idx)); }); } -void ObjectList::delete_from_model_and_list(const ItemType type, const int obj_idx, const int sub_obj_idx) +void ObjectList::update_lock_icons_for_model() { - if ( !(type&(itObject|itVolume|itInstance)) ) - return; - - take_snapshot(_(L("Delete Selected Item"))); - - if (type&itObject) { - del_object(obj_idx); - delete_object_from_list(obj_idx); - } - else { - del_subobject_from_object(obj_idx, sub_obj_idx, type); - - type == itVolume ? delete_volume_from_list(obj_idx, sub_obj_idx) : - delete_instance_from_list(obj_idx, sub_obj_idx); - } + for (size_t obj_idx = 0; obj_idx < (*m_objects).size(); ++obj_idx) + if (!(*m_objects)[obj_idx]->is_cut()) + m_objects_model->UpdateLockIcon(m_objects_model->GetItemById(int(obj_idx)), false); } -void ObjectList::delete_from_model_and_list(const std::vector& items_for_delete) +bool ObjectList::delete_from_model_and_list(const ItemType type, const int obj_idx, const int sub_obj_idx) +{ + if (type & (itObject | itVolume | itInstance)) { + if (type & itObject) { + bool was_cut = object(obj_idx)->is_cut(); + if (del_object(obj_idx)) { + delete_object_from_list(obj_idx); + if (was_cut) + update_lock_icons_for_model(); + return true; + } + return false; + } + if (del_subobject_from_object(obj_idx, sub_obj_idx, type)) { + type == itVolume ? delete_volume_from_list(obj_idx, sub_obj_idx) : + delete_instance_from_list(obj_idx, sub_obj_idx); + return true; + } + } + return false; +} + +bool ObjectList::delete_from_model_and_list(const std::vector& items_for_delete) { if (items_for_delete.empty()) - return; + return false; m_prevent_list_events = true; @@ -2853,14 +3041,18 @@ void ObjectList::delete_from_model_and_list(const std::vector& it if (!(item->type&(itObject | itVolume | itInstance))) continue; if (item->type&itObject) { - del_object(item->obj_idx); + bool was_cut = object(item->obj_idx)->is_cut(); + if (!del_object(item->obj_idx)) + return false;// continue; m_objects_model->Delete(m_objects_model->GetItemById(item->obj_idx)); + if (was_cut) + update_lock_icons_for_model(); } else { if (!del_subobject_from_object(item->obj_idx, item->sub_obj_idx, item->type)) continue; if (item->type&itVolume) { - m_objects_model->Delete(m_objects_model->GetItemByVolumeId(item->obj_idx, item->sub_obj_idx)); + add_volumes_to_object_in_list(item->obj_idx); ModelObject* obj = object(item->obj_idx); if (obj->volumes.size() == 1) { wxDataViewItem parent = m_objects_model->GetItemById(item->obj_idx); @@ -2884,8 +3076,12 @@ void ObjectList::delete_from_model_and_list(const std::vector& it update_info_items(id); } - m_prevent_list_events = true; + m_prevent_list_events = false; + if (modified_objects_ids.empty()) + return false; part_selection_changed(); + + return true; } void ObjectList::delete_all_objects_from_list() @@ -2990,8 +3186,10 @@ void ObjectList::remove() { wxDataViewItem parent = m_objects_model->GetParent(item); ItemType type = m_objects_model->GetItemType(item); - if (type & itObject) - delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1); + if (type & itObject) { + if (!delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1)) + return item; + } else { if (type & (itLayer | itInstance)) { // In case there is just one layer or two instances and we delete it, del_subobject_item will @@ -3001,7 +3199,8 @@ void ObjectList::remove() parent = m_objects_model->GetTopParent(item); } - del_subobject_item(item); + if (!del_subobject_item(item)) + return item; } return parent; @@ -3027,6 +3226,8 @@ void ObjectList::remove() if (m_objects_model->InvalidItem(item)) // item can be deleted for this moment (like last 2 Instances or Volumes) continue; parent = delete_item(item); + if (parent == item && m_objects_model->GetItemType(item) & itObject) // Object wasn't deleted + break; } } @@ -3219,7 +3420,7 @@ void ObjectList::add_layer_item(const t_layer_height_range& range, const auto layer_item = m_objects_model->AddLayersChild(layers_item, range, - config.opt_int("extruder"), + extruder2str(config.opt_int("extruder")), layer_idx); add_settings_item(layer_item, &config); } @@ -3313,6 +3514,24 @@ bool ObjectList::is_selected(const ItemType type) const return false; } +bool ObjectList::is_connectors_item_selected() const +{ + const wxDataViewItem& item = GetSelection(); + if (item) + return m_objects_model->GetItemType(item) == itInfo && m_objects_model->GetInfoItemType(item) == InfoItemType::CutConnectors; + + return false; +} + +bool ObjectList::is_connectors_item_selected(const wxDataViewItemArray& sels) const +{ + for (auto item : sels) + if (m_objects_model->GetItemType(item) == itInfo && m_objects_model->GetInfoItemType(item) == InfoItemType::CutConnectors) + return true; + + return false; +} + int ObjectList::get_selected_layers_range_idx() const { const wxDataViewItem& item = GetSelection(); @@ -3439,11 +3658,18 @@ void ObjectList::update_selections() else { for (auto idx : selection.get_volume_idxs()) { const auto gl_vol = selection.get_volume(idx); - if (gl_vol->volume_idx() >= 0) + if (gl_vol->volume_idx() >= 0) { // Only add GLVolumes with non-negative volume_ids. GLVolumes with negative volume ids // are not associated with ModelVolumes, but they are temporarily generated by the backend // (for example, SLA supports or SLA pad). - sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx())); + int obj_idx = gl_vol->object_idx(); + int vol_idx = gl_vol->volume_idx(); + assert(obj_idx >= 0 && vol_idx >= 0); + if (object(obj_idx)->volumes[vol_idx]->is_cut_connector()) + sels.Add(m_objects_model->GetInfoItemByType(m_objects_model->GetItemById(obj_idx), InfoItemType::CutConnectors)); + else + sels.Add(m_objects_model->GetItemByVolumeId(obj_idx, vol_idx)); + } } m_selection_mode = smVolume; } } @@ -3493,11 +3719,34 @@ void ObjectList::update_selections() if (sels.size() == 0 || m_selection_mode & smSettings) m_selection_mode = smUndef; - - select_items(sels); - // Scroll selected Item in the middle of an object list - ensure_current_item_visible(); + if (fix_cut_selection(sels) || is_connectors_item_selected(sels)) { + m_prevent_list_events = true; + + // If some part is selected, unselect all items except of selected parts of the current object + UnselectAll(); + SetSelections(sels); + + m_prevent_list_events = false; + + // update object selection on Plater + if (!m_prevent_canvas_selection_update) + update_selections_on_canvas(); + + // to update the toolbar and info sizer + if (!GetSelection() || m_objects_model->GetItemType(GetSelection()) == itObject || is_connectors_item_selected()) { + auto event = SimpleEvent(EVT_OBJ_LIST_OBJECT_SELECT); + event.SetEventObject(this); + wxPostEvent(this, event); + } + part_selection_changed(); + } + else { + select_items(sels); + + // Scroll selected Item in the middle of an object list + ensure_current_item_visible(); + } } void ObjectList::update_selections_on_canvas() @@ -3531,16 +3780,29 @@ void ObjectList::update_selections_on_canvas() volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end()); } else if (type == itInfo) { - // When selecting an info item, select one instance of the - // respective object - a gizmo may want to be opened. - int inst_idx = selection.get_instance_idx(); - int scene_obj_idx = selection.get_object_idx(); - mode = Selection::Instance; - // select first instance, unless an instance of the object is already selected - if (scene_obj_idx == -1 || inst_idx == -1 || scene_obj_idx != obj_idx) - inst_idx = 0; - std::vector idxs = selection.get_volume_idxs_from_instance(obj_idx, inst_idx); - volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end()); + if (m_objects_model->GetInfoItemType(item) == InfoItemType::CutConnectors) { + mode = Selection::Volume; + + // When selecting CutConnectors info item, select all object volumes, which are marked as a connector + const ModelObject* obj = object(obj_idx); + for (unsigned int vol_idx = 0; vol_idx < obj->volumes.size(); vol_idx++) + if (obj->volumes[vol_idx]->is_cut_connector()) { + std::vector idxs = selection.get_volume_idxs_from_volume(obj_idx, std::max(instance_idx, 0), vol_idx); + volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end()); + } + } + else { + // When selecting an info item, select one instance of the + // respective object - a gizmo may want to be opened. + int inst_idx = selection.get_instance_idx(); + int scene_obj_idx = selection.get_object_idx(); + mode = Selection::Instance; + // select first instance, unless an instance of the object is already selected + if (scene_obj_idx == -1 || inst_idx == -1 || scene_obj_idx != obj_idx) + inst_idx = 0; + std::vector idxs = selection.get_volume_idxs_from_instance(obj_idx, inst_idx); + volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end()); + } } else { @@ -3556,6 +3818,8 @@ void ObjectList::update_selections_on_canvas() if (sel_cnt == 1) { wxDataViewItem item = GetSelection(); + if (m_objects_model->GetInfoItemType(item) == InfoItemType::CutConnectors) + selection.remove_all(); if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer)) add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, mode); else @@ -3826,6 +4090,53 @@ void ObjectList::fix_multiselection_conflicts() m_prevent_list_events = false; } +bool ObjectList::fix_cut_selection(wxDataViewItemArray& sels) +{ + if (wxGetApp().plater()->canvas3D()->get_gizmos_manager().get_current_type() == GLGizmosManager::Scale) { + for (const auto& item : sels) { + if (m_objects_model->GetItemType(item) & (itInstance | itObject) || + (m_objects_model->GetItemType(item) & itSettings && + m_objects_model->GetItemType(m_objects_model->GetParent(item)) & itObject)) { + + bool is_instance_selection = m_objects_model->GetItemType(item) & itInstance; + + int object_idx = m_objects_model->GetObjectIdByItem(item); + int inst_idx = is_instance_selection ? m_objects_model->GetInstanceIdByItem(item) : 0; + + if (auto obj = object(object_idx); obj->is_cut()) { + sels.Clear(); + + auto cut_id = obj->cut_id; + + int objects_cnt = int((*m_objects).size()); + for (int obj_idx = 0; obj_idx < objects_cnt; ++obj_idx) { + auto object = (*m_objects)[obj_idx]; + if (object->is_cut() && object->cut_id.has_same_id(cut_id)) + sels.Add(is_instance_selection ? m_objects_model->GetItemByInstanceId(obj_idx, inst_idx) : m_objects_model->GetItemById(obj_idx)); + } + return true; + } + } + } + } + return false; +} + +void ObjectList::fix_cut_selection() +{ + wxDataViewItemArray sels; + GetSelections(sels); + if (fix_cut_selection(sels)) { + m_prevent_list_events = true; + + // If some part is selected, unselect all items except of selected parts of the current object + UnselectAll(); + SetSelections(sels); + + m_prevent_list_events = false; + } +} + ModelVolume* ObjectList::get_selected_model_volume() { wxDataViewItem item = GetSelection(); @@ -3856,10 +4167,11 @@ void ObjectList::change_part_type() if (obj_idx < 0) return; const ModelVolumeType type = volume->type(); + const ModelObject* obj = object(obj_idx); if (type == ModelVolumeType::MODEL_PART) { int model_part_cnt = 0; - for (auto vol : (*m_objects)[obj_idx]->volumes) { + for (auto vol : obj->volumes) { if (vol->type() == ModelVolumeType::MODEL_PART) ++model_part_cnt; } @@ -3870,14 +4182,19 @@ void ObjectList::change_part_type() } } + wxArrayString names; - for (const wxString& name : { _L("Part"), _L("Negative Volume"), _L("Modifier") }) - names.Add(name); +// names.Alloc(is_cut_object ? 3 : 5); + if (!is_cut_object) + for (const wxString& type : { _L("Part"), _L("Negative Volume") }) + names.Add(type); + names.Add(_L("Modifier")) if (!volume->text_configuration.has_value()) for (const wxString& name : { _L("Support Blocker"), _L("Support Enforcer") }) names.Add(name); - auto new_type = ModelVolumeType(wxGetSingleChoiceIndex(_L("Type:"), _L("Select type of part"), names, int(type))); + const int type_shift = is_cut_object ? 2 : 0; + auto new_type = ModelVolumeType(type_shift + wxGetApp().GetSingleChoiceIndex(_L("Type:"), _L("Select type of part"), names, int(type) - type_shift)); if (new_type == type || new_type == ModelVolumeType::INVALID) return; @@ -4397,34 +4714,14 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const wxGetApp().plater()->update(); } -wxDataViewItemArray ObjectList::reorder_volumes_and_get_selection(int obj_idx, std::function add_to_selection/* = nullptr*/) +wxDataViewItemArray ObjectList::reorder_volumes_and_get_selection(size_t obj_idx, std::function add_to_selection/* = nullptr*/) { - wxDataViewItemArray items; + (*m_objects)[obj_idx]->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1"); - ModelObject* object = (*m_objects)[obj_idx]; - if (object->volumes.size() <= 1) - return items; + wxDataViewItemArray items = add_volumes_to_object_in_list(obj_idx, std::move(add_to_selection)); - object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1"); + changed_object(int(obj_idx)); - wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx); - m_objects_model->DeleteVolumeChildren(object_item); - - for (const ModelVolume* volume : object->volumes) { - wxDataViewItem vol_item = m_objects_model->AddVolumeChild(object_item, from_u8(volume->name), - volume->type(), - volume->text_configuration.has_value(), - get_warning_icon_name(volume->mesh().stats()), - volume->config.has("extruder") ? volume->config.extruder() : 0, - false); - // add settings to the part, if it has those - add_settings_item(vol_item, &volume->config.get()); - - if (add_to_selection && add_to_selection(volume)) - items.Add(vol_item); - } - - changed_object(obj_idx); return items; } diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 173929e2d..f1b37a95d 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -248,7 +248,7 @@ public: void add_category_to_settings_from_frequent(const std::vector& category_options, wxDataViewItem item); void show_settings(const wxDataViewItem settings_item); bool is_instance_or_object_selected(); - + bool is_selected_object_cut(); void load_subobject(ModelVolumeType type, bool from_galery = false); // ! ysFIXME - delete commented code after testing and rename "load_modifier" to something common //void load_part(ModelObject& model_object, std::vector& added_volumes, ModelVolumeType type, bool from_galery = false); @@ -259,8 +259,8 @@ public: void load_shape_object_from_gallery(const wxArrayString& input_files); void load_mesh_object(const TriangleMesh &mesh, const std::string &name, bool center = true, const TextConfiguration* text_config = nullptr, const Transform3d* transformation = nullptr); - void del_object(const int obj_idx); - void del_subobject_item(wxDataViewItem& item); + bool del_object(const int obj_idx); + bool del_subobject_item(wxDataViewItem& item); void del_settings_from_config(const wxDataViewItem& parent_item); void del_instances_from_object(const int obj_idx); void del_layer_from_object(const int obj_idx, const t_layer_height_range& layer_range); @@ -279,6 +279,9 @@ public: bool is_splittable(bool to_objects); bool selected_instances_of_same_object(); bool can_split_instances(); + bool has_selected_cut_object() const; + void invalidate_cut_info_for_selection(); + void invalidate_cut_info_for_object(size_t obj_idx); bool can_merge_to_multipart_object() const; bool can_merge_to_single_object() const; @@ -290,6 +293,9 @@ public: void changed_object(const int obj_idx = -1) const; void part_selection_changed(); + // Add object's volumes to the list + // Return selected items, if add_to_selection is defined + wxDataViewItemArray add_volumes_to_object_in_list(size_t obj_idx, std::function add_to_selection = nullptr); // Add object to the list void add_object_to_list(size_t obj_idx, bool call_selection_changed = true); // Delete object from the list @@ -297,8 +303,9 @@ public: void delete_object_from_list(const size_t obj_idx); void delete_volume_from_list(const size_t obj_idx, const size_t vol_idx); void delete_instance_from_list(const size_t obj_idx, const size_t inst_idx); - void delete_from_model_and_list(const ItemType type, const int obj_idx, const int sub_obj_idx); - void delete_from_model_and_list(const std::vector& items_for_delete); + void update_lock_icons_for_model(); + bool delete_from_model_and_list(const ItemType type, const int obj_idx, const int sub_obj_idx); + bool delete_from_model_and_list(const std::vector& items_for_delete); // Delete all objects from the list void delete_all_objects_from_list(); // Increase instances count @@ -341,6 +348,8 @@ public: void init_objects(); bool multiple_selection() const ; bool is_selected(const ItemType type) const; + bool is_connectors_item_selected() const; + bool is_connectors_item_selected(const wxDataViewItemArray& sels) const; int get_selected_layers_range_idx() const; void set_selected_layers_range_idx(const int range_idx) { m_selected_layers_range_idx = range_idx; } void set_selection_mode(SELECTION_MODE mode) { m_selection_mode = mode; } @@ -355,6 +364,9 @@ public: bool check_last_selection(wxString& msg_str); // correct current selections to avoid of the possible conflicts void fix_multiselection_conflicts(); + // correct selection in respect to the cut_id if any exists + void fix_cut_selection(); + bool fix_cut_selection(wxDataViewItemArray& sels); ModelVolume* get_selected_model_volume(); void change_part_type(); @@ -390,7 +402,7 @@ public: void toggle_printable_state(); void set_extruder_for_selected_items(const int extruder) const ; - wxDataViewItemArray reorder_volumes_and_get_selection(int obj_idx, std::function add_to_selection = nullptr); + wxDataViewItemArray reorder_volumes_and_get_selection(size_t obj_idx, std::function add_to_selection = nullptr); void apply_volumes_order(); bool has_paint_on_segmentation(); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 9dc119917..c74814540 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -576,6 +576,35 @@ void ObjectManipulation::UpdateAndShow(const bool show) OG_Settings::UpdateAndShow(show); } +void ObjectManipulation::Enable(const bool enadle) +{ + for (auto editor : m_editors) + editor->Enable(enadle); + for (wxWindow* win : std::initializer_list{ m_reset_scale_button, m_reset_rotation_button, m_drop_to_bed_button, m_check_inch, m_lock_bnt +#if ENABLE_WORLD_COORDINATE + ,m_reset_skew_button +#endif // ENABLE_WORLD_COORDINATE + }) + win->Enable(enadle); +} + +void ObjectManipulation::DisableScale() +{ + for (auto editor : m_editors) + editor->Enable(editor->has_opt_key("scale") || editor->has_opt_key("size") ? false : true); + for (wxWindow* win : std::initializer_list{ m_reset_scale_button, m_lock_bnt +#if ENABLE_WORLD_COORDINATE + ,m_reset_skew_button +#endif // ENABLE_WORLD_COORDINATE + }) + win->Enable(false); +} + +void ObjectManipulation::DisableUnuniformScale() +{ + m_lock_bnt->Enable(false); +} + void ObjectManipulation::update_ui_from_settings() { if (m_imperial_units != (wxGetApp().app_config->get("use_inches") == "1")) { @@ -734,7 +763,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) #endif // ENABLE_WORLD_COORDINATE m_new_enabled = true; } - else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) { + else if (obj_list->is_connectors_item_selected() || obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) { reset_settings_value(); m_new_move_label_string = L("Translate"); m_new_rotate_label_string = L("Rotate"); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index e9ffe804a..9995b3e6f 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -64,6 +64,8 @@ public: const std::string& get_full_opt_name() const { return m_full_opt_name; } #endif // ENABLE_WORLD_COORDINATE + bool has_opt_key(const std::string& key) { return m_opt_key == key; } + private: double get_value(); }; @@ -197,6 +199,10 @@ public: void Show(const bool show) override; bool IsShown() override; void UpdateAndShow(const bool show) override; + void Enable(const bool enadle = true); + void Disable() { Enable(false); } + void DisableScale(); + void DisableUnuniformScale(); void update_ui_from_settings(); bool use_colors() { return m_use_colors; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index b52099e07..36aabf31a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -313,8 +313,8 @@ void GLGizmoBase::set_hover_id(int id) assert(!m_dragging); // allow empty grabbers when not using grabbers but use hover_id - flatten, rotate - if (!m_grabbers.empty() && id >= (int) m_grabbers.size()) - return; +// if (!m_grabbers.empty() && id >= (int) m_grabbers.size()) +// return; m_hover_id = id; on_set_hover_id(); @@ -406,15 +406,15 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) { } if (mouse_event.LeftDown()) { - Selection &selection = m_parent.get_selection(); - if (!selection.is_empty() && m_hover_id != -1 && - (m_grabbers.empty() || m_hover_id < static_cast(m_grabbers.size()))) { + Selection &selection = m_parent.get_selection(); + if (!selection.is_empty() && m_hover_id != -1 /* && + (m_grabbers.empty() || m_hover_id < static_cast(m_grabbers.size()))*/) { selection.setup_cache(); m_dragging = true; for (auto &grabber : m_grabbers) grabber.dragging = false; - if (!m_grabbers.empty() && m_hover_id < int(m_grabbers.size())) - m_grabbers[m_hover_id].dragging = true; +// if (!m_grabbers.empty() && m_hover_id < int(m_grabbers.size())) +// m_grabbers[m_hover_id].dragging = true; on_start_dragging(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 5971d1a4c..1d134948d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -215,6 +215,9 @@ public: void unregister_raycasters_for_picking() { unregister_grabbers_for_picking(); on_unregister_raycasters_for_picking(); } #endif // ENABLE_RAYCAST_PICKING + virtual bool is_in_editing_mode() const { return false; } + virtual bool is_selection_rectangle_dragging() const { return false; } + protected: virtual bool on_init() = 0; virtual void on_load(cereal::BinaryInputArchive& ar) {} diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 8767fecb2..14b31d7c5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -4,465 +4,2276 @@ #include -#include -#include -#include -#include - #include #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/GUI_ObjectManipulation.hpp" +#include "slic3r/GUI/format.hpp" +#include "slic3r/Utils/UndoRedo.hpp" #include "libslic3r/AppConfig.hpp" -#include "libslic3r/Model.hpp" #include "libslic3r/TriangleMeshSlicer.hpp" +#include "imgui/imgui_internal.h" + namespace Slic3r { namespace GUI { -const double GLGizmoCut::Offset = 10.0; -const double GLGizmoCut::Margin = 20.0; -static const ColorRGBA GRABBER_COLOR = ColorRGBA::ORANGE(); +static const ColorRGBA GRABBER_COLOR = ColorRGBA::YELLOW(); -GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) +// connector colors +static const ColorRGBA PLAG_COLOR = ColorRGBA::YELLOW(); +static const ColorRGBA DOWEL_COLOR = ColorRGBA::DARK_YELLOW(); +static const ColorRGBA HOVERED_PLAG_COLOR = ColorRGBA::CYAN(); +static const ColorRGBA HOVERED_DOWEL_COLOR = ColorRGBA(0.0f, 0.5f, 0.5f, 1.0f); +static const ColorRGBA SELECTED_PLAG_COLOR = ColorRGBA::GRAY(); +static const ColorRGBA SELECTED_DOWEL_COLOR = ColorRGBA::DARK_GRAY(); +static const ColorRGBA CONNECTOR_DEF_COLOR = ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f); +static const ColorRGBA CONNECTOR_ERR_COLOR = ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f); + +const unsigned int AngleResolution = 64; +const unsigned int ScaleStepsCount = 72; +const float ScaleStepRad = 2.0f * float(PI) / ScaleStepsCount; +const unsigned int ScaleLongEvery = 2; +const float ScaleLongTooth = 0.1f; // in percent of radius +const unsigned int SnapRegionsCount = 8; + +const float UndefFloat = -999.f; +const std::string UndefLabel = " "; + +using namespace Geometry; + +// Generates mesh for a line +static GLModel::Geometry its_make_line(Vec3f beg_pos, Vec3f end_pos) +{ + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; + init_data.reserve_vertices(2); + init_data.reserve_indices(2); + + // vertices + init_data.add_vertex(beg_pos); + init_data.add_vertex(end_pos); + + // indices + init_data.add_line(0, 1); + return init_data; +} + +// Generates mesh for a square plane +static GLModel::Geometry its_make_square_plane(float radius) +{ + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; + init_data.reserve_vertices(4); + init_data.reserve_indices(6); + + // vertices + init_data.add_vertex(Vec3f(-radius, -radius, 0.0)); + init_data.add_vertex(Vec3f(radius , -radius, 0.0)); + init_data.add_vertex(Vec3f(radius , radius , 0.0)); + init_data.add_vertex(Vec3f(-radius, radius , 0.0)); + + // indices + init_data.add_triangle(0, 1, 2); + init_data.add_triangle(2, 3, 0); + return init_data; +} + +//! -- #ysFIXME those functions bodies are ported from GizmoRotation +// Generates mesh for a circle +static void init_from_circle(GLModel& model, double radius) +{ + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P3 }; + init_data.reserve_vertices(ScaleStepsCount); + init_data.reserve_indices(ScaleStepsCount); + + // vertices + indices + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + const float angle = float(i * ScaleStepRad); + init_data.add_vertex(Vec3f(::cos(angle) * float(radius), ::sin(angle) * float(radius), 0.0f)); + init_data.add_index(i); + } + + model.init_from(std::move(init_data)); + model.set_color(ColorRGBA::WHITE()); +} + +// Generates mesh for a scale +static void init_from_scale(GLModel& model, double radius) +{ + const float out_radius_long = float(radius) * (1.0f + ScaleLongTooth); + const float out_radius_short = float(radius) * (1.0f + 0.5f * ScaleLongTooth); + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; + init_data.reserve_vertices(2 * ScaleStepsCount); + init_data.reserve_indices(2 * ScaleStepsCount); + + // vertices + indices + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + const float angle = float(i * ScaleStepRad); + const float cosa = ::cos(angle); + const float sina = ::sin(angle); + const float in_x = cosa * float(radius); + const float in_y = sina * float(radius); + const float out_x = (i % ScaleLongEvery == 0) ? cosa * out_radius_long : cosa * out_radius_short; + const float out_y = (i % ScaleLongEvery == 0) ? sina * out_radius_long : sina * out_radius_short; + + // vertices + init_data.add_vertex(Vec3f(in_x, in_y, 0.0f)); + init_data.add_vertex(Vec3f(out_x, out_y, 0.0f)); + + // indices + init_data.add_line(i * 2, i * 2 + 1); + } + + model.init_from(std::move(init_data)); + model.set_color(ColorRGBA::WHITE()); +} + +// Generates mesh for a snap_radii +static void init_from_snap_radii(GLModel& model, double radius) +{ + const float step = 2.0f * float(PI) / float(SnapRegionsCount); + const float in_radius = float(radius) / 3.0f; + const float out_radius = 2.0f * in_radius; + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; + init_data.reserve_vertices(2 * ScaleStepsCount); + init_data.reserve_indices(2 * ScaleStepsCount); + + // vertices + indices + for (unsigned int i = 0; i < ScaleStepsCount; ++i) { + const float angle = float(i) * step; + const float cosa = ::cos(angle); + const float sina = ::sin(angle); + const float in_x = cosa * in_radius; + const float in_y = sina * in_radius; + const float out_x = cosa * out_radius; + const float out_y = sina * out_radius; + + // vertices + init_data.add_vertex(Vec3f(in_x, in_y, 0.0f)); + init_data.add_vertex(Vec3f(out_x, out_y, 0.0f)); + + // indices + init_data.add_line(i * 2, i * 2 + 1); + } + + model.init_from(std::move(init_data)); + model.set_color(ColorRGBA::WHITE()); +} + +// Generates mesh for a angle_arc +static void init_from_angle_arc(GLModel& model, double angle, double radius) +{ + model.reset(); + + const float step_angle = float(angle) / float(AngleResolution); + const float ex_radius = float(radius); + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3 }; + init_data.reserve_vertices(1 + AngleResolution); + init_data.reserve_indices(1 + AngleResolution); + + // vertices + indices + for (unsigned int i = 0; i <= AngleResolution; ++i) { + const float angle = float(i) * step_angle; + init_data.add_vertex(Vec3f(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f)); + init_data.add_index(i); + } + + model.init_from(std::move(init_data)); +} + +//! -- + +GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -{} - -std::string GLGizmoCut::get_tooltip() const + , m_connectors_group_id (3) + , m_connector_type (CutConnectorType::Plug) + , m_connector_style (size_t(CutConnectorStyle::Prizm)) + , m_connector_shape_id (size_t(CutConnectorShape::Circle)) { - double cut_z = m_cut_z; - if (wxGetApp().app_config->get("use_inches") == "1") - cut_z *= ObjectManipulation::mm_to_in; + m_modes = { _u8L("Planar")//, _u8L("Grid") +// , _u8L("Radial"), _u8L("Modular") + }; - return (m_hover_id == 0 || m_grabbers[0].dragging) ? "Z: " + format(cut_z, 2) : ""; + m_connector_modes = { _u8L("Auto"), _u8L("Manual") }; + m_connector_types = { _u8L("Plug"), _u8L("Dowel") }; + + m_connector_styles = { _u8L("Prizm"), _u8L("Frustum") +// , _u8L("Claw") + }; + + m_connector_shapes = { _u8L("Triangle"), _u8L("Square"), _u8L("Hexagon"), _u8L("Circle") +// , _u8L("D-shape") + }; + + m_axis_names = { "X", "Y", "Z" }; + + update_connector_shape(); } -bool GLGizmoCut::on_mouse(const wxMouseEvent &mouse_event) +std::string GLGizmoCut3D::get_tooltip() const { - return use_grabbers(mouse_event); + std::string tooltip; + if (m_hover_id == Z) { + double koef = m_imperial_units ? ObjectManipulation::mm_to_in : 1.0; + std::string unit_str = " " + (m_imperial_units ? _u8L("inch") : _u8L("mm")); + const BoundingBoxf3 tbb = transformed_bounding_box(m_plane_center); + if (tbb.max.z() >= 0.0) { + double top = (tbb.min.z() <= 0.0 ? tbb.max.z() : tbb.size().z()) * koef; + tooltip += format(top, 2) + " " + unit_str + " (" + _u8L("Top part") + ")"; + if (tbb.min.z() <= 0.0) + tooltip += "\n"; + } + if (tbb.min.z() <= 0.0) { + double bottom = (tbb.max.z() <= 0.0 ? tbb.size().z() : (tbb.min.z() * (-1))) * koef; + tooltip += format(bottom, 2) + " " + unit_str + " (" + _u8L("Bottom part") + ")"; + } + return tooltip; + } + if (tooltip.empty() && (m_hover_id == X || m_hover_id == Y)) { + std::string axis = m_hover_id == X ? "X" : "Y"; + return axis + ": " + format(float(rad2deg(m_angle)), 1) + _u8L("°"); + } + + return tooltip; } -bool GLGizmoCut::on_init() +bool GLGizmoCut3D::on_mouse(const wxMouseEvent &mouse_event) { - m_grabbers.emplace_back(); - m_shortcut_key = WXK_CONTROL_C; - return true; + Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); + Vec2d mouse_pos = mouse_coord.cast(); + + if (mouse_event.ShiftDown() && mouse_event.LeftDown()) + return gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown()); + if (cut_line_processing()) { + if (mouse_event.ShiftDown()) { + if (mouse_event.Moving()|| mouse_event.Dragging()) + return gizmo_event(SLAGizmoEventType::Moving, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown()); + if (mouse_event.LeftUp()) + return gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown()); + } + discard_cut_line_processing(); + } + else if (mouse_event.Moving()) + return false; + + if (use_grabbers(mouse_event)) { + if (m_hover_id >= m_connectors_group_id) { + if (mouse_event.LeftDown() && !mouse_event.CmdDown()&& !mouse_event.AltDown()) + unselect_all_connectors(); + if (mouse_event.LeftUp() && !mouse_event.ShiftDown()) + gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown()); + } + return true; + } + + static bool pending_right_up = false; + if (mouse_event.LeftDown()) { + bool grabber_contains_mouse = (get_hover_id() != -1); + const bool shift_down = mouse_event.ShiftDown(); + if ((!shift_down || grabber_contains_mouse) && + gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false)) + return true; + } + else if (mouse_event.Dragging()) { + bool control_down = mouse_event.CmdDown(); + if (m_parent.get_move_volume_id() != -1) { + // don't allow dragging objects with the Sla gizmo on + return true; + } + if (!control_down && + gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false)) { + // the gizmo got the event and took some action, no need to do + // anything more here + m_parent.set_as_dirty(); + return true; + } + if (control_down && (mouse_event.LeftIsDown() || mouse_event.RightIsDown())) { + // CTRL has been pressed while already dragging -> stop current action + if (mouse_event.LeftIsDown()) + gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), true); + else if (mouse_event.RightIsDown()) + pending_right_up = false; + } + } + else if (mouse_event.LeftUp() && !m_parent.is_mouse_dragging()) { + // in case SLA/FDM gizmo is selected, we just pass the LeftUp event + // and stop processing - neither object moving or selecting is + // suppressed in that case + gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), mouse_event.CmdDown()); + return true; + } + else if (mouse_event.RightDown()) { + if (m_parent.get_selection().get_object_idx() != -1 && + gizmo_event(SLAGizmoEventType::RightDown, mouse_pos, false, false, false)) { + // we need to set the following right up as processed to avoid showing + // the context menu if the user release the mouse over the object + pending_right_up = true; + // event was taken care of by the SlaSupports gizmo + return true; + } + } + else if (pending_right_up && mouse_event.RightUp()) { + pending_right_up = false; + return true; + } + return false; } -std::string GLGizmoCut::on_get_name() const +void GLGizmoCut3D::shift_cut_z(double delta) { - return _u8L("Cut"); + Vec3d new_cut_center = m_plane_center; + new_cut_center[Z] += delta; + set_center(new_cut_center); } -void GLGizmoCut::on_set_state() +void GLGizmoCut3D::rotate_vec3d_around_plane_center(Vec3d&vec) { - // Reset m_cut_z on gizmo activation - if (m_state == On) - m_cut_z = bounding_box().center().z(); + vec = Transformation( assemble_transform(m_plane_center) * m_rotation_m * assemble_transform(-m_plane_center)).get_matrix() * vec; } -bool GLGizmoCut::on_is_activable() const +void GLGizmoCut3D::put_connectors_on_cut_plane(const Vec3d& cp_normal, double cp_offset) { - const Selection& selection = m_parent.get_selection(); - return selection.is_single_full_instance() && !selection.is_wipe_tower(); + ModelObject* mo = m_c->selection_info()->model_object(); + if (CutConnectors& connectors = mo->cut_connectors; !connectors.empty()) { + const float sla_shift = m_c->selection_info()->get_sla_shift(); + const Vec3d& instance_offset = mo->instances[m_c->selection_info()->get_active_instance()]->get_offset(); + + for (auto& connector : connectors) { + // convert connetor pos to the world coordinates + Vec3d pos = connector.pos + instance_offset; + pos[Z] += sla_shift; + // scalar distance from point to plane along the normal + double distance = -cp_normal.dot(pos) + cp_offset; + // move connector + connector.pos += distance * cp_normal; + } + } } -void GLGizmoCut::on_start_dragging() +void GLGizmoCut3D::update_clipper() { - if (m_hover_id == -1) + BoundingBoxf3 box = bounding_box(); + + Vec3d beg, end = beg = m_plane_center; + beg[Z] = box.center().z() - m_radius; + end[Z] = box.center().z() + m_radius; + + rotate_vec3d_around_plane_center(beg); + rotate_vec3d_around_plane_center(end); + + double dist = (m_plane_center - beg).norm(); + + // calculate normal and offset for clipping plane + Vec3d normal = end - beg; + if (normal == Vec3d::Zero()) + return; + dist = std::clamp(dist, 0.0001, normal.norm()); + normal.normalize(); + const double offset = normal.dot(beg) + dist; + + m_c->object_clipper()->set_range_and_pos(normal, offset, dist); + + put_connectors_on_cut_plane(normal, offset); + + if (m_raycasters.empty()) + on_register_raycasters_for_picking(); + else + update_raycasters_for_picking_transform(); +} + +void GLGizmoCut3D::update_clipper_on_render() +{ + update_clipper(); + force_update_clipper_on_render = false; +} + +void GLGizmoCut3D::set_center(const Vec3d& center) +{ + set_center_pos(center); + update_clipper(); +} + +bool GLGizmoCut3D::render_combo(const std::string& label, const std::vector& lines, size_t& selection_idx) +{ + ImGui::AlignTextToFramePadding(); + m_imgui->text(label); + ImGui::SameLine(m_label_width); + ImGui::PushItemWidth(m_control_width); + + size_t selection_out = selection_idx; + // It is necessary to use BeginGroup(). Otherwise, when using SameLine() is called, then other items will be drawn inside the combobox. + ImGui::BeginGroup(); + ImVec2 combo_pos = ImGui::GetCursorScreenPos(); + if (ImGui::BeginCombo(("##"+label).c_str(), "")) { + for (size_t line_idx = 0; line_idx < lines.size(); ++line_idx) { + ImGui::PushID(int(line_idx)); + if (ImGui::Selectable("", line_idx == selection_idx)) + selection_out = line_idx; + + ImGui::SameLine(); + ImGui::Text("%s", lines[line_idx].c_str()); + ImGui::PopID(); + } + + ImGui::EndCombo(); + } + + ImVec2 backup_pos = ImGui::GetCursorScreenPos(); + ImGuiStyle& style = ImGui::GetStyle(); + + ImGui::SetCursorScreenPos(ImVec2(combo_pos.x + style.FramePadding.x, combo_pos.y + style.FramePadding.y)); + ImGui::Text("%s", selection_out < lines.size() ? lines[selection_out].c_str() : UndefLabel.c_str()); + ImGui::SetCursorScreenPos(backup_pos); + ImGui::EndGroup(); + + bool is_changed = selection_idx != selection_out; + selection_idx = selection_out; + + if (is_changed) + update_connector_shape(); + + return is_changed; +} + +bool GLGizmoCut3D::render_double_input(const std::string& label, double& value_in) +{ + ImGui::AlignTextToFramePadding(); + m_imgui->text(label); + ImGui::SameLine(m_label_width); + ImGui::PushItemWidth(m_control_width); + + double value = value_in; + if (m_imperial_units) + value *= ObjectManipulation::mm_to_in; + double old_val = value; + ImGui::InputDouble(("##" + label).c_str(), &value, 0.0f, 0.0f, "%.2f", ImGuiInputTextFlags_CharsDecimal); + + ImGui::SameLine(); + m_imgui->text(m_imperial_units ? _L("in") : _L("mm")); + + value_in = value * (m_imperial_units ? ObjectManipulation::in_to_mm : 1.0); + return !is_approx(old_val, value); +} + +bool GLGizmoCut3D::render_slider_double_input(const std::string& label, float& value_in, float& tolerance_in) +{ + ImGui::AlignTextToFramePadding(); + m_imgui->text(label); + ImGui::SameLine(m_label_width); + ImGui::PushItemWidth(m_control_width * 0.85f); + + float value = value_in; + if (m_imperial_units) + value *= float(ObjectManipulation::mm_to_in); + float old_val = value; + + constexpr float UndefMinVal = -0.1f; + + const BoundingBoxf3 bbox = bounding_box(); + float mean_size = float((bbox.size().x() + bbox.size().y() + bbox.size().z()) / 9.0); + float min_size = value_in < 0.f ? UndefMinVal : 2.f; + if (m_imperial_units) { + mean_size *= float(ObjectManipulation::mm_to_in); + min_size *= float(ObjectManipulation::mm_to_in); + } + std::string format = value_in < 0.f ? UndefLabel : + m_imperial_units ? "%.4f " + _u8L("in") : "%.2f " + _u8L("mm"); + + m_imgui->slider_float(("##" + label).c_str(), &value, min_size, mean_size, format.c_str()); + value_in = value * float(m_imperial_units ? ObjectManipulation::in_to_mm : 1.0); + + ImGui::SameLine(m_label_width + m_control_width + 3); + ImGui::PushItemWidth(m_control_width * 0.3f); + + float old_tolerance, tolerance = old_tolerance = tolerance_in * 100.f; + std::string format_t = tolerance_in < 0.f ? UndefLabel : "%.f %%"; + float min_tolerance = tolerance_in < 0.f ? UndefMinVal : 0.f; + + m_imgui->slider_float(("##tolerance_" + label).c_str(), &tolerance, min_tolerance, 20.f, format_t.c_str(), 1.f, true, _L("Tolerance")); + tolerance_in = tolerance * 0.01f; + + return !is_approx(old_val, value) || !is_approx(old_tolerance, tolerance); +} + +void GLGizmoCut3D::render_move_center_input(int axis) +{ + m_imgui->text(m_axis_names[axis]+":"); + ImGui::SameLine(); + ImGui::PushItemWidth(0.3f*m_control_width); + + Vec3d move = m_plane_center; + double in_val, value = in_val = move[axis]; + if (m_imperial_units) + value *= ObjectManipulation::mm_to_in; + ImGui::InputDouble(("##move_" + m_axis_names[axis]).c_str(), &value, 0.0, 0.0, "%.2f", ImGuiInputTextFlags_CharsDecimal); + ImGui::SameLine(); + + double val = value * (m_imperial_units ? ObjectManipulation::in_to_mm : 1.0); + + if (in_val != val) { + move[axis] = val; + set_center(move); + } +} + +bool GLGizmoCut3D::render_connect_type_radio_button(CutConnectorType type) +{ + ImGui::SameLine(type == CutConnectorType::Plug ? m_label_width : 2*m_label_width); + ImGui::PushItemWidth(m_control_width); + if (m_imgui->radio_button(m_connector_types[size_t(type)], m_connector_type == type)) { + m_connector_type = type; + update_connector_shape(); + return true; + } + return false; +} + +void GLGizmoCut3D::render_connect_mode_radio_button(CutConnectorMode mode) +{ + ImGui::SameLine(mode == CutConnectorMode::Auto ? m_label_width : 2*m_label_width); + ImGui::PushItemWidth(m_control_width); + if (m_imgui->radio_button(m_connector_modes[int(mode)], m_connector_mode == mode)) + m_connector_mode = mode; +} + +bool GLGizmoCut3D::render_reset_button(const std::string& label_id, const std::string& tooltip) const +{ + const ImGuiStyle& style = ImGui::GetStyle(); + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 1, style.ItemSpacing.y }); + + ImGui::PushStyleColor(ImGuiCol_Button, { 0.25f, 0.25f, 0.25f, 0.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.4f, 0.4f, 0.4f, 1.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.4f, 0.4f, 0.4f, 1.0f }); + + std::string btn_label; + btn_label += ImGui::RevertButton; + const bool revert = ImGui::Button((btn_label +"##" + label_id).c_str()); + + ImGui::PopStyleColor(3); + + if (ImGui::IsItemHovered()) + m_imgui->tooltip(tooltip.c_str(), ImGui::GetFontSize() * 20.0f); + + ImGui::PopStyleVar(); + + return revert; +} + +static Vec2d ndc_to_ss(const Vec3d& ndc, const std::array& viewport) { + const double half_w = 0.5 * double(viewport[2]); + const double half_h = 0.5 * double(viewport[3]); + return { half_w * ndc.x() + double(viewport[0]) + half_w, half_h * ndc.y() + double(viewport[1]) + half_h }; +}; +static Vec3d clip_to_ndc(const Vec4d& clip) { + return Vec3d(clip.x(), clip.y(), clip.z()) / clip.w(); +} +static Vec4d world_to_clip(const Vec3d& world, const Matrix4d& projection_view_matrix) { + return projection_view_matrix * Vec4d(world.x(), world.y(), world.z(), 1.0); +} +static Vec2d world_to_ss(const Vec3d& world, const Matrix4d& projection_view_matrix, const std::array& viewport) { + return ndc_to_ss(clip_to_ndc(world_to_clip(world, projection_view_matrix)), viewport); +} + +static wxString get_label(Vec3d vec) +{ + wxString str = "x=" + double_to_string(vec.x(), 2) + + ", y=" + double_to_string(vec.y(), 2) + + ", z=" + double_to_string(vec.z(), 2); + return str; +} + +static wxString get_label(Vec2d vec) +{ + wxString str = "x=" + double_to_string(vec.x(), 2) + + ", y=" + double_to_string(vec.y(), 2); + return str; +} + +void GLGizmoCut3D::render_cut_plane() +{ + if (cut_line_processing()) return; - const BoundingBoxf3 box = bounding_box(); - m_max_z = box.max.z(); - m_start_z = m_cut_z; - m_drag_pos = m_grabbers[m_hover_id].center; - m_drag_center = box.center(); - m_drag_center.z() = m_cut_z; -} + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; -void GLGizmoCut::on_dragging(const UpdateData &data) -{ - assert(m_hover_id != -1); - set_cut_z(m_start_z + calc_projection(data.mouse_ray)); -} - -void GLGizmoCut::on_render() -{ - const BoundingBoxf3 box = bounding_box(); - Vec3d plane_center = box.center(); - plane_center.z() = m_cut_z; - m_max_z = box.max.z(); - set_cut_z(m_cut_z); - - update_contours(); - - const float min_x = box.min.x() - Margin; - const float max_x = box.max.x() + Margin; - const float min_y = box.min.y() - Margin; - const float max_y = box.max.y() + Margin; glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_CULL_FACE)); glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); -#if ENABLE_LEGACY_OPENGL_REMOVAL -#if ENABLE_GL_CORE_PROFILE - const Vec3d diff = plane_center - m_old_center; - // Z changed when move with cut plane - // X and Y changed when move with cutted object - bool is_changed = std::abs(diff.x()) > EPSILON || std::abs(diff.y()) > EPSILON || std::abs(diff.z()) > EPSILON; -#endif // ENABLE_GL_CORE_PROFILE + shader->start_using(); - GLShaderProgram* shader = wxGetApp().get_shader("flat"); - if (shader != nullptr) { - shader->start_using(); -#if !ENABLE_GL_CORE_PROFILE - const Vec3d diff = plane_center - m_old_center; - // Z changed when move with cut plane - // X and Y changed when move with cutted object - bool is_changed = std::abs(diff.x()) > EPSILON || - std::abs(diff.y()) > EPSILON || - std::abs(diff.z()) > EPSILON; -#endif // !ENABLE_GL_CORE_PROFILE - m_old_center = plane_center; + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_model_matrix = camera.get_view_matrix() * translation_transform(m_plane_center) * m_rotation_m; - if (!m_plane.is_initialized() || is_changed) { - m_plane.reset(); + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; - init_data.color = { 0.8f, 0.8f, 0.8f, 0.5f }; - init_data.reserve_vertices(4); - init_data.reserve_indices(6); + if (can_perform_cut()) +// m_plane.set_color({ 0.8f, 0.8f, 0.8f, 0.5f }); + m_plane.set_color({ 0.9f, 0.9f, 0.9f, 0.5f }); + else + m_plane.set_color({ 1.0f, 0.8f, 0.8f, 0.5f }); + m_plane.render(); - // vertices - init_data.add_vertex(Vec3f(min_x, min_y, plane_center.z())); - init_data.add_vertex(Vec3f(max_x, min_y, plane_center.z())); - init_data.add_vertex(Vec3f(max_x, max_y, plane_center.z())); - init_data.add_vertex(Vec3f(min_x, max_y, plane_center.z())); + glsafe(::glEnable(GL_CULL_FACE)); + glsafe(::glDisable(GL_BLEND)); - // indices - init_data.add_triangle(0, 1, 2); - init_data.add_triangle(2, 3, 0); - - m_plane.init_from(std::move(init_data)); - } - - const Camera& camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("view_model_matrix", camera.get_view_matrix()); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - - m_plane.render(); -#else - // Draw the cutting plane - ::glBegin(GL_QUADS); - ::glColor4f(0.8f, 0.8f, 0.8f, 0.5f); - ::glVertex3f(min_x, min_y, plane_center.z()); - ::glVertex3f(max_x, min_y, plane_center.z()); - ::glVertex3f(max_x, max_y, plane_center.z()); - ::glVertex3f(min_x, max_y, plane_center.z()); - glsafe(::glEnd()); -#endif // ENABLE_LEGACY_OPENGL_REMOVAL - -#if ENABLE_GL_CORE_PROFILE - shader->stop_using(); - } - - shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat"); - if (shader != nullptr) { - shader->start_using(); - - const Camera& camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("view_model_matrix", camera.get_view_matrix()); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - const std::array& viewport = camera.get_viewport(); - shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); - shader->set_uniform("width", 0.5f); - shader->set_uniform("gap_size", 0.0f); -#endif // ENABLE_GL_CORE_PROFILE - - glsafe(::glEnable(GL_CULL_FACE)); - glsafe(::glDisable(GL_BLEND)); - - // Draw the grabber and the connecting line - m_grabbers[0].center = plane_center; - m_grabbers[0].center.z() = plane_center.z() + Offset; - - glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); - -#if ENABLE_GL_CORE_PROFILE - if (!OpenGLManager::get_gl_info().is_core_profile()) -#endif // ENABLE_GL_CORE_PROFILE - glsafe(::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f)); -#if ENABLE_LEGACY_OPENGL_REMOVAL - if (!m_grabber_connection.is_initialized() || is_changed) { - m_grabber_connection.reset(); - - GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; - init_data.color = ColorRGBA::YELLOW(); - init_data.reserve_vertices(2); - init_data.reserve_indices(2); - - // vertices - init_data.add_vertex((Vec3f)plane_center.cast()); - init_data.add_vertex((Vec3f)m_grabbers[0].center.cast()); - - // indices - init_data.add_line(0, 1); - - m_grabber_connection.init_from(std::move(init_data)); - } - - m_grabber_connection.render(); - -#if ENABLE_GL_CORE_PROFILE - shader->set_uniform("view_model_matrix", camera.get_view_matrix()* Geometry::assemble_transform(m_cut_contours.shift)); - m_cut_contours.contours.render(); -#endif // ENABLE_GL_CORE_PROFILE - - shader->stop_using(); - } - - shader = wxGetApp().get_shader("gouraud_light"); -#else - glsafe(::glColor3f(1.0, 1.0, 0.0)); - ::glBegin(GL_LINES); - ::glVertex3dv(plane_center.data()); - ::glVertex3dv(m_grabbers[0].center.data()); - glsafe(::glEnd()); - - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); -#endif // ENABLE_LEGACY_OPENGL_REMOVAL - if (shader != nullptr) { - shader->start_using(); - shader->set_uniform("emission_factor", 0.1f); - - m_grabbers[0].color = GRABBER_COLOR; - m_grabbers[0].render(m_hover_id == 0, float((box.size().x() + box.size().y() + box.size().z()) / 3.0)); - - shader->stop_using(); - } - -#if !ENABLE_GL_CORE_PROFILE -#if ENABLE_LEGACY_OPENGL_REMOVAL - shader = wxGetApp().get_shader("flat"); - if (shader != nullptr) { - shader->start_using(); - - const Camera& camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("view_model_matrix", camera.get_view_matrix()* Geometry::assemble_transform(m_cut_contours.shift)); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); -#else - glsafe(::glPushMatrix()); - glsafe(::glTranslated(m_cut_contours.shift.x(), m_cut_contours.shift.y(), m_cut_contours.shift.z())); -#endif // ENABLE_LEGACY_OPENGL_REMOVAL - glsafe(::glLineWidth(2.0f)); - m_cut_contours.contours.render(); -#if ENABLE_LEGACY_OPENGL_REMOVAL - shader->stop_using(); - } -#else - glsafe(::glPopMatrix()); -#endif // ENABLE_LEGACY_OPENGL_REMOVAL -#endif // !ENABLE_GL_CORE_PROFILE + shader->stop_using(); } -#if ENABLE_RAYCAST_PICKING -void GLGizmoCut::on_register_raycasters_for_picking() +static float get_grabber_mean_size(const BoundingBoxf3& bb) { + return float((bb.size().x() + bb.size().y() + bb.size().z()) / 3.0); +} + +void GLGizmoCut3D::render_model(GLModel& model, const ColorRGBA& color, Transform3d view_model_matrix) +{ + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + if (shader) { + shader->start_using(); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", wxGetApp().plater()->get_camera().get_projection_matrix()); + + model.set_color(color); + model.render(); + + shader->stop_using(); + } +} + +void GLGizmoCut3D::render_line(GLModel& line_model, const ColorRGBA& color, Transform3d view_model_matrix, float width) +{ + GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat"); + if (shader) { + shader->start_using(); + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", wxGetApp().plater()->get_camera().get_projection_matrix()); + shader->set_uniform("width", width); + + line_model.set_color(color); + line_model.render(); + + shader->stop_using(); + } +} + +void GLGizmoCut3D::render_rotation_snapping(Axis axis, const ColorRGBA& color) +{ + GLShaderProgram* line_shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat"); + if (!line_shader) + return; + + const Camera& camera = wxGetApp().plater()->get_camera(); + Transform3d view_model_matrix = camera.get_view_matrix() * translation_transform(m_plane_center) * m_start_dragging_m; + + if (axis == X) + view_model_matrix = view_model_matrix * rotation_transform(0.5 * PI * Vec3d::UnitY()) * rotation_transform(-PI * Vec3d::UnitZ()); + else + view_model_matrix = view_model_matrix * rotation_transform(-0.5 * PI * Vec3d::UnitZ()) * rotation_transform(-0.5 * PI * Vec3d::UnitY()); + + line_shader->start_using(); + line_shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + line_shader->set_uniform("view_model_matrix", view_model_matrix); + line_shader->set_uniform("width", 0.25f); + + m_circle.render(); + m_scale.render(); + m_snap_radii.render(); + m_reference_radius.render(); + if (m_dragging) { + line_shader->set_uniform("width", 1.5f); + m_angle_arc.set_color(color); + m_angle_arc.render(); + } + + line_shader->stop_using(); +} + +void GLGizmoCut3D::render_grabber_connection(const ColorRGBA& color, Transform3d view_matrix) +{ + const Transform3d line_view_matrix = view_matrix * scale_transform(Vec3d(1.0, 1.0, m_grabber_connection_len)); + + render_line(m_grabber_connection, color, line_view_matrix, 0.2f); +}; + +void GLGizmoCut3D::render_cut_plane_grabbers() +{ + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + + ColorRGBA color = m_hover_id == Z ? complementary(GRABBER_COLOR) : GRABBER_COLOR; + + const Transform3d view_matrix = wxGetApp().plater()->get_camera().get_view_matrix() * translation_transform(m_plane_center) * m_rotation_m; + + const Grabber& grabber = m_grabbers.front(); + const float mean_size = get_grabber_mean_size(bounding_box()); + + double size = m_dragging && m_hover_id == Z ? double(grabber.get_dragging_half_size(mean_size)) : double(grabber.get_half_size(mean_size)); + + Vec3d cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); + Vec3d offset = 1.25 * size * Vec3d::UnitZ(); + + // render Z grabber + + if (!m_dragging && m_hover_id < 0) + render_grabber_connection(color, view_matrix); + render_model(m_sphere.model, color, view_matrix * scale_transform(size)); + + if ((!m_dragging && m_hover_id < 0) || m_hover_id == Z) + { + const BoundingBoxf3 tbb = transformed_bounding_box(m_plane_center); + if (tbb.min.z() <= 0.0) + render_model(m_cone.model, color, view_matrix * assemble_transform(-offset, PI * Vec3d::UnitX(), cone_scale)); + + if (tbb.max.z() >= 0.0) + render_model(m_cone.model, color, view_matrix * assemble_transform(offset, Vec3d::Zero(), cone_scale)); + } + + // render top sphere for X/Y grabbers + + if ((!m_dragging && m_hover_id < 0) || m_hover_id == X || m_hover_id == Y) + { + size = m_dragging ? double(grabber.get_dragging_half_size(mean_size)) : double(grabber.get_half_size(mean_size)); + color = m_hover_id == Y ? complementary(ColorRGBA::GREEN()) : + m_hover_id == X ? complementary(ColorRGBA::RED()) : ColorRGBA::GRAY(); + render_model(m_sphere.model, color, view_matrix * assemble_transform(m_grabber_connection_len * Vec3d::UnitZ(), Vec3d::Zero(), size * Vec3d::Ones())); + } + + // render X grabber + + if ((!m_dragging && m_hover_id < 0) || m_hover_id == X) + { + size = m_dragging && m_hover_id == X ? double(grabber.get_dragging_half_size(mean_size)) : double(grabber.get_half_size(mean_size)); + cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); + color = m_hover_id == X ? complementary(ColorRGBA::RED()) : ColorRGBA::RED(); + + if (m_hover_id == X) { + render_grabber_connection(color, view_matrix); + render_rotation_snapping(X, color); + } + + offset = Vec3d(0.0, 1.25 * size, m_grabber_connection_len); + render_model(m_cone.model, color, view_matrix * assemble_transform(offset, -0.5 * PI * Vec3d::UnitX(), cone_scale)); + offset = Vec3d(0.0, -1.25 * size, m_grabber_connection_len); + render_model(m_cone.model, color, view_matrix * assemble_transform(offset, 0.5 * PI * Vec3d::UnitX(), cone_scale)); + } + + // render Y grabber + + if ((!m_dragging && m_hover_id < 0) || m_hover_id == Y) + { + size = m_dragging && m_hover_id == Y ? double(grabber.get_dragging_half_size(mean_size)) : double(grabber.get_half_size(mean_size)); + cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); + color = m_hover_id == Y ? complementary(ColorRGBA::GREEN()) : ColorRGBA::GREEN(); + + if (m_hover_id == Y) { + render_grabber_connection(color, view_matrix); + render_rotation_snapping(Y, color); + } + + offset = Vec3d(1.25 * size, 0.0, m_grabber_connection_len); + render_model(m_cone.model, color, view_matrix * assemble_transform(offset, 0.5 * PI * Vec3d::UnitY(), cone_scale)); + offset = Vec3d(-1.25 * size, 0.0, m_grabber_connection_len); + render_model(m_cone.model, color, view_matrix * assemble_transform(offset, -0.5 * PI * Vec3d::UnitY(), cone_scale)); + } +} + +void GLGizmoCut3D::render_cut_line() +{ + if (!cut_line_processing() || m_line_end == Vec3d::Zero()) + return; + + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + + m_cut_line.reset(); + m_cut_line.init_from(its_make_line((Vec3f)m_line_beg.cast(), (Vec3f)m_line_end.cast())); + + render_line(m_cut_line, GRABBER_COLOR, wxGetApp().plater()->get_camera().get_view_matrix(), 0.25f); +} + +bool GLGizmoCut3D::on_init() +{ + m_grabbers.emplace_back(); + m_shortcut_key = WXK_CONTROL_C; + + // initiate info shortcuts + const wxString ctrl = GUI::shortkey_ctrl_prefix(); + const wxString alt = GUI::shortkey_alt_prefix(); + const wxString shift = "Shift+"; + + m_shortcuts.push_back(std::make_pair(_L("Left click"), _L("Add connector"))); + m_shortcuts.push_back(std::make_pair(_L("Right click"), _L("Remove connector"))); + m_shortcuts.push_back(std::make_pair(_L("Drag"), _L("Move connector"))); + m_shortcuts.push_back(std::make_pair(shift + _L("Left click"), _L("Add connector to selection"))); + m_shortcuts.push_back(std::make_pair(alt + _L("Left click"), _L("Remove connector from selection"))); + m_shortcuts.push_back(std::make_pair(ctrl + "A", _L("Select all connectors"))); + + return true; +} + +void GLGizmoCut3D::on_load(cereal::BinaryInputArchive& ar) +{ + ar( m_keep_upper, m_keep_lower, m_rotate_lower, m_rotate_upper, m_hide_cut_plane, m_mode, m_connectors_editing,//m_selected, + // m_connector_depth_ratio, m_connector_size, m_connector_mode, m_connector_type, m_connector_style, m_connector_shape_id, + m_ar_plane_center, m_rotation_m); + + set_center_pos(m_ar_plane_center, true); + + force_update_clipper_on_render = true; + + m_parent.request_extra_frame(); +} + +void GLGizmoCut3D::on_save(cereal::BinaryOutputArchive& ar) const +{ + ar( m_keep_upper, m_keep_lower, m_rotate_lower, m_rotate_upper, m_hide_cut_plane, m_mode, m_connectors_editing,//m_selected, + // m_connector_depth_ratio, m_connector_size, m_connector_mode, m_connector_type, m_connector_style, m_connector_shape_id, + m_ar_plane_center, m_start_dragging_m); +} + +std::string GLGizmoCut3D::on_get_name() const +{ + return _u8L("Cut"); +} + +void GLGizmoCut3D::on_set_state() +{ + if (m_state == On) { + update_bb(); + m_connectors_editing = !m_selected.empty(); + + // initiate archived values + m_ar_plane_center = m_plane_center; + m_start_dragging_m = m_rotation_m; + + m_parent.request_extra_frame(); + } + else { + m_c->object_clipper()->release(); + m_selected.clear(); + } + force_update_clipper_on_render = m_state == On; +} + +void GLGizmoCut3D::on_register_raycasters_for_picking() +{ + assert(m_raycasters.empty()); // the gizmo grabbers are rendered on top of the scene, so the raytraced picker should take it into account m_parent.set_raycaster_gizmos_on_top(true); + + init_picking_models(); + + if (m_connectors_editing) { + if (CommonGizmosDataObjects::SelectionInfo* si = m_c->selection_info()) { + const CutConnectors& connectors = si->model_object()->cut_connectors; + for (int i = 0; i < int(connectors.size()); ++i) + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i + m_connectors_group_id, *(m_shapes[connectors[i].attribs]).mesh_raycaster, Transform3d::Identity())); + } + } + else { + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, X, *m_cone.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, X, *m_cone.mesh_raycaster, Transform3d::Identity())); + + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Y, *m_cone.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Y, *m_cone.mesh_raycaster, Transform3d::Identity())); + + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Z, *m_sphere.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Z, *m_cone.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, Z, *m_cone.mesh_raycaster, Transform3d::Identity())); + } + + update_raycasters_for_picking_transform(); } -void GLGizmoCut::on_unregister_raycasters_for_picking() +void GLGizmoCut3D::on_unregister_raycasters_for_picking() { + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo); + m_raycasters.clear(); + // the gizmo grabbers are rendered on top of the scene, so the raytraced picker should take it into account m_parent.set_raycaster_gizmos_on_top(false); } -#else -void GLGizmoCut::on_render_for_picking() + +void GLGizmoCut3D::update_raycasters_for_picking() { - glsafe(::glDisable(GL_DEPTH_TEST)); - render_grabbers_for_picking(m_parent.get_selection().get_bounding_box()); + on_unregister_raycasters_for_picking(); + on_register_raycasters_for_picking(); } -#endif // ENABLE_RAYCAST_PICKING -void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit) +void GLGizmoCut3D::set_volumes_picking_state(bool state) { - static float last_y = 0.0f; - static float last_h = 0.0f; - - m_imgui->begin(_L("Cut"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); - - const bool imperial_units = wxGetApp().app_config->get("use_inches") == "1"; - - // adjust window position to avoid overlap the view toolbar - const float win_h = ImGui::GetWindowHeight(); - y = std::min(y, bottom_limit - win_h); - ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); - if (last_h != win_h || last_y != y) { - // ask canvas for another frame to render the window in the correct position - m_imgui->set_requires_extra_frame(); - if (last_h != win_h) - last_h = win_h; - if (last_y != y) - last_y = y; + std::vector>* raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); + if (raycasters != nullptr) { + const Selection& selection = m_parent.get_selection(); + const Selection::IndicesList ids = selection.get_volume_idxs(); + for (unsigned int id : ids) { + const GLVolume* v = selection.get_volume(id); + auto it = std::find_if(raycasters->begin(), raycasters->end(), [v](std::shared_ptr item) { return item->get_raycaster() == v->mesh_raycaster.get(); }); + if (it != raycasters->end()) + (*it)->set_active(state); + } } - - ImGui::AlignTextToFramePadding(); - m_imgui->text("Z"); - ImGui::SameLine(); - ImGui::PushItemWidth(m_imgui->get_style_scaling() * 150.0f); - - double cut_z = m_cut_z; - if (imperial_units) - cut_z *= ObjectManipulation::mm_to_in; - ImGui::InputDouble("", &cut_z, 0.0f, 0.0f, "%.2f", ImGuiInputTextFlags_CharsDecimal); - - ImGui::SameLine(); - m_imgui->text(imperial_units ? _L("in") : _L("mm")); - - m_cut_z = cut_z * (imperial_units ? ObjectManipulation::in_to_mm : 1.0); - - ImGui::Separator(); - - m_imgui->checkbox(_L("Keep upper part"), m_keep_upper); - m_imgui->checkbox(_L("Keep lower part"), m_keep_lower); - m_imgui->checkbox(_L("Rotate lower part upwards"), m_rotate_lower); - - ImGui::Separator(); - - m_imgui->disabled_begin((!m_keep_upper && !m_keep_lower) || m_cut_z <= 0.0 || m_max_z <= m_cut_z); - const bool cut_clicked = m_imgui->button(_L("Perform cut")); - m_imgui->disabled_end(); - - m_imgui->end(); - - if (cut_clicked && (m_keep_upper || m_keep_lower)) - perform_cut(m_parent.get_selection()); } -void GLGizmoCut::set_cut_z(double cut_z) +void GLGizmoCut3D::update_raycasters_for_picking_transform() { - // Clamp the plane to the object's bounding box - m_cut_z = std::clamp(cut_z, 0.0, m_max_z); -} + if (m_connectors_editing) { + CommonGizmosDataObjects::SelectionInfo* si = m_c->selection_info(); + if (!si) + return; + const ModelObject* mo = si->model_object(); + const CutConnectors& connectors = mo->cut_connectors; + if (connectors.empty()) + return; + auto inst_id = m_c->selection_info()->get_active_instance(); + if (inst_id < 0) + return; -void GLGizmoCut::perform_cut(const Selection& selection) -{ - const int instance_idx = selection.get_instance_idx(); - const int object_idx = selection.get_object_idx(); + const Vec3d& instance_offset = mo->instances[inst_id]->get_offset(); + const double sla_shift = double(m_c->selection_info()->get_sla_shift()); - wxCHECK_RET(instance_idx >= 0 && object_idx >= 0, "GLGizmoCut: Invalid object selection"); + const ClippingPlane* cp = m_c->object_clipper()->get_clipping_plane(); + const Vec3d& normal = cp && cp->is_active() ? cp->get_normal() : m_clp_normal; - // m_cut_z is the distance from the bed. Subtract possible SLA elevation. - const GLVolume* first_glvolume = selection.get_first_volume(); - const double object_cut_z = m_cut_z - first_glvolume->get_sla_shift_z(); + for (size_t i = 0; i < connectors.size(); ++i) { + const CutConnector& connector = connectors[i]; - if (0.0 < object_cut_z && object_cut_z < m_max_z) - wxGetApp().plater()->cut(object_idx, instance_idx, object_cut_z, - only_if(m_keep_upper, ModelObjectCutAttribute::KeepUpper) | - only_if(m_keep_lower, ModelObjectCutAttribute::KeepLower) | - only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower)); + float height = connector.height; + // recalculate connector position to world position + Vec3d pos = connector.pos + instance_offset; + if (connector.attribs.type == CutConnectorType::Dowel && + connector.attribs.style == CutConnectorStyle::Prizm) { + pos -= height * normal; + height *= 2; + } + pos[Z] += sla_shift; + + const Transform3d scale_trafo = scale_transform(Vec3f(connector.radius, connector.radius, height).cast()); + m_raycasters[i]->set_transform(translation_transform(pos) * m_rotation_m * scale_trafo); + } + } else { - // the object is SLA-elevated and the plane is under it. + const Transform3d trafo = translation_transform(m_plane_center) * m_rotation_m; + + const BoundingBoxf3 box = bounding_box(); + const float mean_size = get_grabber_mean_size(box); + + double size = double(m_grabbers.front().get_half_size(mean_size)); + Vec3d scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size); + + Vec3d offset = Vec3d(0.0, 1.25 * size, m_grabber_connection_len); + m_raycasters[0]->set_transform(trafo * assemble_transform(offset, -0.5 * PI * Vec3d::UnitX(), scale)); + offset = Vec3d(0.0, -1.25 * size, m_grabber_connection_len); + m_raycasters[1]->set_transform(trafo * assemble_transform(offset, 0.5 * PI * Vec3d::UnitX(), scale)); + + offset = Vec3d(1.25 * size, 0.0, m_grabber_connection_len); + m_raycasters[2]->set_transform(trafo * assemble_transform(offset, 0.5 * PI * Vec3d::UnitY(), scale)); + offset = Vec3d(-1.25 * size, 0.0, m_grabber_connection_len); + m_raycasters[3]->set_transform(trafo * assemble_transform(offset, -0.5 * PI * Vec3d::UnitY(), scale)); + + offset = 1.25 * size * Vec3d::UnitZ(); + m_raycasters[4]->set_transform(trafo * scale_transform(size)); + m_raycasters[5]->set_transform(trafo * assemble_transform(-offset, PI * Vec3d::UnitX(), scale)); + m_raycasters[6]->set_transform(trafo * assemble_transform(offset, Vec3d::Zero(), scale)); } } -double GLGizmoCut::calc_projection(const Linef3& mouse_ray) const +void GLGizmoCut3D::on_set_hover_id() { - double projection = 0.0; +} - const Vec3d starting_vec = m_drag_pos - m_drag_center; - const double len_starting_vec = starting_vec.norm(); - if (len_starting_vec != 0.0) { - const Vec3d mouse_dir = mouse_ray.unit_vector(); +bool GLGizmoCut3D::on_is_activable() const +{ + const Selection& selection = m_parent.get_selection(); + const int object_idx = selection.get_object_idx(); + if (object_idx < 0) + return false; + + bool is_dowel_object = false; + if (const ModelObject* mo = wxGetApp().plater()->model().objects[object_idx]; mo->is_cut()) { + int solid_connector_cnt = 0; + int connectors_cnt = 0; + for (const ModelVolume* volume : mo->volumes) { + if (volume->is_cut_connector()) { + connectors_cnt++; + if (volume->is_model_part()) + solid_connector_cnt++; + } + if (connectors_cnt > 1) + break; + } + is_dowel_object = connectors_cnt == 1 && solid_connector_cnt == 1; + } + + // This is assumed in GLCanvas3D::do_rotate, do not change this + // without updating that function too. + return selection.is_single_full_instance() && !is_dowel_object && !m_parent.is_layers_editing_enabled(); +} + +bool GLGizmoCut3D::on_is_selectable() const +{ + return wxGetApp().get_mode() != comSimple; +} + +Vec3d GLGizmoCut3D::mouse_position_in_local_plane(Axis axis, const Linef3& mouse_ray) const +{ + double half_pi = 0.5 * PI; + + Transform3d m = Transform3d::Identity(); + + switch (axis) + { + case X: + { + m.rotate(Eigen::AngleAxisd(half_pi, Vec3d::UnitZ())); + m.rotate(Eigen::AngleAxisd(-half_pi, Vec3d::UnitY())); + break; + } + case Y: + { + m.rotate(Eigen::AngleAxisd(half_pi, Vec3d::UnitY())); + m.rotate(Eigen::AngleAxisd(half_pi, Vec3d::UnitZ())); + break; + } + default: + case Z: + { + // no rotation applied + break; + } + } + + m = m * m_start_dragging_m.inverse(); + m.translate(-m_plane_center); + + return transform(mouse_ray, m).intersect_plane(0.0); +} + +void GLGizmoCut3D::dragging_grabber_z(const GLGizmoBase::UpdateData &data) +{ + Vec3d starting_box_center = m_plane_center - Vec3d::UnitZ(); // some Margin + rotate_vec3d_around_plane_center(starting_box_center); + + const Vec3d&starting_drag_position = m_plane_center; + double projection = 0.0; + + Vec3d starting_vec = starting_drag_position - starting_box_center; + if (starting_vec.norm() != 0.0) { + Vec3d mouse_dir = data.mouse_ray.unit_vector(); // finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position // use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form // in our case plane normal and ray direction are the same (orthogonal view) // when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal - const Vec3d inters = mouse_ray.a + (m_drag_pos - mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir; + Vec3d inters = data.mouse_ray.a + (starting_drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir; // vector from the starting position to the found intersection - const Vec3d inters_vec = inters - m_drag_pos; + Vec3d inters_vec = inters - starting_drag_position; + starting_vec.normalize(); // finds projection of the vector along the staring direction - projection = inters_vec.dot(starting_vec.normalized()); + projection = inters_vec.dot(starting_vec); } - return projection; + if (wxGetKeyState(WXK_SHIFT)) + projection = m_snap_step * (double)std::round(projection / m_snap_step); + + const Vec3d shift = starting_vec * projection; + + // move cut plane center + set_center(m_plane_center + shift); } -BoundingBoxf3 GLGizmoCut::bounding_box() const +void GLGizmoCut3D::dragging_grabber_xy(const GLGizmoBase::UpdateData &data) +{ + const Vec2d mouse_pos = to_2d(mouse_position_in_local_plane((Axis)m_hover_id, data.mouse_ray)); + + const Vec2d orig_dir = Vec2d::UnitX(); + const Vec2d new_dir = mouse_pos.normalized(); + + const double two_pi = 2.0 * PI; + + double theta = ::acos(std::clamp(new_dir.dot(orig_dir), -1.0, 1.0)); + if (cross2(orig_dir, new_dir) < 0.0) + theta = two_pi - theta; + + const double len = mouse_pos.norm(); + // snap to coarse snap region + if (m_snap_coarse_in_radius <= len && len <= m_snap_coarse_out_radius) { + const double step = two_pi / double(SnapRegionsCount); + theta = step * std::round(theta / step); + } + // snap to fine snap region (scale) + else if (m_snap_fine_in_radius <= len && len <= m_snap_fine_out_radius) { + const double step = two_pi / double(ScaleStepsCount); + theta = step * std::round(theta / step); + } + + if (is_approx(theta, two_pi)) + theta = 0.0; + if (m_hover_id == X) + theta += 0.5 * PI; + + Vec3d rotation = Vec3d::Zero(); + rotation[m_hover_id] = theta; + m_rotation_m = m_start_dragging_m * rotation_transform(rotation); + + m_angle = theta; + while (m_angle > two_pi) + m_angle -= two_pi; + if (m_angle < 0.0) + m_angle += two_pi; + + update_clipper(); +} + +void GLGizmoCut3D::dragging_connector(const GLGizmoBase::UpdateData &data) +{ + CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors; + std::pair pos_and_normal; + Vec3d pos_world; + + if (unproject_on_cut_plane(data.mouse_pos.cast(), pos_and_normal, pos_world)) { + connectors[m_hover_id - m_connectors_group_id].pos = pos_and_normal.first; + update_raycasters_for_picking_transform(); + } +} + +void GLGizmoCut3D::on_dragging(const UpdateData& data) +{ + if (m_hover_id < 0) + return; + if (m_hover_id == Z) + dragging_grabber_z(data); + else if (m_hover_id == X || m_hover_id == Y) + dragging_grabber_xy(data); + else if (m_hover_id >= m_connectors_group_id && m_connector_mode == CutConnectorMode::Manual) + dragging_connector(data); +} + +void GLGizmoCut3D::on_start_dragging() +{ + m_angle = 0.0; + if (m_hover_id >= m_connectors_group_id && m_connector_mode == CutConnectorMode::Manual) + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Move connector"), UndoRedo::SnapshotType::GizmoAction); + + if (m_hover_id == X || m_hover_id == Y) + m_start_dragging_m = m_rotation_m; +} + +void GLGizmoCut3D::on_stop_dragging() +{ + if (m_hover_id == X || m_hover_id == Y) { + m_angle_arc.reset(); + m_angle = 0.0; + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Rotate cut plane"), UndoRedo::SnapshotType::GizmoAction); + m_start_dragging_m = m_rotation_m; + } + else if (m_hover_id == Z) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Move cut plane"), UndoRedo::SnapshotType::GizmoAction); + m_ar_plane_center = m_plane_center; + } +} + +void GLGizmoCut3D::set_center_pos(const Vec3d& center_pos, bool force/* = false*/) +{ + bool can_set_center_pos = force; + if (!can_set_center_pos) { + const BoundingBoxf3 tbb = transformed_bounding_box(center_pos); + if (tbb.max.z() > -1. && tbb.min.z() < 1.) + can_set_center_pos = true; + else { + const double old_dist = (m_bb_center - m_plane_center).norm(); + const double new_dist = (m_bb_center - center_pos).norm(); + // check if forcing is reasonable + if (new_dist < old_dist) + can_set_center_pos = true; + } + } + + if (can_set_center_pos) { + m_plane_center = center_pos; + m_center_offset = m_plane_center - m_bb_center; + } +} + +BoundingBoxf3 GLGizmoCut3D::bounding_box() const { BoundingBoxf3 ret; const Selection& selection = m_parent.get_selection(); const Selection::IndicesList& idxs = selection.get_volume_idxs(); - return selection.get_bounding_box(); - for (unsigned int i : idxs) { const GLVolume* volume = selection.get_volume(i); - if (!volume->is_modifier) + // respect just to the solid parts for FFF and ignore pad and supports for SLA + if (!volume->is_modifier && !volume->is_sla_pad() && !volume->is_sla_support()) ret.merge(volume->transformed_convex_hull_bounding_box()); } return ret; } -void GLGizmoCut::update_contours() +BoundingBoxf3 GLGizmoCut3D::transformed_bounding_box(const Vec3d& plane_center, bool revert_move /*= false*/) const { - const Selection& selection = m_parent.get_selection(); - const GLVolume* first_glvolume = selection.get_first_volume(); - const BoundingBoxf3& box = first_glvolume->transformed_convex_hull_bounding_box(); + // #ysFIXME !!! + BoundingBoxf3 ret; - const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()]; - const int instance_idx = selection.get_instance_idx(); - std::vector volumes_idxs = std::vector(model_object->volumes.size()); - std::vector volumes_trafos = std::vector(model_object->volumes.size()); - for (size_t i = 0; i < model_object->volumes.size(); ++i) { - volumes_idxs[i] = model_object->volumes[i]->id(); - volumes_trafos[i] = model_object->volumes[i]->get_matrix(); + const CommonGizmosDataObjects::SelectionInfo* sel_info = m_c->selection_info(); + if (!sel_info) + return ret; + const ModelObject* mo = sel_info->model_object(); + if (!mo) + return ret; + const int instance_idx = sel_info->get_active_instance(); + if (instance_idx < 0 || mo->instances.empty()) + return ret; + const ModelInstance* mi = mo->instances[instance_idx]; + + const Vec3d& instance_offset = mi->get_offset(); + Vec3d cut_center_offset = plane_center - instance_offset; + cut_center_offset[Z] -= sel_info->get_sla_shift(); + + const auto move = assemble_transform(-cut_center_offset); + const auto move2 = assemble_transform(plane_center); + + const auto cut_matrix = (revert_move ? move2 : Transform3d::Identity()) * m_rotation_m.inverse() * move; + + const Selection& selection = m_parent.get_selection(); + const Selection::IndicesList& idxs = selection.get_volume_idxs(); + for (unsigned int i : idxs) { + const GLVolume* volume = selection.get_volume(i); + // respect just to the solid parts for FFF and ignore pad and supports for SLA + if (!volume->is_modifier && !volume->is_sla_pad() && !volume->is_sla_support()) { + + const auto instance_matrix = assemble_transform( + Vec3d::Zero(), // don't apply offset + volume->get_instance_rotation().cwiseProduct(Vec3d(1.0, 1.0, 1.0)), + volume->get_instance_scaling_factor(), + volume->get_instance_mirror() + ); + + auto volume_trafo = instance_matrix * volume->get_volume_transformation().get_matrix(); + + ret.merge(volume->transformed_convex_hull_bounding_box(cut_matrix * volume_trafo)); + } + } + return ret; +} + +bool GLGizmoCut3D::update_bb() +{ + const BoundingBoxf3 box = bounding_box(); + if (m_max_pos != box.max || m_min_pos != box.min) { + + invalidate_cut_plane(); + + m_max_pos = box.max; + m_min_pos = box.min; + m_bb_center = box.center(); + if (box.contains(m_center_offset)) + set_center_pos(m_bb_center + m_center_offset, true); + else + set_center_pos(m_bb_center, true); + + m_radius = box.radius(); + m_grabber_connection_len = 0.75 * m_radius;// std::min(0.75 * m_radius, 35.0); + m_grabber_radius = m_grabber_connection_len * 0.85; + + m_snap_coarse_in_radius = m_grabber_radius / 3.0; + m_snap_coarse_out_radius = m_snap_coarse_in_radius * 2.; + m_snap_fine_in_radius = m_grabber_connection_len * 0.85; + m_snap_fine_out_radius = m_grabber_connection_len * 1.15; + + m_plane.reset(); + m_cone.reset(); + m_sphere.reset(); + m_grabber_connection.reset(); + m_circle.reset(); + m_scale.reset(); + m_snap_radii.reset(); + m_reference_radius.reset(); + + on_unregister_raycasters_for_picking(); + + clear_selection(); + if (CommonGizmosDataObjects::SelectionInfo* selection = m_c->selection_info()) + m_selected.resize(selection->model_object()->cut_connectors.size(), false); + + return true; + } + return false; +} + +void GLGizmoCut3D::init_picking_models() +{ + if (!m_cone.model.is_initialized()) { + indexed_triangle_set its = its_make_cone(1.0, 1.0, PI / 12.0); + m_cone.model.init_from(its); + m_cone.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); + } + if (!m_sphere.model.is_initialized()) { + indexed_triangle_set its = its_make_sphere(1.0, PI / 12.0); + m_sphere.model.init_from(its); + m_sphere.mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); + } + if (m_shapes.empty()) + init_connector_shapes(); +} + +void GLGizmoCut3D::init_rendering_items() +{ + if (!m_grabber_connection.is_initialized()) + m_grabber_connection.init_from(its_make_line(Vec3f::Zero(), Vec3f::UnitZ())); + if (!m_circle.is_initialized()) + init_from_circle(m_circle, m_grabber_radius); + if (!m_scale.is_initialized()) + init_from_scale(m_scale, m_grabber_radius); + if (!m_snap_radii.is_initialized()) + init_from_snap_radii(m_snap_radii, m_grabber_radius); + if (!m_reference_radius.is_initialized()) { + m_reference_radius.init_from(its_make_line(Vec3f::Zero(), m_grabber_connection_len * Vec3f::UnitX())); + m_reference_radius.set_color(ColorRGBA::WHITE()); + } + if (!m_angle_arc.is_initialized() || m_angle != 0.0) + init_from_angle_arc(m_angle_arc, m_angle, m_grabber_connection_len); + + if (!m_plane.is_initialized() && !m_hide_cut_plane && !m_connectors_editing) { + if (m_cut_plane_as_circle) + m_plane.init_from(its_make_frustum_dowel(2. * m_radius, 0.3, 180)); + else + m_plane.init_from(its_make_square_plane(float(m_radius))); + } +} + +void GLGizmoCut3D::render_clipper_cut() +{ + if (! m_connectors_editing) + ::glDisable(GL_DEPTH_TEST); + m_c->object_clipper()->render_cut(); + if (! m_connectors_editing) + ::glEnable(GL_DEPTH_TEST); +} + +void GLGizmoCut3D::on_render() +{ + if (update_bb() || force_update_clipper_on_render) { + update_clipper_on_render(); + m_c->object_clipper()->set_behavior(m_connectors_editing, m_connectors_editing, 0.4); } - bool trafos_match = std::equal(volumes_trafos.begin(), volumes_trafos.end(), - m_cut_contours.volumes_trafos.begin(), m_cut_contours.volumes_trafos.end(), - [](const Transform3d& a, const Transform3d& b) { return a.isApprox(b); }); + init_picking_models(); - if (0.0 < m_cut_z && m_cut_z < m_max_z) { - if (m_cut_contours.cut_z != m_cut_z || m_cut_contours.object_id != model_object->id() || - m_cut_contours.instance_idx != instance_idx || m_cut_contours.volumes_idxs != volumes_idxs || - !trafos_match) { - m_cut_contours.cut_z = m_cut_z; + init_rendering_items(); - if (m_cut_contours.object_id != model_object->id() || m_cut_contours.volumes_idxs != volumes_idxs || !trafos_match) - m_cut_contours.mesh = model_object->raw_mesh(); + render_connectors(); - m_cut_contours.position = box.center(); - m_cut_contours.shift = Vec3d::Zero(); - m_cut_contours.object_id = model_object->id(); - m_cut_contours.instance_idx = instance_idx; - m_cut_contours.volumes_idxs = volumes_idxs; - m_cut_contours.volumes_trafos = volumes_trafos; - m_cut_contours.contours.reset(); + render_clipper_cut(); - MeshSlicingParams slicing_params; - slicing_params.trafo = first_glvolume->get_instance_transformation().get_matrix(); - slicing_params.trafo.pretranslate(Vec3d(0., 0., first_glvolume->get_sla_shift_z())); + if (!m_hide_cut_plane && !m_connectors_editing) { + render_cut_plane(); + render_cut_plane_grabbers(); + } - const Polygons polys = slice_mesh(m_cut_contours.mesh.its, m_cut_z, slicing_params); - if (!polys.empty()) { - m_cut_contours.contours.init_from(polys, static_cast(m_cut_z)); -#if ENABLE_LEGACY_OPENGL_REMOVAL - m_cut_contours.contours.set_color(ColorRGBA::WHITE()); -#else - m_cut_contours.contours.set_color(-1, { 1.0f, 1.0f, 1.0f, 1.0f }); -#endif // ENABLE_LEGACY_OPENGL_REMOVAL + render_cut_line(); + + m_selection_rectangle.render(m_parent); +} + +void GLGizmoCut3D::render_debug_input_window() +{ + m_imgui->begin(wxString("DEBUG")); + + static bool hide_clipped = false; + static bool fill_cut = false; + static float contour_width = 0.4f; + + m_imgui->checkbox(_L("Hide cut plane and grabbers"), m_hide_cut_plane); + if (m_imgui->checkbox("hide_clipped", hide_clipped) && !hide_clipped) + m_clp_normal = m_c->object_clipper()->get_clipping_plane()->get_normal(); + m_imgui->checkbox("fill_cut", fill_cut); + m_imgui->slider_float("contour_width", &contour_width, 0.f, 3.f); + if (auto oc = m_c->object_clipper()) + oc->set_behavior(hide_clipped || m_connectors_editing, fill_cut || m_connectors_editing, double(contour_width)); + + ImGui::Separator(); + + if (m_imgui->checkbox(_L("Render cut plane as circle"), m_cut_plane_as_circle)) + m_plane.reset(); + + m_imgui->end(); +} + +void GLGizmoCut3D::adjust_window_position(float x, float y, float bottom_limit) +{ + static float last_y = 0.0f; + static float last_h = 0.0f; + + const float win_h = ImGui::GetWindowHeight(); + y = std::min(y, bottom_limit - win_h); + + ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); + + if (!is_approx(last_h, win_h) || !is_approx(last_y, y)) { + // ask canvas for another frame to render the window in the correct position + m_imgui->set_requires_extra_frame(); + if (!is_approx(last_h, win_h)) + last_h = win_h; + if (!is_approx(last_y, y)) + last_y = y; + } +} + +void GLGizmoCut3D::unselect_all_connectors() +{ + std::fill(m_selected.begin(), m_selected.end(), false); + m_selected_count = 0; + validate_connector_settings(); +} + +void GLGizmoCut3D::select_all_connectors() +{ + std::fill(m_selected.begin(), m_selected.end(), true); + m_selected_count = int(m_selected.size()); +} + +void GLGizmoCut3D::render_shortcuts() +{ + if (m_imgui->button("? " + (m_show_shortcuts ? wxString(ImGui::CollapseBtn) : wxString(ImGui::ExpandBtn)))) + m_show_shortcuts = !m_show_shortcuts; + + if (m_show_shortcuts) + for (const auto&shortcut : m_shortcuts ){ + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, shortcut.first); + ImGui::SameLine(m_label_width); + m_imgui->text(shortcut.second); + } +} + +void GLGizmoCut3D::apply_selected_connectors(std::function apply_fn) +{ + for (size_t idx = 0; idx < m_selected.size(); idx++) + if (m_selected[idx]) + apply_fn(idx); + + update_raycasters_for_picking_transform(); +} + +void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors) +{ + // add shortcuts panel + render_shortcuts(); + + // Connectors section + + ImGui::Separator(); + + // WIP : Auto : Need to implement + // m_imgui->text(_L("Mode")); + // render_connect_mode_radio_button(CutConnectorMode::Auto); + // render_connect_mode_radio_button(CutConnectorMode::Manual); + + ImGui::AlignTextToFramePadding(); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Connectors")); + + m_imgui->disabled_begin(connectors.empty()); + ImGui::SameLine(m_label_width); + if (render_reset_button("connectors", _u8L("Remove connectors"))) + reset_connectors(); + m_imgui->disabled_end(); + + m_imgui->text(_L("Type")); + bool type_changed = render_connect_type_radio_button(CutConnectorType::Plug); + type_changed |= render_connect_type_radio_button(CutConnectorType::Dowel); + if (type_changed) + apply_selected_connectors([this, &connectors] (size_t idx) { connectors[idx].attribs.type = CutConnectorType(m_connector_type); }); + + m_imgui->disabled_begin(m_connector_type == CutConnectorType::Dowel); + if (type_changed && m_connector_type == CutConnectorType::Dowel) { + m_connector_style = size_t(CutConnectorStyle::Prizm); + apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.style = CutConnectorStyle(m_connector_style); }); + } + if (render_combo(_u8L("Style"), m_connector_styles, m_connector_style)) + apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.style = CutConnectorStyle(m_connector_style); }); + m_imgui->disabled_end(); + + if (render_combo(_u8L("Shape"), m_connector_shapes, m_connector_shape_id)) + apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.shape = CutConnectorShape(m_connector_shape_id); }); + + if (render_slider_double_input(_u8L("Depth ratio"), m_connector_depth_ratio, m_connector_depth_ratio_tolerance)) + apply_selected_connectors([this, &connectors](size_t idx) { + if (m_connector_depth_ratio > 0) + connectors[idx].height = m_connector_depth_ratio; + if (m_connector_depth_ratio_tolerance >= 0) + connectors[idx].height_tolerance = m_connector_depth_ratio_tolerance; + }); + + if (render_slider_double_input(_u8L("Size"), m_connector_size, m_connector_size_tolerance)) + apply_selected_connectors([this, &connectors](size_t idx) { + if (m_connector_size > 0) + connectors[idx].radius = 0.5f * m_connector_size; + if (m_connector_size_tolerance >= 0) + connectors[idx].radius_tolerance = m_connector_size_tolerance; + }); + + ImGui::Separator(); + + if (m_imgui->button(_L("Confirm connectors"))) { + m_clp_normal = m_c->object_clipper()->get_clipping_plane()->get_normal(); + unselect_all_connectors(); + set_connectors_editing(false); + } +} + +void GLGizmoCut3D::render_build_size() +{ + double koef = m_imperial_units ? ObjectManipulation::mm_to_in : 1.0; + wxString unit_str = " " + (m_imperial_units ? _L("in") : _L("mm")); + const BoundingBoxf3 tbb = transformed_bounding_box(m_plane_center); + + Vec3d tbb_sz = tbb.size(); + wxString size = "X: " + double_to_string(tbb_sz.x() * koef, 2) + unit_str + + ", Y: " + double_to_string(tbb_sz.y() * koef, 2) + unit_str + + ", Z: " + double_to_string(tbb_sz.z() * koef, 2) + unit_str; + + ImGui::AlignTextToFramePadding(); + m_imgui->text(_L("Build size")); + ImGui::SameLine(m_label_width); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, size); +} + +void GLGizmoCut3D::reset_cut_plane() +{ + set_center(bounding_box().center()); + m_rotation_m = Transform3d::Identity(); + m_angle_arc.reset(); + update_clipper(); +} + +void GLGizmoCut3D::invalidate_cut_plane() +{ + m_rotation_m = Transform3d::Identity(); + m_plane_center = Vec3d::Zero(); + m_min_pos = Vec3d::Zero(); + m_max_pos = Vec3d::Zero(); + m_bb_center = Vec3d::Zero(); + m_center_offset = Vec3d::Zero(); +} + +void GLGizmoCut3D::set_connectors_editing(bool connectors_editing) +{ + m_connectors_editing = connectors_editing; + update_raycasters_for_picking(); + + m_parent.request_extra_frame(); +} + +void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) +{ + // WIP : cut plane mode + // render_combo(_u8L("Mode"), m_modes, m_mode); + + if (m_mode == size_t(CutMode::cutPlanar)) { + ImGui::AlignTextToFramePadding(); + m_imgui->text(wxString(ImGui::InfoMarkerSmall)); + ImGui::SameLine(); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Hold SHIFT key and connect some two points of an object to cut by line")); + + ImGui::Separator(); + + render_build_size(); + + ImGui::AlignTextToFramePadding(); + m_imgui->text(_L("Cut position: ")); + ImGui::SameLine(m_label_width); + render_move_center_input(Z); + ImGui::SameLine(); + + const bool is_cut_plane_init = m_rotation_m.isApprox(Transform3d::Identity()) && bounding_box().center() == m_plane_center; + m_imgui->disabled_begin(is_cut_plane_init); + if (render_reset_button("cut_plane", _u8L("Reset cutting plane"))) + reset_cut_plane(); + m_imgui->disabled_end(); + + if (wxGetApp().plater()->printer_technology() == ptFFF) { + m_imgui->disabled_begin(!m_keep_upper || !m_keep_lower); + if (m_imgui->button(_L("Add/Edit connectors"))) + set_connectors_editing(true); + m_imgui->disabled_end(); + } + + ImGui::Separator(); + + auto render_part_action_line = [this, connectors](const wxString& label, const wxString& suffix, bool& keep_part, bool& place_on_cut_part, bool& rotate_part) { + bool keep = true; + ImGui::AlignTextToFramePadding(); + m_imgui->text(label); + + ImGui::SameLine(m_label_width); + + m_imgui->disabled_begin(!connectors.empty()); + m_imgui->checkbox(_L("Keep") + suffix, connectors.empty() ? keep_part : keep); + m_imgui->disabled_end(); + + ImGui::SameLine(2 * m_label_width); + + m_imgui->disabled_begin(!keep_part); + if (m_imgui->checkbox(_L("Place on cut") + suffix, place_on_cut_part)) + rotate_part = false; + ImGui::SameLine(); + if (m_imgui->checkbox(_L("Flip") + suffix, rotate_part)) + place_on_cut_part = false; + m_imgui->disabled_end(); + }; + + m_imgui->text(_L("After cut") + ": "); + render_part_action_line( _L("Upper part"), "##upper", m_keep_upper, m_place_on_cut_upper, m_rotate_upper); + render_part_action_line( _L("Lower part"), "##lower", m_keep_lower, m_place_on_cut_lower, m_rotate_lower); + } + + ImGui::Separator(); + + m_imgui->disabled_begin(!can_perform_cut()); + if(m_imgui->button(_L("Perform cut"))) + perform_cut(m_parent.get_selection()); + m_imgui->disabled_end(); +} + +void GLGizmoCut3D::validate_connector_settings() +{ + if (m_connector_depth_ratio < 0.f) + m_connector_depth_ratio = 3.f; + if (m_connector_depth_ratio_tolerance < 0.f) + m_connector_depth_ratio_tolerance = 0.1f; + if (m_connector_size < 0.f) + m_connector_size = 2.5f; + if (m_connector_size_tolerance < 0.f) + m_connector_size_tolerance = 0.f; + + if (m_connector_type == CutConnectorType::Undef) + m_connector_type = CutConnectorType::Plug; + if (m_connector_style == size_t(CutConnectorStyle::Undef)) + m_connector_style = size_t(CutConnectorStyle::Prizm); + if (m_connector_shape_id == size_t(CutConnectorShape::Undef)) + m_connector_shape_id = size_t(CutConnectorShape::Circle); +} + +void GLGizmoCut3D::init_input_window_data(CutConnectors &connectors) +{ + m_imperial_units = wxGetApp().app_config->get("use_inches") == "1"; + m_label_width = m_imgui->get_font_size() * 6.f; + m_control_width = m_imgui->get_font_size() * 9.f; + + if (m_connectors_editing && m_selected_count > 0) { + float depth_ratio { UndefFloat }; + float depth_ratio_tolerance { UndefFloat }; + float radius { UndefFloat }; + float radius_tolerance { UndefFloat }; + CutConnectorType type { CutConnectorType::Undef }; + CutConnectorStyle style { CutConnectorStyle::Undef }; + CutConnectorShape shape { CutConnectorShape::Undef }; + + bool is_init = false; + for (size_t idx = 0; idx < m_selected.size(); idx++) + if (m_selected[idx]) { + const CutConnector& connector = connectors[idx]; + if (!is_init) { + depth_ratio = connector.height; + depth_ratio_tolerance = connector.height_tolerance; + radius = connector.radius; + radius_tolerance = connector.radius_tolerance; + type = connector.attribs.type; + style = connector.attribs.style; + shape = connector.attribs.shape; + + if (m_selected_count == 1) + break; + is_init = true; + } + else { + if (!is_approx(depth_ratio, connector.height)) + depth_ratio = UndefFloat; + if (!is_approx(depth_ratio_tolerance, connector.height_tolerance)) + depth_ratio_tolerance = UndefFloat; + if (!is_approx(radius,connector.radius)) + radius = UndefFloat; + if (!is_approx(radius_tolerance, connector.radius_tolerance)) + radius_tolerance = UndefFloat; + + if (type != connector.attribs.type) + type = CutConnectorType::Undef; + if (style != connector.attribs.style) + style = CutConnectorStyle::Undef; + if (shape != connector.attribs.shape) + shape = CutConnectorShape::Undef; + } + } + + m_connector_depth_ratio = depth_ratio; + m_connector_depth_ratio_tolerance = depth_ratio_tolerance; + m_connector_size = 2.f * radius; + m_connector_size_tolerance = radius_tolerance; + m_connector_type = type; + m_connector_style = size_t(style); + m_connector_shape_id = size_t(shape); + } +} + +void GLGizmoCut3D::render_input_window_warning() const +{ + if (wxGetApp().plater()->printer_technology() == ptFFF && m_has_invalid_connector) { + wxString out = wxString(ImGui::WarningMarkerSmall) + _L("Invalid connectors detected") + ":"; + if (m_info_stats.outside_cut_contour > size_t(0)) + out += "\n - " + format_wxstr(_L_PLURAL("%1$d connector is out of cut contour", "%1$d connectors are out of cut contour", m_info_stats.outside_cut_contour), + m_info_stats.outside_cut_contour); + if (m_info_stats.outside_bb > size_t(0)) + out += "\n - " + format_wxstr(_L_PLURAL("%1$d connector is out of object", "%1$d connectors are out of object", m_info_stats.outside_bb), + m_info_stats.outside_bb); + if (m_info_stats.is_overlap) + out += "\n - " + _L("Some connectors are overlapped"); + m_imgui->text(out); + } + if (!m_keep_upper && !m_keep_lower) + m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Invalid state. \nNo one part is selected for keep after cut")); +} + +void GLGizmoCut3D::on_render_input_window(float x, float y, float bottom_limit) +{ + m_imgui->begin(get_name(), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + + // adjust window position to avoid overlap the view toolbar + adjust_window_position(x, y, bottom_limit); + + CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors; + + init_input_window_data(connectors); + + if (m_connectors_editing) // connectors mode + render_connectors_input_window(connectors); + else + render_cut_plane_input_window(connectors); + + render_input_window_warning(); + + m_imgui->end(); + + render_debug_input_window(); +} + +// get volume transformation regarding to the "border". Border is related from the size of connectors +Transform3d GLGizmoCut3D::get_volume_transformation(const ModelVolume* volume) const +{ + bool is_prizm_dowel = m_connector_type == CutConnectorType::Dowel && m_connector_style == size_t(CutConnectorStyle::Prizm); + const Transform3d connector_trafo = assemble_transform( + is_prizm_dowel ? Vec3d(0.0, 0.0, -m_connector_depth_ratio) : Vec3d::Zero(), + Transformation(m_rotation_m).get_rotation(), + Vec3d(0.5*m_connector_size, 0.5*m_connector_size, is_prizm_dowel ? 2 * m_connector_depth_ratio : m_connector_depth_ratio), + Vec3d::Ones()); + const Vec3d connector_bb = m_connector_mesh.transformed_bounding_box(connector_trafo).size(); + + const Vec3d bb = volume->mesh().bounding_box().size(); + + // calculate an unused border - part of the the volume, where we can't put connectors + const Vec3d border_scale(connector_bb.x() / bb.x(), connector_bb.y() / bb.y(), connector_bb.z() / bb.z()); + + const Transform3d vol_matrix = volume->get_matrix(); + const Vec3d vol_trans = vol_matrix.translation(); + // offset of the volume will be changed after scaling, so calculate the needed offset and set it to a volume_trafo + const Vec3d offset(vol_trans.x() * border_scale.x(), vol_trans.y() * border_scale.y(), vol_trans.z() * border_scale.z()); + + // scale and translate volume to suppress to put connectors too close to the border + return assemble_transform(offset, Vec3d::Zero(), Vec3d::Ones() - border_scale, Vec3d::Ones()) * vol_matrix; +} + +bool GLGizmoCut3D::is_conflict_for_connector(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos) +{ + // check if connector pos is out of clipping plane + if (m_c->object_clipper() && !m_c->object_clipper()->is_projection_inside_cut(cur_pos)) { + m_info_stats.outside_cut_contour++; + return true; + } + + const CutConnector& cur_connector = connectors[idx]; + const Transform3d matrix = translation_transform(cur_pos) * m_rotation_m * + scale_transform(Vec3f(cur_connector.radius, cur_connector.radius, cur_connector.height).cast()); + const BoundingBoxf3 cur_tbb = m_shapes[cur_connector.attribs].model.get_bounding_box().transformed(matrix); + + if (!bounding_box().contains(cur_tbb)) { + m_info_stats.outside_bb++; + return true; + } + + for (size_t i = 0; i < connectors.size(); ++i) { + if (i == idx) + continue; + const CutConnector& connector = connectors[i]; + + if ((connector.pos - cur_connector.pos).norm() < double(connector.radius + cur_connector.radius)) { + m_info_stats.is_overlap = true; + return true; + } + } + + return false; +} + +void GLGizmoCut3D::render_connectors() +{ + ::glEnable(GL_DEPTH_TEST); + + if (cut_line_processing() || m_connector_mode == CutConnectorMode::Auto || !m_c->selection_info()) + return; + + const ModelObject* mo = m_c->selection_info()->model_object(); + auto inst_id = m_c->selection_info()->get_active_instance(); + if (inst_id < 0) + return; + const CutConnectors& connectors = mo->cut_connectors; + if (connectors.size() != m_selected.size()) { + // #ysFIXME + clear_selection(); + m_selected.resize(connectors.size(), false); + } + + ColorRGBA render_color = CONNECTOR_DEF_COLOR; + + const ModelInstance* mi = mo->instances[inst_id]; + const Vec3d& instance_offset = mi->get_offset(); + const double sla_shift = double(m_c->selection_info()->get_sla_shift()); + + const ClippingPlane* cp = m_c->object_clipper()->get_clipping_plane(); + const Vec3d& normal = cp && cp->is_active() ? cp->get_normal() : m_clp_normal; + + m_has_invalid_connector = false; + m_info_stats.invalidate(); + + for (size_t i = 0; i < connectors.size(); ++i) { + const CutConnector& connector = connectors[i]; + + float height = connector.height; + // recalculate connector position to world position + Vec3d pos = connector.pos + instance_offset + sla_shift * Vec3d::UnitZ(); + + // First decide about the color of the point. + if (is_conflict_for_connector(i, connectors, pos)) { + m_has_invalid_connector = true; + render_color = CONNECTOR_ERR_COLOR; + } + else if (!m_connectors_editing) + render_color = CONNECTOR_ERR_COLOR; + else if (size_t(m_hover_id - m_connectors_group_id) == i) + render_color = connector.attribs.type == CutConnectorType::Dowel ? HOVERED_DOWEL_COLOR : HOVERED_PLAG_COLOR; + else if (m_selected[i]) + render_color = connector.attribs.type == CutConnectorType::Dowel ? SELECTED_DOWEL_COLOR : SELECTED_PLAG_COLOR; + else // neither hover nor picking + render_color = connector.attribs.type == CutConnectorType::Dowel ? DOWEL_COLOR : PLAG_COLOR; + + const Camera& camera = wxGetApp().plater()->get_camera(); + if (connector.attribs.type == CutConnectorType::Dowel && + connector.attribs.style == CutConnectorStyle::Prizm) { + pos -= height * normal; + height *= 2; + } + const Transform3d view_model_matrix = camera.get_view_matrix() * translation_transform(pos) * m_rotation_m * + scale_transform(Vec3f(connector.radius, connector.radius, height).cast()); + + render_model(m_shapes[connector.attribs].model, render_color, view_model_matrix); + } +} + +bool GLGizmoCut3D::can_perform_cut() const +{ + if (m_has_invalid_connector || (!m_keep_upper && !m_keep_lower) || m_connectors_editing) + return false; + + const auto clipper = m_c->object_clipper(); + return clipper && clipper->has_valid_contour(); +} + +void GLGizmoCut3D::apply_connectors_in_model(ModelObject* mo, bool &create_dowels_as_separate_object) +{ + if (m_connector_mode == CutConnectorMode::Manual) { + clear_selection(); + + for (CutConnector&connector : mo->cut_connectors) { + connector.rotation_m = m_rotation_m; + + if (connector.attribs.type == CutConnectorType::Dowel) { + if (connector.attribs.style == CutConnectorStyle::Prizm) + connector.height *= 2; + create_dowels_as_separate_object = true; + } + else { + // culculate shift of the connector center regarding to the position on the cut plane + Vec3d shifted_center = m_plane_center + Vec3d::UnitZ(); + rotate_vec3d_around_plane_center(shifted_center); + Vec3d norm = (shifted_center - m_plane_center).normalized(); + connector.pos += norm * 0.5 * double(connector.height); } } - else if (box.center() != m_cut_contours.position) { - m_cut_contours.shift = box.center() - m_cut_contours.position; + mo->apply_cut_connectors(_u8L("Connector")); + } +} + +void GLGizmoCut3D::perform_cut(const Selection& selection) +{ + if (!can_perform_cut()) + return; + const int instance_idx = selection.get_instance_idx(); + const int object_idx = selection.get_object_idx(); + + wxCHECK_RET(instance_idx >= 0 && object_idx >= 0, "GLGizmoCut: Invalid object selection"); + + Plater* plater = wxGetApp().plater(); + ModelObject* mo = plater->model().objects[object_idx]; + if (!mo) + return; + + // deactivate CutGizmo and than perform a cut + m_parent.reset_all_gizmos(); + + // m_cut_z is the distance from the bed. Subtract possible SLA elevation. + const double sla_shift_z = selection.get_first_volume()->get_sla_shift_z(); + + const Vec3d instance_offset = mo->instances[instance_idx]->get_offset(); + Vec3d cut_center_offset = m_plane_center - instance_offset; + cut_center_offset[Z] -= sla_shift_z; + + // perform cut + { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Cut by Plane")); + + bool create_dowels_as_separate_object = false; + const bool has_connectors = !mo->cut_connectors.empty(); + // update connectors pos as offset of its center before cut performing + apply_connectors_in_model(mo, create_dowels_as_separate_object); + + plater->cut(object_idx, instance_idx, assemble_transform(cut_center_offset) * m_rotation_m, + only_if(has_connectors ? true : m_keep_upper, ModelObjectCutAttribute::KeepUpper) | + only_if(has_connectors ? true : m_keep_lower, ModelObjectCutAttribute::KeepLower) | + only_if(m_place_on_cut_upper, ModelObjectCutAttribute::PlaceOnCutUpper) | + only_if(m_place_on_cut_lower, ModelObjectCutAttribute::PlaceOnCutLower) | + only_if(m_rotate_upper, ModelObjectCutAttribute::FlipUpper) | + only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower) | + only_if(create_dowels_as_separate_object, ModelObjectCutAttribute::CreateDowels)); + } +} + + + +// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal +// Return false if no intersection was found, true otherwise. +bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair& pos_and_normal, Vec3d& pos_world) +{ + const float sla_shift = m_c->selection_info()->get_sla_shift(); + + const ModelObject* mo = m_c->selection_info()->model_object(); + const ModelInstance* mi = mo->instances[m_c->selection_info()->get_active_instance()]; + const Transform3d instance_trafo = sla_shift > 0.f ? + assemble_transform(Vec3d(0.0, 0.0, sla_shift)) * mi->get_transformation().get_matrix() : mi->get_transformation().get_matrix(); + const Camera& camera = wxGetApp().plater()->get_camera(); + + int mesh_id = -1; + for (const ModelVolume* mv : mo->volumes) { + ++mesh_id; + if (!mv->is_model_part()) + continue; + Vec3f normal; + Vec3f hit; + bool clipping_plane_was_hit = false; + +// const Transform3d volume_trafo = get_volume_transformation(mv); + const Transform3d volume_trafo = mv->get_transformation().get_matrix(); + + m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh(mouse_position, instance_trafo * volume_trafo, + camera, hit, normal, m_c->object_clipper()->get_clipping_plane(true), + nullptr, &clipping_plane_was_hit); + if (clipping_plane_was_hit) { + // recalculate hit to object's local position + Vec3d hit_d = hit.cast(); + hit_d -= mi->get_offset(); + hit_d[Z] -= sla_shift; + + // Return both the point and the facet normal. + pos_and_normal = std::make_pair(hit_d, normal.cast()); + pos_world = hit.cast(); + return true; } } + return false; +} + +void GLGizmoCut3D::clear_selection() +{ + m_selected.clear(); + m_selected_count = 0; +} + +void GLGizmoCut3D::reset_connectors() +{ + m_c->selection_info()->model_object()->cut_connectors.clear(); + update_raycasters_for_picking(); + clear_selection(); +} + +void GLGizmoCut3D::init_connector_shapes() +{ + for (const CutConnectorType& type : {CutConnectorType::Dowel, CutConnectorType::Plug}) + for (const CutConnectorStyle& style : {CutConnectorStyle::Frustum, CutConnectorStyle::Prizm}) + for (const CutConnectorShape& shape : {CutConnectorShape::Circle, CutConnectorShape::Hexagon, CutConnectorShape::Square, CutConnectorShape::Triangle}) { + const CutConnectorAttributes attribs = { type, style, shape }; + const indexed_triangle_set its = ModelObject::get_connector_mesh(attribs); + m_shapes[attribs].model.init_from(its); + m_shapes[attribs].mesh_raycaster = std::make_unique(std::make_shared(std::move(its))); + } +} + +void GLGizmoCut3D::update_connector_shape() +{ + CutConnectorAttributes attribs = { m_connector_type, CutConnectorStyle(m_connector_style), CutConnectorShape(m_connector_shape_id) }; + + const indexed_triangle_set its = ModelObject::get_connector_mesh(attribs); + m_connector_mesh.clear(); + m_connector_mesh = TriangleMesh(its); +} + +bool GLGizmoCut3D::cut_line_processing() const +{ + return m_line_beg != Vec3d::Zero(); +} + +void GLGizmoCut3D::discard_cut_line_processing() +{ + m_line_beg = m_line_end = Vec3d::Zero(); +} + +bool GLGizmoCut3D::process_cut_line(SLAGizmoEventType action, const Vec2d& mouse_position) +{ + const Camera& camera = wxGetApp().plater()->get_camera(); + + Vec3d pt; + Vec3d dir; + MeshRaycaster::line_from_mouse_pos(mouse_position, Transform3d::Identity(), camera, pt, dir); + dir.normalize(); + pt += dir; // Move the pt along dir so it is not clipped. + + if (action == SLAGizmoEventType::LeftDown && !cut_line_processing()) { + m_line_beg = pt; + m_line_end = pt; + on_unregister_raycasters_for_picking(); + return true; + } + + if (cut_line_processing()) { + m_line_end = pt; + if (action == SLAGizmoEventType::LeftDown || action == SLAGizmoEventType::LeftUp) { + Vec3d line_dir = m_line_end - m_line_beg; + if (line_dir.norm() < 3.0) + return true; + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Cut by line"), UndoRedo::SnapshotType::GizmoAction); + + Vec3d cross_dir = line_dir.cross(dir).normalized(); + Eigen::Quaterniond q; + Transform3d m = Transform3d::Identity(); + m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(Vec3d::UnitZ(), cross_dir).toRotationMatrix(); + + m_rotation_m = m; + m_angle_arc.reset(); + + set_center(m_plane_center + cross_dir * (cross_dir.dot(pt - m_plane_center))); + + discard_cut_line_processing(); + } + else if (action == SLAGizmoEventType::Moving) + this->set_dirty(); + return true; + } + return false; +} + +bool GLGizmoCut3D::add_connector(CutConnectors& connectors, const Vec2d& mouse_position) +{ + if (!m_connectors_editing) + return false; + + std::pair pos_and_normal; + Vec3d pos_world; + if (unproject_on_cut_plane(mouse_position.cast(), pos_and_normal, pos_world)) { + const Vec3d& hit = pos_and_normal.first; + + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Add connector"), UndoRedo::SnapshotType::GizmoAction); + unselect_all_connectors(); + + connectors.emplace_back(hit, m_rotation_m, + m_connector_size * 0.5f, m_connector_depth_ratio, + m_connector_size_tolerance, m_connector_depth_ratio_tolerance, + CutConnectorAttributes( CutConnectorType(m_connector_type), + CutConnectorStyle(m_connector_style), + CutConnectorShape(m_connector_shape_id))); + m_selected.push_back(true); + m_selected_count = 1; + assert(m_selected.size() == connectors.size()); + update_raycasters_for_picking(); + m_parent.set_as_dirty(); + + return true; + } + return false; +} + +bool GLGizmoCut3D::delete_selected_connectors(CutConnectors& connectors) +{ + if (connectors.empty()) + return false; + + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Delete connector"), UndoRedo::SnapshotType::GizmoAction); + + // remove connectors + for (int i = int(connectors.size()) - 1; i >= 0; i--) + if (m_selected[i]) + connectors.erase(connectors.begin() + i); + // remove selections + m_selected.erase(std::remove_if(m_selected.begin(), m_selected.end(), [](const auto& selected) { + return selected; }), m_selected.end()); + m_selected_count = 0; + + assert(m_selected.size() == connectors.size()); + update_raycasters_for_picking(); + m_parent.set_as_dirty(); + return true; +} + +void GLGizmoCut3D::select_connector(int idx, bool select) +{ + m_selected[idx] = select; + if (select) + ++m_selected_count; else - m_cut_contours.contours.reset(); + --m_selected_count; +} + +bool GLGizmoCut3D::is_selection_changed(bool alt_down, bool shift_down) +{ + if (m_hover_id >= m_connectors_group_id) { + if (alt_down) + select_connector(m_hover_id - m_connectors_group_id, false); + else { + if (!shift_down) + unselect_all_connectors(); + select_connector(m_hover_id - m_connectors_group_id, true); + } + return true; + } + return false; +} + +void GLGizmoCut3D::process_selection_rectangle(CutConnectors &connectors) +{ + GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_state(); + + ModelObject* mo = m_c->selection_info()->model_object(); + int active_inst = m_c->selection_info()->get_active_instance(); + + // First collect positions of all the points in world coordinates. + Transformation trafo = mo->instances[active_inst]->get_transformation(); + trafo.set_offset(trafo.get_offset() + double(m_c->selection_info()->get_sla_shift()) * Vec3d::UnitZ()); + + std::vector points; + for (const CutConnector&connector : connectors) + points.push_back(connector.pos + trafo.get_offset()); + + // Now ask the rectangle which of the points are inside. + std::vector points_idxs = m_selection_rectangle.contains(points); + m_selection_rectangle.stop_dragging(); + + for (size_t idx : points_idxs) + select_connector(int(idx), rectangle_status == GLSelectionRectangle::EState::Select); +} + +bool GLGizmoCut3D::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) +{ + if (is_dragging() || m_connector_mode == CutConnectorMode::Auto || (!m_keep_upper || !m_keep_lower)) + return false; + + if ( m_hover_id < 0 && shift_down && ! m_connectors_editing && + (action == SLAGizmoEventType::LeftDown || action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::Moving) ) + return process_cut_line(action, mouse_position); + + if (!m_connectors_editing) + return false; + + CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors; + + if (action == SLAGizmoEventType::LeftDown) { + if (shift_down || alt_down) { + // left down with shift - show the selection rectangle: + if (m_hover_id == -1) + m_selection_rectangle.start_dragging(mouse_position, shift_down ? GLSelectionRectangle::EState::Select : GLSelectionRectangle::EState::Deselect); + } + else + // If there is no selection and no hovering, add new point + if (m_hover_id == -1 && !shift_down && !alt_down) + if (!add_connector(connectors, mouse_position)) + m_ldown_mouse_position = mouse_position; + return true; + } + + if (action == SLAGizmoEventType::LeftUp && !m_selection_rectangle.is_dragging()) { + if ((m_ldown_mouse_position - mouse_position).norm() < 5.) + unselect_all_connectors(); + return is_selection_changed(alt_down, shift_down); + } + + // left up with selection rectangle - select points inside the rectangle: + if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp || action == SLAGizmoEventType::AltUp) && m_selection_rectangle.is_dragging()) { + // Is this a selection or deselection rectangle? + process_selection_rectangle(connectors); + return true; + } + + // dragging the selection rectangle: + if (action == SLAGizmoEventType::Dragging) { + if (m_selection_rectangle.is_dragging()) { + m_selection_rectangle.dragging(mouse_position); + return true; + } + return false; + } + + if (action == SLAGizmoEventType::RightDown && !shift_down) { + // If any point is in hover state, this should initiate its move - return control back to GLCanvas: + if (m_hover_id < m_connectors_group_id) + return false; + unselect_all_connectors(); + select_connector(m_hover_id - m_connectors_group_id, true); + return delete_selected_connectors(connectors); + } + + if (action == SLAGizmoEventType::Delete) + return delete_selected_connectors(connectors); + + if (action == SLAGizmoEventType::SelectAll) { + select_all_connectors(); + return true; + } + + return false; +} + +CommonGizmosDataID GLGizmoCut3D::on_get_requirements() const { + return CommonGizmosDataID( + int(CommonGizmosDataID::SelectionInfo) + | int(CommonGizmosDataID::InstancesHider) + | int(CommonGizmosDataID::ObjectClipper) + | int(CommonGizmosDataID::Raycaster)); } } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 0a7274e2e..35b6a92ce 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -2,55 +2,161 @@ #define slic3r_GLGizmoCut_hpp_ #include "GLGizmoBase.hpp" +#include "slic3r/GUI/GLSelectionRectangle.hpp" #include "slic3r/GUI/GLModel.hpp" #include "libslic3r/TriangleMesh.hpp" -#include "libslic3r/ObjectID.hpp" +#include "libslic3r/Model.hpp" namespace Slic3r { + +enum class CutConnectorType : int; +class ModelVolume; +struct CutConnectorAttributes; + namespace GUI { class Selection; -class GLGizmoCut : public GLGizmoBase -{ - static const double Offset; - static const double Margin; +enum class SLAGizmoEventType : unsigned char; + +class GLGizmoCut3D : public GLGizmoBase +{ + Transform3d m_rotation_m{ Transform3d::Identity() }; + double m_snap_step{ 1.0 }; + int m_connectors_group_id; + + // archived values + Vec3d m_ar_plane_center { Vec3d::Zero() }; + + Vec3d m_plane_center{ Vec3d::Zero() }; + // data to check position of the cut palne center on gizmo activation + Vec3d m_min_pos{ Vec3d::Zero() }; + Vec3d m_max_pos{ Vec3d::Zero() }; + Vec3d m_bb_center{ Vec3d::Zero() }; + Vec3d m_center_offset{ Vec3d::Zero() }; + + // values from RotationGizmo + double m_radius{ 0.0 }; + double m_grabber_radius{ 0.0 }; + double m_grabber_connection_len{ 0.0 }; + + double m_snap_coarse_in_radius{ 0.0 }; + double m_snap_coarse_out_radius{ 0.0 }; + double m_snap_fine_in_radius{ 0.0 }; + double m_snap_fine_out_radius{ 0.0 }; + + // dragging angel in hovered axes + Transform3d m_start_dragging_m{ Transform3d::Identity() }; + double m_angle{ 0.0 }; + + TriangleMesh m_connector_mesh; + // workaround for using of the clipping plane normal + Vec3d m_clp_normal{ Vec3d::Ones() }; + + Vec3d m_line_beg{ Vec3d::Zero() }; + Vec3d m_line_end{ Vec3d::Zero() }; + + Vec2d m_ldown_mouse_position{ Vec2d::Zero() }; - double m_cut_z{ 0.0 }; - double m_max_z{ 0.0 }; - double m_start_z{ 0.0 }; - Vec3d m_drag_pos; - Vec3d m_drag_center; - bool m_keep_upper{ true }; - bool m_keep_lower{ true }; - bool m_rotate_lower{ false }; -#if ENABLE_LEGACY_OPENGL_REMOVAL GLModel m_plane; GLModel m_grabber_connection; - Vec3d m_old_center; -#endif // ENABLE_LEGACY_OPENGL_REMOVAL + GLModel m_cut_line; - struct CutContours + PickingModel m_sphere; + PickingModel m_cone; + std::map m_shapes; + std::vector> m_raycasters; + + GLModel m_circle; + GLModel m_scale; + GLModel m_snap_radii; + GLModel m_reference_radius; + GLModel m_angle_arc; + + Vec3d m_old_center; + + struct InvalidConnectorsStatistics { - TriangleMesh mesh; - GLModel contours; - double cut_z{ 0.0 }; - Vec3d position{ Vec3d::Zero() }; - Vec3d shift{ Vec3d::Zero() }; - ObjectID object_id; - int instance_idx{ -1 }; - std::vector volumes_idxs; - std::vector volumes_trafos; + unsigned int outside_cut_contour; + unsigned int outside_bb; + bool is_overlap; + + void invalidate() { + outside_cut_contour = 0; + outside_bb = 0; + is_overlap = false; + } + } m_info_stats; + + bool m_keep_upper{ true }; + bool m_keep_lower{ true }; + bool m_place_on_cut_upper{ true }; + bool m_place_on_cut_lower{ false }; + bool m_rotate_upper{ false }; + bool m_rotate_lower{ false }; + + bool m_hide_cut_plane{ false }; + bool m_connectors_editing{ false }; + bool m_cut_plane_as_circle{ false }; + + float m_connector_depth_ratio{ 3.f }; + float m_connector_size{ 2.5f }; + + float m_connector_depth_ratio_tolerance{ 0.1f }; + float m_connector_size_tolerance{ 0.f }; + + float m_label_width{ 150.0 }; + float m_control_width{ 200.0 }; + bool m_imperial_units{ false }; + bool force_update_clipper_on_render{false}; + + mutable std::vector m_selected; // which pins are currently selected + int m_selected_count{ 0 }; + + GLSelectionRectangle m_selection_rectangle; + + bool m_has_invalid_connector{ false }; + + bool m_show_shortcuts{ false }; + std::vector> m_shortcuts; + + enum class CutMode { + cutPlanar + , cutGrig + //,cutRadial + //,cutModular }; - CutContours m_cut_contours; + enum class CutConnectorMode { + Auto + , Manual + }; + + std::vector m_modes; + size_t m_mode{ size_t(CutMode::cutPlanar) }; + + std::vector m_connector_modes; + CutConnectorMode m_connector_mode{ CutConnectorMode::Manual }; + + std::vector m_connector_types; + CutConnectorType m_connector_type; + + std::vector m_connector_styles; + size_t m_connector_style; + + std::vector m_connector_shapes; + size_t m_connector_shape_id; + + std::vector m_axis_names; public: - GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - - double get_cut_z() const { return m_cut_z; } - void set_cut_z(double cut_z); + GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); std::string get_tooltip() const override; + bool unproject_on_cut_plane(const Vec2d& mouse_pos, std::pair& pos_and_normal, Vec3d& pos_world); + bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); + + bool is_in_editing_mode() const override { return m_connectors_editing; } + bool is_selection_rectangle_dragging() const override { return m_selection_rectangle.is_dragging(); } /// /// Drag of plane @@ -59,29 +165,105 @@ public: /// Return True when use the information otherwise False. bool on_mouse(const wxMouseEvent &mouse_event) override; + void shift_cut_z(double delta); + void rotate_vec3d_around_plane_center(Vec3d&vec); + void put_connectors_on_cut_plane(const Vec3d& cp_normal, double cp_offset); + void update_clipper(); + void update_clipper_on_render(); + void set_connectors_editing() { m_connectors_editing = true; } + void invalidate_cut_plane(); + + BoundingBoxf3 bounding_box() const; + BoundingBoxf3 transformed_bounding_box(const Vec3d& plane_center, bool revert_move = false) const; + protected: - virtual bool on_init() override; - virtual void on_load(cereal::BinaryInputArchive& ar) override { ar(m_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower); } - virtual void on_save(cereal::BinaryOutputArchive& ar) const override { ar(m_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower); } - virtual std::string on_get_name() const override; - virtual void on_set_state() override; - virtual bool on_is_activable() const override; - virtual void on_start_dragging() override; - virtual void on_dragging(const UpdateData& data) override; - virtual void on_render() override; -#if ENABLE_RAYCAST_PICKING + bool on_init() override; + void on_load(cereal::BinaryInputArchive&ar) override; + void on_save(cereal::BinaryOutputArchive&ar) const override; + std::string on_get_name() const override; + void on_set_state() override; + CommonGizmosDataID on_get_requirements() const override; + void on_set_hover_id() override; + bool on_is_activable() const override; + bool on_is_selectable() const override; + Vec3d mouse_position_in_local_plane(Axis axis, const Linef3&mouse_ray) const; + void dragging_grabber_z(const GLGizmoBase::UpdateData &data); + void dragging_grabber_xy(const GLGizmoBase::UpdateData &data); + void dragging_connector(const GLGizmoBase::UpdateData &data); + void on_dragging(const UpdateData&data) override; + void on_start_dragging() override; + void on_stop_dragging() override; + void on_render() override; + + void render_debug_input_window(); + void adjust_window_position(float x, float y, float bottom_limit); + void unselect_all_connectors(); + void select_all_connectors(); + void render_shortcuts(); + void apply_selected_connectors(std::function apply_fn); + void render_connectors_input_window(CutConnectors &connectors); + void render_build_size(); + void reset_cut_plane(); + void set_connectors_editing(bool connectors_editing); + void render_cut_plane_input_window(CutConnectors &connectors); + void init_input_window_data(CutConnectors &connectors); + void render_input_window_warning() const; + bool add_connector(CutConnectors&connectors, const Vec2d&mouse_position); + bool delete_selected_connectors(CutConnectors&connectors); + void select_connector(int idx, bool select); + bool is_selection_changed(bool alt_down, bool shift_down); + void process_selection_rectangle(CutConnectors &connectors); + virtual void on_register_raycasters_for_picking() override; virtual void on_unregister_raycasters_for_picking() override; -#else - virtual void on_render_for_picking() override; -#endif // ENABLE_RAYCAST_PICKING - virtual void on_render_input_window(float x, float y, float bottom_limit) override; + void update_raycasters_for_picking(); + void set_volumes_picking_state(bool state); + void update_raycasters_for_picking_transform(); + + void on_render_input_window(float x, float y, float bottom_limit) override; + + bool wants_enter_leave_snapshots() const override { return true; } + std::string get_gizmo_entering_text() const override { return _u8L("Entering Cut gizmo"); } + std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Cut gizmo"); } + std::string get_action_snapshot_name() override { return _u8L("Cut gizmo editing"); } private: - void perform_cut(const Selection& selection); - double calc_projection(const Linef3& mouse_ray) const; - BoundingBoxf3 bounding_box() const; - void update_contours(); + void set_center(const Vec3d& center); + bool render_combo(const std::string& label, const std::vector& lines, size_t& selection_idx); + bool render_double_input(const std::string& label, double& value_in); + bool render_slider_double_input(const std::string& label, float& value_in, float& tolerance_in); + void render_move_center_input(int axis); + void render_connect_mode_radio_button(CutConnectorMode mode); + bool render_reset_button(const std::string& label_id, const std::string& tooltip) const; + bool render_connect_type_radio_button(CutConnectorType type); + Transform3d get_volume_transformation(const ModelVolume* volume) const; + bool is_conflict_for_connector(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos); + void render_connectors(); + + bool can_perform_cut() const; + void apply_connectors_in_model(ModelObject* mo, bool &create_dowels_as_separate_object); + bool cut_line_processing() const; + void discard_cut_line_processing(); + + void render_cut_plane(); + void render_model(GLModel& model, const ColorRGBA& color, Transform3d view_model_matrix); + void render_line(GLModel& line_model, const ColorRGBA& color, Transform3d view_model_matrix, float width); + void render_rotation_snapping(Axis axis, const ColorRGBA& color); + void render_grabber_connection(const ColorRGBA& color, Transform3d view_matrix); + void render_cut_plane_grabbers(); + void render_cut_line(); + void perform_cut(const Selection&selection); + void set_center_pos(const Vec3d¢er_pos, bool force = false); + bool update_bb(); + void init_picking_models(); + void init_rendering_items(); + void render_clipper_cut(); + void clear_selection(); + void reset_connectors(); + void init_connector_shapes(); + void update_connector_shape(); + void validate_connector_settings(); + bool process_cut_line(SLAGizmoEventType action, const Vec2d& mouse_position); }; } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index b30c29db1..5f0a110ce 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -1,550 +1,550 @@ -#include "GLGizmoFdmSupports.hpp" - -#include "libslic3r/Model.hpp" - -//#include "slic3r/GUI/3DScene.hpp" -#include "slic3r/GUI/GLCanvas3D.hpp" -#include "slic3r/GUI/GUI_App.hpp" -#include "slic3r/GUI/ImGuiWrapper.hpp" -#include "slic3r/GUI/Plater.hpp" -#include "slic3r/GUI/GUI_ObjectList.hpp" -#include "slic3r/GUI/format.hpp" -#include "slic3r/Utils/UndoRedo.hpp" -#include "libslic3r/Print.hpp" -#include "slic3r/GUI/MsgDialog.hpp" - - -#include - - -namespace Slic3r::GUI { - - - -void GLGizmoFdmSupports::on_shutdown() -{ - m_highlight_by_angle_threshold_deg = 0.f; - m_parent.use_slope(false); - m_parent.toggle_model_objects_visibility(true); -} - - - -std::string GLGizmoFdmSupports::on_get_name() const -{ - return _u8L("Paint-on supports"); -} - - - -bool GLGizmoFdmSupports::on_init() -{ - m_shortcut_key = WXK_CONTROL_L; - - m_desc["auto_generate"] = _L("Auto-generate supports"); - m_desc["generating"] = _L("Generating supports..."); - m_desc["clipping_of_view"] = _L("Clipping of view") + ": "; - m_desc["reset_direction"] = _L("Reset direction"); - m_desc["cursor_size"] = _L("Brush size") + ": "; - m_desc["cursor_type"] = _L("Brush shape") + ": "; - m_desc["enforce_caption"] = _L("Left mouse button") + ": "; - m_desc["enforce"] = _L("Enforce supports"); - m_desc["block_caption"] = _L("Right mouse button") + ": "; - m_desc["block"] = _L("Block supports"); - m_desc["remove_caption"] = _L("Shift + Left mouse button") + ": "; - m_desc["remove"] = _L("Remove selection"); - m_desc["remove_all"] = _L("Remove all selection"); - m_desc["circle"] = _L("Circle"); - m_desc["sphere"] = _L("Sphere"); - m_desc["pointer"] = _L("Triangles"); - m_desc["highlight_by_angle"] = _L("Highlight overhang by angle"); - m_desc["enforce_button"] = _L("Enforce"); - m_desc["cancel"] = _L("Cancel"); - - m_desc["tool_type"] = _L("Tool type") + ": "; - m_desc["tool_brush"] = _L("Brush"); - m_desc["tool_smart_fill"] = _L("Smart fill"); - - m_desc["smart_fill_angle"] = _L("Smart fill angle"); - - m_desc["split_triangles"] = _L("Split triangles"); - m_desc["on_overhangs_only"] = _L("On overhangs only"); - - return true; -} - -void GLGizmoFdmSupports::render_painter_gizmo() -{ - const Selection& selection = m_parent.get_selection(); - - glsafe(::glEnable(GL_BLEND)); - glsafe(::glEnable(GL_DEPTH_TEST)); - - render_triangles(selection); - m_c->object_clipper()->render_cut(); - m_c->instances_hider()->render_cut(); - render_cursor(); - - glsafe(::glDisable(GL_BLEND)); -} - - - -void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit) -{ - if (! m_c->selection_info()->model_object()) - return; - - const float approx_height = m_imgui->scaled(25.f); - y = std::min(y, bottom_limit - approx_height); - m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); - - m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); - - // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: - const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, - m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); - const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); - const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.f); - const float autoset_slider_label_max_width = m_imgui->scaled(7.5f); - const float autoset_slider_left = m_imgui->calc_text_size(m_desc.at("highlight_by_angle"), autoset_slider_label_max_width).x + m_imgui->scaled(1.f); - - const float cursor_type_radio_circle = m_imgui->calc_text_size(m_desc["circle"]).x + m_imgui->scaled(2.5f); - const float cursor_type_radio_sphere = m_imgui->calc_text_size(m_desc["sphere"]).x + m_imgui->scaled(2.5f); - const float cursor_type_radio_pointer = m_imgui->calc_text_size(m_desc["pointer"]).x + m_imgui->scaled(2.5f); - - const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); - const float button_enforce_width = m_imgui->calc_text_size(m_desc.at("enforce_button")).x; - const float button_cancel_width = m_imgui->calc_text_size(m_desc.at("cancel")).x; - const float buttons_width = std::max(button_enforce_width, button_cancel_width) + m_imgui->scaled(0.5f); - const float minimal_slider_width = m_imgui->scaled(4.f); - - const float tool_type_radio_left = m_imgui->calc_text_size(m_desc["tool_type"]).x + m_imgui->scaled(1.f); - const float tool_type_radio_brush = m_imgui->calc_text_size(m_desc["tool_brush"]).x + m_imgui->scaled(2.5f); - const float tool_type_radio_smart_fill = m_imgui->calc_text_size(m_desc["tool_smart_fill"]).x + m_imgui->scaled(2.5f); - - const float split_triangles_checkbox_width = m_imgui->calc_text_size(m_desc["split_triangles"]).x + m_imgui->scaled(2.5f); - const float on_overhangs_only_checkbox_width = m_imgui->calc_text_size(m_desc["on_overhangs_only"]).x + m_imgui->scaled(2.5f); - - float caption_max = 0.f; - float total_text_max = 0.f; - for (const auto &t : std::array{"enforce", "block", "remove"}) { - caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); - total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); - } - total_text_max += caption_max + m_imgui->scaled(1.f); - caption_max += m_imgui->scaled(1.f); - - const float sliders_left_width = std::max(std::max(autoset_slider_left, smart_fill_slider_left), std::max(cursor_slider_left, clipping_slider_left)); - const float slider_icon_width = m_imgui->get_slider_icon_size().x; - float window_width = minimal_slider_width + sliders_left_width + slider_icon_width; - window_width = std::max(window_width, total_text_max); - window_width = std::max(window_width, button_width); - window_width = std::max(window_width, split_triangles_checkbox_width); - window_width = std::max(window_width, on_overhangs_only_checkbox_width); - window_width = std::max(window_width, cursor_type_radio_circle + cursor_type_radio_sphere + cursor_type_radio_pointer); - window_width = std::max(window_width, tool_type_radio_left + tool_type_radio_brush + tool_type_radio_smart_fill); - window_width = std::max(window_width, 2.f * buttons_width + m_imgui->scaled(1.f)); - - auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, caption); - ImGui::SameLine(caption_max); - m_imgui->text(text); - }; - - for (const auto &t : std::array{"enforce", "block", "remove"}) - draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); - - ImGui::Separator(); - - if (waiting_for_autogenerated_supports) { - m_imgui->text(m_desc.at("generating")); - } else { - bool generate = m_imgui->button(m_desc.at("auto_generate")); - if (generate) - auto_generate(); - } - ImGui::Separator(); - - float position_before_text_y = ImGui::GetCursorPos().y; - ImGui::AlignTextToFramePadding(); - m_imgui->text_wrapped(m_desc["highlight_by_angle"] + ":", autoset_slider_label_max_width); - ImGui::AlignTextToFramePadding(); - float position_after_text_y = ImGui::GetCursorPos().y; - std::string format_str = std::string("%.f") + I18N::translate_utf8("°", - "Degree sign to use in the respective slider in FDM supports gizmo," - "placed after the number with no whitespace in between."); - ImGui::SameLine(sliders_left_width); - - float slider_height = m_imgui->get_slider_float_height(); - // Makes slider to be aligned to bottom of the multi-line text. - float slider_start_position_y = std::max(position_before_text_y, position_after_text_y - slider_height); - ImGui::SetCursorPosY(slider_start_position_y); - - ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); - wxString tooltip = format_wxstr(_L("Preselects faces by overhang angle. It is possible to restrict paintable facets to only preselected faces when " - "the option \"%1%\" is enabled."), m_desc["on_overhangs_only"]); - if (m_imgui->slider_float("##angle_threshold_deg", &m_highlight_by_angle_threshold_deg, 0.f, 90.f, format_str.data(), 1.0f, true, tooltip)) { - m_parent.set_slope_normal_angle(90.f - m_highlight_by_angle_threshold_deg); - if (! m_parent.is_using_slope()) { - m_parent.use_slope(true); - m_parent.set_as_dirty(); - } - } - - // Restores the cursor position to be below the multi-line text. - ImGui::SetCursorPosY(std::max(position_before_text_y + slider_height, position_after_text_y)); - - const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; - - m_imgui->disabled_begin(m_highlight_by_angle_threshold_deg == 0.f); - ImGui::NewLine(); - ImGui::SameLine(window_width - 2.f*buttons_width - m_imgui->scaled(0.5f)); - if (m_imgui->button(m_desc["enforce_button"], buttons_width, 0.f)) { - select_facets_by_angle(m_highlight_by_angle_threshold_deg, false); - m_highlight_by_angle_threshold_deg = 0.f; - m_parent.use_slope(false); - } - ImGui::SameLine(window_width - buttons_width); - if (m_imgui->button(m_desc["cancel"], buttons_width, 0.f)) { - m_highlight_by_angle_threshold_deg = 0.f; - m_parent.use_slope(false); - } - m_imgui->disabled_end(); - - - ImGui::Separator(); - - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc["tool_type"]); - - float tool_type_offset = tool_type_radio_left + (window_width - tool_type_radio_left - tool_type_radio_brush - tool_type_radio_smart_fill + m_imgui->scaled(0.5f)) / 2.f; - ImGui::SameLine(tool_type_offset); - ImGui::PushItemWidth(tool_type_radio_brush); - if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == ToolType::BRUSH)) - m_tool_type = ToolType::BRUSH; - - if (ImGui::IsItemHovered()) - m_imgui->tooltip(_L("Paints facets according to the chosen painting brush."), max_tooltip_width); - - ImGui::SameLine(tool_type_offset + tool_type_radio_brush); - ImGui::PushItemWidth(tool_type_radio_smart_fill); - if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == ToolType::SMART_FILL)) - m_tool_type = ToolType::SMART_FILL; - - if (ImGui::IsItemHovered()) - m_imgui->tooltip(_L("Paints neighboring facets whose relative angle is less or equal to set angle."), max_tooltip_width); - - m_imgui->checkbox(m_desc["on_overhangs_only"], m_paint_on_overhangs_only); - if (ImGui::IsItemHovered()) - m_imgui->tooltip(format_wxstr(_L("Allows painting only on facets selected by: \"%1%\""), m_desc["highlight_by_angle"]), max_tooltip_width); - - ImGui::Separator(); - - if (m_tool_type == ToolType::BRUSH) { - m_imgui->text(m_desc.at("cursor_type")); - ImGui::NewLine(); - - float cursor_type_offset = (window_width - cursor_type_radio_sphere - cursor_type_radio_circle - cursor_type_radio_pointer + m_imgui->scaled(1.5f)) / 2.f; - ImGui::SameLine(cursor_type_offset); - ImGui::PushItemWidth(cursor_type_radio_sphere); - if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE)) - m_cursor_type = TriangleSelector::CursorType::SPHERE; - - if (ImGui::IsItemHovered()) - m_imgui->tooltip(_L("Paints all facets inside, regardless of their orientation."), max_tooltip_width); - - ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere); - ImGui::PushItemWidth(cursor_type_radio_circle); - - if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE)) - m_cursor_type = TriangleSelector::CursorType::CIRCLE; - - if (ImGui::IsItemHovered()) - m_imgui->tooltip(_L("Ignores facets facing away from the camera."), max_tooltip_width); - - ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + cursor_type_radio_circle); - ImGui::PushItemWidth(cursor_type_radio_pointer); - - if (m_imgui->radio_button(m_desc["pointer"], m_cursor_type == TriangleSelector::CursorType::POINTER)) - m_cursor_type = TriangleSelector::CursorType::POINTER; - - if (ImGui::IsItemHovered()) - m_imgui->tooltip(_L("Paints only one facet."), max_tooltip_width); - - m_imgui->disabled_begin(m_cursor_type != TriangleSelector::CursorType::SPHERE && m_cursor_type != TriangleSelector::CursorType::CIRCLE); - - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("cursor_size")); - ImGui::SameLine(sliders_left_width); - ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); - m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true, _L("Alt + Mouse wheel")); - - m_imgui->checkbox(m_desc["split_triangles"], m_triangle_splitting_enabled); - - if (ImGui::IsItemHovered()) - m_imgui->tooltip(_L("Splits bigger facets into smaller ones while the object is painted."), max_tooltip_width); - - m_imgui->disabled_end(); - } else { - assert(m_tool_type == ToolType::SMART_FILL); - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc["smart_fill_angle"] + ":"); - - ImGui::SameLine(sliders_left_width); - ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); - if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true, _L("Alt + Mouse wheel"))) - for (auto &triangle_selector : m_triangle_selectors) { - triangle_selector->seed_fill_unselect_all_triangles(); - triangle_selector->request_update_render_data(); - } - } - - ImGui::Separator(); - if (m_c->object_clipper()->get_position() == 0.f) { - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("clipping_of_view")); - } - else { - if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this](){ - m_c->object_clipper()->set_position(-1., false); - }); - } - } - - auto clp_dist = float(m_c->object_clipper()->get_position()); - ImGui::SameLine(sliders_left_width); - ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); - if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel"))) - m_c->object_clipper()->set_position(clp_dist, true); - - ImGui::Separator(); - if (m_imgui->button(m_desc.at("remove_all"))) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), UndoRedo::SnapshotType::GizmoAction); - ModelObject *mo = m_c->selection_info()->model_object(); - int idx = -1; - for (ModelVolume *mv : mo->volumes) - if (mv->is_model_part()) { - ++idx; - m_triangle_selectors[idx]->reset(); - m_triangle_selectors[idx]->request_update_render_data(); - } - - update_model_object(); - this->waiting_for_autogenerated_supports = false; - m_parent.set_as_dirty(); - } - - m_imgui->end(); -} - - - -void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block) -{ - float threshold = (float(M_PI)/180.f)*threshold_deg; - const Selection& selection = m_parent.get_selection(); - const ModelObject* mo = m_c->selection_info()->model_object(); - const ModelInstance* mi = mo->instances[selection.get_instance_idx()]; - - int mesh_id = -1; - for (const ModelVolume* mv : mo->volumes) { - if (! mv->is_model_part()) - continue; - - ++mesh_id; - -#if ENABLE_WORLD_COORDINATE - const Transform3d trafo_matrix = mi->get_matrix_no_offset() * mv->get_matrix_no_offset(); -#else - const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true); -#endif // ENABLE_WORLD_COORDINATE - Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast().normalized(); - Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast().normalized(); - - float dot_limit = limit.dot(down); - - // Now calculate dot product of vert_direction and facets' normals. - int idx = 0; - const indexed_triangle_set &its = mv->mesh().its; - for (const stl_triangle_vertex_indices &face : its.indices) { - if (its_face_normal(its, face).dot(down) > dot_limit) { - m_triangle_selectors[mesh_id]->set_facet(idx, block ? EnforcerBlockerType::BLOCKER : EnforcerBlockerType::ENFORCER); - m_triangle_selectors.back()->request_update_render_data(); - } - ++ idx; - } - } - - Plater::TakeSnapshot snapshot(wxGetApp().plater(), block ? _L("Block supports by angle") - : _L("Add supports by angle")); - update_model_object(); - this->waiting_for_autogenerated_supports = false; - m_parent.set_as_dirty(); -} - -void GLGizmoFdmSupports::data_changed() -{ - GLGizmoPainterBase::data_changed(); - if (! m_c->selection_info()) - return; - - ModelObject* mo = m_c->selection_info()->model_object(); - if (mo && this->waiting_for_autogenerated_supports) { - get_data_from_backend(); - } else { - this->waiting_for_autogenerated_supports = false; - } -} - -void GLGizmoFdmSupports::get_data_from_backend() -{ - if (! has_backend_supports()) - return; - ModelObject* mo = m_c->selection_info()->model_object(); - - // find the respective PrintObject, we need a pointer to it - for (const PrintObject* po : m_parent.fff_print()->objects()) { - if (po->model_object()->id() == mo->id()) { - std::unordered_map mvs; - for (const ModelVolume* mv : po->model_object()->volumes) { - if (mv->is_model_part()) { - mvs.emplace(mv->id().id, mv); - } - } - int mesh_id = -1.0f; - for (ModelVolume* mv : mo->volumes){ - if (mv->is_model_part()){ - mesh_id++; - mv->supported_facets.assign(mvs[mv->id().id]->supported_facets); - m_triangle_selectors[mesh_id]->deserialize(mv->supported_facets.get_data(), true); - m_triangle_selectors[mesh_id]->request_update_render_data(); - } - } - this->waiting_for_autogenerated_supports = false; - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); - m_parent.set_as_dirty(); - } - } -} - - -void GLGizmoFdmSupports::update_model_object() const -{ - bool updated = false; - ModelObject* mo = m_c->selection_info()->model_object(); - int idx = -1; - for (ModelVolume* mv : mo->volumes) { - if (! mv->is_model_part()) - continue; - ++idx; - updated |= mv->supported_facets.set(*m_triangle_selectors[idx].get()); - } - - if (updated) { - const ModelObjectPtrs& mos = wxGetApp().model().objects; - wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin()); - - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); - } -} - -void GLGizmoFdmSupports::update_from_model_object() -{ - wxBusyCursor wait; - - const ModelObject* mo = m_c->selection_info()->model_object(); - m_triangle_selectors.clear(); - - int volume_id = -1; - for (const ModelVolume* mv : mo->volumes) { - if (! mv->is_model_part()) - continue; - - ++volume_id; - - // This mesh does not account for the possible Z up SLA offset. - const TriangleMesh* mesh = &mv->mesh(); - - m_triangle_selectors.emplace_back(std::make_unique(*mesh)); - // Reset of TriangleSelector is done inside TriangleSelectorGUI's constructor, so we don't need it to perform it again in deserialize(). - m_triangle_selectors.back()->deserialize(mv->supported_facets.get_data(), false); - m_triangle_selectors.back()->request_update_render_data(); - } -} - -bool GLGizmoFdmSupports::has_backend_supports() const -{ - const ModelObject* mo = m_c->selection_info()->model_object(); - if (! mo) - return false; - - // find PrintObject with this ID - for (const PrintObject* po : m_parent.fff_print()->objects()) { - if (po->model_object()->id() == mo->id()) - return po->is_step_done(posSupportSpotsSearch); - } - return false; -} - -void GLGizmoFdmSupports::reslice_FDM_supports(bool postpone_error_messages) const { - wxGetApp().CallAfter( - [this, postpone_error_messages]() { - wxGetApp().plater()->reslice_FFF_until_step(posSupportSpotsSearch, - *m_c->selection_info()->model_object(), postpone_error_messages); - }); -} - -void GLGizmoFdmSupports::auto_generate() -{ - ModelObject *mo = m_c->selection_info()->model_object(); - bool not_painted = std::all_of(mo->volumes.begin(), mo->volumes.end(), [](const ModelVolume* vol){ - return vol->type() != ModelVolumeType::MODEL_PART || vol->supported_facets.empty(); - }); - - MessageDialog dlg(GUI::wxGetApp().plater(), - _L("Autogeneration will erase all currently painted areas.") + "\n\n" + - _L("Are you sure you want to do it?") + "\n", - _L("Warning"), wxICON_WARNING | wxYES | wxNO); - - if (not_painted || dlg.ShowModal() == wxID_YES) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Autogenerate support points")); - int mesh_id = -1.0f; - for (ModelVolume *mv : mo->volumes) { - if (mv->is_model_part()) { - mesh_id++; - mv->supported_facets.reset(); - m_triangle_selectors[mesh_id]->reset(); - m_triangle_selectors[mesh_id]->request_update_render_data(); - } - } - - mo->config.set("support_material", true); - mo->config.set("support_material_auto", false); - this->waiting_for_autogenerated_supports = true; - wxGetApp().CallAfter([this]() { reslice_FDM_supports(); }); - } -} - - -PainterGizmoType GLGizmoFdmSupports::get_painter_type() const -{ - return PainterGizmoType::FDM_SUPPORTS; -} - -wxString GLGizmoFdmSupports::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const -{ - wxString action_name; - if (shift_down) - action_name = _L("Remove selection"); - else { - if (button_down == Button::Left) - action_name = _L("Add supports"); - else - action_name = _L("Block supports"); - } - return action_name; -} - -} // namespace Slic3r::GUI +#include "GLGizmoFdmSupports.hpp" + +#include "libslic3r/Model.hpp" + +//#include "slic3r/GUI/3DScene.hpp" +#include "slic3r/GUI/GLCanvas3D.hpp" +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/ImGuiWrapper.hpp" +#include "slic3r/GUI/Plater.hpp" +#include "slic3r/GUI/GUI_ObjectList.hpp" +#include "slic3r/GUI/format.hpp" +#include "slic3r/Utils/UndoRedo.hpp" +#include "libslic3r/Print.hpp" +#include "slic3r/GUI/MsgDialog.hpp" + + +#include + + +namespace Slic3r::GUI { + + + +void GLGizmoFdmSupports::on_shutdown() +{ + m_highlight_by_angle_threshold_deg = 0.f; + m_parent.use_slope(false); + m_parent.toggle_model_objects_visibility(true); +} + + + +std::string GLGizmoFdmSupports::on_get_name() const +{ + return _u8L("Paint-on supports"); +} + + + +bool GLGizmoFdmSupports::on_init() +{ + m_shortcut_key = WXK_CONTROL_L; + + m_desc["auto_generate"] = _L("Auto-generate supports"); + m_desc["generating"] = _L("Generating supports..."); + m_desc["clipping_of_view"] = _L("Clipping of view") + ": "; + m_desc["reset_direction"] = _L("Reset direction"); + m_desc["cursor_size"] = _L("Brush size") + ": "; + m_desc["cursor_type"] = _L("Brush shape") + ": "; + m_desc["enforce_caption"] = _L("Left mouse button") + ": "; + m_desc["enforce"] = _L("Enforce supports"); + m_desc["block_caption"] = _L("Right mouse button") + ": "; + m_desc["block"] = _L("Block supports"); + m_desc["remove_caption"] = _L("Shift + Left mouse button") + ": "; + m_desc["remove"] = _L("Remove selection"); + m_desc["remove_all"] = _L("Remove all selection"); + m_desc["circle"] = _L("Circle"); + m_desc["sphere"] = _L("Sphere"); + m_desc["pointer"] = _L("Triangles"); + m_desc["highlight_by_angle"] = _L("Highlight overhang by angle"); + m_desc["enforce_button"] = _L("Enforce"); + m_desc["cancel"] = _L("Cancel"); + + m_desc["tool_type"] = _L("Tool type") + ": "; + m_desc["tool_brush"] = _L("Brush"); + m_desc["tool_smart_fill"] = _L("Smart fill"); + + m_desc["smart_fill_angle"] = _L("Smart fill angle"); + + m_desc["split_triangles"] = _L("Split triangles"); + m_desc["on_overhangs_only"] = _L("On overhangs only"); + + return true; +} + +void GLGizmoFdmSupports::render_painter_gizmo() +{ + const Selection& selection = m_parent.get_selection(); + + glsafe(::glEnable(GL_BLEND)); + glsafe(::glEnable(GL_DEPTH_TEST)); + + render_triangles(selection); + m_c->object_clipper()->render_cut(); + m_c->instances_hider()->render_cut(); + render_cursor(); + + glsafe(::glDisable(GL_BLEND)); +} + + + +void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit) +{ + if (! m_c->selection_info()->model_object()) + return; + + const float approx_height = m_imgui->scaled(25.f); + y = std::min(y, bottom_limit - approx_height); + m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); + + m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); + + // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: + const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, + m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); + const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); + const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.f); + const float autoset_slider_label_max_width = m_imgui->scaled(7.5f); + const float autoset_slider_left = m_imgui->calc_text_size(m_desc.at("highlight_by_angle"), autoset_slider_label_max_width).x + m_imgui->scaled(1.f); + + const float cursor_type_radio_circle = m_imgui->calc_text_size(m_desc["circle"]).x + m_imgui->scaled(2.5f); + const float cursor_type_radio_sphere = m_imgui->calc_text_size(m_desc["sphere"]).x + m_imgui->scaled(2.5f); + const float cursor_type_radio_pointer = m_imgui->calc_text_size(m_desc["pointer"]).x + m_imgui->scaled(2.5f); + + const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); + const float button_enforce_width = m_imgui->calc_text_size(m_desc.at("enforce_button")).x; + const float button_cancel_width = m_imgui->calc_text_size(m_desc.at("cancel")).x; + const float buttons_width = std::max(button_enforce_width, button_cancel_width) + m_imgui->scaled(0.5f); + const float minimal_slider_width = m_imgui->scaled(4.f); + + const float tool_type_radio_left = m_imgui->calc_text_size(m_desc["tool_type"]).x + m_imgui->scaled(1.f); + const float tool_type_radio_brush = m_imgui->calc_text_size(m_desc["tool_brush"]).x + m_imgui->scaled(2.5f); + const float tool_type_radio_smart_fill = m_imgui->calc_text_size(m_desc["tool_smart_fill"]).x + m_imgui->scaled(2.5f); + + const float split_triangles_checkbox_width = m_imgui->calc_text_size(m_desc["split_triangles"]).x + m_imgui->scaled(2.5f); + const float on_overhangs_only_checkbox_width = m_imgui->calc_text_size(m_desc["on_overhangs_only"]).x + m_imgui->scaled(2.5f); + + float caption_max = 0.f; + float total_text_max = 0.f; + for (const auto &t : std::array{"enforce", "block", "remove"}) { + caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); + total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); + } + total_text_max += caption_max + m_imgui->scaled(1.f); + caption_max += m_imgui->scaled(1.f); + + const float sliders_left_width = std::max(std::max(autoset_slider_left, smart_fill_slider_left), std::max(cursor_slider_left, clipping_slider_left)); + const float slider_icon_width = m_imgui->get_slider_icon_size().x; + float window_width = minimal_slider_width + sliders_left_width + slider_icon_width; + window_width = std::max(window_width, total_text_max); + window_width = std::max(window_width, button_width); + window_width = std::max(window_width, split_triangles_checkbox_width); + window_width = std::max(window_width, on_overhangs_only_checkbox_width); + window_width = std::max(window_width, cursor_type_radio_circle + cursor_type_radio_sphere + cursor_type_radio_pointer); + window_width = std::max(window_width, tool_type_radio_left + tool_type_radio_brush + tool_type_radio_smart_fill); + window_width = std::max(window_width, 2.f * buttons_width + m_imgui->scaled(1.f)); + + auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, caption); + ImGui::SameLine(caption_max); + m_imgui->text(text); + }; + + for (const auto &t : std::array{"enforce", "block", "remove"}) + draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); + + ImGui::Separator(); + + if (waiting_for_autogenerated_supports) { + m_imgui->text(m_desc.at("generating")); + } else { + bool generate = m_imgui->button(m_desc.at("auto_generate")); + if (generate) + auto_generate(); + } + ImGui::Separator(); + + float position_before_text_y = ImGui::GetCursorPos().y; + ImGui::AlignTextToFramePadding(); + m_imgui->text_wrapped(m_desc["highlight_by_angle"] + ":", autoset_slider_label_max_width); + ImGui::AlignTextToFramePadding(); + float position_after_text_y = ImGui::GetCursorPos().y; + std::string format_str = std::string("%.f") + I18N::translate_utf8("°", + "Degree sign to use in the respective slider in FDM supports gizmo," + "placed after the number with no whitespace in between."); + ImGui::SameLine(sliders_left_width); + + float slider_height = m_imgui->get_slider_float_height(); + // Makes slider to be aligned to bottom of the multi-line text. + float slider_start_position_y = std::max(position_before_text_y, position_after_text_y - slider_height); + ImGui::SetCursorPosY(slider_start_position_y); + + ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); + wxString tooltip = format_wxstr(_L("Preselects faces by overhang angle. It is possible to restrict paintable facets to only preselected faces when " + "the option \"%1%\" is enabled."), m_desc["on_overhangs_only"]); + if (m_imgui->slider_float("##angle_threshold_deg", &m_highlight_by_angle_threshold_deg, 0.f, 90.f, format_str.data(), 1.0f, true, tooltip)) { + m_parent.set_slope_normal_angle(90.f - m_highlight_by_angle_threshold_deg); + if (! m_parent.is_using_slope()) { + m_parent.use_slope(true); + m_parent.set_as_dirty(); + } + } + + // Restores the cursor position to be below the multi-line text. + ImGui::SetCursorPosY(std::max(position_before_text_y + slider_height, position_after_text_y)); + + const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; + + m_imgui->disabled_begin(m_highlight_by_angle_threshold_deg == 0.f); + ImGui::NewLine(); + ImGui::SameLine(window_width - 2.f*buttons_width - m_imgui->scaled(0.5f)); + if (m_imgui->button(m_desc["enforce_button"], buttons_width, 0.f)) { + select_facets_by_angle(m_highlight_by_angle_threshold_deg, false); + m_highlight_by_angle_threshold_deg = 0.f; + m_parent.use_slope(false); + } + ImGui::SameLine(window_width - buttons_width); + if (m_imgui->button(m_desc["cancel"], buttons_width, 0.f)) { + m_highlight_by_angle_threshold_deg = 0.f; + m_parent.use_slope(false); + } + m_imgui->disabled_end(); + + + ImGui::Separator(); + + ImGui::AlignTextToFramePadding(); + m_imgui->text(m_desc["tool_type"]); + + float tool_type_offset = tool_type_radio_left + (window_width - tool_type_radio_left - tool_type_radio_brush - tool_type_radio_smart_fill + m_imgui->scaled(0.5f)) / 2.f; + ImGui::SameLine(tool_type_offset); + ImGui::PushItemWidth(tool_type_radio_brush); + if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == ToolType::BRUSH)) + m_tool_type = ToolType::BRUSH; + + if (ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Paints facets according to the chosen painting brush."), max_tooltip_width); + + ImGui::SameLine(tool_type_offset + tool_type_radio_brush); + ImGui::PushItemWidth(tool_type_radio_smart_fill); + if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == ToolType::SMART_FILL)) + m_tool_type = ToolType::SMART_FILL; + + if (ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Paints neighboring facets whose relative angle is less or equal to set angle."), max_tooltip_width); + + m_imgui->checkbox(m_desc["on_overhangs_only"], m_paint_on_overhangs_only); + if (ImGui::IsItemHovered()) + m_imgui->tooltip(format_wxstr(_L("Allows painting only on facets selected by: \"%1%\""), m_desc["highlight_by_angle"]), max_tooltip_width); + + ImGui::Separator(); + + if (m_tool_type == ToolType::BRUSH) { + m_imgui->text(m_desc.at("cursor_type")); + ImGui::NewLine(); + + float cursor_type_offset = (window_width - cursor_type_radio_sphere - cursor_type_radio_circle - cursor_type_radio_pointer + m_imgui->scaled(1.5f)) / 2.f; + ImGui::SameLine(cursor_type_offset); + ImGui::PushItemWidth(cursor_type_radio_sphere); + if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE)) + m_cursor_type = TriangleSelector::CursorType::SPHERE; + + if (ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Paints all facets inside, regardless of their orientation."), max_tooltip_width); + + ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere); + ImGui::PushItemWidth(cursor_type_radio_circle); + + if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE)) + m_cursor_type = TriangleSelector::CursorType::CIRCLE; + + if (ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Ignores facets facing away from the camera."), max_tooltip_width); + + ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + cursor_type_radio_circle); + ImGui::PushItemWidth(cursor_type_radio_pointer); + + if (m_imgui->radio_button(m_desc["pointer"], m_cursor_type == TriangleSelector::CursorType::POINTER)) + m_cursor_type = TriangleSelector::CursorType::POINTER; + + if (ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Paints only one facet."), max_tooltip_width); + + m_imgui->disabled_begin(m_cursor_type != TriangleSelector::CursorType::SPHERE && m_cursor_type != TriangleSelector::CursorType::CIRCLE); + + ImGui::AlignTextToFramePadding(); + m_imgui->text(m_desc.at("cursor_size")); + ImGui::SameLine(sliders_left_width); + ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); + m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true, _L("Alt + Mouse wheel")); + + m_imgui->checkbox(m_desc["split_triangles"], m_triangle_splitting_enabled); + + if (ImGui::IsItemHovered()) + m_imgui->tooltip(_L("Splits bigger facets into smaller ones while the object is painted."), max_tooltip_width); + + m_imgui->disabled_end(); + } else { + assert(m_tool_type == ToolType::SMART_FILL); + ImGui::AlignTextToFramePadding(); + m_imgui->text(m_desc["smart_fill_angle"] + ":"); + + ImGui::SameLine(sliders_left_width); + ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); + if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true, _L("Alt + Mouse wheel"))) + for (auto &triangle_selector : m_triangle_selectors) { + triangle_selector->seed_fill_unselect_all_triangles(); + triangle_selector->request_update_render_data(); + } + } + + ImGui::Separator(); + if (m_c->object_clipper()->get_position() == 0.f) { + ImGui::AlignTextToFramePadding(); + m_imgui->text(m_desc.at("clipping_of_view")); + } + else { + if (m_imgui->button(m_desc.at("reset_direction"))) { + wxGetApp().CallAfter([this](){ + m_c->object_clipper()->set_position_by_ratio(-1., false); + }); + } + } + + auto clp_dist = float(m_c->object_clipper()->get_position()); + ImGui::SameLine(sliders_left_width); + ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); + if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel"))) + m_c->object_clipper()->set_position_by_ratio(clp_dist, true); + + ImGui::Separator(); + if (m_imgui->button(m_desc.at("remove_all"))) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), UndoRedo::SnapshotType::GizmoAction); + ModelObject *mo = m_c->selection_info()->model_object(); + int idx = -1; + for (ModelVolume *mv : mo->volumes) + if (mv->is_model_part()) { + ++idx; + m_triangle_selectors[idx]->reset(); + m_triangle_selectors[idx]->request_update_render_data(); + } + + update_model_object(); + this->waiting_for_autogenerated_supports = false; + m_parent.set_as_dirty(); + } + + m_imgui->end(); +} + + + +void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block) +{ + float threshold = (float(M_PI)/180.f)*threshold_deg; + const Selection& selection = m_parent.get_selection(); + const ModelObject* mo = m_c->selection_info()->model_object(); + const ModelInstance* mi = mo->instances[selection.get_instance_idx()]; + + int mesh_id = -1; + for (const ModelVolume* mv : mo->volumes) { + if (! mv->is_model_part()) + continue; + + ++mesh_id; + +#if ENABLE_WORLD_COORDINATE + const Transform3d trafo_matrix = mi->get_matrix_no_offset() * mv->get_matrix_no_offset(); +#else + const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true); +#endif // ENABLE_WORLD_COORDINATE + Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast().normalized(); + Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast().normalized(); + + float dot_limit = limit.dot(down); + + // Now calculate dot product of vert_direction and facets' normals. + int idx = 0; + const indexed_triangle_set &its = mv->mesh().its; + for (const stl_triangle_vertex_indices &face : its.indices) { + if (its_face_normal(its, face).dot(down) > dot_limit) { + m_triangle_selectors[mesh_id]->set_facet(idx, block ? EnforcerBlockerType::BLOCKER : EnforcerBlockerType::ENFORCER); + m_triangle_selectors.back()->request_update_render_data(); + } + ++ idx; + } + } + + Plater::TakeSnapshot snapshot(wxGetApp().plater(), block ? _L("Block supports by angle") + : _L("Add supports by angle")); + update_model_object(); + this->waiting_for_autogenerated_supports = false; + m_parent.set_as_dirty(); +} + +void GLGizmoFdmSupports::data_changed() +{ + GLGizmoPainterBase::data_changed(); + if (! m_c->selection_info()) + return; + + ModelObject* mo = m_c->selection_info()->model_object(); + if (mo && this->waiting_for_autogenerated_supports) { + get_data_from_backend(); + } else { + this->waiting_for_autogenerated_supports = false; + } +} + +void GLGizmoFdmSupports::get_data_from_backend() +{ + if (! has_backend_supports()) + return; + ModelObject* mo = m_c->selection_info()->model_object(); + + // find the respective PrintObject, we need a pointer to it + for (const PrintObject* po : m_parent.fff_print()->objects()) { + if (po->model_object()->id() == mo->id()) { + std::unordered_map mvs; + for (const ModelVolume* mv : po->model_object()->volumes) { + if (mv->is_model_part()) { + mvs.emplace(mv->id().id, mv); + } + } + int mesh_id = -1.0f; + for (ModelVolume* mv : mo->volumes){ + if (mv->is_model_part()){ + mesh_id++; + mv->supported_facets.assign(mvs[mv->id().id]->supported_facets); + m_triangle_selectors[mesh_id]->deserialize(mv->supported_facets.get_data(), true); + m_triangle_selectors[mesh_id]->request_update_render_data(); + } + } + this->waiting_for_autogenerated_supports = false; + m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + m_parent.set_as_dirty(); + } + } +} + + +void GLGizmoFdmSupports::update_model_object() const +{ + bool updated = false; + ModelObject* mo = m_c->selection_info()->model_object(); + int idx = -1; + for (ModelVolume* mv : mo->volumes) { + if (! mv->is_model_part()) + continue; + ++idx; + updated |= mv->supported_facets.set(*m_triangle_selectors[idx].get()); + } + + if (updated) { + const ModelObjectPtrs& mos = wxGetApp().model().objects; + wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin()); + + m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + } +} + +void GLGizmoFdmSupports::update_from_model_object() +{ + wxBusyCursor wait; + + const ModelObject* mo = m_c->selection_info()->model_object(); + m_triangle_selectors.clear(); + + int volume_id = -1; + for (const ModelVolume* mv : mo->volumes) { + if (! mv->is_model_part()) + continue; + + ++volume_id; + + // This mesh does not account for the possible Z up SLA offset. + const TriangleMesh* mesh = &mv->mesh(); + + m_triangle_selectors.emplace_back(std::make_unique(*mesh)); + // Reset of TriangleSelector is done inside TriangleSelectorGUI's constructor, so we don't need it to perform it again in deserialize(). + m_triangle_selectors.back()->deserialize(mv->supported_facets.get_data(), false); + m_triangle_selectors.back()->request_update_render_data(); + } +} + +bool GLGizmoFdmSupports::has_backend_supports() const +{ + const ModelObject* mo = m_c->selection_info()->model_object(); + if (! mo) + return false; + + // find PrintObject with this ID + for (const PrintObject* po : m_parent.fff_print()->objects()) { + if (po->model_object()->id() == mo->id()) + return po->is_step_done(posSupportSpotsSearch); + } + return false; +} + +void GLGizmoFdmSupports::reslice_FDM_supports(bool postpone_error_messages) const { + wxGetApp().CallAfter( + [this, postpone_error_messages]() { + wxGetApp().plater()->reslice_FFF_until_step(posSupportSpotsSearch, + *m_c->selection_info()->model_object(), postpone_error_messages); + }); +} + +void GLGizmoFdmSupports::auto_generate() +{ + ModelObject *mo = m_c->selection_info()->model_object(); + bool not_painted = std::all_of(mo->volumes.begin(), mo->volumes.end(), [](const ModelVolume* vol){ + return vol->type() != ModelVolumeType::MODEL_PART || vol->supported_facets.empty(); + }); + + MessageDialog dlg(GUI::wxGetApp().plater(), + _L("Autogeneration will erase all currently painted areas.") + "\n\n" + + _L("Are you sure you want to do it?") + "\n", + _L("Warning"), wxICON_WARNING | wxYES | wxNO); + + if (not_painted || dlg.ShowModal() == wxID_YES) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Autogenerate support points")); + int mesh_id = -1.0f; + for (ModelVolume *mv : mo->volumes) { + if (mv->is_model_part()) { + mesh_id++; + mv->supported_facets.reset(); + m_triangle_selectors[mesh_id]->reset(); + m_triangle_selectors[mesh_id]->request_update_render_data(); + } + } + + mo->config.set("support_material", true); + mo->config.set("support_material_auto", false); + this->waiting_for_autogenerated_supports = true; + wxGetApp().CallAfter([this]() { reslice_FDM_supports(); }); + } +} + + +PainterGizmoType GLGizmoFdmSupports::get_painter_type() const +{ + return PainterGizmoType::FDM_SUPPORTS; +} + +wxString GLGizmoFdmSupports::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const +{ + wxString action_name; + if (shift_down) + action_name = _L("Remove selection"); + else { + if (button_down == Button::Left) + action_name = _L("Add supports"); + else + action_name = _L("Block supports"); + } + return action_name; +} + +} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index bbae3f242..d21005e4c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -478,19 +478,19 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos if (action == SLAGizmoEventType::MouseWheelUp && control_down) { double pos = m_c->object_clipper()->get_position(); pos = std::min(1., pos + 0.01); - m_c->object_clipper()->set_position(pos, true); + m_c->object_clipper()->set_position_by_ratio(pos, true); return true; } if (action == SLAGizmoEventType::MouseWheelDown && control_down) { double pos = m_c->object_clipper()->get_position(); pos = std::max(0., pos - 0.01); - m_c->object_clipper()->set_position(pos, true); + m_c->object_clipper()->set_position_by_ratio(pos, true); return true; } if (action == SLAGizmoEventType::ResetClippingPlane) { - m_c->object_clipper()->set_position(-1., false); + m_c->object_clipper()->set_position_by_ratio(-1., false); return true; } @@ -885,7 +885,7 @@ RENDER_AGAIN: else { if (m_imgui->button(m_desc.at("reset_direction"))) { wxGetApp().CallAfter([this](){ - m_c->object_clipper()->set_position(-1., false); + m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -894,7 +894,7 @@ RENDER_AGAIN: ImGui::PushItemWidth(window_width - settings_sliders_left); float clp_dist = m_c->object_clipper()->get_position(); if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) - m_c->object_clipper()->set_position(clp_dist, true); + m_c->object_clipper()->set_position_by_ratio(clp_dist, true); // make sure supports are shown/hidden as appropriate bool show_sups = m_c->instances_hider()->are_supports_shown(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index aa8cdda04..0fdc3b2db 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -31,7 +31,7 @@ public: void data_changed() override; bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); void delete_selected_points(); - bool is_selection_rectangle_dragging() const { + bool is_selection_rectangle_dragging() const override { return m_selection_rectangle.is_dragging(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 89cdf748f..8c67014b6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -476,7 +476,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_imgui->text(m_desc.at("clipping_of_view")); } else { if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position(-1., false); }); + wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -484,7 +484,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::SameLine(sliders_left_width); ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel"))) - m_c->object_clipper()->set_position(clp_dist, true); + m_c->object_clipper()->set_position_by_ratio(clp_dist, true); ImGui::Separator(); if (m_imgui->button(m_desc.at("remove_all"))) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index bf414d04c..9fb3f6f46 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -8,6 +8,7 @@ #if ENABLE_LEGACY_OPENGL_REMOVAL #include "slic3r/GUI/Plater.hpp" #endif // ENABLE_LEGACY_OPENGL_REMOVAL +#include "libslic3r/Model.hpp" #include @@ -79,7 +80,8 @@ std::string GLGizmoMove3D::on_get_name() const bool GLGizmoMove3D::on_is_activable() const { - return !m_parent.get_selection().is_empty(); + const Selection& selection = m_parent.get_selection(); + return !selection.is_any_cut_volume() && !selection.is_any_connector() && !selection.is_empty(); } void GLGizmoMove3D::on_start_dragging() diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 62611ac25..6640c5e06 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -537,7 +537,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous pos = action == SLAGizmoEventType::MouseWheelDown ? std::max(0., pos - 0.01) : std::min(1., pos + 0.01); - m_c->object_clipper()->set_position(pos, true); + m_c->object_clipper()->set_position_by_ratio(pos, true); return true; } else if (alt_down) { @@ -573,7 +573,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } if (action == SLAGizmoEventType::ResetClippingPlane) { - m_c->object_clipper()->set_position(-1., false); + m_c->object_clipper()->set_position_by_ratio(-1., false); return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 35468717b..6c57df7e5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -12,6 +12,7 @@ #include "slic3r/GUI/Jobs/RotoptimizeJob.hpp" #include "libslic3r/PresetBundle.hpp" +#include "libslic3r/Model.hpp" #include @@ -868,7 +869,8 @@ std::string GLGizmoRotate3D::on_get_name() const bool GLGizmoRotate3D::on_is_activable() const { - return !m_parent.get_selection().is_empty(); + const Selection& selection = m_parent.get_selection(); + return !selection.is_any_cut_volume() && !selection.is_any_connector() && !selection.is_empty(); } void GLGizmoRotate3D::on_start_dragging() diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 59f7b2353..4f8b58610 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -8,6 +8,7 @@ #if ENABLE_LEGACY_OPENGL_REMOVAL #include "slic3r/GUI/Plater.hpp" #endif // ENABLE_LEGACY_OPENGL_REMOVAL +#include "libslic3r/Model.hpp" #include @@ -103,6 +104,12 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event) return use_grabbers(mouse_event); } +void GLGizmoScale3D::enable_ununiversal_scale(bool enable) +{ + for (unsigned int i = 0; i < 6; ++i) + m_grabbers[i].enabled = enable; +} + void GLGizmoScale3D::data_changed() { #if ENABLE_WORLD_COORDINATE @@ -161,7 +168,7 @@ std::string GLGizmoScale3D::on_get_name() const bool GLGizmoScale3D::on_is_activable() const { const Selection& selection = m_parent.get_selection(); - return !selection.is_empty() && !selection.is_wipe_tower(); + return !selection.is_any_cut_volume() && !selection.is_any_connector() && !selection.is_empty() && !selection.is_wipe_tower(); } void GLGizmoScale3D::on_start_dragging() @@ -448,7 +455,7 @@ void GLGizmoScale3D::on_render() // draw grabbers render_grabbers(grabber_mean_size); } - else if (m_hover_id == 0 || m_hover_id == 1) { + else if ((m_hover_id == 0 || m_hover_id == 1) && m_grabbers[0].enabled && m_grabbers[1].enabled) { #if ENABLE_LEGACY_OPENGL_REMOVAL // draw connections #if ENABLE_GL_CORE_PROFILE @@ -493,7 +500,7 @@ void GLGizmoScale3D::on_render() shader->stop_using(); } } - else if (m_hover_id == 2 || m_hover_id == 3) { + else if ((m_hover_id == 2 || m_hover_id == 3) && m_grabbers[2].enabled && m_grabbers[3].enabled) { #if ENABLE_LEGACY_OPENGL_REMOVAL // draw connections #if ENABLE_GL_CORE_PROFILE @@ -538,7 +545,7 @@ void GLGizmoScale3D::on_render() shader->stop_using(); } } - else if (m_hover_id == 4 || m_hover_id == 5) { + else if ((m_hover_id == 4 || m_hover_id == 5) && m_grabbers[4].enabled && m_grabbers[5].enabled) { #if ENABLE_LEGACY_OPENGL_REMOVAL // draw connections #if ENABLE_GL_CORE_PROFILE diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp index 0b9ae702d..d51cec815 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp @@ -85,6 +85,7 @@ public: bool on_mouse(const wxMouseEvent &mouse_event) override; void data_changed() override; + void enable_ununiversal_scale(bool enable); protected: virtual bool on_init() override; virtual std::string on_get_name() const override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 418f180de..a49356579 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -156,7 +156,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) else { if (m_imgui->button(m_desc.at("reset_direction"))) { wxGetApp().CallAfter([this](){ - m_c->object_clipper()->set_position(-1., false); + m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -165,7 +165,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::SameLine(sliders_left_width); ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel"))) - m_c->object_clipper()->set_position(clp_dist, true); + m_c->object_clipper()->set_position_by_ratio(clp_dist, true); ImGui::Separator(); if (m_imgui->button(m_desc.at("remove_all"))) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index b562eb49a..579cbbe67 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -673,19 +673,19 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous if (action == SLAGizmoEventType::MouseWheelUp && control_down) { double pos = m_c->object_clipper()->get_position(); pos = std::min(1., pos + 0.01); - m_c->object_clipper()->set_position(pos, true); + m_c->object_clipper()->set_position_by_ratio(pos, true); return true; } if (action == SLAGizmoEventType::MouseWheelDown && control_down) { double pos = m_c->object_clipper()->get_position(); pos = std::max(0., pos - 0.01); - m_c->object_clipper()->set_position(pos, true); + m_c->object_clipper()->set_position_by_ratio(pos, true); return true; } if (action == SLAGizmoEventType::ResetClippingPlane) { - m_c->object_clipper()->set_position(-1., false); + m_c->object_clipper()->set_position_by_ratio(-1., false); return true; } @@ -972,7 +972,7 @@ RENDER_AGAIN: else { if (m_imgui->button(m_desc.at("reset_direction"))) { wxGetApp().CallAfter([this](){ - m_c->object_clipper()->set_position(-1., false); + m_c->object_clipper()->set_position_by_ratio(-1., false); }); } } @@ -981,7 +981,7 @@ RENDER_AGAIN: ImGui::PushItemWidth(window_width - clipping_slider_left); float clp_dist = m_c->object_clipper()->get_position(); if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) - m_c->object_clipper()->set_position(clp_dist, true); + m_c->object_clipper()->set_position_by_ratio(clp_dist, true); if (m_imgui->button("?")) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index ed48b6e5e..136276803 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -62,8 +62,8 @@ public: void delete_selected_points(bool force = false); //ClippingPlane get_sla_clipping_plane() const; - bool is_in_editing_mode() const { return m_editing_mode; } - bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); } + bool is_in_editing_mode() const override { return m_editing_mode; } + bool is_selection_rectangle_dragging() const override { return m_selection_rectangle.is_dragging(); } bool has_backend_supports() const; void reslice_SLA_supports(bool postpone_error_messages = false) const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index ce3ba1d4a..9734f1b77 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -425,8 +425,11 @@ void ObjectClipper::render_cut() const if (m_clp_ratio == 0.) return; const SelectionInfo* sel_info = get_pool()->selection_info(); + int sel_instance_idx = sel_info->get_active_instance(); + if (sel_instance_idx < 0) + return; const ModelObject* mo = sel_info->model_object(); - const Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation(); + const Geometry::Transformation inst_trafo = mo->instances[sel_instance_idx]->get_transformation(); size_t clipper_id = 0; for (const ModelVolume* mv : mo->volumes) { @@ -440,19 +443,30 @@ void ObjectClipper::render_cut() const clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD)); #if ENABLE_LEGACY_OPENGL_REMOVAL clipper->render_cut({ 1.0f, 0.37f, 0.0f, 1.0f }); + clipper->render_contour({ 1.f, 1.f, 1.f, 1.f}); #else glsafe(::glPushMatrix()); glsafe(::glColor3f(1.0f, 0.37f, 0.0f)); clipper->render_cut(); - glsafe(::glPopMatrix()); + glsafe(::glColor3f(1.f, 1.f, 1.f)); + clipper->render_contour(); #endif // ENABLE_LEGACY_OPENGL_REMOVAL ++clipper_id; } } +bool ObjectClipper::is_projection_inside_cut(const Vec3d& point) const +{ + return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [point](const std::unique_ptr& cl) { return cl->is_projection_inside_cut(point); }); +} -void ObjectClipper::set_position(double pos, bool keep_normal) +bool ObjectClipper::has_valid_contour() const +{ + return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [](const std::unique_ptr& cl) { return cl->has_valid_contour(); }); +} + +void ObjectClipper::set_position_by_ratio(double pos, bool keep_normal) { const ModelObject* mo = get_pool()->selection_info()->model_object(); int active_inst = get_pool()->selection_info()->get_active_instance(); @@ -470,7 +484,36 @@ void ObjectClipper::set_position(double pos, bool keep_normal) get_pool()->get_canvas()->set_as_dirty(); } +void ObjectClipper::set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset, double pos) +{ + m_clp.reset(new ClippingPlane(cpl_normal, cpl_offset)); + m_clp_ratio = pos; + get_pool()->get_canvas()->set_as_dirty(); +} +const ClippingPlane* ObjectClipper::get_clipping_plane(bool ignore_hide_clipped) const +{ + static const ClippingPlane no_clip = ClippingPlane::ClipsNothing(); + return (ignore_hide_clipped || m_hide_clipped) ? m_clp.get() : &no_clip; +} + +void ObjectClipper::set_behavior(bool hide_clipped, bool fill_cut, double contour_width) +{ + m_hide_clipped = hide_clipped; + for (auto& clipper : m_clippers) + clipper->set_behaviour(fill_cut, contour_width); +} + +void ObjectClipper::pass_mouse_click(const Vec3d& pt) +{ + for (auto& clipper : m_clippers) + clipper->pass_mouse_click(pt); +} + +std::vector ObjectClipper::get_disabled_contours() const +{ + return std::vector(); +} void SupportsClipper::on_update() { @@ -557,11 +600,13 @@ void SupportsClipper::render_cut() const #if ENABLE_LEGACY_OPENGL_REMOVAL m_clipper->render_cut({ 1.0f, 0.f, 0.37f, 1.0f }); + m_clipper->render_contour({ 1.f, 1.f, 1.f, 1.f }); #else glsafe(::glPushMatrix()); glsafe(::glColor3f(1.0f, 0.f, 0.37f)); m_clipper->render_cut(); - glsafe(::glPopMatrix()); + glsafe(::glColor3f(1.0f, 1.f, 1.f)); + m_clipper->render_contour(); #endif // ENABLE_LEGACY_OPENGL_REMOVAL } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 7dd2c110e..f8ead27f9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -255,10 +255,19 @@ public: CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; } #endif // NDEBUG - void set_position(double pos, bool keep_normal); + void set_normal(const Vec3d& dir); double get_position() const { return m_clp_ratio; } - ClippingPlane* get_clipping_plane() const { return m_clp.get(); } + const ClippingPlane* get_clipping_plane(bool ignore_hide_clipped = false) const; void render_cut() const; + void set_position_by_ratio(double pos, bool keep_normal); + void set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset, double pos); + void set_behavior(bool hide_clipped, bool fill_cut, double contour_width); + + void pass_mouse_click(const Vec3d& pt); + std::vector get_disabled_contours() const; + + bool is_projection_inside_cut(const Vec3d& point_in) const; + bool has_valid_contour() const; protected: @@ -271,6 +280,7 @@ private: std::unique_ptr m_clp; double m_clp_ratio = 0.; double m_active_inst_bb_radius = 0.; + bool m_hide_clipped = true; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index b7b597ca1..c66191d10 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -100,7 +100,7 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoScale3D(m_parent, "scale.svg", 1)); m_gizmos.emplace_back(new GLGizmoRotate3D(m_parent, "rotate.svg", 2)); m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, "place.svg", 3)); - m_gizmos.emplace_back(new GLGizmoCut(m_parent, "cut.svg", 4)); + m_gizmos.emplace_back(new GLGizmoCut3D(m_parent, "cut.svg", 4)); m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5)); m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6)); m_gizmos.emplace_back(new GLGizmoFdmSupports(m_parent, "fdm_supports.svg", 7)); @@ -290,6 +290,8 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p return dynamic_cast(m_gizmos[Seam].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else if (m_current == MmuSegmentation) return dynamic_cast(m_gizmos[MmuSegmentation].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); + else if (m_current == Cut) + return dynamic_cast(m_gizmos[Cut].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else return false; } @@ -507,7 +509,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) #endif /* __APPLE__ */ { // Sla gizmo selects all support points - if ((m_current == SlaSupports || m_current == Hollow) && gizmo_event(SLAGizmoEventType::SelectAll)) + if ((m_current == SlaSupports || m_current == Hollow || m_current == Cut) && gizmo_event(SLAGizmoEventType::SelectAll)) processed = true; break; @@ -551,7 +553,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) case WXK_BACK: case WXK_DELETE: { - if ((m_current == SlaSupports || m_current == Hollow) && gizmo_event(SLAGizmoEventType::Delete)) + if ((m_current == SlaSupports || m_current == Hollow || m_current == Cut) && gizmo_event(SLAGizmoEventType::Delete)) processed = true; break; @@ -610,20 +612,11 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) if (evt.GetEventType() == wxEVT_KEY_UP) { - if (m_current == SlaSupports || m_current == Hollow) + if (m_current == SlaSupports || m_current == Hollow || m_current == Cut) { - bool is_editing = true; - bool is_rectangle_dragging = false; - - if (m_current == SlaSupports) { - GLGizmoSlaSupports* gizmo = dynamic_cast(get_current()); - is_editing = gizmo->is_in_editing_mode(); - is_rectangle_dragging = gizmo->is_selection_rectangle_dragging(); - } - else { - GLGizmoHollow* gizmo = dynamic_cast(get_current()); - is_rectangle_dragging = gizmo->is_selection_rectangle_dragging(); - } + GLGizmoBase* gizmo = get_current(); + const bool is_editing = m_current == Hollow ? true : gizmo->is_in_editing_mode(); + const bool is_rectangle_dragging = gizmo->is_selection_rectangle_dragging(); if (keyCode == WXK_SHIFT) { @@ -645,7 +638,7 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) else if (evt.GetEventType() == wxEVT_KEY_DOWN) { if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) - && dynamic_cast(get_current())->is_in_editing_mode()) + && get_current()->is_in_editing_mode()) { // m_parent.set_cursor(GLCanvas3D::Cross); processed = true; @@ -653,8 +646,8 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) else if (m_current == Cut) { auto do_move = [this, &processed](double delta_z) { - GLGizmoCut* cut = dynamic_cast(get_current()); - cut->set_cut_z(delta_z + cut->get_cut_z()); + GLGizmoCut3D* cut = dynamic_cast(get_current()); + cut->shift_cut_z(delta_z); processed = true; }; @@ -662,6 +655,9 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) { case WXK_NUMPAD_UP: case WXK_UP: { do_move(1.0); break; } case WXK_NUMPAD_DOWN: case WXK_DOWN: { do_move(-1.0); break; } + case WXK_SHIFT : case WXK_ALT: { + processed = get_current()->is_in_editing_mode(); + } default: { break; } } } else if (m_current == Simplify && keyCode == WXK_ESCAPE) { @@ -1044,6 +1040,11 @@ GLGizmoBase* GLGizmosManager::get_current() const return ((m_current == Undefined) || m_gizmos.empty()) ? nullptr : m_gizmos[m_current].get(); } +GLGizmoBase* GLGizmosManager::get_gizmo(GLGizmosManager::EType type) const +{ + return ((type == Undefined) || m_gizmos.empty()) ? nullptr : m_gizmos[type].get(); +} + GLGizmosManager::EType GLGizmosManager::get_gizmo_from_name(const std::string& gizmo_name) const { std::vector selectable_idxs = get_selectable_idxs(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 26389324b..95f090f22 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -200,6 +200,7 @@ public: EType get_current_type() const { return m_current; } GLGizmoBase* get_current() const; + GLGizmoBase* get_gizmo(GLGizmosManager::EType type) const; EType get_gizmo_from_name(const std::string& gizmo_name) const; bool is_running() const; diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 4cbbca9ca..ad2f2712c 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -59,6 +59,11 @@ static const std::map font_icons = { {ImGui::PreferencesHoverButton, "notification_preferences_hover"}, {ImGui::SliderFloatEditBtnIcon, "edit_button" }, {ImGui::SliderFloatEditBtnPressedIcon, "edit_button_pressed" }, + {ImGui::ExpandBtn , "expand_btn" }, + {ImGui::CollapseBtn , "collapse_btn" }, + {ImGui::RevertButton , "undo" }, + {ImGui::WarningMarkerSmall , "notification_warning" }, + {ImGui::InfoMarkerSmall , "notification_info" }, }; static const std::map font_icons_large = { diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 960948b24..e33d29ba1 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -16,15 +16,27 @@ #include +#include + namespace Slic3r { namespace GUI { +void MeshClipper::set_behaviour(bool fill_cut, double contour_width) +{ + if (fill_cut != m_fill_cut || contour_width != m_contour_width) + m_result.reset(); + m_fill_cut = fill_cut; + m_contour_width = contour_width; +} + + + void MeshClipper::set_plane(const ClippingPlane& plane) { if (m_plane != plane) { m_plane = plane; - m_triangles_valid = false; + m_result.reset(); } } @@ -33,7 +45,7 @@ void MeshClipper::set_limiting_plane(const ClippingPlane& plane) { if (m_limiting_plane != plane) { m_limiting_plane = plane; - m_triangles_valid = false; + m_result.reset(); } } @@ -43,8 +55,7 @@ void MeshClipper::set_mesh(const TriangleMesh& mesh) { if (m_mesh != &mesh) { m_mesh = &mesh; - m_triangles_valid = false; - m_triangles2d.resize(0); + m_result.reset(); } } @@ -52,8 +63,7 @@ void MeshClipper::set_negative_mesh(const TriangleMesh& mesh) { if (m_negative_mesh != &mesh) { m_negative_mesh = &mesh; - m_triangles_valid = false; - m_triangles2d.resize(0); + m_result.reset(); } } @@ -63,8 +73,7 @@ void MeshClipper::set_transformation(const Geometry::Transformation& trafo) { if (! m_trafo.get_matrix().isApprox(trafo.get_matrix())) { m_trafo = trafo; - m_triangles_valid = false; - m_triangles2d.resize(0); + m_result.reset(); } } @@ -74,13 +83,9 @@ void MeshClipper::render_cut(const ColorRGBA& color) void MeshClipper::render_cut() #endif // ENABLE_LEGACY_OPENGL_REMOVAL { - if (! m_triangles_valid) + if (! m_result) recalculate_triangles(); - #if ENABLE_LEGACY_OPENGL_REMOVAL - if (m_model.vertices_count() == 0 || m_model.indices_count() == 0) - return; - GLShaderProgram* curr_shader = wxGetApp().get_current_shader(); if (curr_shader != nullptr) curr_shader->stop_using(); @@ -91,8 +96,10 @@ void MeshClipper::render_cut() const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - m_model.set_color(color); - m_model.render(); + for (CutIsland& isl : m_result->cut_islands) { + isl.model.set_color(isl.disabled ? ColorRGBA(1.f, 0.f, 0.f, 1.f) : color); + isl.model.render(); + } shader->stop_using(); } @@ -105,19 +112,80 @@ void MeshClipper::render_cut() } +#if ENABLE_LEGACY_OPENGL_REMOVAL +void MeshClipper::render_contour(const ColorRGBA& color) +#else +void MeshClipper::render_contour() +#endif // ENABLE_LEGACY_OPENGL_REMOVAL +{ + if (! m_result) + recalculate_triangles(); +#if ENABLE_LEGACY_OPENGL_REMOVAL + GLShaderProgram* curr_shader = wxGetApp().get_current_shader(); + if (curr_shader != nullptr) + curr_shader->stop_using(); + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader != nullptr) { + shader->start_using(); + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("view_model_matrix", camera.get_view_matrix()); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + for (CutIsland& isl : m_result->cut_islands) { + isl.model_expanded.set_color(color); + isl.model_expanded.render(); + } + shader->stop_using(); + } + + if (curr_shader != nullptr) + curr_shader->start_using(); +#else + if (m_vertex_array_expanded.has_VBOs()) + m_vertex_array_expanded.render(); +#endif // ENABLE_LEGACY_OPENGL_REMOVAL +} + +bool MeshClipper::is_projection_inside_cut(const Vec3d& point_in) const +{ + if (!m_result || m_result->cut_islands.empty()) + return false; + Vec3d point = m_result->trafo.inverse() * point_in; + Point pt_2d = Point::new_scale(Vec2d(point.x(), point.y())); + + for (const CutIsland& isl : m_result->cut_islands) { + if (isl.expoly_bb.contains(pt_2d) && isl.expoly.contains(pt_2d)) + return true; + } + return false; +} + +bool MeshClipper::has_valid_contour() const +{ + return m_result && std::any_of(m_result->cut_islands.begin(), m_result->cut_islands.end(), [](const CutIsland& isl) { return !isl.expoly.empty(); }); +} + + +void MeshClipper::pass_mouse_click(const Vec3d& point_in) +{ + if (! m_result || m_result->cut_islands.empty()) + return; + Vec3d point = m_result->trafo.inverse() * point_in; + Point pt_2d = Point::new_scale(Vec2d(point.x(), point.y())); + + for (CutIsland& isl : m_result->cut_islands) { + if (isl.expoly_bb.contains(pt_2d) && isl.expoly.contains(pt_2d)) + isl.disabled = ! isl.disabled; + } +} void MeshClipper::recalculate_triangles() { -#if ENABLE_WORLD_COORDINATE - const Transform3f instance_matrix_no_translation_no_scaling = m_trafo.get_rotation_matrix().cast(); -#else - const Transform3f& instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast(); -#endif // ENABLE_WORLD_COORDINATE - // Calculate clipping plane normal in mesh coordinates. - const Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_plane.get_normal().cast(); - const Vec3d up = up_noscale.cast().cwiseProduct(m_trafo.get_scaling_factor()); - // Calculate distance from mesh origin to the clipping plane (in mesh coordinates). - const float height_mesh = m_plane.distance(m_trafo.get_offset()) * (up_noscale.norm()/up.norm()); + m_result = ClipResult(); + + auto plane_mesh = Eigen::Hyperplane(m_plane.get_normal(), -m_plane.distance(Vec3d::Zero())).transform(m_trafo.get_matrix().inverse()); + const Vec3d up = plane_mesh.normal(); + const float height_mesh = -plane_mesh.offset(); // Now do the cutting MeshSlicingParams slicing_params; @@ -137,6 +205,8 @@ void MeshClipper::recalculate_triangles() tr.rotate(q); tr = m_trafo.get_matrix() * tr; + m_result->trafo = tr; + if (m_limiting_plane != ClippingPlane::ClipsNothing()) { // Now remove whatever ended up below the limiting plane (e.g. sinking objects). @@ -190,42 +260,108 @@ void MeshClipper::recalculate_triangles() } } - m_triangles2d = triangulate_expolygons_2f(expolys, m_trafo.get_matrix().matrix().determinant() < 0.); - tr.pretranslate(0.001 * m_plane.get_normal().normalized()); // to avoid z-fighting + Transform3d tr2 = tr; + tr2.pretranslate(0.002 * m_plane.get_normal().normalized()); + #if ENABLE_LEGACY_OPENGL_REMOVAL - m_model.reset(); + std::vector triangles2d; - GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - init_data.reserve_vertices(m_triangles2d.size()); - init_data.reserve_indices(m_triangles2d.size()); + for (const ExPolygon& exp : expolys) { + triangles2d.clear(); - // vertices + indices - for (auto it = m_triangles2d.cbegin(); it != m_triangles2d.cend(); it = it + 3) { - init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast(), (Vec3f)up.cast()); - init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); - init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); - const size_t idx = it - m_triangles2d.cbegin(); - init_data.add_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); + m_result->cut_islands.push_back(CutIsland()); + CutIsland& isl = m_result->cut_islands.back(); + + if (m_fill_cut) { + triangles2d = triangulate_expolygon_2f(exp, m_trafo.get_matrix().matrix().determinant() < 0.); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + init_data.reserve_vertices(triangles2d.size()); + init_data.reserve_indices(triangles2d.size()); + + // vertices + indices + for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) { + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + const size_t idx = it - triangles2d.cbegin(); + init_data.add_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); + } + + if (!init_data.is_empty()) + isl.model.init_from(std::move(init_data)); + } + + if (m_contour_width != 0. && ! exp.contour.empty()) { + triangles2d.clear(); + + // The contours must not scale with the object. Check the scale factor + // in the respective directions, create a scaled copy of the ExPolygon + // offset it and then unscale the result again. + + Transform3d t = tr; + t.translation() = Vec3d::Zero(); + double scale_x = (t * Vec3d::UnitX()).norm(); + double scale_y = (t * Vec3d::UnitY()).norm(); + + // To prevent overflow after scaling, downscale the input if needed: + double extra_scale = 1.; + int32_t limit = int32_t(std::min(std::numeric_limits::max() / (2. * scale_x), std::numeric_limits::max() / (2. * scale_y))); + int32_t max_coord = 0; + for (const Point& pt : exp.contour) + max_coord = std::max(max_coord, std::max(std::abs(pt.x()), std::abs(pt.y()))); + if (max_coord + m_contour_width >= limit) + extra_scale = 0.9 * double(limit) / max_coord; + + ExPolygon exp_copy = exp; + if (extra_scale != 1.) + exp_copy.scale(extra_scale); + exp_copy.scale(scale_x, scale_y); + + ExPolygons expolys_exp = offset_ex(exp_copy, scale_(m_contour_width)); + expolys_exp = diff_ex(expolys_exp, ExPolygons({exp_copy})); + + for (ExPolygon& e : expolys_exp) { + e.scale(1./scale_x, 1./scale_y); + if (extra_scale != 1.) + e.scale(1./extra_scale); + } + + + triangles2d = triangulate_expolygons_2f(expolys_exp, m_trafo.get_matrix().matrix().determinant() < 0.); + GLModel::Geometry init_data = GLModel::Geometry(); + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + init_data.reserve_vertices(triangles2d.size()); + init_data.reserve_indices(triangles2d.size()); + + // vertices + indices + for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) { + init_data.add_vertex((Vec3f)(tr2 * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr2 * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr2 * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + const size_t idx = it - triangles2d.cbegin(); + init_data.add_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2); + } + + if (!init_data.is_empty()) + isl.model_expanded.init_from(std::move(init_data)); + } + + isl.expoly = std::move(exp); + isl.expoly_bb = get_extents(exp); } - - if (!init_data.is_empty()) - m_model.init_from(std::move(init_data)); #else - m_vertex_array.release_geometry(); - for (auto it=m_triangles2d.cbegin(); it != m_triangles2d.cend(); it=it+3) { - m_vertex_array.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up); - m_vertex_array.push_geometry(tr * Vec3d((*(it+1))(0), (*(it+1))(1), height_mesh), up); - m_vertex_array.push_geometry(tr * Vec3d((*(it+2))(0), (*(it+2))(1), height_mesh), up); - const size_t idx = it - m_triangles2d.cbegin(); - m_vertex_array.push_triangle(idx, idx+1, idx+2); - } - m_vertex_array.finalize_geometry(true); + #error NOT IMPLEMENTED #endif // ENABLE_LEGACY_OPENGL_REMOVAL - m_triangles_valid = true; + + +#if ENABLE_LEGACY_OPENGL_REMOVAL +#else + #error NOT IMPLEMENTED +#endif // ENABLE_LEGACY_OPENGL_REMOVAL } @@ -239,7 +375,7 @@ void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3 Vec3d& point, Vec3d& direction) #else void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, - Vec3d& point, Vec3d& direction) const + Vec3d& point, Vec3d& direction) #endif // ENABLE_RAYCAST_PICKING { Matrix4d modelview = camera.get_view_matrix().matrix(); @@ -264,8 +400,11 @@ void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3 bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane, - size_t* facet_idx) const + size_t* facet_idx, bool* was_clipping_plane_hit) const { + if (was_clipping_plane_hit) + *was_clipping_plane_hit = false; + Vec3d point; Vec3d direction; line_from_mouse_pos(mouse_pos, trafo, camera, point, direction); @@ -286,9 +425,26 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& break; } - if (i==hits.size() || (hits.size()-i) % 2 != 0) { - // All hits are either clipped, or there is an odd number of unclipped - // hits - meaning the nearest must be from inside the mesh. + if (i==hits.size()) { + // All hits are clipped. + return false; + } + if ((hits.size()-i) % 2 != 0) { + // There is an odd number of unclipped hits - meaning the nearest must be from inside the mesh. + // In that case, calculate intersection with the clipping place. + if (clipping_plane && was_clipping_plane_hit) { + direction = direction + point; + point = trafo * point; // transform to world coords + direction = trafo * direction - point; + + Vec3d normal = -clipping_plane->get_normal().cast(); + double den = normal.dot(direction); + if (den != 0.) { + double t = (-clipping_plane->get_offset() - normal.dot(point))/den; + position = (point + t * direction).cast(); + *was_clipping_plane_hit = true; + } + } return false; } @@ -302,6 +458,35 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& return true; } +bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, + Vec3d& position, Vec3d& normal) const +{ + Vec3d point; + Vec3d direction; + line_from_mouse_pos(mouse_pos, trafo, camera, point, direction); + + std::vector hits = m_emesh.query_ray_hits(point, direction); + + if (hits.empty()) + return false; // no intersection found + + // Now stuff the points in the provided vector and calculate normals if asked about them: + position = hits[0].position(); + normal = hits[0].normal(); + + return true; +} + +bool MeshRaycaster::is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const +{ + point = trafo.inverse() * point; + + std::vector hits = m_emesh.query_ray_hits(point, direction); + std::vector neg_hits = m_emesh.query_ray_hits(point, -direction); + + return !hits.empty() && !neg_hits.empty(); +} + std::vector MeshRaycaster::get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector& points, const ClippingPlane* clipping_plane) const diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 9f7d394a9..9db2ed1b1 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -14,6 +14,7 @@ #endif // ENABLE_LEGACY_OPENGL_REMOVAL #include +#include #if ENABLE_RAYCAST_PICKING #include #endif // ENABLE_RAYCAST_PICKING @@ -80,6 +81,10 @@ public: class MeshClipper { public: + // Set whether the cut should be triangulated and whether a cut + // contour should be calculated and shown. + void set_behaviour(bool fill_cut, double contour_width); + // Inform MeshClipper about which plane we want to use to cut the mesh // This is supposed to be in world coordinates. void set_plane(const ClippingPlane& plane); @@ -103,10 +108,16 @@ public: // be set in world coords. #if ENABLE_LEGACY_OPENGL_REMOVAL void render_cut(const ColorRGBA& color); + void render_contour(const ColorRGBA& color); #else void render_cut(); #endif // ENABLE_LEGACY_OPENGL_REMOVAL + void pass_mouse_click(const Vec3d& pt); + + bool is_projection_inside_cut(const Vec3d& point) const; + bool has_valid_contour() const; + private: void recalculate_triangles(); @@ -115,13 +126,27 @@ private: const TriangleMesh* m_negative_mesh = nullptr; ClippingPlane m_plane; ClippingPlane m_limiting_plane = ClippingPlane::ClipsNothing(); - std::vector m_triangles2d; #if ENABLE_LEGACY_OPENGL_REMOVAL - GLModel m_model; + + struct CutIsland { + GLModel model; + GLModel model_expanded; + ExPolygon expoly; + BoundingBox expoly_bb; + bool disabled = false; + }; + struct ClipResult { + std::vector cut_islands; + Transform3d trafo; // this rotates the cut into world coords + }; + std::optional m_result; + #else + #error NOT IMLEMENTED GLIndexedVertexArray m_vertex_array; #endif // ENABLE_LEGACY_OPENGL_REMOVAL - bool m_triangles_valid = false; + bool m_fill_cut = true; + double m_contour_width = 0.; }; @@ -150,8 +175,10 @@ public: { } - void line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, - Vec3d& point, Vec3d& direction) const; + static void line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, + Vec3d& point, Vec3d& direction); +// void line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, +// Vec3d& point, Vec3d& direction) const; #endif // ENABLE_RAYCAST_PICKING // Given a mouse position, this returns true in case it is on the mesh. @@ -159,12 +186,18 @@ public: const Vec2d& mouse_pos, const Transform3d& trafo, // how to get the mesh into world coords const Camera& camera, // current camera position - Vec3f& position, // where to save the positibon of the hit (mesh coords) + Vec3f& position, // where to save the positibon of the hit (mesh coords if mesh, world coords if clipping plane) Vec3f& normal, // normal of the triangle that was hit const ClippingPlane* clipping_plane = nullptr, // clipping plane (if active) - size_t* facet_idx = nullptr // index of the facet hit + size_t* facet_idx = nullptr, // index of the facet hit + bool* was_clipping_plane_hit = nullptr // is the hit on the clipping place cross section? ) const; + // Given a mouse position, this returns true in case it is on the mesh. + bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, Vec3d& position, Vec3d& normal) const; + + bool is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const; + // Given a vector of points in woorld coordinates, this returns vector // of indices of points that are visible (i.e. not cut by clipping plane // or obscured by part of the mesh. diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index ac3fb178e..b2e9bf008 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -1234,6 +1234,7 @@ void NotificationManager::UpdatedItemsInfoNotification::add_type(InfoItemType ty case InfoItemType::MmuSegmentation: text += format(_L_PLURAL("%1$d object was loaded with multimaterial painting.", "%1$d objects were loaded with multimaterial painting.",(*it).second), (*it).second) + "\n"; break; case InfoItemType::VariableLayerHeight: text += format(_L_PLURAL("%1$d object was loaded with variable layer height.", "%1$d objects were loaded with variable layer height.", (*it).second), (*it).second) + "\n"; break; case InfoItemType::Sinking: text += format(_L_PLURAL("%1$d object was loaded with partial sinking.", "%1$d objects were loaded with partial sinking.", (*it).second), (*it).second) + "\n"; break; + case InfoItemType::CutConnectors: text += format(_L_PLURAL("%1$d object was loaded as a part of cut object.", "%1$d objects were loaded as parts of cut object", (*it).second), (*it).second) + "\n"; break; default: BOOST_LOG_TRIVIAL(error) << "Unknown InfoItemType: " << (*it).second; break; } } diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index d3fd9071a..4f40ab379 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -34,10 +34,19 @@ void ObjectDataViewModelNode::init_container() #endif //__WXGTK__ } +void ObjectDataViewModelNode::invalidate_container() +{ +#ifndef __WXGTK__ + if (this->GetChildCount() == 0) + this->m_container = false; +#endif //__WXGTK__ +} + static constexpr char LayerRootIcon[] = "edit_layers_all"; static constexpr char LayerIcon[] = "edit_layers_some"; static constexpr char WarningIcon[] = "exclamation"; static constexpr char WarningManifoldIcon[] = "exclamation_manifold"; +static constexpr char LockIcon[] = "cut_"; struct InfoItemAtributes { std::string name; @@ -48,6 +57,7 @@ const std::map INFO_ITEMS{ // info_item Type info_item Name info_item BitmapName { InfoItemType::CustomSupports, {L("Paint-on supports"), "fdm_supports_" }, }, { InfoItemType::CustomSeam, {L("Paint-on seam"), "seam_" }, }, + { InfoItemType::CutConnectors, {L("Cut connectors"), "cut_connectors" }, }, { InfoItemType::MmuSegmentation, {L("Multimaterial painting"), "mmu_segmentation_"}, }, { InfoItemType::Sinking, {L("Sinking"), "sinking"}, }, { InfoItemType::VariableLayerHeight, {L("Variable layer height"), "layers"}, }, @@ -56,19 +66,16 @@ const std::map INFO_ITEMS{ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const wxString& sub_obj_name, Slic3r::ModelVolumeType type, - const wxBitmapBundle& bmp, const bool is_text_volume, const wxString& extruder, - const int idx/* = -1*/, - const std::string& warning_icon_name /*= std::string*/) : + const int idx/* = -1*/) : m_parent(parent), m_name(sub_obj_name), m_type(itVolume), m_volume_type(type), m_is_text_volume(is_text_volume), m_idx(idx), - m_extruder(type == Slic3r::ModelVolumeType::MODEL_PART || type == Slic3r::ModelVolumeType::PARAMETER_MODIFIER ? extruder : ""), - m_warning_icon_name(warning_icon_name) + m_extruder(type == Slic3r::ModelVolumeType::MODEL_PART || type == Slic3r::ModelVolumeType::PARAMETER_MODIFIER ? extruder : "") { set_action_and_extruder_icons(); init_container(); @@ -174,13 +181,6 @@ void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable) *get_bmp_bundle(m_printable == piPrintable ? "eye_open" : "eye_closed"); } -void ObjectDataViewModelNode::set_warning_icon(const std::string& warning_icon_name) -{ - m_warning_icon_name = warning_icon_name; - if (warning_icon_name.empty()) - m_bmp = m_empty_bmp; -} - void ObjectDataViewModelNode::update_settings_digest_bitmaps() { m_bmp = m_empty_bmp; @@ -329,6 +329,7 @@ ObjectDataViewModel::ObjectDataViewModel() m_text_volume_bmps = MenuFactory::get_text_volume_bitmaps(); m_warning_bmp = *get_bmp_bundle(WarningIcon); m_warning_manifold_bmp = *get_bmp_bundle(WarningManifoldIcon); + m_lock_bmp = *get_bmp_bundle(LockIcon); for (auto item : INFO_ITEMS) m_info_bmps[item.first] = get_bmp_bundle(item.second.bmp_name); @@ -342,19 +343,55 @@ ObjectDataViewModel::~ObjectDataViewModel() m_bitmap_cache = nullptr; } -wxBitmapBundle& ObjectDataViewModel::GetWarningBitmap(const std::string& warning_icon_name) +void ObjectDataViewModel::UpdateBitmapForNode(ObjectDataViewModelNode* node) { - return warning_icon_name.empty() ? m_empty_bmp : warning_icon_name == WarningIcon ? m_warning_bmp : m_warning_manifold_bmp; + int vol_type = static_cast(node->GetVolumeType()); + bool is_volume_node = vol_type >= 0; + + if (!node->has_warning_icon() && !node->has_lock()) { + node->SetBitmap(is_volume_node ? *m_volume_bmps.at(vol_type) : m_empty_bmp); + return; + } + + std::string scaled_bitmap_name = std::string(); + if (node->has_warning_icon()) + scaled_bitmap_name += node->warning_icon_name(); + if (node->has_lock()) + scaled_bitmap_name += LockIcon; + if (is_volume_node) + scaled_bitmap_name += std::to_string(vol_type); + scaled_bitmap_name += (wxGetApp().dark_mode() ? "-dm" : "-lm"); + + wxBitmapBundle* bmp = m_bitmap_cache->find_bndl(scaled_bitmap_name); + if (!bmp) { + std::vector bmps; + if (node->has_warning_icon()) + bmps.emplace_back(node->warning_icon_name() == WarningIcon ? &m_warning_bmp : &m_warning_manifold_bmp); + if (node->has_lock()) + bmps.emplace_back(&m_lock_bmp); + if (is_volume_node) + bmps.emplace_back(m_volume_bmps[vol_type]); + bmp = m_bitmap_cache->insert_bndl(scaled_bitmap_name, bmps); + } + + node->SetBitmap(*bmp); } -wxDataViewItem ObjectDataViewModel::Add(const wxString &name, - const int extruder, - const std::string& warning_icon_name/* = std::string()*/ ) +void ObjectDataViewModel::UpdateBitmapForNode(ObjectDataViewModelNode* node, const std::string& warning_icon_name, bool has_lock) { - const wxString extruder_str = extruder == 0 ? _L("default") : wxString::Format("%d", extruder); - auto root = new ObjectDataViewModelNode(name, extruder_str); + node->SetWarningIconName(warning_icon_name); + node->SetLock(has_lock); + UpdateBitmapForNode(node); +} + +wxDataViewItem ObjectDataViewModel::AddObject(const wxString &name, + const wxString& extruder, + const std::string& warning_icon_name, + const bool has_lock) +{ + auto root = new ObjectDataViewModelNode(name, extruder); // Add warning icon if detected auto-repaire - root->SetWarningBitmap(GetWarningBitmap(warning_icon_name), warning_icon_name); + UpdateBitmapForNode(root, warning_icon_name, has_lock); m_objects.push_back(root); // notify control @@ -367,44 +404,30 @@ wxDataViewItem ObjectDataViewModel::Add(const wxString &name, wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent_item, const wxString &name, + const int volume_idx, const Slic3r::ModelVolumeType volume_type, - const bool is_text_volume /*- false*/, - const std::string& warning_icon_name/* = std::string()*/, - const int extruder/* = 0*/, - const bool create_frst_child/* = true*/) + const std::string& warning_icon_name, + const bool is_text_volume = false, + const wxString& extruder) { ObjectDataViewModelNode *root = static_cast(parent_item.GetID()); if (!root) return wxDataViewItem(0); - wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder); - // get insertion position according to the existed Layers and/or Instances Items int insert_position = get_root_idx(root, itLayerRoot); if (insert_position < 0) insert_position = get_root_idx(root, itInstanceRoot); - if (create_frst_child && root->m_volumes_cnt == 0) - { - const Slic3r::ModelVolumeType type = Slic3r::ModelVolumeType::MODEL_PART; - const auto node = new ObjectDataViewModelNode(root, root->m_name, type, nullptr, root->is_text_volume(), extruder_str, 0, root->m_warning_icon_name); - SetVolumeBitmap(node); - insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position); - // notify control - const wxDataViewItem child((void*)node); - ItemAdded(parent_item, child); - - root->m_volumes_cnt++; - if (insert_position >= 0) insert_position++; - } - - const auto node = new ObjectDataViewModelNode(root, name, volume_type, nullptr, is_text_volume, extruder_str, root->m_volumes_cnt, warning_icon_name); - SetVolumeBitmap(node); + const auto node = new ObjectDataViewModelNode(root, name, volume_type, extruder, volume_idx); + UpdateBitmapForNode(node, warning_icon_name, root->has_lock() && volume_type < ModelVolumeType::PARAMETER_MODIFIER); insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position); // if part with errors is added, but object wasn't marked, then mark it - if (!warning_icon_name.empty() && warning_icon_name != root->m_warning_icon_name && - (root->m_warning_icon_name.empty() || root->m_warning_icon_name == WarningManifoldIcon) ) - root->SetWarningBitmap(GetWarningBitmap(warning_icon_name), warning_icon_name); + if (!warning_icon_name.empty() && warning_icon_name != root->warning_icon_name() && + (!root->has_warning_icon() || root->warning_icon_name() == WarningManifoldIcon)) { + root->SetWarningIconName(warning_icon_name); + UpdateBitmapForNode(root); + } // notify control const wxDataViewItem child((void*)node); @@ -602,14 +625,12 @@ wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_i wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item, const t_layer_height_range& layer_range, - const int extruder/* = 0*/, + const wxString& extruder, const int index /* = -1*/) { ObjectDataViewModelNode *parent_node = static_cast(parent_item.GetID()); if (!parent_node) return wxDataViewItem(0); - wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder); - // get LayerRoot node ObjectDataViewModelNode *layer_root_node; wxDataViewItem layer_root_item; @@ -626,7 +647,7 @@ wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_ } // Add layer node - ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, layer_range, index, extruder_str); + ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, layer_range, index, extruder); if (index < 0) layer_root_node->Append(layer_node); else @@ -715,10 +736,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item) delete node_parent; ret_item = wxDataViewItem(obj_node); -#ifndef __WXGTK__ - if (obj_node->GetChildCount() == 0) - obj_node->m_container = false; -#endif //__WXGTK__ + obj_node->invalidate_container(); ItemDeleted(ret_item, wxDataViewItem(node_parent)); return ret_item; } @@ -734,10 +752,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item) delete node_parent; ret_item = wxDataViewItem(obj_node); -#ifndef __WXGTK__ - if (obj_node->GetChildCount() == 0) - obj_node->m_container = false; -#endif //__WXGTK__ + obj_node->invalidate_container(); ItemDeleted(ret_item, wxDataViewItem(node_parent)); return ret_item; } @@ -763,10 +778,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item) node_parent->m_volumes_cnt = 0; delete last_child_node; -#ifndef __WXGTK__ - if (node_parent->GetChildCount() == 0) - node_parent->m_container = false; -#endif //__WXGTK__ + node_parent->invalidate_container(); ItemDeleted(parent, wxDataViewItem(last_child_node)); wxCommandEvent event(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED); @@ -801,10 +813,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item) // set m_containet to FALSE if parent has no child if (node_parent) { -#ifndef __WXGTK__ - if (node_parent->GetChildCount() == 0) - node_parent->m_container = false; -#endif //__WXGTK__ + node_parent->invalidate_container(); ret_item = parent; } @@ -846,10 +855,7 @@ wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &par parent_node->set_printable_icon(last_inst_printable); ItemDeleted(parent_item, inst_root_item); ItemChanged(parent_item); -#ifndef __WXGTK__ - if (parent_node->GetChildCount() == 0) - parent_node->m_container = false; -#endif //__WXGTK__ + parent_node->invalidate_container(); } // update object_node printable property @@ -894,10 +900,7 @@ void ObjectDataViewModel::DeleteChildren(wxDataViewItem& parent) ItemDeleted(parent, item); } - // set m_containet to FALSE if parent has no child -#ifndef __WXGTK__ - root->m_container = false; -#endif //__WXGTK__ + root->invalidate_container(); } void ObjectDataViewModel::DeleteVolumeChildren(wxDataViewItem& parent) @@ -927,11 +930,7 @@ void ObjectDataViewModel::DeleteVolumeChildren(wxDataViewItem& parent) ItemDeleted(parent, item); } root->m_volumes_cnt = 0; - - // set m_containet to FALSE if parent has no child -#ifndef __WXGTK__ - root->m_container = false; -#endif //__WXGTK__ + root->invalidate_container(); } void ObjectDataViewModel::DeleteSettings(const wxDataViewItem& parent) @@ -1679,6 +1678,7 @@ void ObjectDataViewModel::UpdateBitmaps() m_text_volume_bmps = MenuFactory::get_text_volume_bitmaps(); m_warning_bmp = *get_bmp_bundle(WarningIcon); m_warning_manifold_bmp = *get_bmp_bundle(WarningManifoldIcon); + m_lock_bmp = *get_bmp_bundle(LockIcon); for (auto item : INFO_ITEMS) m_info_bmps[item.first] = get_bmp_bundle(item.second.bmp_name); @@ -1697,10 +1697,8 @@ void ObjectDataViewModel::UpdateBitmaps() switch (node->m_type) { case itObject: - if (node->m_bmp.IsOk()) node->m_bmp = GetWarningBitmap(node->m_warning_icon_name); - break; case itVolume: - SetVolumeBitmap(node); + UpdateBitmapForNode(node); break; case itLayerRoot: node->m_bmp = *get_bmp_bundle(LayerRootIcon); @@ -1749,13 +1747,14 @@ void ObjectDataViewModel::AddWarningIcon(const wxDataViewItem& item, const std:: ObjectDataViewModelNode *node = static_cast(item.GetID()); if (node->GetType() & itObject) { - node->SetWarningBitmap(GetWarningBitmap(warning_icon_name), warning_icon_name); + UpdateBitmapForNode(node, warning_icon_name, node->has_lock()); return; } if (node->GetType() & itVolume) { - node->SetWarningBitmap(GetVolumeIcon(*node, warning_icon_name), warning_icon_name); - node->GetParent()->SetWarningBitmap(GetWarningBitmap(warning_icon_name), warning_icon_name); + UpdateBitmapForNode(node, warning_icon_name, node->has_lock()); + if (ObjectDataViewModelNode* parent = node->GetParent()) + UpdateBitmapForNode(parent, warning_icon_name, parent->has_lock()); return; } } @@ -1770,12 +1769,9 @@ void ObjectDataViewModel::DeleteWarningIcon(const wxDataViewItem& item, const bo if (!node->GetBitmap().IsOk() || !(node->GetType() & (itVolume | itObject))) return; - if (node->GetType() & itVolume) { - node->SetWarningBitmap(*m_volume_bmps[static_cast(node->volume_type())], ""); - return; - } + node->SetWarningIconName(std::string()); + UpdateBitmapForNode(node); - node->SetWarningBitmap(wxNullBitmap, ""); if (unmark_object) { wxDataViewItemArray children; @@ -1802,6 +1798,26 @@ void ObjectDataViewModel::UpdateWarningIcon(const wxDataViewItem& item, const st AddWarningIcon(item, warning_icon_name); } +void ObjectDataViewModel::UpdateLockIcon(const wxDataViewItem& item, bool has_lock) +{ + if (!item.IsOk()) + return; + ObjectDataViewModelNode* node = static_cast(item.GetID()); + if (node->has_lock() == has_lock) + return; + + node->SetLock(has_lock); + UpdateBitmapForNode(node); + + if (node->GetType() & itObject) { + wxDataViewItemArray children; + GetChildren(item, children); + for (const wxDataViewItem& child : children) + UpdateLockIcon(child, has_lock); + } + ItemChanged(item); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/ObjectDataViewModel.hpp b/src/slic3r/GUI/ObjectDataViewModel.hpp index cd071c291..212d1c9e4 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.hpp +++ b/src/slic3r/GUI/ObjectDataViewModel.hpp @@ -51,6 +51,7 @@ enum class InfoItemType Undef, CustomSupports, CustomSeam, + CutConnectors, MmuSegmentation, Sinking, VariableLayerHeight @@ -79,9 +80,10 @@ class ObjectDataViewModelNode PrintIndicator m_printable {piUndef}; wxBitmapBundle m_printable_icon; std::string m_warning_icon_name{ "" }; + bool m_has_lock{false}; std::string m_action_icon_name = ""; - ModelVolumeType m_volume_type; + ModelVolumeType m_volume_type{ -1 }; bool m_is_text_volume{ false }; InfoItemType m_info_item_type {InfoItemType::Undef}; @@ -100,11 +102,9 @@ public: ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const wxString& sub_obj_name, Slic3r::ModelVolumeType type, - const wxBitmapBundle& bmp, const bool is_text_volume, const wxString& extruder, - const int idx = -1, - const std::string& warning_icon_name = std::string()); + const int idx = -1 ); ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const t_layer_height_range& layer_range, @@ -130,7 +130,9 @@ public: } void init_container(); - bool IsContainer() const + void invalidate_container(); + + bool IsContainer() const { return m_container; } @@ -183,7 +185,8 @@ public: void SetVolumeType(ModelVolumeType type) { m_volume_type = type; } void SetBitmap(const wxBitmapBundle &icon) { m_bmp = icon; } void SetExtruder(const wxString &extruder) { m_extruder = extruder; } - void SetWarningBitmap(const wxBitmapBundle& icon, const std::string& warning_icon_name) { m_bmp = icon; m_warning_icon_name = warning_icon_name; } + void SetWarningIconName(const std::string& warning_icon_name) { m_warning_icon_name = warning_icon_name; } + void SetLock(bool has_lock) { m_has_lock = has_lock; } const wxBitmapBundle& GetBitmap() const { return m_bmp; } const wxString& GetName() const { return m_name; } ItemType GetType() const { return m_type; } @@ -230,8 +233,6 @@ public: void set_extruder_icon(); // Set printable icon for node void set_printable_icon(PrintIndicator printable); - // Set warning icon for node - void set_warning_icon(const std::string& warning_icon); void update_settings_digest_bitmaps(); bool update_settings_digest(const std::vector& categories); @@ -243,7 +244,9 @@ public: bool valid(); #endif /* NDEBUG */ bool invalid() const { return m_idx < -1; } - bool has_warning_icon() const { return !m_warning_icon_name.empty(); } + bool has_warning_icon() const { return !m_warning_icon_name.empty(); } + bool has_lock() const { return m_has_lock; } + const std::string& warning_icon_name() const { return m_warning_icon_name; } private: friend class ObjectDataViewModel; @@ -266,6 +269,7 @@ class ObjectDataViewModel :public wxDataViewModel wxBitmapBundle m_empty_bmp; wxBitmapBundle m_warning_bmp; wxBitmapBundle m_warning_manifold_bmp; + wxBitmapBundle m_lock_bmp; wxDataViewCtrl* m_ctrl { nullptr }; @@ -273,16 +277,17 @@ public: ObjectDataViewModel(); ~ObjectDataViewModel(); - wxDataViewItem Add( const wxString &name, - const int extruder, - const std::string& warning_icon_name = std::string()); + wxDataViewItem AddObject( const wxString &name, + const wxString& extruder, + const std::string& warning_icon_name, + const bool has_lock); wxDataViewItem AddVolumeChild( const wxDataViewItem &parent_item, const wxString &name, + const int volume_idx, const Slic3r::ModelVolumeType volume_type, + const std::string& warning_icon_name, const bool is_text_volume = false, - const std::string& warning_icon_name = std::string(), - const int extruder = 0, - const bool create_frst_child = true); + const wxString& extruder); wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); wxDataViewItem AddInfoChild(const wxDataViewItem &parent_item, InfoItemType info_type); wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num); @@ -290,7 +295,7 @@ public: wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item); wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item, const t_layer_height_range& layer_range, - const int extruder = 0, + const wxString& extruder, const int index = -1); size_t GetItemIndexForFirstVolume(ObjectDataViewModelNode* node_parent); wxDataViewItem Delete(const wxDataViewItem &item); @@ -395,6 +400,7 @@ public: void AddWarningIcon(const wxDataViewItem& item, const std::string& warning_name); void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false); void UpdateWarningIcon(const wxDataViewItem& item, const std::string& warning_name); + void UpdateLockIcon(const wxDataViewItem& item, bool has_lock); bool HasWarningIcon(const wxDataViewItem& item) const; t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const; @@ -408,7 +414,8 @@ private: wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item); void AddAllChildren(const wxDataViewItem& parent); - wxBitmapBundle& GetWarningBitmap(const std::string& warning_icon_name); + void UpdateBitmapForNode(ObjectDataViewModelNode* node); + void UpdateBitmapForNode(ObjectDataViewModelNode* node, const std::string& warning_icon_name, bool has_lock); }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 2bccf2cb7..baacafe43 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -97,6 +97,7 @@ #include "MsgDialog.hpp" #include "ProjectDirtyStateManager.hpp" #include "Gizmos/GLGizmoSimplify.hpp" // create suggestion notification +#include "Gizmos/GLGizmoCut.hpp" #ifdef __APPLE__ #include "Gizmos/GLGizmosManager.hpp" @@ -1792,7 +1793,7 @@ struct Plater::priv std::string get_config(const std::string &key) const; std::vector load_files(const std::vector& input_files, bool load_model, bool load_config, bool used_inches = false); - std::vector load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false); + std::vector load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false, bool call_selection_changed = true); fs::path get_export_file_path(GUI::FileType file_type); wxString get_export_file(GUI::FileType file_type); @@ -1807,7 +1808,7 @@ struct Plater::priv void select_all(); void deselect_all(); void remove(size_t obj_idx); - void delete_object_from_model(size_t obj_idx); + bool delete_object_from_model(size_t obj_idx); void delete_all_objects_from_model(); void reset(); void mirror(Axis axis); @@ -2718,7 +2719,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ // #define AUTOPLACEMENT_ON_LOAD -std::vector Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z) +std::vector Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z, bool call_selection_changed /*= true*/) { const Vec3d bed_size = Slic3r::to_3d(this->bed.build_volume().bounding_volume2d().size(), 1.0) - 2.0 * Vec3d::Ones(); @@ -2801,17 +2802,18 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs& mode notification_manager->close_notification_of_type(NotificationType::UpdatedItemsInfo); for (const size_t idx : obj_idxs) { - wxGetApp().obj_list()->add_object_to_list(idx); + wxGetApp().obj_list()->add_object_to_list(idx, call_selection_changed); } - update(); - // Update InfoItems in ObjectList after update() to use of a correct value of the GLCanvas3D::is_sinking(), - // which is updated after a view3D->reload_scene(false, flags & (unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH) call - for (const size_t idx : obj_idxs) - wxGetApp().obj_list()->update_info_items(idx); - - object_list_changed(); + if (call_selection_changed) { + update(); + // Update InfoItems in ObjectList after update() to use of a correct value of the GLCanvas3D::is_sinking(), + // which is updated after a view3D->reload_scene(false, flags & (unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH) call + for (const size_t idx : obj_idxs) + wxGetApp().obj_list()->update_info_items(idx); + object_list_changed(); + } this->schedule_background_process(); return obj_idxs; @@ -2990,16 +2992,35 @@ void Plater::priv::remove(size_t obj_idx) } -void Plater::priv::delete_object_from_model(size_t obj_idx) +bool Plater::priv::delete_object_from_model(size_t obj_idx) { + // check if object isn't cut + // show warning message that "cut consistancy" will not be supported any more + ModelObject* obj = model.objects[obj_idx]; + if (obj->is_cut()) { + InfoDialog dialog(q, _L("Delete object which is a part of cut object"), + _L("You try to delete an object which is a part of a cut object.\n" + "This action will break a cut correspondence.\n" + "After that PrusaSlicer can't garantie model consistency"), + false, wxYES | wxCANCEL | wxCANCEL_DEFAULT | wxICON_WARNING); + dialog.SetButtonLabel(wxID_YES, _L("Delete object")); + if (dialog.ShowModal() == wxID_CANCEL) + return false; + } + wxString snapshot_label = _L("Delete Object"); - if (! model.objects[obj_idx]->name.empty()) - snapshot_label += ": " + wxString::FromUTF8(model.objects[obj_idx]->name.c_str()); + if (!obj->name.empty()) + snapshot_label += ": " + wxString::FromUTF8(obj->name.c_str()); Plater::TakeSnapshot snapshot(q, snapshot_label); m_worker.cancel_all(); + + if (obj->is_cut()) + sidebar->obj_list()->invalidate_cut_info_for_object(obj_idx); + model.delete_object(obj_idx); update(); object_list_changed(); + return true; } void Plater::priv::delete_all_objects_from_model() @@ -4438,7 +4459,10 @@ void Plater::priv::on_action_split_volumes(SimpleEvent&) void Plater::priv::on_action_layersediting(SimpleEvent&) { - view3D->enable_layers_editing(!view3D->is_layers_editing_enabled()); + const bool enable_layersediting = !view3D->is_layers_editing_enabled(); + view3D->enable_layers_editing(enable_layersediting); + if (enable_layersediting) + view3D->get_canvas3d()->reset_all_gizmos(); notification_manager->set_move_from_overlay(view3D->is_layers_editing_enabled()); } @@ -4481,7 +4505,7 @@ void Plater::priv::on_right_click(RBtnEvent& evt) selection.is_single_full_object() || selection.is_multiple_full_instance(); #if ENABLE_WORLD_COORDINATE - const bool is_part = selection.is_single_volume_or_modifier(); + const bool is_part = selection.is_single_volume_or_modifier() && ! selection.is_any_connector(); #else const bool is_part = selection.is_single_volume() || selection.is_single_modifier(); #endif // ENABLE_WORLD_COORDINATE @@ -4763,7 +4787,8 @@ bool Plater::priv::can_split(bool to_objects) const bool Plater::priv::can_scale_to_print_volume() const { const BuildVolume::Type type = this->bed.build_volume().type(); - return !view3D->get_canvas3d()->get_selection().is_empty() && (type == BuildVolume::Type::Rectangle || type == BuildVolume::Type::Circle); + return !sidebar->obj_list()->has_selected_cut_object() && + !view3D->get_canvas3d()->get_selection().is_empty() && (type == BuildVolume::Type::Rectangle || type == BuildVolume::Type::Circle); } bool Plater::priv::layers_height_allowed() const @@ -4778,16 +4803,19 @@ bool Plater::priv::layers_height_allowed() const bool Plater::priv::can_mirror() const { - return get_selection().is_from_single_instance(); + return !sidebar->obj_list()->has_selected_cut_object() && get_selection().is_from_single_instance(); } bool Plater::priv::can_replace_with_stl() const { - return get_selection().get_volume_idxs().size() == 1; + return !sidebar->obj_list()->has_selected_cut_object() && get_selection().get_volume_idxs().size() == 1; } bool Plater::priv::can_reload_from_disk() const { + if (sidebar->obj_list()->has_selected_cut_object()) + return false; + #if ENABLE_RELOAD_FROM_DISK_REWORK // collect selected reloadable ModelVolumes std::vector> selected_volumes = reloadable_volumes(model, get_selection()); @@ -4901,8 +4929,12 @@ bool Plater::priv::can_fix_through_netfabb() const bool Plater::priv::can_simplify() const { + const int obj_idx = get_selected_object_idx(); // is object for simplification selected - if (get_selected_object_idx() < 0) return false; + // cut object can't be simplify + if (obj_idx < 0 || model.objects[obj_idx]->is_cut()) + return false; + // is already opened? if (q->canvas3D()->get_gizmos_manager().get_current_type() == GLGizmosManager::EType::Simplify) @@ -4918,8 +4950,7 @@ bool Plater::priv::can_increase_instances() const if (q->canvas3D()->get_gizmos_manager().get_current_type() == GLGizmosManager::Emboss) return false; - int obj_idx = get_selected_object_idx(); - return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()); + return !sidebar->obj_list()->has_selected_cut_object(); } bool Plater::priv::can_decrease_instances() const @@ -4928,8 +4959,7 @@ bool Plater::priv::can_decrease_instances() const || q->canvas3D()->get_gizmos_manager().is_in_editing_mode()) return false; - int obj_idx = get_selected_object_idx(); - return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && (model.objects[obj_idx]->instances.size() > 1); + return !sidebar->obj_list()->has_selected_cut_object(); } bool Plater::priv::can_split_to_objects() const @@ -5735,7 +5765,7 @@ void Plater::reset_with_confirm() reset(); } -void Plater::delete_object_from_model(size_t obj_idx) { p->delete_object_from_model(obj_idx); } +bool Plater::delete_object_from_model(size_t obj_idx) { return p->delete_object_from_model(obj_idx); } void Plater::remove_selected() { @@ -5912,23 +5942,29 @@ void Plater::toggle_layers_editing(bool enable) canvas3D()->force_main_toolbar_left_action(canvas3D()->get_main_toolbar_item_id("layersediting")); } -void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, ModelObjectCutAttributes attributes) +void Plater::cut(size_t obj_idx, size_t instance_idx, const Transform3d& cut_matrix, ModelObjectCutAttributes attributes) { wxCHECK_RET(obj_idx < p->model.objects.size(), "obj_idx out of bounds"); - auto *object = p->model.objects[obj_idx]; + auto* object = p->model.objects[obj_idx]; wxCHECK_RET(instance_idx < object->instances.size(), "instance_idx out of bounds"); - if (! attributes.has(ModelObjectCutAttribute::KeepUpper) && ! attributes.has(ModelObjectCutAttribute::KeepLower)) - return; - - Plater::TakeSnapshot snapshot(this, _L("Cut by Plane")); - wxBusyCursor wait; - const auto new_objects = object->cut(instance_idx, z, attributes); - remove(obj_idx); - p->load_model_objects(new_objects); + const auto new_objects = object->cut(instance_idx, cut_matrix, attributes); + + model().delete_object(obj_idx); + sidebar().obj_list()->delete_object_from_list(obj_idx); + + // suppress to call selection update for Object List to avoid call of early Gizmos on/off update + p->load_model_objects(new_objects, false, false); + + // now process all updates of the 3d scene + update(); + // Update InfoItems in ObjectList after update() to use of a correct value of the GLCanvas3D::is_sinking(), + // which is updated after a view3D->reload_scene(false, flags & (unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH) call + for (size_t idx = 0; idx < p->model.objects.size(); idx++) + wxGetApp().obj_list()->update_info_items(idx); Selection& selection = p->get_selection(); size_t last_id = p->model.objects.size() - 1; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index a51744d06..4f9e1ef53 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -242,7 +242,7 @@ public: void remove(size_t obj_idx); void reset(); void reset_with_confirm(); - void delete_object_from_model(size_t obj_idx); + bool delete_object_from_model(size_t obj_idx); void remove_selected(); void increase_instances(size_t num = 1); void decrease_instances(size_t num = 1); @@ -253,7 +253,7 @@ public: void convert_unit(ConversionType conv_type); void toggle_layers_editing(bool enable); - void cut(size_t obj_idx, size_t instance_idx, coordf_t z, ModelObjectCutAttributes attributes); + void cut(size_t obj_idx, size_t instance_idx, const Transform3d& cut_matrix, ModelObjectCutAttributes attributes); void export_gcode(bool prefer_removable); void export_stl_obj(bool extended = false, bool selection_only = false); diff --git a/src/slic3r/GUI/SavePresetDialog.cpp b/src/slic3r/GUI/SavePresetDialog.cpp index 57aa5da98..40f981722 100644 --- a/src/slic3r/GUI/SavePresetDialog.cpp +++ b/src/slic3r/GUI/SavePresetDialog.cpp @@ -163,7 +163,7 @@ void SavePresetDialog::Item::update() if (m_valid_type == ValidationType::Valid && existing) { if (m_preset_name == m_presets->get_selected_preset_name()) { - if (!rename && m_presets->get_edited_preset().is_dirty || + if ((!rename && m_presets->get_edited_preset().is_dirty) || m_parent->get_preset_bundle()) // means that we save modifications from the DiffDialog info_line = _L("Save preset modifications to existing user profile"); else diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index abb2fb03c..47d4f7cfc 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -510,6 +510,28 @@ void Selection::volumes_changed(const std::vector &map_volume_old_to_new this->set_bounding_boxes_dirty(); } +bool Selection::is_any_connector() const +{ + const int obj_idx = get_object_idx(); + + if ((is_any_volume() || is_any_modifier() || is_mixed()) && // some solid_part AND/OR modifier is selected + obj_idx >= 0 && m_model->objects[obj_idx]->is_cut()) { + const ModelVolumePtrs& obj_volumes = m_model->objects[obj_idx]->volumes; + for (size_t vol_idx = 0; vol_idx < obj_volumes.size(); vol_idx++) + if (obj_volumes[vol_idx]->is_cut_connector()) + for (const GLVolume* v : *m_volumes) + if (v->object_idx() == obj_idx && v->volume_idx() == (int)vol_idx && v->selected) + return true; + } + return false; +} + +bool Selection::is_any_cut_volume() const +{ + const int obj_idx = get_object_idx(); + return is_any_volume() && obj_idx >= 0 && m_model->objects[obj_idx]->is_cut(); +} + bool Selection::is_single_full_instance() const { if (m_type == SingleFullInstance) @@ -1524,7 +1546,7 @@ int Selection::bake_transform_if_needed() const if (needs_baking) { MessageDialog dlg((wxWindow*)wxGetApp().mainframe, - _L("The currently manipulated object is tilted or contains tilted parts (rotation angles are not multiples of 90�). " + _L("The currently manipulated object is tilted or contains tilted parts (rotation angles are not multiples of 90°). " "Non-uniform scaling of tilted objects is only possible in non-local coordinate systems, " "once the rotation is embedded into the object coordinates.") + "\n" + _L("This operation is irreversible.") + "\n" + diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 0f9c38bb4..969bc48d9 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -320,6 +320,8 @@ public: bool is_single_volume() const { return m_type == SingleVolume; } bool is_multiple_volume() const { return m_type == MultipleVolume; } bool is_any_volume() const { return is_single_volume() || is_multiple_volume(); } + bool is_any_connector() const; + bool is_any_cut_volume() const; bool is_mixed() const { return m_type == Mixed; } bool is_from_single_instance() const { return get_instance_idx() != -1; } bool is_from_single_object() const; diff --git a/src/slic3r/GUI/UnsavedChangesDialog.hpp b/src/slic3r/GUI/UnsavedChangesDialog.hpp index 69f808451..a0b53dadf 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.hpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.hpp @@ -414,7 +414,7 @@ public: std::string get_left_preset_name(Preset::Type type); std::string get_right_preset_name(Preset::Type type); - std::vector get_selected_options(Preset::Type type) const { return std::move(m_tree->options(type, true)); } + std::vector get_selected_options(Preset::Type type) const { return m_tree->options(type, true); } protected: void on_dpi_changed(const wxRect& suggested_rect) override;